Skip to content

Commit 59a0bd8

Browse files
authored
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
1 parent c94da00 commit 59a0bd8

File tree

6 files changed

+37
-7
lines changed

6 files changed

+37
-7
lines changed

lib/src/main/java/org/asamk/signal/manager/api/Message.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public record Message(
77
String messageText,
88
List<String> attachments,
99
boolean viewOnce,
10+
boolean voiceNote,
1011
List<Mention> mentions,
1112
Optional<Quote> quote,
1213
Optional<Sticker> sticker,

lib/src/main/java/org/asamk/signal/manager/helper/AttachmentHelper.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ public StreamDetails retrieveAttachment(final String id) throws IOException {
4444
return attachmentStore.retrieveAttachment(id);
4545
}
4646

47-
public List<SignalServiceAttachment> uploadAttachments(final List<String> attachments) throws AttachmentInvalidException, IOException {
48-
final var attachmentStreams = createAttachmentStreams(attachments);
47+
public List<SignalServiceAttachment> uploadAttachments(final List<String> attachments, boolean voiceNote) throws AttachmentInvalidException, IOException {
48+
final var attachmentStreams = createAttachmentStreams(attachments, voiceNote);
4949

5050
try {
5151
// Upload attachments here, so we only upload once even for multiple recipients
@@ -61,14 +61,18 @@ public List<SignalServiceAttachment> uploadAttachments(final List<String> attach
6161
}
6262
}
6363

64-
private List<SignalServiceAttachmentStream> createAttachmentStreams(List<String> attachments) throws AttachmentInvalidException, IOException {
64+
public List<SignalServiceAttachment> uploadAttachments(final List<String> attachments) throws AttachmentInvalidException, IOException {
65+
return uploadAttachments(attachments, false);
66+
}
67+
68+
private List<SignalServiceAttachmentStream> createAttachmentStreams(List<String> attachments, boolean voiceNote) throws AttachmentInvalidException, IOException {
6569
if (attachments == null) {
6670
return null;
6771
}
6872
final var signalServiceAttachments = new ArrayList<SignalServiceAttachmentStream>(attachments.size());
6973
for (var attachment : attachments) {
7074
final var uploadSpec = dependencies.getMessageSender().getResumableUploadSpec();
71-
signalServiceAttachments.add(AttachmentUtils.createAttachmentStream(attachment, uploadSpec));
75+
signalServiceAttachments.add(AttachmentUtils.createAttachmentStream(attachment, voiceNote, uploadSpec));
7276
}
7377
return signalServiceAttachments;
7478
}

lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,7 @@ private void applyMessage(
843843
messageBuilder.withBody(message.messageText());
844844
}
845845
if (!message.attachments().isEmpty()) {
846-
final var uploadedAttachments = context.getAttachmentHelper().uploadAttachments(message.attachments());
846+
final var uploadedAttachments = context.getAttachmentHelper().uploadAttachments(message.attachments(), message.voiceNote());
847847
if (!additionalAttachments.isEmpty()) {
848848
additionalAttachments.addAll(uploadedAttachments);
849849
messageBuilder.withAttachments(additionalAttachments);

lib/src/main/java/org/asamk/signal/manager/util/AttachmentUtils.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,49 @@ public class AttachmentUtils {
1414

1515
public static SignalServiceAttachmentStream createAttachmentStream(
1616
String attachment,
17+
boolean voiceNote,
1718
ResumableUploadSpec resumableUploadSpec
1819
) throws AttachmentInvalidException {
1920
try {
2021
final var streamDetails = Utils.createStreamDetails(attachment);
2122

22-
return createAttachmentStream(streamDetails.first(), streamDetails.second(), resumableUploadSpec);
23+
return createAttachmentStream(streamDetails.first(), streamDetails.second(), voiceNote, resumableUploadSpec);
2324
} catch (IOException e) {
2425
throw new AttachmentInvalidException(attachment, e);
2526
}
2627
}
2728

29+
public static SignalServiceAttachmentStream createAttachmentStream(
30+
String attachment,
31+
ResumableUploadSpec resumableUploadSpec
32+
) throws AttachmentInvalidException {
33+
return createAttachmentStream(attachment, false, resumableUploadSpec);
34+
}
35+
2836
public static SignalServiceAttachmentStream createAttachmentStream(
2937
StreamDetails streamDetails,
3038
Optional<String> name,
39+
boolean voiceNote,
3140
ResumableUploadSpec resumableUploadSpec
3241
) throws ResumeLocationInvalidException {
33-
// TODO maybe add a parameter to set the voiceNote, borderless, preview, width, height and caption option
3442
final var uploadTimestamp = System.currentTimeMillis();
3543
return SignalServiceAttachmentStream.newStreamBuilder()
3644
.withStream(streamDetails.getStream())
3745
.withContentType(streamDetails.getContentType())
3846
.withLength(streamDetails.getLength())
3947
.withFileName(name.orElse(null))
48+
.withVoiceNote(voiceNote)
4049
.withUploadTimestamp(uploadTimestamp)
4150
.withResumableUploadSpec(resumableUploadSpec)
4251
.withUuid(UUID.randomUUID())
4352
.build();
4453
}
54+
55+
public static SignalServiceAttachmentStream createAttachmentStream(
56+
StreamDetails streamDetails,
57+
Optional<String> name,
58+
ResumableUploadSpec resumableUploadSpec
59+
) throws ResumeLocationInvalidException {
60+
return createAttachmentStream(streamDetails, name, false, resumableUploadSpec);
61+
}
4562
}

src/main/java/org/asamk/signal/commands/SendCommand.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ public void attachToSubparser(final Subparser subparser) {
109109
.action(Arguments.storeTrue())
110110
.help("Send the message without the urgent flag, so no push notification is triggered for the recipient. "
111111
+ "The message will still be delivered in real-time if the recipient's app is active.");
112+
subparser.addArgument("--voice-note")
113+
.action(Arguments.storeTrue())
114+
.help("Mark audio attachments as voice notes. Voice notes are displayed inline in Signal clients.");
112115
}
113116

114117
@Override
@@ -171,6 +174,7 @@ public void handleCommand(
171174
attachments = List.of();
172175
}
173176
final var viewOnce = Boolean.TRUE.equals(ns.getBoolean("view-once"));
177+
final var voiceNote = Boolean.TRUE.equals(ns.getBoolean("voice-note"));
174178

175179
final var selfNumber = m.getSelfNumber();
176180

@@ -247,6 +251,7 @@ public void handleCommand(
247251
final var message = new Message(messageText,
248252
attachments,
249253
viewOnce,
254+
voiceNote,
250255
mentions,
251256
Optional.ofNullable(quote),
252257
Optional.ofNullable(sticker),

src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ public long sendMessage(final String messageText, final List<String> attachments
238238
final var message = new Message(messageText,
239239
attachments,
240240
false,
241+
false,
241242
List.of(),
242243
Optional.empty(),
243244
Optional.empty(),
@@ -404,6 +405,7 @@ public long sendNoteToSelfMessage(
404405
final var message = new Message(messageText,
405406
attachments,
406407
false,
408+
false,
407409
List.of(),
408410
Optional.empty(),
409411
Optional.empty(),
@@ -451,6 +453,7 @@ public long sendGroupMessage(final String messageText, final List<String> attach
451453
final var message = new Message(messageText,
452454
attachments,
453455
false,
456+
false,
454457
List.of(),
455458
Optional.empty(),
456459
Optional.empty(),

0 commit comments

Comments
 (0)