Skip to content

Commit

Permalink
feat: backport text-in-voice support to v13 (#7999)
Browse files Browse the repository at this point in the history
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
  • Loading branch information
suneettipirneni and Jiralite committed Jun 5, 2022
1 parent 114bcc0 commit ddfe15b
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 75 deletions.
2 changes: 1 addition & 1 deletion src/client/actions/WebhooksUpdate.js
Expand Up @@ -10,7 +10,7 @@ class WebhooksUpdate extends Action {
/**
* Emitted whenever a channel has its webhooks changed.
* @event Client#webhookUpdate
* @param {TextChannel|NewsChannel} channel The channel that had a webhook update
* @param {TextChannel|NewsChannel|VoiceChannel} channel The channel that had a webhook update
*/
if (channel) client.emit(Events.WEBHOOKS_UPDATE, channel);
}
Expand Down
52 changes: 4 additions & 48 deletions src/structures/BaseGuildTextChannel.js
Expand Up @@ -89,16 +89,6 @@ class BaseGuildTextChannel extends GuildChannel {
return this.edit({ defaultAutoArchiveDuration }, reason);
}

/**
* Sets whether this channel is flagged as NSFW.
* @param {boolean} [nsfw=true] Whether the channel should be considered NSFW
* @param {string} [reason] Reason for changing the channel's NSFW flag
* @returns {Promise<TextChannel>}
*/
setNSFW(nsfw = true, reason) {
return this.edit({ nsfw }, reason);
}

/**
* Sets the type of this channel (only conversion between text and news is supported)
* @param {string} type The new channel type
Expand All @@ -109,44 +99,6 @@ class BaseGuildTextChannel extends GuildChannel {
return this.edit({ type }, reason);
}

/**
* Fetches all webhooks for the channel.
* @returns {Promise<Collection<Snowflake, Webhook>>}
* @example
* // Fetch webhooks
* channel.fetchWebhooks()
* .then(hooks => console.log(`This channel has ${hooks.size} hooks`))
* .catch(console.error);
*/
fetchWebhooks() {
return this.guild.channels.fetchWebhooks(this.id);
}

/**
* Options used to create a {@link Webhook} in a {@link TextChannel} or a {@link NewsChannel}.
* @typedef {Object} ChannelWebhookCreateOptions
* @property {?(BufferResolvable|Base64Resolvable)} [avatar] Avatar for the webhook
* @property {string} [reason] Reason for creating the webhook
*/

/**
* Creates a webhook for the channel.
* @param {string} name The name of the webhook
* @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook
* @returns {Promise<Webhook>} Returns the created Webhook
* @example
* // Create a webhook for the current channel
* channel.createWebhook('Snek', {
* avatar: 'https://i.imgur.com/mI8XcpG.jpg',
* reason: 'Needed a cool new Webhook'
* })
* .then(console.log)
* .catch(console.error)
*/
createWebhook(name, options = {}) {
return this.guild.channels.createWebhook(this.id, name, options);
}

/**
* Sets a new topic for the guild channel.
* @param {?string} topic The new topic for the guild channel
Expand Down Expand Up @@ -221,6 +173,10 @@ class BaseGuildTextChannel extends GuildChannel {
createMessageComponentCollector() {}
awaitMessageComponent() {}
bulkDelete() {}
fetchWebhooks() {}
createWebhook() {}
setRateLimitPerUser() {}
setNSFW() {}
}

TextBasedChannel.applyToClass(BaseGuildTextChannel, true);
Expand Down
10 changes: 9 additions & 1 deletion src/structures/DMChannel.js
Expand Up @@ -94,8 +94,16 @@ class DMChannel extends Channel {
createMessageComponentCollector() {}
awaitMessageComponent() {}
// Doesn't work on DM channels; bulkDelete() {}
// Doesn't work on DM channels; setRateLimitPerUser() {}
// Doesn't work on DM channels; setNSFW() {}
}

TextBasedChannel.applyToClass(DMChannel, true, ['bulkDelete']);
TextBasedChannel.applyToClass(DMChannel, true, [
'bulkDelete',
'fetchWebhooks',
'createWebhook',
'setRateLimitPerUser',
'setNSFW',
]);

module.exports = DMChannel;
2 changes: 1 addition & 1 deletion src/structures/Message.js
Expand Up @@ -383,7 +383,7 @@ class Message extends Base {

/**
* The channel that the message was sent in
* @type {TextChannel|DMChannel|NewsChannel|ThreadChannel}
* @type {TextBasedChannel}
* @readonly
*/
get channel() {
Expand Down
2 changes: 1 addition & 1 deletion src/structures/MessagePayload.js
Expand Up @@ -277,7 +277,7 @@ module.exports = MessagePayload;

/**
* A target for a message.
* @typedef {TextChannel|DMChannel|User|GuildMember|Webhook|WebhookClient|Interaction|InteractionWebhook|
* @typedef {TextBasedChannel|User|GuildMember|Webhook|WebhookClient|Interaction|InteractionWebhook|
* Message|MessageManager} MessageTarget
*/

Expand Down
4 changes: 3 additions & 1 deletion src/structures/ThreadChannel.js
Expand Up @@ -545,8 +545,10 @@ class ThreadChannel extends Channel {
createMessageComponentCollector() {}
awaitMessageComponent() {}
bulkDelete() {}
// Doesn't work on Thread channels; setRateLimitPerUser() {}
// Doesn't work on Thread channels; setNSFW() {}
}

TextBasedChannel.applyToClass(ThreadChannel, true);
TextBasedChannel.applyToClass(ThreadChannel, true, ['setRateLimitPerUser', 'setNSFW']);

module.exports = ThreadChannel;
52 changes: 52 additions & 0 deletions src/structures/VoiceChannel.js
Expand Up @@ -2,6 +2,8 @@

const process = require('node:process');
const BaseGuildVoiceChannel = require('./BaseGuildVoiceChannel');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const MessageManager = require('../managers/MessageManager');
const { VideoQualityModes } = require('../util/Constants');
const Permissions = require('../util/Permissions');

Expand All @@ -10,8 +12,21 @@ let deprecationEmittedForEditable = false;
/**
* Represents a guild voice channel on Discord.
* @extends {BaseGuildVoiceChannel}
* @implements {TextBasedChannel}
*/
class VoiceChannel extends BaseGuildVoiceChannel {
constructor(guild, data, client) {
super(guild, data, client, false);

/**
* A manager of the messages sent to this channel
* @type {MessageManager}
*/
this.messages = new MessageManager(this);

this._patch(data);
}

_patch(data) {
super._patch(data);

Expand All @@ -24,6 +39,26 @@ class VoiceChannel extends BaseGuildVoiceChannel {
} else {
this.videoQualityMode ??= null;
}

if ('last_message_id' in data) {
/**
* The last message id sent in the channel, if one was sent
* @type {?Snowflake}
*/
this.lastMessageId = data.last_message_id;
}

if ('messages' in data) {
for (const message of data.messages) this.messages._add(message);
}

if ('rate_limit_per_user' in data) {
/**
* The rate limit per user (slowmode) for this channel in seconds
* @type {number}
*/
this.rateLimitPerUser = data.rate_limit_per_user;
}
}

/**
Expand Down Expand Up @@ -112,6 +147,21 @@ class VoiceChannel extends BaseGuildVoiceChannel {
return this.edit({ videoQualityMode }, reason);
}

// These are here only for documentation purposes - they are implemented by TextBasedChannel
/* eslint-disable no-empty-function */
get lastMessage() {}
send() {}
sendTyping() {}
createMessageCollector() {}
awaitMessages() {}
createMessageComponentCollector() {}
awaitMessageComponent() {}
bulkDelete() {}
fetchWebhooks() {}
createWebhook() {}
setRateLimitPerUser() {}
setNSFW() {}

/**
* Sets the RTC region of the channel.
* @name VoiceChannel#setRTCRegion
Expand All @@ -127,4 +177,6 @@ class VoiceChannel extends BaseGuildVoiceChannel {
*/
}

TextBasedChannel.applyToClass(VoiceChannel, true, ['lastPinAt']);

module.exports = VoiceChannel;
62 changes: 62 additions & 0 deletions src/structures/interfaces/TextBasedChannel.js
Expand Up @@ -330,6 +330,64 @@ class TextBasedChannel {
throw new TypeError('MESSAGE_BULK_DELETE_TYPE');
}

/**
* Fetches all webhooks for the channel.
* @returns {Promise<Collection<Snowflake, Webhook>>}
* @example
* // Fetch webhooks
* channel.fetchWebhooks()
* .then(hooks => console.log(`This channel has ${hooks.size} hooks`))
* .catch(console.error);
*/
fetchWebhooks() {
return this.guild.channels.fetchWebhooks(this.id);
}

/**
* Options used to create a {@link Webhook} in a guild text-based channel.
* @typedef {Object} ChannelWebhookCreateOptions
* @property {?(BufferResolvable|Base64Resolvable)} [avatar] Avatar for the webhook
* @property {string} [reason] Reason for creating the webhook
*/

/**
* Creates a webhook for the channel.
* @param {string} name The name of the webhook
* @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook
* @returns {Promise<Webhook>} Returns the created Webhook
* @example
* // Create a webhook for the current channel
* channel.createWebhook('Snek', {
* avatar: 'https://i.imgur.com/mI8XcpG.jpg',
* reason: 'Needed a cool new Webhook'
* })
* .then(console.log)
* .catch(console.error)
*/
createWebhook(name, options = {}) {
return this.guild.channels.createWebhook(this.id, name, options);
}

/**
* Sets the rate limit per user (slowmode) for this channel.
* @param {number} rateLimitPerUser The new rate limit in seconds
* @param {string} [reason] Reason for changing the channel's rate limit
* @returns {Promise<this>}
*/
setRateLimitPerUser(rateLimitPerUser, reason) {
return this.edit({ rateLimitPerUser }, reason);
}

/**
* Sets whether this channel is flagged as NSFW.
* @param {boolean} [nsfw=true] Whether the channel should be considered NSFW
* @param {string} [reason] Reason for changing the channel's NSFW flag
* @returns {Promise<this>}
*/
setNSFW(nsfw = true, reason) {
return this.edit({ nsfw }, reason);
}

static applyToClass(structure, full = false, ignore = []) {
const props = ['send'];
if (full) {
Expand All @@ -342,6 +400,10 @@ class TextBasedChannel {
'awaitMessages',
'createMessageComponentCollector',
'awaitMessageComponent',
'fetchWebhooks',
'createWebhook',
'setRateLimitPerUser',
'setNSFW',
);
}
for (const prop of props) {
Expand Down
5 changes: 4 additions & 1 deletion src/util/Constants.js
Expand Up @@ -558,7 +558,8 @@ exports.ChannelTypes = createEnum([
* * TextChannel
* * NewsChannel
* * ThreadChannel
* @typedef {DMChannel|TextChannel|NewsChannel|ThreadChannel} TextBasedChannels
* * VoiceChannel
* @typedef {DMChannel|TextChannel|NewsChannel|ThreadChannel|VoiceChannel} TextBasedChannels
*/

/**
Expand All @@ -576,6 +577,7 @@ exports.ChannelTypes = createEnum([
* * GUILD_NEWS_THREAD
* * GUILD_PUBLIC_THREAD
* * GUILD_PRIVATE_THREAD
* * GUILD_VOICE
* @typedef {string} TextBasedChannelTypes
*/
exports.TextBasedChannelTypes = [
Expand All @@ -585,6 +587,7 @@ exports.TextBasedChannelTypes = [
'GUILD_NEWS_THREAD',
'GUILD_PUBLIC_THREAD',
'GUILD_PRIVATE_THREAD',
'GUILD_VOICE',
];

/**
Expand Down

0 comments on commit ddfe15b

Please sign in to comment.