diff --git a/src/client/Client.js b/src/client/Client.js index 687cc06a6..21d117b30 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -315,6 +315,14 @@ class Client extends EventEmitter { return this.rest.methods.getWebhook(id, token); } + /** + * Fetch available voice regions + * @returns {Collection} + */ + fetchVoiceRegions() { + return this.rest.methods.fetchVoiceRegions(); + } + /** * Sweeps all channels' messages and removes the ones older than the max message lifetime. * If the message has been edited, the time of the edit is used rather than the time of the original message. diff --git a/src/client/rest/RESTMethods.js b/src/client/rest/RESTMethods.js index b5a22a10e..744136e9f 100644 --- a/src/client/rest/RESTMethods.js +++ b/src/client/rest/RESTMethods.js @@ -17,6 +17,7 @@ const UserProfile = require('../../structures/UserProfile'); const ClientOAuth2Application = require('../../structures/ClientOAuth2Application'); const Channel = require('../../structures/Channel'); const Guild = require('../../structures/Guild'); +const VoiceRegion = require('../../structures/VoiceRegion'); class RESTMethods { constructor(restManager) { @@ -47,6 +48,15 @@ class RESTMethods { return this.rest.makeRequest('get', Constants.Endpoints.botGateway, true); } + fetchVoiceRegions(guildID) { + const endpoint = Constants.Endpoints[guildID ? 'guildVoiceRegions' : 'voiceRegions']; + return this.rest.makeRequest('get', guildID ? endpoint(guildID) : endpoint, true).then(res => { + const regions = new Collection(); + for (const region of res) regions.set(region.id, new VoiceRegion(region)); + return regions; + }); + } + sendMessage(channel, content, { tts, nonce, embed, disableEveryone, split, code, reply } = {}, file = null) { return new Promise((resolve, reject) => { // eslint-disable-line complexity if (typeof content !== 'undefined') content = this.client.resolver.resolveString(content); diff --git a/src/structures/Guild.js b/src/structures/Guild.js index fef675a0a..dff0f610a 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -322,6 +322,14 @@ class Guild { return this.client.rest.methods.getGuildWebhooks(this); } + /** + * Fetch available voice regions + * @returns {Collection} + */ + fetchVoiceRegions() { + return this.client.rest.methods.fetchVoiceRegions(this.id); + } + /** * Fetch a single guild member from a user. * @param {UserResolvable} user The user to fetch the member for diff --git a/src/structures/Message.js b/src/structures/Message.js index 252ca98d6..45e7d7efe 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -540,7 +540,7 @@ class Message { } _addReaction(emoji, user) { - const emojiID = emoji.identifier; + const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : encodeURIComponent(emoji.name); let reaction; if (this.reactions.has(emojiID)) { reaction = this.reactions.get(emojiID); @@ -549,16 +549,13 @@ class Message { reaction = new MessageReaction(this, emoji, 0, user.id === this.client.user.id); this.reactions.set(emojiID, reaction); } - if (!reaction.users.has(user.id)) { - reaction.users.set(user.id, user); - reaction.count++; - return reaction; - } - return null; + if (!reaction.users.has(user.id)) reaction.users.set(user.id, user); + reaction.count++; + return reaction; } _removeReaction(emoji, user) { - const emojiID = emoji.identifier; + const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : encodeURIComponent(emoji.name); if (this.reactions.has(emojiID)) { const reaction = this.reactions.get(emojiID); if (reaction.users.has(user.id)) { diff --git a/src/structures/MessageEmbed.js b/src/structures/MessageEmbed.js index 1249c422b..0343b511a 100644 --- a/src/structures/MessageEmbed.js +++ b/src/structures/MessageEmbed.js @@ -1,5 +1,6 @@ /** * Represents an embed in a message (image/video preview, rich embed, etc.) + * This class is only used for *recieved* embeds. If you wish to send one, use the {@link RichEmbed} class. */ class MessageEmbed { constructor(message, data) { diff --git a/src/structures/VoiceChannel.js b/src/structures/VoiceChannel.js index e6d5b637f..b69279c8e 100644 --- a/src/structures/VoiceChannel.js +++ b/src/structures/VoiceChannel.js @@ -50,7 +50,7 @@ class VoiceChannel extends GuildChannel { * @type {boolean} */ get full() { - return this.members.size >= this.userLimit; + return this.userLimit > 0 && this.members.size >= this.userLimit; } /** diff --git a/src/structures/VoiceRegion.js b/src/structures/VoiceRegion.js new file mode 100644 index 000000000..ee53e7861 --- /dev/null +++ b/src/structures/VoiceRegion.js @@ -0,0 +1,50 @@ +/** + * Represents a Discord voice region for guilds + */ +class VoiceRegion { + constructor(data) { + /** + * ID of the region + * @type {string} + */ + this.id = data.id; + + /** + * Name of the region + * @type {string} + */ + this.name = data.name; + + /** + * Whether the region is VIP-only + * @type {boolean} + */ + this.vip = data.vip; + + /** + * Whether the region is deprecated + * @type {boolean} + */ + this.deprecated = data.deprecated; + + /** + * Whether the region is optimal + * @type {boolean} + */ + this.optimal = data.optimal; + + /** + * Whether the region is custom + * @type {boolean} + */ + this.custom = data.custom; + + /** + * A sample hostname for what a connection might look like + * @type {string} + */ + this.sampleHostname = data.sample_hostname; + } +} + +module.exports = VoiceRegion; diff --git a/src/util/Constants.js b/src/util/Constants.js index 5d9d7fecc..3bfc67520 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -105,6 +105,8 @@ const Endpoints = exports.Endpoints = { relationships: (userID) => `${Endpoints.user(userID)}/relationships`, note: (userID) => `${Endpoints.me}/notes/${userID}`, + voiceRegions: `${API}/voice/regions`, + // guilds guilds: `${API}/guilds`, guild: (guildID) => `${Endpoints.guilds}/${guildID}`, @@ -124,6 +126,7 @@ const Endpoints = exports.Endpoints = { guildChannels: (guildID) => `${Endpoints.guild(guildID)}/channels`, guildEmojis: (guildID) => `${Endpoints.guild(guildID)}/emojis`, guildSearch: (guildID) => `${Endpoints.guild(guildID)}/messages/search`, + guildVoiceRegions: (guildID) => `${Endpoints.guild(guildID)}/regions`, // channels channels: `${API}/channels`,