UNPKG

selfbot-discord

Version:
377 lines (341 loc) • 11.6 kB
const path = require('path'); const fs = require('fs'); const snekfetch = require('snekfetch'); const Constants = require('../util/Constants'); const convertToBuffer = require('../util/Util').convertToBuffer; const User = require('../structures/User'); const Message = require('../structures/Message'); const Guild = require('../structures/Guild'); const Channel = require('../structures/Channel'); const GuildMember = require('../structures/GuildMember'); const Emoji = require('../structures/Emoji'); const ReactionEmoji = require('../structures/ReactionEmoji'); const Role = require('../structures/Role'); /** * The DataResolver identifies different objects and tries to resolve a specific piece of information from them, e.g. * extracting a User from a Message object. * @private */ class ClientDataResolver { /** * @param {Client} client The client the resolver is for */ constructor(client) { this.client = client; } /** * Data that resolves to give a User object. This can be: * * A User object * * A Snowflake * * A Message object (resolves to the message author) * * A Guild object (owner of the guild) * * A GuildMember object * @typedef {User|Snowflake|Message|Guild|GuildMember} UserResolvable */ /** * Resolves a UserResolvable to a User object. * @param {UserResolvable} user The UserResolvable to identify * @returns {?User} */ resolveUser(user) { if (user instanceof User) return user; if (typeof user === 'string') return this.client.users.get(user) || null; if (user instanceof GuildMember) return user.user; if (user instanceof Message) return user.author; if (user instanceof Guild) return user.owner; return null; } /** * Resolves a UserResolvable to a user ID string. * @param {UserResolvable} user The UserResolvable to identify * @returns {?Snowflake} */ resolveUserID(user) { if (user instanceof User || user instanceof GuildMember) return user.id; if (typeof user === 'string') return user || null; if (user instanceof Message) return user.author.id; if (user instanceof Guild) return user.ownerID; return null; } /** * Data that resolves to give a Guild object. This can be: * * A Guild object * * A Snowflake * @typedef {Guild|Snowflake} GuildResolvable */ /** * Resolves a GuildResolvable to a Guild object. * @param {GuildResolvable} guild The GuildResolvable to identify * @returns {?Guild} */ resolveGuild(guild) { if (guild instanceof Guild) return guild; if (typeof guild === 'string') return this.client.guilds.get(guild) || null; return null; } /** * Data that resolves to give a GuildMember object. This can be: * * A GuildMember object * * A User object * @typedef {GuildMember|User} GuildMemberResolvable */ /** * Resolves a GuildMemberResolvable to a GuildMember object. * @param {GuildResolvable} guild The guild that the member is part of * @param {UserResolvable} user The user that is part of the guild * @returns {?GuildMember} */ resolveGuildMember(guild, user) { if (user instanceof GuildMember) return user; guild = this.resolveGuild(guild); user = this.resolveUser(user); if (!guild || !user) return null; return guild.members.get(user.id) || null; } /** * Data that can be resolved to a Role object. This can be: * * A Role * * A Snowflake * @typedef {Role|Snowflake} RoleResolvable */ /** * Resolves a RoleResolvable to a Role object. * @param {GuildResolvable} guild The guild that this role is part of * @param {RoleResolvable} role The role resolvable to resolve * @returns {?Role} */ resolveRole(guild, role) { if (role instanceof Role) return role; guild = this.resolveGuild(guild); if (!guild) return null; if (typeof role === 'string') return guild.roles.get(role); return null; } /** * Data that can be resolved to give a Channel object. This can be: * * A Channel object * * A Message object (the channel the message was sent in) * * A Guild object (the #general channel) * * A Snowflake * @typedef {Channel|Guild|Message|Snowflake} ChannelResolvable */ /** * Resolves a ChannelResolvable to a Channel object. * @param {ChannelResolvable} channel The channel resolvable to resolve * @returns {?Channel} */ resolveChannel(channel) { if (channel instanceof Channel) return channel; if (typeof channel === 'string') return this.client.channels.get(channel) || null; if (channel instanceof Message) return channel.channel; if (channel instanceof Guild) return channel.channels.get(channel.id) || null; return null; } /** * Resolves a ChannelResolvable to a channel ID. * @param {ChannelResolvable} channel The channel resolvable to resolve * @returns {?Snowflake} */ resolveChannelID(channel) { if (channel instanceof Channel) return channel.id; if (typeof channel === 'string') return channel; if (channel instanceof Message) return channel.channel.id; if (channel instanceof Guild) return channel.defaultChannel.id; return null; } /** * Data that can be resolved to give an invite code. This can be: * * An invite code * * An invite URL * @typedef {string} InviteResolvable */ /** * Resolves InviteResolvable to an invite code. * @param {InviteResolvable} data The invite resolvable to resolve * @returns {string} */ resolveInviteCode(data) { const inviteRegex = /discord(?:app\.com\/invite|\.gg(?:\/invite)?)\/([\w-]{2,255})/i; const match = inviteRegex.exec(data); if (match && match[1]) return match[1]; return data; } /** * Data that can be resolved to give a string. This can be: * * A string * * An array (joined with a new line delimiter to give a string) * * Any value * @typedef {string|Array|*} StringResolvable */ /** * Resolves a StringResolvable to a string. * @param {StringResolvable} data The string resolvable to resolve * @returns {string} */ resolveString(data) { if (typeof data === 'string') return data; if (data instanceof Array) return data.join('\n'); return String(data); } /** * Resolves a Base64Resolvable, a string, or a BufferResolvable to a Base 64 image. * @param {BufferResolvable|Base64Resolvable} image The image to be resolved * @returns {Promise<?string>} */ resolveImage(image) { if (!image) return Promise.resolve(null); if (typeof image === 'string' && image.startsWith('data:')) { return Promise.resolve(image); } return this.resolveFile(image).then(this.resolveBase64); } /** * Data that resolves to give a Base64 string, typically for image uploading. This can be: * * A Buffer * * A base64 string * @typedef {Buffer|string} Base64Resolvable */ /** * Resolves a Base64Resolvable to a Base 64 image. * @param {Base64Resolvable} data The base 64 resolvable you want to resolve * @returns {?string} */ resolveBase64(data) { if (data instanceof Buffer) return `data:image/jpg;base64,${data.toString('base64')}`; return data; } /** * Data that can be resolved to give a Buffer. This can be: * * A Buffer * * The path to a local file * * A URL * * A Stream * @typedef {string|Buffer} BufferResolvable */ /** * @external Stream * @see {@link https://nodejs.org/api/stream.html} */ /** * Resolves a BufferResolvable to a Buffer. * @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve * @returns {Promise<Buffer>} */ resolveFile(resource) { if (resource instanceof Buffer) return Promise.resolve(resource); if (this.client.browser && resource instanceof ArrayBuffer) return Promise.resolve(convertToBuffer(resource)); if (typeof resource === 'string') { if (/^https?:\/\//.test(resource)) { return snekfetch.get(resource).then(res => res.body instanceof Buffer ? res.body : Buffer.from(res.text)); } return new Promise((resolve, reject) => { const file = path.resolve(resource); fs.stat(file, (err, stats) => { if (err) return reject(err); if (!stats || !stats.isFile()) return reject(new Error(`The file could not be found: ${file}`)); fs.readFile(file, (err2, data) => { if (err2) reject(err2); else resolve(data); }); return null; }); }); } else if (resource && resource.pipe && typeof resource.pipe === 'function') { return new Promise((resolve, reject) => { const buffers = []; resource.once('error', reject); resource.on('data', data => buffers.push(data)); resource.once('end', () => resolve(Buffer.concat(buffers))); }); } return Promise.reject(new TypeError('The resource must be a string or Buffer.')); } /** * Data that can be resolved to give an emoji identifier. This can be: * * The unicode representation of an emoji * * A custom emoji ID * * An Emoji object * * A ReactionEmoji object * @typedef {string|Emoji|ReactionEmoji} EmojiIdentifierResolvable */ /** * Resolves an EmojiResolvable to an emoji identifier. * @param {EmojiIdentifierResolvable} emoji The emoji resolvable to resolve * @returns {?string} */ resolveEmojiIdentifier(emoji) { if (emoji instanceof Emoji || emoji instanceof ReactionEmoji) return emoji.identifier; if (typeof emoji === 'string') { if (this.client.emojis.has(emoji)) return this.client.emojis.get(emoji).identifier; else if (!emoji.includes('%')) return encodeURIComponent(emoji); else return emoji; } return null; } /** * Can be a Hex Literal, Hex String, Number, RGB Array, or one of the following * ``` * [ * 'DEFAULT', * 'WHITE', * 'AQUA', * 'GREEN', * 'BLUE', * 'PURPLE', * 'LUMINOUS_VIVID_PINK', * 'GOLD', * 'ORANGE', * 'RED', * 'GREY', * 'DARKER_GREY', * 'NAVY', * 'DARK_AQUA', * 'DARK_GREEN', * 'DARK_BLUE', * 'DARK_PURPLE', * 'DARK_VIVID_PINK', * 'DARK_GOLD', * 'DARK_ORANGE', * 'DARK_RED', * 'DARK_GREY', * 'LIGHT_GREY', * 'DARK_NAVY', * 'RANDOM', * ] * ``` * or something like * ``` * [255, 0, 255] * ``` * for purple * @typedef {string|number|Array} ColorResolvable */ /** * Resolves a ColorResolvable into a color number. * @param {ColorResolvable} color Color to resolve * @returns {number} A color */ static resolveColor(color) { if (typeof color === 'string') { if (color === 'RANDOM') return Math.floor(Math.random() * (0xFFFFFF + 1)); if (color === 'DEFAULT') return 0; color = Constants.Colors[color] || parseInt(color.replace('#', ''), 16); } else if (color instanceof Array) { color = (color[0] << 16) + (color[1] << 8) + color[2]; } if (color < 0 || color > 0xFFFFFF) { throw new RangeError('Color must be within the range 0 - 16777215 (0xFFFFFF).'); } else if (color && isNaN(color)) { throw new TypeError('Unable to convert color to a number.'); } return color; } /** * @param {ColorResolvable} color Color to resolve * @returns {number} A color */ resolveColor(color) { return this.constructor.resolveColor(color); } } module.exports = ClientDataResolver;