Skip to content

Commit 352c981

Browse files
almeidxckohen
andauthored
feat: send voice messages (#10462)
* feat: send voice messages * fix: title reference Co-authored-by: ckohen <[email protected]> * docs: clarify voice message attachment properties in documentation --------- Co-authored-by: ckohen <[email protected]>
1 parent f7c77a7 commit 352c981

File tree

9 files changed

+122
-13
lines changed

9 files changed

+122
-13
lines changed

packages/discord.js/src/managers/GuildForumThreadManager.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ class GuildForumThreadManager extends ThreadManager {
2222
* @typedef {BaseMessageOptions} GuildForumThreadMessageCreateOptions
2323
* @property {StickerResolvable} [stickers] The stickers to send with the message
2424
* @property {BitFieldResolvable} [flags] The flags to send with the message
25-
* <info>Only `MessageFlags.SuppressEmbeds` and `MessageFlags.SuppressNotifications` can be set.</info>
25+
* <info>Only {@link MessageFlags.SuppressEmbeds}, {@link MessageFlags.SuppressNotifications}, and
26+
* {@link MessageFlags.IsVoiceMessage} can be set.</info>
2627
*/
2728

2829
/**

packages/discord.js/src/structures/Attachment.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ const { basename, flatten } = require('../util/Util.js');
55

66
/**
77
* @typedef {Object} AttachmentPayload
8-
* @property {?string} name The name of the attachment
98
* @property {Stream|BufferResolvable} attachment The attachment in this payload
10-
* @property {?string} description The description of the attachment
9+
* @property {string} [name] The name of the attachment
10+
* @property {string} [description] The description of the attachment
11+
* @property {title} [title] The title of the attachment
12+
* @property {string} [waveform] The base64 encoded byte array representing a sampled waveform (from voice message attachments)
13+
* @property {number} [duration] The duration of the attachment in seconds (from voice message attachments)
1114
*/
1215

1316
/**
@@ -115,7 +118,7 @@ class Attachment {
115118
if ('duration_secs' in data) {
116119
/**
117120
* The duration of this attachment in seconds
118-
* <info>This will only be available if the attachment is an audio file.</info>
121+
* <info>This will only be available if the attachment is the audio file from a voice message.</info>
119122
*
120123
* @type {?number}
121124
*/
@@ -127,7 +130,7 @@ class Attachment {
127130
if ('waveform' in data) {
128131
/**
129132
* The base64 encoded byte array representing a sampled waveform
130-
* <info>This will only be available if the attachment is an audio file.</info>
133+
* <info>This will only be available if this attachment is the audio file from a voice message.</info>
131134
*
132135
* @type {?string}
133136
*/

packages/discord.js/src/structures/AttachmentBuilder.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,43 @@ class AttachmentBuilder {
1717
* @type {BufferResolvable|Stream}
1818
*/
1919
this.attachment = attachment;
20+
2021
/**
2122
* The name of this attachment
2223
*
2324
* @type {?string}
2425
*/
2526
this.name = data.name;
27+
2628
/**
2729
* The description of the attachment
2830
*
2931
* @type {?string}
3032
*/
3133
this.description = data.description;
34+
35+
/**
36+
* The title of the attachment
37+
*
38+
* @type {?string}
39+
*/
40+
this.title = data.title;
41+
42+
/**
43+
* The base64 encoded byte array representing a sampled waveform
44+
* <info>This is only for voice message attachments.</info>
45+
*
46+
* @type {?string}
47+
*/
48+
this.waveform = data.waveform;
49+
50+
/**
51+
* The duration of the attachment in seconds
52+
* <info>This is only for voice message attachments.</info>
53+
*
54+
* @type {?number}
55+
*/
56+
this.duration = data.duration;
3257
}
3358

3459
/**
@@ -64,6 +89,41 @@ class AttachmentBuilder {
6489
return this;
6590
}
6691

92+
/**
93+
* Sets the title of this attachment.
94+
*
95+
* @param {string} title The title of the file
96+
* @returns {AttachmentBuilder} This attachment
97+
*/
98+
setTitle(title) {
99+
this.title = title;
100+
return this;
101+
}
102+
103+
/**
104+
* Sets the waveform of this attachment.
105+
* <info>This is only for voice message attachments.</info>
106+
*
107+
* @param {string} waveform The base64 encoded byte array representing a sampled waveform
108+
* @returns {AttachmentBuilder} This attachment
109+
*/
110+
setWaveform(waveform) {
111+
this.waveform = waveform;
112+
return this;
113+
}
114+
115+
/**
116+
* Sets the duration of this attachment.
117+
* <info>This is only for voice message attachments.</info>
118+
*
119+
* @param {number} duration The duration of the attachment in seconds
120+
* @returns {AttachmentBuilder} This attachment
121+
*/
122+
setDuration(duration) {
123+
this.duration = duration;
124+
return this;
125+
}
126+
67127
/**
68128
* Sets whether this attachment is a spoiler
69129
*
@@ -119,4 +179,7 @@ exports.AttachmentBuilder = AttachmentBuilder;
119179
* @typedef {Object} AttachmentData
120180
* @property {string} [name] The name of the attachment
121181
* @property {string} [description] The description of the attachment
182+
* @property {string} [title] The title of the attachment
183+
* @property {string} [waveform] The base64 encoded byte array representing a sampled waveform (for voice message attachments)
184+
* @property {number} [duration] The duration of the attachment in seconds (for voice message attachments)
122185
*/

packages/discord.js/src/structures/MessagePayload.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ class MessagePayload {
192192
const attachments = this.options.files?.map((file, index) => ({
193193
id: index.toString(),
194194
description: file.description,
195+
title: file.title,
196+
waveform: file.waveform,
197+
duration_secs: file.duration,
195198
}));
196199
if (Array.isArray(this.options.attachments)) {
197200
this.options.attachments.push(...(attachments ?? []));

packages/discord.js/src/structures/Webhook.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class Webhook {
142142
* @typedef {BaseMessageOptionsWithPoll} WebhookMessageCreateOptions
143143
* @property {boolean} [tts=false] Whether the message should be spoken aloud
144144
* @property {MessageFlags} [flags] Which flags to set for the message.
145-
* <info>Only the {@link MessageFlags.SuppressEmbeds} flag can be set.</info>
145+
* <info>Only {@link MessageFlags.SuppressEmbeds} and {@link MessageFlags.IsVoiceMessage} can be set.</info>
146146
* @property {string} [username=this.name] Username override for the message
147147
* @property {string} [avatarURL] Avatar URL override for the message
148148
* @property {Snowflake} [threadId] The id of the thread in the channel to send to.

packages/discord.js/src/structures/interfaces/InteractionResponses.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ class InteractionResponses {
4545
* @property {boolean} [tts=false] Whether the message should be spoken aloud
4646
* @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response
4747
* @property {MessageFlagsResolvable} [flags] Which flags to set for the message.
48-
* <info>Only `MessageFlags.Ephemeral`, `MessageFlags.SuppressEmbeds`, and `MessageFlags.SuppressNotifications`
49-
* can be set.</info>
48+
* <info>Only {@link MessageFlags.Ephemeral}, {@link MessageFlags.SuppressEmbeds},
49+
* {@link MessageFlags.SuppressNotifications}, and {@link MessageFlags.IsVoiceMessage} can be set.</info>
5050
*/
5151

5252
/**

packages/discord.js/src/structures/interfaces/TextBasedChannel.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ class TextBasedChannel {
114114
* that message will be returned and no new message will be created
115115
* @property {StickerResolvable[]} [stickers=[]] The stickers to send in the message
116116
* @property {MessageFlags} [flags] Which flags to set for the message.
117-
* <info>Only {@link MessageFlags.SuppressEmbeds}, {@link MessageFlags.SuppressNotifications} and
118-
* {@link MessageFlags.IsComponentsV2} can be set.</info>
117+
* <info>Only {@link MessageFlags.SuppressEmbeds}, {@link MessageFlags.SuppressNotifications},
118+
* {@link MessageFlags.IsComponentsV2}, and {@link MessageFlags.IsVoiceMessage} can be set.</info>
119119
* <info>{@link MessageFlags.IsComponentsV2} is required if passing components that aren't action rows</info>
120120
*/
121121

packages/discord.js/typings/index.d.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2249,10 +2249,16 @@ export class AttachmentBuilder {
22492249
public attachment: BufferResolvable | Stream;
22502250
public description: string | null;
22512251
public name: string | null;
2252+
public title: string | null;
2253+
public waveform: string | null;
2254+
public duration: number | null;
22522255
public get spoiler(): boolean;
22532256
public setDescription(description: string): this;
22542257
public setFile(attachment: BufferResolvable | Stream, name?: string): this;
22552258
public setName(name: string): this;
2259+
public setTitle(title: string): this;
2260+
public setWaveform(waveform: string): this;
2261+
public setDuration(duration: number): this;
22562262
public setSpoiler(spoiler?: boolean): this;
22572263
public toJSON(): unknown;
22582264
public static from(other: JSONEncodable<AttachmentPayload>): AttachmentBuilder;
@@ -4828,7 +4834,10 @@ export interface BaseApplicationCommandData {
48284834

48294835
export interface AttachmentData {
48304836
description?: string;
4837+
duration?: number;
48314838
name?: string;
4839+
title?: string;
4840+
waveform?: string;
48324841
}
48334842

48344843
export type CommandOptionDataTypeResolvable = ApplicationCommandOptionType;
@@ -5878,7 +5887,10 @@ export interface FetchThreadsOptions {
58785887
export interface AttachmentPayload {
58795888
attachment: BufferResolvable | Stream;
58805889
description?: string;
5890+
duration?: number;
58815891
name?: string;
5892+
title?: string;
5893+
waveform?: string;
58825894
}
58835895

58845896
export type GlobalSweepFilter<Key, Value> = () =>
@@ -6398,9 +6410,13 @@ export interface InteractionDeferUpdateOptions {
63986410
export interface InteractionReplyOptions extends BaseMessageOptions, MessageOptionsPoll {
63996411
flags?:
64006412
| BitFieldResolvable<
6401-
Extract<MessageFlagsString, 'Ephemeral' | 'IsComponentsV2' | 'SuppressEmbeds' | 'SuppressNotifications'>,
6413+
Extract<
6414+
MessageFlagsString,
6415+
'Ephemeral' | 'IsComponentsV2' | 'IsVoiceMessage' | 'SuppressEmbeds' | 'SuppressNotifications'
6416+
>,
64026417
| MessageFlags.Ephemeral
64036418
| MessageFlags.IsComponentsV2
6419+
| MessageFlags.IsVoiceMessage
64046420
| MessageFlags.SuppressEmbeds
64056421
| MessageFlags.SuppressNotifications
64066422
>
@@ -6577,8 +6593,11 @@ export interface MessageOptionsPoll {
65776593
export interface MessageOptionsFlags {
65786594
flags?:
65796595
| BitFieldResolvable<
6580-
Extract<MessageFlagsString, 'IsComponentsV2' | 'SuppressEmbeds' | 'SuppressNotifications'>,
6581-
MessageFlags.IsComponentsV2 | MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
6596+
Extract<MessageFlagsString, 'IsComponentsV2' | 'IsVoiceMessage' | 'SuppressEmbeds' | 'SuppressNotifications'>,
6597+
| MessageFlags.IsComponentsV2
6598+
| MessageFlags.IsVoiceMessage
6599+
| MessageFlags.SuppressEmbeds
6600+
| MessageFlags.SuppressNotifications
65826601
>
65836602
| undefined;
65846603
}

packages/discord.js/typings/index.test-d.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3000,3 +3000,23 @@ await guildScheduledEventManager.edit(snowflake, { recurrenceRule: null });
30003000
byMonth: [GuildScheduledEventRecurrenceRuleMonth.May],
30013001
});
30023002
}
3003+
3004+
await textChannel.send({
3005+
files: [
3006+
new AttachmentBuilder('https://example.com/voice-message.ogg')
3007+
.setDuration(2)
3008+
.setWaveform('AFUqPDw3Eg2hh4+gopOYj4xthU4='),
3009+
],
3010+
flags: MessageFlags.IsVoiceMessage,
3011+
});
3012+
3013+
await textChannel.send({
3014+
files: [
3015+
{
3016+
attachment: 'https://example.com/voice-message.ogg',
3017+
duration: 2,
3018+
waveform: 'AFUqPDw3Eg2hh4+gopOYj4xthU4=',
3019+
},
3020+
],
3021+
flags: MessageFlags.IsVoiceMessage,
3022+
});

0 commit comments

Comments
 (0)