From c14f95030b9f83e6150ac17527a3cb5c9faa8f21 Mon Sep 17 00:00:00 2001 From: Trivernis Date: Fri, 21 Dec 2018 17:16:52 +0100 Subject: [PATCH 1/4] Syntax completion --- bot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot.js b/bot.js index 9a3a764..ec786db 100644 --- a/bot.js +++ b/bot.js @@ -90,7 +90,7 @@ function registerCommands() { cmd.createCommand('_', 'repeat', (msg, argv) => { return argv['repeattext']; - }, ['repeattext']) + }, ['repeattext']); } // defining the client's handlers From ec888aa5b764a14ae79141de6d7dc59f239ff86d Mon Sep 17 00:00:00 2001 From: Trivernis Date: Fri, 21 Dec 2018 18:37:33 +0100 Subject: [PATCH 2/4] Improved music.js - Added DJ class --- bot.js | 49 ++++---- lib/music.js | 321 ++++++++++++++++++++++++++++----------------------- 2 files changed, 200 insertions(+), 170 deletions(-) diff --git a/bot.js b/bot.js index ec786db..d3dc8a5 100644 --- a/bot.js +++ b/bot.js @@ -12,7 +12,6 @@ function main() { cmd.setLogger(logger); cmd.init(); registerCommands(); - music.setClient(client); client.login(authToken).then(()=> { logger.debug("Logged in"); }); @@ -20,11 +19,11 @@ function main() { function registerCommands() { cmd.createCommand('~', 'play', (msg, argv) => { - let vc = msg.member.voiceChannel; + let gid = msg.guild.id; let url = argv['url']; if (!url) return 'No url given.'; try { - return music.play(vc, url); + return music.play(gid, url); } catch(err) { logger.error(err); msg.reply(`${JSON.stringify(err)}`); @@ -45,47 +44,45 @@ function registerCommands() { }); cmd.createCommand('~', 'stop', (msg) => { - let vc = msg.member.voiceChannel; - music.stop(vc); + let gid = msg.guild.id; + music.stop(gid); }); cmd.createCommand('~', 'pause', (msg) => { - let vc = msg.member.voiceChannel; - music.pause(vc); + let gid = msg.guild.id; + music.pause(gid); }); cmd.createCommand('~', 'resume', (msg) => { - let vc = msg.member.voiceChannel; - music.resume(vc); + let gid = msg.guild.id; + music.resume(gid); }); cmd.createCommand('~', 'skip', (msg) => { - let vc = msg.member.voiceChannel; - music.skip(vc); + let gid = msg.guild.id; + music.skip(gid); }); cmd.createCommand('~', 'plist', (msg) => { - let vc = msg.member.voiceChannel; - music.getQueue(vc, (songs) => { - let songlist = "**Songs**\n"; - for (let i = 0; i < songs.length; i++) { - if (i > 10) break; - songlist += songs[i] + '\n'; - } - msg.reply(songlist); - }); + let gid = msg.guild.id; + let songs = music.getQueue(gid); + let songlist = "**Songs**\n"; + for (let i = 0; i < songs.length; i++) { + if (i > 10) break; + songlist += songs[i] + '\n'; + } + return songlist; }); cmd.createCommand('~', 'shuffle', (msg) => { - let vc = msg.member.voiceChannel; - music.shuffle(vc); + let gid = msg.guild.id; + music.shuffle(gid); }); cmd.createCommand('~', 'current', (msg) => { - let vc = msg.member.voiceChannel; - music.nowPlaying(vc, (title, url) => { - msg.reply(`Playing: ${title}\n ${url}`); - }); + let gid = msg.guild.id; + let song = music.nowPlaying(gid); + return `Playing: ${song.title}\n ${song.url}`; }); cmd.createCommand('_', 'repeat', (msg, argv) => { diff --git a/lib/music.js b/lib/music.js index a670582..89636e1 100644 --- a/lib/music.js +++ b/lib/music.js @@ -5,218 +5,251 @@ const Discord = require("discord.js"), ytapiKey = "AIzaSyBLF20r-c4mXoAT2qBFB5YlCgT0D-izOaU"; /* Variable Definition */ let logger = require('winston'); -let client = null; +let djs = {}; let connections = {}; /* Function Definition */ // TODO: initCommands function that takes the cmd.js module as variable and uses it to create commands -/** - * Getting the logger; - * @param {Object} newLogger - */ -exports.setLogger = function (newLogger) { - logger = newLogger; -}; - -/** - * Sets the discord Client for the module - * @param newClient - */ -exports.setClient = function(newClient) { - client = newClient; -}; +class DJ { + constructor(voiceChannel) { + this.conn = null; + this.disp = null; + this.queue = []; + this.playing = false; + this.current = null; + this.volume = 0.5; + this.voiceChannel = voiceChannel; + } -/** - * Connects to a voicechannel - * @param voiceChannel - */ -exports.connect = function(voiceChannel) { - logger.debug(JSON.stringify()); - logger.verbose(`Connecting to voiceChannel ${voiceChannel.name}`); - if (client !== null) { - voiceChannel.join().then(connection => { - logger.info(`Connected to Voicechannel ${voiceChannel.name}`); - connections[voiceChannel.guild.id] = { - 'conn': connection, - 'disp': null, - 'queue': [], - 'playing': false, - current: null - }; + connect() { + logger.verbose(`Connecting to voiceChannel ${this.voiceChannel.name}`); + return this.voiceChannel.join().then(connection => { + logger.info(`Connected to Voicechannel ${this.voiceChannel.name}`); + this.conn = connection; }); - } else { - logger.error("Client is null"); } -}; -/** - * Plays a file - * @param filename - */ -exports.playFile = function(voiceChannel, filename) { - let gid = voiceChannel.guild.id; - let conn = connections[gid].conn; - if (conn !== null) { - connections[gid].disp = conn.playFile(filename); - connections[gid].playing = true; - } else { - this.connect(voiceChannel); - logger.warn("Not connected to a voicechannel"); + playFile(filename) { + if (this.conn !== null) { + this.disp = this.conn.playFile(filename); + this.playing = true; + } else { + logger.warn("Not connected to a voicechannel. Connection now."); + this.connect(this.voiceChannel).then(() => { + this.playFile(filename); + }); + } } -}; -exports.play = function(voiceChannel, url) { - let gid = voiceChannel.guild.id; - if (!connections[gid]) this.connect(voiceChannel); - let conn = connections[gid].conn; - if (conn !== null) { + playYouTube(url) { + if (!this.conn) this.connect(this.voiceChannel).then(this.playYouTube(url)); let plist = url.match(/(?<=\?list=)[\w\-]+/g); if (plist) { logger.debug(`Adding playlist ${plist} to queue`); ypi(ytapiKey, plist).then(items => { for (let i = 0; i < items.length; i++) { let vurl = `https://www.youtube.com/watch?v=${items[i].resourceId.videoId}`; - connections[gid].queue.push(vurl); + this.queue.push({'url': vurl, 'title': null}); + yttl(vurl.replace(/http(s)?:\/\/(www.)?youtube.com\/watch\?v=/g, ''), (err, title) => { + if (err) { + logger.error(err); + } else { + this.queue.find((el) => { + return (el.url === vurl); + }).title = title; + } + }); } - this.play(voiceChannel, connections[gid].queue.shift()); + this.playYouTube(this.queue.shift().url); }); return; } - if (!connections[gid].playing) { + if (!this.playing) { logger.debug(`Playing ${url}`); - connections[gid].disp = conn.playStream(ytdl(url, { + this.disp = this.conn.playStream(ytdl(url, { filter: "audioonly" - }), {seek: 0, volume: 0.5}); - connections[gid].disp.on('end', () => { - connections[gid].playing = false; - connections[gid].current = null; - if (connections[gid].queue.length > 0) { - this.play(voiceChannel, connections[gid].queue.shift()); + }), {seek: 0, volume: this.volume}); + this.disp.on('end', () => { + this.playing = false; + this.current = null; + if (this.queue.length > 0) { + this.current = this.queue.shift() + this.playYouTube(this.current.url); + } else { + this.stop(); } }); - connections[gid].playing = true; - connections[gid].current = url; + this.playing = true; } else { logger.debug(`Added ${url} to the queue`); - connections[gid].queue.push(url); + this.queue.push(url); + } + } + + setVolume(percentage) { + logger.verbose(`Setting volume to ${percentage}`); + if (this.disp !== null) { + this.disp.setVolume(percentage); + } else { + logger.warn("No dispatcher found.") } - } else { - logger.warn("Not connected to a voicechannel"); } + + pause() { + logger.verbose("Pausing music..."); + if (this.disp !== null) { + this.disp.pause(); + } else { + logger.warn("No dispatcher found"); + } + } + + resume() { + logger.verbose("Resuming music..."); + if (this.disp !== null) { + this.disp.resume(); + } else { + logger.warn("No dispatcher found"); + } + } + + stop() { + logger.verbose("Stopping music..."); + if (this.disp !== null) { + this.disp.end(); + logger.debug("Ended dispatcher"); + } + if (this.conn !== null) { + this.conn.disconnect(); + logger.debug("Ended connection"); + } + } + + skip () { + logger.debug("Skipping song"); + if (this.disp !== null) { + this.disp.end(); + } + } + + get playlist() { + let songs = []; + this.queue.forEach((entry) => { + songs.push(entry.title); + }); + return songs; + } + + get song() { + return this.current.title; + } + + shuffle() { + this.queue = shuffleArray(this.queue); + } +} + +/** + * Getting the logger; + * @param {Object} newLogger + */ +exports.setLogger = function (newLogger) { + logger = newLogger; +}; + +/** + * Connects to a voicechannel + * @param voiceChannel + */ +exports.connect = function(voiceChannel) { + let gid = voiceChannel.guild.id; + let voiceDJ = new DJ(voiceChannel); + voiceDJ.connect(); + djs[gid] = voiceDJ; +}; + +/** + * Plays a file + * @param filename + * @param guildId + */ +exports.playFile = function(guildId, filename) { + djs[guildId].playFile(filename); +}; + +/** + * Plays a YT Url + * @param guildId + * @param url + */ +exports.play = function(guildId, url) { + djs[guildId].playYouTube(url); }; /** * Sets the volume of the music * @param percentage - * @param voiceChannel + * @param guildId */ -exports.setVolume = function(voiceChannel, percentage) { - let disp = connections[voiceChannel.guild.id].disp; - logger.verbose(`Setting volume to ${percentage}`); - if (disp !== null) { - disp.setVolume(percentage); - } else { - logger.warn("No dispatcher found.") - } +exports.setVolume = function(guildId, percentage) { + djs[guildId].setVolume(percentage); }; /** * pauses the music */ -exports.pause = function(voiceChannel) { - let disp = connections[voiceChannel.guild.id].disp; - logger.verbose("Pausing music..."); - if (disp !== null) { - disp.pause(); - } else { - logger.warn("No dispatcher found"); - } +exports.pause = function(guildId) { + djs[guildId].pause(); }; /** * Resumes the music + * @param guildId */ -exports.resume = function(voiceChannel) { - let disp = connections[voiceChannel.guild.id].disp; - logger.verbose("Resuming music..."); - if (disp !== null) { - disp.resume(); - } else { - logger.warn("No dispatcher found"); - } +exports.resume = function(guildId) { + djs[guildId].resume(); }; /** * Stops the music + * @param guildId */ -exports.stop = function(voiceChannel) { - let gid = voiceChannel.guild.id; - let disp = connections[gid].disp; - let conn = connections[gid].conn; - logger.verbose("Stopping music..."); - if (disp !== null) { - disp.end(); - logger.debug("Ended dispatcher"); - } - if (conn !== null) { - conn.disconnect(); - logger.debug("Ended connection"); - } - connections[gid].playing = false; +exports.stop = function(guildId) { + djs[guildId].stop(); + delete djs[guildId]; }; /** * Skips the song + * @param guildId */ -exports.skip = function(voiceChannel) { - let disp = connections[voiceChannel.guild.id].disp; - logger.debug("Skipping song"); - if (disp !== null) { - disp.end(); - } +exports.skip = function(guildId) { + djs[guildId].skip(); }; /** - * executes the callback when the titlelist is finished + * Returns the queue + * @param guildId */ -exports.getQueue = function(voiceChannel, callback) { - let titles = []; - connections[voiceChannel.guild.id].queue.forEach((url) => { - yttl(url.replace(/http(s)?:\/\/(www.)?youtube.com\/watch\?v=/g, ''), (err, title) => { - if (err) { - logger.error(err); - } else { - titles.push(title); - } - }); - }); - setTimeout(() => callback(titles), 2000 ); +exports.getQueue = function(guildId) { + return djs[guildId].playlist; }; /** * evokes the callback function with the title of the current song - * @param callback - * @param voiceChannel + * @param guildId */ -exports.nowPlaying = function(voiceChannel, callback) { - let gid = voiceChannel.guild.id; - if (connections[gid].queue.length > 0) { - yttl(connections[gid].current.replace(/http(s)?:\/\/(www.)?youtube.com\/watch\?v=/g, ''), (err, title) => { - if (err) { - logger.error(err); - } else { - callback(title, connections[gid].current); - } - }); - } +exports.nowPlaying = function(guildId) { + return djs[guildId].song; }; /** * shuffles the queue + * @param guildId */ -exports.shuffle = function(voiceChannel) { - connections[voiceChannel.guild.id].queue = shuffle(connections[voiceChannel.guild.id].queue); +exports.shuffle = function(guildId) { + djs[guildId].shuffle(); }; /** @@ -224,7 +257,7 @@ exports.shuffle = function(voiceChannel) { * @param array * @returns {Array} */ -function shuffle(array) { +function shuffleArray(array) { let currentIndex = array.length, temporaryValue, randomIndex; // While there remain elements to shuffle... From 3dde5c40cb7d1f289bf695611ab31200b2594279 Mon Sep 17 00:00:00 2001 From: Trivernis Date: Fri, 21 Dec 2018 19:08:45 +0100 Subject: [PATCH 3/4] Fixed Bugs created by changing music.js - Fixed output of current song - Fixed output of playlist - Fixed toggeling skip - Fixed next auto toggle --- bot.js | 1 + lib/music.js | 85 +++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/bot.js b/bot.js index d3dc8a5..9dc1a97 100644 --- a/bot.js +++ b/bot.js @@ -66,6 +66,7 @@ function registerCommands() { cmd.createCommand('~', 'plist', (msg) => { let gid = msg.guild.id; let songs = music.getQueue(gid); + logger.debug(`found ${songs.length} songs`); let songlist = "**Songs**\n"; for (let i = 0; i < songs.length; i++) { if (i > 10) break; diff --git a/lib/music.js b/lib/music.js index 89636e1..0dd5efe 100644 --- a/lib/music.js +++ b/lib/music.js @@ -22,7 +22,16 @@ class DJ { this.voiceChannel = voiceChannel; } + /** + * Connects to the given voice channel. Disconnects from the previous one if it exists. + * When the bot was moved and connect is executed again, it connects to the initial VoiceChannel because the + * VoiceChannel is saved as object variable. + * @returns {Promise} + */ connect() { + if (this.conn) { + this.stop(); + } logger.verbose(`Connecting to voiceChannel ${this.voiceChannel.name}`); return this.voiceChannel.join().then(connection => { logger.info(`Connected to Voicechannel ${this.voiceChannel.name}`); @@ -30,6 +39,11 @@ class DJ { }); } + /** + * Plays a file for the given filename. + * TODO: Implement queue + * @param filename + */ playFile(filename) { if (this.conn !== null) { this.disp = this.conn.playFile(filename); @@ -42,6 +56,12 @@ class DJ { } } + /** + * Plays the url of the current song if there is no song playing or puts it in the queue. + * If the url is a playlist (regex match), the videos of the playlist are fetched and put + * in the queue. For each song the title is saved in the queue too. + * @param url + */ playYouTube(url) { if (!this.conn) this.connect(this.voiceChannel).then(this.playYouTube(url)); let plist = url.match(/(?<=\?list=)[\w\-]+/g); @@ -55,13 +75,19 @@ class DJ { if (err) { logger.error(err); } else { - this.queue.find((el) => { - return (el.url === vurl); - }).title = title; + try { + logger.debug(`Found title: ${title} for ${vurl}`); + this.queue.find((el) => { + return (el.url === vurl); + }).title = title; + } catch (error) { + logger.error(JSON.stringify(error)); + } } }); } - this.playYouTube(this.queue.shift().url); + this.current = this.queue.shift(); + this.playYouTube(this.current.url); }); return; } @@ -74,7 +100,7 @@ class DJ { this.playing = false; this.current = null; if (this.queue.length > 0) { - this.current = this.queue.shift() + this.current = this.queue.shift(); this.playYouTube(this.current.url); } else { this.stop(); @@ -83,19 +109,41 @@ class DJ { this.playing = true; } else { logger.debug(`Added ${url} to the queue`); - this.queue.push(url); + this.queue.push({'url': url, 'title': null}); + yttl(url.replace(/http(s)?:\/\/(www.)?youtube.com\/watch\?v=/g, ''), (err, title) => { + if (err) { + logger.error(err); + } else { + try { + logger.debug(`Found title: ${title} for ${url}`); + this.queue.find((el) => { + return (el.url === url); + }).title = title; + } catch (error) { + console.error(JSON.stringify(error)); + } + } + }); } } + /** + * Sets the volume of the dispatcher to the given value + * @param percentage + */ setVolume(percentage) { logger.verbose(`Setting volume to ${percentage}`); if (this.disp !== null) { + this.volume = percentage; this.disp.setVolume(percentage); } else { logger.warn("No dispatcher found.") } } + /** + * Pauses if a dispatcher exists + */ pause() { logger.verbose("Pausing music..."); if (this.disp !== null) { @@ -105,6 +153,9 @@ class DJ { } } + /** + * Resumes if a dispatcher exists + */ resume() { logger.verbose("Resuming music..."); if (this.disp !== null) { @@ -114,7 +165,11 @@ class DJ { } } + /** + * Stops playing music by ending the Dispatcher and disconnecting + */ stop() { + this.queue = []; logger.verbose("Stopping music..."); if (this.disp !== null) { this.disp.end(); @@ -126,6 +181,10 @@ class DJ { } } + /** + * Skips to the next song by ending the current StreamDispatcher and thereby triggering the + * end event of the dispatcher that automatically plays the next song. + */ skip () { logger.debug("Skipping song"); if (this.disp !== null) { @@ -133,18 +192,30 @@ class DJ { } } + /** + * Returns the title for each song saved in the queue + * @returns {Array} + */ get playlist() { let songs = []; + logger.debug(`Playlist: ${JSON.stringify(this.queue)}`); this.queue.forEach((entry) => { songs.push(entry.title); }); return songs; } + /** + * Returns the song saved in the private variable 'current' + * @returns {null|*} + */ get song() { - return this.current.title; + return this.current; } + /** + * Shuffles the queue + */ shuffle() { this.queue = shuffleArray(this.queue); } From 08091ba15ae88b007f06891296aab7853cee0a4c Mon Sep 17 00:00:00 2001 From: Trivernis Date: Fri, 21 Dec 2018 20:57:22 +0100 Subject: [PATCH 4/4] More Fixes - Playlists can be saved (will be server specific in the future) - Saved playlists can be played with ~play --- bot.js | 86 ++++++++++++++++++------ lib/cmd.js | 14 ++-- lib/{datacollector.js => datahandler.js} | 2 +- lib/music.js | 63 ++++++++++++++--- 4 files changed, 128 insertions(+), 37 deletions(-) rename lib/{datacollector.js => datahandler.js} (69%) diff --git a/bot.js b/bot.js index 9dc1a97..e9ca33f 100644 --- a/bot.js +++ b/bot.js @@ -1,38 +1,72 @@ const Discord = require("discord.js"), + fs = require('fs'), logger = require('./lib/logging').getLogger(), - music = require('./lib/music'); + music = require('./lib/music'), cmd = require("./lib/cmd"), client = new Discord.Client(), args = require('args-parser')(process.argv), - authToken = args.token, - prefix = '~'; + authToken = args.token; + +let savedplaylists = {}; function main() { music.setLogger(logger); cmd.setLogger(logger); cmd.init(); + if (fs.existsSync('./data/savedplaylists.json')) { + savedplaylists = JSON.parse(fs.readFileSync('./data/savedplaylists.json')) + } registerCommands(); client.login(authToken).then(()=> { logger.debug("Logged in"); }); } +function savePlaylist(url, name) { + savedplaylists[name] = url; + fs.writeFile('./data/savedplaylists.json',JSON.stringify(savedplaylists), (err) => { + if (err) logger.warn(JSON.stringify(err)); + }) +} + function registerCommands() { cmd.createCommand('~', 'play', (msg, argv) => { - let gid = msg.guild.id; + let vc = msg.member.voiceChannel; let url = argv['url']; if (!url) return 'No url given.'; + if (!url.match(/http/g)) { + if (savedplaylists[url]) { + url = savedplaylists[url]; + } + } try { - return music.play(gid, url); + return music.play(vc, url); } catch(err) { logger.error(err); msg.reply(`${JSON.stringify(err)}`); } - }, ['url']); + }, ['url'], "Adds the url to the YouTube video/playlist into the queue."); + + cmd.createCommand('~', 'playnext', (msg, argv) => { + let vc = msg.member.voiceChannel; + let url = argv['url']; + if (!url) return 'No url given.'; + if (!url.match(/http/g)) { + if (savedplaylists[url]) { + url = savedplaylists[url]; + } + } + try { + return music.playnext(vc, url); + } catch(err) { + logger.error(err); + msg.reply(`${JSON.stringify(err)}`); + } + }, ['url'], "Plays the YouTube video after the currently playing song."); cmd.createCommand('~', 'ping', () => { return 'Pong!'; - }); + }, [], "Try it yourself."); cmd.createCommand('~', 'join', (msg) => { if (msg.member.voiceChannel) { @@ -41,54 +75,66 @@ function registerCommands() { else { msg.reply("You are not connected to a voicechannel."); } - }); + }, [], "Joins the VC you are in."); cmd.createCommand('~', 'stop', (msg) => { let gid = msg.guild.id; music.stop(gid); - }); + }, [], "Stops playling music and leavs."); cmd.createCommand('~', 'pause', (msg) => { let gid = msg.guild.id; music.pause(gid); - }); + }, [], "Pauses playing."); cmd.createCommand('~', 'resume', (msg) => { let gid = msg.guild.id; music.resume(gid); - }); + }, [], "Resumes playing."); cmd.createCommand('~', 'skip', (msg) => { let gid = msg.guild.id; music.skip(gid); - }); + }, [], "Skips the current song."); - cmd.createCommand('~', 'plist', (msg) => { + cmd.createCommand('~', 'clear', (msg) => { + let gid = msg.guild.id; + music.clearQueue(gid); + return "All songs have been deleted, commander :no_mouth: " + }, [],"Clears the playlist."); + + cmd.createCommand('~', 'playlist', (msg) => { let gid = msg.guild.id; let songs = music.getQueue(gid); logger.debug(`found ${songs.length} songs`); - let songlist = "**Songs**\n"; + let songlist = `**${songs.length} Songs in playlist**\n`; for (let i = 0; i < songs.length; i++) { if (i > 10) break; songlist += songs[i] + '\n'; } return songlist; - }); + }, [], "Shows the next ten songs."); cmd.createCommand('~', 'shuffle', (msg) => { let gid = msg.guild.id; music.shuffle(gid); - }); + return "The queue has successfully been shuffled :slight_smile:" + }, [], "Shuffles the playlist."); cmd.createCommand('~', 'current', (msg) => { let gid = msg.guild.id; let song = music.nowPlaying(gid); return `Playing: ${song.title}\n ${song.url}`; - }); + }, [], "Shows the currently playing song."); + + cmd.createCommand('~', 'repeatafterme', (msg, argv) => { + return argv['word']; + }, ['word'], "Repeats a single word you say."); - cmd.createCommand('_', 'repeat', (msg, argv) => { - return argv['repeattext']; - }, ['repeattext']); + cmd.createCommand('~', 'save', (msg, argv) => { + savePlaylist(argv['url'], argv['name']); + return `Saved song/playlist as ${argv['name']}` + }, ['url', 'name'], "Saves the YouTube song/playlist with a specific name. ~play [name] to play the playlist"); } // defining the client's handlers diff --git a/lib/cmd.js b/lib/cmd.js index 7e4b5cc..27f40fe 100644 --- a/lib/cmd.js +++ b/lib/cmd.js @@ -14,13 +14,14 @@ exports.setLogger = function(newLogger) { logger = newLogger; }; -exports.createCommand = function(prefix, command, call, argv) { +exports.createCommand = function(prefix, command, call, argv, description) { try { logger.debug(`Creating command ${command} with prefix ${prefix} and arguments ${argv}`); if (!commands[prefix]) commands[prefix] = {}; // create Object commands prefix commands[prefix][command] = { // assign the command - args: argv || [], // with arguments - callback: call // and function + args: argv || [], + callback: call, + description: description }; logger.debug(`Created command ${prefix}${command}`); } catch (err) { @@ -80,10 +81,13 @@ exports.init = function() { helpstr += "Commands\n---\n"; Object.keys(commands).forEach((key) => { Object.keys(commands[key]).forEach((cmd) => { - helpstr += "\n" + key + cmd + " " + JSON.stringify(commands[key][cmd].args) + "\n"; + helpstr += "\n" + key + cmd + " " + JSON.stringify(commands[key][cmd].args).replace(/"|\[\]/g, ''); + if (commands[key][cmd].description) { + helpstr += '\t' + commands[key][cmd].description + '\n'; + } }); }); helpstr += "```"; return helpstr; - }); + }, [], "Shows this help."); }; \ No newline at end of file diff --git a/lib/datacollector.js b/lib/datahandler.js similarity index 69% rename from lib/datacollector.js rename to lib/datahandler.js index 5962a62..ae56f6c 100644 --- a/lib/datacollector.js +++ b/lib/datahandler.js @@ -4,7 +4,7 @@ let logger = require('winston'); /* Function Definition */ - +// TODO: Class that handles file-data for a server, functions to get/set data for specific server id /** * Getting the logger * @param {Object} newLogger diff --git a/lib/music.js b/lib/music.js index 0dd5efe..f3f0808 100644 --- a/lib/music.js +++ b/lib/music.js @@ -62,7 +62,7 @@ class DJ { * in the queue. For each song the title is saved in the queue too. * @param url */ - playYouTube(url) { + playYouTube(url, playnext) { if (!this.conn) this.connect(this.voiceChannel).then(this.playYouTube(url)); let plist = url.match(/(?<=\?list=)[\w\-]+/g); if (plist) { @@ -73,7 +73,7 @@ class DJ { this.queue.push({'url': vurl, 'title': null}); yttl(vurl.replace(/http(s)?:\/\/(www.)?youtube.com\/watch\?v=/g, ''), (err, title) => { if (err) { - logger.error(err); + logger.debug(JSON.stringify(err)); } else { try { logger.debug(`Found title: ${title} for ${vurl}`); @@ -81,7 +81,7 @@ class DJ { return (el.url === vurl); }).title = title; } catch (error) { - logger.error(JSON.stringify(error)); + logger.verbose(JSON.stringify(error)); } } }); @@ -109,10 +109,14 @@ class DJ { this.playing = true; } else { logger.debug(`Added ${url} to the queue`); - this.queue.push({'url': url, 'title': null}); + if (playnext) { + this.queue.unshift({'url': url, 'title': null}); + } else { + this.queue.push({'url': url, 'title': null}); + } yttl(url.replace(/http(s)?:\/\/(www.)?youtube.com\/watch\?v=/g, ''), (err, title) => { if (err) { - logger.error(err); + logger.debug(JSON.stringify(err)); } else { try { logger.debug(`Found title: ${title} for ${url}`); @@ -120,7 +124,7 @@ class DJ { return (el.url === url); }).title = title; } catch (error) { - console.error(JSON.stringify(error)); + console.verbose(JSON.stringify(error)); } } }); @@ -198,7 +202,6 @@ class DJ { */ get playlist() { let songs = []; - logger.debug(`Playlist: ${JSON.stringify(this.queue)}`); this.queue.forEach((entry) => { songs.push(entry.title); }); @@ -219,6 +222,13 @@ class DJ { shuffle() { this.queue = shuffleArray(this.queue); } + + /** + * Clears the playlist + */ + clear() { + this.queue = []; + } } /** @@ -236,8 +246,8 @@ exports.setLogger = function (newLogger) { exports.connect = function(voiceChannel) { let gid = voiceChannel.guild.id; let voiceDJ = new DJ(voiceChannel); - voiceDJ.connect(); djs[gid] = voiceDJ; + return voiceDJ.connect(); }; /** @@ -251,11 +261,34 @@ exports.playFile = function(guildId, filename) { /** * Plays a YT Url - * @param guildId + * @param voiceChannel + * @param url + */ +exports.play = function(voiceChannel, url) { + let guildId = voiceChannel.guild.id; + if (!djs[guildId]) { + this.connect(voiceChannel).then(() => { + djs[guildId].playYouTube(url); + }); + } else { + djs[guildId].playYouTube(url); + } +}; + +/** + * plays the given url as next song + * @param voiceChannel * @param url */ -exports.play = function(guildId, url) { - djs[guildId].playYouTube(url); +exports.playnext = function(voiceChannel, url) { + let guildId = voiceChannel.guild.id; + if (!djs[guildId]) { + this.connect(voiceChannel).then(() => { + djs[guildId].playYouTube(url, true); + }); + } else { + djs[guildId].playYouTube(url, true); + } }; /** @@ -299,6 +332,14 @@ exports.skip = function(guildId) { djs[guildId].skip(); }; +/** + * Clears the playlist + * @param guildId + */ +exports.clearQueue = function(guildId) { + djs[guildId].clear(); +}; + /** * Returns the queue * @param guildId