mirror of
https://github.com/AsamK/signal-cli.git
synced 2026-04-13 07:30:25 +00:00
Add --voice-note flag for send command (#1973)
Add support for marking audio attachments as voice notes when sending messages. Voice notes are displayed inline with a play button in Signal clients, rather than as file attachments. This addresses a longstanding TODO in AttachmentUtils.java and resolves the feature request in #1601. Changes: - Add 'voiceNote' field to Message record - Pass voiceNote flag through AttachmentHelper to AttachmentUtils - Add .withVoiceNote() to SignalServiceAttachmentStream builder - Add --voice-note CLI argument to SendCommand - Support voiceNote parameter in JSON-RPC mode Usage: signal-cli send -a audio.m4a --voice-note +1234567890 JSON-RPC: {"method":"send","params":{"attachment":"audio.m4a","voiceNote":true,...}} Closes #1601
This commit is contained in:
parent
c94da00212
commit
59a0bd87cd
@ -7,6 +7,7 @@ public record Message(
|
||||
String messageText,
|
||||
List<String> attachments,
|
||||
boolean viewOnce,
|
||||
boolean voiceNote,
|
||||
List<Mention> mentions,
|
||||
Optional<Quote> quote,
|
||||
Optional<Sticker> sticker,
|
||||
|
||||
@ -44,8 +44,8 @@ public class AttachmentHelper {
|
||||
return attachmentStore.retrieveAttachment(id);
|
||||
}
|
||||
|
||||
public List<SignalServiceAttachment> uploadAttachments(final List<String> attachments) throws AttachmentInvalidException, IOException {
|
||||
final var attachmentStreams = createAttachmentStreams(attachments);
|
||||
public List<SignalServiceAttachment> uploadAttachments(final List<String> attachments, boolean voiceNote) throws AttachmentInvalidException, IOException {
|
||||
final var attachmentStreams = createAttachmentStreams(attachments, voiceNote);
|
||||
|
||||
try {
|
||||
// Upload attachments here, so we only upload once even for multiple recipients
|
||||
@ -61,14 +61,18 @@ public class AttachmentHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private List<SignalServiceAttachmentStream> createAttachmentStreams(List<String> attachments) throws AttachmentInvalidException, IOException {
|
||||
public List<SignalServiceAttachment> uploadAttachments(final List<String> attachments) throws AttachmentInvalidException, IOException {
|
||||
return uploadAttachments(attachments, false);
|
||||
}
|
||||
|
||||
private List<SignalServiceAttachmentStream> createAttachmentStreams(List<String> attachments, boolean voiceNote) throws AttachmentInvalidException, IOException {
|
||||
if (attachments == null) {
|
||||
return null;
|
||||
}
|
||||
final var signalServiceAttachments = new ArrayList<SignalServiceAttachmentStream>(attachments.size());
|
||||
for (var attachment : attachments) {
|
||||
final var uploadSpec = dependencies.getMessageSender().getResumableUploadSpec();
|
||||
signalServiceAttachments.add(AttachmentUtils.createAttachmentStream(attachment, uploadSpec));
|
||||
signalServiceAttachments.add(AttachmentUtils.createAttachmentStream(attachment, voiceNote, uploadSpec));
|
||||
}
|
||||
return signalServiceAttachments;
|
||||
}
|
||||
|
||||
@ -843,7 +843,7 @@ public class ManagerImpl implements Manager {
|
||||
messageBuilder.withBody(message.messageText());
|
||||
}
|
||||
if (!message.attachments().isEmpty()) {
|
||||
final var uploadedAttachments = context.getAttachmentHelper().uploadAttachments(message.attachments());
|
||||
final var uploadedAttachments = context.getAttachmentHelper().uploadAttachments(message.attachments(), message.voiceNote());
|
||||
if (!additionalAttachments.isEmpty()) {
|
||||
additionalAttachments.addAll(uploadedAttachments);
|
||||
messageBuilder.withAttachments(additionalAttachments);
|
||||
|
||||
@ -14,32 +14,49 @@ public class AttachmentUtils {
|
||||
|
||||
public static SignalServiceAttachmentStream createAttachmentStream(
|
||||
String attachment,
|
||||
boolean voiceNote,
|
||||
ResumableUploadSpec resumableUploadSpec
|
||||
) throws AttachmentInvalidException {
|
||||
try {
|
||||
final var streamDetails = Utils.createStreamDetails(attachment);
|
||||
|
||||
return createAttachmentStream(streamDetails.first(), streamDetails.second(), resumableUploadSpec);
|
||||
return createAttachmentStream(streamDetails.first(), streamDetails.second(), voiceNote, resumableUploadSpec);
|
||||
} catch (IOException e) {
|
||||
throw new AttachmentInvalidException(attachment, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static SignalServiceAttachmentStream createAttachmentStream(
|
||||
String attachment,
|
||||
ResumableUploadSpec resumableUploadSpec
|
||||
) throws AttachmentInvalidException {
|
||||
return createAttachmentStream(attachment, false, resumableUploadSpec);
|
||||
}
|
||||
|
||||
public static SignalServiceAttachmentStream createAttachmentStream(
|
||||
StreamDetails streamDetails,
|
||||
Optional<String> name,
|
||||
boolean voiceNote,
|
||||
ResumableUploadSpec resumableUploadSpec
|
||||
) throws ResumeLocationInvalidException {
|
||||
final var uploadTimestamp = System.currentTimeMillis();
|
||||
return SignalServiceAttachmentStream.newStreamBuilder()
|
||||
.withStream(streamDetails.getStream())
|
||||
.withContentType(streamDetails.getContentType())
|
||||
.withLength(streamDetails.getLength())
|
||||
.withFileName(name.orElse(null))
|
||||
.withVoiceNote(voiceNote)
|
||||
.withUploadTimestamp(uploadTimestamp)
|
||||
.withResumableUploadSpec(resumableUploadSpec)
|
||||
.withUuid(UUID.randomUUID())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static SignalServiceAttachmentStream createAttachmentStream(
|
||||
StreamDetails streamDetails,
|
||||
Optional<String> name,
|
||||
ResumableUploadSpec resumableUploadSpec
|
||||
) throws ResumeLocationInvalidException {
|
||||
// TODO maybe add a parameter to set the voiceNote, borderless, preview, width, height and caption option
|
||||
final var uploadTimestamp = System.currentTimeMillis();
|
||||
return SignalServiceAttachmentStream.newStreamBuilder()
|
||||
.withStream(streamDetails.getStream())
|
||||
.withContentType(streamDetails.getContentType())
|
||||
.withLength(streamDetails.getLength())
|
||||
.withFileName(name.orElse(null))
|
||||
.withUploadTimestamp(uploadTimestamp)
|
||||
.withResumableUploadSpec(resumableUploadSpec)
|
||||
.withUuid(UUID.randomUUID())
|
||||
.build();
|
||||
return createAttachmentStream(streamDetails, name, false, resumableUploadSpec);
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,6 +109,9 @@ public class SendCommand implements JsonRpcLocalCommand {
|
||||
.action(Arguments.storeTrue())
|
||||
.help("Send the message without the urgent flag, so no push notification is triggered for the recipient. "
|
||||
+ "The message will still be delivered in real-time if the recipient's app is active.");
|
||||
subparser.addArgument("--voice-note")
|
||||
.action(Arguments.storeTrue())
|
||||
.help("Mark audio attachments as voice notes. Voice notes are displayed inline in Signal clients.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -171,6 +174,7 @@ public class SendCommand implements JsonRpcLocalCommand {
|
||||
attachments = List.of();
|
||||
}
|
||||
final var viewOnce = Boolean.TRUE.equals(ns.getBoolean("view-once"));
|
||||
final var voiceNote = Boolean.TRUE.equals(ns.getBoolean("voice-note"));
|
||||
|
||||
final var selfNumber = m.getSelfNumber();
|
||||
|
||||
@ -247,6 +251,7 @@ public class SendCommand implements JsonRpcLocalCommand {
|
||||
final var message = new Message(messageText,
|
||||
attachments,
|
||||
viewOnce,
|
||||
voiceNote,
|
||||
mentions,
|
||||
Optional.ofNullable(quote),
|
||||
Optional.ofNullable(sticker),
|
||||
|
||||
@ -238,6 +238,7 @@ public class DbusSignalImpl implements Signal, AutoCloseable {
|
||||
final var message = new Message(messageText,
|
||||
attachments,
|
||||
false,
|
||||
false,
|
||||
List.of(),
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
@ -404,6 +405,7 @@ public class DbusSignalImpl implements Signal, AutoCloseable {
|
||||
final var message = new Message(messageText,
|
||||
attachments,
|
||||
false,
|
||||
false,
|
||||
List.of(),
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
@ -451,6 +453,7 @@ public class DbusSignalImpl implements Signal, AutoCloseable {
|
||||
final var message = new Message(messageText,
|
||||
attachments,
|
||||
false,
|
||||
false,
|
||||
List.of(),
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user