Merge pull request #13 from Trivernis/develop

Develop
pull/14/head
Trivernis 6 years ago committed by GitHub
commit 61ae3937d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,7 +3,34 @@ discordbot
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>]` `node bot.js [--token=<DiscordBotToken>] [--ytapi=<GoogleApiKey>] [--owner=<DiscordTag>] [--prefix=<Char>] [--game=<String>]`
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
// config.json
{
"prefix": "_",
"token": "DISCORD BOT TOKEN",
"ytapikey": "YOUTUBE API KEY",
"presence": "THE DEFAULT GAME IF NO presences.txt IS FOUND IN ./data/",
"presence_duration": 300000,
"owners": [
"SPECIFY A LIST OF BOT-OWNERS"
],
"music": {
"timeout": 300000
}
}
```
Features
---
At the moment the bot can...
- [x] ...play music (YouTube videos and playlists)
- [x] ...save songs/playlists with a given name
- [x] ...log stuff in a database
- [ ] ...transform into a cow
Ideas Ideas
--- ---

@ -39,8 +39,6 @@ function main() {
client.login(authToken).then(() => { client.login(authToken).then(() => {
logger.debug("Logged in"); logger.debug("Logged in");
}); });
} }
function registerCommands() { function registerCommands() {

@ -114,15 +114,17 @@
"name": "save", "name": "save",
"permission": "dj", "permission": "dj",
"args": [ "args": [
"url", "url"
"name"
], ],
"description": "Saves the YouTube song/playlist with a specific name" "description": "Saves the YouTube song/playlist with a specific name"
}, },
"saved": { "saved": {
"name": "saved", "name": "saved",
"permission": "all", "permission": "all",
"description": "Prints out all saved playlists." "description": "Prints out all saved playlists.",
"response": {
"no_saved": "There are no saved songs/playlists :("
}
} }
} }
} }

@ -103,7 +103,12 @@ module.exports.Servant = class {
} }
let argv = argvars.slice(nLength); let argv = argvars.slice(nLength);
logger.debug(`Executing callback for command: ${command}, kwargs: ${kwargs}, argv: ${argv}`); logger.debug(`Executing callback for command: ${command}, kwargs: ${kwargs}, argv: ${argv}`);
try {
return cmd.callback(msg, kwargs, argv) || globResult; return cmd.callback(msg, kwargs, argv) || globResult;
} catch (err) {
logger.error(err.message);
return `The command \`${command}\` has thrown an error.`;
}
} }
}; };
@ -189,16 +194,16 @@ function parseGlobalCommand(msg) {
/** /**
* @param msg * @param msg
* @param role {String} * @param rolePerm {String}
* @returns {boolean} * @returns {boolean}
*/ */
function checkPermission(msg, role) { function checkPermission(msg, rolePerm) {
if (!role || ['all', 'any', 'everyone'].includes(role)) if (!rolePerm || ['all', 'any', 'everyone'].includes(rolePerm))
return true; return true;
if (msg.author.tag === args.owner || config.owners.includes(msg.author.tag)) { if (msg.author.tag === args.owner || config.owners.includes(msg.author.tag)) {
return true; return true;
} else { } else {
if (msg.member && role && msg.member.roles.some(role => role.name.toLowerCase() === role.toLowerCase())) if (msg.member && rolePerm && msg.member.roles.some(role => role.name.toLowerCase() === rolePerm.toLowerCase()))
return true return true
} }
return false return false

@ -18,7 +18,10 @@ fs.exists(datapath, (exist) => {
}); });
/* Function Definition */ /* Function Definition */
/**
* @deprecated
* @type {DataHandler}
*/
exports.DataHandler = class { exports.DataHandler = class {
constructor(name) { constructor(name) {
this.workingDir = path.join(datapath, name); this.workingDir = path.join(datapath, name);

@ -1,9 +1,11 @@
const cmd = require('./cmd'), const cmd = require('./cmd'),
music = require('./music'), music = require('./music'),
data = require('./data'), utils = require('./utils.js'),
config = require('../config.json'), config = require('../config.json'),
servercmd = require('../commands/servercommands'), servercmd = require('../commands/servercommands'),
handlers = {}; sqlite3 = require('sqlite3'),
handlers = {},
dbDir = './data/gdb';
let logger = require('winston'); let logger = require('winston');
exports.setLogger = function (newLogger) { exports.setLogger = function (newLogger) {
@ -11,61 +13,65 @@ exports.setLogger = function (newLogger) {
music.setLogger(logger); music.setLogger(logger);
}; };
/**
* Server-Specific commands, music and more
* @type {GuildHandler}
*/
exports.GuildHandler = class { exports.GuildHandler = class {
constructor(guild, prefix) { constructor(guild, prefix) {
this.guild = guild; this.guild = guild;
this.dataHandler = new data.DataHandler(guild.name);
this.dj = null; this.dj = null;
this.mention = false; this.mention = false;
this.prefix = prefix || config.prefix; this.prefix = prefix || config.prefix;
this.servant = new cmd.Servant(this.prefix); this.servant = new cmd.Servant(this.prefix);
utils.dirExistence('./data', () => {
utils.dirExistence('./data/gdb', () => {
this.db = new sqlite3.Database(`./data/gdb/${guild}.db`);
this.createTables();
})
});
this.registerMusicCommands(); this.registerMusicCommands();
} }
/** /**
* function shortcut returns the data from the dataHandler * Creates all tables needed in the Database.
* @param name * These are at the moment:
* @returns {{}} * messages - logs all messages send on the server
* playlists - save playlists to play them later
*/ */
getData(name) { createTables() {
return this.dataHandler.getData(name); let createCmd = 'CREATE TABLE IF NOT EXISTS';
let autoIdPK = 'id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL';
this.db.run(`${createCmd} messages (
${autoIdPK},
creation_timestamp DATETIME NOT NULL,
author VARCHAR(128) NOT NULL,
author_name VARCHAR(128),
content TEXT NOT NULL
)`);
this.db.run(`${createCmd} playlists (
${autoIdPK},
name VARCHAR(32) UNIQUE NOT NULL,
url VARCHAR(255) NOT NULL
)`);
} }
/**
* appends data to the data handler
* @param name
* @param key
* @param value
*/
appendData(name, key, value) {
let data = this.getData(name);
data[key] = value;
this.dataHandler.setData(name, data);
}
/**
* deletes an entry from the data handler
* @param name
* @param key
*/
deleteDataEntry(name, key) {
let data = this.getData(name);
delete data[key];
this.dataHandler.setData(name, data);
}
/**
* registers all music commands and initializes a dj
* @param cmdPrefix
*/
/** /**
* 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.
* @param msg * @param msg
*/ */
handleMessage(msg) { handleMessage(msg) {
if (this.db) {
this.db.run(
'INSERT INTO messages (author, creation_timestamp, author_name, content) values (?, ?, ?, ?)',
[msg.author.id, msg.createdTimestamp, msg.author.username, msg.content],
(err) => {
if (err)
logger.error(err.message);
}
);
}
let answer = this.servant.parseCommand(msg); let answer = this.servant.parseCommand(msg);
if (!answer) return; if (!answer) return;
if (this.mention) { if (this.mention) {
@ -75,59 +81,98 @@ exports.GuildHandler = class {
} }
} }
/**
* Connect to a voice-channel if not connected and play the url
* @param vc
* @param url
*/
connectAndPlay(vc, url) {
if (!this.dj.connected) {
this.dj.connect(vc).then(() => {
this.dj.playYouTube(url);
});
} else {
this.dj.playYouTube(url);
}
}
/**
* registers all music commands and initializes a dj
* @param cmdPrefix
*/
registerMusicCommands(cmdPrefix) { registerMusicCommands(cmdPrefix) {
let prefix = cmdPrefix || this.prefix; let prefix = cmdPrefix || this.prefix;
this.dj = new music.DJ(); this.dj = new music.DJ();
// play command // play command
this.servant.createCommand(servercmd.music.play, (msg, argv) => { this.servant.createCommand(servercmd.music.play, (msg, kwargs, argv) => {
let vc = msg.member.voiceChannel; let vc = msg.member.voiceChannel;
let url = argv['url']; let url = kwargs['url'];
if (!vc) if (!vc)
return 'You are not connected to a VoiceChannel'; return 'You are not connected to a VoiceChannel';
if (!url) if (!url)
return servercmd.music.play.response.no_url; return servercmd.music.play.response.no_url;
if (!url.match(/http/g)) { if (!url.match(/http/g)) {
if (this.getData('savedplaylists') && this.getData('savedplaylists')[url]) { if (argv)
url = this.getData('savedplaylists')[url]; url += ' ' + argv.join(' ');
} else { this.db.get('SELECT url FROM playlists WHERE name = ?', [url], (err, row) => {
return servercmd.music.play.response.url_invalid; if (err) {
console.error(err.message);
} }
if (!row) {
return servercmd.music.play.response.url_invalid;
} }
url = row.url;
try { try {
if (!this.dj.connected) { this.connectAndPlay(vc, url);
this.dj.connect(vc).then(() => { } catch (err) {
this.dj.playYouTube(url); logger.error(err.message);
return servercmd.music.play.response.failure;
}
}); });
} else { } else {
this.dj.playYouTube(url); try {
} this.connectAndPlay(vc, url);
} catch (err) { } catch (err) {
logger.error(err); logger.error(err.message);
return servercmd.music.play.response.failure; return servercmd.music.play.response.failure;
} }
}
return servercmd.music.play.response.success; return servercmd.music.play.response.success;
}); });
// playnext command // playnext command
this.servant.createCommand(servercmd.music.playnext,(msg, argv) => { this.servant.createCommand(servercmd.music.playnext,(msg, kwargs, argv) => {
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;
let url = argv['url']; let url = kwargs['url'];
if (!url) return servercmd.music.playnext.response.no_url; if (!url) return servercmd.music.playnext.response.no_url;
if (!url.match(/http/g)) { if (!url.match(/http/g)) {
if (this.getData('savedplaylists') && this.getData('savedplaylists')[url]) { if (argv)
url = this.getData('savedplaylists')[url]; url += ' ' + argv.join(' ');
} else { this.db.get('SELECT url FROM playlists WHERE name = ?', [url], (err, row) => {
return servercmd.music.playnext.response.url_invalid; if (err) {
console.error(err.message);
}
if (!row) {
return servercmd.music.play.response.url_invalid;
} }
url = row.url;
try {
this.dj.playYouTube(url, true);
} catch (err) {
logger.error(err.message);
return servercmd.music.play.response.failure;
} }
});
} else {
try { try {
this.dj.playYouTube(url, true); this.dj.playYouTube(url, true);
} catch (err) { } catch (err) {
logger.error(err); logger.error(err);
return servercmd.music.playnext.response.failure; return servercmd.music.playnext.response.failure;
} }
}
return servercmd.music.playnext.response.success; return servercmd.music.playnext.response.success;
}); });
@ -206,19 +251,42 @@ exports.GuildHandler = class {
}); });
// saves playlists // saves playlists
this.servant.createCommand(servercmd.music.save, (msg, argv) => { this.servant.createCommand(servercmd.music.save, (msg, kwargs, argv) => {
this.appendData('savedplaylists', argv.name, argv.url); let saveName = argv.join(' ');
return `Saved song/playlist as ${argv['name']}` this.db.get('SELECT COUNT(*) count FROM playlists WHERE name = ?', [saveName], (err, row) => {
if(err) {
logger.error(err.message);
}
if (!row || row.count === 0) {
this.db.run('INSERT INTO playlists (name, url) VALUES (?, ?)', [saveName, kwargs.url], (err) => {
if (err)
logger.error(err.message);
});
} else {
this.db.run('UPDATE playlists SET url = ? WHERE name = ?', [kwargs.url, saveName], (err) => {
if (err)
logger.error(err.message);
});
}
});
return `Saved song/playlist as ${saveName}`
}); });
// saved command - prints out saved playlists // saved command - prints out saved playlists
this.servant.createCommand(servercmd.music.saved, () => { this.servant.createCommand(servercmd.music.saved, (msg) => {
let response = '```markdown\nSaved Playlists:\n==\n'; let response = '```markdown\nSaved Playlists:\n==\n';
Object.entries(this.getData('savedplaylists')).forEach(([key, value]) => { this.db.all('SELECT name, url FROM playlists', (err, rows) => {
response += `${key.padEnd(10, ' ')} ${value} \n\n`; if (err)
}); logger.error(err.message);
for (let row of rows) {
response += `${row.name.padEnd(10, ' ')}: ${row.url} \n\n`;
}
response += '```'; response += '```';
return response; if (rows.length === 0)
msg.channel.send(servercmd.music.saved.response.no_saved);
else
msg.channel.send(response);
});
}); });
} }
}; };

@ -7,6 +7,7 @@
"ffmpeg-binaries": "4.0.0", "ffmpeg-binaries": "4.0.0",
"get-youtube-title": "1.0.0", "get-youtube-title": "1.0.0",
"opusscript": "0.0.6", "opusscript": "0.0.6",
"sqlite3": "^4.0.6",
"winston": "3.1.0", "winston": "3.1.0",
"winston-daily-rotate-file": "3.5.1", "winston-daily-rotate-file": "3.5.1",
"youtube-playlist-info": "1.1.2", "youtube-playlist-info": "1.1.2",

Loading…
Cancel
Save