├── .env_example ├── .gitignore ├── index.js ├── README.md ├── events ├── clientEvents │ ├── ready.js │ ├── msg.js │ └── voiceStateUpdate.js ├── dispatcherEvents │ ├── error.js │ └── finish.js └── events.js ├── struct ├── funcs │ ├── shuffle.js │ ├── end.js │ ├── exe.js │ ├── msToTime.js │ ├── handleVideo.js │ └── play.js ├── client.js └── config │ └── messages.js ├── commands ├── replay.js ├── shuffle.js ├── resume.js ├── pause.js ├── loop.js ├── previous.js ├── loopsong.js ├── stop.js ├── volume.js ├── skipto.js ├── remove.js ├── seek.js ├── queue.js ├── skip.js ├── nowplaying.js ├── help.js ├── search.js └── play.js ├── package.json ├── LICENSE └── config.js /.env_example: -------------------------------------------------------------------------------- 1 | TOKEN= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | package-lock.json 3 | .env -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const MusicClient = require("./struct/client.js"); 2 | const client = new MusicClient({}); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Music-Bot 2 | 3 | A simple discord music bot built from Musix V3.6 4 | 5 | ## Installation 6 | 7 | npm install (idk how yarn works) 8 | 9 | ## Usage 10 | 11 | Start with npm start 12 | 13 | Be sure to fill out the requiered fields in .env_example and rename the file to .env 14 | -------------------------------------------------------------------------------- /events/clientEvents/ready.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "ready", 3 | async execute(client) { 4 | client.user.setActivity(`@${client.user.username} help | 🎶`, { 5 | type: "LISTENING", 6 | }); 7 | client.user.setStatus("online"); 8 | console.log(`- Activated -`); 9 | }, 10 | }; -------------------------------------------------------------------------------- /events/dispatcherEvents/error.js: -------------------------------------------------------------------------------- 1 | module.exports = async function (client, error, guild) { 2 | const queue = client.queue.get(guild.id); 3 | console.error(error); 4 | queue.voiceChannel.leave(); 5 | client.queue.delete(guild.id); 6 | return queue.textChannel.send(client.messages.errorDispatcher + `\`${error}\``); 7 | }; -------------------------------------------------------------------------------- /struct/funcs/shuffle.js: -------------------------------------------------------------------------------- 1 | module.exports = function (a) { 2 | for (let i = a.length - 1; i > 1; i--) { 3 | const j = Math.floor(Math.random() * (i + 1)); 4 | if (i === 0 || j === 0) { 5 | console.log(`J or I is 0. I: ${i} J: ${j}`); 6 | } else { 7 | [a[i], a[j]] = [a[j], a[i]]; 8 | } 9 | } 10 | return a; 11 | }; -------------------------------------------------------------------------------- /commands/replay.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'replay', 3 | alias: ["rp"], 4 | usage: '', 5 | description: 'Replay the currently playing song.', 6 | category: 'music', 7 | async execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | queue.endReason = "replay"; 10 | queue.connection.dispatcher.end() 11 | } 12 | }; -------------------------------------------------------------------------------- /commands/shuffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'shuffle', 3 | alias: ["none"], 4 | usage: '', 5 | description: 'Shuffle the queue.', 6 | category: 'music', 7 | execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | client.funcs.shuffle(queue.songs); 10 | msg.channel.send(client.messages.shuffled); 11 | } 12 | }; -------------------------------------------------------------------------------- /struct/funcs/end.js: -------------------------------------------------------------------------------- 1 | module.exports = async function (client, msg, pos, command) { 2 | const seek = parseInt(pos); 3 | const queue = client.queue.get(msg.guild.id); 4 | if (command.name === "seek") { 5 | queue.time = pos * 1000; 6 | } else { 7 | queue.time = queue.connection.dispatcher.streamTime + queue.time; 8 | } 9 | queue.connection.dispatcher.end(); 10 | queue.endReason = "seek"; 11 | client.funcs.play(msg.guild, queue.songs[0], client, seek, false); 12 | }; 13 | -------------------------------------------------------------------------------- /commands/resume.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'resume', 3 | alias: ["continue"], 4 | usage: '', 5 | description: 'Resume the paused music.', 6 | category: 'music', 7 | execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (!queue.paused) return msg.channel.send(client.messages.notPaused); 10 | queue.paused = false; 11 | queue.connection.dispatcher.resume(true); 12 | return msg.channel.send(client.messages.resumed); 13 | } 14 | }; -------------------------------------------------------------------------------- /commands/pause.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'pause', 3 | alias: ["none"], 4 | usage: '', 5 | description: 'Pause the currently playing music.', 6 | category: 'music', 7 | execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (queue.paused) return msg.channel.send(client.messages.alreadyPaused); 10 | queue.paused = true; 11 | queue.connection.dispatcher.pause(true); 12 | return msg.channel.send(client.messages.paused); 13 | } 14 | }; -------------------------------------------------------------------------------- /commands/loop.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'loop', 3 | alias: [], 4 | usage: '', 5 | description: 'loop the queue.', 6 | category: 'music', 7 | async execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (!queue.looping) { 10 | queue.looping = true; 11 | msg.channel.send(client.messages.looping); 12 | } else { 13 | queue.looping = false; 14 | msg.channel.send(client.messages.noLooping); 15 | } 16 | } 17 | }; -------------------------------------------------------------------------------- /commands/previous.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'previous', 3 | alias: ["prev", "return", "back"], 4 | usage: '', 5 | description: 'Play the previous song.', 6 | category: 'music', 7 | async execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id) 9 | if (queue.prevSongs.length < 1) return msg.channel.send(client.messages.noPreviousSongs); 10 | queue.endReason = "previous"; 11 | queue.connection.dispatcher.end() 12 | msg.channel.send(client.messages.previousSong) 13 | } 14 | }; -------------------------------------------------------------------------------- /struct/funcs/exe.js: -------------------------------------------------------------------------------- 1 | module.exports = function (msg, args, client, Discord, command) { 2 | const permissions = msg.channel.permissionsFor(msg.client.user); 3 | if (!permissions.has("EMBED_LINKS")) 4 | return msg.channel.send(client.messages.noPermsEmbed); 5 | if (!permissions.has("USE_EXTERNAL_EMOJIS")) 6 | return msg.channel.send(client.noPermsUseExternalEmojis); 7 | try { 8 | command.uses++; 9 | command.execute(msg, args, client, Discord, command); 10 | } catch (error) { 11 | msg.reply(client.messages.errorExe); 12 | console.error(error); 13 | } 14 | }; -------------------------------------------------------------------------------- /commands/loopsong.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'loopsong', 3 | alias: ["none"], 4 | usage: '', 5 | description: 'loop the currently playing song.', 6 | category: 'music', 7 | async execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (!queue.songLooping) { 10 | queue.songLooping = true; 11 | let message; 12 | message = client.messages.loopingSong.replace("%TITLE%", queue.songs[0].title); 13 | msg.channel.send(message); 14 | } else { 15 | queue.songLooping = false; 16 | msg.channel.send(client.messages.noLoopingSong); 17 | } 18 | } 19 | }; -------------------------------------------------------------------------------- /events/dispatcherEvents/finish.js: -------------------------------------------------------------------------------- 1 | module.exports = async function (client, reason, guild) { 2 | const queue = client.queue.get(guild.id); 3 | queue.playing = false; 4 | if (reason === "seek") { 5 | return (queue.playing = true); 6 | } 7 | 8 | if (!queue.songLooping) { 9 | if (queue.looping) { 10 | queue.songs.push(queue.songs[0]); 11 | } 12 | 13 | queue.time = 0; 14 | queue.votes = 0; 15 | queue.voters = []; 16 | if (reason !== "replay") { 17 | if (reason === "previous") queue.songs.unshift(queue.prevSongs.pop()) 18 | if (reason !== "previous") queue.prevSongs.push(queue.songs.shift()); 19 | } 20 | } 21 | client.funcs.play(guild, queue.songs[0], client, 0, true); 22 | }; -------------------------------------------------------------------------------- /commands/stop.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'stop', 3 | description: 'Stop the music and clear the queue.', 4 | alias: ["none"], 5 | usage: '', 6 | category: 'music', 7 | execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (msg.content.includes("-force")) { 10 | if (queue) { 11 | queue.voiceChannel.leave(); 12 | queue.exists = false; 13 | } 14 | if (msg.guild.voice.channel) msg.guild.voice.channel.leave(); 15 | client.queue.delete(guild.id); 16 | return msg.channel.send(client.messages.stop); 17 | } 18 | queue.songs = []; 19 | queue.looping = false; 20 | queue.endReason = "stop"; 21 | queue.connection.dispatcher.end(); 22 | msg.channel.send(client.messages.stop); 23 | } 24 | }; -------------------------------------------------------------------------------- /struct/funcs/msToTime.js: -------------------------------------------------------------------------------- 1 | module.exports = function msToTime(duration, format) { 2 | var seconds = Math.floor((duration / 1000) % 60), 3 | minutes = Math.floor((duration / (1000 * 60)) % 60), 4 | hours = Math.floor((duration / (1000 * 60 * 60)) % 24), 5 | days = Math.floor((duration / (1000 * 60 * 60 * 24)) % 24); 6 | 7 | days = (days < 10) ? "0" + days : days; 8 | hours = (hours < 10) ? "0" + hours : hours; 9 | minutes = (minutes < 10) ? "0" + minutes : minutes; 10 | seconds = (seconds < 10) ? "0" + seconds : seconds; 11 | 12 | if (format === "hh:mm:ss") { 13 | return `${hours}:${minutes}:${seconds}`; 14 | } else if (format === "dd:hh:mm:ss") { 15 | return `${days}:${hours}:${minutes}:${seconds}`; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /events/events.js: -------------------------------------------------------------------------------- 1 | module.exports = function (client) { 2 | const Discord = require('discord.js'); 3 | const events = './clientEvents/'; 4 | client.on('ready', () => { 5 | require(`${events}ready.js`).execute(client); 6 | }); 7 | client.on('message', (msg) => { 8 | require(`${events}msg.js`).execute(client, msg, Discord); 9 | }); 10 | client.on('guildCreate', (guild) => { 11 | require(`${events}guildCreate.js`).execute(client, guild); 12 | }); 13 | client.on('voiceStateUpdate', (oldState, newState) => { 14 | require(`${events}voiceStateUpdate.js`).execute(client, oldState, newState); 15 | }); 16 | client.on('error', (error) => { 17 | client.channels.fetch(client.config.debug_channel).send(`Error: ${error} on shard: ${client.shard}`); 18 | }); 19 | } -------------------------------------------------------------------------------- /commands/volume.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'volume', 3 | description: 'Volume command.', 4 | alias: ["none"], 5 | usage: '', 6 | cooldown: 5, 7 | category: 'music', 8 | execute(msg, args, client, Discord, command) { 9 | const queue = client.queue.get(msg.guild.id); 10 | if (!args[1] && queue) return msg.channel.send(`${client.messages.currentVolume}**${queue.volume}**`); 11 | const volume = parseFloat(args[1]); 12 | if (isNaN(volume)) return msg.channel.send(client.messages.validNumber); 13 | if (volume > 100) return msg.channel.send(client.messages.maxVolume); 14 | if (volume < 0) return msg.channel.send(client.messages.positiveVolume); 15 | queue.volume = volume; 16 | queue.connection.dispatcher.setVolume(volume / 100); 17 | return msg.channel.send(`${client.messages.setVolume}**${volume}**`); 18 | } 19 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "music-bot", 3 | "version": "3.6.1", 4 | "description": "A simple discord music bot built from Musix V3.6", 5 | "main": "./index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/MatteZ02/Music-Bot.git" 12 | }, 13 | "author": "Matte", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/MatteZ02/Music-Bot/issues" 17 | }, 18 | "homepage": "https://github.com/MatteZ02/Music-Bot#readme", 19 | "dependencies": { 20 | "@discordjs/opus": "^0.2.1", 21 | "discord.js": "^12.4.1", 22 | "dotenv": "^8.2.0", 23 | "fs": "0.0.1-security", 24 | "prism-media": "^1.2.2", 25 | "ytdl-core": "^4.0.3", 26 | "ytpl": "^1.0.1", 27 | "ytsr": "^0.1.21" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /commands/skipto.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "skipto", 3 | alias: ["st"], 4 | usage: "", 5 | description: "Skip to a point in the queue", 6 | category: "music", 7 | async execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (!args[1]) 10 | return msg.channel.send( 11 | `${client.messages.correctUsage}\`${command.usage}\`` 12 | ); 13 | let point = parseInt(args[1]); 14 | point = point - 1; 15 | if (isNaN(point)) return msg.channel.send(client.messages.validNumber); 16 | if (point > queue.songs.size) 17 | return msg.channel.send(client.messages.noSongs); 18 | if (point < 0) return msg.channel.send(client.messages.cantSkipToCurrent); 19 | for (let i = 0; i < point; i++) { 20 | queue.prevSongs.push(queue.songs.shift()); 21 | } 22 | queue.endReason = "skipto"; 23 | queue.time = 0; 24 | queue.connection.dispatcher.end(); 25 | }, 26 | }; -------------------------------------------------------------------------------- /commands/remove.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "remove", 3 | alias: ["rm", "delete", "del"], 4 | usage: "", 5 | description: "Remove a song from the queue", 6 | category: "music", 7 | execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (!args[1]) return msg.channel.send(client.messages.provideASong); 10 | const pos = parseInt(args[1]); 11 | if (isNaN(pos)) return msg.channel.send(client.messages.validNumber); 12 | if (pos < 1) return msg.channel.send(client.messages.noSongs); 13 | let message1; 14 | let message2; 15 | message1 = client.messages.queueLength.replace( 16 | "%SONGS%", 17 | queue.songs.length - 1 18 | ); 19 | if (pos < 0) return msg.channel.send(client.messages.noSongsInQueue); 20 | if (pos >= queue.songs.length) return msg.channel.send(message1); 21 | message2 = client.messages.removed.replace( 22 | "%SONG%", 23 | queue.songs[pos].title 24 | ); 25 | msg.channel.send(message2); 26 | return queue.songs.splice(pos, 1); 27 | }, 28 | }; -------------------------------------------------------------------------------- /commands/seek.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "seek", 3 | alias: ["none"], 4 | usage: "", 5 | description: "Seek to a specific point in the currently playing song.", 6 | category: "music", 7 | async execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (queue.nigthCore) 10 | return msg.channel.send(client.messages.disableNigthCore); 11 | if (!args[1]) 12 | return msg.channel.send( 13 | `${client.messages.correctUsage}\`${ 14 | client.config.prefix 15 | }seek ${command.usage}\`` 16 | ); 17 | const pos = parseInt(args[1]); 18 | if (isNaN(pos)) { 19 | if (pos < 0) 20 | return msg.channel.send(client.messages.seekingPointPositive); 21 | let message; 22 | message = client.messages.seekMax.replace( 23 | "%LENGTH%", 24 | queue.songs[0].info.lengthSeconds 25 | ); 26 | if (pos > queue.songs[0].info.lengthSeconds) return msg.channel.send(message); 27 | } 28 | client.funcs.end(client, msg, pos, command); 29 | }, 30 | }; -------------------------------------------------------------------------------- /commands/queue.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'queue', 3 | alias: ["q", "list", "ls", "songs"], 4 | usage: '', 5 | description: 'See the queue.', 6 | category: 'music', 7 | async execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (!queue) return msg.channel.send(client.messages.noServerQueue); 10 | const page = 1; 11 | let queuesongs = queue.songs.slice((page - 1) * 20 + 1, page * 20 + 1); 12 | let queuemessage = `${queuesongs.map(song => `**#** ${song.title}`).join('\n')}` 13 | const hashs = queuemessage.split('**#**').length; 14 | for (let i = 0; i < hashs; i++) { 15 | queuemessage = queuemessage.replace('**#**', `**${i + 1}**`); 16 | } 17 | let message; 18 | message = client.messages.queueDesc.replace("%SONG%", queue.songs[0].title); 19 | const embed = new Discord.MessageEmbed() 20 | .setTitle(client.messages.queueTitle) 21 | .setDescription(`${message}\n${queuemessage}`) 22 | .setFooter(`${queue.songs.length - 1} ${client.messages.queueFooter}`) 23 | .setColor(client.config.embedColor) 24 | return msg.channel.send(embed); 25 | } 26 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Matte 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | require("dotenv/config"); 2 | 3 | module.exports = { 4 | token: process.env.TOKEN, 5 | embedColor: "#b50002", 6 | prefix: "!", 7 | }; 8 | 9 | module.exports.streamConfig = { 10 | ytdlOptions: { 11 | filter: "audio", 12 | highWaterMark: 1 << 15, 13 | volume: false, 14 | requestOptions: { 15 | maxRedirects: 4 16 | } 17 | }, 18 | options: { 19 | seek: null, 20 | bitrate: 1024, 21 | volume: 1, 22 | type: "converted", 23 | }, 24 | } 25 | 26 | module.exports.emojis = { 27 | garbage: "🗑️ ", 28 | green_check_mark: ":white_check_mark: ", 29 | loading: ":arrows_counterclockwise: ", 30 | loudSound: ":loud_sound: ", 31 | megaPhone: "📣 ", 32 | notes: ":notes: ", 33 | pause: ":pause_button: ", 34 | previous: ":previous_track: ", 35 | redx: ":x: ", 36 | repeat: ":repeat: ", 37 | repeatSong: ":repeat_one: ", 38 | resume: ":arrow_forward: ", 39 | shuffle: ":twisted_rigthwards_arrows: ", 40 | signal: ":signal_strength: ", 41 | skip: ":next_track: ", 42 | speaker: ":speaker: ", 43 | stop: ":stop_button: ", 44 | stopWatch: ":stopwatch: ", 45 | volumeHigh: ":loud_sound: ", 46 | } -------------------------------------------------------------------------------- /events/clientEvents/msg.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "message", 3 | async execute(client, msg, Discord) { 4 | if (msg.author.bot || !msg.guild) return; 5 | let prefix = client.config.prefix; 6 | const args = msg.content.slice(prefix.length).split(" "); 7 | if (client.config.devMode) prefix = client.config.devPrefix; 8 | if (msg.mentions.users.first()) { 9 | if (msg.mentions.users.first().id === client.user.id) { 10 | if (!args[1]) return; 11 | if (args[1] === "prefix") { 12 | if (!args[2]) 13 | return msg.channel.send( 14 | `${client.messages.prefixHere}\`${prefix}\`.` 15 | ); 16 | if (args[2] === "=" && args[3]) return (prefix = args[3]); 17 | } 18 | args.shift(); 19 | getCommand(client, args, msg, Discord); 20 | } 21 | } 22 | if (!msg.content.startsWith(prefix)) return; 23 | getCommand(client, args, msg, Discord); 24 | }, 25 | }; 26 | 27 | function getCommand(client, args, msg, Discord) { 28 | if (!args[0]) return; 29 | const commandName = args[0].toLowerCase(); 30 | if (commandName === "none") return; 31 | const command = 32 | client.commands.get(commandName) || 33 | client.commands.find( 34 | (cmd) => cmd.alias && cmd.alias.includes(commandName) 35 | ); 36 | if (!command) return; 37 | client.funcs.exe(msg, args, client, Discord, command); 38 | } -------------------------------------------------------------------------------- /commands/skip.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "skip", 3 | alias: ["s", "next"], 4 | usage: "", 5 | description: "Skip the currently playing song.", 6 | category: "music", 7 | execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (!queue || !queue.playing) 10 | return msg.channel.send(client.messages.noServerQueue); 11 | if (msg.member.voice.channel !== queue.voiceChannel) 12 | return msg.channel.send(client.messages.wrongVoiceChannel); 13 | vote(queue, msg, client); 14 | }, 15 | }; 16 | 17 | function skipSong(queue, msg, client) { 18 | msg.channel.send(client.messages.skipped); 19 | queue.endReason = "skip"; 20 | queue.time = 0; 21 | queue.connection.dispatcher.end(); 22 | } 23 | 24 | function vote(queue, msg, client) { 25 | queue.votesNeeded = Math.floor(queue.voiceChannel.members.size / 2); 26 | queue.votesNeeded.toFixed(); 27 | if (queue.voiceChannel.members.size > 2) { 28 | if (queue.voters.includes(msg.member.id)) 29 | return msg.channel.send(client.messages.alreadyVoted); 30 | queue.votes++; 31 | queue.voters.push(msg.member.id); 32 | if (queue.votes >= queue.votesNeeded) { 33 | queue.voters = []; 34 | queue.votes = 0; 35 | queue.votesNeeded = null; 36 | return skipSong(queue, msg, client); 37 | } else 38 | return msg.channel.send( 39 | `${client.messages.notEnoughVotes} ${queue.votes} / ${queue.votesNeeded}!` 40 | ); 41 | } else { 42 | return skipSong(queue, msg, client); 43 | } 44 | } -------------------------------------------------------------------------------- /events/clientEvents/voiceStateUpdate.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'voiceStateUpdate', 3 | async execute(client, oldState, newState) { 4 | if (oldState.channel === null) return newState.setSelfDeaf(true); 5 | let change = false; 6 | const queue = client.queue.get(newState.guild.id); 7 | if (!queue) return; 8 | if (newState.member.id === client.user.id && oldState.member.id === client.user.id) { 9 | if (newState.member.voice.channel === null) { 10 | queue.songs = []; 11 | queue.looping = false; 12 | queue.endReason = "manual disconnect"; 13 | return client.queue.delete(newState.guild.id); 14 | } 15 | if (newState.member.voice.channel !== queue.voiceChannel) { 16 | change = true; 17 | queue.voiceChannel = newState.member.voice.channel; 18 | queue.connection = newState.connection; 19 | } 20 | } 21 | if (oldState.channel.members.size === 1 && oldState.channel === queue.voiceChannel || change) { 22 | setTimeout(() => { 23 | if (!queue || !queue.connection.dispatcher || queue.connection.dispatcher === null) return; 24 | if (queue.voiceChannel.members.size === 1) { 25 | queue.textChannel.send(client.messages.leftAlone); 26 | queue.songs = []; 27 | queue.looping = false; 28 | queue.endReason = "Timeout"; 29 | queue.connection.dispatcher.end(); 30 | } 31 | }, 120000); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /struct/funcs/handleVideo.js: -------------------------------------------------------------------------------- 1 | const Discord = require("discord.js"); 2 | const ytdl = require("ytdl-core"); 3 | 4 | module.exports = async function ( 5 | resource, 6 | msg, 7 | voiceChannel, 8 | client, 9 | playlist, 10 | type 11 | ) { 12 | const songInfo = await ytdl.getInfo(resource).catch(err => console.log(err)); 13 | const song = { 14 | title: Discord.Util.escapeMarkdown(songInfo.videoDetails.title), 15 | url: resource, 16 | author: msg.author, 17 | type: type, 18 | info: songInfo.videoDetails 19 | }; 20 | 21 | const queue = client.queue.get(msg.guild.id); 22 | 23 | if (queue) { 24 | queue.songs.push(song); 25 | queue.textChannel = msg.channel; 26 | if (playlist) return; 27 | let message; 28 | message = client.messages.songAdded.replace("%TITLE%", song.title); 29 | return msg.channel.send(message); 30 | } 31 | 32 | const construct = { 33 | textChannel: msg.channel, 34 | voiceChannel: voiceChannel, 35 | connection: null, 36 | songs: [], 37 | prevSongs: [], 38 | volume: 50, 39 | bass: 1, 40 | nigthCore: false, 41 | playing: false, 42 | paused: false, 43 | looping: false, 44 | songLooping: false, 45 | votes: 0, 46 | voters: [], 47 | votesNeeded: null, 48 | time: 0, 49 | endReason: null, 50 | }; 51 | 52 | construct.songs.push(song); 53 | 54 | client.queue.set(msg.guild.id, construct); 55 | 56 | try { 57 | const connection = await voiceChannel.join(); 58 | construct.connection = connection; 59 | client.funcs.play(msg.guild, construct.songs[0], client, 0, true); 60 | } catch (error) { 61 | client.queue.delete(msg.guild.id); 62 | return msg.channel.send(client.messages.error + error); 63 | } 64 | return; 65 | }; -------------------------------------------------------------------------------- /commands/nowplaying.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "nowplaying", 3 | alias: ["np", "playing"], 4 | usage: "", 5 | description: "See the currently playing song position and length.", 6 | category: "music", 7 | async execute(msg, args, client, Discord, command) { 8 | const queue = client.queue.get(msg.guild.id); 9 | if (!queue) return msg.channel.send(client.messages.noServerQueue); 10 | let songTime = (queue.songs[0].info.lengthSeconds * 1000).toFixed(0); 11 | let completed = ( 12 | queue.connection.dispatcher.streamTime + queue.time 13 | ).toFixed(0); 14 | let barlength = 30; 15 | let completedpercent = ((completed / songTime) * barlength).toFixed(0); 16 | let array = []; 17 | for (let i = 0; i < completedpercent - 1; i++) { 18 | array.push("⎯"); 19 | } 20 | array.push("🔘"); 21 | for (let i = 0; i < barlength - completedpercent - 1; i++) { 22 | array.push("⎯"); 23 | } 24 | const embed = new Discord.MessageEmbed() 25 | .setTitle(client.messages.nowPlaying) 26 | .setDescription( 27 | `${client.messages.nowPlayingDesc} ${ 28 | queue.songs[0].title 29 | }\n\`${array.join("")}\`\n\`${client.funcs.msToTime( 30 | completed, 31 | "hh:mm:ss" 32 | )} / ${client.funcs.msToTime(songTime, "hh:mm:ss")}\`\nchannel: \`${queue.songs[0].info.author.name}\`` 33 | ) 34 | .setFooter(`Queued by ${queue.songs[0].author.tag}`) 35 | .setURL(queue.songs[0].url) 36 | .setThumbnail(queue.songs[0].info.thumbnail.thumbnails[4].url) 37 | .setColor(client.config.embedColor); 38 | if (queue.nigthCore) 39 | embed.setDescription( 40 | `${client.messages.nowPlayingDesc} ${queue.songs[0].title} \nchannel: \`${queue.songs[0].info.author.name}\`` 41 | ); 42 | return msg.channel.send(embed); 43 | }, 44 | }; -------------------------------------------------------------------------------- /struct/client.js: -------------------------------------------------------------------------------- 1 | const { 2 | Client, 3 | Collection, 4 | Intents 5 | } = require("discord.js"); 6 | const fs = require("fs"); 7 | const path = require("path"); 8 | const events = require("../events/events.js"); 9 | 10 | const myIntents = new Intents(); 11 | myIntents.add( 12 | 1 << 0, // GUILDS 13 | 1 << 7, // GUILD_VOICE_STATES 14 | 1 << 9, // GUILD_MESSAGES 15 | ); 16 | 17 | module.exports = class extends Client { 18 | constructor() { 19 | super({ 20 | disableEveryone: true, 21 | disabledEvents: ["TYPING_START"], 22 | ws: { 23 | intents: myIntents 24 | } 25 | }); 26 | 27 | this.commands = new Collection(); 28 | this.commandAliases = new Collection(); 29 | this.settingCmd = new Collection(); 30 | this.queue = new Map(); 31 | this.funcs = {}; 32 | this.dispatcher = {}; 33 | this.config = require("../config"); 34 | this.messages = require("./config/messages.js"); 35 | this.dispatcher.finish = require("../events/dispatcherEvents/finish.js"); 36 | this.dispatcher.error = require("../events/dispatcherEvents/error.js"); 37 | this.global = { 38 | db: { 39 | guilds: {}, 40 | }, 41 | }; 42 | 43 | fs.readdirSync(path.join(__dirname, "funcs")).forEach((filename) => { 44 | this.funcs[filename.slice(0, -3)] = require(`./funcs/${filename}`); 45 | }); 46 | 47 | const commandFiles = fs 48 | .readdirSync(path.join(path.dirname(__dirname), "commands")) 49 | .filter((f) => f.endsWith(".js")); 50 | for (const file of commandFiles) { 51 | const command = require(`../commands/${file}`); 52 | command.uses = 0; 53 | this.commands.set(command.name, command); 54 | this.commandAliases.set(command.alias, command); 55 | } 56 | 57 | events(this); 58 | 59 | this.login(this.config.token).catch((err) => 60 | console.log("Failed to login: " + err) 61 | ); 62 | } 63 | }; -------------------------------------------------------------------------------- /commands/help.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "help", 3 | alias: ["h"], 4 | usage: "", 5 | description: "List all commands", 6 | category: "info", 7 | execute(msg, args, client, Discord, command) { 8 | if (args[1]) { 9 | if (!client.commands.has(args[1])) 10 | return msg.channel.send("That command does not exist"); 11 | const command = client.commands.get(args[1]); 12 | const embed = new Discord.MessageEmbed() 13 | .setTitle(`${client.config.prefix}${command.name} ${command.usage}`) 14 | .setDescription(command.description) 15 | .setFooter( 16 | `${client.messages.helpCmdFooter} \`${command.alias.map( 17 | (a) => `${a}, ` 18 | )}\`` 19 | ) 20 | .setColor(client.config.embedColor); 21 | msg.channel.send(embed); 22 | } else { 23 | const categories = []; 24 | for (let i = 0; i < client.commands.size; i++) { 25 | if (!categories.includes(client.commands.array()[i].category)) 26 | categories.push(client.commands.array()[i].category); 27 | } 28 | let commands = ""; 29 | for (let i = 0; i < categories.length; i++) { 30 | commands += `**» ${categories[i].toUpperCase()}**\n${client.commands 31 | .filter( 32 | (x) => x.category === categories[i] && !x.omitFromHelp && !x.onlyDev 33 | ) 34 | .map((x) => `\`${x.name}\``) 35 | .join(", ")}\n`; 36 | } 37 | let message; 38 | message = client.messages.helpFooter.replace( 39 | "%PREFIX%", 40 | client.config.prefix 41 | ); 42 | const embed = new Discord.MessageEmbed() 43 | .setTitle(`${client.user.username} ${client.messages.helpTitle}`) 44 | .setDescription(commands) 45 | .setFooter(message) 46 | .setColor(client.config.embedColor); 47 | msg.channel.send(embed); 48 | } 49 | }, 50 | }; 51 | -------------------------------------------------------------------------------- /struct/funcs/play.js: -------------------------------------------------------------------------------- 1 | module.exports = async function (guild, song, client, seek, play) { 2 | const { Readable: ReadableStream } = require("stream"); 3 | const Discord = require("discord.js"); 4 | const ytdl = require("ytdl-core"); 5 | const { streamConfig } = require("../../config.js"); 6 | const prism = require("prism-media"); 7 | const queue = client.queue.get(guild.id); 8 | if (!song) { 9 | queue.voiceChannel.leave(); 10 | client.queue.delete(guild.id); 11 | return; 12 | } 13 | 14 | streamConfig.options.seek = seek; 15 | 16 | let input = song.url; 17 | if (song.type === "ytdl") 18 | input = ytdl(song.url, streamConfig.ytdlOptions).on("error", (err) => 19 | console.log(err) 20 | ); 21 | 22 | const ffmpegArgs = [ 23 | "-analyzeduration", 24 | "0", 25 | "-loglevel", 26 | "0", 27 | "-f", 28 | "s16le", 29 | "-ar", 30 | "48000", 31 | "-ac", 32 | "2", 33 | ]; 34 | 35 | const isStream = input instanceof ReadableStream; 36 | 37 | const args = isStream ? ffmpegArgs.slice() : ["-i", input, ...ffmpegArgs]; 38 | args.unshift("-ss", String(seek)); 39 | 40 | const transcoder = new prism.FFmpeg({ 41 | args: args, 42 | }); 43 | 44 | const stream = input.pipe(transcoder).on("error", (error) => { 45 | console.log(error); 46 | }); 47 | 48 | const dispatcher = queue.connection 49 | .play(stream, streamConfig.options) 50 | .on("finish", () => { 51 | client.dispatcher.finish(client, queue.endReason, guild); 52 | }) 53 | .on("start", () => { 54 | queue.endReason = null; 55 | dispatcher.player.streamingData.pausedTime = 0; 56 | }) 57 | .on("error", (error) => { 58 | client.dispatcher.error(client, error, guild); 59 | }); 60 | dispatcher.setVolume(queue.volume / 100); 61 | if (song.type !== "ytdl") return; 62 | const embed = new Discord.MessageEmbed() 63 | .setTitle(`${client.messages.startPlaying}**${song.title}**`) 64 | .setDescription( 65 | `Song duration: \`${client.funcs.msToTime( 66 | queue.songs[0].info.lengthSeconds * 1000, 67 | "hh:mm:ss" 68 | )}\`` 69 | ) 70 | .setColor(client.config.embedColor); 71 | queue.textChannel.send(embed); 72 | queue.playing = true; 73 | }; 74 | -------------------------------------------------------------------------------- /commands/search.js: -------------------------------------------------------------------------------- 1 | const ytsr = require('ytsr'); 2 | const he = require('he'); 3 | 4 | module.exports = { 5 | name: 'search', 6 | alias: ["sr", "find"], 7 | usage: '', 8 | description: 'Search the top 10 queryes and choose one.', 9 | category: 'music', 10 | async execute(msg, args, client, Discord, command) { 11 | const searchString = args.slice(1).join(" "); 12 | const queue = client.queue.get(msg.guild.id); 13 | const voiceChannel = msg.member.voice.channel; 14 | if (!queue) { 15 | if (!msg.member.voice.channel) return msg.channel.send(client.messages.noVoiceChannel); 16 | } else { 17 | if (voiceChannel !== queue.voiceChannel) return msg.channel.send(client.messages.wrongVoiceChannel); 18 | } 19 | if (!args[1]) return msg.channel.send(client.messages.noQuery); 20 | if (voiceChannel.full) return msg.channel.send(client.messages.channelFull); 21 | if (!voiceChannel.joinable) return msg.channel.send(client.messages.noPermsConnect); 22 | if (!voiceChannel.speakable) return msg.channel.send(client.messages.noPermsSpeak); 23 | ytsr(searchString, { 24 | limit: 20, 25 | }, async function (err, res) { 26 | if (err) return console.log(err); 27 | if (!res.items[0]) return msg.channel.send(client.messages.noResults); 28 | const videoResults = res.items.filter(item => item.type === "video"); 29 | const videos = videoResults.slice(0, 10); 30 | let index = 0; 31 | const embed = new Discord.MessageEmbed() 32 | .setTitle(client.messages.songSelection) 33 | .setDescription(`${videos.map(video2 => `**${++index}** ${he.decode(video2.title)} `).join('\n')}`) 34 | .setFooter(client.messages.provideANumber) 35 | .setColor(client.config.embedColor) 36 | msg.channel.send(embed); 37 | try { 38 | var response = await msg.channel.awaitMessages(message2 => message2.content > 0 && message2.content < 11 && message2.author === msg.author, { 39 | max: 1, 40 | time: 10000, 41 | errors: ['time'] 42 | }); 43 | } catch (err) { 44 | console.error(err); 45 | return msg.channel.send(client.messages.cancellingVideoSelection); 46 | } 47 | const videoIndex = parseInt(response.first().content) - 1; 48 | return client.funcs.handleVideo(videos[videoIndex].link, msg, voiceChannel, client, false, "ytdl"); 49 | }) 50 | } 51 | }; -------------------------------------------------------------------------------- /commands/play.js: -------------------------------------------------------------------------------- 1 | const ytdl = require("ytdl-core"); 2 | const ytsr = require("ytsr"); 3 | const ytpl = require("ytpl"); 4 | 5 | module.exports = { 6 | name: "play", 7 | alias: ["p", "music"], 8 | usage: "", 9 | description: "Play some music.", 10 | category: "music", 11 | async execute(msg, args, client, Discord, command) { 12 | 13 | const searchString = args.slice(1).join(" "); 14 | const url = args[1] ? args[1].replace(/<(.+)>/g, "$1") : ""; 15 | const queue = client.queue.get(msg.guild.id); 16 | const voiceChannel = msg.member.voice.channel; 17 | if (!queue) { 18 | if (!msg.member.voice.channel) 19 | return msg.channel.send(client.messages.noVoiceChannel); 20 | } else { 21 | if (voiceChannel !== queue.voiceChannel) 22 | return msg.channel.send(client.messages.wrongVoiceChannel); 23 | } 24 | if (!args[1]) return msg.channel.send(client.messages.noQuery); 25 | if (voiceChannel.full) return msg.channel.send(client.messages.channelFull); 26 | if (!voiceChannel.joinable) 27 | return msg.channel.send(client.messages.noPermsConnect); 28 | if (!voiceChannel.speakable) 29 | return msg.channel.send(client.messages.noPermsSpeak); 30 | if (ytdl.validateURL(url)) { 31 | client.funcs.handleVideo( 32 | url, 33 | msg, 34 | voiceChannel, 35 | client, 36 | false, 37 | "ytdl" 38 | ); 39 | } else if ( 40 | url.match(/^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/) 41 | ) { 42 | const lmsg = await msg.channel.send(client.messages.loadingSongs); 43 | const playlist = await ytpl(url).catch((err) => { 44 | msg.channel.send(client.messages.error + err); 45 | console.log("Error whilst getting playlist " + err); 46 | }); 47 | if (!playlist || !playlist.items) return msg.channel.send(client.messages.noResults); 48 | for (const video of playlist.items) { 49 | client.funcs.handleVideo( 50 | video.url, 51 | msg, 52 | voiceChannel, 53 | client, 54 | true, 55 | "ytdl" 56 | ); 57 | } 58 | const message = client.messages.playlistAdded.replace( 59 | "%TITLE%", 60 | playlist.title 61 | ); 62 | return lmsg.edit(message); 63 | } else { 64 | if (searchString.length > 127) return msg.channel.send(client.messages.noResults); 65 | const res = await ytsr(searchString, { 66 | limit: 10 67 | }).catch((err) => { 68 | msg.channel.send(client.messages.error + err); 69 | console.log("Error whilst ytsr" + err); 70 | }); 71 | if (!res || !res.items[0]) return msg.channel.send(client.messages.noResults); 72 | const videoResults = res.items.filter(item => item.type == "video"); 73 | if (!videoResults[0]) return msg.channel.send(client.messages.noResults); 74 | client.funcs.handleVideo(videoResults[0].link, msg, voiceChannel, client, false, "ytdl"); 75 | } 76 | }, 77 | }; -------------------------------------------------------------------------------- /struct/config/messages.js: -------------------------------------------------------------------------------- 1 | const { emojis } = require("../../config.js"); 2 | 3 | module.exports = { 4 | emojis: emojis, 5 | alreadyPaused: emojis.redx + "The music is already paused!", 6 | alreadyVoted: emojis.redx + "You have already voted to skip!", 7 | announceSongs: emojis.megaPhone + "Current setting:", 8 | announceSongsFalse: 9 | emojis.green_check_mark + "announcesongs now set to `false`!", 10 | announceSongsTrue: 11 | emojis.green_check_mark + "announcesongs now set to `true`!", 12 | bassApplied: 13 | emojis.volumeHigh + "The bass level **%BASS%** has been applied!", 14 | bassFalse: emojis.green_check_mark + "Bass is now false!", 15 | bassLevel: emojis.green_check_mark + "Bass level is now", 16 | boolean: emojis.redx + "Please define a boolean! (true/false)", 17 | cancellingVideoSelection: emojis.redx + "Cancelling video selection", 18 | cantSkipToCurrent: 19 | emojis.redx + "You can't skip to the song currently playing!", 20 | channelAdded: 21 | emojis.green_check_mark + "Channel %CHANNEL% added to the blacklist!", 22 | channelAlreadyBlackListed: 23 | emojis.redx + "That channel is already blacklisted!", 24 | channelFull: emojis.redx + "Your voice channel is full!", 25 | channelNotBlackListed: 26 | emojis.redx + "That channel is not blacklisted or does not exist!", 27 | channelRemoved: 28 | emojis.green_check_mark + 29 | "Channel %CHANNEL% has been removed from the blacklist!", 30 | correctUsage: emojis.redx + "correct usage: ", 31 | currentBass: emojis.loudSound + "The current bass is: ", 32 | currentDefaultBass: emojis.speaker + "Currect default bass level: ", 33 | currentDefaultVolume: emojis.speaker + "Current default volume is:", 34 | currentNigthCore: emojis.speaker + "Currect Nigthcore setting: ", 35 | currentPrefix: "Current prefix:", 36 | currentVolume: emojis.loudSound + "The current volume is: ", 37 | defaultVolumeMax: 38 | emojis.redx + 39 | "The default volume must be below `100` for quality and safety resons.", 40 | defaultVolumeNumber: 41 | emojis.redx + 42 | "I'm sorry, But the default volume needs to be a valid __number__.", 43 | defaultVolumeSet: emojis.green_check_mark + "Default volume set to:", 44 | devMode: 45 | emojis.redx + 46 | "Dev mode has been turned on! Commands are only available to developer(s)!", 47 | disableNigthCore: 48 | emojis.redx + "Please disable nigthCore in order to use this command!", 49 | dispatcherError: "Error with the dispatcher: ", 50 | error: emojis.redx + "An error occured!.\nError: ", 51 | errorConnecting: "Error with connecting to voice channel: ", 52 | errorDetected: "Error detected: ", 53 | errorDispatcher: 54 | emojis.redx + 55 | "An error has occured while playing music! The queue has been deleted.\nError: ", 56 | errorExe: emojis.redx + "there was an error trying to execute that command!", 57 | helpCmdFooter: "Command Alias:", 58 | helpFooter: 59 | '"%PREFIX%help " to see more information about a command.', 60 | helpTitle: "help", 61 | leftAlone: "I have left the channel as i was left alone.", 62 | loadingSongs: emojis.loading + "Loading song(s)", 63 | looping: emojis.repeat + "Looping the queue now!", 64 | loopingSong: emojis.repeatSong + "Looping **%TITLE%** now!", 65 | maxBass: emojis.redx + "The max bass is `100`!", 66 | maxVolume: emojis.redx + "The max volume is `100`!", 67 | mentionChannel: emojis.redx + "Please mention a channel!", 68 | nigthCoreApplied: 69 | emojis.green_check_mark + 70 | "NigthCore is now **%BOOLEAN%** this will be applied when the next song starts playing!", 71 | noLooping: emojis.repeat + "No longer looping the queue!", 72 | noLoopingSong: emojis.repeatSong + "No longer looping the song!", 73 | noPermsConnect: 74 | emojis.redx + 75 | "I cannot connect to your voice channel, make sure I have the proper permissions!", 76 | noPermsEmbed: 77 | emojis.redx + 78 | "I cannot send embeds (Embed links), make sure I have the proper permissions!", 79 | noPermsManageRoles: 80 | emojis.redx + 81 | "I cannot create roles (Manage roles), make sure I have the proper permissions! I will need this permission to create a `DJ` role since i did not find one!", 82 | noPermsManageSettings: 83 | emojis.redx + 84 | "You need the `MANAGE_SERVER` permission to change the settings!", 85 | noPermsSpeak: 86 | emojis.redx + 87 | "I cannot speak in your voice channel, make sure I have the proper permissions!", 88 | noPermsUseExternalEmojis: 89 | emojis.redx + 90 | "I cannot use external emojis, make sure I have the proper permissions!", 91 | noPreviousSongs: emojis.redx + "No previous songs!", 92 | noQuery: emojis.redx + "you need to use a link or search for a song!", 93 | noResults: emojis.redx + "I could not obtain any search results!", 94 | noServerQueue: emojis.redx + "There is nothing playing!", 95 | noSongs: emojis.redx + "That song does not exist!", 96 | noSongsInQueue: emojis.redx + "There are no songs in the queue!", 97 | nowPlayingDesc: emojis.notes + "**Now playing:**", 98 | notEnoughVotes: emojis.redx + "Not enough votes!", 99 | notPaused: emojis.redx + "The music in not paused!", 100 | noVoiceChannel: 101 | emojis.redx + 102 | "I'm sorry but you need to be in a voice channel to play music!", 103 | nowPlaying: "__Now playing__", 104 | paused: emojis.pause + "Paused the music!", 105 | playlistAdded: 106 | emojis.green_check_mark + 107 | "Playlist: **%TITLE%** has been added to the queue!", 108 | positiveBass: emojis.redx + "The bass needs to be a positive number!", 109 | positiveVolume: emojis.redx + "The volume needs to be a positive number!", 110 | provideANumber: 111 | "Please provide a number ranging from 1-10 to select one of the search results.", 112 | provideASong: 113 | emojis.redx + "Please provide a song position in queue for me to remove!", 114 | queueDesc: 115 | "**Now playing:** %SONG%\n:arrow_down: Next in queue :arrow_down:", 116 | queueFooter: "songs in the queue!", 117 | queueLength: emojis.redx + "There are only %SONGS% song(s) in the queue!", 118 | queueTitle: "__Song queue__", 119 | quotaReached: 120 | emojis.redx + 121 | "Quota reached please try again after midnight Pacific Time (PT)!", 122 | removed: emojis.garbage + "removed `%SONG%` from the queue!", 123 | resumed: emojis.resume + "Resumed the music!", 124 | seekingPointPositive: 125 | emojis.redx + "The seeking point needs to be a positive number!", 126 | seekMax: 127 | emojis.redx + 128 | "The lenght of this song is %LENGTH% seconds! You can't seek further than that!", 129 | setVolume: emojis.volumeHigh + "I set the volume to: ", 130 | shuffled: emojis.shuffle + "Queue suffled!", 131 | skipped: emojis.skip + "Skipped the song!", 132 | songAdded: 133 | emojis.green_check_mark + "**%TITLE%** has been added to the queue!", 134 | songsAdded: emojis.green_check_mark + "%AMOUNT% songs added to the queue!", 135 | songSelection: "__Song Selection__", 136 | startPlaying: emojis.notes + "Start playing: ", 137 | stop: emojis.stop + "Stopped the music!", 138 | validNumber: 139 | emojis.redx + "I'm sorry, But you need to enter a valid __number__.", 140 | wrongVoiceChannel: 141 | emojis.redx + 142 | "I'm sorry but you need to be in the same voice channel as i am to use this command!", 143 | }; 144 | --------------------------------------------------------------------------------