3
0
mirror of https://github.com/reality/dbot.git synced 2024-11-27 22:39:26 +01:00
This commit is contained in:
Joe MacMahon 2012-06-16 17:50:30 +01:00
commit de8895d5e2
26 changed files with 864 additions and 664 deletions

View File

@ -1,8 +1,15 @@
{ {
"name": "depressionbot", "name": "testressionbot",
"password": "fishes", "servers": {
"admin": [ "batman" ], "freenode": {
"server": "irc.freenode.net",
"port": 6667,
"nickserv": "nickserv",
"password": "lolturtles",
"channels": [ "channels": [
"#42" "#realitest"
] ]
}
},
"admin": [ "batman" ],
} }

View File

@ -1,147 +1,135 @@
/**
* Module Name: Admin
* Description: Set of commands which only one who is a DepressionBot
* administrator can run - as such, it has its own command execution listener.
*/
var fs = require('fs'); var fs = require('fs');
var sys = require('sys') var sys = require('sys')
var exec = require('child_process').exec; var exec = require('child_process').exec;
var adminCommands = function(dbot) { var admin = function(dbot) {
var dbot = dbot;
var commands = { var commands = {
'join': function(data, params) { // Join a channel
dbot.instance.join(params[1]); 'join': function(event) {
dbot.say(data.channel, 'Joined ' + params[1]); var channel = event.params[1];
dbot.instance.join(event, channel);
event.reply(dbot.t('join', {'channel': channel}));
}, },
'opme': function(data, params) { // Leave a channel
dbot.instance.send('MODE ' + params[1] + ' +o ', data.user); 'part': function(event) {
var channel = event.params[1];
event.instance.part(event, channel);
event.reply(dbot.t('part', {'channel': channel}));
}, },
'part': function(data, params) { // Op admin caller in given channel
dbot.instance.part(params[1]); 'opme': function(event) {
event.channel = event.params[1];
dbot.instance.mode(event, '+o ' + event.user);
}, },
// Do a git pull and reload // Do a git pull and reload
'greload': function(data, params) { 'greload': function(event) {
var child; var child = exec("git pull", function (error, stdout, stderr) {
event.reply(dbot.t('gpull'));
child = exec("git pull", function (error, stdout, stderr) { commands.reload(event);
console.log(stderr);
dbot.say(data.channel, dbot.t('gpull'));
commands.reload(data, params);
}.bind(this)); }.bind(this));
}, },
'reload': function(data, params) { // Reload DB, translations and modules.
'reload': function(event) {
dbot.db = JSON.parse(fs.readFileSync('db.json', 'utf-8')); dbot.db = JSON.parse(fs.readFileSync('db.json', 'utf-8'));
dbot.strings = JSON.parse(fs.readFileSync('strings.json', 'utf-8')); dbot.strings = JSON.parse(fs.readFileSync('strings.json', 'utf-8'));
dbot.reloadModules(); dbot.reloadModules();
dbot.say(data.channel, dbot.t('reload')); event.reply(dbot.t('reload'));
}, },
'say': function(data, params) { // Say something in a channel (TODO probably doesn't work.)
if (params[1] === "@") { 'say': function(event) {
var c = data.channel; var channel = event.params[1];
} else { if(event.params[1] === "@") {
var c = params[1]; var channel = event.channel;
} }
var m = params.slice(2).join(' '); var message = event.params.slice(2).join(' ');
dbot.say(c, m); dbot.say(event.server, channel, message);
}, },
'act': function(data, params) { // Load new module
if (params[1] === "@") { 'load': function(event) {
var c = data.channel; var moduleName = event.params[1];
} else { dbot.moduleNames.push(moduleName);
var c = params[1];
}
var m = params.slice(2).join(' ');
dbot.act(c, m);
},
'load': function(data, params) {
dbot.moduleNames.push(params[1]);
dbot.reloadModules(); dbot.reloadModules();
dbot.say(data.channel, dbot.t('load_module', {'moduleName': params[1]})); event.reply(dbot.t('load_module', {'moduleName': moduleName}));
}, },
'unload': function(data, params) { // Unload a loaded module
if(dbot.moduleNames.include(params[1])) { 'unload': function(event) {
var cacheKey = require.resolve('../modules/' + params[1]); var moduleName = event.params[1];
if(dbot.moduleNames.include(moduleName)) {
var cacheKey = require.resolve('../modules/' + moduleName);
delete require.cache[cacheKey]; delete require.cache[cacheKey];
var moduleIndex = dbot.moduleNames.indexOf(params[1]); var moduleIndex = dbot.moduleNames.indexOf(moduleName);
dbot.moduleNames.splice(moduleIndex, 1); dbot.moduleNames.splice(moduleIndex, 1);
dbot.reloadModules(); dbot.reloadModules();
dbot.say(data.channel, dbot.t('unload_module', {'moduleName': params[1]}));
event.reply(dbot.t('unload_module', {'moduleName': moduleName}));
} else { } else {
dbot.say(data.channel, dbot.t('unload_error', {'moduleName': params[1]})); event.reply(dbot.t('unload_error', {'moduleName': moduleName}));
} }
}, },
'ban': function(data, params) { // Ban user from command or *
if(dbot.db.bans.hasOwnProperty(params[2])) { 'ban': function(event) {
dbot.db.bans[params[2]].push(params[1]); var username = event.params[1];
} else { var command = event.params[2];
dbot.db.bans[params[2]] = [ params[1] ];
if(!dbot.db.bans.hasOwnProperty(command)) {
dbot.db.bans[command] = [ ];
} }
dbot.say(data.channel, dbot.t('banned', {'user': params[1], 'command': params[2]})); dbot.db.bans[command].push(username);
event.reply(dbot.t('banned', {'user': username, 'command': command}));
}, },
'unban': function(data, params) { // Unban a user from command or *
if(dbot.db.bans.hasOwnProperty(params[2]) && dbot.db.bans[params[2]].include(params[1])) { 'unban': function(event) {
dbot.db.bans[params[2]].splice(dbot.db.bans[params[2]].indexOf(params[1]), 1); var username = event.params[1];
dbot.say(data.channel, dbot.t('unbanned', {'user': params[1], 'command': params[2]})); var command = event.params[2];
if(dbot.db.bans.hasOwnProperty(command) && dbot.db.bans[command].include(username)) {
dbot.db.bans[command].splice(dbot.db.bans[command].indexOf(username), 1);
event.reply(dbot.t('unbanned', {'user': username, 'command': command}));
} else { } else {
dbot.say(data.channel, dbot.t('unban_error', {'user': params[1]})); event.reply(dbot.t('unban_error', {'user': username}));
} }
}, },
'modehate': function(data, params) { // Lock quote category so quotes can't be removed
dbot.db.modehate.push(params[1]); 'lock': function(event) {
dbot.say(data.channel, dbot.t('modehate', {'user': params[1]})); var category = event.params[1];
}, dbot.db.locks.push(category);
event.reply(dbot.t('qlock', {'category': category}));
'unmodehate': function(data, params) {
dbot.db.modehate.splice(dbot.db.modehate.indexOf(params[1]), 1);
dbot.say(data.channel, dbot.t('unmodehate', {'user': params[1]}));
},
'lock': function(data, params) {
dbot.db.locks.push(params[1]);
dbot.say(data.channel, dbot.t('qlock', {'category': params[1]}));
} }
}; };
return { return {
// These commands are implemented as their own listener so it can easily 'name': 'admin',
// check whether the user is the admin, and so that the admin can't ban 'ignorable': false,
// themselves and then not be able to rectify it...
'listener': function(data) {
if(data.channel == dbot.name) data.channel = data.user;
params = data.message.split(' '); /**
if(commands.hasOwnProperty(params[0]) && dbot.admin.include(data.user)) { * Run the appropriate admin command given the input (and user).
commands[params[0]](data, params); */
'listener': function(event) {
var commandName = event.params[0];
if(commands.hasOwnProperty(commandName) && dbot.admin.include(event.user)) {
commands[commandName](event);
dbot.save(); dbot.save();
} }
}, },
'on': 'PRIVMSG'
'onLoad': function() {
return {
'~resetadmin': function(data, params) {
dbot.admin = dbot.config.admin;
}
}
},
'on': 'PRIVMSG',
'name': 'admin',
'ignorable': false
}; };
}; };
exports.fetch = function(dbot) { exports.fetch = function(dbot) {
return adminCommands(dbot); return admin(dbot);
}; };

View File

@ -1,15 +1,18 @@
/**
* Module Name: AutoShorten
* Description: Automatically shorten link over a certain length and post the
* short link to the channel.
*/
var http = require('http'); var http = require('http');
var autoshorten = function(dbot) { var autoshorten = function(dbot) {
var name = 'autoshorten';
var dbot = dbot;
return { return {
'listener': function(data) { 'name': 'autoshorten',
if((dbot.db.ignores.hasOwnProperty(data.user) && 'ignorable': true,
dbot.db.ignores[data.user].include(name)) == false) {
'listener': function(event) {
var urlRegex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; var urlRegex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
var urlMatches = data.message.match(urlRegex); var urlMatches = event.message.match(urlRegex);
if(urlMatches !== null && urlMatches[0].length > 80) { if(urlMatches !== null && urlMatches[0].length > 80) {
var url = urlMatches[0]; // Only doing one, screw you. var url = urlMatches[0]; // Only doing one, screw you.
@ -24,18 +27,12 @@ var autoshorten = function(dbot) {
http.get(options, function(res) { http.get(options, function(res) {
res.setEncoding('utf8'); res.setEncoding('utf8');
res.on('data', function (response) { res.on('data', function (response) {
dbot.say(data.channel, dbot.t('shorten_link', {'user': data.user}) + JSON.parse(response).surl); event.reply(dbot.t('shorten_link', {'user': event.user}) + JSON.parse(response).surl);
}); });
}); });
} }
}
}, },
'on': 'PRIVMSG'
'on': 'PRIVMSG',
'name': name,
'ignorable': true
}; };
} }

View File

@ -1,56 +0,0 @@
// Find which badwords are currently enacted in the current channel
var badwords = function(dbot) {
var name = 'badwords';
var dbot = dbot;
var badWordLock = false;
var commands = {
'~badwords': function(data, params) {
if(badWordLock == true) {
dbot.say('reality', 'Another badwords query is in action. Try again in a few seconds.');
} else {
data.channel = '#42';
badWordLock = true;
dbot.sessionData.badwords.waiting = true;
dbot.say('bots', 'badwords ' + data.channel + ' list');
dbot.instance.addListener('PRIVMSG',
dbot.sessionData.badwords = {};
badWordLock = false;
}
}
};
return {
'onLoad': function() {
if(!dbot.sessionData.hasOwnProperty('badwords')) {
dbot.sessionData.badwords = {};
}
return commands;
},
'listener': function(data) {
if(data.channel === 'bots') {
if(data.message.indexOf('bad words list is empty') != -1) {
dbot.sessionData.badwords.count = 0;
dbot.sessionData.badwords.finished = true;
} else {
var wordMatch = data.message.valMatch(/\w([1-10])\w(.*)/, 2);
dbot.say('reality', wordMatch[1]);
}
}
},
'on': 'PRIVMSG',
'name': name,
'ignorable': true
};
};
exports.fetch = function(dbot) {
return badwords(dbot);
};

View File

@ -1,123 +1,83 @@
// Module which handles the command execution syntax for DBot. Not much is going /**
// to work without this. * Module Name: Command
* Description: An essential module which maps PRIVMSG input to an appropriate
* command and then runs that command, given the user isn't banned from or
* ignoring that command.
*/
var command = function(dbot) { var command = function(dbot) {
var dbot = dbot; /**
* Is user banned from using command?
return { */
'onLoad': function() { var isBanned = function(user, command) {
return { var banned = false;
'~ignore': function(data, params) { if(dbot.db.bans.hasOwnProperty(command)) {
var ignorableModules = []; if(dbot.db.bans[command].include(user) || dbot.db.bans['*'].include(user)) {
for(var i=0;i<dbot.modules.length;i++) { banned = true;
if(dbot.modules[i].ignorable != null && dbot.modules[i].ignorable == true) {
ignorableModules.push(dbot.modules[i].name);
}
}
if(params[1] == undefined) {
dbot.say(data.channel,
dbot.t('ignore_usage', {'user': data.user, 'modules': ignorableModules.join(', ')}));
} else {
if(dbot.moduleNames.include(params[1])) {
if(!dbot.db.ignores.hasOwnProperty(data.user)) {
dbot.db.ignores[data.user] = [];
}
if(dbot.db.ignores[data.user].include(params[1])) {
dbot.say(data.channel, dbot.t('already_ignoring', {'user': data.user}));
} else {
dbot.db.ignores[data.user].push(params[1]);
dbot.say(data.channel, dbot.t('ignored', {'user': data.user, 'module': params[1]}));
}
} else {
dbot.say(data.channel, dbot.t('invalid_ignore', {'user': data.user}));
}
}
},
'~unignore': function(data, params) {
var ignoredModules = [];
if(dbot.db.ignores.hasOwnProperty(data.user)) {
ignoredModules = dbot.db.ignores[data.user];
}
if(params[1] == undefined) {
dbot.say(data.channel,
dbot.t('unignore_usage', {'user': data.user, 'modules': ignoredModules.join(', ')}));
} else {
if(ignoredModules.include(params[1]) == false) {
dbot.say(data.channel, dbot.t('invalid_unignore', {'user': data.user}));
} else {
dbot.db.ignores[data.user].splice(dbot.db.ignores[data.user].indexOf(params[1]), 1);
dbot.say(data.channel, dbot.t('unignored', {'user': data.user, 'module': params[1]}));
}
} }
} }
return banned;
}; };
},
'listener': function(data) { /**
var params = data.message.split(' '); * Is user ignoring command?
if(data.channel == dbot.name) data.channel = data.user; */
var isIgnoring = function(user, command) {
var module = dbot.commandMap[command];
var ignoring = false;
if(dbot.db.ignores.hasOwnProperty(user) && dbot.db.ignores[user].include(module)) {
ignoring = true;
}
return ignoring;
};
if(dbot.commands.hasOwnProperty(params[0])) { /**
if((dbot.db.bans.hasOwnProperty(params[0]) && * Apply Regex to event message, store result. Return false if it doesn't
dbot.db.bans[params[0]].include(data.user)) || dbot.db.bans['*'].include(data.user)) { * apply.
dbot.say(data.channel, dbot.t('command_ban', {'user': data.user})); */
} else { var applyRegex = function(commandName, event) {
var commandBelongsTo = dbot.commandMap[params[0]]; var applies = false;
if(dbot.db.ignores.hasOwnProperty(data.user) && if(dbot.commands[commandName].hasOwnProperty('regex')) {
dbot.db.ignores[data.user].include(commandBelongsTo)) { var cRegex = dbot.commands[commandName].regex;
// do nothing var q = event.message.valMatch(cRegex[0], cRegex[1]);
} else {
dbot.commands[params[0]](data, params);
dbot.save();
}
}
} else {
var q = data.message.valMatch(/^~([\d\w\s-]*)/, 2);
if(q) { if(q) {
if(dbot.db.bans['*'].include(data.user)) { applies = true;
dbot.say(data.channel, dbot.t('command_ban', {'user': data.user})); event.input = q;
} else {
q[1] = q[1].trim();
key = dbot.cleanNick(q[1])
if(dbot.db.quoteArrs.hasOwnProperty(key) && dbot.moduleNames.include('quotes') &&
(dbot.db.ignores.hasOwnProperty(data.user) &&
dbot.db.ignores[data.user].include('quotes')) == false) {
var params = ['~q'];
key.split(' ').each((function(word) {
this.push(word);
}).bind(params));
data.message = params.join(' ');
dbot.commands[params[0]](data, params);
dbot.save();
} else {
// See if it's similar to anything
var winnerDistance = Infinity;
var winner = false;
for(var commandName in dbot.commands) {
var distance = String.prototype.distance(params[0], commandName);
if(distance < winnerDistance) {
winner = commandName;
winnerDistance = distance;
} }
} else {
applies = true;
}
return applies;
};
return {
'name': 'command',
'ignorable': false,
/**
* Run the appropriate command given the input.
*/
'listener': function(event) {
var commandName = event.params[0];
if(!dbot.commands.hasOwnProperty(commandName)) {
commandName = '~';
} }
if(winnerDistance < 3) { if(isBanned(event.user, commandName)) {
dbot.say(data.channel, dbot.t('command_typo', {'command': winner})); event.reply(dbot.t('command_ban', {'user': event.user}));
} } else {
if(!isIgnoring(event.user, commandName)) {
if(applyRegex(commandName, event)) {
dbot.commands[commandName](event);
dbot.save();
} else {
if(commandName !== '~') {
event.reply(dbot.t('syntax_error'));
} }
} }
} }
} }
}, },
'on': 'PRIVMSG'
'on': 'PRIVMSG',
'name': 'command',
'ignorable': false
}; };
}; };

View File

@ -42,19 +42,19 @@ var normalizeDiceSpec = function (specString) {
var dice = function(dbot) { var dice = function(dbot) {
var commands = { var commands = {
'~roll': function (data, params) { '~roll': function (event) {
var rolls = []; var rolls = [];
if (params.length === 1) { if (event.params.length === 1) {
params.push("d6"); event.params.push("d6");
} }
for (var i = 1; i < params.length; i++) { for (var i = 1; i < event.params.length; i++) {
var diceSpec = parseDiceSpec(params[i]); var diceSpec = parseDiceSpec(event.params[i]);
if (diceSpec === false) { if (diceSpec === false) {
rolls.push([params[i], false]); rolls.push([event.params[i], false]);
} else { } else {
rolls.push([normalizeDiceSpec(params[i]), [], diceSpec["modifier"]]); rolls.push([normalizeDiceSpec(event.params[i]), [], diceSpec["modifier"]]);
for (var j = 0; j < diceSpec["count"] ; j++) { for (var j = 0; j < diceSpec["count"] ; j++) {
rolls[rolls.length-1][1].push(Math.ceil(Math.random() * diceSpec["sides"])); rolls[rolls.length-1][1].push(Math.ceil(Math.random() * diceSpec["sides"]));
} }
@ -63,7 +63,7 @@ var dice = function(dbot) {
for (var i = 0; i < rolls.length; i++) { for (var i = 0; i < rolls.length; i++) {
if (rolls[i][1] === false) { if (rolls[i][1] === false) {
dbot.say(data.channel, rolls[i][0] + ": invalid dice spec"); event.reply(rolls[i][0] + ": invalid dice spec");
} else { } else {
if (rolls[i][1].length > 1) { if (rolls[i][1].length > 1) {
var total = " (total " + rolls[i][1].sum(); var total = " (total " + rolls[i][1].sum();
@ -79,7 +79,7 @@ var dice = function(dbot) {
} else { } else {
var total = ""; var total = "";
} }
dbot.say(data.channel, rolls[i][0] + ": " + rolls[i][1].join(" ") + total); event.reply(rolls[i][0] + ": " + rolls[i][1].join(" ") + total);
} }
} }
} }

View File

@ -1,3 +1,7 @@
/**
* Module Name: Drama
* Description: Experimental, you probably don't want it.
*/
var brain = require('brain'); var brain = require('brain');
var drama = function(dbot) { var drama = function(dbot) {
@ -25,70 +29,65 @@ var drama = function(dbot) {
var bayes = new brain.BayesianClassifier(options); var bayes = new brain.BayesianClassifier(options);
var commands = { var commands = {
'~train': function(data, params) { '~train': function(event) {
if(dbot.admin.include(data.user)) { if(dbot.admin.include(event.user)) {
bayes.train(last[params[1]][params[2]], params[3]); bayes.train(last[event.params[1]][event.params[2]], event.params[3]);
dbot.say(data.channel, 'Last thing ' + params[2] + ' said in ' + event.reply('Last thing ' + event.params[2] + ' said in ' +
params[1] + ' (' + last[params[1]][params[2]] + ') classified as \'' + params[3] + '\''); event.params[1] + ' (' + last[event.params[1]][event.params[2]] + ') classified as \'' + event.params[3] + '\'');
} }
}, },
'~rtrain': function(data, params) { '~rtrain': function(event) {
if(dbot.admin.include(data.user)) { if(dbot.admin.include(event.user)) {
var category = params[1]; var category = event.params[1];
params.splice(0, 2); event.params.splice(0, 2);
var msg = params.join(' '); var msg = event.params.join(' ');
bayes.train(msg, category); bayes.train(msg, category);
dbot.say(data.channel, '\'' + msg + '\' classified as \'' + category + '\''); event.reply('\'' + msg + '\' classified as \'' + category + '\'');
} }
}, },
'~classify': function(data, params) { '~classify': function(event) {
params.splice(0, 1); event.params.splice(0, 1);
var msg = params.join(' '); var msg = event.params.join(' ');
bayes.classify(msg, function(category) { bayes.classify(msg, function(category) {
dbot.say(data.channel, 'Classified as: ' + category + '!'); event.reply('Classified as: ' + category + '!');
}.bind(this)); }.bind(this));
} }
} }
return { return {
'onLoad': function() { 'name': 'drama',
return commands; 'ignorable': false,
}, 'commands': commands,
'listener': function(data) { 'listener': function(data) {
var category = bayes.classify(data.message, function(category) { var category = bayes.classify(data.message, function(category) {
if(category !== 'normal') { if(category !== 'normal') {
if(category === 'beinganasshole') { if(category === 'beinganasshole') {
if(dbot.db.drama.beinganasshole.hasOwnProperty(data.user)) { if(dbot.db.drama.beinganasshole.hasOwnProperty(event.user)) {
dbot.db.drama.beinganasshole[data.user]++; dbot.db.drama.beinganasshole[event.user]++;
} else { } else {
dbot.db.drama.beinganasshole[data.user] = 1; dbot.db.drama.beinganasshole[event.user] = 1;
} }
} else if(category === 'sd') { } else if(category === 'sd') {
if(dbot.db.drama.sd.hasOwnProperty(data.user)) { if(dbot.db.drama.sd.hasOwnProperty(event.user)) {
dbot.db.drama.sd[data.user]++; dbot.db.drama.sd[event.user]++;
} else { } else {
dbot.db.drama.sd[data.user] = 1; dbot.db.drama.sd[event.user] = 1;
} }
} }
} }
}.bind(this)); }.bind(this));
if(last.hasOwnProperty(data.channel)) { if(last.hasOwnProperty(event.channel)) {
last[data.channel][data.user] = data.message; last[event.channel][event.user] = data.message;
} else { } else {
last[data.channel] = { }; last[event.channel] = { };
last[data.channel][data.user] = data.message; last[event.channel][event.user] = data.message;
} }
}, },
'on': 'PRIVMSG'
'on': 'PRIVMSG',
'name': 'drama',
'ignorable': false
}; };
} }

81
modules/ignore.js Normal file
View File

@ -0,0 +1,81 @@
/**
* Module Name: Ignore
* Description: Handles commands in which users can choose to ignore listeners
* and commands from certain modules. It also populates the JSBot instance with
* this information, since that actually performs the ignorance.
*/
var ignore = function(dbot) {
var commands = {
'~ignore': function(event) {
var ignorableModules = [];
for(var i=0;i<dbot.modules.length;i++) {
if(dbot.modules[i].ignorable != null && dbot.modules[i].ignorable == true) {
ignorableModules.push(dbot.modules[i].name);
}
}
var module = event.params[1];
if(module === undefined) {
event.reply(dbot.t('ignore_usage', {'user': event.user, 'modules': ignorableModules.join(', ')}));
} else {
if(ignorableModules.include(module)) {
if(dbot.db.ignores.hasOwnProperty(event.user) && dbot.db.ignores[event.user].include(module)) {
event.reply(dbot.t('already_ignoring', {'user': event.user}));
} else {
if(dbot.db.ignores.hasOwnProperty(module)) {
dbot.db.ignores[event.user].push(module);
} else {
dbot.db.ignores[event.user] = [module];
}
dbot.instance.ignoreTag(event.user, module);
event.reply(dbot.t('ignored', {'user': event.user, 'module': module}));
}
} else {
event.reply(dbot.t('invalid_ignore', {'user': event.user}));
}
}
},
'~unignore': function(event) {
var ignoredModules = [];
if(dbot.db.ignores.hasOwnProperty(event.user)) {
ignoredModules = dbot.db.ignores[event.user];
}
var module = event.params[1];
if(module === undefined) {
event.reply(dbot.t('unignore_usage', {'user': event.user, 'modules': ignoredModules.join(', ')}));
} else {
if(ignoredModules.include(module) == false) {
event.reply(dbot.t('invalid_unignore', {'user': event.user}));
} else {
dbot.db.ignores[event.user].splice(dbot.db.ignores[event.user].indexOf(module), 1);
dbot.instance.removeIgnore(event.user, module)
event.reply(dbot.t('unignored', {'user': event.user, 'module': module}));
}
}
}
};
return {
'name': 'ignore',
'ignorable': false,
'commands': commands,
'onLoad': function() {
dbot.instance.clearIgnores();
for(var user in dbot.db.ignores) {
if(dbot.db.ignores.hasOwnProperty(user)) {
for(var i=0;i<dbot.db.ignores[user].length;i++) {
dbot.instance.ignoreTag(user, dbot.db.ignores[user][i]);
}
}
}
}
};
};
exports.fetch = function(dbot) {
return ignore(dbot);
};

View File

@ -1,37 +1,40 @@
/**
* Module Name: JS
* Description: Allows users to run sandboxed JS code, printing the result in
* the channel. Also allows admins to run un-sandboxed Javascript code with
* access to the DepressionBot instance memory.
*/
var vm = require('vm'); var vm = require('vm');
var sbox = require('sandbox'); var sbox = require('sandbox');
var js = function(dbot) { var js = function(dbot) {
var dbot = dbot;
var s = new sbox(); var s = new sbox();
var commands = { var commands = {
'~js': function(data, params) { // Run JS code sandboxed, return result to channel.
var q = data.message.valMatch(/^~js (.*)/, 2); '~js': function(event) {
s.run(q[1], function(output) { s.run(event.input[1], function(output) {
dbot.say(data.channel, output.result); event.reply(output.result);
}); }.bind(this));
}, },
'~ajs': function(data, params) { // Run JS code un-sandboxed, with access to DBot memory (admin-only).
var q = data.message.valMatch(/^~ajs (.*)/, 2); '~ajs': function(event) {
if(dbot.admin.include(data.user) ) { if(dbot.admin.include(event.user) ) {
var ret = eval(q[1]); var ret = eval(event.input[1]);
if(ret != undefined) { if(ret !== undefined) {
dbot.say(data.channel, ret); event.reply(ret);
} }
} }
} }
}; };
commands['~js'].regex = [/^~js (.*)/, 2];
commands['~ajs'].regex = [/^~ajs (.*)/, 2];
return { return {
'onLoad': function() {
return commands;
},
'name': 'js', 'name': 'js',
'ignorable': true,
'ignorable': true 'commands': commands
}; };
}; };

View File

@ -4,25 +4,27 @@ var kick = function(dbot) {
var commands = { var commands = {
// Give the number of times a given user has been kicked and has kicked // Give the number of times a given user has been kicked and has kicked
// other people. // other people.
'~kickcount': function(data, params) { '~kickcount': function(event) {
if(!dbot.db.kicks.hasOwnProperty(params[1])) { var username = event.params[1];
if(!dbot.db.kicks.hasOwnProperty(username)) {
var kicks = '0'; var kicks = '0';
} else { } else {
var kicks = dbot.db.kicks[params[1]]; var kicks = dbot.db.kicks[username];
} }
if(!dbot.db.kickers.hasOwnProperty(params[1])) { if(!dbot.db.kickers.hasOwnProperty(username)) {
var kicked = '0'; var kicked = '0';
} else { } else {
var kicked = dbot.db.kickers[params[1]]; var kicked = dbot.db.kickers[username];
} }
dbot.say(data.channel, dbot.t('user_kicks', {'user': params[1], 'kicks': kicks, 'kicked': kicked})); event.reply(dbot.t('user_kicks', {'user': username, 'kicks': kicks, 'kicked': kicked}));
}, },
// Output a list of the people who have been kicked the most and those // Output a list of the people who have been kicked the most and those
// who have kicked other people the most. // who have kicked other people the most.
'~kickstats': function(data, params) { '~kickstats': function(event) {
var orderedKickLeague = function(list, topWhat) { var orderedKickLeague = function(list, topWhat) {
var kickArr = []; var kickArr = [];
for(var kickUser in list) { for(var kickUser in list) {
@ -42,57 +44,39 @@ var kick = function(dbot) {
return kickString.slice(0, -2); return kickString.slice(0, -2);
}; };
dbot.say(data.channel, orderedKickLeague(dbot.db.kicks, 'Kicked')); event.reply(orderedKickLeague(dbot.db.kicks, 'Kicked'));
dbot.say(data.channel, orderedKickLeague(dbot.db.kickers, 'Kickers')); event.reply(orderedKickLeague(dbot.db.kickers, 'Kickers'));
} }
}; };
return { return {
// Counts kicks 'name': 'kick',
'listener': function(data) { 'ignorable': false,
if(data.kickee == dbot.name) { 'commands': commands,
dbot.instance.join(data.channel);
dbot.say(data.channel, dbot.t('kicked_dbot', {'botname': dbot.name})); 'listener': function(event) {
if(event.kickee == dbot.name) {
dbot.instance.join(event, event.channel);
event.reply(dbot.t('kicked_dbot', {'botname': dbot.name}));
dbot.db.kicks[dbot.name] += 1; dbot.db.kicks[dbot.name] += 1;
} else { } else {
if(!dbot.db.kicks.hasOwnProperty(event.kickee)) {
if(dbot.db.modehate.include(data.user)) { dbot.db.kicks[event.kickee] = 1;
dbot.instance.send('KICK ' + data.channel + ' ' + data.user + ' :gtfo (MODEHATE)');
if(!dbot.db.kicks.hasOwnProperty(data.user)) {
dbot.db.kicks[data.user] = 1;
} else { } else {
dbot.db.kicks[data.user] += 1; dbot.db.kicks[event.kickee] += 1;
}
} }
if(!dbot.db.kicks.hasOwnProperty(data.kickee)) { if(!dbot.db.kickers.hasOwnProperty(event.user)) {
dbot.db.kicks[data.kickee] = 1; dbot.db.kickers[event.user] = 1;
} else { } else {
dbot.db.kicks[data.kickee] += 1; dbot.db.kickers[event.user] += 1;
} }
if(!dbot.db.kickers.hasOwnProperty(data.user)) { event.reply(event.kickee + '-- (' + dbot.t('user_kicks',
dbot.db.kickers[data.user] = 1; {'user': event.kickee, 'kicks': dbot.db.kicks[event.kickee], 'kicked': dbot.db.kickers[event.kickee]}) + ')');
} else {
dbot.db.kickers[data.user] += 1;
}
dbot.say(data.channel, data.kickee + '-- (' +
dbot.t('user_kicks', {'user': data.kickee, 'kicks': dbot.db.kicks[data.kickee],
'kicked': dbot.db.kickers[data.kickee]}) + ')');
} }
}, },
on: 'KICK'
on: 'KICK',
'onLoad': function() {
return commands;
},
'name': 'kick',
'ignorable': false
}; };
}; };

52
modules/link.js Normal file
View File

@ -0,0 +1,52 @@
/**
* Module Name: Link
* Description: Stores recent channel links, with commands to retrieve
* information about links.
*/
var request = require('request');
var link = function(dbot) {
var urlRegex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
var links = {};
var commands = {
'~title': function(event) {
var link = links[event.channel];
if(event.params[1] !== undefined) {
var urlMatches = event.params[1].match(urlRegex);
if(urlMatches !== null) {
link = urlMatches[0];
}
}
request(link, function (error, response, body) {
if(!error && response.statusCode == 200) {
body = body.replace(/(\r\n|\n\r|\n)/gm, " ");
var title = body.valMatch(/<title>(.*)<\/title>/, 2);
if(title) {
event.reply(title[1]);
} else {
event.reply('no title found');
}
}
});
}
};
return {
'name': 'link',
'ignorable': true,
'commands': commands,
'listener': function(event) {
var urlMatches = event.message.match(urlRegex);
if(urlMatches !== null) {
links[event.channel] = urlMatches[0];
}
},
'on': 'PRIVMSG'
};
};
exports.fetch = function(dbot) {
return link(dbot);
};

View File

@ -1,23 +0,0 @@
var modehate = function(dbot) {
var dbot = dbot;
return {
'listener': function(data, params) {
if(data.raw[0].indexOf('-oooo') != -1) {
dbot.instance.send('KICK #42 ' + data.user + ' :gtfo - mass deop protection');
} else if(dbot.db.modehate.include(data.user) && data.raw[0].indexOf('-o') != -1) {
dbot.instance.send('KICK ' + data.channel + ' ' + data.user + ' :gtfo');
}
},
'on': 'MODE',
'name': 'modehate',
'ignorable': false
};
};
exports.fetch = function(dbot) {
return modehate(dbot);
};

85
modules/poll.js Normal file
View File

@ -0,0 +1,85 @@
var poll = function(dbot) {
if(!dbot.db.hasOwnProperty('polls')) {
dbot.db.polls = {};
}
var polls = dbot.db.polls;
var commands = {
'~newpoll': function(event) {
var name = event.input[1];
var options = event.input[2].split(',');
var description = event.input[3];
if(name === undefined || name === 'help') {
event.reply(dbot.t('newpoll_usage'));
} else {
if(polls.hasOwnProperty(name)) {
event.reply(dbot.t('poll_exists', {'name': name}));
} else {
polls[name] = {
'name': name,
'description': description,
'owner': event.user,
'votes': {},
'votees': {}
};
for(var i=0;i<options.length;i++) {
polls[name]['votes'][options[i]] = 0;
}
event.reply(dbot.t('poll_created', {'name': name, 'description': description}) +
' - http://nc.no.de:443/polls/' + name);
}
}
},
'~vote': function(event) {
var name = event.input[1];
var vote = event.input[2];
if(polls.hasOwnProperty(name)) {
if(polls[name].votes.hasOwnProperty(vote)) {
if(polls[name].votees.hasOwnProperty(event.user)) {
var oldVote = polls[name].votees[event.user];
polls[name].votes[oldVote]--;
polls[name].votes[vote]++;
polls[name].votees[event.user] = vote;
event.reply(dbot.t('changed_vote', {'vote': vote, 'poll': name,
'count': polls[name].votes[vote], 'user': event.user}));
} else {
polls[name].votes[vote]++;
polls[name].votees[event.user] = vote;
event.reply(dbot.t('voted', {'vote': vote, 'poll': name,
'count': polls[name].votes[vote], 'user': event.user}));
}
} else {
event.reply(dbot.t('invalid_vote', {'vote': vote}));
}
} else {
event.reply(dbot.t('poll_unexistent', {'name': name}));
}
},
'~pdesc': function(event) {
var name = event.input[1];
if(polls.hasOwnProperty(name)) {
event.reply(name + ': ' + polls[name].description + ' - http://nc.no.de:443/polls/' + name);
} else {
event.reply(dbot.t('poll_unexistent', {'name': name}));
}
}
};
commands['~newpoll'].regex = [/~newpoll ([^ ]+) \[options=([^ ]+)\] (.+)/, 4];
commands['~vote'].regex = [/~vote ([^ ]+) ([^ ]+)/, 3];
commands['~pdesc'].regex = [/~pdesc ([^ ]+)/, 2];
return {
'name': 'poll',
'ignorable': true,
'commands': commands
};
};
exports.fetch = function(dbot) {
return poll(dbot);
}

View File

@ -3,25 +3,20 @@ var puns = function(dbot) {
var dbot = dbot; var dbot = dbot;
return { return {
'listener': function(data) { 'name': name,
data.user = dbot.cleanNick(data.user); 'ignorable': true,
if((dbot.db.ignores.hasOwnProperty(data.user) && 'listener': function(event) {
dbot.db.ignores[data.user].include(name)) == false) { event.user = dbot.cleanNick(event.user);
if(dbot.moduleNames.include('quotes') && if(dbot.moduleNames.include('quotes') &&
dbot.db.quoteArrs.hasOwnProperty(data.user)) { dbot.db.quoteArrs.hasOwnProperty(event.user)) {
data.message = '~q ' + data.user.toLowerCase(); event.message = '~q ' + event.user;
var params = data.message.split(' '); event.action = 'PRIVMSG';
dbot.commands[params[0]](data, params); event.params = event.message.split(' ');
} dbot.instance.emit(event);
} }
}, },
'on': 'JOIN'
'on': 'JOIN',
'name': name,
'ignorable': true
}; };
} }

View File

@ -4,7 +4,8 @@ var quotes = function(dbot) {
var addStack = []; var addStack = [];
var rmAllowed = true; var rmAllowed = true;
// Retrieve a random quote from a given category, interpolating any quote references (~~QUOTE CATEGORY~~) within it // Retrieve a random quote from a given category, interpolating any quote
// references (~~QUOTE CATEGORY~~) within it
var interpolatedQuote = function(key, quoteTree) { var interpolatedQuote = function(key, quoteTree) {
if(quoteTree !== undefined && quoteTree.indexOf(key) != -1) { if(quoteTree !== undefined && quoteTree.indexOf(key) != -1) {
return ''; return '';
@ -28,39 +29,34 @@ var quotes = function(dbot) {
} }
} }
// Parse quote parameters
/*
var paramRefs = quoteString.match(/~~\$([1-9])~~/g);
var thisParam;
while(paramRefs && (thisParam = paramRefs.shift()) !== undefined) {
thisParam = thisParam[1];
console.log(thisParam);
if(thisParam < params.length) {
quoteString = quoteString.replace("~~$" + thisParam + "~~", params[thisParam]);
}
}
*/
return quoteString; return quoteString;
}; };
var commands = { var commands = {
'~q': function(data, params) { // Alternative syntax to ~q
var q = data.message.valMatch(/^~q ([\d\w\s-]*)/, 2); '~': function(event) {
if(q) { commands['~q'](event);
q[1] = q[1].trim(); },
key = q[1].toLowerCase();
if(quotes.hasOwnProperty(key)) { // Retrieve quote from a category in the database.
dbot.say(data.channel, q[1] + ': ' + interpolatedQuote(key)); '~q': function(event) {
} else { var key = event.input[1].trim().toLowerCase();
dbot.say(data.channel, dbot.t('category_not_found', {'category': q[1]})); var altKey;
if(key.split(' ').length > 0) {
altKey = key.replace(/ /g, '_');
} }
if(quotes.hasOwnProperty(key)) {
event.reply(key + ': ' + interpolatedQuote(key));
} else if(quotes.hasOwnProperty(altKey)) {
event.reply(altKey + ': ' + interpolatedQuote(altKey));
} else {
event.reply(dbot.t('category_not_found', {'category': key}));
} }
}, },
// shows the biggest categories // Shows a list of the biggest categories
'~qstats': function(data, params) { '~qstats': function(event) {
var qSizes = []; var qSizes = [];
for(var cat in quotes) { for(var cat in quotes) {
if(quotes[cat].length != 0) { if(quotes[cat].length != 0) {
@ -77,76 +73,55 @@ var quotes = function(dbot) {
qString += qSizes[i][0] + " (" + qSizes[i][1] + "), "; qString += qSizes[i][0] + " (" + qSizes[i][1] + "), ";
} }
dbot.say(data.channel, qString.slice(0, -2)); event.reply(qString.slice(0, -2));
}, },
'~qsearch': function(data, params) { // Search a given category for some text.
if(params[2] === undefined) { '~qsearch': function(event) {
dbot.say(data.channel, dbot.t('syntax_error')); var haystack = event.input[1].trim().toLowerCase();
} else { var needle = event.input[2];
params[1].trim(); if(quotes.hasOwnProperty(haystack)) {
key = params[1].toLowerCase();
if(!quotes.hasOwnProperty(key)) {
dbot.say(data.channel, dbot.t('empty_category'));
} else {
var matches = []; var matches = [];
quotes[haystack].each(function(quote) {
quotes[key].each(function(quote) { if(quote.indexOf(needle) != -1) {
if(quote.indexOf(params[2]) != -1) {
matches.push(quote); matches.push(quote);
} }
}.bind(this)); }.bind(this));
if(matches.length == 0) { if(matches.length == 0) {
dbot.say(data.channel, dbot.t('no_results')); event.reply(dbot.t('no_results'));
} else { } else {
dbot.say(data.channel, params[1] + ' (' + params[2] + '): ' + matches.random() + ' [' + matches.length + ' results]'); event.reply(dbot.t('search_results', {'category': haystack, 'needle': needle,
} 'quote': matches.random(), 'matches': matches.length}));
} }
} else {
event.reply(dbot.t('empty_category'));
} }
}, },
'~rmlast': function(data, params) { '~rmlast': function(event) {
if(rmAllowed == true || dbot.admin.include(data.user)) { if(rmAllowed == true || dbot.admin.include(event.user)) {
var q = data.message.valMatch(/^~rmlast ([\d\w\s-]*)/, 2); var key = event.input[1].trim().toLowerCase();
if(q) { if(quotes.hasOwnProperty(key)) {
q[1] = q[1].trim() if(!dbot.db.locks.include(key) || dbot.admin.include(event.user)) {
key = q[1].toLowerCase();
if(quotes.hasOwnProperty(q[1])) {
if(!dbot.db.locks.include(q[1]) || dbot.admin.include(data.user)) {
var quote = quotes[key].pop(); var quote = quotes[key].pop();
if(quotes[key].length === 0) { if(quotes[key].length === 0) {
delete quotes[key]; delete quotes[key];
} }
rmAllowed = false; rmAllowed = false;
dbot.say(data.channel, '\'' + quote + '\'' + event.reply(dbot.t('removed_from', {'quote': quote, 'category': key}));
dbot.t('removed_from') + q[1]);
} else { } else {
dbot.say(data.channel, dbot.t('locked_category', {'category': q[1]})); event.reply(dbot.t('locked_category', {'category': q[1]}));
} }
} else { } else {
dbot.say(data.channel, dbot.t('no_quotes', {'category': q[1]})); event.reply(dbot.t('no_quotes', {'category': q[1]}));
} }
} else { } else {
var last = addStack.pop(); event.reply(dbot.t('rmlast_spam'));
if(last) {
if(!dbot.db.locks.include(last)) {
quotes[last].pop();
rmAllowed = false;
dbot.say(data.channel, dbot.t('last_removed', {'category': last}));
} else {
dbot.say(data.channel, dbot.t('locked_category', {'category': last}));
}
} else {
dbot.say(data.channel, dbot.t('no_recent_adds'));
}
}
} else {
dbot.say(data.channel, dbot.t('rmlast_spam'));
} }
}, },
'~rm': function(data, params) { /*'~rm': function(data, params) {
if(rmAllowed == true || dbot.admin.include(data.user)) { if(rmAllowed == true || dbot.admin.include(data.user)) {
var q = data.message.valMatch(/^~rm ([\d\w\s-]*) (.+)$/, 3); var q = data.message.valMatch(/^~rm ([\d\w\s-]*) (.+)$/, 3);
if(q) { if(q) {
@ -175,82 +150,57 @@ var quotes = function(dbot) {
} else { } else {
dbot.say(data.channel, dbot.t('rmlast_spam')); dbot.say(data.channel, dbot.t('rmlast_spam'));
} }
}, },*/
'~qcount': function(data, params) { '~qcount': function(event) {
var q = data.message.valMatch(/^~qcount ([\d\w\s-]*)/, 2); var input = event.message.valMatch(/^~qcount ([\d\w\s-]*)/, 2);
if(q) { if(input) { // Give quote count for named category
q[1] = q[1].trim(); var key = input[1].trim().toLowerCase();
key = q[1].toLowerCase();
if(quotes.hasOwnProperty(key)) { if(quotes.hasOwnProperty(key)) {
dbot.say(data.channel, dbot.t('quote_count', {'category': q[1], 'count': quotes[key].length})); event.reply(dbot.t('quote_count', {'category': key, 'count': quotes[key].length}));
} else { } else {
dbot.say(data.channel, dbot.t('no_quotes', {'category': q[1]})); event.reply(dbot.t('no_quotes', {'category': key}));
} }
} else { // Give total quote count } else { // Give total quote count
var totalQuoteCount = 0; var totalQuoteCount = 0;
for(var category in quotes) { for(var category in quotes) {
totalQuoteCount += category.length; totalQuoteCount += category.length;
} }
dbot.say(data.channel, dbot.t('total_quotes', {'count': totalQuoteCount})); event.reply(dbot.t('total_quotes', {'count': totalQuoteCount}));
} }
}, },
'~qadd': function(data, params) { '~qadd': function(event) {
var q = data.message.valMatch(/^~qadd ([\d\w\s-]+?)[ ]?=[ ]?(.+)$/, 3); var key = event.input[1].toLowerCase();
if(q) { var text = event.input[2];
key = q[1].toLowerCase();
if(!Object.isArray(quotes[key])) { if(!Object.isArray(quotes[key])) {
quotes[key] = []; quotes[key] = [];
}
if(quotes[key].include(text)) {
event.reply(dbot.t('quote_exists'));
} else { } else {
if (quotes[key].include(q[2])) { quotes[key].push(text);
dbot.say(data.channel, dbot.t('quote_exists'));
return;
}
}
quotes[key].push(q[2]);
addStack.push(q[1]);
rmAllowed = true; rmAllowed = true;
dbot.say(data.channel, dbot.t('quote_saved', {'category': q[1], 'count': quotes[key].length})); event.reply(dbot.t('quote_saved', {'category': key, 'count': quotes[key].length}));
} else {
dbot.say(data.channel, dbot.t('syntax_error'));
} }
}, },
'~qset': function(data, params) { '~rq': function(event) {
var q = data.message.valMatch(/^~qset ([\d\w\s-]*)=(.+)$/, 3);
if(q) {
q[1] = q[1].trim();
key = q[1].toLowerCase();
if(!quotes.hasOwnProperty(key) || (quotes.hasOwnProperty(key) &&
quotes[key].length == 1)) {
quotes[key] = [q[2]];
dbot.say(data.channel, dbot.t('quote_saved', {'category': q[1], 'count': 1}));
} else {
dbot.say(data.channel, dbot.t('quote_replace'));
}
}
},
'~rq': function(data, params) {
var rQuote = Object.keys(quotes).random(); var rQuote = Object.keys(quotes).random();
dbot.say(data.channel, rQuote + ': ' + interpolatedQuote(rQuote)); event.reply(rQuote + ': ' + interpolatedQuote(rQuote));
}, },
'~d': function(data, params) { '~link': function(event) {
dbot.say(data.channel, data.user + ': ' + interpolatedQuote(dbot.name)); var key = event.params[1].trim().toLowerCase();
}, if(quotes.hasOwnProperty(key)) {
event.reply(dbot.t('quote_link', {'category': key}) + ' - http://nc.no.de:443/quotes/' + key);
'~link': function(data, params) {
if(params[1] === undefined || !quotes.hasOwnProperty(params[1].toLowerCase())) {
dbot.say(data.channel, dbot.t('syntax_error'));
} else { } else {
dbot.say(data.channel, dbot.t('quote_link', {'category': params[1]}) + event.reply(dbot.t('category_not_found'));
' - http://nc.no.de:443/quotes/' + params[1]);
} }
}, },
'~qprune': function(data) { '~qprune': function(event) {
var pruned = [] var pruned = []
for(key in quotes) { for(key in quotes) {
if(quotes.hasOwnProperty(key)) { if(quotes.hasOwnProperty(key)) {
@ -261,22 +211,31 @@ var quotes = function(dbot) {
} }
} }
if(pruned.length > 0) { if(pruned.length > 0) {
dbot.say(data.channel, dbot.t('prune', {'categories': pruned.join(", ")})); event.reply(dbot.t('prune', {'categories': pruned.join(", ")}));
} else { } else {
dbot.say(data.channel, dbot.t('no_prune')); event.reply(dbot.t('no_prune'));
} }
} }
}; };
commands['~'].regex = [/^~([\d\w\s-]*)/, 2];
commands['~q'].regex = [/^~q ([\d\w\s-]*)/, 2];
commands['~qsearch'].regex = [/^~qsearch ([\d\w\s-]+?)[ ]?=[ ]?(.+)$/, 3];
commands['~rmlast'].regex = [/^~rmlast ([\d\w\s-]*)/, 2];
commands['~qadd'].regex = [/^~qadd ([\d\w\s-]+?)[ ]?=[ ]?(.+)$/, 3];
return { return {
'name': 'quotes',
'ignorable': true,
'commands': commands,
'onLoad': function() { 'onLoad': function() {
dbot.timers.addTimer(1000 * 60 * 3, function() { dbot.timers.addTimer(1000 * 60 * 3, function() {
rmAllowed = true; rmAllowed = true;
}); });
return commands;
}, },
// For automatic quote retrieval /* For automatic quote retrieval
'listener': function(data, params) { 'listener': function(data, params) {
if((dbot.db.ignores.hasOwnProperty(data.user) && if((dbot.db.ignores.hasOwnProperty(data.user) &&
dbot.db.ignores[data.user].include(name)) == false) { dbot.db.ignores[data.user].include(name)) == false) {
@ -304,11 +263,7 @@ var quotes = function(dbot) {
} }
}, },
'on': 'PRIVMSG', 'on': 'PRIVMSG',*/
'name': name,
'ignorable': true
}; };
}; };

View File

@ -1,10 +1,8 @@
var spelling = function(dbot) { var spelling = function(dbot) {
var name = 'spelling';
var dbot = dbot;
var last = {}; var last = {};
var correct = function (data, correction, candidate, output_callback) { var correct = function (event, correction, candidate, output_callback) {
var rawCandidates = last[data.channel][candidate].split(' ').allGroupings(); var rawCandidates = last[event.channel][candidate].split(' ').allGroupings();
var candidates = []; var candidates = [];
for(var i=0;i<rawCandidates.length;i++) { for(var i=0;i<rawCandidates.length;i++) {
candidates.push(rawCandidates[i].join(' ')); candidates.push(rawCandidates[i].join(' '));
@ -22,14 +20,14 @@ var spelling = function(dbot) {
if(winnerDistance < Math.ceil(winner.length * 1.33)) { if(winnerDistance < Math.ceil(winner.length * 1.33)) {
if(winner !== correction) { if(winner !== correction) {
var fix = last[data.channel][candidate].replace(winner, correction); var fix = last[event.channel][candidate].replace(winner, correction);
if (/^.ACTION/.test(fix)) { if (/^.ACTION/.test(fix)) {
fix = fix.replace(/^.ACTION/, '/me'); fix = fix.replace(/^.ACTION/, '/me');
} }
last[data.channel][candidate] = fix; last[event.channel][candidate] = fix;
var output = { var output = {
'fix': fix, 'fix': fix,
'correcter': data.user, 'correcter': event.user,
'candidate': candidate 'candidate': candidate
}; };
output_callback(output); output_callback(output);
@ -38,35 +36,30 @@ var spelling = function(dbot) {
} }
return { return {
'listener': function(data, params) { 'name': 'spelling',
if((dbot.db.ignores.hasOwnProperty(data.user) && 'ignorable': true,
dbot.db.ignores[data.user].include(name)) == false) {
var q = data.message.valMatch(/^(?:\*\*?([\d\w\s']*)|([\d\w\s']*)\*\*?)$/, 3); 'listener': function(event) {
var otherQ = data.message.valMatch(/^([\d\w\s]*): (?:\*\*?([\d\w\s']*)|([\d\w\s']*)\*\*?)$/, 4); var q = event.message.valMatch(/^(?:\*\*?([\d\w\s']*)|([\d\w\s']*)\*\*?)$/, 3);
var otherQ = event.message.valMatch(/^([\d\w\s]*): (?:\*\*?([\d\w\s']*)|([\d\w\s']*)\*\*?)$/, 4);
if(q) { if(q) {
correct(data, q[1] || q[2], data.user, function (e) { correct(event, q[1] || q[2], event.user, function (e) {
dbot.say(data.channel, dbot.t('spelling_self', e)); event.reply(dbot.t('spelling_self', e));
}); });
} else if(otherQ) { } else if(otherQ) {
correct(data, otherQ[2] || otherQ[3], otherQ[1], function (e) { correct(event, otherQ[2] || otherQ[3], otherQ[1], function (e) {
dbot.say(data.channel, dbot.t('spelling_other', e)); event.reply(dbot.t('spelling_other', e));
}); });
} else { } else {
if(last.hasOwnProperty(data.channel)) { if(last.hasOwnProperty(event.channel)) {
last[data.channel][data.user] = data.message; last[event.channel][event.user] = event.message;
} else { } else {
last[data.channel] = { }; last[event.channel] = { };
last[data.channel][data.user] = data.message; last[event.channel][event.user] = event.message;
}
} }
} }
}, },
'on': 'PRIVMSG'
'on': 'PRIVMSG',
'name': name,
'ignorable': true
} }
} }

View File

@ -1,9 +1,6 @@
var express = require('express'); var express = require('express');
// Web interface module using the express framework
var webInterface = function(dbot) { var webInterface = function(dbot) {
var dbot = dbot;
var pub = 'public'; var pub = 'public';
var app = express.createServer(); var app = express.createServer();
@ -12,8 +9,8 @@ var webInterface = function(dbot) {
app.set('view engine', 'jade'); app.set('view engine', 'jade');
app.get('/', function(req, res) { app.get('/', function(req, res) {
res.redirect('/quotes'); //res.redirect('/quotes');
//res.render('index', { }); res.render('index', { 'name': dbot.name });
}); });
// Lists the quote categories // Lists the quote categories
@ -37,16 +34,38 @@ var webInterface = function(dbot) {
res.render('quotes', { 'name': dbot.name, 'quotes': dbot.db.quoteArrs[rCategory], locals: { 'url_regex': RegExp.prototype.url_regex() } }); res.render('quotes', { 'name': dbot.name, 'quotes': dbot.db.quoteArrs[rCategory], locals: { 'url_regex': RegExp.prototype.url_regex() } });
}); });
// Lists all of the polls
app.get('/polls', function(req, res) {
res.render('polllist', { 'name': dbot.name, 'polllist': Object.keys(dbot.db.polls) });
});
// Shows the results of a poll
app.get('/polls/:key', function(req, res) {
var key = req.params.key.toLowerCase();
if(dbot.db.polls.hasOwnProperty(key)) {
// tally the votes
var totalVotes = 0;
for( var v in dbot.db.polls[key].votes ) {
var N = Number(dbot.db.polls[key].votes[v]);
if( !isNaN(N) ) {
totalVotes += N;
}
}
res.render('polls', { 'name': dbot.name, 'description': dbot.db.polls[key].description, 'votees': Object.keys(dbot.db.polls[key].votees), 'options': dbot.db.polls[key].votes, locals: { 'totalVotes': totalVotes, 'url_regex': RegExp.prototype.url_regex() } });
} else {
res.render('error', { 'name': dbot.name, 'message': 'No polls under that key.' });
}
});
app.listen(dbot.webPort); app.listen(dbot.webPort);
return { return {
'name': 'web',
'ignorable': false,
'onDestroy': function() { 'onDestroy': function() {
app.close(); app.close();
}, }
'name': 'web',
'ignorable': false
}; };
}; };

View File

@ -1,23 +1,16 @@
var youAre = function(dbot) { var youAre = function(dbot) {
var name = 'youare';
return { return {
'listener': function(data) { 'name': 'youare',
if((dbot.db.ignores.hasOwnProperty(data.user) && 'ignorable': false,
dbot.db.ignores[data.user].include(name)) == false) {
var key = data.message.valMatch(/(\bis\b|\bare\b)\s+([\w\s\d]*?)(\s+)?(,|\.|\band\b|$)/, 5);
if(key && key[2] != "" && Number.prototype.chanceIn(1, 100) && data.user != 'aisbot') { 'listener': function(event) {
dbot.say(data.channel, data.user + ': You\'re ' + key[2] + '.'); var key = event.message.valMatch(/(\bis\b|\bare\b)\s+([\w\s\d]*?)(\s+)?(,|\.|\band\b|$)/, 5);
}
if(key && key[2] != "" && Number.prototype.chanceIn(1, 100) && event.user != 'aisbot') {
event.reply(event.user + ': You\'re ' + key[2] + '.');
} }
}, },
'on': 'PRIVMSG'
'on': 'PRIVMSG',
'name': name,
'ignorable': false
}; };
}; };

View File

@ -21,11 +21,28 @@ body {
text-shadow: 1px 1px 2px #2B2B2B; text-shadow: 1px 1px 2px #2B2B2B;
} }
h1,h2 {
margin: 0;
padding: 0;
}
p {
margin: 15px 5px;
}
div#page { div#page {
width: 90%; width: 90%;
margin: 0 auto 0 auto; margin: 0 auto 0 auto;
} }
div#backlink {
position: absolute;
top: 10px;
left: 15px;
text-align: left;
font-size: 0.8em;
}
div#title { div#title {
font-size: 42px; font-size: 42px;
font-weight: bold; font-weight: bold;
@ -38,7 +55,8 @@ div#title a {
} }
div#main { div#main {
padding: 25px 0px; position: relative;
padding: 15px 5px;
margin: 0px; margin: 0px;
font-size: 21px; font-size: 21px;
text-align:center; text-align:center;
@ -59,6 +77,24 @@ a,a:active,a:visited {
text-decoration: none; text-decoration: none;
} }
/* Index Page */
#modulelinks {
margin: 0;
padding: 0;
}
.module {
display: inline-block;
width: 45%;
padding: 15px 0;
margin: 0 2%;
background: #F5F5F5;
border-radius: 15px;
}
.module:hover {
background: #BBB;
}
ul#quotelist { ul#quotelist {
padding: 0; padding: 0;
margin: 0; margin: 0;
@ -105,3 +141,34 @@ li.quote {
img { img {
max-width: 100%; max-width: 100%;
} }
/* Polls */
#votelist {
margin: 10px 0;
padding: 0 40px;
}
li.option {
list-style: none;
text-align: left;
font-size: 1.2em;
}
li.option-votes {
list-style: none;
text-align: left;
margin-bottom: 10px;
}
.vote-percentage {
height: 20px;
background: #444;
}
.vote-track {
height: 20px;
width: 100%;
background: #EEE;
margin: 2px 0;
box-shadow: inset 0px 0px 3px #444;
}

69
run.js
View File

@ -43,39 +43,56 @@ var DBot = function(timers) {
this.db.ignores = {}; this.db.ignores = {};
} }
// Load the strings file // Load Strings file
this.strings = JSON.parse(fs.readFileSync('strings.json', 'utf-8')); this.strings = JSON.parse(fs.readFileSync('strings.json', 'utf-8'));
// Initialise run-time resources
this.sessionData = {};
this.timers = timers.create();
// Populate bot properties with config data // Populate bot properties with config data
this.name = this.config.name || 'dbox'; this.name = this.config.name || 'dbox';
this.admin = this.config.admin || [ 'reality' ]; this.admin = this.config.admin || [ 'reality' ];
this.password = this.config.password || 'lolturtles'; this.moduleNames = this.config.modules || [ 'ignore', 'admin', 'command', 'dice', 'js', 'kick', 'puns', 'quotes', 'spelling', 'youare' ];
this.nickserv = this.config.nickserv || 'zippy';
this.server = this.config.server || 'elara.ivixor.net';
this.port = this.config.port || 6667;
this.webPort = this.config.webPort || 443;
this.moduleNames = this.config.modules || [ 'command', 'js', 'admin', 'kick', 'modehate', 'quotes', 'puns', 'spelling', 'web', 'youare', 'autoshorten' ];
this.language = this.config.language || 'english'; this.language = this.config.language || 'english';
this.sessionData = {}; this.webPort = this.config.webPort || 80;
this.timers = timers.create(); // It's the user's responsibility to fill this data structure up properly in
// the config file. They can d-d-d-deal with it if they have problems.
this.instance = jsbot.createJSBot(this.name, this.server, this.port, this, function() { this.servers = this.config.servers || {
if(this.config.hasOwnProperty('channels')) { 'freenode': {
this.config.channels.each(function(channel) { 'server': 'irc.freenode.net',
this.instance.join(channel); 'port': 6667,
}.bind(this)); 'nickserv': 'nickserv',
'password': 'lolturtles',
'channels': [
'#realitest'
]
}
};
// Create JSBot and connect to each server
this.instance = jsbot.createJSBot(this.name);
for(var name in this.servers) {
if(this.servers.hasOwnProperty(name)) {
var server = this.servers[name];
this.instance.addConnection(name, server.server, server.port, this.admin, function(event) {
var server = this.servers[event.server];
for(var i=0;i<server.channels.length;i++) {
this.instance.join(event, server.channels[i]);
}
}.bind(this), server.nickserv, server.password);
}
} }
}.bind(this), this.nickserv, this.password);
// Load the modules and connect to the server // Load the modules and connect to the server
this.reloadModules(); this.reloadModules();
this.instance.connect(); this.instance.connectAll();
}; };
// Say something in a channel // Say something in a channel
DBot.prototype.say = function(channel, data) { DBot.prototype.say = function(server, channel, message) {
this.instance.say(channel, data); this.instance.say(server, channel, message);
}; };
// Format given stored string in config language // Format given stored string in config language
@ -88,9 +105,9 @@ DBot.prototype.t = function(string, formatData) {
return this.strings[string][lang].format(formatData); return this.strings[string][lang].format(formatData);
}; };
DBot.prototype.act = function(channel, data) { /*DBot.prototype.act = function(channel, data) {
this.instance.send('PRIVMSG', channel, ':\001ACTION ' + data + '\001'); this.instance.send('PRIVMSG', channel, ':\001ACTION ' + data + '\001');
} }*/
// Save the database file // Save the database file
DBot.prototype.save = function() { DBot.prototype.save = function() {
@ -137,11 +154,15 @@ DBot.prototype.reloadModules = function() {
this.rawModules.push(rawModule); this.rawModules.push(rawModule);
if(module.listener) { if(module.listener) {
this.instance.addListener(module.on, module.listener); this.instance.addListener(module.on, module.name, module.listener);
} }
if(module.onLoad) { if(module.onLoad) {
var newCommands = module.onLoad(); module.onLoad();
}
if(module.commands) {
var newCommands = module.commands;
for(key in newCommands) { for(key in newCommands) {
if(newCommands.hasOwnProperty(key) && Object.prototype.isFunction(newCommands[key])) { if(newCommands.hasOwnProperty(key) && Object.prototype.isFunction(newCommands[key])) {
this.commands[key] = newCommands[key]; this.commands[key] = newCommands[key];
@ -152,7 +173,7 @@ DBot.prototype.reloadModules = function() {
this.modules.push(module); this.modules.push(module);
} catch(err) { } catch(err) {
console.log(this.strings[this.language].module_load_error.format({'moduleName': name})); console.log(this.t('module_load_error', {'moduleName': name}));
console.log(err); console.log(err);
} }
}.bind(this)); }.bind(this));

View File

@ -186,5 +186,35 @@
"kicked_dbot": { "kicked_dbot": {
"english": "Thou shalt not kick {botname}", "english": "Thou shalt not kick {botname}",
"spanish": "No expulsás {botname}" "spanish": "No expulsás {botname}"
},
"search_results": {
"english": "{category} ({needle}): '{quote}' [{matches} results]"
},
"join": {
"english": "Joined {channel}"
},
"part": {
"english": "Left {channel}"
},
"newpoll_usage": {
"english": "Usage: ~newpoll name [options=opt1,opt2,opt3] description"
},
"poll_exists": {
"english": "Poll '{name}' already exists."
},
"poll_created": {
"english": "Poll '{name}' created ({description}). Cast thy votations!"
},
"changed_vote": {
"english": "{user} changed their vote in {poll} to '{vote}' ({count})"
},
"voted": {
"english": "{user} voted for '{vote}' in {poll} ({count})"
},
"invalid_vote": {
"english": "Invalid vote: {vote}"
},
"poll_unexistent": {
"english": "Poll '{name}' doesn't exist."
} }
} }

View File

@ -1,3 +1,3 @@
div#main #modulelinks
p a.module(href='/quotes') Quotes
a(href: '/quotes') Quotes a.module(href='/polls') Polls

9
views/polllist.jade Normal file
View File

@ -0,0 +1,9 @@
div#backlink
a(href='/') &laquo; Home
div#controls
input(type="text", name="search", id="search-text", oninput="search(this.value)")
ul#quotelist
-each poll in polllist
a(href='/polls/'+poll)
li.quotes #{poll}

37
views/polls.jade Normal file
View File

@ -0,0 +1,37 @@
div#backlink
a(href='/polls/') &laquo; Poll list
h2 #{description}
p Voters (#{locals.totalVotes}):
-each voter in votees
| #{voter}
ul#votelist
-var hasYouTubeVids=false
-each votes,option in options
-var percentage = votes/locals.totalVotes*100
-if(options.hasOwnProperty(option))
-if(option.match(locals.url_regex))
li.option
-if(option.match(/(jpg|png|gif|jpeg|tiff)$/))
a(href=option)
img(src=option)
-else if(option.match(/youtube.com\/watch/))
-hasYouTubeVids = true
span(class='ytplaceholder')
=option
-else
a(href=option)
=option
-else
li.option #{option}
li.option-votes
.vote-track
-if(!isNaN(percentage))
.vote-percentage(style="width: #{percentage}%")
-if(votes == 1)
|#{votes} vote
-else
|#{votes} votes
-if(!isNaN(percentage))
|(#{percentage.toFixed(2)}%)
-if(hasYouTubeVids)
script(src='/ytembed.js')

View File

@ -1,3 +1,5 @@
div#backlink
a(href='/') &laquo; Home
div#controls div#controls
input(type="text", name="search", id="search-text", oninput="search(this.value)") input(type="text", name="search", id="search-text", oninput="search(this.value)")
ul#quotelist ul#quotelist

View File

@ -1,3 +1,5 @@
div#backlink
a(href='/quotes/') &laquo; Quote list
ul#quotelist ul#quotelist
-var hasYouTubeVids=false -var hasYouTubeVids=false
-each quote in quotes -each quote in quotes