UNPKG

discord.js-music-hiico

Version:

Edit of discord.js-music-v11

367 lines (327 loc) 10.3 kB
const YoutubeDL = require('youtube-dl'); const ytdl = require('ytdl-core'); var hc = 0xc4ffe1 /** * Takes a discord.js client and turns it into a music bot. * Thanks to 'derekmartinez18' for helping. * * @param {Client} client - The discord.js client. * @param {object} options - (Optional) Options to configure the music bot. Acceptable options are: * prefix: The prefix to use for the commands (default '!'). * global: Whether to use a global queue instead of a server-specific queue (default false). * maxQueueSize: The maximum queue size (default 20). * anyoneCanSkip: Allow anybody to skip the song. * clearInvoker: Clear the command message. * volume: The default volume of the player. */ module.exports = function (client, options) { // Get all options. let PREFIX = (options && options.prefix) || '_'; let GLOBAL = (options && options.global) || false; let MAX_QUEUE_SIZE = (options && options.maxQueueSize) || 20; let DEFAULT_VOLUME = (options && options.volume) || 50; let ALLOW_ALL_SKIP = (options && options.anyoneCanSkip) || false; let CLEAR_INVOKER = (options && options.clearInvoker) || false; // Create an object of queues. let queues = {}; // Catch message events. client.on('message', msg => { const message = msg.content.trim(); // Check if the message is a command. if (message.toLowerCase().startsWith(PREFIX.toLowerCase())) { // Get the command and suffix. const command = message.substring(PREFIX.length).split(/[ \n]/)[0].toLowerCase().trim(); const suffix = message.substring(PREFIX.length + command.length).trim(); // Process the commands. switch (command) { case 'play': return play(msg, suffix); case 'skip': return skip(msg, suffix); case 'volume': return volume(msg, suffix); } if (CLEAR_INVOKER) { msg.delete(); } } }); /** * Checks if a user is an admin. * * @param {GuildMember} member - The guild member * @returns {boolean} - */ function isAdmin(member) { return member.hasPermission("ADMINISTRATOR"); } /** * Checks if the user can skip the song. * * @param {GuildMember} member - The guild member * @param {array} queue - The current queue * @returns {boolean} - If the user can skip */ function canSkip(member, queue) { if (ALLOW_ALL_SKIP) return true; else if (queue[0].requester === member.id) return true; else if (isAdmin(member)) return true; else return false; } /** * Gets the song queue of the server. * * @param {integer} server - The server id. * @returns {object} - The song queue. */ function getQueue(server) { // Check if global queues are enabled. if (GLOBAL) server = '_'; // Change to global queue. // Return the queue. if (!queues[server]) queues[server] = []; return queues[server]; } /** * The command for adding a song to the queue. * * @param {Message} msg - Original message. * @param {string} suffix - Command suffix. * @returns {<promise>} - The response edit. */ function play(msg, suffix) { // Make sure the user is in a voice channel. if (msg.member.voiceChannel === undefined) return msg.channel.send({ embed: { color: hc, title: ":no_entry_sign: Tu n'es pas connecté à un Salon Vocal.", } }); // Make sure the suffix exists. if (!suffix) return msg.channel.send({ embed: { color: hc, title: ":no_entry_sign: Aucune vidéo spécifiée.", } }); // Get the queue. const queue = getQueue(msg.guild.id); // Check if the queue has reached its maximum size. if (queue.length >= MAX_QUEUE_SIZE) { return msg.channel.send({ embed: { color: hc, title: "Taille maximum de la liste d'attente atteinte.", } }); } // Get the video information. msg.channel.send({ embed: { color: hc, title: ':mag_right: Recherche...', } }).then(response => { var searchstring = suffix if (!suffix.toLowerCase().startsWith('http')) { searchstring = 'gvsearch1:' + suffix; } YoutubeDL.getInfo(searchstring, ['-q', '--no-warnings', '--force-ipv4'], (err, info) => { // Verify the info. if (err || info.format_id === undefined || info.format_id.startsWith('0')) { return msg.channel.send({ embed: { color: hc, title: ":no_entry_sign: Vidéo invalide.", } }); } info.requester = msg.author.id; // Queue the video. msg.channel.send({ embed: { color: hc, title: "Queued : " + info.title, } }).then(() => { queue.push(info); // Play if only one element in the queue. if (queue.length === 1) executeQueue(msg, queue); }).catch(console.log); }); }).catch(console.log); } /** * The command for skipping a song. * * @param {Message} msg - Original message. * @param {string} suffix - Command suffix. * @returns {<promise>} - The response message. */ function skip(msg, suffix) { // Get the voice connection. const voiceConnection = client.voiceConnections.find(val => val.channel.guild.id == msg.guild.id); if (voiceConnection === null) return msg.channel.send({ embed: { color: hc, title: "Aucune musique n'est présentement jouée.", } }); // Get the queue. const queue = getQueue(msg.guild.id); if (!canSkip(msg.member, queue)) return msg.channel.send({ embed: { color: hc, title: ":no_entry_sign: Impossible de skip la musique.", } }).then((response) => { response.delete(5000); }); // Get the number to skip. let toSkip = 1; // Default 1. if (!isNaN(suffix) && parseInt(suffix) > 0) { toSkip = parseInt(suffix); } toSkip = Math.min(toSkip, queue.length); // Skip. queue.splice(0, toSkip - 1); // Resume and stop playing. const dispatcher = voiceConnection.player.dispatcher; if (voiceConnection.paused) dispatcher.resume(); dispatcher.end(); msg.channel.send({ embed: { color: hc, title: "Skipped : " + toSkip, } }); } /** * The command for changing the song volume. * * @param {Message} msg - Original message. * @param {string} suffix - Command suffix. * @returns {<promise>} - The response message. */ function volume(msg, suffix) { // Get the voice connection. const voiceConnection = client.voiceConnections.find(val => val.channel.guild.id == msg.guild.id); if (voiceConnection === null) return msg.channel.send({ embed: { color: hc, title: "Aucune musique n'est présentement jouée.", } }); if (!isAdmin(msg.member)) return msg.channel.send({ embed: { color: hc, title: ":no_entry_sign: Tu n'es pas authorisé à utiliser cette commande.", } }); // Get the dispatcher const dispatcher = voiceConnection.player.dispatcher; if (suffix > 200 || suffix < 0) return msg.channel.send({ embed: { color: hc, title: "Son trops fort !", } }); msg.channel.send({ embed: { color: hc, title: "Volume réglé à : " + suffix, } }); dispatcher.setVolume((suffix/100)); } /** * Executes the next song in the queue. * * @param {Message} msg - Original message. * @param {object} queue - The song queue for this server. * @returns {<promise>} - The voice channel. */ function executeQueue(msg, queue) { // If the queue is empty, finish. if (queue.length === 0) { msg.channel.send({ embed: { color: hc, title: "Playback finished.", } }); // Leave the voice channel. const voiceConnection = client.voiceConnections.find(val => val.channel.guild.id == msg.guild.id); if (voiceConnection !== null) return voiceConnection.disconnect(); } new Promise((resolve, reject) => { // Join the voice channel if not already in one. const voiceConnection = client.voiceConnections.find(val => val.channel.guild.id == msg.guild.id); if (voiceConnection === null) { // Check if the user is in a voice channel. if (msg.member.voiceChannel) { msg.member.voiceChannel.join().then(connection => { resolve(connection); }).catch((error) => { console.log(error); }); } else { // Otherwise, clear the queue and do nothing. queue.splice(0, queue.length); reject(); } } else { resolve(voiceConnection); } }).then(connection => { // Get the first item in the queue. const video = queue[0]; console.log(video.webpage_url); // Play the video. msg.channel.send({ embed: { color: hc, title: "Now Playing : " + video.title, } }).then(() => { let dispatcher = connection.playStream(ytdl(video.webpage_url, {filter: 'audioonly'}), {seek: 0, volume: (DEFAULT_VOLUME/100)}); connection.on('error', (error) => { // Skip to the next song. console.log(error); queue.shift(); executeQueue(msg, queue); }); dispatcher.on('error', (error) => { // Skip to the next song. console.log(error); queue.shift(); executeQueue(msg, queue); }); dispatcher.on('end', () => { // Wait a second. setTimeout(() => { if (queue.length > 0) { // Remove the song from the queue. queue.shift(); // Play the next song in the queue. executeQueue(msg, queue); } }, 1000); }); }).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); }); } } /** * Wrap text in a code block and escape grave characters. * * @param {string} text - The input text. * @returns {string} - The wrapped text. */ function wrap(text) { return '```\n' + text.replace(/`/g, '`' + String.fromCharCode(8203)) + '\n```'; }