Added cmdsequence saving

- Sequences of commands can be saved with ~savecmd
- When saving the semicolon must be escaped by backslash
- saved commands can be listed with ~savedcmd
- saved commands can be executed with ~execute [name]
- renamed ~save to ~savemedia and ~saved to ~savedmedia
- added a command to delete saved entries
pull/36/head
Trivernis 6 years ago
parent dd2a49209f
commit 4921ee243c

@ -160,7 +160,7 @@ class Bot {
*/ */
registerCommands() { registerCommands() {
// useless test command // useless test command
cmd.createGlobalCommand(prefix + 'repeatafterme', (msg, argv, args) => { cmd.createGlobalCommand(prefix + 'say', (msg, argv, args) => {
return args.join(' '); return args.join(' ');
}, [], "Repeats what you say"); }, [], "Repeats what you say");
@ -333,10 +333,7 @@ class Bot {
let resolvedAnswer = await answer; let resolvedAnswer = await answer;
await this.answerMessage(msg, resolvedAnswer); await this.answerMessage(msg, resolvedAnswer);
} else if (answer instanceof Array) { } else if (answer instanceof Array) {
let answerPromises = []; await waterfall(answer.map((x) => async () => await this.answerMessage(msg, x))); // execute each after another
for (let answerPart of answer)
answerPromises.push(async () => await this.answerMessage(msg, answerPart));
await waterfall(answerPromises);
} else if ({}.toString.call(answer) === '[object Function]') { } else if ({}.toString.call(answer) === '[object Function]') {
await this.answerMessage(msg, answer()); await this.answerMessage(msg, answer());
} else if (answer) { } else if (answer) {

@ -5,6 +5,42 @@
"permission": "all", "permission": "all",
"description": "Shows the roles used for commands on the server.", "description": "Shows the roles used for commands on the server.",
"category": "Utility" "category": "Utility"
},
"savecmd": {
"name": "savecmd",
"permission": "moderator",
"description": "Saves a sequence of commands under a new name. ~save [cmdsequence] [cmdname]. Semicoli must be escaped with \\ (Backslash)",
"category": "Utility"
},
"savedcmd": {
"name": "savedcmd",
"permission": "all",
"description": "Displays the saved commands.",
"category": "Utility",
"response": {
"no_commands": "There are no saved commands."
}
},
"deletecmd": {
"name": "deletecmd",
"permission": "moderator",
"description": "Delete a saved command.",
"args": [
"cmdname"
],
"category": "Utility"
},
"execute": {
"name": "execute",
"permission": "all",
"args": [
"cmdname"
],
"description": "Execute saved commands.",
"category": "Utility",
"response": {
"not_found": "This command could not be found."
}
} }
}, },
"music": { "music": {
@ -132,8 +168,8 @@
"repeat_false": "Not listening on repeat anymore." "repeat_false": "Not listening on repeat anymore."
} }
}, },
"save": { "savemedia": {
"name": "save", "name": "savemedia",
"permission": "dj", "permission": "dj",
"args": [ "args": [
"url" "url"
@ -141,14 +177,23 @@
"description": "Saves the YouTube song/playlist with a specific name", "description": "Saves the YouTube song/playlist with a specific name",
"category": "Music" "category": "Music"
}, },
"saved": { "savedmedia": {
"name": "saved", "name": "savedmedia",
"permission": "all", "permission": "all",
"description": "Prints out all saved playlists.", "description": "Prints out all saved playlists and songs.",
"category": "Music", "category": "Music",
"response": { "response": {
"no_saved": "There are no saved songs/playlists :(" "no_saved": "There are no saved songs/playlists :("
} }
},
"deletemedia": {
"name": "deletemedia",
"permission": "dj",
"description": "Deletes a saved media entry. ~deletemedia [name]",
"category": "Music",
"response": {
"no_name": "You must provide a name for the media that shall be deleted."
}
} }
} }
} }

@ -35,7 +35,9 @@ exports.Servant = class {
} else { } else {
let helpEmbed = new Discord.RichEmbed() let helpEmbed = new Discord.RichEmbed()
.setTitle('Commands'); .setTitle('Commands')
.setDescription('Create a sequence of commands with `;` (semicolon).')
.setTimestamp();
let globHelp = ''; let globHelp = '';
Object.entries(globCommands).sort().forEach(([key, value]) => { Object.entries(globCommands).sort().forEach(([key, value]) => {
if (value.role !== 'owner' || checkPermission(msg, 'owner')) if (value.role !== 'owner' || checkPermission(msg, 'owner'))
@ -107,12 +109,19 @@ exports.Servant = class {
* @param msg * @param msg
* @param globResult * @param globResult
* @param content * @param content
* @param returnFunction Boolean if the return value should be a function.
* @param fallback
* @returns {*} * @returns {*}
*/ */
processCommand(msg, globResult, content, returnFunction) { processCommand(msg, globResult, content, returnFunction, fallback) {
let command = (content.match(/^.\w+/) || [])[0]; let command = (content.match(/^.\w+/) || [])[0];
if (!command || !this.commands[command]) if (!command || !this.commands[command])
return globResult; if (fallback && !globResult) {
command = fallback;
content = `${fallback} ${content}`;
} else {
return globResult;
}
let cmd = this.commands[command]; let cmd = this.commands[command];
if (!checkPermission(msg, cmd.role)) if (!checkPermission(msg, cmd.role))
return 'No Permission'; return 'No Permission';
@ -143,14 +152,18 @@ exports.Servant = class {
let globResult = parseGlobalCommand(msg); let globResult = parseGlobalCommand(msg);
logger.debug(`Global command result is ${globResult}`); logger.debug(`Global command result is ${globResult}`);
let content = msg.content; let content = msg.content;
let commands = content.split(';').map(x => x.replace(/^ +/, '')); let commands = content.split(/(?<!\\);/).map(x => x.replace(/^ +/, ''));
if (commands.length === 1) { if (commands.length === 1) {
return this.processCommand(msg, globResult, content); return this.processCommand(msg, globResult, content);
} else { } else {
let answers = []; let answers = [];
for (let i = 0; i < commands.length; i++) let previousCommand = (commands[0].match(/^.\w+/) || [])[0];;
for (let i = 0; i < commands.length; i++) {
answers.push(this.processCommand(msg, globResult[i], commands[i], answers.push(this.processCommand(msg, globResult[i], commands[i],
true)); // return function to avoid "race conditions" true, previousCommand)); // return function to avoid "race conditions"
let commandMatch = (commands[i].match(/^.\w+/) || [])[0];
previousCommand = this.commands[commandMatch]? commandMatch : previousCommand;
}
return answers; return answers;
} }
@ -215,6 +228,7 @@ exports.init = function (prefix) {
} else { } else {
let helpEmbed = new Discord.RichEmbed() let helpEmbed = new Discord.RichEmbed()
.setTitle('Global Commands') .setTitle('Global Commands')
.setDescription('Create a sequence of commands with `;` (semicolon).')
.setTimestamp(); .setTimestamp();
let description = ''; let description = '';
Object.entries(globCommands).sort().forEach(([key, value]) => { Object.entries(globCommands).sort().forEach(([key, value]) => {
@ -248,7 +262,7 @@ function processCommand(cmd, msg, content, returnFunction) {
*/ */
function parseGlobalCommand(msg) { function parseGlobalCommand(msg) {
let content = msg.content; let content = msg.content;
let commands = content.split(';').map(x => x.replace(/^ +/, '')); let commands = content.split(/(?<!\\);/).map(x => x.replace(/^ +/, ''));
if (commands.length === 1) { if (commands.length === 1) {
let command = (content.match(/^.\w+/) || [])[0]; let command = (content.match(/^.\w+/) || [])[0];
if (!command || !globCommands[command]) if (!command || !globCommands[command])
@ -260,15 +274,25 @@ function parseGlobalCommand(msg) {
return processCommand(cmd, msg, content); return processCommand(cmd, msg, content);
} else { } else {
let answers = []; let answers = [];
let previousCommand = '';
for (let commandPart of commands) { for (let commandPart of commands) {
let command = (commandPart.match(/^.\w+/) || [])[0]; let command = (commandPart.match(/^.\w+/) || [])[0] || previousCommand;
previousCommand = globCommands[command]? command : previousCommand;
if (!commandPart || !globCommands[command]) {
commandPart = `${previousCommand} ${commandPart}`;
command = previousCommand;
}
if (command && globCommands[command]) { if (command && globCommands[command]) {
let cmd = globCommands[command]; let cmd = globCommands[command];
if (checkPermission(msg, cmd.role)) { if (checkPermission(msg, cmd.role)) {
logger.debug(`Permission <${cmd.role}> granted for command ${command} for user <${msg.author.tag}>`); logger.debug(`Permission <${cmd.role}> granted for command ${command} for user <${msg.author.tag}>`);
answers.push(processCommand(cmd, msg, commandPart, answers.push(processCommand(cmd, msg, commandPart,
true)); // return an function to avoid "race conditions" true)); // return an function to avoid "race conditions"
} else {
answers.push(false);
} }
} else {
answers.push(false);
} }
} }
return answers; return answers;
@ -285,8 +309,9 @@ function checkPermission(msg, 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 && rolePerm && msg.member.roles.some(role => role.name.toLowerCase() === rolePerm.toLowerCase())) if (msg.member && rolePerm && rolePerm !== 'owner' && msg.member.roles
.some(role => (role.name.toLowerCase() === rolePerm.toLowerCase() || role.name.toLowerCase() === 'botcommander')))
return true; return true;
return false; return false;

@ -36,7 +36,7 @@ exports.GuildHandler = class {
logger.debug(`Connected to the database for ${this.guild}`); logger.debug(`Connected to the database for ${this.guild}`);
await this.createTables(); await this.createTables();
// register commands // register commands
this.registerMusicCommands(); this.registerCommands();
} }
/** /**
@ -66,6 +66,11 @@ exports.GuildHandler = class {
name VARCHAR(32) UNIQUE NOT NULL, name VARCHAR(32) UNIQUE NOT NULL,
url VARCHAR(255) NOT NULL url VARCHAR(255) NOT NULL
)`); )`);
await this.db.run(`${utils.sql.tableExistCreate} commands (
${utils.sql.pkIdSerial},
name VARCHAR(32) UNIQUE NOT NULL,
command VARCHAR(255) NOT NULL
)`);
} }
/** /**
@ -81,10 +86,7 @@ exports.GuildHandler = class {
let resolvedAnswer = await answer; let resolvedAnswer = await answer;
await this.answerMessage(msg, resolvedAnswer); await this.answerMessage(msg, resolvedAnswer);
} else if (answer instanceof Array) { } else if (answer instanceof Array) {
let answerPromises = []; await waterfall(answer.map((x) => async () => await this.answerMessage(msg, x)));
for (let answerPart of answer)
answerPromises.push(async () => await this.answerMessage(msg, answerPart));
await waterfall(answerPromises);
} else if ({}.toString.call(answer) === '[object Function]') { // check if the answer is of type function } else if ({}.toString.call(answer) === '[object Function]') { // check if the answer is of type function
await this.answerMessage(msg, answer()); await this.answerMessage(msg, answer());
} else { } else {
@ -124,7 +126,7 @@ exports.GuildHandler = class {
/** /**
* registers all music commands and initializes a dj * registers all music commands and initializes a dj
*/ */
registerMusicCommands() { registerCommands() {
this.dj = new music.DJ(); this.dj = new music.DJ();
let playCb = async (msg, kwargs, argv, template, next) => { let playCb = async (msg, kwargs, argv, template, next) => {
@ -261,8 +263,8 @@ exports.GuildHandler = class {
} }
}); });
// saves playlists // saves playlists and videos
this.servant.createCommand(servercmd.music.save, async (msg, kwargs, argv) => { this.servant.createCommand(servercmd.music.savemedia, async (msg, kwargs, argv) => {
let saveName = argv.join(' '); let saveName = argv.join(' ');
let row = await this.db.get('SELECT COUNT(*) count FROM playlists WHERE name = ?', [saveName]); let row = await this.db.get('SELECT COUNT(*) count FROM playlists WHERE name = ?', [saveName]);
if (!row || row.count === 0) if (!row || row.count === 0)
@ -272,19 +274,75 @@ exports.GuildHandler = class {
return `Saved song/playlist as ${saveName}`; return `Saved song/playlist as ${saveName}`;
}); });
// saved command - prints out saved playlists // savedmedia command - prints out saved playlists and videos
this.servant.createCommand(servercmd.music.saved, async (msg) => { this.servant.createCommand(servercmd.music.savedmedia, async () => {
let response = ''; let response = '';
let rows = await this.db.all('SELECT name, url FROM playlists'); let rows = await this.db.all('SELECT name, url FROM playlists');
for (let row of rows) for (let row of rows)
response += `[${row.name}](${row.url})\n`; response += `[${row.name}](${row.url})\n`;
if (rows.length === 0) if (rows.length === 0)
msg.channel.send(servercmd.music.saved.response.no_saved); return servercmd.music.savedmedia.response.no_saved;
else else
return new Discord.RichEmbed() return new Discord.RichEmbed()
.setTitle('Saved Songs and Playlists') .setTitle('Saved Songs and Playlists')
.setDescription(response); .setDescription(response)
.setFooter(`Play a saved entry with ${this.prefix}play [Entryname]`)
.setTimestamp();
});
this.servant.createCommand(servercmd.music.deletemedia, async (msg, kwargs, argv) => {
let saveName = argv.join(' ');
if (!saveName) {
return servercmd.music.deletemedia.response.no_name;
} else {
await this.db.run('DELETE FROM playlists WHERE name = ?', [saveName]);
return `Deleted ${saveName} from saved media`;
}
});
// savecmd - saves a command sequence with a name
this.servant.createCommand(servercmd.utils.savecmd, async (msg, kwargs, argv) => {
let saveName = argv.pop();
let cmdsequence = argv.join(' ').replace(/\\/g, '');
let row = await this.db.get('SELECT COUNT(*) count FROM commands WHERE name = ?', [saveName]);
if (!row || row.count === 0)
await this.db.run('INSERT INTO commands (name, command) VALUES (?, ?)', [saveName, cmdsequence]);
else
await this.db.run('UPDATE commands SET sequence = ? WHERE name = ?', [cmdsequence, saveName]);
return `saved command sequence as ${saveName}`;
});
// savedcmd - prints saved commands
this.servant.createCommand(servercmd.utils.savedcmd, async () => {
let response = new Discord.RichEmbed()
.setTitle('Saved Commands')
.setFooter(`Execute a saved entry with ${this.prefix}execute [Entryname]`)
.setTimestamp();
let rows = await this.db.all('SELECT name, command FROM commands');
if (rows.length === 0)
return servercmd.utils.savedcmd.response.no_commands;
else
for (let row of rows)
response.addField(row.name, '`' + row.command + '`');
return response;
});
// deletecmd - deletes a command from saved commands
this.servant.createCommand(servercmd.utils.deletecmd, async (msg, kwargs) => {
await this.db.run('DELETE FROM commands WHERE name = ?', [kwargs.cmdname]);
return `Deleted command ${kwargs.cmdname}`;
});
// execute - executes a saved command
this.servant.createCommand(servercmd.utils.execute, async (msg, kwargs) => {
let row = await this.db.get('SELECT command FROM commands WHERE name = ?', [kwargs.cmdname]);
if (row) {
msg.content = row.command;
await this.handleMessage(msg);
} else {
return servercmd.utils.execute.response.not_found;
}
}); });
} }
}; };

@ -71,7 +71,7 @@ head
span#dj-queueCount span#dj-queueCount
| Songs in Queue | Songs in Queue
span.cell span.cell
| Next | Next
span#dj-queueDisplayCount 0 span#dj-queueDisplayCount 0
| Songs: | Songs:
#dj-songQueue #dj-songQueue

Loading…
Cancel
Save