From 08091ba15ae88b007f06891296aab7853cee0a4c Mon Sep 17 00:00:00 2001 From: Trivernis Date: Fri, 21 Dec 2018 20:57:22 +0100 Subject: [PATCH] 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