mirror of
https://github.com/reality/dbot.git
synced 2024-11-27 22:39:26 +01:00
Merge branch 'master' of github.com:reality/depressionbot
This commit is contained in:
commit
8c81842643
118
README.md
Normal file
118
README.md
Normal file
@ -0,0 +1,118 @@
|
||||
# Depressionbot IRC Bot
|
||||
|
||||
## Introduction
|
||||
|
||||
Depressionbot is an IRC bot which aims to be the fanciest IRC bot around - On
|
||||
the general standard of software fanciness, dbot is rated as being '75% the same
|
||||
as bathing in fine, fine grape juice.'
|
||||
|
||||
Please note that this documentation is not complete and is a work in progress,
|
||||
given I started it rather a long time after I began development of the project.
|
||||
Please don't judge me too harshly for this as I am, in fact, mildly allergic to
|
||||
writing documentation.
|
||||
|
||||
Requirements:
|
||||
|
||||
- Node JS
|
||||
- [JSBot](http://github.com/reality/JSBot "JSBot"), the Javascript library I
|
||||
wrote to handle the IRC protocol and event listeners etc.
|
||||
- Various modules have their own requirements also.
|
||||
|
||||
## Modules:
|
||||
|
||||
### Command
|
||||
|
||||
This handles the command execution logic for DBot.
|
||||
|
||||
1. Does the input match a command key in *dbot.commands* ?
|
||||
2. Is there a quote category which matches the first part of the input
|
||||
(*~category*)?
|
||||
3. Is there a command name similar to to the first part of the input (*~name*)
|
||||
in *dbot.commands*?
|
||||
|
||||
This is the only module which is force loaded, even if it's not in the
|
||||
configuration.
|
||||
|
||||
### Quotes
|
||||
|
||||
This is the original reason that DBot was created, stores and displays quotes.
|
||||
|
||||
Commands:
|
||||
|
||||
- _~q category_ - Display a random quote from a given category.
|
||||
- _~qadd category=newquote_ - Add a new quote to the database.
|
||||
- _~qstats_ - Show a list of the biggest quote categories.
|
||||
- _~qsearch category needle_ - Search for a quote in a given category.
|
||||
- _~rmlast [category]_ - Remove the last quote added to a given category, or the
|
||||
last quote added.
|
||||
- _~rm category quote_ - Remove a given quote from the given category.
|
||||
- _~qcount category_ - Show the number of quotes stored in the given category.
|
||||
- _~rq_ - Show a random quote from a random category.
|
||||
- _~d_ - Show a quote from the category which matches the bot's name.
|
||||
- _~link category_ - Create a link to the page on the web interface which displays the
|
||||
given category's quotes.
|
||||
- _~qprune_ - Delete empty quote categories.
|
||||
|
||||
Unfortunately, this module is fairly highly coupled with certain other areas of
|
||||
the program. I am working on this, but note, for example, that one can still
|
||||
access quotes with the *~category* syntax even if the quotes module isn't
|
||||
loaded.
|
||||
|
||||
### Admin
|
||||
|
||||
Various administration functionality such as banning users, hot-reloading the
|
||||
code and ordering him to talk. Note that commands added here are handled with
|
||||
their own listener, rather than being part of the command logic which is handled
|
||||
by the Command module. Functionality in this module can be slightly unsafe as
|
||||
not much error checking on the input is performed.
|
||||
|
||||
TODO: Add summaries for each command in this module.
|
||||
|
||||
### Spelling
|
||||
|
||||
Will attempt to correct a users' spelling by using the levenshtein distance
|
||||
algorithm. One corrects the spelling of their previous message by simply posting
|
||||
a message with their correction and an asterisk:
|
||||
|
||||
> user: I am a tutrle.
|
||||
> user: *turtle
|
||||
user meant: I am a turtle.
|
||||
|
||||
The regular expression for this module also accepts two asterisks at the
|
||||
beginning of the correction, or at the end; it also accepts several words as the
|
||||
correction and deals with these fairly intelligently. Users may also attempt
|
||||
to correct another users like so:
|
||||
|
||||
> userone: I am a tutrle.
|
||||
> usertwo: userone: *turtle
|
||||
> usertwo thinks userone meant: I am a turtle.
|
||||
|
||||
### JS
|
||||
|
||||
This module provides two commands which allow the execution of Javascript code.
|
||||
For regular users, there is the *~js* command, which is completely sandboxed,
|
||||
but can still be used for calculation and the like.
|
||||
|
||||
> ~js Array(16).join('wat'-1) + " Batman!";
|
||||
'NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN Batman!'
|
||||
|
||||
This feature is fairly safe as the user doesn't have access to anything
|
||||
dangerous, and is safe from infinite loops or locking DBot up because the code
|
||||
which is run is killed if it does not finish within a short amount of time.
|
||||
|
||||
For administrators, the incredibly useful *~ajs* command is also available. The
|
||||
input for this command is simply 'eval'-ed and therefore has full access to
|
||||
DBot's memory. Of course, this is incredibly unsafe, but I find it rather fun;
|
||||
remember to only give extremely trusted friends administrator access to DBot, as
|
||||
there's nothing to stop them wiping the database or something similar - if
|
||||
you're worried about that kind of thing, do not load this module.
|
||||
|
||||
However, it's useful for many things, such as administrative activity for
|
||||
which there isn't a command in the admin module. For example, you could hot-add
|
||||
a new administrator like this:
|
||||
|
||||
> ~ajs dbot.admin.push('batman');
|
||||
2
|
||||
|
||||
You can also use this for debugging, or even adding new commands while DBot is
|
||||
running.
|
@ -1,4 +1,6 @@
|
||||
var fs = require('fs');
|
||||
var sys = require('sys')
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
var adminCommands = function(dbot) {
|
||||
var dbot = dbot;
|
||||
@ -6,17 +8,28 @@ var adminCommands = function(dbot) {
|
||||
var commands = {
|
||||
'join': function(data, params) {
|
||||
dbot.instance.join(params[1]);
|
||||
dbot.say(dbot.admin, 'Joined ' + params[1]);
|
||||
dbot.say(data.channel, 'Joined ' + params[1]);
|
||||
},
|
||||
|
||||
'opme': function(data, params) {
|
||||
dbot.instance.send('MODE ' + params[1] + ' +o ', dbot.admin);
|
||||
dbot.instance.send('MODE ' + params[1] + ' +o ', data.user);
|
||||
},
|
||||
|
||||
'part': function(data, params) {
|
||||
dbot.instance.part(params[1]);
|
||||
},
|
||||
|
||||
// Do a git pull and reload
|
||||
'greload': function(data, params) {
|
||||
var child;
|
||||
|
||||
child = exec("git pull", function (error, stdout, stderr) {
|
||||
console.log(stderr);
|
||||
dbot.say(data.channel, 'Git pulled that shit.');
|
||||
commands.reload(data, params);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
'reload': function(data, params) {
|
||||
dbot.db = JSON.parse(fs.readFileSync('db.json', 'utf-8'));
|
||||
dbot.reloadModules();
|
||||
@ -24,11 +37,25 @@ var adminCommands = function(dbot) {
|
||||
},
|
||||
|
||||
'say': function(data, params) {
|
||||
var c = params[1];
|
||||
if (params[1] === "@") {
|
||||
var c = data.channel;
|
||||
} else {
|
||||
var c = params[1];
|
||||
}
|
||||
var m = params.slice(2).join(' ');
|
||||
dbot.say(c, m);
|
||||
},
|
||||
|
||||
'act': function(data, params) {
|
||||
if (params[1] === "@") {
|
||||
var c = data.channel;
|
||||
} else {
|
||||
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();
|
||||
@ -92,7 +119,7 @@ var adminCommands = function(dbot) {
|
||||
if(data.channel == dbot.name) data.channel = data.user;
|
||||
|
||||
params = data.message.split(' ');
|
||||
if(commands.hasOwnProperty(params[0]) && data.user == dbot.admin) {
|
||||
if(commands.hasOwnProperty(params[0]) && dbot.admin.include(data.user)) {
|
||||
commands[params[0]](data, params);
|
||||
dbot.save();
|
||||
}
|
||||
|
105
modules/command.js
Normal file
105
modules/command.js
Normal file
@ -0,0 +1,105 @@
|
||||
// Module which handles the command execution syntax for DBot. Not much is going
|
||||
// to work without this.
|
||||
var command = function(dbot) {
|
||||
var dbot = dbot;
|
||||
|
||||
var ignoreCommands = function (data, params) {
|
||||
if(data.channel == dbot.name) data.channel = data.user;
|
||||
var targetCommand = params[1];
|
||||
var ignoreMins = parseFloat(params[2]);
|
||||
|
||||
if(!dbot.sessionData.hasOwnProperty("ignoreCommands")) {
|
||||
dbot.sessionData.ignoreCommands = {};
|
||||
}
|
||||
if(!dbot.sessionData.ignoreCommands.hasOwnProperty(targetCommand)) {
|
||||
dbot.sessionData.ignoreCommands[targetCommand] = [];
|
||||
}
|
||||
|
||||
if(dbot.sessionData.ignoreCommands[targetCommand].include(data.channel)) {
|
||||
dbot.say(data.channel, "Already ignoring '" + targetCommand + "' in '" + data.channel + "'.");
|
||||
} else {
|
||||
dbot.sessionData.ignoreCommands[targetCommand].push(data.channel);
|
||||
dbot.timers.addOnceTimer(ignoreMins * 60 * 1000, function() {
|
||||
dbot.sessionData.ignoreCommands[targetCommand].splice(dbot.sessionData.ignoreCommands[targetCommand].indexOf(data.channel), 1);
|
||||
dbot.say(data.channel, "No longer ignoring '" + targetCommand + "' in '" + data.channel + "'.");
|
||||
});
|
||||
dbot.say(data.channel, "Ignoring '" + targetCommand + "' in '" + data.channel + "' for the next " + ignoreMins + " minute" + (ignoreMins == 1 ? "" : "s") + ".");
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
'onLoad': function() {
|
||||
return {
|
||||
'~ignore': ignoreCommands
|
||||
};
|
||||
},
|
||||
'listener': function(data) {
|
||||
var params = data.message.split(' ');
|
||||
if(data.channel == dbot.name) data.channel = data.user;
|
||||
|
||||
var ignoringCommand = false;
|
||||
if(dbot.sessionData.hasOwnProperty("ignoreCommands")) {
|
||||
if(dbot.sessionData.ignoreCommands.hasOwnProperty(params[0])) {
|
||||
if(dbot.sessionData.ignoreCommands[params[0]].include(data.channel)) {
|
||||
ignoringCommand = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(dbot.commands.hasOwnProperty(params[0])) {
|
||||
if((dbot.db.bans.hasOwnProperty(params[0]) &&
|
||||
dbot.db.bans[params[0]].include(data.user)) || dbot.db.bans['*'].include(data.user)) {
|
||||
dbot.say(data.channel, data.user +
|
||||
' is banned from using this command. Commence incineration.');
|
||||
} else if(ignoringCommand) {
|
||||
// do nothing, this stops us falling through to the non-command stuff
|
||||
} else {
|
||||
dbot.commands[params[0]](data, params);
|
||||
dbot.save();
|
||||
}
|
||||
} else {
|
||||
var q = data.message.valMatch(/^~([\d\w\s-]*)/, 2);
|
||||
if(q) {
|
||||
if(dbot.db.bans['*'].include(data.user)) {
|
||||
dbot.say(data.channel, data.user +
|
||||
' is banned from using this command. Commence incineration.');
|
||||
} else {
|
||||
q[1] = q[1].trim();
|
||||
key = dbot.cleanNick(q[1])
|
||||
if(dbot.db.quoteArrs.hasOwnProperty(key) && dbot.moduleNames.include('quotes')) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if(winnerDistance < 3) {
|
||||
dbot.say(data.channel, 'Did you mean ' + winner + '? Learn to type, hippie!');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'on': 'PRIVMSG'
|
||||
};
|
||||
};
|
||||
|
||||
exports.fetch = function(dbot) {
|
||||
return command(dbot);
|
||||
};
|
||||
|
97
modules/dice.js
Normal file
97
modules/dice.js
Normal file
@ -0,0 +1,97 @@
|
||||
var parseDiceSpec = function (specString) {
|
||||
var rawSpec = specString.valMatch(/^([0-9]*)d(%|[0-9]*)(|[+-][0-9]+)$/i, 4);
|
||||
if (rawSpec !== false) {
|
||||
if (rawSpec[2] === "%") {
|
||||
rawSpec[2] = 100;
|
||||
}
|
||||
return {
|
||||
"count": parseInt(rawSpec[1] || 1),
|
||||
"sides": parseInt(rawSpec[2] || 6),
|
||||
"modifier": parseInt(rawSpec[3] || 0)
|
||||
};
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var normalizeDiceSpec = function (specString) {
|
||||
var diceSpec = parseDiceSpec(specString);
|
||||
|
||||
if (diceSpec["count"] > 1) {
|
||||
var count = diceSpec["count"];
|
||||
} else {
|
||||
var count = "";
|
||||
}
|
||||
|
||||
if (diceSpec["sides"] === 100) {
|
||||
var sides = "%";
|
||||
} else {
|
||||
var sides = diceSpec["sides"];
|
||||
}
|
||||
|
||||
if (diceSpec["modifier"] > 0) {
|
||||
var modifier = "+" + diceSpec["modifier"];
|
||||
} else if (diceSpec["modifier"] < 0) {
|
||||
var modifier = diceSpec["modifier"];
|
||||
} else {
|
||||
var modifier = "";
|
||||
}
|
||||
|
||||
return (count + "d" + sides + modifier);
|
||||
};
|
||||
|
||||
var dice = function(dbot) {
|
||||
var commands = {
|
||||
'~roll': function (data, params) {
|
||||
var rolls = [];
|
||||
|
||||
if (params.length === 1) {
|
||||
params.push("d6");
|
||||
}
|
||||
|
||||
for (var i = 1; i < params.length; i++) {
|
||||
var diceSpec = parseDiceSpec(params[i]);
|
||||
if (diceSpec === false) {
|
||||
rolls.push([params[i], false]);
|
||||
} else {
|
||||
rolls.push([normalizeDiceSpec(params[i]), [], diceSpec["modifier"]]);
|
||||
for (var j = 0; j < diceSpec["count"] ; j++) {
|
||||
rolls[rolls.length-1][1].push(Math.ceil(Math.random() * diceSpec["sides"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < rolls.length; i++) {
|
||||
if (rolls[i][1] === false) {
|
||||
dbot.say(data.channel, rolls[i][0] + ": invalid dice spec");
|
||||
} else {
|
||||
if (rolls[i][1].length > 1) {
|
||||
var total = " (total " + rolls[i][1].sum();
|
||||
if (rolls[i][2] != 0) {
|
||||
if (rolls[i][2] > 0) {
|
||||
total += " + ";
|
||||
} else {
|
||||
total += " - ";
|
||||
}
|
||||
total += Math.abs(rolls[i][2]) + " -> " + (rolls[i][1].sum() + rolls[i][2]);
|
||||
}
|
||||
total += ")"
|
||||
} else {
|
||||
var total = "";
|
||||
}
|
||||
dbot.say(data.channel, rolls[i][0] + ": " + rolls[i][1].join(" ") + total);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
'onLoad': function() {
|
||||
return commands;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.fetch = function(dbot) {
|
||||
return dice(dbot);
|
||||
};
|
@ -26,7 +26,7 @@ var drama = function(dbot) {
|
||||
|
||||
var commands = {
|
||||
'~train': function(data, params) {
|
||||
if(data.user == dbot.admin || data.user == 'golem' || data.user == 'Sam') {
|
||||
if(dbot.admin.include(data.user)) {
|
||||
bayes.train(last[params[1]][params[2]], params[3]);
|
||||
dbot.say(data.channel, 'Last thing ' + params[2] + ' said in ' +
|
||||
params[1] + ' (' + last[params[1]][params[2]] + ') classified as \'' + params[3] + '\'');
|
||||
@ -34,7 +34,7 @@ var drama = function(dbot) {
|
||||
},
|
||||
|
||||
'~rtrain': function(data, params) {
|
||||
if(data.user == dbot.admin || data.user == 'golem' || data.user == 'Sam') {
|
||||
if(dbot.admin.include(data.user)) {
|
||||
var category = params[1];
|
||||
params.splice(0, 2);
|
||||
var msg = params.join(' ');
|
||||
|
@ -15,8 +15,11 @@ var js = function(dbot) {
|
||||
|
||||
'~ajs': function(data, params) {
|
||||
var q = data.message.valMatch(/^~ajs (.*)/, 2);
|
||||
if(data.user == dbot.admin) {
|
||||
dbot.say(data.channel, eval(q[1]));
|
||||
if(dbot.admin.include(data.user) ) {
|
||||
var ret = eval(q[1]);
|
||||
if(ret != undefined) {
|
||||
dbot.say(data.channel, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -13,8 +13,6 @@ var modehate = function(dbot) {
|
||||
'on': 'MODE'
|
||||
};
|
||||
};
|
||||
~ajs dbot.instance.addListener('MODE', function(data) { if(data.channel == '#42' && data.raw[0].indexOf('Snow') != -1 && data.raw[0].indexOf('+o') != -1) { dbot.instance.send('MODE #42 -o Snow'); } }
|
||||
|
||||
|
||||
exports.fetch = function(dbot) {
|
||||
return modehate(dbot);
|
||||
|
@ -3,13 +3,12 @@ var puns = function(dbot) {
|
||||
|
||||
return {
|
||||
'listener': function(data) {
|
||||
if(data.user == 'reality') {
|
||||
dbot.instance.say(data.channel, dbot.db.quoteArrs['realityonce'].random());
|
||||
} else if(dbot.db.quoteArrs.hasOwnProperty(data.user.toLowerCase())) {
|
||||
dbot.say(data.channel, data.user + ': ' + dbot.db.quoteArrs[data.user.toLowerCase()].random());
|
||||
} else if(dbot.instance.inChannel(data.channel)) {
|
||||
dbot.instance.say('aisbot', '.karma ' + data.user);
|
||||
dbot.waitingForKarma = data.channel;
|
||||
if(dbot.moduleNames.include('quotes')) {
|
||||
if(dbot.db.quoteArrs.hasOwnProperty(data.user.toLowerCase())) {
|
||||
data.message = '~q ' + data.user.toLowerCase();
|
||||
var params = data.message.split(' ');
|
||||
dbot.commands[params[0]](data, params);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -2,7 +2,48 @@ var quotes = function(dbot) {
|
||||
var quotes = dbot.db.quoteArrs;
|
||||
var addStack = [];
|
||||
var rmAllowed = true;
|
||||
|
||||
|
||||
// Retrieve a random quote from a given category, interpolating any quote references (~~QUOTE CATEGORY~~) within it
|
||||
var interpolatedQuote = function(key, quoteTree) {
|
||||
if(quoteTree !== undefined && quoteTree.indexOf(key) != -1) {
|
||||
return '';
|
||||
} else if(quoteTree === undefined) {
|
||||
quoteTree = [];
|
||||
}
|
||||
|
||||
var quoteString = quotes[key].random();
|
||||
|
||||
// Parse quote interpolations
|
||||
var quoteRefs = quoteString.match(/~~([\d\w\s-]*)~~/g);
|
||||
var thisRef;
|
||||
|
||||
while(quoteRefs && (thisRef = quoteRefs.shift()) !== undefined) {
|
||||
var cleanRef = dbot.cleanNick(thisRef.replace(/^~~/,'').replace(/~~$/,'').trim());
|
||||
if (quotes.hasOwnProperty(cleanRef)) {
|
||||
quoteTree.push(key);
|
||||
quoteString = quoteString.replace("~~" + cleanRef + "~~",
|
||||
interpolatedQuote(cleanRef, quoteTree.slice()));
|
||||
quoteTree.pop();
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
var commands = {
|
||||
'~q': function(data, params) {
|
||||
var q = data.message.valMatch(/^~q ([\d\w\s-]*)/, 2);
|
||||
@ -10,7 +51,7 @@ var quotes = function(dbot) {
|
||||
q[1] = q[1].trim();
|
||||
key = q[1].toLowerCase();
|
||||
if(quotes.hasOwnProperty(key)) {
|
||||
dbot.say(data.channel, q[1] + ': ' + quotes[key].random());
|
||||
dbot.say(data.channel, q[1] + ': ' + interpolatedQuote(key));
|
||||
} else {
|
||||
dbot.say(data.channel, 'Nobody loves ' + q[1]);
|
||||
}
|
||||
@ -65,13 +106,13 @@ var quotes = function(dbot) {
|
||||
},
|
||||
|
||||
'~rmlast': function(data, params) {
|
||||
if(rmAllowed == true || data.user == dbot.admin) {
|
||||
if(rmAllowed == true || dbot.admin.include(data.user)) {
|
||||
var q = data.message.valMatch(/^~rmlast ([\d\w\s-]*)/, 2);
|
||||
if(q) {
|
||||
q[1] = q[1].trim()
|
||||
key = q[1].toLowerCase();
|
||||
if(quotes.hasOwnProperty(q[1])) {
|
||||
if(!dbot.db.locks.include(q[1]) || data.user == dbot.admin) {
|
||||
if(!dbot.db.locks.include(q[1]) || dbot.admin.include(data.user)) {
|
||||
var quote = quotes[key].pop();
|
||||
if(quotes[key].length === 0) {
|
||||
delete quotes[key];
|
||||
@ -104,7 +145,7 @@ var quotes = function(dbot) {
|
||||
},
|
||||
|
||||
'~rm': function(data, params) {
|
||||
if(rmAllowed == true || data.user == dbot.admin) {
|
||||
if(rmAllowed == true || dbot.admin.include(data.user)) {
|
||||
var q = data.message.valMatch(/^~rm ([\d\w\s-]*) (.+)$/, 3);
|
||||
if(q) {
|
||||
if(quotes.hasOwnProperty(q[1])) {
|
||||
@ -112,6 +153,9 @@ var quotes = function(dbot) {
|
||||
var index = quotes[q[1]].indexOf(q[2]);
|
||||
if(index != -1) {
|
||||
quotes[q[1]].splice(index, 1);
|
||||
if(quotes[q[1]].length === 0) {
|
||||
delete quotes[q[1]];
|
||||
}
|
||||
rmAllowed = false;
|
||||
dbot.say(data.channel, '\'' + q[2] + '\' removed from ' + q[1]);
|
||||
} else {
|
||||
@ -144,7 +188,6 @@ var quotes = function(dbot) {
|
||||
} else { // Give total quote count
|
||||
var totalQuoteCount = 0;
|
||||
for(var category in quotes) {
|
||||
console.log('adding ' + category.length);
|
||||
totalQuoteCount += category.length;
|
||||
}
|
||||
dbot.say(data.channel, 'There are ' + totalQuoteCount + ' quotes in total.');
|
||||
@ -152,7 +195,7 @@ var quotes = function(dbot) {
|
||||
},
|
||||
|
||||
'~qadd': function(data, params) {
|
||||
var q = data.message.valMatch(/^~qadd ([\d\w\s-]*)=(.+)$/, 3);
|
||||
var q = data.message.valMatch(/^~qadd ([\d\w\s-]+?)[ ]?=[ ]?(.+)$/, 3);
|
||||
if(q) {
|
||||
key = q[1].toLowerCase();
|
||||
if(!Object.isArray(quotes[key])) {
|
||||
@ -189,11 +232,11 @@ var quotes = function(dbot) {
|
||||
|
||||
'~rq': function(data, params) {
|
||||
var rQuote = Object.keys(quotes).random();
|
||||
dbot.say(data.channel, rQuote + ': ' + quotes[rQuote].random());
|
||||
dbot.say(data.channel, rQuote + ': ' + interpolatedQuote(rQuote));
|
||||
},
|
||||
|
||||
'~d': function(data, params) {
|
||||
dbot.say(data.channel, data.user + ': ' + dbot.db.quoteArrs['depressionbot'].random());
|
||||
dbot.say(data.channel, data.user + ': ' + interpolatedQuote(dbot.name));
|
||||
},
|
||||
|
||||
'~link': function(data, params) {
|
||||
@ -202,6 +245,23 @@ var quotes = function(dbot) {
|
||||
} else {
|
||||
dbot.say(data.channel, 'Link to "'+params[1]+'" - http://nc.no.de:443/quotes/'+params[1]);
|
||||
}
|
||||
},
|
||||
|
||||
'~qprune': function(data) {
|
||||
var pruned = []
|
||||
for(key in quotes) {
|
||||
if(quotes.hasOwnProperty(key)) {
|
||||
if(quotes[key].length == 0) {
|
||||
delete quotes[key];
|
||||
pruned.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pruned.length > 0) {
|
||||
dbot.say(data.channel, "Pruning empty quote categories: " + pruned.join(", "));
|
||||
} else {
|
||||
dbot.say(data.channel, "No empty quote categories. Commence incineration.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -227,6 +287,9 @@ var quotes = function(dbot) {
|
||||
dbot.db.bans['*'].include(data.user)) {
|
||||
dbot.say(data.channel, data.user + ' is banned from using this command. Commence incineration.');
|
||||
} else {
|
||||
if(!dbot.db.quoteArrs.hasOwnProperty('realityonce')) {
|
||||
dbot.db.quoteArrs['realityonce'] = [];
|
||||
}
|
||||
dbot.db.quoteArrs['realityonce'].push('reality ' + once[1] + '.');
|
||||
addStack.push('realityonce');
|
||||
rmAllowed = true;
|
||||
|
@ -18,26 +18,26 @@ var webInterface = function(dbot) {
|
||||
|
||||
// Lists the quote categories
|
||||
app.get('/quotes', function(req, res) {
|
||||
res.render('quotelist', { 'quotelist': Object.keys(dbot.db.quoteArrs) });
|
||||
res.render('quotelist', { 'name': dbot.name, 'quotelist': Object.keys(dbot.db.quoteArrs) });
|
||||
});
|
||||
|
||||
// Lists quotes in a category
|
||||
app.get('/quotes/:key', function(req, res) {
|
||||
var key = req.params.key.toLowerCase();
|
||||
if(dbot.db.quoteArrs.hasOwnProperty(key)) {
|
||||
res.render('quotes', { 'quotes': dbot.db.quoteArrs[key], locals: { 'url_regex': RegExp.prototype.url_regex() } });
|
||||
res.render('quotes', { 'name': dbot.name, 'quotes': dbot.db.quoteArrs[key], locals: { 'url_regex': RegExp.prototype.url_regex() } });
|
||||
} else {
|
||||
res.render('error', { 'message': 'No quotes under that key.' });
|
||||
res.render('error', { 'name': dbot.name, 'message': 'No quotes under that key.' });
|
||||
}
|
||||
});
|
||||
|
||||
// Load random quote category page
|
||||
app.get('/rq', function(req, res) {
|
||||
var rCategory = Object.keys(dbot.db.quoteArrs).random();
|
||||
res.render('quotes', { '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() } });
|
||||
});
|
||||
|
||||
app.listen(443);
|
||||
app.listen(dbot.webPort);
|
||||
|
||||
return {
|
||||
'onDestroy': function() {
|
||||
|
22
public/ytembed.js
Normal file
22
public/ytembed.js
Normal file
@ -0,0 +1,22 @@
|
||||
// let's fetch us some goddamn API
|
||||
var apiEmbed = document.createElement('script');
|
||||
apiEmbed.src = 'http://www.youtube.com/player_api';
|
||||
document.getElementsByTagName('script')[0].parentNode.insertBefore(apiEmbed, document.getElementsByTagName('script')[0]);
|
||||
|
||||
// this will be called by the player API when it's finished downloading
|
||||
function onYouTubePlayerAPIReady() {
|
||||
var youTubePlaceholders = document.getElementsByClassName('ytplaceholder');
|
||||
for(var i = 0; i < youTubePlaceholders.length; i++) {
|
||||
var videoURL = youTubePlaceholders[i].innerHTML;
|
||||
var videoIDMaybe = videoURL.match(/[?&]v=([A-Za-z0-9\-_]+)(?:[?&]|$)/);
|
||||
youTubePlaceholders[i].innerText = '';
|
||||
if(videoIDMaybe) {
|
||||
var ytVideoID = videoIDMaybe[1];
|
||||
var player = new YT.Player(youTubePlaceholders[i], {
|
||||
height: '203',
|
||||
width: '336',
|
||||
videoId: ytVideoID
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
93
run.js
93
run.js
@ -6,16 +6,50 @@ require('./snippets');
|
||||
var DBot = function(timers) {
|
||||
// Load external files
|
||||
this.config = JSON.parse(fs.readFileSync('config.json', 'utf-8'));
|
||||
this.db = JSON.parse(fs.readFileSync('db.json', 'utf-8'));
|
||||
this.db = null;
|
||||
var rawDB;
|
||||
try {
|
||||
var rawDB = fs.readFileSync('db.json', 'utf-8');
|
||||
} catch (e) {
|
||||
this.db = {}; // If no db file, make empty one
|
||||
}
|
||||
if(!this.db) { // If it wasn't empty
|
||||
this.db = JSON.parse(rawDB);
|
||||
}
|
||||
|
||||
// Repair any deficiencies in the DB; if this is a new DB, that's everything
|
||||
if(!this.db.hasOwnProperty("bans")) {
|
||||
this.db.bans = {};
|
||||
}
|
||||
if(!this.db.bans.hasOwnProperty("*")) {
|
||||
this.db.bans["*"] = [];
|
||||
}
|
||||
if(!this.db.hasOwnProperty("quoteArrs")) {
|
||||
this.db.quoteArrs = {};
|
||||
}
|
||||
if(!this.db.hasOwnProperty("kicks")) {
|
||||
this.db.kicks = {};
|
||||
}
|
||||
if(!this.db.hasOwnProperty("kickers")) {
|
||||
this.db.kickers = {};
|
||||
}
|
||||
if(!this.db.hasOwnProperty("modehate")) {
|
||||
this.db.modehate = [];
|
||||
}
|
||||
if(!this.db.hasOwnProperty("locks")) {
|
||||
this.db.locks = [];
|
||||
}
|
||||
|
||||
// Populate bot properties with config data
|
||||
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.nickserv = this.config.nickserv || 'zippy';
|
||||
this.server = this.config.server || 'elara.ivixor.net';
|
||||
this.port = this.config.port || 6667;
|
||||
this.moduleNames = this.config.modules || [ 'js', 'admin', 'kick', 'modehate', 'quotes', 'puns', 'spelling', 'web', 'youare' ];
|
||||
this.webPort = this.config.webPort || 443;
|
||||
this.moduleNames = this.config.modules || [ 'command', 'js', 'admin', 'kick', 'modehate', 'quotes', 'puns', 'spelling', 'web', 'youare' ];
|
||||
this.sessionData = {};
|
||||
|
||||
this.timers = timers.create();
|
||||
|
||||
@ -38,7 +72,7 @@ DBot.prototype.say = 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
|
||||
@ -62,6 +96,12 @@ DBot.prototype.reloadModules = function() {
|
||||
this.timers.clearTimers();
|
||||
this.save();
|
||||
|
||||
// Enforce having command. it can still be reloaded, but dbot _will not_
|
||||
// function without it, so not having it should be impossible
|
||||
if(!this.moduleNames.include("command")) {
|
||||
this.moduleNames.push("command");
|
||||
}
|
||||
|
||||
// Reload Javascript snippets
|
||||
var path = require.resolve('./snippets');
|
||||
delete require.cache[path];
|
||||
@ -97,51 +137,6 @@ DBot.prototype.reloadModules = function() {
|
||||
|
||||
return module;
|
||||
}.bind(this));
|
||||
|
||||
this.instance.addListener('PRIVMSG', function(data) {
|
||||
params = data.message.split(' ');
|
||||
if(data.channel == this.name) data.channel = data.user;
|
||||
|
||||
if(this.commands.hasOwnProperty(params[0])) {
|
||||
if((this.db.bans.hasOwnProperty(params[0]) &&
|
||||
this.db.bans[params[0]].include(data.user)) || this.db.bans['*'].include(data.user))
|
||||
this.say(data.channel, data.user +
|
||||
' is banned from using this command. Commence incineration.');
|
||||
else {
|
||||
this.commands[params[0]](data, params);
|
||||
this.save();
|
||||
}
|
||||
} else {
|
||||
var q = data.message.valMatch(/^~([\d\w\s-]*)/, 2);
|
||||
if(q) {
|
||||
if(this.db.bans['*'].include(data.user)) {
|
||||
this.say(data.channel, data.user +
|
||||
' is banned from using this command. Commence incineration.');
|
||||
} else {
|
||||
q[1] = q[1].trim();
|
||||
key = this.cleanNick(q[1])
|
||||
if(this.db.quoteArrs.hasOwnProperty(key)) {
|
||||
this.say(data.channel, q[1] + ': ' + this.db.quoteArrs[key].random());
|
||||
} else {
|
||||
// See if it's similar to anything
|
||||
var winnerDistance = Infinity;
|
||||
var winner = false;
|
||||
for(var commandName in this.commands) {
|
||||
var distance = String.prototype.distance(params[0], commandName);
|
||||
if(distance < winnerDistance) {
|
||||
winner = commandName;
|
||||
winnerDistance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
if(winnerDistance < 3) {
|
||||
this.say(data.channel, 'Did you mean ' + winner + '? Learn to type, hippie!');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
DBot.prototype.cleanNick = function(key) {
|
||||
|
@ -27,6 +27,14 @@ Array.prototype.include = function(value) {
|
||||
return false;
|
||||
};
|
||||
|
||||
Array.prototype.sum = function() {
|
||||
var sum = 0;
|
||||
for(var i=0;i<this.length;i++) {
|
||||
sum += (parseFloat(this[i]) || 0);
|
||||
}
|
||||
return sum;
|
||||
};
|
||||
|
||||
Array.prototype.allGroupings = function() {
|
||||
if (this.length == 0) {
|
||||
return []; /* short-circuit the empty-array case */
|
||||
|
8
timer.js
8
timer.js
@ -1,15 +1,23 @@
|
||||
var timers = function() {
|
||||
var timers = [];
|
||||
var timeouts = [];
|
||||
|
||||
return {
|
||||
'addTimer': function(interval, callback) { // Because who puts the callback first. Really.
|
||||
timers.push(setInterval(callback, interval));
|
||||
},
|
||||
|
||||
'addOnceTimer': function(delay, callback) { // Because who seriously puts the callback first here too?
|
||||
timeouts.push(setTimeout(callback, delay));
|
||||
},
|
||||
|
||||
'clearTimers': function() {
|
||||
for(var i;i<timers.length;i++) {
|
||||
clearInterval(timers[i]);
|
||||
}
|
||||
for(var i;i<timeouts.length;i++) {
|
||||
clearTimeout(timeouts[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -3,11 +3,11 @@ html(lang='en')
|
||||
head
|
||||
meta(charset='utf-8')
|
||||
link(rel='stylesheet', type='text/css', href='/styles.css')
|
||||
title Depressionbot web interface
|
||||
title #{name} web interface
|
||||
body
|
||||
div#page
|
||||
div#title
|
||||
a(href='/') Depressionbot web interface
|
||||
a(href='/') #{name} web interface
|
||||
div#main
|
||||
!{body}
|
||||
script(type="text/javascript", src="/script.js")
|
||||
|
@ -1,11 +1,19 @@
|
||||
ul#quotelist
|
||||
-var hasYouTubeVids=false
|
||||
-each quote in quotes
|
||||
-if(quote.match(locals.url_regex))
|
||||
li.quote
|
||||
a(href=quote)
|
||||
-if(quote.match(/(jpg|png|gif|jpeg|tiff)$/))
|
||||
-if(quote.match(/(jpg|png|gif|jpeg|tiff)$/))
|
||||
a(href=quote)
|
||||
img(src=quote)
|
||||
-else
|
||||
-else if(quote.match(/youtube.com\/watch/))
|
||||
-hasYouTubeVids = true
|
||||
span(class='ytplaceholder')
|
||||
=quote
|
||||
-else
|
||||
a(href=quote)
|
||||
=quote
|
||||
-else
|
||||
li.quote #{quote}
|
||||
-if(hasYouTubeVids)
|
||||
script(src='/ytembed.js')
|
||||
|
Loading…
Reference in New Issue
Block a user