aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author8cy <[email protected]>2020-04-12 05:54:08 -0700
committer8cy <[email protected]>2020-04-12 05:54:08 -0700
commit5b6a874eab03c7e97794fc334ed2f06caf90b094 (patch)
tree4593cfbb2c5e5f4212fb718e426df43c8abfd523
parentInitial commit (diff)
downloadminecraftsoundtrackbot-5b6a874eab03c7e97794fc334ed2f06caf90b094.tar.xz
minecraftsoundtrackbot-5b6a874eab03c7e97794fc334ed2f06caf90b094.zip
The Beginning, v1.0.0
-rw-r--r--.gitignore6
-rw-r--r--Cache/DiscordEmoji.json1
-rw-r--r--Procfile1
-rw-r--r--app.js6
-rw-r--r--bot.js64
-rw-r--r--commands/utility/help.js29
-rw-r--r--commands/voice/join.js26
-rw-r--r--commands/voice/leave.js30
-rw-r--r--commands/voice/loop.js32
-rw-r--r--commands/voice/pause.js30
-rw-r--r--commands/voice/play.js196
-rw-r--r--commands/voice/queue.js51
-rw-r--r--commands/voice/remove.js39
-rw-r--r--commands/voice/resume.js31
-rw-r--r--commands/voice/shuffle.js52
-rw-r--r--commands/voice/skip.js27
-rw-r--r--commands/voice/skipall.js42
-rw-r--r--commands/voice/skipto.js41
-rw-r--r--commands/voice/volume.js44
-rw-r--r--config.json4
-rw-r--r--package.json28
21 files changed, 780 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f3e60f0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+node_modules/
+package-lock.json
+.vscode
+.vs
+.idea
+.eclipse
diff --git a/Cache/DiscordEmoji.json b/Cache/DiscordEmoji.json
new file mode 100644
index 0000000..4046fd2
--- /dev/null
+++ b/Cache/DiscordEmoji.json
@@ -0,0 +1 @@
+{"Categories":"{\"1\":\"Original Style\",\"18\":\"Recolors\",\"2\":\"TV \\/ Movie\",\"10\":\"Gaming\",\"3\":\"Meme\",\"4\":\"Anime\",\"13\":\"Pepe\",\"5\":\"Celebrity\",\"6\":\"Blobs\",\"7\":\"Thinking\",\"17\":\"Animals\",\"15\":\"Cute\",\"11\":\"Letters\",\"14\":\"Logos\",\"16\":\"Utility\",\"12\":\"Other\",\"8\":\"Animated\",\"9\":\"NSFW\"}"} \ No newline at end of file
diff --git a/Procfile b/Procfile
new file mode 100644
index 0000000..ad01c27
--- /dev/null
+++ b/Procfile
@@ -0,0 +1 @@
+worker: node app.js
diff --git a/app.js b/app.js
new file mode 100644
index 0000000..843db70
--- /dev/null
+++ b/app.js
@@ -0,0 +1,6 @@
+const { ShardingManager } = require('discord.js');
+const config = require('./config.json');
+const manager = new ShardingManager('./bot.js', { token: config['secret'] });
+
+manager.spawn();
+manager.on('shardCreate', shard => console.log(`Launched shard: ${shard.id}`)); \ No newline at end of file
diff --git a/bot.js b/bot.js
new file mode 100644
index 0000000..43fb9a4
--- /dev/null
+++ b/bot.js
@@ -0,0 +1,64 @@
+const config = require('./config.json');
+const { CommandoClient } = require('discord.js-commando');
+const path = require('path');
+const { Structures } = require('discord.js');
+Structures.extend('Guild', Guild => {
+ class MusicGuild extends Guild {
+ constructor(client, data) {
+ super(client, data);
+ this.musicData = {
+ queue: [],
+ isPlaying: false,
+ volume: 1,
+ songDispatcher: null
+ };
+ }
+ }
+ return MusicGuild;
+});
+
+const client = new CommandoClient({
+ commandPrefix: 'msb!',
+ owner: '217348698294714370'
+});
+
+client.registry
+ .registerDefaultTypes()
+ .registerGroups([
+ ['voice', 'Voice Command Group'],
+ ['utility', 'Utility Command Group']
+ ])
+ .registerDefaultGroups()
+ .registerDefaultCommands({
+ help: false
+ })
+ .registerCommandsIn(path.join(__dirname, 'commands'));
+
+client.once('ready', () => {
+ console.log(`Started bot: ${client.user.tag} (ID: ${client.user.id})\nCurrently running on ${client.guilds.cache.size} server(s).`);
+ client.user.setActivity('msb!p | v1.0.0', {
+ type: 'LISTENING'
+ });
+ //client.channels.cache.get('600773421525237781').send('bot started up');
+});
+
+client.on('error', console.error);
+client.on('debug', console.debug);
+
+client.on('message', async msg => {
+ var msgContent = msg.content.toLowerCase();
+ function prefixCheck() {
+ if (msgContent.startsWith('msb!')) {
+ return true;
+ }
+ }
+ if (prefixCheck()) {
+ if (msg.channel.type == 'dm') {
+ console.log(msg.author.tag, 'says', msgContent, 'in a DM');
+ } else {
+ console.log(msg.member.user.tag, 'says', msgContent, 'in #' + msg.channel.name);
+ }
+ }
+});
+
+client.login(config['secret']); \ No newline at end of file
diff --git a/commands/utility/help.js b/commands/utility/help.js
new file mode 100644
index 0000000..5b7174f
--- /dev/null
+++ b/commands/utility/help.js
@@ -0,0 +1,29 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+const { MessageEmbed } = require('discord.js');
+
+module.exports = class HelpUtility extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'help',
+ aliases: ['h'],
+ group: 'utility',
+ memberName: 'help',
+ description: 'Help.',
+ throttling: {
+ usages: 2,
+ duration: 5
+ },
+ guildOnly: true,
+ examples: ['msb!help', 'msb!h']
+ });
+ }
+ run(msg) {
+ let embed = new MessageEmbed()
+ .setColor(0x529B30)
+ .setTitle('MinecraftSoundtrackBot - Help')
+ .addField('Normal Commands', '**msb!join** - Joins your current voice channel.\n**msb!leave** - Leaves the voice channel and ends playback.\n**msb!loop** - Loops the soundtrack.\n**msb!pause** - Pauses soundtrack playback if playing.\n**msb!play** - Plays the Minecraft soundtrack.\n**msb!queue** - Displays the song queue\n**msb!remove** - Remove a certain song from the soundtrack queue.\n**msb!resume** - Resumes the soundtrack if paused.\n**msb!shuffle** - Shuffles the soundtrack queue.\n**msb!skip** - Skips one song ahead in the soundtrack queue.\n**msb!skipall** - Skips all the songs in the soundtrack queue.\n**msb!skipto** - Skip to a certain song in the soundtrack queue.\n**msb!volume** - Changes the volume of playback.')
+ .setFooter(`Bot developed and administrated by sin#1337.`, this.client.users.cache.get('217348698294714370').avatarURL());
+ msg.say(embed);
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/join.js b/commands/voice/join.js
new file mode 100644
index 0000000..2dc1fdd
--- /dev/null
+++ b/commands/voice/join.js
@@ -0,0 +1,26 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+
+module.exports = class JoinVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'join',
+ aliases: ['j'],
+ group: 'voice',
+ memberName: 'join',
+ description: 'Joins your current voice channel.',
+ guildOnly: true,
+ examples: ['msb!join', 'msb!j']
+ });
+ }
+ run(msg) {
+ if (!msg.guild.voice && msg.member.voice.channel) {
+ msg.member.voice.channel.join();
+ msg.reply('Succesfully joined your voice channel. ' + emoji.random());
+ } else if (msg.guild.voice) {
+ msg.reply('I\'m already in voice channel. ' + emoji.random());
+ } else if (!msg.member.voice.channel) {
+ msg.reply('You\'re not in a voice channel. ' + emoji.random());
+ }
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/leave.js b/commands/voice/leave.js
new file mode 100644
index 0000000..ba48594
--- /dev/null
+++ b/commands/voice/leave.js
@@ -0,0 +1,30 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+
+module.exports = class LeaveVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'leave',
+ aliases: ['end', 'stop', 'l'],
+ group: 'voice',
+ memberName: 'leave',
+ description: 'Leaves the voice channel and ends playback.',
+ guildOnly: true,
+ examples: ['msb!leave', 'msb!end', 'msb!stop', 'msb!l']
+ });
+ }
+ run(msg) {
+ var voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.reply('Join a voice channel and try again. ' + emoji.random());
+
+ if (
+ typeof msg.guild.musicData.songDispatcher == 'undefined' ||
+ msg.guild.musicData.songDispatcher == null
+ ) {
+ return msg.reply('The soundtrack isn\'t playing right now. ' + emoji.random());
+ }
+ msg.guild.musicData.songDispatcher.end();
+ msg.guild.musicData.queue.length = 0;
+ return;
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/loop.js b/commands/voice/loop.js
new file mode 100644
index 0000000..507b424
--- /dev/null
+++ b/commands/voice/loop.js
@@ -0,0 +1,32 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+
+module.exports = class LoopVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'loop',
+ aliases: ['repeat'],
+ group: 'voice',
+ memberName: 'loop',
+ description: 'Loops the soundtrack.',
+ guildOnly: true,
+ examples: ['msb!loop', 'msb!repeat']
+ });
+ }
+ run(msg) {
+ var voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.reply('Join a voice channel and try again. ' + emoji.random());
+
+ if (
+ typeof msg.guild.musicData.songDispatcher == 'undefined' ||
+ msg.guild.musicData.songDispatcher == null
+ ) {
+ return msg.reply('The soundtrack isn\'t playing right now. ' + emoji.random());
+ }
+ msg.channel.send(
+ 'Looping the soundtrack ' + emoji.random()
+ );
+ msg.guild.musicData.queue.unshift(msg.guild.musicData.nowPlaying);
+ return;
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/pause.js b/commands/voice/pause.js
new file mode 100644
index 0000000..20d4254
--- /dev/null
+++ b/commands/voice/pause.js
@@ -0,0 +1,30 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+
+module.exports = class PauseVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'pause',
+ group: 'voice',
+ memberName: 'pause',
+ description: 'Pauses soundtrack playback if playing.',
+ guildOnly: true,
+ examples: ['msb!pause']
+ });
+ }
+ run(msg) {
+ var voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.reply('Join a channel and try again. ' + emoji.random());
+
+ if (
+ typeof msg.guild.musicData.songDispatcher == 'undefined' ||
+ msg.guild.musicData.songDispatcher == null
+ ) {
+ return msg.reply('The soundtrack isn\'t playing right now. ' + emoji.random());
+ }
+
+ msg.say('Soundtrack paused :pause_button:');
+
+ msg.guild.musicData.songDispatcher.pause();
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/play.js b/commands/voice/play.js
new file mode 100644
index 0000000..8797593
--- /dev/null
+++ b/commands/voice/play.js
@@ -0,0 +1,196 @@
+const ytdl = require('ytdl-core');
+const { Command } = require('discord.js-commando');
+const { MessageEmbed } = require('discord.js');
+const Youtube = require('simple-youtube-api');
+const { youtubeAPI } = require('../../config.json');
+const youtube = new Youtube('AIzaSyB9xJENORzZt-GmOGx4WsNCPgKSIxhJcds');
+const emoji = require('emoji-random');
+
+module.exports = class PlayVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'play',
+ aliases: ['p'],
+ group: 'voice',
+ memberName: 'play',
+ description: 'Plays the Minecraft soundtrack.',
+ guildOnly: true,
+ clientPermissions: ['SPEAK', 'CONNECT'],
+ examples: ['msb!play', 'msb!p']
+ });
+ }
+ async run(msg) {
+ const voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.say('Join a channel and try again. ' + emoji.random());
+
+ const playlist = await youtube.getPlaylist('https://www.youtube.com/watch?v=05UM-i4PuOY&list=PLxOTV5xn7n1i2HcKtRBthP2loWjrBGAIY').catch(function () {
+ return msg.say('There was a problem getting the soundtrack. ' + emoji.random());
+ });
+ // remove the 10 if you removed the queue limit conditions below
+ const videosObj = await playlist.getVideos(24).catch(function () {
+ return msg.say(
+ 'There was a problem getting the soundtrack. ' + emoji.random()
+ );
+ });
+ for (let i = 0; i < videosObj.length; i++) {
+ const video = await videosObj[i].fetch();
+ // this can be uncommented if you choose to limit the queue
+ // if (msg.guild.musicData.queue.length < 10) {
+ //
+ msg.guild.musicData.queue.push(
+ this.constructSongObj(video, voiceChannel)
+ );
+ // } else {
+ // return msg.say(
+ // `I can't play the full playlist because there will be more than 10 songs in queue`
+ // );
+ // }
+ }
+ if (msg.guild.musicData.isPlaying == false) {
+ msg.guild.musicData.isPlaying = true;
+ return this.playSong(msg.guild.musicData.queue, msg);
+ } else if (msg.guild.musicData.isPlaying == true) {
+ return msg.say(
+ 'Now playing the Minecraft soundtrack. ' + emoji.random()
+ );
+ }
+
+ var that = this;
+ msg.channel
+ .awaitMessages(
+ function (msg) {
+ return (msg.content > 0 && msg.content < 6) || msg.content === 'exit';
+ }, {
+ max: 1,
+ time: 60000,
+ errors: ['time']
+ }
+ )
+ .then(function (response) {
+ const videoIndex = parseInt(response.first().content);
+ if (response.first().content === 'exit') return songEmbed.delete();
+ youtube
+ .getVideoByID(videos[videoIndex - 1].id)
+ .then(function (video) {
+ // // can be uncommented if you don't want the bot to play live streams
+ // if (video.raw.snippet.liveBroadcastContent === 'live') {
+ // songEmbed.delete();
+ // return msg.say("I don't support live streams!");
+ // }
+
+ // // can be uncommented if you don't want the bot to play videos longer than 1 hour
+ // if (video.duration.hours !== 0) {
+ // songEmbed.delete();
+ // return msg.say('I cannot play videos longer than 1 hour');
+ // }
+
+ // // can be uncommented if you don't want to limit the queue
+ // if (msg.guild.musicData.queue.length > 10) {
+ // songEmbed.delete();
+ // return msg.say(
+ // 'There are too many songs in the queue already, skip or wait a bit'
+ // );
+ // }
+ msg.guild.musicData.queue.push(
+ that.constructSongObj(video, voiceChannel)
+ );
+ if (msg.guild.musicData.isPlaying == false) {
+ msg.guild.musicData.isPlaying = true;
+ if (songEmbed) {
+ songEmbed.delete();
+ }
+ that.playSong(msg.guild.musicData.queue, msg);
+ } else if (msg.guild.musicData.isPlaying == true) {
+ if (songEmbed) {
+ songEmbed.delete();
+ }
+ return msg.say('Now playing the Minecraft soundtrack. ' + emoji.random());
+ }
+ })
+ .catch(function () {
+ if (songEmbed) {
+ songEmbed.delete();
+ }
+ return msg.say(
+ 'An error has occured when trying to get the video ID from YouTube. ' + emoji.random()
+ );
+ });
+ });
+ }
+ playSong(queue, msg) {
+ const classThis = this; // use classThis instead of 'this' because of lexical scope below
+ queue[0].voiceChannel
+ .join()
+ .then(function (connection) {
+ const dispatcher = connection
+ .play(
+ ytdl(queue[0].url, {
+ quality: 'highestaudio',
+ highWaterMark: 1024 * 1024 * 10
+ })
+ )
+ .on('start', function () {
+ msg.guild.musicData.songDispatcher = dispatcher;
+ const volume = 100 / 100;
+ msg.guild.musicData.volume = volume;
+ dispatcher.setVolume(msg.guild.musicData.volume);
+ const videoEmbed = new MessageEmbed()
+ .setThumbnail(queue[0].thumbnail)
+ .setColor(0xF97DAE)
+ .addField('Now Playing:', queue[0].title)
+ .addField('Duration:', queue[0].duration);
+ if (queue[1]) videoEmbed.addField('Next Song:', queue[1].title);
+ msg.say(videoEmbed);
+ msg.guild.musicData.nowPlaying = queue[0];
+ return queue.shift();
+ })
+ .on('finish', function () {
+ if (queue.length >= 1) {
+ return classThis.playSong(queue, msg);
+ } else {
+ msg.guild.musicData.isPlaying = false;
+ msg.guild.musicData.nowPlaying = null;
+ msg.guild.musicData.songDispatcher = null;
+ return msg.guild.me.voice.channel.leave();
+ }
+ })
+ .on('error', function (e) {
+ msg.say('Can\'t play soundtrack. ' + emoji.random());
+ console.error(e);
+ msg.guild.musicData.queue.length = 0;
+ msg.guild.musicData.isPlaying = false;
+ msg.guild.musicData.nowPlaying = null;
+ msg.guild.musicData.songDispatcher = null;
+ return msg.guild.me.voice.channel.leave();
+ });
+ })
+ .catch(function (e) {
+ console.error(e);
+ return msg.guild.me.voice.channel.leave();
+ });
+ }
+ constructSongObj(video, voiceChannel) {
+ let duration = this.formatDuration(video.duration);
+ if (duration == '00:00') duration = 'Live Stream';
+ return {
+ url: `https://www.youtube.com/watch?v=${video.raw.id}`,
+ title: video.title,
+ duration,
+ thumbnail: video.thumbnails.high.url,
+ voiceChannel
+ };
+ }
+ // prettier-ignore
+ formatDuration(durationObj) {
+ const duration = `${durationObj.hours ? (durationObj.hours + ':') : ''}${
+ durationObj.minutes ? durationObj.minutes : '00'
+ }:${
+ (durationObj.seconds < 10)
+ ? ('0' + durationObj.seconds)
+ : (durationObj.seconds
+ ? durationObj.seconds
+ : '00')
+ }`;
+ return duration;
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/queue.js b/commands/voice/queue.js
new file mode 100644
index 0000000..abc4b9b
--- /dev/null
+++ b/commands/voice/queue.js
@@ -0,0 +1,51 @@
+const { Command } = require('discord.js-commando');
+const { MessageEmbed } = require('discord.js');
+const emoji = require('emoji-random');
+
+module.exports = class QueueVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'queue',
+ aliases: [
+ 'q',
+ 'song-list',
+ 'next-songs',
+ 'songlist',
+ 'nextsongs',
+ 'nextsong',
+ 'next-song'
+ ],
+ group: 'voice',
+ memberName: 'queue',
+ description: 'Displays the song queue.',
+ guildOnly: true,
+ examples: [
+ 'msb!queue',
+ 'msb!q',
+ 'msb!songlist',
+ 'msb!song-list',
+ 'msb!nextsong',
+ 'msb!next-song',
+ 'msb!nextsongs',
+ 'msb!next-songs'
+ ]
+ });
+ }
+ run(msg) {
+ if (msg.guild.musicData.queue.length == 0)
+ return msg.say('The soundtrack is not queued. ' + emoji.random());
+ const titleArray = [];
+ msg.guild.musicData.queue.map(obj => {
+ titleArray.push(obj.title);
+ });
+ let queueEmbed = new MessageEmbed()
+ .setColor(0xF97DAE)
+ .setTitle('Soundtrack Queue ' + emoji.random());
+ for (let i = 0; i < titleArray.length; i++) {
+ queueEmbed
+ .addField(`‎`, `${i + 1}: ` + `${titleArray[i]}`)
+ .setFooter(`Bot developed and administrated by sin#1337.`, this.client.users.cache.get('217348698294714370').avatarURL());
+ }
+ return msg.say(queueEmbed);
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/remove.js b/commands/voice/remove.js
new file mode 100644
index 0000000..edcb948
--- /dev/null
+++ b/commands/voice/remove.js
@@ -0,0 +1,39 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+
+module.exports = class RemoveVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'remove',
+ group: 'voice',
+ memberName: 'remove',
+ description: 'Remove a certain song from the soundtrack queue.',
+ guildOnly: true,
+ args: [
+ {
+ key: 'songNumber',
+ prompt: 'What song would you like the remove?',
+ type: 'integer'
+ }
+ ],
+ examples: ['msb!remove 2']
+ });
+ }
+ run(msg, { songNumber }) {
+ if (songNumber < 1 && songNumber >= msg.guild.musicData.queue.length) {
+ return msg.reply('Please enter a valid song number. ' + emoji.random());
+ }
+ var voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.reply('Join a voice channel and try again. ' + emoji.random());
+
+ if (
+ typeof msg.guild.musicData.songDispatcher == 'undefined' ||
+ msg.guild.musicData.songDispatcher == null
+ ) {
+ return msg.reply('The soundtrack isn\'t playing right now. ' + emoji.random());
+ }
+
+ msg.guild.musicData.queue.splice(songNumber - 1, 1);
+ return msg.say(`Removed song **#${songNumber}** from soundtrack queue. ` + emoji.random());
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/resume.js b/commands/voice/resume.js
new file mode 100644
index 0000000..a3f32ce
--- /dev/null
+++ b/commands/voice/resume.js
@@ -0,0 +1,31 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+
+module.exports = class ResumeVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'resume',
+ aliases: ['unpause'],
+ group: 'voice',
+ memberName: 'resume',
+ description: 'Resumes the soundtrack if paused.',
+ guildOnly: true,
+ examples: ['msb!resume', 'msb!unpause']
+ });
+ }
+ run(msg) {
+ var voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.reply('Join a channel and try again. ' + emoji.random());
+
+ if (
+ typeof msg.guild.musicData.songDispatcher == 'undefined' ||
+ msg.guild.musicData.songDispatcher == null
+ ) {
+ return msg.reply('The soundtrack isn\'t playing right now. ' + emoji.random());
+ }
+
+ msg.say('Soundtrack resumed :play_pause:');
+
+ msg.guild.musicData.songDispatcher.resume();
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/shuffle.js b/commands/voice/shuffle.js
new file mode 100644
index 0000000..a6251ca
--- /dev/null
+++ b/commands/voice/shuffle.js
@@ -0,0 +1,52 @@
+const { Command } = require('discord.js-commando');
+const { MessageEmbed } = require('discord.js');
+const emoji = require('emoji-random');
+
+module.exports = class ShuffleVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'shuffle',
+ group: 'voice',
+ memberName: 'shuffle',
+ description: 'Shuffles the soundtrack queue.',
+ guildOnly: true,
+ examples: ['msb!shuffle']
+ });
+ }
+ run(msg) {
+ var voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.reply('Join a channel and try again. ' + emoji.random());
+
+ if (
+ typeof msg.guild.musicData.songDispatcher == 'undefined' ||
+ msg.guild.musicData.songDispatcher == null
+ ) {
+ return msg.reply('The soundtrack isn\'t playing right now. ' + emoji.random());
+ }
+
+ if (msg.guild.musicData.queue.length < 1)
+ return msg.say('This is the only song in the soundtrack queue. ' + emoji.random());
+
+ shuffleQueue(msg.guild.musicData.queue);
+
+ const titleArray = [];
+ msg.guild.musicData.queue.map(obj => {
+ titleArray.push(obj.title);
+ });
+ var queueEmbed = new MessageEmbed()
+ .setColor(0xF97DAE)
+ .setTitle('New Soundtrack Queue ' + emoji.random())
+ .setFooter(`Bot developed and administrated by sin#1337.`, this.client.users.cache.get('217348698294714370').avatarURL());
+ for (let i = 0; i < titleArray.length; i++) {
+ queueEmbed.addField(`${i + 1}:`, `${titleArray[i]}`);
+ }
+ return msg.say(queueEmbed);
+ }
+};
+
+function shuffleQueue(queue) {
+ for (let i = queue.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [queue[i], queue[j]] = [queue[j], queue[i]];
+ }
+} \ No newline at end of file
diff --git a/commands/voice/skip.js b/commands/voice/skip.js
new file mode 100644
index 0000000..9cac14c
--- /dev/null
+++ b/commands/voice/skip.js
@@ -0,0 +1,27 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+
+module.exports = class SkipVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'skip',
+ group: 'voice',
+ memberName: 'skip',
+ description: 'Skips one song ahead in the soundtrack queue.',
+ guildOnly: true,
+ examples: ['msb!skip']
+ });
+ }
+ run(msg) {
+ const voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.reply('Join a channel and try again. ' + emoji.random());
+
+ if (
+ typeof msg.guild.musicData.songDispatcher == 'undefined' ||
+ msg.guild.musicData.songDispatcher == null
+ ) {
+ return msg.reply('The soundtrack isn\'t playing right now. ' + emoji.random());
+ }
+ msg.guild.musicData.songDispatcher.end();
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/skipall.js b/commands/voice/skipall.js
new file mode 100644
index 0000000..32800b1
--- /dev/null
+++ b/commands/voice/skipall.js
@@ -0,0 +1,42 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+
+module.exports = class SkipAllVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'skipall',
+ aliases: [
+ 'endqueue',
+ 'endq',
+ 'skipqueue',
+ 'skipq'
+ ],
+ group: 'voice',
+ memberName: 'skipall',
+ description: 'Skips all the songs in the soundtrack queue.',
+ guildOnly: true,
+ examples: [
+ 'msb!endqueue',
+ 'msb!endq',
+ 'msb!skipqueue',
+ 'msb!skipq'
+ ]
+ });
+ }
+ run(msg) {
+ var voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.reply('Join a channel and try again. ' + emoji.random());
+
+ if (
+ typeof msg.guild.musicData.songDispatcher == 'undefined' ||
+ msg.guild.musicData.songDispatcher == null
+ ) {
+ return msg.reply('The soundtrack isn\'t playing right now. ' + emoji.random());
+ }
+ if (!msg.guild.musicData.queue)
+ return msg.say('This is the only song in the soundtrack queue. ' + emoji.random());
+ msg.guild.musicData.songDispatcher.end();
+ msg.guild.musicData.queue.length = 0; // clear queue
+ return;
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/skipto.js b/commands/voice/skipto.js
new file mode 100644
index 0000000..aa27add
--- /dev/null
+++ b/commands/voice/skipto.js
@@ -0,0 +1,41 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+
+module.exports = class SkipToVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'skipto',
+ group: 'voice',
+ memberName: 'skipto',
+ description: 'Skip to a certain song in the soundtrack queue.',
+ guildOnly: true,
+ args: [{
+ key: 'songNumber',
+ prompt: 'What song would you like the skip to?',
+ type: 'integer'
+ }],
+ examples: ['msb!skipto 5']
+ });
+ }
+ run(msg, { songNumber }) {
+ if (songNumber < 1 && songNumber >= msg.guild.musicData.queue.length) {
+ return msg.reply('Please enter a valid song number' + emoji.random());
+ }
+ var voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.reply('Join a channel and try again. ' + emoji.random());
+
+ if (
+ typeof msg.guild.musicData.songDispatcher == 'undefined' ||
+ msg.guild.musicData.songDispatcher == null
+ ) {
+ return msg.reply('The soundtrack isn\'t playing right now. ' + emoji.random());
+ }
+
+ if (msg.guild.musicData.queue < 1)
+ return msg.reply('This is the only song in the soundtrack queue. ' + emoji.random());
+
+ msg.guild.musicData.queue.splice(0, songNumber - 1);
+ msg.guild.musicData.songDispatcher.end();
+ return;
+ }
+}; \ No newline at end of file
diff --git a/commands/voice/volume.js b/commands/voice/volume.js
new file mode 100644
index 0000000..0a59a68
--- /dev/null
+++ b/commands/voice/volume.js
@@ -0,0 +1,44 @@
+const { Command } = require('discord.js-commando');
+const emoji = require('emoji-random');
+
+module.exports = class VolumeVoice extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'volume',
+ aliases: ['vol', 'v'],
+ group: 'voice',
+ memberName: 'volume',
+ description: 'Changes the volume of playback.',
+ guildOnly: true,
+ args: [
+ {
+ key: 'wantedVol',
+ prompt: 'What would you like the volume to be? (1 - 200)',
+ type: 'integer',
+ validate: wantedVol => wantedVol >= 1 && wantedVol <= 200
+ }
+ ],
+ examples: [
+ 'msb!volume 20',
+ 'msb!vol 50',
+ 'msb!v 70'
+ ]
+ });
+ }
+ run(msg, { wantedVol }) {
+ var voiceChannel = msg.member.voice.channel;
+ if (!voiceChannel) return msg.reply('Join a channel and try again. ' + emoji.random());
+
+ if (
+ typeof msg.guild.musicData.songDispatcher == 'undefined' ||
+ msg.guild.musicData.songDispatcher == null
+ ) {
+ return msg.reply('The soundtrack isn\'t playing right now. ' + emoji.random());
+ }
+
+ const volume = wantedVol / 100;
+ msg.guild.musicData.volume = volume;
+ msg.guild.musicData.songDispatcher.setVolume(volume);
+ msg.reply(`Volume is now: **${wantedVol}%** ` + emoji.random());
+ }
+}; \ No newline at end of file
diff --git a/config.json b/config.json
new file mode 100644
index 0000000..5adfe68
--- /dev/null
+++ b/config.json
@@ -0,0 +1,4 @@
+{
+ "secret":"Njk4ODUxMDg2MDM5MTIyMDIx.XpL56w.N-xtqZ7iFAO6IA_RR453AZZrFkE",
+ "yt-api-key":"AIzaSyB9xJENORzZt-GmOGx4WsNCPgKSIxhJcds"
+} \ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..cde9cdb
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "package",
+ "version": "1.0.0",
+ "description": "",
+ "main": "app.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "sin",
+ "license": "MIT",
+ "dependencies": {
+ "@discordjs/opus": "^0.1.0",
+ "at-quotes": "^1.3.3",
+ "btc-value": "^3.0.1",
+ "demojijs": "^1.2.0",
+ "discord.js": "github:discordjs/discord.js",
+ "discord.js-commando": "github:discordjs/Commando",
+ "emoji-random": "^0.1.2",
+ "ffmpeg-static": "^4.1.0",
+ "figlet": "^1.3.0",
+ "is-image-url": "^1.1.8",
+ "moment": "^2.24.0",
+ "moment-duration-format": "^2.3.2",
+ "node-opus": "^0.3.3",
+ "simple-youtube-api": "^5.2.1",
+ "ytdl-core": "^2.0.1"
+ }
+}