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.
`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
---

@ -39,8 +39,6 @@ function main() {
client.login(authToken).then(() => {
logger.debug("Logged in");
});
}
function registerCommands() {
@ -87,7 +85,7 @@ function registerCommands() {
// returns the time the bot is running
cmd.createGlobalCommand(prefix + 'uptime', () => {
return `Uptime: \`${client.uptime/1000} s\``
return `Uptime: \`${client.uptime / 1000} s\``
}, [], 'Returns the uptime of the bot', 'owner');
// returns the numbe of guilds, the bot has joined

@ -114,15 +114,17 @@
"name": "save",
"permission": "dj",
"args": [
"url",
"name"
"url"
],
"description": "Saves the YouTube song/playlist with a specific name"
},
"saved": {
"name": "saved",
"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);
logger.debug(`Executing callback for command: ${command}, kwargs: ${kwargs}, argv: ${argv}`);
return cmd.callback(msg, kwargs, argv) || globResult;
try {
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 role {String}
* @param rolePerm {String}
* @returns {boolean}
*/
function checkPermission(msg, role) {
if (!role || ['all', 'any', 'everyone'].includes(role))
function checkPermission(msg, rolePerm) {
if (!rolePerm || ['all', 'any', 'everyone'].includes(rolePerm))
return true;
if (msg.author.tag === args.owner || config.owners.includes(msg.author.tag)) {
return true;
} 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 false

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

@ -1,9 +1,11 @@
const cmd = require('./cmd'),
music = require('./music'),
data = require('./data'),
utils = require('./utils.js'),
config = require('../config.json'),
servercmd = require('../commands/servercommands'),
handlers = {};
sqlite3 = require('sqlite3'),
handlers = {},
dbDir = './data/gdb';
let logger = require('winston');
exports.setLogger = function (newLogger) {
@ -11,61 +13,65 @@ exports.setLogger = function (newLogger) {
music.setLogger(logger);
};
/**
* Server-Specific commands, music and more
* @type {GuildHandler}
*/
exports.GuildHandler = class {
constructor(guild, prefix) {
this.guild = guild;
this.dataHandler = new data.DataHandler(guild.name);
this.dj = null;
this.mention = false;
this.prefix = prefix || config.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();
}
/**
* function shortcut returns the data from the dataHandler
* @param name
* @returns {{}}
*/
getData(name) {
return this.dataHandler.getData(name);
}
/**
* 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
* Creates all tables needed in the Database.
* These are at the moment:
* messages - logs all messages send on the server
* playlists - save playlists to play them later
*/
deleteDataEntry(name, key) {
let data = this.getData(name);
delete data[key];
this.dataHandler.setData(name, data);
createTables() {
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
)`);
}
/**
* 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
* replies or just sends the answer.
* @param 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);
if (!answer) return;
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) {
let prefix = cmdPrefix || this.prefix;
this.dj = new music.DJ();
// 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 url = argv['url'];
let url = kwargs['url'];
if (!vc)
return 'You are not connected to a VoiceChannel';
if (!url)
return servercmd.music.play.response.no_url;
if (!url.match(/http/g)) {
if (this.getData('savedplaylists') && this.getData('savedplaylists')[url]) {
url = this.getData('savedplaylists')[url];
} else {
return servercmd.music.play.response.url_invalid;
}
}
try {
if (!this.dj.connected) {
this.dj.connect(vc).then(() => {
this.dj.playYouTube(url);
});
} else {
this.dj.playYouTube(url);
if (argv)
url += ' ' + argv.join(' ');
this.db.get('SELECT url FROM playlists WHERE name = ?', [url], (err, row) => {
if (err) {
console.error(err.message);
}
if (!row) {
return servercmd.music.play.response.url_invalid;
}
url = row.url;
try {
this.connectAndPlay(vc, url);
} catch (err) {
logger.error(err.message);
return servercmd.music.play.response.failure;
}
});
} else {
try {
this.connectAndPlay(vc, url);
} catch (err) {
logger.error(err.message);
return servercmd.music.play.response.failure;
}
} catch (err) {
logger.error(err);
return servercmd.music.play.response.failure;
}
return servercmd.music.play.response.success;
});
// playnext command
this.servant.createCommand(servercmd.music.playnext,(msg, argv) => {
this.servant.createCommand(servercmd.music.playnext,(msg, kwargs, argv) => {
let vc = msg.member.voiceChannel;
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.match(/http/g)) {
if (this.getData('savedplaylists') && this.getData('savedplaylists')[url]) {
url = this.getData('savedplaylists')[url];
} else {
return servercmd.music.playnext.response.url_invalid;
if (argv)
url += ' ' + argv.join(' ');
this.db.get('SELECT url FROM playlists WHERE name = ?', [url], (err, row) => {
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 {
this.dj.playYouTube(url, true);
} catch (err) {
logger.error(err);
return servercmd.music.playnext.response.failure;
}
}
try {
this.dj.playYouTube(url, true);
} catch (err) {
logger.error(err);
return servercmd.music.playnext.response.failure;
}
return servercmd.music.playnext.response.success;
});
@ -206,19 +251,42 @@ exports.GuildHandler = class {
});
// saves playlists
this.servant.createCommand(servercmd.music.save, (msg, argv) => {
this.appendData('savedplaylists', argv.name, argv.url);
return `Saved song/playlist as ${argv['name']}`
this.servant.createCommand(servercmd.music.save, (msg, kwargs, argv) => {
let saveName = argv.join(' ');
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
this.servant.createCommand(servercmd.music.saved, () => {
this.servant.createCommand(servercmd.music.saved, (msg) => {
let response = '```markdown\nSaved Playlists:\n==\n';
Object.entries(this.getData('savedplaylists')).forEach(([key, value]) => {
response += `${key.padEnd(10, ' ')} ${value} \n\n`;
this.db.all('SELECT name, url FROM playlists', (err, rows) => {
if (err)
logger.error(err.message);
for (let row of rows) {
response += `${row.name.padEnd(10, ' ')}: ${row.url} \n\n`;
}
response += '```';
if (rows.length === 0)
msg.channel.send(servercmd.music.saved.response.no_saved);
else
msg.channel.send(response);
});
response += '```';
return response;
});
}
};

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

Loading…
Cancel
Save