From c88421115026c3cd19c7bd22abe5dfc4cc81bd2b Mon Sep 17 00:00:00 2001 From: Trivernis Date: Sun, 23 Dec 2018 14:38:16 +0100 Subject: [PATCH] Added Data function - DataHandler handles Data (wow) - save to save playlist (server specific) - saved to get saved playlist - play with saved name plays the saved playlist - data is stored in data folder - every server has a subfolder - entry file to manage all files that should be accessable - fixed bug where music doesn't play when play was invoked - if this bug appeares again, the skip command could fix it (because it creates a dispatcher if none exists) --- bot.js | 22 +--------- lib/cmd.js | 4 +- lib/data.js | 102 +++++++++++++++++++++++++++++++++++++++++++++ lib/datahandler.js | 14 ------- lib/guilding.js | 68 +++++++++++++++++++++++------- lib/music.js | 13 +++++- 6 files changed, 168 insertions(+), 55 deletions(-) create mode 100644 lib/data.js delete mode 100644 lib/datahandler.js diff --git a/bot.js b/bot.js index f048a39..d1e6326 100644 --- a/bot.js +++ b/bot.js @@ -1,7 +1,6 @@ const Discord = require("discord.js"), fs = require('fs'), logger = require('./lib/logging').getLogger(), - music = require('./lib/music'), cmd = require("./lib/cmd"), guilding = require('./lib/guilding'), client = new Discord.Client(), @@ -10,28 +9,16 @@ const Discord = require("discord.js"), prefix = args.prefix || '~', gamepresence = args.game || 'NieR:Automata'; -let savedplaylists = {}; - function main() { - music.setLogger(logger); cmd.setLogger(logger); + guilding.setLogger(logger); cmd.init(prefix); - 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.createGlobalCommand(prefix + 'ping', () => { return 'Pong!'; @@ -40,15 +27,8 @@ function registerCommands() { cmd.createGlobalCommand(prefix + 'repeatafterme', (msg, argv, args) => { return args.join(' '); },[], "Repeats what you say"); - - cmd.createGlobalCommand(prefix + '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"); } -// defining the client's handlers - client.on('ready', () => { logger.info(`logged in as ${client.user.tag}!`); client.user.setPresence({game: {name: gamepresence, type: "PLAYING"}, status: 'online'}); diff --git a/lib/cmd.js b/lib/cmd.js index 012172e..b5e1d41 100644 --- a/lib/cmd.js +++ b/lib/cmd.js @@ -16,7 +16,7 @@ exports.Servant = class { let helpstr = "```markdown\n"; helpstr += "Commands\n---\n"; Object.entries(globCommands).concat(Object.entries(this.commands)).forEach(([key, value]) => { - let cmdhelp = `${key} [${value.args.join('] [')}]`.padEnd(25, ' '); + let cmdhelp = `${key} [${value.args.join('] [')}]`.replace('[]', '').padEnd(25, ' '); cmdhelp += value.description || ''; helpstr += `\n${cmdhelp}\n`; }); @@ -116,7 +116,7 @@ exports.init = function(prefix) { let helpstr = "```markdown\n"; helpstr += "Commands\n---\n"; Object.entries(globCommands).forEach(([key, value]) => { - let cmdhelp = `${key} [${value.args.join('] [')}]`.padEnd(25, ' '); + let cmdhelp = `${key} [${value.args.join('] [')}]`.replace('[]', '').padEnd(25, ' '); cmdhelp += value.description || ''; helpstr += `\n${cmdhelp}\n`; }); diff --git a/lib/data.js b/lib/data.js new file mode 100644 index 0000000..7042bfc --- /dev/null +++ b/lib/data.js @@ -0,0 +1,102 @@ +/* Module definition */ +const + fs = require('fs'), + path = require('path'); + +/* Variable Definition */ +let logger = require('winston'), + datapath = './data', + entryfile = 'fileentries.json'; + +fs.exists(datapath, (exist) => { + if (!exist) { + fs.mkdir(datapath, (err) => { + if (err) + logger.warn(JSON.stringify(err)); + }) + } +}); + +/* Function Definition */ + +exports.DataHandler = class { + constructor(name) { + this.workingDir = path.join(datapath, name); + this.fileEntries = {}; + this.fileData = {}; + fs.exists(this.workingDir, (exists) => { + if (!exists) { + fs.mkdir(this.workingDir, (err) => { + if (err) + logger.error(JSON.stringify(err)); + }); + } + }); + if (fs.existsSync(this.getfp(entryfile))) { + try { + this.fileEntries = this.getJSONSync(entryfile); + } catch (err) { + logger.error(JSON.stringify(err)); + } + } + } + + addEntry(name, path) { + this.fileEntries.name = path; + this.refreshEntries(); + } + + getfp(file) { + return path.join(this.workingDir, file); + } + + getcont(file, callback) { + fs.readFile(this.getfp, 'utf-8', callback); + } + + getJSONSync(file) { + return JSON.parse(fs.readFileSync(this.getfp(file), 'utf-8')); + } + + refreshEntries() { + fs.writeFile(this.getfp(entryfile), JSON.stringify(this.fileEntries), (err) => { + if (err) + logger.warn(JSON.stringify(err)); + }); + } + + getData(name) { + try { + if (this.fileData[name]) + return this.fileData[name]; + else if (this.fileEntries[name]) { + this.fileData[name] = this.getJSONSync(this.fileEntries[name]); + return this.fileData[name]; + } + return {}; + } catch (err) { + logger.error(JSON.stringify(err)); + } + } + + + setData(name, data) { + this.fileData[name] = data; + if (!this.fileEntries[name]) { + this.fileEntries[name] = name + '.json'; + } + this.refreshEntries(); + fs.writeFile(this.getfp(this.fileEntries[name]), JSON.stringify(this.fileData[name]), (err) => { + if (err) + logger.warn(JSON.stringify(err)); + }); + } +}; + +/** + * Getting the logger + * @param {Object} newLogger + */ +exports.setLogger = function (newLogger) { + logger = newLogger; +}; \ No newline at end of file diff --git a/lib/datahandler.js b/lib/datahandler.js deleted file mode 100644 index ae56f6c..0000000 --- a/lib/datahandler.js +++ /dev/null @@ -1,14 +0,0 @@ -/* Module definition */ - -/* Variable Definition */ -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 - */ -exports.getLogger = function (newLogger) { - logger = newLogger; -}; \ No newline at end of file diff --git a/lib/guilding.js b/lib/guilding.js index 1cbdaaf..c396fb2 100644 --- a/lib/guilding.js +++ b/lib/guilding.js @@ -1,25 +1,41 @@ const cmd = require('./cmd'), music = require('./music'), + data = require('./data'), handlers = {}; let logger = require('winston'); -exports.setLogger = function(newLogger) { +exports.setLogger = function (newLogger) { logger = newLogger; + music.setLogger(logger); }; -exports.GuildHandler = class{ +exports.GuildHandler = class { constructor(guild, prefix) { this.guild = guild; + this.dataHandler = new data.DataHandler(guild.name); this.dj = null; this.servant = null; this.mention = false; this.prefix = prefix || '~'; - this.data = { - savedplaylists: {} - }; this.registerMusicCommands(); } + getData(name) { + return this.dataHandler.getData(name); + } + + appendData(name, key, value) { + let data = this.getData(name); + data[key] = value; + this.dataHandler.setData(name, data); + } + + deleteDataEntry(name, key) { + let data = this.getData(name); + delete data[key]; + this.dataHandler.setData(name, data); + } + registerMusicCommands(cmdPrefix) { let prefix = cmdPrefix || this.prefix; this.dj = new music.DJ(); @@ -33,8 +49,8 @@ exports.GuildHandler = class{ if (!url) return 'No url given.'; if (!url.match(/http/g)) { - if (this.data.savedplaylists[url]) { - url = this.data.savedplaylists[url]; + if (this.getData('savedplaylists') && this.getData('savedplaylists')[url]) { + url = this.getData('savedplaylists')[url]; } else { return 'Not a valid url.'; } @@ -44,10 +60,10 @@ exports.GuildHandler = class{ this.dj.connect(vc).then(() => { this.dj.playYouTube(url); }); - }else { + } else { return this.dj.playYouTube(url); } - } catch(err) { + } catch (err) { logger.error(err); return `${JSON.stringify(err)}`; } @@ -60,15 +76,15 @@ exports.GuildHandler = class{ let url = argv['url']; if (!url) return 'No url given.'; if (!url.match(/http/g)) { - if (this.data.savedplaylists[url]) { - url = this.data.savedplaylists[url]; + if (this.getData('savedplaylists') && this.getData('savedplaylists')[url]) { + url = this.getData('savedplaylists')[url]; } else { return 'Not a valid url'; } } try { return this.dj.playYouTube(url, true); - } catch(err) { + } catch (err) { logger.error(err); return `${JSON.stringify(err)}`; } @@ -78,8 +94,7 @@ exports.GuildHandler = class{ this.createCommand(prefix + 'join', (msg) => { if (msg.member.voiceChannel) { this.dj.connect(msg.member.voiceChannel); - } - else { + } else { msg.reply("You are not connected to a voicechannel."); } }, [], "Joins the VC you are in."); @@ -112,7 +127,7 @@ exports.GuildHandler = class{ this.createCommand(prefix + 'clear', () => { this.dj.clear(); return "DJ-Queue cleared"; - }, [],"Clears the playlist."); + }, [], "Clears the playlist."); // playlist command this.createCommand(prefix + 'playlist', () => { @@ -137,6 +152,22 @@ exports.GuildHandler = class{ this.dj.shuffle(); return "Randomized the order of the queue." }, [], "Shuffles the playlist."); + + // saves playlists + this.createCommand(prefix + 'save', (msg, argv) => { + this.appendData('savedplaylists', argv.name, argv.url); + return `Saved song/playlist as ${argv['name']}` + }, ['url', 'name'], "Saves the YouTube song/playlist with a specific name"); + + // saved command - prints out saved playlists + this.createCommand(prefix + 'saved', () => { + let response = '```markdown\nSaved Playlists:\n==\n' + Object.entries(this.getData('savedplaylists')).forEach(([key, value]) => { + response += `${key.padEnd(10, ' ')} ${value} \n\n`; + }); + response += '```' + return response; + }, [], "Prints out all saved playlists."); } createCommand(command, call, args, description) { @@ -156,7 +187,12 @@ exports.GuildHandler = class{ } }; -exports.getHandler = function(guild, prefix) { +/** + * @param guild + * @param prefix + * @returns {GuildHandler} + */ +exports.getHandler = function (guild, prefix) { if (!handlers[guild.id]) handlers[guild.id] = new this.GuildHandler(guild, prefix); return handlers[guild.id]; }; \ No newline at end of file diff --git a/lib/music.js b/lib/music.js index 06f2423..fae5847 100644 --- a/lib/music.js +++ b/lib/music.js @@ -123,7 +123,7 @@ exports.DJ = class{ }); return; } - if (!this.playing) { + if (!this.playing || !this.disp) { logger.debug(`Playing ${url}`); this.disp = this.conn.playStream(ytdl(url, { filter: "audioonly" @@ -232,12 +232,21 @@ exports.DJ = class{ /** * 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. + * end event of the dispatcher that automatically plays the next song. If no dispatcher is found + * It tries to play the next song with playYouTube */ skip () { logger.debug("Skipping song"); if (this.disp !== null) { this.disp.end(); + } else { + this.playing = false; + if (this.queue.length > 0) { + this.current = this.queue.shift(); + this.playYouTube(this.current.url); + } else { + this.stop(); + } } }