New command syntax

- creating commands requires a command template that is stored in the commands folder in a json file
- command templates manage permissions, arguments, responses and the command name
- added config file -> needs to be created, template coming soon
pull/12/head
Trivernis 6 years ago
parent 98b809ba66
commit 2b6ea2123f

3
.gitignore vendored

@ -2,4 +2,5 @@
.idea
data
package-lock.json
node_modules
node_modules
config.json

@ -4,11 +4,12 @@ const Discord = require("discord.js"),
cmd = require("./lib/cmd"),
guilding = require('./lib/guilding'),
utils = require('./lib/utils'),
config = require('./config.json'),
client = new Discord.Client(),
args = require('args-parser')(process.argv),
authToken = args.token,
prefix = args.prefix || '~',
gamepresence = args.game || prefix + 'help';
authToken = args.token || config.token,
prefix = args.prefix || config.prefix,
gamepresence = args.game || config.presence;
let presences = [],
rotator = null;
@ -31,7 +32,7 @@ function main() {
lineReader.on('line', (line) => {
presences.push(line);
});
rotator = setInterval(() => rotatePresence(), 60000);
rotator = client.setInterval(() => rotatePresence(), config.presence_duration);
}
})
});
@ -43,14 +44,12 @@ function main() {
}
function registerCommands() {
cmd.createGlobalCommand(prefix + 'ping', () => {
return 'Pong!';
}, [], "Try it yourself.");
// useless test command
cmd.createGlobalCommand(prefix + 'repeatafterme', (msg, argv, args) => {
return args.join(' ');
}, [], "Repeats what you say");
// adds a presence that will be saved in the presence file and added to the rotation
cmd.createGlobalCommand(prefix + 'addpresence', (msg, argv, args) => {
let p = args.join(' ');
presences.push(p);
@ -59,6 +58,7 @@ function registerCommands() {
return `Added Presence \`${p}\``;
}, [], "Adds a presence to the rotation.", 'owner');
// shuts down the bot after destroying the client
cmd.createGlobalCommand(prefix + 'shutdown', (msg) => {
msg.reply('Shutting down...').finally(() => {
logger.debug('Destroying client...');
@ -69,15 +69,31 @@ function registerCommands() {
});
}, [], "Shuts the bot down.", 'owner');
// forces a presence rotation
cmd.createGlobalCommand(prefix + 'rotate', () => {
try {
clearInterval(rotator);
client.clearInterval(rotator);
rotatePresence();
rotator = setInterval(() => rotatePresence(), 60000);
rotator = client.setInterval(() => rotatePresence(), config.presence_duration);
} catch (error) {
logger.warn(JSON.stringify(error));
}
}, [], 'Force presence rotation', 'owner');
// ping command that returns the ping attribute of the client
cmd.createGlobalCommand(prefix + 'ping', () => {
return `Current average ping: \`${client.ping} ms\``;
}, [], 'Returns the current average ping', 'owner');
// returns the time the bot is running
cmd.createGlobalCommand(prefix + 'uptime', () => {
return `Uptime: \`${client.uptime/1000} s\``
}, [], 'Returns the uptime of the bot', 'owner');
// returns the numbe of guilds, the bot has joined
cmd.createGlobalCommand(prefix + 'guilds', () => {
return `Number of guilds: \`${client.guilds.size}\``
}, [], 'Returns the uptime of the bot', 'owner');
}
function rotatePresence() {

@ -0,0 +1,9 @@
{
"utils": {
"help": {
"name": "help",
"permission": "all",
"description": "Shows this help command"
}
}
}

@ -0,0 +1,128 @@
{
"utils": {
"roles": {
"name": "roles",
"permission": "all",
"description": "Shows the roles used for commands on the server."
}
},
"music": {
"play": {
"name": "play",
"permission": "all",
"args": [
"url"
],
"description": "Adds the url to the YouTube video/playlist into the queue.",
"response": {
"success": "Added Song/Playlist to the queue.",
"failure": "Failed adding Song/Playlist to the queue.",
"url_invalid": "This is not a valid url!",
"no_url": "I need an url to a video to play"
}
},
"playnext": {
"name": "playnext",
"permission": "all",
"args": [
"url"
],
"description": "Adds the url to the YouTube video as next song to the queue.",
"response": {
"success": "Added Song as next Song to the queue.",
"failure": "Failed adding Song as next Song to the queue.",
"url_invalid": "This is not a valid url!",
"no_url": "I need an url to a video to play"
}
},
"join": {
"name": "join",
"permission": "all",
"description": "Joins the VC you are in.",
"response": {
"not_connected": "You are not connected to a Voice Channel."
}
},
"stop": {
"name": "stop",
"permission": "dj",
"description": "Stops playing music and leaves.",
"response": {
"success": "Stopping now..."
}
},
"pause": {
"name": "pause",
"permission": "all",
"description": "Pauses playing.",
"response": {
"success": "Pausing playback."
}
},
"resume": {
"name": "resume",
"permission": "all",
"description": "Resumes playing.",
"response": {
"success": "Resuming playback."
}
},
"skip": {
"name": "skip",
"permission": "dj",
"description": "Skips the current song.",
"response": {
"success": "Skipping to the next song."
}
},
"clear": {
"name": "clear",
"permission": "dj",
"description": "Clears the queue.",
"response": {
"success": "The Queue has been cleared."
}
},
"playlist": {
"name": "queue",
"permission": "all",
"description": "Shows the next ten songs."
},
"current": {
"name": "np",
"permission": "all",
"description": "Shows the currently playing song."
},
"shuffle": {
"name": "shuffle",
"permission": "all",
"description": "Shuffles the playlist.",
"response": {
"success": "The Queue has been shuffled."
}
},
"repeat": {
"name": "repeat",
"permission": "all",
"description": "Toggle listening on repeat.",
"response": {
"repeat_true": "Listening on repeat now!",
"repeat_false": "Not listening on repeat anymore."
}
},
"save": {
"name": "save",
"permission": "dj",
"args": [
"url",
"name"
],
"description": "Saves the YouTube song/playlist with a specific name"
},
"saved": {
"name": "saved",
"permission": "all",
"description": "Prints out all saved playlists."
}
}
}

@ -4,54 +4,73 @@
let logger = require('winston'),
globCommands = {},
ownerCommands = {},
args = require('args-parser')(process.argv);
config = require('../config.json'),
args = require('args-parser')(process.argv),
gcmdTempl = require('../commands/globalcommands'),
scmdTempl = require('../commands/servercommands');
/* Function Definition */
/**
* @type {Servant}
*/
exports.Servant = class {
module.exports.Servant = class {
constructor(prefix) {
this.commands = {};
this.createCommand(((prefix || '~') + 'help') || "~help", () => {
this.prefix = prefix;
// show all commands (except the owner commands if the user is not an owner)
this.createCommand(gcmdTempl.utils.help, (msg) => {
let helpstr = "```markdown\n";
helpstr += "Commands\n===\n";
helpstr += 'Global Commands\n---\n';
Object.entries(globCommands).sort().forEach(([key, value]) => {
if (value.role !== 'owner' || msg.author.tag === args.owner) {
if (value.role !== 'owner' || checkPermission(msg, 'owner')) {
let cmdhelp = `${key} [${value.args.join('] [')}]`.replace('[]', '').padEnd(25, ' ');
cmdhelp += value.description || '';
cmdhelp += `\nPermission: ${value.role||'all'}`;
helpstr += `\n${cmdhelp}\n`;
}
});
helpstr += '\nServer Commands\n---\n';
Object.entries(this.commands).sort().forEach(([key, value]) => {
if (value.role !== 'owner' || msg.author.tag === args.owner) {
if (value.role !== 'owner' || checkPermission(msg, 'owner')) {
let cmdhelp = `${key} [${value.args.join('] [')}]`.replace('[]', '').padEnd(25, ' ');
cmdhelp += value.description || '';
cmdhelp += `\nPermission: ${value.role||'all'}`;
helpstr += `\n${cmdhelp}\n`;
}
});
helpstr += "```";
return helpstr;
}, [], "Shows this help.");
});
// show all roles that are used by commands
this.createCommand(scmdTempl.utils.roles, () => {
let roles = [];
Object.entries(globCommands).concat(Object.entries(this.commands)).sort().forEach(([key, value]) => {
roles.push(value.role || 'all');
});
return `**Roles**\n${[...new Set(roles)].join('\n')}`;
});
}
/**
* Creates a command entry in the private commands dict
* @param command
* @param template
* @param call
* @param args
* @param description
*/
createCommand(command, call, args, description, role) {
this.commands[command] = {
'args': args,
'description': description,
createCommand(template, call) {
if (!template.name) {
logger.debug(`Name of command template is null or undef. Failed creating command.`)
return;
}
this.commands[this.prefix + template.name] = {
'args': template.args || [],
'description': template.description,
'callback': call,
'role': role
'role': template.role
};
logger.debug(`Created server command: ${this.prefix + template.name}, args: ${template.args}`);
}
/**
@ -93,7 +112,7 @@ exports.Servant = class {
* Getting the logger
* @param {Object} newLogger
*/
exports.setLogger = function (newLogger) {
module.exports.setLogger = function (newLogger) {
logger = newLogger;
};
@ -105,14 +124,14 @@ exports.setLogger = function (newLogger) {
* @param description
* @param role
*/
exports.createGlobalCommand = function (command, call, args, description, role) {
module.exports.createGlobalCommand = function (command, call, args, description, role) {
globCommands[command] = {
'args': args || [],
'description': description,
'callback': call,
'role': role
};
logger.debug(`Created command: ${command}, args: ${args}`);
logger.debug(`Created global command: ${command}, args: ${args}`);
};
@ -121,22 +140,23 @@ exports.createGlobalCommand = function (command, call, args, description, role)
* @param msg
* @returns {boolean|*}
*/
exports.parseMessage = function (msg) {
module.exports.parseMessage = function (msg) {
return parseGlobalCommand(msg);
};
/**
* Initializes the module by creating a help command
*/
exports.init = function (prefix) {
module.exports.init = function (prefix) {
logger.verbose("Created help command");
this.createGlobalCommand((prefix + 'help') || "~help", (msg) => {
this.createGlobalCommand(((prefix || config.prefix) + 'help'), (msg) => {
let helpstr = "```markdown\n";
helpstr += "Commands\n---\n";
Object.entries(globCommands).sort().forEach(([key, value]) => {
if (value.role !== 'owner' || msg.author.tag === args.owner) {
if (value.role !== 'owner' || checkPermission(msg, 'owner')) {
let cmdhelp = `${key} [${value.args.join('] [')}]`.replace('[]', '').padEnd(25, ' ');
cmdhelp += value.description || '';
cmdhelp += `\nPermission: ${value.role||'all'}`;
helpstr += `\n${cmdhelp}\n`;
}
});
@ -167,13 +187,18 @@ function parseGlobalCommand(msg) {
return cmd.callback(msg, kwargs, argv);
}
/**
* @param msg
* @param role {String}
* @returns {boolean}
*/
function checkPermission(msg, role) {
if (!role || ['all', 'any', 'everyone'].includes(role))
return true;
if (msg.author.tag === args.owner) {
if (msg.author.tag === args.owner || config.owners.includes(msg.author.tag)) {
return true;
} else {
if (msg.member && role && msg.member.roles.find("id", role.id))
if (msg.member && role && msg.member.roles.some(role => role.name.toLowerCase() === role.toLowerCase()))
return true
}
return false

@ -1,6 +1,8 @@
const cmd = require('./cmd'),
music = require('./music'),
data = require('./data'),
config = require('../config.json'),
servercmd = require('../commands/servercommands'),
handlers = {};
let logger = require('winston');
@ -15,9 +17,9 @@ exports.GuildHandler = class {
this.guild = guild;
this.dataHandler = new data.DataHandler(guild.name);
this.dj = null;
this.servant = null;
this.mention = false;
this.prefix = prefix || '~';
this.prefix = prefix || config.prefix;
this.servant = new cmd.Servant(this.prefix);
this.registerMusicCommands();
}
@ -57,23 +59,39 @@ exports.GuildHandler = class {
* 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) {
let answer = this.servant.parseCommand(msg);
if (!answer) return;
if (this.mention) {
msg.reply(answer);
} else {
msg.channel.send(answer);
}
}
registerMusicCommands(cmdPrefix) {
let prefix = cmdPrefix || this.prefix;
this.dj = new music.DJ();
// play command
this.createCommand(prefix + 'play', (msg, argv) => {
this.servant.createCommand(servercmd.music.play, (msg, argv) => {
let vc = msg.member.voiceChannel;
let url = argv['url'];
if (!vc)
return 'You are not connected to a VoiceChannel';
if (!url)
return 'No url given.';
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 'Not a valid url.';
return servercmd.music.play.response.url_invalid;
}
}
try {
@ -82,76 +100,78 @@ exports.GuildHandler = class {
this.dj.playYouTube(url);
});
} else {
return this.dj.playYouTube(url);
this.dj.playYouTube(url);
}
} catch (err) {
logger.error(err);
return `${JSON.stringify(err)}`;
return servercmd.music.play.response.failure;
}
}, ['url'], "Adds the url to the YouTube video/playlist into the queue.");
return servercmd.music.play.response.success;
});
// playnext command
this.createCommand(prefix + 'playnext', (msg, argv) => {
this.servant.createCommand(servercmd.music.playnext,(msg, argv) => {
let vc = msg.member.voiceChannel;
if (!this.dj.connected) this.dj.voiceChannel = vc;
let url = argv['url'];
if (!url) return 'No url given.';
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 'Not a valid url';
return servercmd.music.playnext.response.url_invalid;
}
}
try {
return this.dj.playYouTube(url, true);
this.dj.playYouTube(url, true);
} catch (err) {
logger.error(err);
return `${JSON.stringify(err)}`;
return servercmd.music.playnext.response.failure;
}
}, ['url'], "Adds the url to the YouTube video as next song to the queue.");
return servercmd.music.playnext.response.success;
});
// join command
this.createCommand(prefix + 'join', (msg) => {
this.servant.createCommand(servercmd.music.join, (msg) => {
if (msg.member.voiceChannel) {
this.dj.connect(msg.member.voiceChannel);
} else {
return "You are not connected to a voicechannel.";
return servercmd.music.join.response.not_connected;
}
}, [], "Joins the VC you are in.");
});
// stop command
this.createCommand(prefix + 'stop', () => {
this.servant.createCommand(servercmd.music.stop, () => {
this.dj.stop();
return "Stopping now";
}, [], "Stops playing music and leaves.");
return servercmd.music.stop.response.success;
});
// pause command
this.createCommand(prefix + 'pause', () => {
this.servant.createCommand(servercmd.music.pause, () => {
this.dj.pause();
return "Pausing playing";
}, [], "Pauses playing.");
return servercmd.music.pause.response.success;
});
// resume command
this.createCommand(prefix + 'resume', () => {
this.servant.createCommand(servercmd.music.resume, () => {
this.dj.resume();
return "Resuming playing";
}, [], "Resumes playing.");
return servercmd.music.resume.response.success;
});
// skip command
this.createCommand(prefix + 'skip', () => {
this.servant.createCommand(servercmd.music.skip, () => {
this.dj.skip();
return "Skipping Song";
}, [], "Skips the current song.");
return servercmd.music.skip.response.success;
});
// clear command
this.createCommand(prefix + 'clear', () => {
this.servant.createCommand(servercmd.music.clear, () => {
this.dj.clear();
return "DJ-Queue cleared";
}, [], "Clears the playlist.");
return servercmd.music.clear.response.success;
});
// playlist command
this.createCommand(prefix + 'playlist', () => {
this.servant.createCommand(servercmd.music.playlist, () => {
let songs = this.dj.playlist;
logger.debug(`found ${songs.length} songs`);
let songlist = `**${songs.length} Songs in playlist**\n`;
@ -160,63 +180,46 @@ exports.GuildHandler = class {
songlist += songs[i] + '\n';
}
return songlist;
}, [], "Shows the next ten songs.");
});
// np command
this.createCommand(prefix + 'np', () => {
this.servant.createCommand(servercmd.music.current, () => {
let song = this.dj.song;
return `Playing: ${song.title}\n ${song.url}`;
}, [], "Shows the currently playing song.");
});
// shuffle command
this.createCommand(prefix + 'shuffle', () => {
this.servant.createCommand(servercmd.music.shuffle, () => {
this.dj.shuffle();
return "Randomized the order of the queue."
}, [], "Shuffles the playlist.");
return servercmd.music.shuffle.response.success;
});
// repeat command
this.servant.createCommand(servercmd.music.repeat, () => {
if (this.dj) {
this.dj.repeat = !this.dj.repeat;
if (this.dj.repeat)
return servercmd.music.repeat.response.repeat_true;
else
return servercmd.music.repeat.response.repeat_false;
}
});
// saves playlists
this.createCommand(prefix + 'save', (msg, argv) => {
this.servant.createCommand(servercmd.music.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', () => {
this.servant.createCommand(servercmd.music.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.");
}
/**
* creates a servant if not set and lets the servant create a command
* @param command
* @param call
* @param args
* @param description
*/
createCommand(command, call, args, description) {
if (!this.servant) this.servant = new cmd.Servant(this.prefix);
this.servant.createCommand(command, call, args, description);
}
/**
* 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.servant) this.servant = new cmd.Servant(this.prefix);
let answer = this.servant.parseCommand(msg);
if (!answer) return;
if (this.mention) {
msg.reply(answer);
} else {
msg.channel.send(answer);
}
});
}
};

@ -3,7 +3,8 @@ const Discord = require("discord.js"),
ypi = require('youtube-playlist-info'),
yttl = require('get-youtube-title'),
args = require('args-parser')(process.argv),
ytapiKey = args.ytapi;
config = require('../config.json'),
ytapiKey = args.ytapi || config.ytapikey;
/* Variable Definition */
let logger = require('winston');
let djs = {};
@ -18,6 +19,7 @@ exports.DJ = class {
this.queue = [];
this.playing = false;
this.current = null;
this.repeat = false;
this.volume = 0.5;
this.voiceChannel = voiceChannel;
}
@ -81,7 +83,7 @@ exports.DJ = class {
if (this.voiceChannel && this.voiceChannel.members.size === 1)
logger.verbose(`Exiting ${this.voiceChannel.name}`);
this.stop();
}, 300000);
}, config.music.timeout || 300000);
} else if (this.connected)
setTimeout(() => this.checkListeners(), 10000);
}
@ -120,6 +122,7 @@ exports.DJ = class {
});
}
this.current = this.queue.shift();
if (this.repeat) this.queue.push(this.current);
this.playYouTube(this.current.url);
});
return;
@ -135,6 +138,7 @@ exports.DJ = class {
this.current = null;
if (this.queue.length > 0) {
this.current = this.queue.shift();
if (this.repeat) this.queue.push(this.current);
this.playYouTube(this.current.url);
} else {
this.stop();

Loading…
Cancel
Save