Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: send voice messages #10462

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class GuildForumThreadManager extends ThreadManager {
* @typedef {BaseMessageOptions} GuildForumThreadMessageCreateOptions
* @property {StickerResolvable} [stickers] The stickers to send with the message
* @property {BitFieldResolvable} [flags] The flags to send with the message
* <info>Only `MessageFlags.SuppressEmbeds` and `MessageFlags.SuppressNotifications` can be set.</info>
* <info>Only `MessageFlags.SuppressEmbeds`, `MessageFlags.SuppressNotifications`, and `MessageFlags.IsVoiceMessage`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* can be set.</info>
*/

/**
Expand Down
7 changes: 5 additions & 2 deletions packages/discord.js/src/structures/Attachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ const { basename, flatten } = require('../util/Util');

/**
* @typedef {Object} AttachmentPayload
* @property {?string} name The name of the attachment
* @property {Stream|BufferResolvable} attachment The attachment in this payload
* @property {?string} description The description of the attachment
* @property {string} [name] The name of the attachment
* @property {string} [description] The description of the attachment
* @property {title} [title] The title of the attachment
* @property {string} [waveform] The base64 encoded byte array representing a sampled waveform
* @property {number} [duration] The duration of the attachment in seconds
*/

/**
Expand Down
71 changes: 62 additions & 9 deletions packages/discord.js/src/structures/AttachmentBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,45 @@ class AttachmentBuilder {
* @type {BufferResolvable|Stream}
*/
this.attachment = attachment;

/**
* The name of this attachment
* @type {?string}
*/
this.name = data.name;

/**
* The description of the attachment
* @type {?string}
*/
this.description = data.description;

/**
* The title of the attachment
* @type {?string}
*/
this.title = data.title;

/**
* The base64 encoded byte array representing a sampled waveform
* @type {?string}
*/
this.waveform = data.waveform;

/**
* The duration of the attachment in seconds
* @type {?number}
*/
this.duration = data.duration;
}

/**
* Whether this attachment has been marked as a spoiler
* @type {boolean}
* @readonly
*/
get spoiler() {
almeidx marked this conversation as resolved.
Show resolved Hide resolved
return basename(this.name).startsWith('SPOILER_');
}

/**
Expand Down Expand Up @@ -58,6 +87,36 @@ class AttachmentBuilder {
return this;
}

/**
* Sets the title of this attachment.
* @param {string} title The title of the file
* @returns {AttachmentBuilder} This attachment
*/
setTitle(title) {
this.title = title;
return this;
}

/**
* Sets the waveform of this attachment.
* @param {string} waveform The base64 encoded byte array representing a sampled waveform
* @returns {AttachmentBuilder} This attachment
*/
setWaveform(waveform) {
this.waveform = waveform;
return this;
}

/**
* Sets the duration of this attachment.
* @param {number} duration The duration of the attachment in seconds
* @returns {AttachmentBuilder} This attachment
*/
setDuration(duration) {
this.duration = duration;
return this;
}

/**
* Sets whether this attachment is a spoiler
* @param {boolean} [spoiler=true] Whether the attachment should be marked as a spoiler
Expand All @@ -76,15 +135,6 @@ class AttachmentBuilder {
return this;
}

/**
* Whether or not this attachment has been marked as a spoiler
* @type {boolean}
* @readonly
*/
get spoiler() {
return basename(this.name).startsWith('SPOILER_');
}

toJSON() {
return flatten(this);
}
Expand All @@ -108,4 +158,7 @@ module.exports = AttachmentBuilder;
* @typedef {Object} AttachmentData
* @property {string} [name] The name of the attachment
* @property {string} [description] The description of the attachment
* @property {string} [title] The title of the attachment
* @property {string} [waveform] The base64 encoded byte array representing a sampled waveform
* @property {number} [duration] The duration of the attachment in seconds
*/
3 changes: 3 additions & 0 deletions packages/discord.js/src/structures/MessagePayload.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ class MessagePayload {
const attachments = this.options.files?.map((file, index) => ({
id: index.toString(),
description: file.description,
title: file.name,
waveform: file.waveform,
duration_secs: file.duration,
}));
if (Array.isArray(this.options.attachments)) {
this.options.attachments.push(...(attachments ?? []));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ class InteractionResponses {
* @property {boolean} [ephemeral] Whether the reply should be ephemeral
* @property {boolean} [fetchReply] Whether to fetch the reply
* @property {MessageFlags} [flags] Which flags to set for the message.
* <info>Only `MessageFlags.Ephemeral`, `MessageFlags.SuppressEmbeds`, and `MessageFlags.SuppressNotifications`
* can be set.</info>
* <info>Only `MessageFlags.Ephemeral`, `MessageFlags.SuppressEmbeds`, `MessageFlags.SuppressNotifications`,
* and `MessageFlags.IsVoiceMessage` can be set.</info>
*/

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ class TextBasedChannel {
* that message will be returned and no new message will be created
* @property {StickerResolvable[]} [stickers=[]] The stickers to send in the message
* @property {MessageFlags} [flags] Which flags to set for the message.
* <info>Only `MessageFlags.SuppressEmbeds` and `MessageFlags.SuppressNotifications` can be set.</info>
* <info>Only `MessageFlags.SuppressEmbeds`, `MessageFlags.SuppressNotifications`, and `MessageFlags.IsVoiceMessage`
* can be set.</info>
*/

/**
Expand Down
23 changes: 19 additions & 4 deletions packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2204,10 +2204,16 @@ export class AttachmentBuilder {
public attachment: BufferResolvable | Stream;
public description: string | null;
public name: string | null;
public title: string | null;
public waveform: string | null;
public duration: number | null;
public get spoiler(): boolean;
public setDescription(description: string): this;
public setFile(attachment: BufferResolvable | Stream, name?: string): this;
public setName(name: string): this;
public setTitle(title: string): this;
public setWaveform(waveform: string): this;
public setDuration(duration: number): this;
public setSpoiler(spoiler?: boolean): this;
public toJSON(): unknown;
public static from(other: JSONEncodable<AttachmentPayload>): AttachmentBuilder;
Expand Down Expand Up @@ -4752,6 +4758,9 @@ export interface BaseApplicationCommandData {
export interface AttachmentData {
name?: string;
description?: string;
title?: string;
waveform?: string;
duration?: number;
}

export type CommandOptionDataTypeResolvable = ApplicationCommandOptionType;
Expand Down Expand Up @@ -5773,6 +5782,9 @@ export interface AttachmentPayload {
attachment: BufferResolvable | Stream;
name?: string;
description?: string;
title?: string;
waveform?: string;
duration?: number;
}

export type GlobalSweepFilter<Key, Value> = () =>
Expand Down Expand Up @@ -6240,8 +6252,11 @@ export interface InteractionReplyOptions extends BaseMessageOptions {
ephemeral?: boolean;
fetchReply?: boolean;
flags?: BitFieldResolvable<
Extract<MessageFlagsString, 'Ephemeral' | 'SuppressEmbeds' | 'SuppressNotifications'>,
MessageFlags.Ephemeral | MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
Extract<MessageFlagsString, 'Ephemeral' | 'SuppressEmbeds' | 'SuppressNotifications' | 'IsVoiceMessage'>,
| MessageFlags.Ephemeral
| MessageFlags.SuppressEmbeds
| MessageFlags.SuppressNotifications
| MessageFlags.IsVoiceMessage
>;
}

Expand Down Expand Up @@ -6402,8 +6417,8 @@ export interface MessageCreateOptions extends BaseMessageOptions {
reply?: ReplyOptions;
stickers?: readonly StickerResolvable[];
flags?: BitFieldResolvable<
Extract<MessageFlagsString, 'SuppressEmbeds' | 'SuppressNotifications'>,
MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
Extract<MessageFlagsString, 'SuppressEmbeds' | 'SuppressNotifications' | 'IsVoiceMessage'>,
MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications | MessageFlags.IsVoiceMessage
>;
}

Expand Down
21 changes: 21 additions & 0 deletions packages/discord.js/typings/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
APIMentionableSelectComponent,
APIModalInteractionResponseCallbackData,
WebhookType,
MessageFlags,
} from 'discord-api-types/v10';
import {
ApplicationCommand,
Expand Down Expand Up @@ -2592,3 +2593,23 @@ declare const poll: Poll;
expectType<Collection<Snowflake, StickerPack>>(await client.fetchStickerPacks());
expectType<Collection<Snowflake, StickerPack>>(await client.fetchStickerPacks({}));
expectType<StickerPack>(await client.fetchStickerPacks({ packId: snowflake }));

await textChannel.send({
files: [
new AttachmentBuilder('https://example.com/voice-message.ogg')
.setDuration(2)
.setWaveform('AFUqPDw3Eg2hh4+gopOYj4xthU4='),
],
flags: MessageFlags.IsVoiceMessage,
});

await textChannel.send({
files: [
{
attachment: 'https://example.com/voice-message.ogg',
duration: 2,
waveform: 'AFUqPDw3Eg2hh4+gopOYj4xthU4=',
},
],
flags: MessageFlags.IsVoiceMessage,
});