Structural changes

- removed data.js
- added Bot class to bot.js
- moved handling guildhandlers to bot class
- moved shuffleArray from music to utils
- cleanup
pull/29/head
Trivernis 6 years ago
parent 21ce5efafe
commit f1abc3b9b4

@ -3,7 +3,7 @@ discordbot [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blu
A bot that does the discord thing. A bot that does the discord thing.
`node bot.js [--token=<DiscordBotToken>] [--ytapi=<GoogleApiKey>] [--owner=<DiscordTag>] [--prefix=<Char>] [--game=<String>] [-i=<Boolen>]` `node bot.node [--token=<DiscordBotToken>] [--ytapi=<GoogleApiKey>] [--owner=<DiscordTag>] [--prefix=<Char>] [--game=<String>] [-i=<Boolen>]`
The arguments are optional because the token and youtube-api-key that the bot needs to run can also be defined in the config.json in the bot's directory: The arguments are optional because the token and youtube-api-key that the bot needs to run can also be defined in the config.json in the bot's directory:
```json5 ```json5

429
bot.js

@ -5,252 +5,287 @@ const Discord = require("discord.js"),
guilding = require('./lib/guilding'), guilding = require('./lib/guilding'),
utils = require('./lib/utils'), utils = require('./lib/utils'),
config = require('./config.json'), config = require('./config.json'),
client = new Discord.Client(),
args = require('args-parser')(process.argv), args = require('args-parser')(process.argv),
sqlite3 = require('sqlite3'), sqlite3 = require('sqlite3'),
authToken = args.token || config.api.botToken, authToken = args.token || config.api.botToken,
prefix = args.prefix || config.prefix || '~', prefix = args.prefix || config.prefix || '~',
gamepresence = args.game || config.presence; gamepresence = args.game || config.presence;
let presences = [], // loaded from presences.txt file if the file exists class Bot {
rotator = null, // an interval id to stop presence duration if needed constructor() {
maindb = null; this.client = new Discord.Client();
this.mention = false;
this.rotator = null;
this.maindb = null;
this.presences = [];
this.guildHandlers = [];
function main() { logger.verbose('Registering cleanup function');
logger.verbose('Registering cleanup function'); utils.Cleanup(() => {
for (let gh in Object.values(this.guildHandlers)) {
utils.Cleanup(() => { if (gh)
guilding.destroyAll(); gh.destroy();
client.destroy(); }
}); this.client.destroy().then(() => {
cmd.setLogger(logger); logger.debug('destroyed client');
logger.verbose('Verifying config'); });
});
cmd.setLogger(logger);
logger.verbose('Verifying config');
let configVerifyer = new utils.ConfigVerifyer(config, [ let configVerifyer = new utils.ConfigVerifyer(config, [
"api.botToken", "api.youTubeApiKey" "api.botToken", "api.youTubeApiKey"
]); ]);
if (!configVerifyer.verifyConfig(logger)) { if (!configVerifyer.verifyConfig(logger)) {
if (!args.i) { if (!args.i) {
logger.info('Invalid config. Exiting'); logger.info('Invalid config. Exiting');
process.exit(1); process.exit(1);
}
} }
} guilding.setLogger(logger);
guilding.setLogger(logger); cmd.init(prefix);
cmd.init(prefix); logger.verbose('Registering commands');
logger.verbose('Registering commands'); this.registerCommands();
registerCommands(); logger.debug('Checking for ./data/ existence');
utils.dirExistence('./data', () => {
logger.debug('Checking for ./data/ existence') logger.verbose('Connecting to main database');
utils.dirExistence('./data', () => { this.maindb = new sqlite3.Database('./data/main.db', (err) => {
logger.verbose('Connecting to main database'); if (err) {
maindb = new sqlite3.Database('./data/main.db', (err) => { logger.error(err.message);
if (err) { } else {
logger.error(err.message); this.maindb.run(`${utils.sql.tableExistCreate} presences (
} else {
maindb.run(`${utils.sql.tableExistCreate} presences (
${utils.sql.pkIdSerial}, ${utils.sql.pkIdSerial},
text VARCHAR(255) UNIQUE NOT NULL text VARCHAR(255) UNIQUE NOT NULL
)`, (err) => { )`, (err) => {
if (err) { if (err) {
logger.error(err.message); logger.error(err.message);
} else { } else {
logger.debug('Loading presences'); logger.debug('Loading presences');
loadPresences(); this.loadPresences();
} }
}); });
} }
});
}); });
}); this.registerCallbacks();
registerCallbacks(); }
client.login(authToken).then(() => { start() {
logger.debug("Logged in"); return new Promise((resolve, reject) => {
}); this.client.login(authToken).then(() => {
} logger.debug("Logged in");
resolve();
}).catch((err) => {
reject(err);
});
})
}
/** /**
* If a data/presences.txt exists, it is read and each line is put into the presences array. * If a data/presences.txt exists, it is read and each line is put into the presences array.
* Each line is also stored in the main.db database. After the file is completely read, it get's deleted. * Each line is also stored in the main.db database. After the file is completely read, it get's deleted.
* Then the data is read from the database and if the presence doesn't exist in the presences array, it get's * Then the data is read from the database and if the presence doesn't exist in the presences array, it get's
* pushed in there. If the presences.txt file does not exist, the data is just read from the database. In the end * pushed in there. If the presences.txt file does not exist, the data is just read from the database. In the end
* a rotator is created that rotates the presence every configured duration. * a rotator is created that rotates the presence every configured duration.
*/ */
function loadPresences() { loadPresences() {
if(fs.existsSync('./data/presences.txt')) { if (fs.existsSync('./data/presences.txt')) {
let lineReader = require('readline').createInterface({ let lineReader = require('readline').createInterface({
input: require('fs').createReadStream('./data/presences.txt') input: require('fs').createReadStream('./data/presences.txt')
}); });
lineReader.on('line', (line) => { lineReader.on('line', (line) => {
maindb.run('INSERT INTO presences (text) VALUES (?)', [line], (err) => { this.maindb.run('INSERT INTO presences (text) VALUES (?)', [line], (err) => {
if(err) { if (err) {
logger.warn(err.message);
}
});
this.presences.push(line);
});
this.rotator = this.client.setInterval(() => this.rotatePresence(), config.presence_duration || 360000);
fs.unlink('./data/presences.txt', (err) => {
if (err)
logger.warn(err.message); logger.warn(err.message);
}
}); });
presences.push(line); this.maindb.all('SELECT text FROM presences', (err, rows) => {
}); if (err) {
rotator = client.setInterval(() => rotatePresence(), config.presence_duration || 360000); logger.warn(err.message);
fs.unlink('./data/presences.txt', (err) => { } else {
if (err) for (let row of rows) {
logger.warn(err.message); if (!row[0] in this.presences)
}); this.presences.push(row.text);
maindb.all('SELECT text FROM presences', (err, rows) => { }
if (err) {
logger.warn(err.message);
} else {
for(let row of rows) {
if (!row[0] in presences)
presences.push(row.text);
} }
} })
}) } else {
} else { this.maindb.all('SELECT text FROM presences', (err, rows) => {
maindb.all('SELECT text FROM presences', (err, rows) => { if (err) {
if (err) { logger.warn(err.message);
logger.warn(err.message); } else {
} else { for (let row of rows) {
for(let row of rows) { this.presences.push(row.text);
presences.push(row.text); }
} }
} this.rotator = this.client.setInterval(() => this.rotatePresence(), config.presence_duration || 360000);
rotator = client.setInterval(() => rotatePresence(), config.presence_duration || 360000); })
}) }
} }
}
/** /**
* registeres global commands * registeres global commands
*/ */
function registerCommands() { registerCommands() {
// useless test command // useless test command
cmd.createGlobalCommand(prefix + 'repeatafterme', (msg, argv, args) => { cmd.createGlobalCommand(prefix + 'repeatafterme', (msg, argv, args) => {
return args.join(' '); return args.join(' ');
}, [], "Repeats what you say"); }, [], "Repeats what you say");
// adds a presence that will be saved in the presence file and added to the rotation // adds a presence that will be saved in the presence file and added to the rotation
cmd.createGlobalCommand(prefix + 'addpresence', (msg, argv, args) => { cmd.createGlobalCommand(prefix + 'addpresence', (msg, argv, args) => {
let p = args.join(' '); let p = args.join(' ');
presences.push(p); this.presences.push(p);
maindb.run('INSERT INTO presences (text) VALUES (?)', [p], (err) => { this.maindb.run('INSERT INTO presences (text) VALUES (?)', [p], (err) => {
if (err) if (err)
logger.warn(err.message); logger.warn(err.message);
}); });
return `Added Presence \`${p}\``; return `Added Presence \`${p}\``;
}, [], "Adds a presence to the rotation.", 'owner'); }, [], "Adds a presence to the rotation.", 'owner');
// shuts down the bot after destroying the client // shuts down the bot after destroying the client
cmd.createGlobalCommand(prefix + 'shutdown', (msg) => { cmd.createGlobalCommand(prefix + 'shutdown', (msg) => {
msg.reply('Shutting down...').finally(() => { msg.reply('Shutting down...').finally(() => {
logger.debug('Destroying client...'); logger.debug('Destroying client...');
client.destroy().finally(() => { this.client.destroy().finally(() => {
logger.debug(`Exiting Process...`); logger.debug(`Exiting Process...`);
process.exit(0); process.exit(0);
});
}); });
}); }, [], "Shuts the bot down.", 'owner');
}, [], "Shuts the bot down.", 'owner');
// forces a presence rotation // forces a presence rotation
cmd.createGlobalCommand(prefix + 'rotate', () => { cmd.createGlobalCommand(prefix + 'rotate', () => {
try { try {
client.clearInterval(rotator); this.client.clearInterval(this.rotator);
rotatePresence(); this.rotatePresence();
rotator = client.setInterval(() => rotatePresence(), config.presence_duration); this.rotator = this.client.setInterval(() => this.rotatePresence(), config.presence_duration);
} catch (error) { } catch (error) {
logger.warn(JSON.stringify(error)); logger.warn(JSON.stringify(error));
} }
}, [], 'Force presence rotation', 'owner'); }, [], 'Force presence rotation', 'owner');
// ping command that returns the ping attribute of the client // ping command that returns the ping attribute of the client
cmd.createGlobalCommand(prefix + 'ping', () => { cmd.createGlobalCommand(prefix + 'ping', () => {
return `Current average ping: \`${client.ping} ms\``; return `Current average ping: \`${this.client.ping} ms\``;
}, [], 'Returns the current average ping', 'owner'); }, [], 'Returns the current average ping', 'owner');
// returns the time the bot is running // returns the time the bot is running
cmd.createGlobalCommand(prefix + 'uptime', () => { cmd.createGlobalCommand(prefix + 'uptime', () => {
let uptime = utils.getSplitDuration(client.uptime); let uptime = utils.getSplitDuration(this.client.uptime);
return new Discord.RichEmbed().setDescription(` return new Discord.RichEmbed().setDescription(`
**${uptime.days}** days **${uptime.days}** days
**${uptime.hours}** hours **${uptime.hours}** hours
**${uptime.minutes}** minutes **${uptime.minutes}** minutes
**${uptime.seconds}** seconds **${uptime.seconds}** seconds
**${uptime.milliseconds}** milliseconds **${uptime.milliseconds}** milliseconds
`).setTitle('Uptime'); `).setTitle('Uptime');
}, [], 'Returns the uptime of the bot', 'owner'); }, [], 'Returns the uptime of the bot', 'owner');
// returns the numbe of guilds, the bot has joined // returns the numbe of guilds, the bot has joined
cmd.createGlobalCommand(prefix + 'guilds', () => { cmd.createGlobalCommand(prefix + 'guilds', () => {
return `Number of guilds: \`${client.guilds.size}\`` return `Number of guilds: \`${this.client.guilds.size}\``
}, [], 'Returns the number of guilds the bot has joined', 'owner'); }, [], 'Returns the number of guilds the bot has joined', 'owner');
} }
/**
* changes the presence of the bot by using one stored in the presences array
*/
function rotatePresence() {
let pr = presences.shift();
presences.push(pr);
client.user.setPresence({game: {name: `${gamepresence} | ${pr}`, type: "PLAYING"}, status: 'online'});
logger.debug(`Presence rotation to ${pr}`);
}
/** /**
* Sends the answer recieved from the commands callback. * changes the presence of the bot by using one stored in the presences array
* Handles the sending differently depending on the type of the callback return */
* @param msg rotatePresence() {
* @param answer let pr = this.presences.shift();
*/ this.presences.push(pr);
function answerMessage(msg, answer) { this.client.user.setPresence({game: {name: `${gamepresence} | ${pr}`, type: "PLAYING"}, status: 'online'});
if (answer instanceof Promise || answer) { logger.debug(`Presence rotation to ${pr}`);
if (answer instanceof Discord.RichEmbed) {
(this.mention)? msg.reply('', answer) : msg.channel.send('', answer);
} else if (answer instanceof Promise) {
answer
.then((answer) => answerMessage(msg, answer))
.catch((error) => answerMessage(msg, error));
} else {
(this.mention)? msg.reply(answer) : msg.channel.send(answer);
}
} else {
logger.warn(`Empty answer won't be send.`);
} }
}
/**
* Registeres callbacks for client events
*/
function registerCallbacks() {
client.on('error', (err) => {
logger.error(err.message);
});
client.on('ready', () => { /**
logger.info(`logged in as ${client.user.tag}!`); * Registeres callbacks for client events
client.user.setPresence({game: {name: gamepresence, type: "PLAYING"}, status: 'online'}); */
}); registerCallbacks() {
this.client.on('error', (err) => {
logger.error(err.message);
});
this.client.on('ready', () => {
logger.info(`logged in as ${this.client.user.tag}!`);
this.client.user.setPresence({game: {name: gamepresence, type: "PLAYING"}, status: 'online'})
.catch((err) => {
if (err)
logger.warn(err.message);
});
});
client.on('message', msg => { this.client.on('message', msg => {
try { try {
if (msg.author === client.user) { if (msg.author === this.client.user) {
logger.verbose(`ME: ${msg.content}`); logger.verbose(`ME: ${msg.content}`);
return; return;
}
logger.verbose(`<${msg.author.tag}>: ${msg.content}`);
if (!msg.guild) {
let reply = cmd.parseMessage(msg);
this.answerMessage(msg, reply);
} else {
this.getGuildHandler(msg.guild, prefix).handleMessage(msg);
}
} catch (err) {
logger.error(err.stack);
} }
logger.verbose(`<${msg.author.tag}>: ${msg.content}`); });
if (!msg.guild) { }
let reply = cmd.parseMessage(msg);
answerMessage(msg, reply); /**
* Sends the answer recieved from the commands callback.
* Handles the sending differently depending on the type of the callback return
* @param msg
* @param answer
*/
answerMessage(msg, answer) {
if (answer instanceof Promise || answer) {
if (answer instanceof Discord.RichEmbed) {
(this.mention) ? msg.reply('', answer) : msg.channel.send('', answer);
} else if (answer instanceof Promise) {
answer
.then((answer) => answerMessage(msg, answer))
.catch((error) => answerMessage(msg, error));
} else { } else {
guilding.getHandler(msg.guild, prefix).handleMessage(msg); (this.mention) ? msg.reply(answer) : msg.channel.send(answer);
} }
} catch (err) { } else {
logger.error(err.stack); logger.warn(`Empty answer won't be send.`);
} }
}); }
/**
* Returns the guild handler by id, creates one if it doesn't exist and returns it then
* @param guild
* @param prefix
* @returns {*}
*/
getGuildHandler(guild, prefix) {
if (!this.guildHandlers[guild.id])
this.guildHandlers[guild.id] = new guilding.GuildHandler(guild, prefix);
return this.guildHandlers[guild.id];
};
} }
// Executing the main function // Executing the main function
if (typeof require !== 'undefined' && require.main === module) { if (typeof require !== 'undefined' && require.main === module) {
logger.info("Starting up... "); // log the current date so that the logfile is better to read. logger.info("Starting up... "); // log the current date so that the logfile is better to read.
main(); let discordBot = new Bot();
discordBot.start().catch((err) => {
logger.error(err.message);
});
} }

@ -21,7 +21,7 @@ exports.Servant = class {
this.createCommand(gcmdTempl.utils.help, (msg, kwargs) => { this.createCommand(gcmdTempl.utils.help, (msg, kwargs) => {
if (kwargs.command) { if (kwargs.command) {
let cmd = kwargs.command; let cmd = kwargs.command;
let allCommands ={...globCommands, ...this.commands}; let allCommands = {...globCommands, ...this.commands};
if (cmd.charAt(0) !== prefix) if (cmd.charAt(0) !== prefix)
cmd = this.prefix + cmd; cmd = this.prefix + cmd;
if (allCommands[cmd]) { if (allCommands[cmd]) {
@ -58,7 +58,7 @@ exports.Servant = class {
for (let cat of categories) { for (let cat of categories) {
helpEmbed.addField(cat, catCommands[cat]); helpEmbed.addField(cat, catCommands[cat]);
} }
helpEmbed.setFooter( prefix + 'help [command] for more info to each command'); helpEmbed.setFooter(prefix + 'help [command] for more info to each command');
return helpEmbed; return helpEmbed;
} }
}); });
@ -96,6 +96,7 @@ exports.Servant = class {
/** /**
* Removes a command * Removes a command
* @param command * @param command
* @deprecated Why would you want to remove a command?
*/ */
removeCommand(command) { removeCommand(command) {
delete this.commands[command]; delete this.commands[command];
@ -201,7 +202,7 @@ exports.init = function (prefix) {
description += `\`${key}\` \t`; description += `\`${key}\` \t`;
} }
}); });
helpEmbed.setFooter( prefix + 'help [command] for more info to each command'); helpEmbed.setFooter(prefix + 'help [command] for more info to each command');
helpEmbed.setDescription(description); helpEmbed.setDescription(description);
return helpEmbed; return helpEmbed;
} }

@ -1,138 +0,0 @@
/* 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 */
/**
* @deprecated
* @type {DataHandler}
*/
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));
}
}
}
/**
* adds an entry to the fileEntries. refreshes the entrie file
* @param name
* @param path
*/
addEntry(name, path) {
this.fileEntries.name = path;
this.refreshEntries();
}
/**
* shortcut function to join the path with the working directory
* @param file
* @returns {Promise<VoiceConnection> | string}
*/
getfp(file) {
return path.join(this.workingDir, file);
}
/**
* shortcut function that evokes the callback after reading the file. the files path is the name
* joined with the working directory
* @param file
* @param callback
*/
getcont(file, callback) {
fs.readFile(this.getfp, 'utf-8', callback);
}
/**
* returns the JSON content of a file in the working directory
* @param file
* @returns {any}
*/
getJSONSync(file) {
return JSON.parse(fs.readFileSync(this.getfp(file), 'utf-8'));
}
/**
* writes all entris of the fileEntries variable into the fileEntries file.
*/
refreshEntries() {
fs.writeFile(this.getfp(entryfile), JSON.stringify(this.fileEntries), (err) => {
if (err)
logger.warn(JSON.stringify(err));
});
}
/**
* returns the data for the entry <name>
* @param name
* @returns {*}
*/
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));
}
}
/**
* sets the entry <name> to data
* @param name
* @param data
*/
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;
};

@ -6,7 +6,7 @@ const cmd = require('./cmd'),
sqlite3 = require('sqlite3'), sqlite3 = require('sqlite3'),
Discord = require('discord.js'), Discord = require('discord.js'),
handlers = {}, handlers = {},
dbDir = './data/gdb'; dataDir = config.dataPath || './data';
let logger = require('winston'); let logger = require('winston');
exports.setLogger = function (newLogger) { exports.setLogger = function (newLogger) {
@ -29,9 +29,9 @@ exports.GuildHandler = class {
this.ready = false; this.ready = false;
this.msgsQueue = []; this.msgsQueue = [];
// checking if the data direcotry exists and if the gdb directory exists and creates them if they don't // checking if the data direcotry exists and if the gdb directory exists and creates them if they don't
utils.dirExistence('./data', () => { utils.dirExistence(dataDir, () => {
utils.dirExistence('./data/gdb', () => { utils.dirExistence(dataDir + '/gdb', () => {
this.db = new sqlite3.Database(`./data/gdb/${guild}.db`, (err) => { this.db = new sqlite3.Database(`${dataDir}/gdb/${guild}.db`, (err) => {
if (err) if (err)
logger.error(err.message); logger.error(err.message);
logger.debug(`Connected to the database for ${guild}`); logger.debug(`Connected to the database for ${guild}`);
@ -48,7 +48,10 @@ exports.GuildHandler = class {
}); });
} }
destroy(){ /**
* Destroys the guild handler
*/
destroy() {
this.dj.stop(); this.dj.stop();
this.db.close(); this.db.close();
} }
@ -82,18 +85,19 @@ exports.GuildHandler = class {
answerMessage(msg, answer) { answerMessage(msg, answer) {
if (answer instanceof Promise || answer) { if (answer instanceof Promise || answer) {
if (answer instanceof Discord.RichEmbed) { if (answer instanceof Discord.RichEmbed) {
(this.mention)? msg.reply('', answer) : msg.channel.send('', answer); (this.mention) ? msg.reply('', answer) : msg.channel.send('', answer);
} else if (answer instanceof Promise) { } else if (answer instanceof Promise) {
answer answer
.then((answer) => this.answerMessage(msg, answer)) .then((answer) => this.answerMessage(msg, answer))
.catch((error) => this.answerMessage(msg, error)); .catch((error) => this.answerMessage(msg, error));
} else { } else {
(this.mention)? msg.reply(answer) : msg.channel.send(answer); (this.mention) ? msg.reply(answer) : msg.channel.send(answer);
} }
} else { } else {
logger.warn(`Empty answer won't be send.`); logger.debug(`Empty answer won't be send.`);
} }
} }
/** /**
* handles the message by letting the servant parse the command. Depending on the message setting it * handles the message by letting the servant parse the command. Depending on the message setting it
* replies or just sends the answer. * replies or just sends the answer.
@ -142,7 +146,6 @@ exports.GuildHandler = class {
* @param cmdPrefix * @param cmdPrefix
*/ */
registerMusicCommands(cmdPrefix) { registerMusicCommands(cmdPrefix) {
let prefix = cmdPrefix || this.prefix;
this.dj = new music.DJ(); this.dj = new music.DJ();
// play command // play command
@ -186,7 +189,7 @@ exports.GuildHandler = class {
}); });
// playnext command // playnext command
this.servant.createCommand(servercmd.music.playnext,(msg, kwargs, argv) => { this.servant.createCommand(servercmd.music.playnext, (msg, kwargs, argv) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let vc = msg.member.voiceChannel; let vc = msg.member.voiceChannel;
if (!this.dj.connected) this.dj.voiceChannel = vc; if (!this.dj.connected) this.dj.voiceChannel = vc;
@ -310,23 +313,20 @@ exports.GuildHandler = class {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let saveName = argv.join(' '); let saveName = argv.join(' ');
this.db.get('SELECT COUNT(*) count FROM playlists WHERE name = ?', [saveName], (err, row) => { this.db.get('SELECT COUNT(*) count FROM playlists WHERE name = ?', [saveName], (err, row) => {
if(err) { if (err) {
logger.error(err.message); logger.error(err.message);
reject();
} }
let cb = (err) => { // defining the callback for usage below
if (err)
logger.error(err.message);
else
resolve(`Saved song/playlist as ${saveName}`);
};
if (!row || row.count === 0) { if (!row || row.count === 0) {
this.db.run('INSERT INTO playlists (name, url) VALUES (?, ?)', [saveName, kwargs.url], (err) => { this.db.run('INSERT INTO playlists (name, url) VALUES (?, ?)', [saveName, kwargs.url], cb);
if (err)
logger.error(err.message);
else
resolve(`Saved song/playlist as ${saveName}`);
});
} else { } else {
this.db.run('UPDATE playlists SET url = ? WHERE name = ?', [kwargs.url, saveName], (err) => { this.db.run('UPDATE playlists SET url = ? WHERE name = ?', [kwargs.url, saveName], cb)
if (err)
logger.error(err.message);
else
resolve(`Saved song/playlist as ${saveName}`);
});
} }
}); });
}); });
@ -337,8 +337,10 @@ exports.GuildHandler = class {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let response = ''; let response = '';
this.db.all('SELECT name, url FROM playlists', (err, rows) => { this.db.all('SELECT name, url FROM playlists', (err, rows) => {
if (err) if (err) {
logger.error(err.message); logger.error(err.message);
reject();
}
for (let row of rows) { for (let row of rows) {
response += `[${row.name}](${row.url})\n`; response += `[${row.name}](${row.url})\n`;
} }
@ -360,6 +362,7 @@ exports.GuildHandler = class {
* @param guild * @param guild
* @param prefix * @param prefix
* @returns {GuildHandler} * @returns {GuildHandler}
* @deprecated use Bot class method instead
*/ */
exports.getHandler = function (guild, prefix) { exports.getHandler = function (guild, prefix) {
if (!handlers[guild.id]) if (!handlers[guild.id])
@ -369,6 +372,7 @@ exports.getHandler = function (guild, prefix) {
/** /**
* Destroy all handlers to safely end all sql3-clients. * Destroy all handlers to safely end all sql3-clients.
* @deprecated automated in Bot class cleanup
*/ */
exports.destroyAll = function () { exports.destroyAll = function () {
logger.debug('Destroying all handlers...'); logger.debug('Destroying all handlers...');

@ -1,5 +1,4 @@
const Discord = require("discord.js"), const ytdl = require("ytdl-core"),
ytdl = require("ytdl-core"),
ypi = require('youtube-playlist-info'), ypi = require('youtube-playlist-info'),
yttl = require('get-youtube-title'), yttl = require('get-youtube-title'),
args = require('args-parser')(process.argv), args = require('args-parser')(process.argv),
@ -9,7 +8,6 @@ const Discord = require("discord.js"),
/* Variable Definition */ /* Variable Definition */
let logger = require('winston'); let logger = require('winston');
let djs = {}; let djs = {};
let connections = {};
/* Function Definition */ /* Function Definition */
@ -288,7 +286,7 @@ exports.DJ = class {
* Shuffles the queue * Shuffles the queue
*/ */
shuffle() { shuffle() {
this.queue = shuffleArray(this.queue); this.queue = utils.shuffleArray(this.queue);
} }
/** /**
@ -310,6 +308,7 @@ exports.setLogger = function (newLogger) {
/** /**
* Connects to a voicechannel * Connects to a voicechannel
* @param voiceChannel * @param voiceChannel
* @deprecated
*/ */
exports.connect = function (voiceChannel) { exports.connect = function (voiceChannel) {
let gid = voiceChannel.guild.id; let gid = voiceChannel.guild.id;
@ -322,6 +321,7 @@ exports.connect = function (voiceChannel) {
* Plays a file * Plays a file
* @param filename * @param filename
* @param guildId * @param guildId
* @deprecated
*/ */
exports.playFile = function (guildId, filename) { exports.playFile = function (guildId, filename) {
djs[guildId].playFile(filename); djs[guildId].playFile(filename);
@ -331,6 +331,7 @@ exports.playFile = function (guildId, filename) {
* Plays a YT Url * Plays a YT Url
* @param voiceChannel * @param voiceChannel
* @param url * @param url
* @deprecated
*/ */
exports.play = function (voiceChannel, url) { exports.play = function (voiceChannel, url) {
let guildId = voiceChannel.guild.id; let guildId = voiceChannel.guild.id;
@ -347,6 +348,7 @@ exports.play = function (voiceChannel, url) {
* plays the given url as next song * plays the given url as next song
* @param voiceChannel * @param voiceChannel
* @param url * @param url
* @deprecated
*/ */
exports.playnext = function (voiceChannel, url) { exports.playnext = function (voiceChannel, url) {
let guildId = voiceChannel.guild.id; let guildId = voiceChannel.guild.id;
@ -363,6 +365,7 @@ exports.playnext = function (voiceChannel, url) {
* Sets the volume of the music * Sets the volume of the music
* @param percentage * @param percentage
* @param guildId * @param guildId
* @deprecated
*/ */
exports.setVolume = function (guildId, percentage) { exports.setVolume = function (guildId, percentage) {
djs[guildId].setVolume(percentage); djs[guildId].setVolume(percentage);
@ -370,6 +373,7 @@ exports.setVolume = function (guildId, percentage) {
/** /**
* pauses the music * pauses the music
* @deprecated
*/ */
exports.pause = function (guildId) { exports.pause = function (guildId) {
djs[guildId].pause(); djs[guildId].pause();
@ -378,6 +382,7 @@ exports.pause = function (guildId) {
/** /**
* Resumes the music * Resumes the music
* @param guildId * @param guildId
* @deprecated
*/ */
exports.resume = function (guildId) { exports.resume = function (guildId) {
djs[guildId].resume(); djs[guildId].resume();
@ -386,6 +391,7 @@ exports.resume = function (guildId) {
/** /**
* Stops the music * Stops the music
* @param guildId * @param guildId
* @deprecated
*/ */
exports.stop = function (guildId) { exports.stop = function (guildId) {
djs[guildId].stop(); djs[guildId].stop();
@ -395,6 +401,7 @@ exports.stop = function (guildId) {
/** /**
* Skips the song * Skips the song
* @param guildId * @param guildId
* @deprecated
*/ */
exports.skip = function (guildId) { exports.skip = function (guildId) {
djs[guildId].skip(); djs[guildId].skip();
@ -403,6 +410,7 @@ exports.skip = function (guildId) {
/** /**
* Clears the playlist * Clears the playlist
* @param guildId * @param guildId
* @deprecated
*/ */
exports.clearQueue = function (guildId) { exports.clearQueue = function (guildId) {
djs[guildId].clear(); djs[guildId].clear();
@ -411,6 +419,7 @@ exports.clearQueue = function (guildId) {
/** /**
* Returns the queue * Returns the queue
* @param guildId * @param guildId
* @deprecated
*/ */
exports.getQueue = function (guildId) { exports.getQueue = function (guildId) {
return djs[guildId].playlist; return djs[guildId].playlist;
@ -419,6 +428,7 @@ exports.getQueue = function (guildId) {
/** /**
* evokes the callback function with the title of the current song * evokes the callback function with the title of the current song
* @param guildId * @param guildId
* @deprecated
*/ */
exports.nowPlaying = function (guildId) { exports.nowPlaying = function (guildId) {
return djs[guildId].song; return djs[guildId].song;
@ -427,31 +437,8 @@ exports.nowPlaying = function (guildId) {
/** /**
* shuffles the queue * shuffles the queue
* @param guildId * @param guildId
* @deprecated
*/ */
exports.shuffle = function (guildId) { exports.shuffle = function (guildId) {
djs[guildId].shuffle(); djs[guildId].shuffle();
}; };
/**
* Shuffles an array with Fisher-Yates Shuffle
* @param array
* @returns {Array}
*/
function shuffleArray(array) {
let currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}

@ -6,9 +6,6 @@ const fs = require('fs');
function noOp() { function noOp() {
} }
let sysdataPath = './res/data/sys.json';
let sysData = {};
/** /**
* returns the extension of a file for the given filename. * returns the extension of a file for the given filename.
* @param {String} filename The name of the file. * @param {String} filename The name of the file.
@ -47,6 +44,30 @@ exports.objectDeepFind = function (object, attributePath) {
return current; return current;
}; };
/**
* Shuffles an array with Fisher-Yates Shuffle
* @param array
* @returns {Array}#
*/
exports.shuffleArray = function(array) {
let currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
/** /**
* lets you define a cleanup for your program exit * lets you define a cleanup for your program exit
* @param {Function} callback the cleanup function * @param {Function} callback the cleanup function

Loading…
Cancel
Save