3
0
mirror of https://github.com/reality/dbot.git synced 2025-08-03 07:37:22 +02:00

Compare commits

..

No commits in common. "master" and "v0.3.9" have entirely different histories.

270 changed files with 2890 additions and 12821 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
# Ignore the user config files # Ignore the user config files
config.json
db.json db.json
# ignore npm # ignore npm

11
.gitmodules vendored
View File

@ -1,6 +1,9 @@
[submodule "jsbot"] [submodule "jsbot"]
path = jsbot path = jsbot
url = git://github.com/reality/jsbot.git url = git://github.com/reality/jsbot.git
[submodule "modules/github"] [submodule "modules/github"]
path = modules/github path = modules/github
url = git://github.com/zuzak/dbot-github.git url = git://github.com/zuzak/dbot-github.git
[submodule "modules/stats"]
path = modules/stats
url = git@github.com:SamStudio8/dbot-stats.git

View File

@ -11,27 +11,18 @@ 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 Please don't judge me too harshly for this as I am, in fact, mildly allergic to
writing documentation. writing documentation.
## Getting Started Requirements:
To get started with DBot, you first need to decide on a database system to use. - Node JS
DBot uses the [databank](http://github.com/e14n/databank) library, and each - [JSBot](http://github.com/reality/JSBot "JSBot"), a Javascript library which
module can be configured to use any database driver databank supports in its handles the IRC protocol
respective config.json file. There is currently no default database driver - Underscore JS library
option. - Various modules have their own requirements also.
The default for all modules is the 'redis' driver, and you can simply install ### External Modules
the Redis server to get going.
Once you have that set up, you can install DBot's dependencies, configure and JSBot and externally developed modules can be imported by running the following
run the bot for the first time with the following command: commands in the cloned repository:
``` git submodule init
./install git submodule update
```
## Upgrading
If you have used a previous version of DBot, then you can migrate most data
using the [dbot-migrate](https://github.com/reality/dbot-migrate) module.
Instructions on how to run this are included in the repository - remember to
remove db.json after migration, otherwise the instance will be slow!

View File

@ -1,6 +1,5 @@
dbot version 0.5-dev depressionbot version 0.4-dev
this.db.search('releases', { 'name': 'jimbletron' }, function(result) { "RELEASE" });
"the database is a grilled cheese" "the database is a grilled cheese"
_.each(dbot.modules, function(module) { "RESCORE EVERYTHING" }); _.each(dbot.modules, function(module) { "RESCORE EVERYTHING" });
"He called his bot depressionbot, and that's when he was happy." "He called his bot depressionbot, and that's when he was happy."

View File

@ -15,13 +15,10 @@
"admins": [ "batman" ], "admins": [ "batman" ],
"moderators": [ "whatever" ], "moderators": [ "whatever" ],
"power_users": [], "power_users": [],
"moduleNames": [ "ignore", "admin", "command", "dice", "js", "kick", "quotes", "spelling", "users", "youare", "timers", "sstats", "link" ], "moduleNames": [ "ignore", "admin", "command", "dice", "js", "kick", "quotes", "spelling", "youare", "timers", "stats", "users", "link" ],
"language": "en", "language": "en",
"debugMode": false, "debugMode": false,
"debugLevel": 1, "debugLevel": 1,
"dbType": "redis",
"redisPort": 6379,
"timezone": "Europe/London",
"repoRoot": "https://github.com/reality/depressionbot/", "repoRoot": "https://github.com/reality/depressionbot/",
"version": "Depressionbot IRC bot 0.5-dev - Lovingly crafted by The DepressionBot Foundation (a charity arm of the Official Aberystwyth Open Source International Development League)." "version": "Depressionbot IRC bot 0.4-dev - Lovingly crafted by The DepressionBot Foundation (a charity arm of the Official Aberystwyth Open Source International Development League)."
} }

View File

@ -1,33 +0,0 @@
var databank = require('databank'),
Databank = databank.Databank,
DatabankObject = databank.DatabankObject,
_ = require('underscore')._;
/**
* Multiplex databank objects
*/
var DatabaseDriver = function(config) {
this.config = config;
this.databank = null;
};
/**
* Connect to or create a new DataBank
*/
DatabaseDriver.prototype.createDB = function(name, driver, schema, callback) {
var params = { 'schema': schema };
if(driver == 'redis' && _.has(this.config, 'redisPort')) params.port = this.config.redisPort;
if(driver == 'disk') params.dir = 'db';
this.databank = Databank.get(driver, params);
this.databank.connect({}, function(err) {
if(err) {
console.log('Didn\'t manage to connect to the data source - ' + err);
} else {
callback(this.databank);
}
}.bind(this));
};
exports.DatabaseDriver = DatabaseDriver;

48
install
View File

@ -1,48 +0,0 @@
#!/bin/bash
cat LICENCE
git submodule init
git submodule update
command -v node > /dev/null
if [[ $? -gt 0 ]]; then
echo 'node.js is not installed. Please install it before running install.sh.'
exit 1
fi
command -v npm > /dev/null
if [[ $? -gt 0 ]]; then
echo 'npm is not installed. Please install it before running install.sh'
exit 1
fi
npm install googlemaps humanize feedparser node-units tvdb method-override 500px process async wordnik node-uuid underscore request request-promise-native vm2 express moment-timezone moment jade databank databank-redis ent passport passport-local password-hash connect-flash
cd public/
wget https://github.com/twbs/bootstrap/releases/download/v3.3.2/bootstrap-3.3.2-dist.zip
unzip bootstrap-3.3.2-dist.zip
mv bootstrap-3.3.2-dist bootstrap
rm bootstrap-3.3.2-dist.zip
mkdir d3
cd d3
wget https://github.com/mbostock/d3/releases/download/v3.5.5/d3.zip
unzip d3.zip
rm d3.zip
cd ../..
if [ ! -f config.json ];
then
echo 'Creating configuration file...'
cp config.json.sample config.json
$EDITOR config.json # Open config file with EDITOR variable, but if not available:
if [[ $? != 0 ]]; then vim config.json; fi # Find the return code from previous command, if failed then use vim to edit.
fi
read -p "Setup complete. Run dbot now? [y/N]"
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
echo 'Okay. To run the bot, use "node run.js"'
exit
fi
node run.js

46
install.sh Executable file
View File

@ -0,0 +1,46 @@
#!/bin/bash
cat LICENCE
git submodule init
git submodule update
if [ ! -e /usr/bin/node ] && [ ! -e /usr/local/bin/node ];
then
echo 'node.js is not installed. Please install it before running install.sh.'
exit 1
fi
if [ ! -e /usr/bin/npm ] && [ ! -e /usr/local/bin/npm ];
then
echo 'npm is not installed. Please install it before running install.sh'
exit 1
fi
npm install wordnik ent underscore request sandbox express moment jade@0.25
cd public/
wget http://twitter.github.com/bootstrap/assets/bootstrap.zip
unzip bootstrap.zip
rm bootstrap.zip
mkdir d3
cd d3
wget http://d3js.org/d3.v3.zip
unzip d3.v3.zip
rm d3.v3.zip
cd ../..
if [ ! -f config.json ];
then
echo 'Creating configuration file...'
cp config.json.sample config.json
vim config.json
fi
read -p "Setup complete. Run depressionbot now? [y/N]"
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
echo 'Okay. To run the bot, use "node run.js"'
exit
fi
node run.js

2
jsbot

@ -1 +1 @@
Subproject commit 4e6af64655674ba1a331910f3ed35b935eaba147 Subproject commit 11cbb75b504fbb703450a2f8c938d5a81680109c

View File

@ -1,28 +0,0 @@
## FOO
bar.
### Description
This module provides a command which allows users to foobar.
### Dependencies
It has following dependencies:
+ [foo](link)
### config.json
foo
```
```
### Commands
#### ~foo [(bar]
Example:
+ ~foo bar
### TODO

View File

@ -1,4 +0,0 @@
{
"foo": true,
"foo": "bar"
}

View File

@ -1,39 +0,0 @@
/**
* Module Name: foo
* Description: bar.
* Requires: foo [bar]
*/
var _ = require('underscore')._,
bar = require('foo');//dependencies
var foo = function(dbot) { //name of module
this.ApiRoot = 'API_ROOT_HERE';
this.internalAPI = {
//code for internal api here
};
this.api = {
//code for api here
};
this.commands = {
//code for commands here
};
this.onLoad = function() {
//code for stuff to be done on load here
};
this.onDestroy = function() {
//stuff to be done on destroy here
};
}
};
exports.fetch = function(dbot) {
return new foo(dbot); //name of module
};

View File

@ -1,8 +0,0 @@
{
"foo": {
"en": "{output} bar"
},
"foo2": {
"en": "Something went wrong :( Example:'~foo bar'"
}
}

View File

@ -1,3 +0,0 @@
{
"~foo": "~foo [bar]"
}

View File

@ -26,15 +26,6 @@ channel, it will attempt to give the caller ops in the current channel.
Perform a git pull, and then execute the 'reload' command. Saves a lot of time Perform a git pull, and then execute the 'reload' command. Saves a lot of time
updating! updating!
#### version [module]
Shows the git version of the currently loaded revision of DBot. If module is
provided, it will attempt to get the revision of the module (this is only useful
for submodules).
#### status [module]
Show the recorded status for a given module, this is helpful for debugging
issues when loading or for checking if a module is loaded.
#### reload #### reload
Reload all of the modules currently in use by DBot. By using this, all module Reload all of the modules currently in use by DBot. By using this, all module
functionality should be reloadable and replaceable without having to restart the functionality should be reloadable and replaceable without having to restart the
@ -55,18 +46,12 @@ loaded by the standard DBot process.
Unload a currently loaded module. This removes the module, and then triggers a Unload a currently loaded module. This removes the module, and then triggers a
reload of all modules. reload of all modules.
#### setconfig [path] [value] #### ban [user] [command]
Set a config value at path to be a certain value persistently. For example, if Ban a user from using a command. Command may be replaced with '\*,' which will
you want to change the web module to listen on port 9001, you can run _setconfig ban a user from use of all commands. Users banned from all commands will still
web.webPort 9001_. be subject to module listeners.
#### pushconfig [path] [value] #### unban [user] [command]
Push a new value to an existing config array. For example, if you want to add Unban a user from using a given command. If a user was previously banned using
the user 'batman62' to the DBot moderators, you can run _pushconfig moderators the '\*' wildcard, they may also be unbanned from such by replacing command with
batman62_. an asterisk here as well.
#### showconfig [path]
Use this to explore and view the DBot configuration. If called without a path,
it will display the config keys in the root; if the path is a subkey, it will
show all config keys under that key. If you give it an actual key, it'll show you
the currently effective config value.

View File

@ -1,62 +1,12 @@
/** /**
* Module Name: Admin * Module Name: Admin
* Description: Set of commands which only one who is a DepressionBot * Description: Set of commands which only one who is a DepressionBot
* administrator can run. * administrator can run - as such, it has its own command execution listener.
*/ */
var fs = require('fs'), var fs = require('fs'),
_ = require('underscore')._; _ = require('underscore')._;
var admin = function(dbot) { var admin = function(dbot) {
this.internalAPI = {
'getCurrentConfig': function(configKey, callback) {
var configPath = dbot.config;
configKey = configKey.split('.');
for(var i=0;i<configKey.length;i++) {
if(_.has(configPath, configKey[i])) {
configPath = configPath[configKey[i]];
} else {
configPath = null;
break;
}
}
callback(configPath);
},
'setConfig': function(configKey, newOption, callback) {
var configPath = dbot.customConfig,
oldOption = null;
configKey = configKey.split('.');
for(var i=0;i<configKey.length-1;i++) {
if(!_.has(configPath, configKey[i])) {
configPath[configKey[i]] = {};
}
configPath = configPath[configKey[i]];
}
if(_.has(configPath, configKey[i])) {
oldOption = configPath[configKey[i]];
}
configPath[configKey[i]] = newOption;
this.internalAPI.saveConfig();
dbot.reloadModules();
callback(null, oldOption);
}.bind(this),
'saveConfig': function() {
var config = dbot.customConfig;
fs.writeFileSync('config.json', JSON.stringify(config, null, ' '));
}
};
this.onLoad = function() {
dbot.api.timers.addTimer(60000, function() {
dbot.save(function() {});
});
};
}; };
exports.fetch = function(dbot) { exports.fetch = function(dbot) {

View File

@ -1,12 +1,49 @@
var fs = require('fs'), var fs = require('fs'),
_ = require('underscore')._, _ = require('underscore')._,
sys = require('sys'), sys = require('sys'),
process = require('process'),
exec = require('child_process').exec; exec = require('child_process').exec;
var commands = function(dbot) { var commands = function(dbot) {
var noChangeConfig = [ 'servers', 'name', 'moduleNames' ]; var noChangeConfig = [ 'servers', 'name', 'moduleNames' ];
var getCurrentConfig = function(configKey) {
var defaultConfigPath = dbot.config;
var userConfigPath = dbot.db.config;
if(configKey) {
var configKey = configKey.split('.');
for(var i=0;i<configKey.length-1;i++) {
if(_.has(defaultConfigPath, configKey[i])) {
if(!_.has(userConfigPath, configKey[i])) {
userConfigPath[configKey[i]] = {};
}
userConfigPath = userConfigPath[configKey[i]];
defaultConfigPath = defaultConfigPath[configKey[i]];
} else {
return false;
}
}
}
var currentOption;
if(configKey && configKey.length != 1) {
configKey = _.last(configKey);
if(_.has(userConfigPath, configKey) && !_.isUndefined(userConfigPath[configKey])) {
currentOption = userConfigPath[configKey];
} else if(_.has(defaultConfigPath, configKey)) {
currentOption = defaultConfigPath[configKey];
}
} else {
currentOption = defaultConfigPath[configKey];
}
return {
'user': userConfigPath,
'default': defaultConfigPath,
'value': currentOption
};
};
var commands = { var commands = {
// Join a channel // Join a channel
'~join': function(event) { '~join': function(event) {
@ -41,23 +78,16 @@ var commands = function(dbot) {
dbot.instance.mode(event, channel, ' +o ' + event.user); dbot.instance.mode(event, channel, ' +o ' + event.user);
}, },
// Op via OperServ in order to work with channels dbot is not joined to, or joined to without having +o itself
'~forceopme': function(event) {
var channel = event.params[1];
if(!_.has(event.allChannels, channel)) {
channel = event.channel.name;
}
dbot.say('tripsit', 'OperServ', ' MODE ' + channel + ' +o ' + event.user);
},
// Do a git pull and reload // Do a git pull and reload
'~greload': function(event) { '~greload': function(event) {
exec("git pull", function (error, stdout, stderr) { exec("git pull", function (error, stdout, stderr) {
exec("git submodule update", function (error, stdout, stderr) { exec("git submodule update", function (error, stdout, stderr) {
event.reply(dbot.t('gpull')); event.reply(dbot.t('gpull'));
commands['~reload'](event); commands['~reload'](event);
commands['~version'](event); event.message = '~version';
event.action = 'PRIVMSG';
event.params = event.message.split(' ');
dbot.instance.emit(event);
}.bind(this)); }.bind(this));
}.bind(this)); }.bind(this));
}, },
@ -90,15 +120,9 @@ var commands = function(dbot) {
if(_.has(dbot.status, moduleName)) { if(_.has(dbot.status, moduleName)) {
var status = dbot.status[moduleName]; var status = dbot.status[moduleName];
if(status === true) { if(status === true) {
event.reply(dbot.t('status_good', { event.reply(dbot.t("status_good",{"module":moduleName, "reason": status}));
'module': moduleName,
'reason': status
}));
} else { } else {
event.reply(dbot.t('status_bad', { event.reply(dbot.t("status_bad",{"module":moduleName, "reason": status}));
'module': moduleName,
'reason': status
}));
} }
} else { } else {
event.reply(dbot.t("status_unloaded")); event.reply(dbot.t("status_unloaded"));
@ -109,9 +133,7 @@ var commands = function(dbot) {
'~reload': function(event) { '~reload': function(event) {
dbot.db = JSON.parse(fs.readFileSync('db.json', 'utf-8')); dbot.db = JSON.parse(fs.readFileSync('db.json', 'utf-8'));
dbot.reloadModules(); dbot.reloadModules();
process.nextTick(function() { event.reply(dbot.t('reload'));
event.reply(dbot.t('reload'));
});
}, },
// Say something in a channel // Say something in a channel
@ -128,21 +150,18 @@ var commands = function(dbot) {
'~load': function(event) { '~load': function(event) {
var moduleName = event.params[1]; var moduleName = event.params[1];
if(!_.include(dbot.config.moduleNames, moduleName)) { if(!_.include(dbot.config.moduleNames, moduleName)) {
dbot.customConfig.moduleNames.push(moduleName); dbot.config.moduleNames.push(moduleName);
this.internalAPI.saveConfig();
dbot.reloadModules(); dbot.reloadModules();
process.nextTick(function() { if(dbot.status[moduleName] === true) {
if(dbot.status[moduleName] === true) { event.reply(dbot.t('load_module', {'moduleName': moduleName}));
event.reply(dbot.t('load_module', { 'moduleName': moduleName })); } else {
} else { event.reply(dbot.t("load_failed",{"module": moduleName}));
event.reply(dbot.t('load_failed', { 'module': moduleName })); }
}
});
} else { } else {
if(moduleName == 'web') { if(moduleName == 'web') {
event.reply(dbot.t('already_loaded_web')); event.reply(dbot.t('already_loaded_web'));
} else { } else {
event.reply(dbot.t('already_loaded', { 'moduleName': moduleName })); event.reply(dbot.t('already_loaded', {'moduleName': moduleName}));
} }
} }
}, },
@ -157,170 +176,98 @@ var commands = function(dbot) {
var cacheKey = require.resolve(moduleDir + moduleName); var cacheKey = require.resolve(moduleDir + moduleName);
delete require.cache[cacheKey]; delete require.cache[cacheKey];
} catch(err) { } } catch(err) { }
dbot.config.moduleNames = _.without(dbot.config.moduleNames, moduleName);
dbot.customConfig.moduleNames = _.without(dbot.config.moduleNames, moduleName);
this.internalAPI.saveConfig();
dbot.reloadModules(); dbot.reloadModules();
process.nextTick(function() { event.reply(dbot.t('unload_module', {'moduleName': moduleName}));
event.reply(dbot.t('unload_module', { 'moduleName': moduleName }));
});
} else { } else {
event.reply(dbot.t('unload_error', { 'moduleName': moduleName })); event.reply(dbot.t('unload_error', {'moduleName': moduleName}));
} }
}, },
/*** Config options ***/ /*** Config options ***/
'~setconfig': function(event) { '~setconfig': function(event) {
var configPath = event.input[1], var configPathString = event.params[1],
newOption = event.input[2]; configKey = _.last(configPathString.split('.')),
newOption = event.params[2];
event.reply(event.input[1]); if(!_.include(noChangeConfig, configKey)) {
var configPath = getCurrentConfig(configPathString);
if(!_.include(noChangeConfig, configPath)) { if(configPath == false || _.isUndefined(configPath.value)) {
this.internalAPI.getCurrentConfig(configPath, function(config) { event.reply(dbot.t("no_config_key"));
if(config !== null) { return;
// Convert to boolean type if config item boolean }
if(_.isBoolean(config)) { var currentOption = configPath.value;
newOption = (newOption == "true");
}
// Convert to integer type is config item integer // Convert to boolean type if config item boolean
if(_.isNumber(config)) { if(_.isBoolean(currentOption)) {
newOption = parseInt(newOption); newOption = (newOption == "true");
} }
if(_.isArray(config)) { // Convert to integer type is config item integer
event.reply(dbot.t("config_array", { "alternate": "pushconfig" })); if(_.isNumber(currentOption)) {
} newOption = parseInt(newOption);
} else { }
event.reply(dbot.t("no_config_key", {'path': configPath}));
configPath = configPath.split('.');
if(_.has(dbot.config.modules, configPath[0])) {
configPath.splice(0, 0, 'modules');
event.input[1] = configPath.join('.');
commands['~setconfig'](event);
return;
} else {
event.reply(dbot.t('new_config_key', { 'key': configPath }));
}
}
this.internalAPI.setConfig(configPath, newOption, function(err) { if(_.isArray(currentOption)) {
event.reply(configPath + ": " + config + " -> " + newOption); event.reply(dbot.t("config_array",{"alternate": "pushconfig"}));
}); }
}.bind(this));
event.reply(configPathString + ": " + currentOption + " -> " + newOption);
configPath['user'][configKey] = newOption;
dbot.reloadModules();
} else { } else {
event.reply(dbot.t("config_lock")); event.reply(dbot.t("config_lock"));
} }
}, },
'~pushconfig': function(event) { '~pushconfig': function(event) {
var configPath = event.input[1], var configPathString = event.params[1],
newOption = event.input[2]; configKey = _.last(configPathString.split('.')),
newOption = event.params[2];
if(!_.include(noChangeConfig, configPath)) { if(!_.include(noChangeConfig, configKey)) {
this.internalAPI.getCurrentConfig(configPath, function(config) { var configPath = getCurrentConfig(configPathString);
if(config !== null) { if(configPath == false || _.isUndefined(configPath.value)) {
if(_.isArray(config)) { event.reply(dbot.t("no_config_key"));
event.reply(configPath + ": " + config + " << " + newOption); return;
config.push(newOption); }
this.internalAPI.setConfig(configPath, config, function(err) {}); var currentArray = configPath.value;
} else {
event.reply(dbot.t("config_array", { "alternate": "setconfig" }));
}
} else {
event.reply(dbot.t("no_config_key", { 'path': configPath }));
}
}.bind(this));
} else {
event.reply(dbot.t("config_lock"));
}
},
'~rmconfig': function(event) { if(!_.isArray(currentArray)) {
var configPath = event.input[1], event.reply(dbot.t("config_array",{"alternate": "setconfig"}));
rmOption = event.input[2]; return;
}
if(!_.include(noChangeConfig, configPath)) { event.reply(configPathString + ": " + currentArray + " << " + newOption);
this.internalAPI.getCurrentConfig(configPath, function(config) { currentArray.push(newOption);
if(config !== null) { dbot.reloadModules();
if(_.isArray(config)) {
event.reply(configPath + ": " + config + " - " + rmOption);
config = _.without(config, rmOption)
this.internalAPI.setConfig(configPath, config, function(err) {});
} else {
event.reply(dbot.t("config_array", { "alternate": "nope" }));
}
} else {
event.reply(dbot.t("no_config_key", { 'path': configPath }));
}
}.bind(this));
} else {
event.reply(dbot.t("config_lock"));
} }
}, },
'~showconfig': function(event) { '~showconfig': function(event) {
var configPath = event.params[1]; var configPathString = event.params[1];
if(configPath.indexOf('servers') != -1) { return false; } var configPath = getCurrentConfig(configPathString);
if(configPath) {
this.internalAPI.getCurrentConfig(configPath, function(config) {
if(config !== null) {
if(_.isArray(config)) {
event.reply(dbot.t("config_keys_location", {
"path": configPath,
"value": config
}));
} else if(_.isObject(config)) {
event.reply(dbot.t("config_keys_location", {
"path": configPath,
"value": _.keys(config)
}));
} else {
event.reply(dbot.t("config_keys_location", {
"path": configPath,
"value": config
}));
}
} else {
event.reply(dbot.t("no_config_key", {'path': configPath}));
configPath = configPath.split('.'); if(configPathString) {
if(_.has(dbot.config.modules, configPath[0])) { var configKey = _.last(configPathString.split('.'));
configPath.splice(0, 0, 'modules'); if(!configKey) {
} else { event.reply(dbot.t("no_config_path"));
configPath.pop(); return;
} }
event.params[1] = configPath.join('.'); if(_.isArray(configPath.value)) {
commands['~showconfig'](event); event.reply(configKey + ': ' + configPath.value);
} } else if(_.isObject(configPath.value)) {
}.bind(this)); event.reply(dbot.t("config_keys_location",{"path":configPathString,"value":Object.keys(configPath.value)}));
} else {
event.reply(configKey + ': ' + configPath.value);
}
} else { } else {
event.reply(dbot.t("config_keys_location", { event.reply(dbot.t("config_keys_location",{"path":"root","value":Object.keys(configPath['default'])}));
"path": "root",
"value": _.keys(dbot.config)
}));
} }
},
'~savemodules': function(event) {
fs.readFile('config.json', 'utf-8', function(err, config) {
config = JSON.parse(config);
config.moduleNames = _.keys(dbot.modules);
fs.writeFile('config.json', JSON.stringify(config, null, ' '), function() {
event.reply(dbot.t('modules_saved', { 'modules': _.keys(dbot.modules) }));
});
});
},
'~die': function(event) {
event.reply('BRB coconut hunting...');
setTimeout(3000, function() {
process.exit(0);
});
} }
}; };
@ -328,18 +275,11 @@ var commands = function(dbot) {
command.access = 'admin'; command.access = 'admin';
}); });
commands['~showconfig'].access = 'admin'; commands['~showconfig'].access = 'moderator';
commands['~join'].access = 'power_user'; commands['~join'].access = 'moderator';
commands['~part'].access = 'power_user'; commands['~part'].access = 'moderator';
commands['~opme'].access = 'moderator'; commands['~opme'].access = 'moderator';
commands['~forceopme'].access = 'power_user'; commands['~say'].access = 'moderator';
commands['~say'].access = 'power_user';
commands['~pushconfig'].access = 'moderator';
commands['~rmconfig'].access = 'moderator';
commands['~pushconfig'].regex = [/pushconfig ([^ ]+) ([^ ]+)/, 3];
commands['~rmconfig'].regex = [/rmconfig ([^ ]+) ([^ ]+)/, 3];
commands['~setconfig'].regex = [/setconfig ([^ ]+) ([^ ]+)/, 3];
return commands; return commands;
}; };

View File

@ -1,5 +1,5 @@
{ {
"ignorable": false, "ignorable": false,
"dbType": "redis", "dependencies": [ "command" ],
"dependencies": [ "command" ] "help": "http://github.com/reality/depressionbot/blob/master/modules/admin/README.md"
} }

View File

@ -5,9 +5,7 @@
"na'vi": "fpxäkìm {channel}(nemfa)", "na'vi": "fpxäkìm {channel}(nemfa)",
"cy": "Wedi ymuno {channel}", "cy": "Wedi ymuno {channel}",
"nl": "{channel} binnengekomen", "nl": "{channel} binnengekomen",
"de": "{channel} beigetreten", "de": "{channel} beigetreten"
"fr": "{channel} rejoint",
"it": "Aderito a {channel}"
}, },
"part": { "part": {
"en": "Left {channel}", "en": "Left {channel}",
@ -15,9 +13,7 @@
"na'vi": "Hum {channel}", "na'vi": "Hum {channel}",
"cy": "Wedi gadael {channel}", "cy": "Wedi gadael {channel}",
"nl": "{channel} verlaten", "nl": "{channel} verlaten",
"de": "{channel} verlassen", "de": "{channel} verlassen"
"fr": "{channel} quitté",
"it": "uscito da {channel}"
}, },
"gpull": { "gpull": {
"en": "Git pulled that shit.", "en": "Git pulled that shit.",
@ -25,9 +21,7 @@
"na'vi": "Gìtìl fì'uti stamarsìm.", "na'vi": "Gìtìl fì'uti stamarsìm.",
"cy": "Wedi tynnu git yr cach na i gyd", "cy": "Wedi tynnu git yr cach na i gyd",
"nl": "Git heeft die zooi binnengehaald.", "nl": "Git heeft die zooi binnengehaald.",
"de": "Git hat es gezogen", "de": "Git hat es gezogen"
"fr": "Git a pullé cette merde",
"it": "Git ha pullato questa coglionata"
}, },
"reload": { "reload": {
"en": "Reloaded that shit.", "en": "Reloaded that shit.",
@ -35,9 +29,7 @@
"na'vi": "Oel fìuti stìyeftxaw.", "na'vi": "Oel fìuti stìyeftxaw.",
"cy": "Ail-lwytho'r cach na", "cy": "Ail-lwytho'r cach na",
"nl": "Die zooi opnieuw geladen.", "nl": "Die zooi opnieuw geladen.",
"de": "Neu geladen", "de": "Neu geladen"
"fr": "Bordel rechargé",
"it": "Ricaricato questa puttanata"
}, },
"load_module": { "load_module": {
"en": "Loaded new module: {moduleName}", "en": "Loaded new module: {moduleName}",
@ -45,9 +37,7 @@
"na'vi": "Oel {moduleName}it amip stìyeftxaw.", "na'vi": "Oel {moduleName}it amip stìyeftxaw.",
"cy": "Wedi llwytho modiwl newydd: {moduleName}", "cy": "Wedi llwytho modiwl newydd: {moduleName}",
"nl": "Nieuwe module geladen: {moduleName}", "nl": "Nieuwe module geladen: {moduleName}",
"de": "Neues Modul geladen: {moduleName}", "de": "Neues Modul geladen: {moduleName}"
"fr": "Nouveau module chargé : {moduleName}",
"it": "Caricato nuovo modulo: {moduleName}"
}, },
"unload_module": { "unload_module": {
"en": "Turned off module: {moduleName}", "en": "Turned off module: {moduleName}",
@ -55,9 +45,7 @@
"na'vi": "Oel {moduleName} tswìya'.", "na'vi": "Oel {moduleName} tswìya'.",
"cy": "Wedi troi ffwrdd y modiwl: {moduleName}", "cy": "Wedi troi ffwrdd y modiwl: {moduleName}",
"nl": "Module uitgeschakeld: {moduleName}", "nl": "Module uitgeschakeld: {moduleName}",
"de": "Modul ausgeschaltet: {moduleName}", "de": "Modul ausgeschaltet: {moduleName}"
"fr": "Module déchargé : {moduleName}",
"it": "Inabilitato modulo: {moduleName}"
}, },
"unload_error": { "unload_error": {
"en": "{moduleName} isn't loaded. Idiot.", "en": "{moduleName} isn't loaded. Idiot.",
@ -65,9 +53,7 @@
"na'vi": "Oel {moduleName}it omum. Nga skxawng lu.", "na'vi": "Oel {moduleName}it omum. Nga skxawng lu.",
"cy": "Di {moduleName} ddim wedi llwytho. Twpsyn", "cy": "Di {moduleName} ddim wedi llwytho. Twpsyn",
"nl": "{moduleName} is niet geladen. Idioot.", "nl": "{moduleName} is niet geladen. Idioot.",
"de": "{moduleName} ist nicht geladen, du Idiot.", "de": "{moduleName} ist nicht geladen, du Idiot."
"fr": "{moduleName} n'est pas chargé. Idiot.",
"it": "{moduleName} non è caricato. Idiota"
}, },
"banned": { "banned": {
"en": "{user} banned from {command}", "en": "{user} banned from {command}",
@ -75,9 +61,7 @@
"na'vi": "{command}ìri {user} ke tung.", "na'vi": "{command}ìri {user} ke tung.",
"cy": "{user} wedi ei gohurio o {command}", "cy": "{user} wedi ei gohurio o {command}",
"nl": "{user} mag {command} niet meer gebruiken", "nl": "{user} mag {command} niet meer gebruiken",
"de": "{user} wurde von {command} gebannt", "de": "{user} wurde von {command} gebannt"
"fr": "{user} a été interdit d'utiliser {command}",
"it": "{user} bandito da {command}"
}, },
"unbanned": { "unbanned": {
"en": "{user} unbanned from {command}", "en": "{user} unbanned from {command}",
@ -85,9 +69,7 @@
"na'vi": "{command}ìri {user} tung set.", "na'vi": "{command}ìri {user} tung set.",
"cy": "{user} wedi ei dad-wahardd o {command}", "cy": "{user} wedi ei dad-wahardd o {command}",
"nl": "{user} mag {command} weer gebruiken", "nl": "{user} mag {command} weer gebruiken",
"de": "{user} wurde von {command} entbannt", "de": "{user} wurde von {command} entbannt"
"fr": "{user} peut de nouveau utiliser {command}",
"it": "{user} riammesso da {command}"
}, },
"unban_error": { "unban_error": {
"en": "{user} wasn't banned from that command, fool.", "en": "{user} wasn't banned from that command, fool.",
@ -95,9 +77,7 @@
"na'vi": "{user} fìtsu'oti tamung srekrr, nga skxawng lu.", "na'vi": "{user} fìtsu'oti tamung srekrr, nga skxawng lu.",
"cy": "Nid oedd {user} wedi ei wahardd o'r gorchymyn yna, twpsyn", "cy": "Nid oedd {user} wedi ei wahardd o'r gorchymyn yna, twpsyn",
"nl": "{user} mag dat commando sowieso al gebruiken, mafketel.", "nl": "{user} mag dat commando sowieso al gebruiken, mafketel.",
"de": "{user} wurde nicht von {command} gebannt, du Trottel", "de": "{user} wurde nicht von {command} gebannt, du Trottel"
"fr": "{user} n'a pas été interdit d'utiliser cette commande, imbécile.",
"it": "{user} non è stato bandito da utilizzare questo commando, imbecille."
}, },
"qlock": { "qlock": {
"en": "Locked quote category: {category}", "en": "Locked quote category: {category}",
@ -105,126 +85,84 @@
"na'vi": "{category}ìri oel 'upxareti fmoli", "na'vi": "{category}ìri oel 'upxareti fmoli",
"cy": "Categori wedi cloi: {category}", "cy": "Categori wedi cloi: {category}",
"nl": "Quote categorie vergrendeld: {category}", "nl": "Quote categorie vergrendeld: {category}",
"de": "Zitat-Kategorie geschlossen: {category}", "de": "Zitat-Kategorie geschlossen: {category}"
"fr": "Catégorie de citations verrouillée : {category}",
"it": "Categoria di citazione bloccata : {category}"
}, },
"already_in_channel": { "already_in_channel": {
"en": "I'm already in {channel}", "en": "I'm already in {channel}",
"na'vi": "Oel {channel}it tok li", "na'vi": "Oel {channel}it tok li",
"cy": "Rydw i eisoes yn {channel}", "cy": "Rydw i eisoes yn {channel}",
"nl": "Ik ben al in {channel}", "nl": "Ik ben al in {channel}",
"de": "Ich bin schon in {channel}", "de": "Ich bin schon in {channel}"
"fr": "Je suis déjà dans {channel}",
"it": "Sono già in {channel}"
}, },
"not_in_channel": { "not_in_channel": {
"en": "I'm not in {channel}", "en": "I'm not in {channel}",
"na'vi": "Oel {channel}it ke tok", "na'vi": "Oel {channel}it ke tok",
"cy": "Rydw i ddim yn {channel}", "cy": "Rydw i ddim yn {channel}",
"nl": "Ik ben niet aanwezig in {channel}", "nl": "Ik ben niet aanwezig in {channel}",
"de": "Ich bin noch nicht in {channel}", "de": "Ich bin noch nicht in {channel}"
"fr": "Je ne suis pas dans {channel}",
"it": "Non sono in {channel}"
}, },
"already_loaded_web": { "already_loaded_web": {
"en": "WHY CAN'T I LOAD ALL THIS WEB? (web already loaded)", "en": "WHY CAN'T I LOAD ALL THIS WEB? (web already loaded)",
"na'vi": "PELUN OEL KE TSUN OMUM FÌWETIT NÌWOTX (wetìri oe omum li)", "na'vi": "PELUN OEL KE TSUN OMUM FÌWETIT NÌWOTX (wetìri oe omum li)",
"cy": "PAM ALLA I DDIM YN LWYTHO POB Y WE? (We eisoes yn lwytho)", "cy": "PAM ALLA I DDIM YN LWYTHO POB Y WE? (We eisoes yn lwytho)",
"nl": "AL DIT WEB WORDT ME TOCH EEN BEETJE TE VEEL! (web is al geladen)", "nl": "AL DIT WEB WORDT ME TOCH EEN BEETJE TE VEEL! (web is al geladen)",
"de": "WARUM KANN DAS NICHT GELADEN WERDEN? (bereits geladen)", "de": "WARUM KANN DAS NICHT GELADEN WERDEN? (bereits geladen)"
"fr": "POURQUOI EST-CE QUE JE PEUX PAS CHARGER TOUT CE WEB? (web déjà chargé)",
"it": "PERCHÉ NON POSSO CARICARE TUTTE QUESTO WEB? (web già caricato)"
}, },
"already_loaded": { "already_loaded": {
"en": "{moduleName} is already loaded.", "en": "{moduleName} is already loaded.",
"na'vi": "Oel omum teri {moduleName}it li.", "na'vi": "Oel omum teri {moduleName}it li.",
"cy": "{moduleName} eisoes yn lwytho", "cy": "{moduleName} eisoes yn lwytho",
"nl": "{moduleName} is al geladen.", "nl": "{moduleName} is al geladen.",
"de": "{moduleName} ist bereits geladen.", "de": "{moduleName} ist bereits geladen."
"fr": "{moduleName} est déjà chargé.",
"it": "{moduleName} già caricato."
}, },
"no_version": { "no_version": {
"en": "No version information or queried module not loaded.", "en": "No version information or queried module not loaded.",
"cy": "Dim gwybodaeth fersiwn neu modiwl holodd dim yn lwytho", "cy": "Dim gwybodaeth fersiwn neu modiwl holodd dim yn lwytho",
"de": "Keine Informationen verfügbar oder gewünschtes Modul wurde noch nicht geladen.", "de": "Keine Informationen verfügbar oder gewünschtes Modul wurde noch nicht geladen."
"fr": "Aucune information de version ou module demandé non chargé.",
"it": "Informazione sulla versione non è disponibile o modulo richiesto non ancora caricato"
}, },
"status_good": { "status_good": {
"en": "{module} status: Shit looks good", "en": "{module} status: Shit looks good",
"cy": "{module} statws: Cachu yn edrych yn dda", "cy": "{module} statws: Cachu yn edrych yn dda",
"de": "Sieht gut aus", "de": "Sieht gut aus"
"fr": "Statut de {module}: Cette merde tourne bien",
"it": "Stato di {modulo}: Funky gallo come sono bello stamattina"
}, },
"status_bad": { "status_bad": {
"en": "{module} status: Failed to load: {reason}", "en": "{module} status: Failed to load: {reason}",
"cy": "{module} statws: Methu i lwytho: {reason}", "cy": "{module} statws: Methu i lwytho: {reason}",
"de": "{module} Status: Konnte nicht geladen werden: {reason}", "de": "{module} Status: Konnte nicht geladen werden: {reason}"
"fr": "Statut de {module}: échec de chargement : {reason}",
"it": "Stato di {module}: Caricamento fallito: {reason}"
}, },
"status_unloaded": { "status_unloaded": {
"en": "Either that module wasn't on the roster or shit is totally fucked.", "en": "Either that module wasn't on the roster or shit is totally fucked.",
"cy": "Naill ai heb fod modiwl oedd ar y rhestr, neu cachu yn gwbl torrodd", "cy": "Naill ai heb fod modiwl oedd ar y rhestr, neu cachu yn gwbl torrodd",
"de": "Entweder ist das Modul nicht auf der Liste oder die Kacke ist am dampfen", "de": "Entweder ist das Modul nicht auf der Liste oder die Kacke ist am dampfen"
"fr": "Soit ce module n'est pas sur la liste, soit tout est complètement niqué",
"it": "O questo modulo non è sulla lista, o sono cazzi amari"
}, },
"load_failed": { "load_failed": {
"en": "Failed to load {module}. See 'status {module}'.", "en": "Failed to load {module}. See 'status {module}'.",
"cy": "Methu i lwytho {module}. Gwelwch 'status {module}'.", "cy": "Methu i lwytho {module}. Gwelwch 'status {module}'.",
"de": "Konnte {module} nicht laden. Siehe 'status {module}'.", "de": "Konnte {module} nicht laden. Siehe 'status {module}'."
"fr": "Echec du chargement de {module}. Voir 'status {module}'.",
"it": "Caricamento di {module} non riuscito. Vedi 'stato {module}'."
}, },
"no_config_key": { "no_config_key": {
"en": "{path} doesn't exist bro", "en": "Config key doesn't exist bro",
"cy": "{path} cyfluniad yn bodoli, fy mrawd", "cy": "Nid yw allwedd cyfluniad yn bodoli, fy mrawd",
"de": "{path} existiert nicht, Bruder", "de": "Einstellung existiert nicht, Bruder"
"fr": "{path} n'existe pas, fréro",
"it": "{path} non esiste, fratello"
}, },
"config_array": { "config_array": {
"en": "Config option is an array. Try '{alternate}'.", "en": "Config option is an array. Try '{alternate}'.",
"cy": "Opsiwn cyfluniad ydy'r amrywiaeth. Rhowch gynnig ar '{alternate}'.", "cy": "Opsiwn cyfluniad ydy'r amrywiaeth. Rhowch gynnig ar '{alternate}'.",
"de": "Einstellung ist ein Array, probiere '{alternate}' aus.", "de": "Einstellung ist ein Array, probiere '{alternate}' aus."
"fr": "L'option de configuration est un array. Essaye '{alternate}'.",
"it": "L'opzione di configurazione è un array. Prova '{alternate}'."
}, },
"config_lock": { "config_lock": {
"en": "This config option cannot be altered while the bot is running.", "en": "This config option cannot be altered while the bot is running.",
"cy": "Ni all yr opsiwn cyfluniad yn cael ei newid tra bod y bot yn rhedeg.", "cy": "Ni all yr opsiwn cyfluniad yn cael ei newid tra bod y bot yn rhedeg.",
"de": "Diese Option kann während der Benutzung des Bots nicht verändert werden", "de": "Diese Option kann während der Benutzung des Bots nicht verändert werden"
"fr": "Cette option de configuration ne peut pas être changée pendant que le bot est activé.",
"it": "Questa opzione di configurazione non può essere alterata mentre il bot è attivo."
}, },
"no_config_path": { "no_config_path": {
"en": "Config path doesn't exist bro", "en": "Config path doesn't exist bro",
"cy": "Nid yw llwybr cyfluniad yn bodoli, fy mrawd", "cy": "Nid yw llwybr cyfluniad yn bodoli, fy mrawd",
"de": "Konfigurationspfad nicht vorhanden, Bruder", "de": "Konfigurationspfad nicht vorhanden, Bruder"
"fr": "Le chemin de configuration n'existe pas, fréro",
"it": "Percorso di configurazione non esiste, fratello"
},
"new_config_key": {
"en": "Warning: Creating new config key: {key}.",
"fr": "Attention : création d'une nouvelle clé de configuration : {key}.",
"it": "Attenzione : Creazione di una nuova chiave di configurazione: {key}.",
"de": "Achtung: Neuer Konfigurationsschlüssel erstellt: {key}."
}, },
"config_keys_location": { "config_keys_location": {
"en": "Config keys in {path}: {value}", "en": "Config keys in {path}: {value}",
"cy": "Allweddi cyfluniad yn {path}: {value}", "cy": "Allweddi cyfluniad yn {path}: {value}",
"de": "Die Konfiguration in {path}: {value}", "de": "Die Konfiguration in {path}: {value}"
"fr": "Clés de configuration dans {path}: {value}",
"it": "Chiave di configurazione in {path}: {value}"
},
"modules_saved": {
"en": "Currently loaded modules now default: {modules}",
"fr": "Les modules actuellement chargés sont maintenant chargés par défaut : {modules}",
"it": "I moduli attualmente caricati sono adesso predefiniti: {modules}",
"de": "Die derzeit geladenen Module sind nun der Standart: {modules}"
} }
} }

View File

@ -1,38 +0,0 @@
/**
* Name: Announce
* Description: Announce things every now and again
*/
var _ = require('underscore')._;
var announce = function(dbot) {
this.announces = dbot.config.modules.announce.announces;
this.lineCount = 0;
this.lastAnnounce = {};
_.each(dbot.config.servers, function(v, k) {
this.lastAnnounce[k] = {};
_.each(this.announces[k], function(announce, channel) {
this.lastAnnounce[k][channel] = announce.distance;
}, this)
}, this);
this.listener = function(event) {
if(_.has(this.lastAnnounce[event.server], event.channel)) {
this.lastAnnounce[event.server][event.channel]--;
if(this.lastAnnounce[event.server][event.channel] == 0) {
var announce = this.config.announces[event.server][event.channel];
this.lastAnnounce[event.server][event.channel] = announce.distance;
dbot.api.quotes.getQuote(announce.category, function(quote) {
if(quote) {
dbot.say(event.server, event.channel, quote);
}
});
}
}
}.bind(this);
this.on = 'PRIVMSG';
};
exports.fetch = function(dbot) {
return new announce(dbot);
};

View File

@ -1,10 +0,0 @@
{
"announces": {
"aberwiki": {
"#test": {
"category": "test",
"distance": 1
}
}
}
}

View File

@ -51,9 +51,6 @@ var api = function(dbot) {
if(callbackIndex != -1) { if(callbackIndex != -1) {
args[callbackIndex] = function() { args[callbackIndex] = function() {
body.data = Array.prototype.slice.call(arguments, 0); body.data = Array.prototype.slice.call(arguments, 0);
if(_.isObject(body.data[0]) && _.has(body.data[0], 'err')) {
body.err = body.data[0].err;
}
res.json(body); res.json(body);
}; };
func.apply(null, args); func.apply(null, args);

View File

@ -1,16 +0,0 @@
var april = function(dbot) {
this.listener = function(event) {
var match = event.message.match(/^i'?( a)?m (an? )?([^ ]+)/i);
if(match) {
dbot.say(event.server, 'operserv', 'svsnick ' + event.user + ' ' + match[3]);
setTimeout(function() {
event.reply('Hi ' + match[3] + ', I\'m ' + dbot.config.name + '!');
}, 1000);
}
}
this.on = 'PRIVMSG';
};
exports.fetch = function(dbot) {
return new april(dbot);
};

View File

@ -1,157 +0,0 @@
/**
* Module Name: atheme
* Description: atheme mode references & retrieve channel flags
*/
var _ = require('underscore')._,
async = require('async');
var atheme = function(dbot) {
this.flagStack = {};
this.hostStack = {};
this.api = {
'getChannelFlags': function(server, channel, callback) {
if(!_.has(this.flagStack, server)) this.flagStack[server] = {};
if(_.has(this.flagStack[server], channel)) { // Already an active flag call
this.flagStack[server][channel].callbacks.push(callback);
} else {
this.flagStack[server][channel] = {
'flags': {},
'callbacks': [ callback ],
'timeout': null,
'working': false
};
}
dbot.say(server, 'chanserv', 'FLAGS ' + channel);
this.flagStack[server][channel].timeout = setTimeout(function() { // Delete callback if no response
if(_.has(this.flagStack[server], channel) && this.flagStack[server][channel].working == false) {
_.each(this.flagStack[server][channel].callbacks, function(callback) {
callback(true, null);
});
delete this.flagStack[server][channel];
}
}.bind(this), 20000);
},
'getVHosts': function(server, mask, callback) {
if(!_.has(this.hostStack, server)) this.hostStack[server] = {};
if(_.has(this.hostStack[server], mask)) { // Already an active host call
this.hostStack[server][channel].callbacks.push(callback);
} else {
this.hostStack[server][mask] = {
'users': [],
'callbacks': [ callback ],
'timeout': null
};
}
dbot.say(server, 'hostserv', 'LISTVHOST ' + mask);
this.hostStack[server][mask].timeout = setTimeout(function() { // Delete callback if no response
if(_.has(this.hostStack[server], mask)) {
_.each(this.hostStack[server][mask].callbacks, function(callback) {
callback(true, null);
});
delete this.hostStack[server][mask];
}
}.bind(this), 5000);
}
};
this.commands = {
'~chanserv': function(event) {
if(_.has(this.config.chanserv, event.input[1])) {
event.reply('ChanServ flag ' + event.input[1] + ': ' + this.config.chanserv[event.input[1]]);
} else {
event.reply('I don\'t know anything about ' + event.input[1]);
}
},
'~chanmode': function(event) {
if(_.has(this.config.chanmodes, event.input[1])) {
event.reply('Channel Mode ' + event.input[1] + ': ' + this.config.chanmodes[event.input[1]]);
} else {
event.reply('I don\'t know anything about ' + event.input[1]);
}
}
};
this.commands['~chanserv'].regex = [/^chanserv (\+.)/, 2];
this.commands['~chanmode'].regex = [/^chanmode (\+.)/, 2];
this.listener = function(event) {
if(event.action === 'NOTICE') {
if(event.user === 'ChanServ') {
var flags = event.params.match(/(\d+)\s+([^ ]+)\s+(\+\w+)\s+\((\#[\w\.]+)\)/),
end = event.params.match(/end of \u0002(\#[\w\.]+)\u0002 flags listing/i);
if(flags && _.has(this.flagStack[event.server], flags[4])) {
this.flagStack[event.server][flags[4]].flags[flags[2]] = flags[3];
} else if(end) {
if(_.has(this.flagStack[event.server], end[1])) {
this.flagStack[event.server][end[1]].working = true;
// Parse wildcard hostmasks to nicks
var allFlags = this.flagStack[event.server][end[1]].flags,
hostMasks = {};
_.each(allFlags, function(f, u) { // TODO: combine to one loop
if(u.indexOf('*!*@') !== -1) {
hostMasks[u] = f;
delete allFlags[u];
}
});
async.each(_.keys(hostMasks), function(hostMask, done) {
this.api.getVHosts(event.server, hostMask.split('@')[1], function(err, users) {
_.each(users, function(user) {
allFlags[user] = hostMasks[hostMask];
});
done();
});
}.bind(this), function() {
_.each(this.flagStack[event.server][end[1]].callbacks, function(callback) {
callback(null, this.flagStack[event.server][end[1]].flags);
}.bind(this));
clearTimeout(this.flagStack[event.server][end[1]].timeout);
delete this.flagStack[event.server][end[1]];
}.bind(this));
}
}
} else if(event.user === 'HostServ') {
_.each(this.hostStack[event.server], function(el, mask) {
if(event.params.match(mask)) {
var user = event.params.match(/- ([^ ]+)/),
end = event.params.match(/matches for pattern/);
if(user) {
this.hostStack[event.server][mask].users.push(user[1]);
} else if(end) {
_.each(this.hostStack[event.server][mask].callbacks, function(callback) {
callback(null, this.hostStack[event.server][mask].users);
}, this);
clearTimeout(this.hostStack[event.server][mask].timeout);
delete this.hostStack[event.server][mask];
}
}
}, this);
}
} else { // PRIVMSG
console.log(event.message);
var akill = event.message.match(/([^ ]+) AKILL:ADD: ([^ ]+) \(reason: (.+)(\) )\(duration: ([^,)]+)/);
if(event.channel == '#services' && akill) {
console.log(akill);
var channel = dbot.config.servers[event.server].admin_channel;
dbot.api.users.getUser(akill[1] + '.' + event.server, function(err, user) {
dbot.api.report.notify('ban', 'tripsit', user, channel, dbot.t('akill', {
'host': akill[2],
'reason': akill[3],
'duration': akill[5]
}));
});
}
}
}.bind(this);
this.on = ['NOTICE', 'PRIVMSG'];
};
exports.fetch = function(dbot) {
return new atheme(dbot);
};

View File

@ -1,50 +0,0 @@
{
"chanserv": {
"+v": "Enables use of the voice/devoice commands.",
"+V": "Enables automatic voice.",
"+h": "Enables use of the halfop/dehalfop commands.",
"+H": "Enables automatic halfop.",
"+o": "Enables use of the op/deop commands.",
"+O": "Enables automatic op.",
"+a": "Enables use of the protect/deprotect commands.",
"+q": "Enables use of the owner/deowner commands.",
"+s": "Enables use of the set command.",
"+i": "Enables use of the invite and getkey commands.",
"+r": "Enables use of the kick, kickban, ban and unban commands.",
"+r": "Enables use of the ban and unban commands.",
"+r": "Enables use of the unban command.",
"+R": "Enables use of the recover and clear commands.",
"+f": "Enables modification of channel access lists.",
"+t": "Enables use of the topic and topicappend commands.",
"+A": "Enables viewing of channel access lists.",
"+S": "Marks the user as a successor.",
"+F": "Grants full founder access.",
"+b": "Enables automatic kickban."
},
"chanmodes": {
"+b": "channel ban",
"+c": "colour filter",
"+e": "ban exemption",
"+f": "channel forwarding",
"+F": "allow anybody to forward to this",
"+g": "allow anybody to invite",
"+i": "invite only",
"+I": "invite exception (invex)",
"+j": "join throttling",
"+k": "key (channel password)",
"+l": "channel member limit",
"+L": "large ban list",
"+m": "moderated",
"+n": "no external messages",
"+o": "channel operator",
"+p": "paranoid channel",
"+P": "permanent channel",
"+q": "quiet",
"+Q": "block forwarded users",
"+r": "block unidentified",
"+s": "secret channel",
"+t": "topic limit",
"+v": "voice",
"+z": "reduced moderation"
}
}

View File

@ -1,5 +0,0 @@
{
"akill": {
"en": "{host} has been AKilled for {duration} due to \"{reason}\""
}
}

View File

@ -21,17 +21,6 @@ Command flow:
This is the only module which is force loaded, even if it's not specified in This is the only module which is force loaded, even if it's not specified in
the configuration file. the configuration file.
### Config
#### useNickserv: false
Use the nickserv module to ensure a user is logged into their account before
running any elevated commands. Note you will still have to load and configure
the nickserv module yourself.
#### accessOutput: false
Show a message to a user if they attempt to run a command they don't have the
access level for.
### Commands ### Commands
#### ~usage [command] #### ~usage [command]

View File

@ -2,52 +2,64 @@ var _ = require('underscore')._;
var api = function(dbot) { var api = function(dbot) {
return { return {
'isBanned': function(user, command) {
var banned = false;
if(_.has(dbot.db.bans, user)) {
if(_.include(dbot.db.bans[user], command) ||
_.include(dbot.db.bans[user], dbot.commands[command].module) ||
_.include(dbot.db.bans[user], '*')) {
banned = true;
}
}
return banned;
},
/** /**
* Does the user have the correct access level to use the command? * Does the user have the correct access level to use the command?
*/ */
'hasAccess': function(event, command, callback) { 'hasAccess': function(server, user, command, callback) {
var accessNeeded = dbot.commands[command].access, var accessNeeded = dbot.commands[command].access;
allowedNicks,
user = event.rUser;
if(_.isUndefined(accessNeeded) || accessNeeded == null) { if(accessNeeded == 'admin' || accessNeeded == 'moderator' || accessNeeded == 'power_user') {
return callback(true); var allowedNicks = dbot.config.admins;
} else if(!_.isFunction(accessNeeded)) { if(accessNeeded == 'moderator') allowedNicks = _.union(allowedNicks, dbot.config.moderators);
if(_.has(dbot.access, accessNeeded)) { if(accessNeeded == 'power_user') allowedNicks = _.union(allowedNicks, dbot.config.power_users);
accessNeeded = dbot.access[accessNeeded];
if(!_.include(allowedNicks, user)) {
callback(false);
} else { } else {
return callback(true); if(_.has(dbot.modules, 'nickserv') && this.config.useNickserv == true) {
dbot.api.nickserv.auth(server, user, function(result) {
callback(result);
});
} else {
callback(true);
}
} }
}
allowedNicks = accessNeeded(event);
if(!_.include(allowedNicks, user.primaryNick) && !_.include(allowedNicks, user.currentNick)) {
callback(false);
} else { } else {
if(_.has(dbot.modules, 'nickserv') && this.config.useNickserv == true) { callback(true);
dbot.api.nickserv.auth(user.server, user.currentNick, function(result, primary) {
if(result == true && primary == user.primaryNick) {
callback(true);
} else {
callback(false);
}
});
} else {
callback(true);
}
} }
}, },
/**
* Is item (user or channel) ignoring command?
*/
'isIgnoring': function(item, command) {
var module = dbot.commands[command].module;
return (_.has(dbot.db.ignores, item) &&
(_.include(dbot.db.ignores[item], module) ||
_.include(dbot.db.ignores[item], '*')));
},
/** /**
* Apply Regex to event message, store result. Return false if it doesn't * Apply Regex to event message, store result. Return false if it doesn't
* apply. * apply.
*/ */
'applyRegex': function(commandName, event) { 'applyRegex': function(commandName, event) {
var applies = false; var applies = false;
event.message = event.message.substring(1);
if(_.has(dbot.commands[commandName], 'regex')) { if(_.has(dbot.commands[commandName], 'regex')) {
var cRegex = dbot.commands[commandName].regex; var cRegex = dbot.commands[commandName].regex;
if(_.isArray(cRegex) && cRegex.length === 2) { if(_.isArray(cRegex) && cRegex.length == 2) {
var q = event.message.valMatch(cRegex[0], cRegex[1]); var q = event.message.valMatch(cRegex[0], cRegex[1]);
if(q) { if(q) {
applies = true; applies = true;
@ -64,6 +76,16 @@ var api = function(dbot) {
applies = true; applies = true;
} }
return applies; return applies;
},
'addHook': function(command, callback) {
console.log('adding hook');
if(_.has(dbot.commands, command)) {
if(!_.has(dbot.commands[command], 'hooks')) {
dbot.commands[command].hooks = [];
}
dbot.commands[command].hooks.push(callback);
}
} }
}; };
}; };

View File

@ -4,158 +4,70 @@
* command and then runs that command, given the user isn't banned from or * command and then runs that command, given the user isn't banned from or
* ignoring that command. * ignoring that command.
*/ */
var _ = require('underscore')._, var _ = require('underscore')._;
cDomain = require('domain').create();
var command = function(dbot) { var command = function(dbot) {
this.dbot = dbot;
/** /**
* Run the appropriate command given the input. * Run the appropriate command given the input.
*/ */
this.listener = function(event) { this.listener = function(event) {
var commandName = event.params[0]; var commandName = event.params[0];
if(commandName.charAt(0) != this.config.commandPrefix || this.config.passiveMode == true) { if(!_.has(dbot.commands, commandName)) {
return; if(_.has(dbot.modules, 'quotes')) {
commandName = '~';
} else {
return;
}
} }
commandName = commandName.substring(1);
this.api.hasAccess(event, commandName, function(hasAccess) { if(this.api.isBanned(event.user, commandName)) {
dbot.api.ignore.isUserIgnoring(event.rUser, commandName, function(isIgnoring) { event.reply(dbot.t('command_ban', {'user': event.user}));
dbot.api.ignore.isUserBanned(event.rUser, commandName, function(isBanned) { } else {
this.api.hasAccess(event.server, event.user, commandName, function(result) {
if(isBanned) { if(result) {
if(this.config.banOutput && commandName != this.config.commandPrefix) { if(!this.api.isIgnoring(event.user, commandName) &&
event.reply(dbot.t('command_ban', {'user': event.user})); !this.api.isIgnoring(event.channel, commandName) &&
} dbot.commands[commandName].disabled !== true) {
} else if(!hasAccess) { if(this.api.applyRegex(commandName, event)) {
if(this.config.accessOutput) { try {
event.reply(dbot.t('access_denied', { 'user': event.user })); var command = dbot.commands[commandName];
} var results = command.apply(dbot.modules[command.module], [event]);
} else if(!isIgnoring && _.has(dbot.commands, commandName) && !dbot.commands[commandName].disabled) { if(_.has(command, 'hooks') && results !== false) {
if(!_.has(dbot.commands, commandName)) { _.each(command['hooks'], function(hook) {
if(_.has(dbot.modules, 'quotes')) { hook.apply(hook.module, _.values(results));
var key = event.message.substring(1); }, this);
dbot.api.quotes.getInterpolatedQuote(event.server,
event.channel.name, event.user, key, function(quote) {
if(quote) {
event.reply(key + ': ' + quote);
} else if(_.has(dbot.modules, 'spelling')) {
var commands = _.keys(dbot.commands),
winner = false,
closestMatch = Infinity;
_.each(commands, function(command) {
var distance = dbot.api.spelling.distance(commandName, command);
if(distance < closestMatch) {
closestMatch = distance;
winner = command;
}
});
if(closestMatch < 1) {
event.reply(commandName + ' not found. Did you mean ' + winner + '?');
return;
} else if(_.has(dbot.modules, 'quotes')) {
dbot.api.link.udLookup(key, function(word, definition) {
if(word) {
event.reply(key + '[UD]: ' + definition);
} else {
event.reply(dbot.t('category_not_found', { 'category': key }));
}
});
} else {
return;
}
} }
}); } catch(err) {
return; if(dbot.config.debugMode == true) {
} else { var stack = err.stack.split('\n').slice(1, dbot.config.debugLevel + 1);
return;
}
}
if(this.api.applyRegex(commandName, event)) { event.reply('- Error in ' + commandName + ':');
try { event.reply('- Message: ' + err);
cDomain.run(function() {
var command = dbot.commands[commandName], _.each(stack, function(stackLine, index) {
results; event.reply('- Stack[' + index + ']: ' +
if(_.has(command, 'resolver')) { stackLine.trim());
event.res = [];
command.resolver(event, function(err) {
if(!err) {
results = command.apply(dbot.modules[command.module], [event]);
}
}); });
} else {
results = command.apply(dbot.modules[command.module], [event]);
} }
});
} catch(err) {
if(dbot.config.debugMode == true) {
var stack = err.stack.split('\n').slice(1, dbot.config.debugLevel + 1);
event.reply('- Error in ' + commandName + ':');
event.reply('- Message: ' + err);
_.each(stack, function(stackLine, index) {
event.reply('- Stack[' + index + ']: ' +
stackLine.trim());
});
} }
} dbot.api.event.emit('command', [ event ]);
if(!_.include(['reload', 'load', 'unload', 'setconfig'], commandName)) dbot.api.event.emit('command', [ event ]); dbot.save();
} else { } else {
if(commandName !== this.config.commandPrefix) { if(commandName !== '~') {
if(_.has(dbot.usage, commandName)) { if(_.has(dbot.usage, commandName)) {
event.reply('Usage: ' + dbot.usage[commandName]); event.reply('Usage: ' + dbot.usage[commandName]);
} else { } else {
event.reply(dbot.t('syntax_error')); event.reply(dbot.t('syntax_error'));
}
} }
} }
} }
} }
}.bind(this));
}.bind(this)); }.bind(this));
}.bind(this)); }
}.bind(this); }.bind(this);
this.on = 'PRIVMSG'; this.on = 'PRIVMSG';
this.onLoad = function() {
// Not sure this is the right place for this. Perhaps they should be in
// another file?
cDomain.on('error', function(err) {
console.log(err); // Hmm
if(_.has(dbot.modules, 'log')) {
// can't really get context
var server = _.keys(dbot.config.servers)[0];
dbot.api.log.log(server, dbot.config.name, '[\u00034ERR\u000f] ' + err.message);
}
});
dbot.access = {
'admin': function(event) {
return dbot.config.admins;
},
'moderator': function(event) {
return [].concat(dbot.access.admin(event), dbot.config.moderators);
},
'power_user': function(event) {
return [].concat(dbot.access.admin(event), dbot.access.moderator(event), dbot.config.power_users);
},
'voice': function(event) {
return [].concat(dbot.access.admin(event), dbot.access.moderator(event), dbot.access.power_user(event),
_.chain(event.channel.nicks)
.filter(function(nick) {
return nick.op == true || nick.voice == true;
})
.pluck('name')
.value());
}
};
}.bind(this);
}; };
exports.fetch = function(dbot) { exports.fetch = function(dbot) {

View File

@ -2,8 +2,8 @@ var _ = require('underscore')._,
request = require('request'); request = require('request');
var commands = function(dbot) { var commands = function(dbot) {
var commands = { return {
'usage': function(event) { '~usage': function(event) {
var commandName = event.params[1]; var commandName = event.params[1];
if(_.has(dbot.usage, commandName)) { if(_.has(dbot.usage, commandName)) {
event.reply(dbot.t('usage', { event.reply(dbot.t('usage', {
@ -39,8 +39,8 @@ var commands = function(dbot) {
var moduleName = event.params[1]; var moduleName = event.params[1];
if(!moduleName || !_.has(dbot.modules, moduleName)) { if(!moduleName || !_.has(dbot.modules, moduleName)) {
event.reply(dbot.t('usage', { event.reply(dbot.t('usage', {
'command': this.config.commandPrefix + 'help', 'command': '~help',
'usage': this.config.commandPrefix + 'help [module]' 'usage': '~help [module]'
})); }));
event.reply(dbot.t('loaded_modules', { event.reply(dbot.t('loaded_modules', {
'modules': _.keys(dbot.modules).join(', ') 'modules': _.keys(dbot.modules).join(', ')
@ -48,8 +48,8 @@ var commands = function(dbot) {
} else { } else {
var helpLink = dbot.config.repoRoot + var helpLink = dbot.config.repoRoot +
'blob/master/modules/' + moduleName + '/README.md'; 'blob/master/modules/' + moduleName + '/README.md';
if(dbot.config.modules[moduleName].help) { if(dbot.config[moduleName].help) {
helpLink = dbot.config.modules[moduleName].help; helpLink = dbot.config[moduleName].help;
} }
// TODO: Check it exists // TODO: Check it exists
@ -60,9 +60,6 @@ var commands = function(dbot) {
} }
} }
}; };
commands['usage'].regex = [/usage ([^ ]+)/, 2];
return commands;
}; };
exports.fetch = function(dbot) { exports.fetch = function(dbot) {

View File

@ -1,9 +1,6 @@
{ {
"ignorable": false, "ignorable": false,
"dependencies": [ "event", "ignore", "users" ], "help": "http://github.com/reality/depressionbot/blob/master/modules/command/README.md",
"useNickserv": false, "useNickserv": false,
"accessOutput": false, "dbKeys": [ "ignores", "bans" ]
"banOutput": false,
"passiveMode": false,
"commandPrefix": "~"
} }

View File

@ -1,13 +1,11 @@
{ {
"command_ban": { "command_ban": {
"en": "{user} is banned from using this command. Commence incineration.", "en": "{user} is banned from using this command. Commence incineration.",
"es": "{user} está prohibido de usar esta instrucción. urrently loaded modules now default: {modules}.", "es": "{user} está prohibido de usar esta instrucción. Comenzar incineración.",
"na'vi": "Tsu'ori {user} ke tung. Nga skxawng lu.", "na'vi": "Tsu'ori {user} ke tung. Nga skxawng lu.",
"cy": "Mae {user} wedi ei gohurio gan ddefnyddio'r gorchymun yma. Cychwyn orfflosgiad", "cy": "Mae {user} wedi ei gohurio gan ddefnyddio'r gorchymun yma. Cychwyn orfflosgiad",
"nl": "{user} mag dit commando niet meer gebruiken. Bereid het verbrandingsritueel voor.", "nl": "{user} mag dit commando niet meer gebruiken. Bereid het verbrandingsritueel voor.",
"de": "{user} darf diesen Befehl nicht benutzen. Verbrennung einleiten", "de": "{user} wurde von diesem Befehl gebannt. Verbrennung einleiten"
"fr": "{user} est interdit d'utiliser cette commande. Commencer l'incinération.",
"it": "A {user} è stato interdetto di utilizzare questo commando. Iniziare incenerimento."
}, },
"syntax_error": { "syntax_error": {
"en": "Invalid syntax. Initiate incineration.", "en": "Invalid syntax. Initiate incineration.",
@ -15,64 +13,43 @@
"na'vi": "Ngeyä pamrel keyawr lu. Nga skxawng lu.", "na'vi": "Ngeyä pamrel keyawr lu. Nga skxawng lu.",
"cy": "Cystrawen annilys. Cychwyn orfflosgiad", "cy": "Cystrawen annilys. Cychwyn orfflosgiad",
"nl": "Ongeldige syntax. Bereid het verbrandingsritueel voor.", "nl": "Ongeldige syntax. Bereid het verbrandingsritueel voor.",
"de": "Syntax ungültig. Verbrennung einleiten", "de": "Syntax ungültig. Verbrennung einleiten"
"fr": "Syntaxe invalide. Initier l'incinération.",
"it": "Sintassi non valida. Iniziare incenerimento"
}, },
"usage": { "usage": {
"en": "Usage for {command}: {usage}.", "en": "Usage for {command}: {usage}.",
"na'vi": "Nga tsun sivar ìlä {command}: {usage}.", "na'vi": "Nga tsun sivar ìlä {command}: {usage}.",
"cy": "Defnydd o {command}: {usage}.", "cy": "Defnydd o {command}: {usage}.",
"nl": "{command} wordt op de volgende manier gebruikt: {usage}.", "nl": "{command} wordt op de volgende manier gebruikt: {usage}.",
"de": "Benutzung von {command}: [usage}.", "de": "Benutzung von {command}: [usage}."
"fr": "Utilisation de {command}: {usage}.",
"it": "Utilizzo di {command}: {usage}."
}, },
"no_usage_info": { "no_usage_info": {
"en": "No usage information found for {command}.", "en": "No usage information found for {command}.",
"na'vi": "Oel ke tsun sivar {comamnd}it", "na'vi": "Oel ke tsun sivar {comamnd}it",
"cy": "Ni chanfuwyd gwybodaeth am ddefnydd o {command}", "cy": "Ni chanfuwyd gwybodaeth am ddefnydd o {command}",
"nl": "Geen gebruiksinformatie gevonden voor {command}.", "nl": "Geen gebruiksinformatie gevonden voor {command}.",
"de": "Keine Gebrauchsanweisung gefunden für {command}.", "de": "Keine Gebrauchsanweisung gefunden für {command}."
"fr": "Aucune information d'utilisation trouvée pour {command}",
"it": "Nessuna informazione d' utilizzo trovata per {command}"
}, },
"help_link": { "help_link": {
"en": "Help for {module}: {link}", "en": "Help for {module}: {link}",
"na'vi": "{module}ä srungìl {link} it tok", "na'vi": "{module}ä srungìl {link} it tok",
"cy": "Cymorth am {module}: {link}", "cy": "Cymorth am {module}: {link}",
"nl": "Hulp voor {module}: {link}", "nl": "Hulp voor {module}: {link}",
"de": "Hilfe für {module}: {link}", "de": "Hilfe für {module}: {link}"
"fr": "Aide pour {module}: {link}",
"it": "Aiuto per {module}: {link}"
}, },
"no_help": { "no_help": {
"en": "No help found for {module}.", "en": "No help found for {module}.",
"na'vi": "Fì{module}ìri oel ke tsun run srungit", "na'vi": "Fì{module}ìri oel ke tsun run srungit",
"cy": "Ni chanfuwyd cymorth am {module}", "cy": "Ni chanfuwyd cymorth am {module}",
"nl": "Geen hulp gevonden voor {module}.", "nl": "Geen hulp gevonden voor {module}.",
"de": "Keine Hilfe gefunden für {module}.", "de": "Keine Hilfe gefunden für {module}."
"fr": "Aucune aide trouvée pour {module}.",
"it": "Nessun aiuto trovato per {module}."
}, },
"loaded_modules": { "loaded_modules": {
"en": "Loaded modules: {modules}.", "en": "Loaded modules: {modules}.",
"cy": "Modiwlau sy'n lwythodd: {modules}.", "cy": "Modiwlau sy'n lwythodd: {modules}.",
"nl": "Geladen modules: {modules}.", "nl": "Geladen modules: {modules}.",
"de": "Module geladen: {modules}.", "de": "Module geladen: {modules}."
"fr": "Modules chargés: {modules}.",
"it": "Moduli caricati: {modules}."
},
"access_denied": {
"en": "{user}: You don't have the access level to run this command.",
"fr": "{user}: Vous n'avez pas le niveau d'accès requis pour utiliser cette commande.",
"it": "{user}: Non hai il livello d'accesso neccessario per utilizzare questo commando.",
"de": "{user}: Du hast nicht die notwendigen Rechte um diesen Befehl zu benutzen."
}, },
"module_commands": { "module_commands": {
"en": "Commands in {module}: {commands}.", "en": "Commands in {module}: {commands}."
"fr": "Commandes de {module}: {commands}.",
"it": "Commandi di {module}: {commands}.",
"de": "Befehle in {module}: {commands}."
} }
} }

View File

@ -1,15 +0,0 @@
## Crypto
Cryptography!
### Description
This module calculates different hashes or ciphertexts for some algorithms.
### Commands
#### ~hash [algorithm] [text]
Calculate the hash of the given text using [algorithm].
#### ~random [number]
Gives [number] bytes of cryptographically strong pseudo-random data as hex string.

View File

@ -1,44 +0,0 @@
/**
* Module Name: Crypto
* Description: Allows the magic of cryptography to take place.
*/
var cr = require('crypto');
var crypto = function(dbot) {
this.commands = {
'~hash': function(event) {
var hash = event.params[1];
try {
var h = cr.createHash(hash);
var tohash = event.params.splice(2, event.params.length-1).join(' ');
h.update(tohash);
event.reply(hash+" of \""+tohash+"\" is: "+h.digest('hex'));
} catch(err) {
event.reply(err);
}
},
'~randomdata': function(event) {
try {
var count = parseInt(event.params[1]);
if(count > 222) {
event.reply("Sorry man, I can't paste that much random data.");
return;
}
cr.randomBytes(count, function(err,buf) {
if(err) {
event.reply(err);
return;
}
event.reply(buf.toString('hex'));
});
} catch (err) {
event.reply(err);
}
}
};
};
exports.fetch = function(dbot) {
return new crypto(dbot);
};

View File

@ -1,6 +0,0 @@
{
"~md5": "~md5 [text]",
"~sha1": "~sha1 [text]",
"~sha256": "~sha256 [text]",
"~aes": "~aes \"[text]\" \"[key]\""
}

View File

@ -1,3 +0,0 @@
{
"outputChannel": "#realitree"
}

View File

@ -1,62 +0,0 @@
var _ = require('underscore')._;
var cspeed = function(dbot) {
this.watches = dbot.db.cspeed;
this.outputChannel = dbot.config.modules.cspeed.outputChannel;
this.counts = {};
this.api = {
'getCounts': function(callback) {
callback(this.counts);
}
};
this.api['getCounts'].external = true;
this.api['getCounts'].extMap = [ 'callback' ];
this.commands = {
'addlpmwatch': function(event) {
var channel = event.params[1];
var key = event.server + '.' + channel;
if(!_.has(this.watches, key)) {
this.watches[key] = {
'server': event.server,
'channel': channel
}; // to be extended with warn nums etc
this.counts[key] = 0;
dbot.api.timers.addTimer(60000, function() {
dbot.say(event.server, this.outputChannel, channel + ' currently : ' + this.counts[key] + ' LPM');
this.counts[key] = 0;
}.bind(this));
event.reply('Added speed watch for ' + channel);
} else {
event.reply('Already watching that channel');
}
}
};
this.listener = function(event) {
var key = event.server + '.' + event.channel;
if(_.has(this.watches, key)) {
this.counts[key]++;
}
}.bind(this);
this.on = 'PRIVMSG';
this.onLoad = function() {
var watches = dbot.db.cspeed;
_.each(watches, function(watch) {
var key = watch.server + '.' + watch.channel;
this.counts[key] = 0;
dbot.api.timers.addTimer(60000, function() {
dbot.say(watch.server, dbot.db.cspeed.outputChannel, watch.channel + ': ' + this.counts[key] + 'LPM');
}.bind(this));
}.bind(this));
}.bind(this);
};
exports.fetch = function(dbot) {
return new cspeed(dbot);
};

View File

@ -1,3 +1,4 @@
{ {
"ignorable": true "ignorable": true,
"help": "https://github.com/reality/depressionbot/blob/master/modules/ctcp/README.md"
} }

View File

@ -1,36 +1,22 @@
var ctcp = function(dbot) { var ctcp = function(dbot) {
this.listener = function(event) { var commands = {
var matches = event.message.match(/\u0001[\w]+\u0001/); "\x01VERSION\x01": function(event) {
if(matches) { // the current client version
// We need the CTCP command event.replyNotice("\x01VERSION " + dbot.config.version + "\x01");
var question = matches[0]; },
// Cut \u0001 characters from command "\x01CLIENTINFO\x01": function(event){
question = question.slice(1,question.length-1); // a list of all supported CTCP commands
switch(question) { event.replyNotice("\x01CLIENTINFO SOURCE VERSION USERINFO\x01");
case 'CLIENTINFO': },
event.replyNotice("\u0001CLIENTINFO SOURCE VERSION USERINFO\u0001"); "\x01SOURCE\x01": function(event){
break; event.replyNotice("\x01SOURCE https://github.com/reality/depressionbot\x01");
case 'FINGER': },
event.replyNotice("\u0001FINGER STOP FINGERING ME BRO\u0001"); "\x01USERINFO\x01": function(event){
break; // a "witty" saying set by the user
case 'SOURCE': event.replyNotice("\z01USERINFO " + dbot.config.name + "\x01");
event.replyNotice("\u0001SOURCE "+dbot.config.repoRoot+"\u0001");
break;
case 'TIME':
var d = new Date();
event.replyNotice("\u0001TIME "+d.toISOString()+"\u0001");
break;
case 'USERINFO':
event.replyNotice("\u0001USERINFO "+dbot.config.name+"\u0001");
break;
case 'VERSION':
event.replyNotice("\u0001VERSION "+dbot.config.version+"\u0001");
break;
default:
event.replyNotice("\u0001"+question+" Idk what you want. Try CLIENTINFO.\u0001");
}
} }
}; }
this.commands = commands;
this.on = 'PRIVMSG'; this.on = 'PRIVMSG';
}; };

View File

@ -1,8 +1,8 @@
{ {
"username": "youruserhere", "username": "youruserhere",
"password": "yourpasswordhere", "password": "yourpasswordhere",
"dependencies": [ "link" ], "dependencies": [ "command" ],
"ignorable": true, "ignorable": true,
"dentQuotes": true, "help": "https://github.com/reality/depressionbot/blob/master/modules/dent/README.md",
"api": "http://quitter.se/" "dentQuotes": false
} }

View File

@ -2,6 +2,7 @@ var request = require('request');
_ = require('underscore')._; _ = require('underscore')._;
var dent = function(dbot) { var dent = function(dbot) {
this.dbot = dbot;
this.StatusRegex = { this.StatusRegex = {
identica: /\bhttps?:\/\/identi\.ca\/notice\/(\d+)\b/ig, identica: /\bhttps?:\/\/identi\.ca\/notice\/(\d+)\b/ig,
twitter: /\bhttps?:\/\/twitter\.com\/\w+\/status\/(\d+)\b/ig twitter: /\bhttps?:\/\/twitter\.com\/\w+\/status\/(\d+)\b/ig
@ -14,14 +15,14 @@ var dent = function(dbot) {
this.api = { this.api = {
'post': function(content) { 'post': function(content) {
var username = this.config.username, var username = dbot.config.dent.username,
password = this.config.password, password = dbot.config.dent.password,
info, info,
auth = "Basic " + auth = "Basic " +
new Buffer(username + ":" + password).toString("base64"); new Buffer(username + ":" + password).toString("base64");
request.post({ request.post({
'url': this.config.api + '/statuses/update.json?status=' + 'url': 'http://identi.ca/api/statuses/update.json?status=' +
escape(content), escape(content),
'headers': { 'headers': {
'Authorization': auth 'Authorization': auth
@ -33,7 +34,7 @@ var dent = function(dbot) {
} }
}; };
this.lookup = function(id, service, callback) { this.lookup = function(event, id, service) {
request({ request({
url: this.StatusAPI[service], url: this.StatusAPI[service],
qs: {"id": id}, qs: {"id": id},
@ -41,7 +42,7 @@ var dent = function(dbot) {
}, function(error, response, body) { }, function(error, response, body) {
if (!error && response.statusCode == 200) { if (!error && response.statusCode == 200) {
if (_.has(body, 'text')) { if (_.has(body, 'text')) {
callback(service + " [" + body.user.screen_name + '] ' + body.text); event.reply(service + " [" + body.user.screen_name + '] ' + body.text);
} }
} }
}); });
@ -53,11 +54,11 @@ var dent = function(dbot) {
event.reply('Dent posted (probably).'); event.reply('Dent posted (probably).');
} }
}; };
this.commands['~dent'].regex = [/^dent (.+)$/, 2]; this.commands['~dent'].regex = [/^~dent (.+)$/, 2];
this.onLoad = function() { this.onLoad = function() {
if(this.config.dentQuotes === true && _.has(dbot.modules, 'quotes')) { if(dbot.config.dent.dentQuotes === true && _.has(dbot.modules, 'quotes')) {
dbot.api.event.addHook('qadd', function(key, text) { dbot.api.command.addHook('~qadd', function(key, text) {
if(text.indexOf('~~') == -1) { if(text.indexOf('~~') == -1) {
this.api.post(key + ': ' + text); this.api.post(key + ': ' + text);
} }
@ -65,8 +66,8 @@ var dent = function(dbot) {
} }
for(s in this.StatusRegex) { for(s in this.StatusRegex) {
dbot.api.link.addHandler(s, this.StatusRegex[s], function(matches, name, callback) { dbot.api.link.addHandler(s, this.StatusRegex[s], function(event, matches, name) {
this.lookup(matches[1], name, callback); this.lookup(event, matches[1], name);
}.bind(this)); }.bind(this));
} }
}.bind(this); }.bind(this);

View File

@ -17,13 +17,13 @@ var parseDiceSpec = function (specString) {
var normalizeDiceSpec = function (specString) { var normalizeDiceSpec = function (specString) {
var diceSpec = parseDiceSpec(specString); var diceSpec = parseDiceSpec(specString);
if (diceSpec["sides"] > 10000) { if (diceSpec["sides"] > 10000) {
return false; return false;
} }
if (diceSpec["count"] > 1000) { if (diceSpec["count"] > 1000) {
return false; return false;
} }
if (diceSpec["count"] > 1) { if (diceSpec["count"] > 1) {
var count = diceSpec["count"]; var count = diceSpec["count"];
@ -74,7 +74,7 @@ var dice = function(dbot) {
event.reply(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 " + _.reduce(rolls[i][1], function(memo, num){ return memo + num; }, 0); var total = " (total " + rolls[i][1].sum();
if (rolls[i][2] != 0) { if (rolls[i][2] != 0) {
if (rolls[i][2] > 0) { if (rolls[i][2] > 0) {
total += " + "; total += " + ";

3
modules/dns/config.json Normal file
View File

@ -0,0 +1,3 @@
{
"help": "https://github.com/reality/depressionbot/blob/master/modules/dns/README.md"
}

View File

@ -2,40 +2,13 @@
* Module Name: DNS * Module Name: DNS
* Description: Performs and reports on basic DNS functions. * Description: Performs and reports on basic DNS functions.
*/ */
var dnsm = require('dns'), var dnsmod = require('dns');
request = require('request'),
http = require('http');
var dns = function(dbot) { var dns = function(dbot) {
if(!_.has(dbot.db, 'ip')) {
dbot.db.ip = {};
}
var ips = dbot.db.ip;
this.api = {
'getGeoIp': function(ip, callback) {
if(_.has(ips, ip)) {
body = ips[ip];
callback(ip + ' is located in '+ body.city + ', ' + body.country + '. Hostname: ' + body.hostname + '. ISP: ' + body.org);
} else {
request.get('http://ipinfo.io/'+ip, {
'json': true
}, function(err, res, body) {
if(!err && body) {
callback(ip + ' is located in '+ body.city + ', ' + body.country + '. Hostname: ' + body.hostname + '. ISP: ' + body.org);
} else {
callback('No info about ' + ip);
}
ips[ip] = body;
});
}
}.bind(this)
};
var commands = { var commands = {
'~lookup': function(event) { '~lookup': function(event) {
domain = event.params[1]; domain = event.params[1];
dnsm.lookup(domain, function (error, addr) { dnsmod.lookup(domain, function (error, addr) {
if (error) { if (error) {
event.reply(dbot.t("lookup-error",{"domain": domain, "code": error.code})); event.reply(dbot.t("lookup-error",{"domain": domain, "code": error.code}));
} else { } else {
@ -43,52 +16,20 @@ var dns = function(dbot) {
} }
}); });
}, },
'~rdns': function(event) { '~rdns': function(event) {
ip = event.params[1]; ip = event.params[1];
dnsm.reverse(ip, function (error, domain) { dnsmod.reverse(ip, function (error, domain) {
if (error) { if (error) {
event.reply(dbot.t("rdns-error",{"domain": domain, "ip": ip, "error": error.code})); event.reply(dbot.t("rdns-error",{"domain": domain, "ip": ip, "error": error.code}));
} else { } else {
event.reply(dbot.t("rdns",{"domain": domain, "ip": ip})); event.reply(dbot.t("rdns",{"domain": domain, "ip": ip}));
} }
}); });
},
'~geoip': function(event) {
var ip = event.params[1];
this.api.getGeoIp(ip, function(result) { event.reply(result); });
},
'~dnsbl': function(event) {
var revIp = event.input[1].trim().split('.').reverse().join('.');
dnsm.lookup(revIp + '.cbl.abuseat.org', function(err, res) {
if(!err && res) {
event.reply(event.input[1] + ' is listed as an abusive IP.');
} else {
event.reply(event.input[1] + ' does not seem to be a Naughty Nancy.');
}
});
} }
}; };
commands['~dnsbl'].regex = [/^dnsbl ([\d\w\s\.-]*)/, 2];
this.commands = commands; this.commands = commands;
if(dbot.config.modules.dns.dnsblconn == true) { this.on = 'PRIVMSG';
this.listener = function(event) {
if(event.message.match('CLICONN')) {
var ip = event.message.match('CLICONN ([^ ]+).*?((?:[0-9]{1,3}\.){3}[0-9]{1,3}) users');
revIp = ip[2].trim().split('.').reverse().join('.');
dbot.say(event.server, '#dnsbl', 'DEBUG: Looking up ' + ip[2] + ' for ' + ip[1] + ' @ ' + revIp);
dnsm.lookup(revIp + '.cbl.abuseat.org', function(err, res) {
if(!err && res) {
dbot.say(event.server, '#dnsbl', 'ALERT: ' + ip[1] + ' connecting from ' + ip[2] + ' may well be NAUGHTY.');
}
});
}
}
this.on = 'NOTICE';
}
}; };
exports.fetch = function(dbot) { exports.fetch = function(dbot) {

View File

@ -3,30 +3,21 @@
"en": "{domain} is \u000303AVAILABLE! \u000314({code})", "en": "{domain} is \u000303AVAILABLE! \u000314({code})",
"cy": "{domain} \u000303AR GAEL! \u000314({code})", "cy": "{domain} \u000303AR GAEL! \u000314({code})",
"nl": "{domain} is \u000303BESCHIKBAAR! \u000314({code})", "nl": "{domain} is \u000303BESCHIKBAAR! \u000314({code})",
"de": "{domain} ist \u000303VERFÜGBAR! \u000314({code})", "de": "{domain} ist \u000303VERFÜGBAR! \u000314({code})"
"fr": "{domain} est \u000303DISPONIBLE! \u000314({code})",
"it": "{domain} è \u000303DISPONIBILE! \u000314({code})"
}, },
"lookup": { "lookup": {
"en": "{domain} is \u000305TAKEN! \u000314({address})", "en": "{domain} is \u000305TAKEN! \u000314({address})",
"cy": "Dydy {domain} \u000305DDIM AR GAEL! \u000314({address})", "cy": "Dydy {domain} \u000305DDIM AR GAEL! \u000314({address})",
"nl": "{domain} is \u000305BEZET! \u000314({address})", "nl": "{domain} is \u000305BEZET! \u000314({address})",
"de": "{domain} ist \u000305BELEGT! \u000314({address})", "de": "{domain} ist \u000305BELEGT! \u000314({address})"
"fr": "{domain} est \u000305PRIS! \u000314({address})",
"it": "{domain} èt \u000305RISERVATO! \u000314({address})"
}, },
"rdns": { "rdns": {
"en": "{ip} \u2192 {domain}", "en": "{ip} \u2192 {domain}"
"fr": "{ip} \u2192 {domain}",
"it": "{ip} \u2192 {domain}",
"de":"{ip} \u2192 {domain}"
}, },
"rdns-error": { "rdns-error": {
"en": "Unable to lookup {ip}. \u000314({error})", "en": "Unable to lookup {ip}. \u000314({error})",
"cy": "Methu am-edrych {ip}. \u000314({error})", "cy": "Methu am-edrych {ip}. \u000314({error})",
"nl": "{ip} kan niet worden opgezocht. \u000314({error})", "nl": "{ip} kan niet worden opgezocht. \u000314({error})",
"de": "Kann {ip} nicht auflösen. \u000314({error})", "de": "Kann {ip} nicht auflösen. \u000314({error})"
"fr": "Impossible de rechercher {ip}. \u000314({error})",
"it": "Non è possibile cercare {ip}. \u000314({error})"
} }
} }

View File

@ -0,0 +1,3 @@
{
"help": "https://github.com/reality/depressionbot/blob/master/modules/event/README.md"
}

View File

@ -0,0 +1,3 @@
{
"help": "https://github.com/reality/depressionbot/blob/master/modules/flashy/README.md"
}

View File

@ -37,7 +37,7 @@ var flashy = function(dbot) {
} }
}; };
this.commands['~flashy'].regex = [/^flashy ([^ ]+) (.+)$/, 3]; this.commands['~flashy'].regex = [/^~flashy ([^ ]+) (.+)$/, 3];
}; };
exports.fetch = function(dbot) { exports.fetch = function(dbot) {

View File

@ -10,7 +10,7 @@ var pages = function(dbot) {
res.render('flashy', { res.render('flashy', {
'name': dbot.config.name, 'name': dbot.config.name,
'colour': colour, 'colour': colour,
'text': decodeURIComponent(req.params.text) 'text': req.params.text
}); });
} }
}; };

View File

@ -1,4 +0,0 @@
{
"outputPrefix": "\u000311food\u000f",
"api_key": "http://food2fork.com/about/api"
}

View File

@ -1,60 +0,0 @@
/**
* Module name: Food
* Description: recipe search
*/
var _ = require('underscore')._,
request = require('request');
var food = function(dbot) {
this.commands = {
'~recipe': function(event) {
request.get('http://food2fork.com/api/search', {
'qs': {
'key': this.config.api_key,
'q': event.input[1]
},
'json': true
}, function(error, response, body) {
if(_.isObject(body) && _.has(body, 'recipes') && body.recipes.length > 0) {
var num = _.random(0, body.recipes.length - 1),
recipe = body.recipes[num];
event.reply(dbot.t('recipe', {
'title': recipe.title,
'link': recipe.source_url
}));
} else {
event.reply(dbot.t('no_recipe'));
}
}.bind(this));
}
};
this.commands['~recipe'].regex = [/^recipe (.+)$/, 2];
this.listener = function(event) {
var match = event.message.match(new RegExp(dbot.config.name + ': what should i (have|eat|make)\\??( for (dinner|lunch|breakfast))?\\??', 'i'));
if(match) {
var page = _.random(0, 200);
request.get('http://food2fork.com/api/search', {
'qs': {
'key': this.config.api_key,
'page': page
},
'json': true
}, function(error, response, body) {
if(_.isObject(body) && _.has(body, 'recipes') && body.recipes.length > 0) {
var num = _.random(0, body.recipes.length - 1),
recipe = body.recipes[num];
event.reply(event.user + ': You should make ' + recipe.title + '. See: ' + recipe.source_url);
}
}.bind(this));
}
}.bind(this);
this.on = 'PRIVMSG';
};
exports.fetch = function(dbot) {
return new food(dbot);
};

View File

@ -1,8 +0,0 @@
{
"recipe": {
"en": "{title} - {link}"
},
"no_recipe": {
"en": "No recipes found."
}
}

View File

@ -1,34 +0,0 @@
## 500px
Adds various 500px functionality.
### Description
This module provides a command which allows users to search for a random popular 500px photo.
### Dependencies
It has following dependencies:
+ [node-500px](https://github.com/ro-ka/node-500px)
### config.json
ignorable and consumerKey has to be configurated. It can be obtained at http://developers.500px.com
```
{
"ignorable": true,
"api_key": "CONSUMERKEY_HERE"
}
```
### Commands
~r500px
Responds with a random popular 500px photo.
Example:
+ ~r500px
### TODO
Photo by user etc.

View File

@ -1,4 +0,0 @@
{
"ignorable": true,
"api_key": "CONSUMERKEY_HERE"
}

View File

@ -1,33 +0,0 @@
/**
* Module Name: 500px
* Description: Adds various 500px functionality.
* Requires: node-500px [http://mjgil.github.io/five-px/]
*/
var _ = require('underscore')._,
API500px = require('500px').API500px;
var fpx = function(dbot) {
this.commands = {
'~r500px': function(event) {
var random = Math.floor(Math.random() * 30);
this.api500px.photos.getPopular({'sort': 'created_at', 'rpp': '30'}, function(error, results) {
if (error) {
event.reply(dbot.t('5px_error'));
console.log(error);
} else {
var name = results.photos[random].name,
id = results.photos[random].id;
event.reply(dbot.t('5px_result',{'name':name,'id':id}));
}
});
}
};
this.onLoad = function() {
this.api500px = new API500px(this.config.api_key);
}.bind(this);
};
exports.fetch = function(dbot) {
return new fpx(dbot);
};

View File

@ -1,8 +0,0 @@
{
"5px_result":{
"en": "{name} - http://500px.com/photo/{id}"
},
"5px_error": {
"en": "Something went wrong :( Example: '~r500px'"
}
}

View File

@ -1,3 +0,0 @@
{
"~r500px": "~r500px"
}

1
modules/github Submodule

@ -0,0 +1 @@
Subproject commit 5f4e3dc8335000e97af528fee289b880a3c99e81

View File

@ -1,18 +0,0 @@
Copyright (c) 2013 Douglas Gardner <douglas@chippy.ch>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,28 +0,0 @@
## Github
Grabs interesting data from the GitHub API.
### Description
This module for [depressionbot](https://github.com/reality/depressionbot) takes some interesting information about Github and parses it in a pleasing manner.
### Configuration
#### defaultrepo
When repository information is lacking from the command, this repository will be used.
#### sortorder
Defines the behaviour of ~issue when no arguments are given. Options are ``created``, ``updated``, or ``comments``.
### Commands
#### ~commits
Returns the number of commits in the repository of the current depressionbot instance.
#### ~gstatus
Returns the [current status of Github](https://status.github.com), and a message explaining the current state of affairs.
#### ~issue (user/repo) [id]
Gives information about the isse pecified, from the default repository if one is not explicitly stated.
#### ~milestone [milestone name]
Returns milestone progress for any given milestone, with a link to the milestone in question.
#### ~repo (repo name)
Returns information about the repo given as a parameter. The repo should be specified as ``user/name``; for example, ``twitter/snowflake``.
#### ~repocount [user]
Returns the number of public Github repositories for the specified user.
### Dependencies
* [request](https://github.com/mikeal/request/):``$ npm install request``

View File

@ -1,8 +0,0 @@
{
"dependencies": [ "command" ],
"ignorable": true,
"help": "http://github.com/zuzak/dbot-github/blob/master/README.md",
"defaultrepo": "reality/dbot",
"sortorder": "updated",
"useragent": "reality/depressionbot github module"
}

View File

@ -1,192 +0,0 @@
/**
* Module Name: Github
* Description: Retrieves interesting Github information
*/
var request = require('request'),
exec = require('child_process').exec;
var github = function(dbot) {
this.api = {
"githubStatus": function(callback){
var reqUrl = "https://status.github.com/api/last-message.json";
request({"url": reqUrl, "headers": {"User-Agent": this.config.useragent}}, function(error, response, body) {
callback(JSON.parse(body));
});
}
};
var commands = {
'~repocount': function(event) {
var reqUrl = "https://api.github.com/users/" + event.params[1] + "/repos";
request({"url": reqUrl, "headers": {"User-Agent": this.config.useragent}}, function(error, response, body) {
if(response.statusCode == "200") {
var result = JSON.parse(body);
event.reply(dbot.t("repocount",{"user": event.params[1], "count": result.length}));
} else {
event.reply(dbot.t("usernotfound"));
}
});
},
'~repo': function(event) {
var repo = event.params[1];
if (typeof repo == 'undefined') {
repo = this.config.defaultrepo;
}
var reqUrl = "https://api.github.com/";
reqUrl += "repos/" + repo;
request({"url": reqUrl, "headers": {"User-Agent": this.config.useragent}}, function(error, response, body) {
var data = JSON.parse(body);
if (data["fork"]) {
event.reply(dbot.t("forkedrepo",data));
} else {
event.reply(dbot.t("unforkedrepo",data));
}
// TODO: move this shizz into an api call
var longurl = "http://github.com/" + repo;
event.reply(dbot.t('location')+" "+longurl);
});
},
'~gstatus': function(event) {
data = this.api.githubStatus(function(data){
event.reply(dbot.t("status"+data["status"]));
event.reply(data["body"]);
}.bind(this));
},
'~milestone': function(event) {
var repo = this.config.defaultrepo;
var name = event.params[1];
if (event.params[2]){
repo = name;
name = event.params[2];
}
var reqUrl = "https://api.github.com/repos/";
reqUrl += repo + "/milestones";
request({"url": reqUrl, "headers":{"User-Agent": this.config.useragent}}, function(error, response, body) {
var data = JSON.parse(body);
for (var section in data) {
var milestone = data[section];
if (milestone["title"] == name){
var str = "Milestone " + milestone["title"];
var progress = milestone["closed_issues"] / (milestone["open_issues"] + milestone["closed_issues"]);
progress = Math.round(progress*100);
var bar = "[";
for (var i = 10; i < 100; i += 10) {
if ((progress/i) > 1) {
bar += "█";
} else {
bar += " ";
}
}
bar += "]";
str += " is " + bar + progress + "% complete";
event.reply(str);
break;
}
}
});
},
'~repocount': function(event) {
// TODO: add handling for non existent user
var reqUrl = "https://api.github.com/users/" + event.params[1] + "/repos";
request({"url": reqUrl,"headers": { "User-Agent": this.config.useragent}}, function(error, response, body) {
var result = JSON.parse(body);
event.reply(event.params[1] + " has " + result.length + " public repositories.");
});
},
'~grate': function(event) {
request.get({"url":"https://api.github.com/rate_limit", "headers":{"User-Agent": this.config.useragent}}, function(error, response, body) {
var data = JSON.parse(body);
if (data.message){
event.reply(data.message);
} else {
event.reply(data.rate.remaining + " requests of " + data.rate.limit + " remaining.");
}
});
},
'~issue': function(event) {
var repo, issue, randflag;
if (isNaN(event.params[1]) && event.params[1]){ // if ~issue foo/bar
repo = event.params[1];
issue = event.params[2];
} else {
repo = this.config.defaultrepo;
issue = event.params[1];
}
if (issue == "*" || issue == "random" || issue == "0") {
issue = "";
randflag = true;
} else if (!issue) { // issue is undefined
issue = "";
} else {
issue = "/" + issue; // got to be a better way
}
var reqUrl = "https://api.github.com/repos/" + repo + "/issues" +
issue + "?sort=" + this.config.sortorder;
request.get({"url": reqUrl, headers: { "User-Agent": this.config.useragent}}, function(error,response, body) {
if (response.statusCode == "200") {
var data = JSON.parse(body);
if (!issue){
if (randflag) {
data = data[Math.floor(Math.random() * data.length)];
} else {
data = data[0];
}
}
if (_.has(data["pull_request"], "html_url")){
data["pull_request"] = " with code";
} else {
data["pull_request"] = "";
}
if (data["state"]=="open") {
data["state"] = "\u000303" + data["state"];
} else {
data["state"] = "\u000304" + data["state"];
}
var labels = "";
for (var i=0; i < data["labels"].length; i++) { // for-in doesn't like me
var color = "\u0003" + (parseInt(data["labels"][i]["color"],16) % 15);
labels += " " + color + data["labels"][i]["name"];
}
data["label"] = labels;
event.reply(dbot.t("issue",data));
event.reply(data["html_url"]);
} else {
event.reply(dbot.t("issuenotfound"));
}
});
},
'~commits': function(event) {
exec("git rev-list --all | wc -l", function(error, stdout, stderr) {
stdout = stdout.trim();
request({"url":"http://numbersapi.com/" + stdout + "?fragment&default=XXX"}, function(error, response, body){
if (body != "XXX"){
event.reply(dbot.t("commitcountfun",{"fact": body, "count": stdout}));
} else {
// nothing fun about the number, let's try the year
request({"url":"http://numbersapi.com/" + stdout + "/year?fragment&default=XXX"}, function(error, response, body){
if (body != "XXX"){
event.reply(dbot.t("commitcountyear",{"fact": body, "count": stdout}));
} else {
event.reply(dbot.t("commitcountboring",{"count": stdout}));
}
});
}
});
});
}
};
this.commands = commands;
this.on = 'PRIVMSG';
};
exports.fetch = function(dbot) {
return new github(dbot);
};

View File

@ -1,94 +0,0 @@
{
"repocount": {
"en": "{user} has {count} public repos.",
"cy": "Mae {count} archifdai cyhoeddus gan {user}.",
"de": "{user} hat {count} öffnetliche Repos.",
"fr": "{user} a {count} dépôt(s) public(s).",
"it": "{user} ha {count} deposito/i pubblico/i."
},
"statusgood": {
"en": "\u000309Shit's fine",
"cy": "\u000309Cachu'n ddirwy",
"de": "\u000309Alles in Ordnung",
"fr": "\u000309Cette merde tourne bien",
"it": "\u000309Funziona a meraviglia."
},
"statusminor": {
"en": "\u000308Shit's touchy",
"cy": "\u000308Cachu'n fregus",
"de": "\u000308Kleinere Probleme vorhanden",
"fr": "\u000308Cette merde a un petit problème",
"it": "\u000308Piccoli problemi all' orizzonte"
},
"statusmajor": {
"en": "\u000304Shit's fucked:",
"cy": "\u000304Cachu wedi cyrraedd y ffan:",
"de": "\u000304Du bist am Arsch",
"fr": "\u000304Cette merde est foutue : ",
"it": "\u000304Sei nella merda : "
},
"location": {
"en": "You can find that shit at:",
"cy": "Gallwch ddod o hyd y cachu yn:",
"de": "Kann gefunden werden unter:",
"fr": "Tu peux trouver cette merde ici : ",
"it": "Puoi trovare questa coglionata a: "
},
"forkedrepo": {
"en": "{name} is a forked {language} repo with {open_issues} unresolved issues [{forks}F {watchers}W]",
"cy": "{name} ydy archif {language} fforchog gyda {open_issues} materion heb eu datrys [{forks}F {watchers}W]",
"de": "{name} ist eine geteilte {language} Repo mit {open_issues} ungelösten Problemen [{forks}F {watchers}W]",
"fr": "{name} est un dépôt fourché {language} avec {open_issues} problème(s) non résolu(s) [{forks}F {watchers}W]",
"it": "{name} è un deposito biforcato {language} con {open_issues} problema/i irrisolto/i [{forks}F {watchers}W]"
},
"unforkedrepo": {
"en": "{name} is a {language} repo with {open_issues} unresolved issues [{forks}F {watchers}W]",
"cy": "{name} ydy archif {language} gyda {open_issues} materion heb eu datrys [{forks}F {watchers}W]",
"de": "{name} ist eine {language} Repo mit {open_issues} ungelösten Problemen [{forks}F {watchers}W]",
"fr": "{name} est un dépôt {language} avec {open_issues} problème(s) non résolu(s) [{forks}F {watchers}W]",
"it": "{name} è un deposito {language} con {open_issues} problema/i irrisolto/i [{forks}F {watchers}W]"
},
"usernotfound": {
"en": "User not found.",
"cy": "Defnyddiwr heb ei ganfod.",
"de": "Benutzer nicht gefunden.",
"fr": "Utilisateur non trouvé.",
"it": "Utente non trovato."
},
"issuenotfound": {
"en": "Unable to find that issue.",
"cy": "Wedi methu dod o hyd mater hwnnw",
"de": "Kann dieses Problem nicht finden.",
"fr": "Impossible de trouver ce problème.",
"it": "Impossibile trovare questo problema."
},
"issue": {
"en": "Issue \u000308{number}\u0003: {title} [{state}{pull_request}\u000315; {comments} comments]{label}",
"cy": "Mater \u000308{number}\u0003: {title} [{state}{pull_request}\u000315; {comments} sylwadau]{label}",
"de": "Problem \u000308{number}\u0003: {title} [{state}{pull_request}\u000315; {comments} comments]{label}",
"fr": "Problème \u000308{number}\u0003: {title} [{state}{pull_request}\u000315; {comments} commentaires]{label}",
"it": "Problema \u000308{number}\u0003: {title} [{state}{pull_request}\u000315; {comments} commento/i]{label}"
},
"commitcountboring": {
"en": "My code has been committed {count} times.",
"cy": "Mae fy cod wedi cael ei gyflawni ar {count} adegau.",
"de": "Mein Code wurde {count} mal bestätigt.",
"fr": "Mon code a été modifié {count} fois.",
"it": "Il mio codice è stato modificato {count} volta/e."
},
"commitcountfun": {
"en": "My repository has the same number of commits as {fact} ({count}).",
"cy": "Yr un nifer o ymrwymo fel {fact} gan fy archif ({count}).",
"de": "Meine Repository hat die gleiche Anzahl Commits wie {fact} ({count}).",
"fr": "Mon dépôt a le même nombre de modifications que {fact} ({count}).",
"it": "Il mio deposito ha lo stesso numero di modifiche come {fact} ({count})."
},
"commitcountyear": {
"en": "My repository's commits number {count}, the year that {fact}.",
"cy": "Nifer o ymrwymo gan fy archif: {count}, y flwyddyn y {fact}.",
"de": "Anzahl der Commits in meinem Repository {count}, des Jahres {fact}",
"fr": "Mon dépot compte {count} modifications, l'année où {fact}.",
"it": "Il mio deposito ha {count} modifica/che, l' anno che {fact}."
}
}

View File

@ -1,29 +0,0 @@
/**
* Module Name: Google Maps
* Description: GMaps and ting
*/
var gm = require('googlemaps'),
_ = require('underscore')._;
var gmaps = function(dbot) {
this.commands = {
'~from': function(event) {
var from = event.input[1],
to = event.input[2],
departureNow = Math.floor((new Date()).getTime()/1000);
gm.directions(from, to, function(err, result) {
if(!err && result && result.status !== 'ZERO_RESULTS') {
event.reply('If you leave right now, it will take ' + result.routes[0].legs[0].duration.text + ' to get from ' + from + ' to ' + to + ' via public transport.');
} else {
event.reply('Apparently one cannot get from ' + from + ' to ' + to + ' using public transport. Do you accept the challenge?');
}
}, 'false', 'transit', null, null,null, null, null, departureNow);
}
};
this.commands['~from'].regex = [/^from (.*) to (.*)/, 3];
};
exports.fetch = function(dbot) {
return new gmaps(dbot);
};

View File

@ -1,4 +0,0 @@
{
"api_key": "sethere",
"outputPrefix": "\u00033goodreads\u000f"
}

View File

@ -1,293 +0,0 @@
/**
* Module Name: GoodReads
* Description: Interacts with the GoodReads API to provide book-oriented functionality to dbot
*/
var util = require('util'),
_ = require('underscore')._,
rp = require('request-promise-native'),
parseString = util.promisify(require('xml2js').parseString);
var GoodReads = function(dbot) {
this.apiRoot = 'https://www.goodreads.com';
this.internalAPI = {
'outputError': (evt, e) => {
switch(e) {
case 'goodreads-error': evt.reply('Error talking to GoodReads.'); return;
case 'book-not-found': evt.reply(dbot.t('gr_nobook')); return;
case 'no-description': evt.reply('No description was found for the book you asked for.'); return;
case 'author-not-found': evt.reply(dbot.t('gr_noauthor')); return;
}
console.log(e);
evt.reply('Something went wrong and I don\'t know what.');
},
'formatProfile': profile => {
var shelves = {};
_.each(profile.user_shelves.user_shelf, shelf => {
shelves[shelf.name] = shelf.book_count['_'];
});
profile.user_shelves = shelves;
return profile;
}
};
this.api = {
'findBook': async term => {
//https://www.goodreads.com/search/index.xml
var body = await rp({
uri: this.apiRoot + '/search/index.xml',
qs: {
key: this.config.api_key,
q: term.split(' ').join('+')
}
});
var response = await parseString(body, { explicitArray: false });
if(!_.has(response, 'GoodreadsResponse')) throw 'goodreads-error';
var result = response.GoodreadsResponse.search.results;
if(!result || !_.has(result, 'work')) throw 'book-not-found';
if(!result.work[0]) throw 'book-not-found';
return {
id: result.work[0].best_book.id['_'],
title: result.work[0].best_book.title,
author: result.work[0].best_book.author.name,
rating: result.work[0].average_rating
};
},
'getSummaryForBook': async id => {
//https://www.goodreads.com/book/show.xml
var body = await rp({
uri: this.apiRoot + '/book/show.xml',
qs: {
key: this.config.api_key,
id: id
}
});
var response = await parseString(body, { explicitArray: false });
if(!_.has(response, 'GoodreadsResponse')) throw 'goodreads-error';
var result = response.GoodreadsResponse.book;
if(!result) throw 'book-not-found';
if(!_.has(result, 'description')) throw 'no-description';
return result.description;
},
'findAuthor': async term => {
//https://www.goodreads.com/api/author_url/<ID>
var body = await rp({
url: this.apiRoot + '/api/author_url/' + term,
qs: {
key: this.config.api_key
}
});
var response = await parseString(body, {explicitArray: false });
if(!_.has(response, 'GoodreadsResponse')) throw 'goodreads-error';
var result = response.GoodreadsResponse.author;
if(!result) throw 'author-not-found';
return {
id: result['$'].id,
author: result.name
};
},
'getProfileById': async id => {
//https://www.goodreads.com/user/show.xml
try {
var body = await rp({
url: this.apiRoot + '/user/show.xml',
qs: {
key: this.config.api_key,
id: id
}
});
}
catch (e) {
if(e.statusCode && e.statusCode == 404) {
throw 'user-not-found';
return;
}
throw e;
}
var response = await parseString(body, { explicitArray: false });
if(!_.has(response, 'GoodreadsResponse')) throw 'goodreads-error';
var result = response.GoodreadsResponse.user;
if(!result) throw 'user-not-found';
return this.internalAPI.formatProfile(result);
},
'getProfileByName': async username => {
//https://www.goodreads.com/user/show.xml
try {
var body = await rp({
url: this.apiRoot + '/user/show.xml',
qs: {
key: this.config.api_key,
username: username
}
});
}
catch (e) {
if(e.statusCode && e.statusCode == 404) {
throw 'user-not-found';
return;
}
throw e;
}
var response = await parseString(body, { explicitArray: false });
if(!_.has(response, 'GoodreadsResponse')) throw 'goodreads-error';
var result = response.GoodreadsResponse.user;
if(!result) throw 'user-not-found';
return this.internalAPI.formatProfile(result);
},
'getShelfForUserId': async (id, shelf) => {
//https://www.goodreads.com/review/list.xml?v=2
var body = await rp({
url: this.apiRoot + '/review/list.xml',
qs: {
v: '2',
key: this.config.api_key,
id: id,
shelf: shelf
}
});
var response = await parseString(body, { explicitArray: false });
if(!_.has(response, 'GoodreadsResponse')) throw 'goodreads-error';
let result = response.GoodreadsResponse.reviews.review;
if(!result) return [];
if(!_.isArray(result)) {
result = [result];
}
return _.map(result, r => {
return {
id: r.book.id['_'],
title: r.book.title_without_series
};
});
}
};
this.commands = {
'~book' : async evt => {
try {
var book = await this.api.findBook(evt.input[1]);
evt.reply(dbot.t('gr_book', {
author: book.author,
title: book.title,
rating: book.rating,
link: this.apiRoot + '/book/show/' + book.id
}));
}
catch(e) { this.internalAPI.outputError(evt, e); }
},
'~booksummary': async evt => {
try {
var book = await this.api.findBook(evt.input[1]);
var summary = await this.api.getSummaryForBook(book.id);
evt.reply(dbot.t('gr_summary', {
title: book.title,
summary: summary,
link: this.apiRoot + '/book/show/' + book.id
}));
}
catch(e) { this.internalAPI.outputError(evt, e); }
},
'~author' : async evt => {
try {
evt.reply(dbot.t('gr_author', await this.api.findAuthor(evt.input[1])));
}
catch(e) { this.internalAPI.outputError(evt, e); }
},
'~reading': async (evt, profile) => {
try {
let books = await this.api.getShelfForUserId(profile.id, 'currently-reading');
var booksCount = books.length;
if(!booksCount) {
evt.reply(dbot.t('gr_not_reading', { user: evt.rUser.currentNick }));
return;
}
let tooMany = booksCount > 5;
if (tooMany) books = _.sample(books, 5);
evt.reply(dbot.t('gr_is_reading', { user: evt.rUser.currentNick, count: booksCount }));
_.each(books, b => {
evt.reply(ostr = b.title + ' - https://www.goodreads.com/book/show/' + b.id);
});
if (tooMany) {
evt.reply('... And ' + (booksCount - 5) + ' more - https://www.goodreads.com/review/list/' + profile.id + '?shelf=currently-reading');
}
}
catch(e) { this.internalAPI.outputError(evt, e); }
}
};
this.commands['~book'].regex = [/^book (.*)/, 2];
this.commands['~booksummary'].regex = [/^booksummary (.*)/, 2];
this.commands['~author'].regex = [/^author ([\d\w\s-]*)/, 2];
this.commands['~reading'].requiresProfile = true;
_.each(this.commands, ((cmd, cmdName) => {
if(cmd.requiresProfile) {
this.commands[cmdName] = (async evt => {
var grUsername = evt.rProfile.goodreads;
if(!grUsername) {
evt.reply(evt.rUser.currentNick + ': Set a Goodreads username with "~set goodreads username"');
return;
}
let grId = evt.rProfile.goodreads_id;
try {
var profile;
if(grId) {
profile = await this.api.getProfileById(grId);
} else {
profile = await this.api.getProfileByName(grUsername);
grId = profile.id;
dbot.api.profile.setProperty(evt.server, evt.user, 'goodreads_id', grId, function(){});
}
await cmd(evt, profile);
}
catch(e) {
if(e === 'user-not-found') evt.reply('User not found. Is your GoodReads username set correctly?');
else this.internalAPI.outputError(evt, e);
}
}).bind(this);
}
}).bind(this))
}
exports.fetch = dbot => new GoodReads(dbot);

View File

@ -1,23 +0,0 @@
{
"gr_book": {
"en": "[{title} by {author} - {rating}] - {link}"
},
"gr_summary": {
"en": "[{title}] - {summary} - {link}"
},
"gr_author": {
"en": "[{author}] - https://www.goodreads.com/author/show/{id}"
},
"gr_nobook": {
"en": "No book by that name was found."
},
"gr_noauthor": {
"en": "No author by that name was found."
},
"gr_not_reading": {
"en": "{user} is not currently reading any books."
},
"gr_is_reading": {
"en": "{user} is currently reading the following {count} books:"
}
}

View File

@ -1,6 +0,0 @@
{
"~book": "~book [bookname] - returns the title, author, rating, and GoodReads link",
"~booksummary": "~booksummary [bookname] - returns the summary for the requested book",
"~author": "~author [authorname] - returns the GoodReads link for the requested author",
"~reading": "~reading - displays up to 5 of the books you are currently reading"
}

View File

@ -1,49 +0,0 @@
var _ = require('underscore')._;
var api = function(dbot) {
return {
// Is user ignoring command/module?
'isUserIgnoring': function(user, item, callback) {
this.internalAPI.isUserImpeded(user, item, 'ignores', callback);
},
// Is user banned from command/module?
'isUserBanned': function(user, item, callback) {
this.internalAPI.isUserImpeded(user, item, 'bans', callback);
},
// Is channel ignoring module?
// TODO: Command support
'isChannelIgnoring': function(channelName, item, callback) {
var isIgnoring = false,
channel = false;
this.db.search('channel_ignores', {
'server': server,
'name': channel
}, function(result) {
channel = result;
}, function(err) {
if(!err && channel && _.include(channel.ignores, item)) {
isIgnoring = true;
}
callback(isIgnoring);
});
},
// Resolve a nick and return their user and ignores object
'getUserIgnores': function(user, callback) {
this.db.read('ignores', user.id, function(err, ignores) {
if(!err && ignores) {
callback(false, ignores);
} else {
callback(true, null);
}
});
}
};
}
exports.fetch = function(dbot) {
return api(dbot);
};

View File

@ -1,6 +1,6 @@
{ {
"ignorable": false, "ignorable": false,
"dependencies": [ "users" ], "dependencies": [ "command" ],
"dbKeys": [ "ignores", "bans" ], "dbKeys": [ "ignores", "bans" ],
"dbType": "redis" "help": "http://github.com/reality/depressionbot/blob/master/modules/ignore/README.md"
} }

View File

@ -5,35 +5,15 @@
* this information, since that actually performs the ignorance. Also provides * this information, since that actually performs the ignorance. Also provides
* commands for moderators to choose the bot to ignore certain channels. * commands for moderators to choose the bot to ignore certain channels.
*/ */
var _ = require('underscore')._, var _ = require('underscore')._;
databank = require('databank'),
uuid = require('node-uuid'),
NoSuchThingError = databank.NoSuchThingError;
var ignore = function(dbot) { var ignore = function(dbot) {
this.internalAPI = {
'isUserImpeded': function(user, item, by, callback) {
this.api.getUserIgnores(user, function(err, ignores) {
var isImpeded = false;
if(!err && ignores) {
if(_.has(dbot.commands, item) && !_.include(ignores[by], item)) {
item = dbot.commands[item].module;
}
if(_.include(ignores[by], item) || _.include(ignores[by], '*')) {
isImpeded = true;
}
}
callback(isImpeded);
});
}.bind(this)
};
var commands = { var commands = {
'~ignore': function(event) { '~ignore': function(event) {
var module = event.params[1]; var module = event.params[1];
var ignorableModules = _.chain(dbot.modules) var ignorableModules = _.chain(dbot.modules)
.filter(function(module, name) { .filter(function(module, name) {
return dbot.config.modules[module].ignorable === true; return dbot.config[module].ignorable === true;
}) })
.pluck('name') .pluck('name')
.value(); .value();
@ -45,30 +25,21 @@ var ignore = function(dbot) {
})); }));
} else { } else {
if(module == '*' || _.include(ignorableModules, module)) { if(module == '*' || _.include(ignorableModules, module)) {
this.api.getUserIgnores(event.rUser, function(err, ignores) { if(_.has(dbot.db.ignores, event.user) && _.include(dbot.db.ignores[event.user], module)) {
if(!ignores) { event.reply(dbot.t('already_ignoring', { 'user': event.user }));
ignores = { } else {
'id': event.rUser.id, if(_.has(dbot.db.ignores, module)) {
'ignores': [], dbot.db.ignores[event.user].push(module);
'bans': [] } else {
}; dbot.db.ignores[event.user] = [module];
} }
if(!_.include(ignores.ignores, module)) { dbot.instance.ignoreTag(event.user, module);
ignores.ignores.push(module); event.reply(dbot.t('ignored', {
this.db.save('ignores', event.rUser.id, ignores, function(err) { 'user': event.user,
if(!err) { 'module': module
dbot.instance.ignoreTag(event.user, module); }));
event.reply(dbot.t('ignored', { }
'user': event.user,
'module': module
}));
}
});
} else {
event.reply(dbot.t('already_ignoring', { 'user': event.user }));
}
}.bind(this));
} else { } else {
event.reply(dbot.t('invalid_ignore', { 'user': event.user })); event.reply(dbot.t('invalid_ignore', { 'user': event.user }));
} }
@ -76,192 +47,139 @@ var ignore = function(dbot) {
}, },
'~unignore': function(event) { '~unignore': function(event) {
var ignoredModules = [];
if(_.has(dbot.db.ignores, event.user)) {
ignoredModules = dbot.db.ignores[event.user];
}
var module = event.params[1]; var module = event.params[1];
this.api.getUserIgnores(event.rUser, function(err, ignores) { if(_.isUndefined(module)) {
if(err || !ignores || _.isUndefined(module)) { event.reply(dbot.t('unignore_usage', {
if(ignores) { 'user': event.user,
event.reply(dbot.t('unignore_usage', { 'modules': ignoredModules.join(', ')
'user': event.user, }));
'modules': ignores.ignores.join(', ') } else {
})); if(_.include(ignoredModules, module)) {
} else { dbot.db.ignores[event.user].splice(dbot.db.ignores[event.user].indexOf(module), 1);
event.reply(dbot.t('empty_unignore_usage', { dbot.instance.removeIgnore(event.user, module)
'user': event.user event.reply(dbot.t('unignored', {
})); 'user': event.user,
} 'module': module
}));
} else { } else {
if(_.include(ignores.ignores, module)) { event.reply(dbot.t('invalid_unignore', { 'user': event.user }));
ignores.ignores = _.without(ignores.ignores, module);
this.db.save('ignores', event.rUser.id, ignores, function(err) {
if(!err) {
dbot.instance.removeIgnore(event.user, module)
event.reply(dbot.t('unignored', {
'user': event.user,
'module': module
}));
}
});
} else {
event.reply(dbot.t('invalid_unignore', { 'user': event.user }));
}
} }
}.bind(this)); }
}, },
'~ban': function(event) { '~ban': function(event) {
var nick = event.input[1], var user = event.params[1];
item = event.input[2]; var module = event.params[2];
if(item == '*' || _.include(dbot.config.moduleNames, item) || _.include(dbot.commands, item)) { if(_.isUndefined(user) || _.isUndefined(module)) {
dbot.api.users.resolveUser(event.server, nick, function(err, user) { event.reply(dbot.t('ban_usage', {'user': event.user}));
this.api.getUserIgnores(user, function(err, ignores) { return;
if(!ignores) { }
ignores = {
'id': user.id,
'ignores': [],
'bans': []
};
}
if(!_.include(ignores.bans, item)) { if(module == '*' || _.include(dbot.config.moduleNames, module) || _.include(dbot.commands, module)) {
ignores.bans.push(item); if(_.has(dbot.db.bans, user) && _.include(dbot.db.bans[user], module)) {
this.db.save('ignores', user.id, ignores, function(err) { event.reply(dbot.t('already_banned', {
if(!err) { 'user': event.user,
event.reply(dbot.t('banned_success', { 'banned': user
'user': event.user, }));
'banned': nick, return;
'module': item }
}));
} if(_.has(dbot.db.bans, event.params[1])) {
}); dbot.db.bans[event.params[1]].push(module);
} else { } else {
event.reply(dbot.t('already_banned', { dbot.db.bans[event.params[1]] = [module];
'user': event.user, }
'banned': nick
})); event.reply(dbot.t('banned_success', {
} 'user': event.user,
}.bind(this)); 'banned': user,
}.bind(this)); 'module': module
}));
} else { } else {
event.reply(dbot.t('invalid_ban', { 'user': event.user })); event.reply(dbot.t('invalid_ban', {'user': event.user}));
} }
}, },
'~unban': function(event) { '~unban': function(event) {
var nick = event.input[1], var bannedModules = [];
item = event.input[2];
dbot.api.users.resolveUser(event.server, nick, function(err, user) { var user = event.params[1];
this.api.getUserIgnores(user, function(err, ignores) { var module = event.params[2];
if(err || !ignores) {
event.reply(dbot.t('invalid_unban', { if(_.isUndefined(user) || _.isUndefined(module)) {
'user': event.user, event.reply(dbot.t('unban_usage', {'user': event.user}));
'banned': nick } else {
})); if(_.has(dbot.db.bans, user) && _.include(dbot.db.bans[user], module)) {
} else { dbot.db.bans[user].splice(dbot.db.bans[user].indexOf(module), 1);
if(_.include(ignores.bans, item)) {
ignores.bans = _.without(ignores.bans, item); event.reply(dbot.t('unbanned_success', {
this.db.save('ignores', user.id, ignores, function(err) { 'user': event.user,
event.reply(dbot.t('unbanned_success', { 'banned': user,
'user': event.user, 'module': module
'banned': nick, }));
'module': item } else {
})); event.reply(dbot.t('invalid_unban', {
}); 'user': event.user,
} else { 'banned': user
event.reply(dbot.t('invalid_unban', { }));
'user': event.user, }
'banned': nick }
}));
}
}
}.bind(this));
}.bind(this));
}, },
'~ignorechannel': function(event) { '~ignorechannel': function(event) {
var channelName = event.input[1], var channel = ((event.params[1] == '@') ? event.channel.name : event.params[1]);
module = event.input[2]; var module = event.params[2];
// Ignoring the value of 'ignorable' at the moment // Ignoring the value of 'ignorable' at the moment
if(module == '*' || _.include(dbot.config.moduleNames, module)) { if(module == '*' || _.include(dbot.config.moduleNames, module)) {
var channel = false; if(!_.has(dbot.db.ignores, channel)) dbot.db.ignores[channel] = [];
if(!_.include(dbot.db.ignores[channel], module)) {
this.db.search('channel_ignores', { dbot.db.ignores[channel].push(module);
'server': event.server, dbot.instance.ignoreTag(channel, module);
'name': channelName event.reply(dbot.t('ignoring_channel', {
}, function(result) { 'module': module,
channel = result; 'channel': channel
}, function(err) { }));
if(!channel) { } else {
var id = uuid.v4(); event.reply(dbot.t('already_ignoring_channel', {
channel = { 'module': module,
'id': id, 'channel': channel
'server': event.server, }));
'name': channelName, }
'ignores': []
};
}
if(!_.include(channel.ignores, module)) {
channel.ignores.push(module);
this.db.save('channel_ignores', channel.id, channel, function(err) {
dbot.instance.ignoreTag(channel.name, module);
event.reply(dbot.t('ignoring_channel', {
'module': module,
'channel': channelName
}));
});
} else {
event.reply(dbot.t('already_ignoring_channel', {
'module': module,
'channel': channelName
}));
}
}.bind(this));
} else { } else {
event.reply(dbot.t('module_not_exist', { 'module': module })); event.reply(dbot.t('module_not_exist', { 'module': module }));
} }
}, },
'~unignorechannel': function(event) { '~unignorechannel': function(event) {
var channelName = event.input[1], var channel = ((event.params[1] == '@') ? event.channel.name : event.params[1]);
module = event.input[2], var module = event.params[2];
channel = false;
this.db.search('channel_ignores', { if(!_.has(dbot.db.ignores, channel)) dbot.db.ignores[channel] = [];
'server': event.server, if(_.include(dbot.db.ignores[channel], module)) {
'name': channelName dbot.db.ignores[channel] = _.without(dbot.db.ignores[channel], module);
}, function(result) { dbot.instance.removeIgnore(channel, module);
channel = result; event.reply(dbot.t('unignoring_channel', {
}, function(err) { 'module': module,
if(channel && _.include(channel.ignores, module)) { 'channel': channel
channel.ignores = _.without(channel.ignores, module); }));
this.db.save('channel_ignores', channel.id, channel, function(err) { } else {
dbot.instance.removeIgnore(channel.name, module); event.reply(dbot.t('not_ignoring_channel', {
event.reply(dbot.t('unignoring_channel', { 'module': module,
'module': module, 'channel': channel
'channel': channelName }));
})); }
});
} else {
event.reply(dbot.t('not_ignoring_channel', {
'module': module,
'channel': channelName
}));
}
}.bind(this));
} }
}; };
commands['~ban'].regex = [/^ban ([^ ]+) ([^ ]+)$/, 3]; commands['~ban'].access = 'moderator';
commands['~unban'].regex = [/^unban ([^ ]+) ([^ ]+)$/, 3]; commands['~unban'].access = 'moderator';
commands['~ignorechannel'].regex = [/^ignorechannel ([^ ]+) ([^ ]+)$/, 3];
commands['~unignorechannel'].regex = [/^unignorechannel ([^ ]+) ([^ ]+)$/, 3];
commands['~ban'].access = 'power_user';
commands['~unban'].access = 'power_user';
commands['~ignorechannel'].access = 'moderator'; commands['~ignorechannel'].access = 'moderator';
commands['~unignorechannel'].access = 'moderator'; commands['~unignorechannel'].access = 'moderator';
@ -269,34 +187,12 @@ var ignore = function(dbot) {
this.onLoad = function() { this.onLoad = function() {
dbot.instance.clearIgnores(); dbot.instance.clearIgnores();
_.each(dbot.db.ignores, function(ignores, item) {
this.db.scan('ignores', function(ignores) { _.each(ignores, function(ignore) {
dbot.api.users.getUser(ignores.id, function(err, user) { dbot.instance.ignoreTag(item, ignore);
if(user) { }, this);
_.each(ignores.ignores, function(module) { }, this);
dbot.instance.ignoreTag(user.currentNick, module); };
});
}
});
}, function(err) { });
this.db.scan('channel_ignores', function(channel) {
_.each(channel.ignores, function(module) {
dbot.instance.ignoreTag(channel.name, module);
});
}, function(err) { });
dbot.api.event.addHook('new_current_nick', function(user, oldNick) {
this.api.getUserIgnores(user, function(err, ignores) {
if(ignores) {
_.each(ignores.ignores, function(module) {
dbot.instance.removeIgnore(oldNick, module);
dbot.instance.ignoreTag(user.currentNick, module);
});
}
}.bind(this));
}.bind(this));
}.bind(this);
}; };
exports.fetch = function(dbot) { exports.fetch = function(dbot) {

View File

@ -5,9 +5,7 @@
"na'vi": "{user}: Sar: ~ignore ['u]. U, nga ke tìng mikyun: {modules}.", "na'vi": "{user}: Sar: ~ignore ['u]. U, nga ke tìng mikyun: {modules}.",
"cy": "{user}: Defnydd: ~ignore [modiwl]. Modiwlau a allech anwybyddu yw: {modules}.", "cy": "{user}: Defnydd: ~ignore [modiwl]. Modiwlau a allech anwybyddu yw: {modules}.",
"nl": "{user}: Gebruik: ~ignore [module]. Modules die negeert kunnen worden zijn: {modules}.", "nl": "{user}: Gebruik: ~ignore [module]. Modules die negeert kunnen worden zijn: {modules}.",
"de": "{user}: Benutzung: ~ignore [module]. Module, die ausgeschaltet werden können: {modules}.", "de": "{user}: Benutzung: ~ignore [module]. Module, die ignoriert werden können: {modules}."
"fr": "{user}: Utilisation: ~ignore [module]. Les modules que vous pouvez ignorer sont: {modules}.",
"it": "{user}: Uso: ~ignore [module]. I moduli che puoi ignorare sono: {modules}."
}, },
"already_ignoring": { "already_ignoring": {
"en": "{user}: You're already ignoring that module.", "en": "{user}: You're already ignoring that module.",
@ -15,9 +13,7 @@
"na'vi": "{user}: 'uri nga ke tìng mikyun srekrr.", "na'vi": "{user}: 'uri nga ke tìng mikyun srekrr.",
"cy": "{user}: Mi rwyt ti'n anwybyddu'r modiwl yna'n barod.", "cy": "{user}: Mi rwyt ti'n anwybyddu'r modiwl yna'n barod.",
"nl": "{user}: Je negeert deze module al.", "nl": "{user}: Je negeert deze module al.",
"de": "{user}: Dieses Modul ist bereits ausgeschaltet.", "de": "{user}: Dieses Modul wird bereits ignoriert."
"fr": "{user}: Vous ignorez déjà ce module.",
"it": "{user}: Stai già ignorando questo modulo"
}, },
"ignored": { "ignored": {
"en": "{user}: Now ignoring {module}.", "en": "{user}: Now ignoring {module}.",
@ -25,9 +21,7 @@
"na'vi": "{user}: Nga ke terìng mikyun {module}ne set.", "na'vi": "{user}: Nga ke terìng mikyun {module}ne set.",
"cy": "{user}: Nawr yn anwybyddu {module}", "cy": "{user}: Nawr yn anwybyddu {module}",
"nl": "{user}: {module} wordt nu genegeerd.", "nl": "{user}: {module} wordt nu genegeerd.",
"de": "{user}: {module} wird nun ausgeschaltet.", "de": "{user}: {module} wird nun ignoriert."
"fr": "{user}: {module} désormais ignoré.",
"it": "{user}: {module} sarà adesso ignorato"
}, },
"invalid_ignore": { "invalid_ignore": {
"en": "{user}: That isn't a valid module name.", "en": "{user}: That isn't a valid module name.",
@ -35,9 +29,7 @@
"na'vi": "{user}: Tsatstxo eyawr ke lu.", "na'vi": "{user}: Tsatstxo eyawr ke lu.",
"cy": "{user}: Nid oedd hwna'n modiwl dilys", "cy": "{user}: Nid oedd hwna'n modiwl dilys",
"nl": "{user}: Dat is geen geldige modulenaam.", "nl": "{user}: Dat is geen geldige modulenaam.",
"de": "{user}: Dies ist kein Name eines Moduls.", "de": "{user}: Dies ist nicht der Name eines Moduls."
"fr": "{user}: Ceci ne correspond pas à un nom de module valide.",
"it": "{user}: Questo non è un nome di modulo valido"
}, },
"unignore_usage": { "unignore_usage": {
"en": "{user}: Usage: ~unignore [module]. Modules you are currently ignoring: {modules}.", "en": "{user}: Usage: ~unignore [module]. Modules you are currently ignoring: {modules}.",
@ -45,19 +37,7 @@
"na'vi": "{user}: Sar: ~unignore ['u]. Uri, nga ke terìng mikyun: {modules}.", "na'vi": "{user}: Sar: ~unignore ['u]. Uri, nga ke terìng mikyun: {modules}.",
"cy": "{user}: Defnydd: ~unignore [modiwl]. Modiwlau rydech yn anwybyddu ar hyn o bryd: {modules}", "cy": "{user}: Defnydd: ~unignore [modiwl]. Modiwlau rydech yn anwybyddu ar hyn o bryd: {modules}",
"nl": "{user}: Gebruik: ~unignore [module]. Modules die momenteel worden genegeerd: {modules}.", "nl": "{user}: Gebruik: ~unignore [module]. Modules die momenteel worden genegeerd: {modules}.",
"de": "{user}: Benutzung: ~unignore [module]. Module, die im Moment ausgeschaltet sind: {modules}.", "de": "{user}: Benutzung: ~unignore [module]. Module, die im Moment ignoriert werden: {modules}."
"fr": "{user}: Utilisation: ~unignore [module]. Modules que vous ignorez actuellement: {modules}.",
"it": "{user}: Uso: ~unignore [module]. Module che ignori attualmente: {modules}."
},
"empty_unignore_usage": {
"en": "{user}: Usage: ~unignore [module].",
"es": "{user}: Modo de empleo: ~unignore [módulo].",
"na'vi": "{user}: Sar: ~unignore ['u].",
"cy": "{user}: Defnydd: ~unignore [modiwl].",
"nl": "{user}: Gebruik: ~unignore [module].",
"de": "{user}: Benutzung: ~unignore [module].",
"fr": "{user}: Utilisation: ~unignore [module].",
"it": "{user}: Uso: ~unignore [module]."
}, },
"invalid_unignore": { "invalid_unignore": {
"en": "{user}: You're not ignoring that module or it doesn't exist.", "en": "{user}: You're not ignoring that module or it doesn't exist.",
@ -65,9 +45,7 @@
"na'vi":"{user}: Nga terìng mikyun fu fì'ul fìtsengit ke tok.", "na'vi":"{user}: Nga terìng mikyun fu fì'ul fìtsengit ke tok.",
"cy": "{user}: Nid wyt ti'n anwybyddu'r modiwl yna neu nid yw e'n bodoli", "cy": "{user}: Nid wyt ti'n anwybyddu'r modiwl yna neu nid yw e'n bodoli",
"nl": "{user}: Deze module bestaat niet of wordt niet genegeerd.", "nl": "{user}: Deze module bestaat niet of wordt niet genegeerd.",
"de": "{user}: Dieses Modul ist entweder ausgeschaltet oder existiert nicht.", "de": "{user}: Dieses Modul wird entweder nicht ignoriert oder existiert nicht."
"fr": "{user}: Vous n'ignorez pas ce module ou il n'existe pas.",
"it": "{user}: Non stai ignorando questo modulo o non esiste."
}, },
"unignored": { "unignored": {
"en": "{user}: No longer ignoring {module}.", "en": "{user}: No longer ignoring {module}.",
@ -75,109 +53,83 @@
"na'vi": "{user}: Nga terìng mikyun {module}ne set", "na'vi": "{user}: Nga terìng mikyun {module}ne set",
"cy": "{user}: Ddim yn anwybyddu {module} bellach", "cy": "{user}: Ddim yn anwybyddu {module} bellach",
"nl": "{user}: {module} wordt niet langer genegeerd.", "nl": "{user}: {module} wordt niet langer genegeerd.",
"de": "{user}: {module} ist nicht länger ausgeschaltet.", "de": "{user}: {module} wird nicht länger ignoriert."
"fr": "{user}: {module} n'est plus ignoré à présent.",
"it": "{user}: {module} non viene attualmente più ignorato"
}, },
"ban_usage": { "ban_usage": {
"en": "{user}: Usage: ~ban [user] [module/command]. Use * for all modules and commands.", "en": "{user}: Usage: ~ban [user] [module/command]. Use * for all modules and commands.",
"cy": "{user}: Defnydd: ~ban [defnyddiwr] [modiwl/gorchymyn]. Defnyddio * am pob modiwlau a gorchmynion.", "cy": "{user}: Defnydd: ~ban [defnyddiwr] [modiwl/gorchymyn]. Defnyddio * am pob modiwlau a gorchmynion.",
"nl": "{user}: Gebruik: ~ban [gebruiker] [module/commando]. Gebruik * voor alle modules en alle commandos.", "nl": "{user}: Gebruik: ~ban [gebruiker] [module/commando]. Gebruik * voor alle modules en alle commandos.",
"de": "{user}: Benutzung ~ban [Benutzer] [module/Befehl]. Benutze * für alle Module und Befehle.", "de": "{user}: Benutzung ~ban [Benutzer] [module/Befehl]. Benutze * für alle Module und Befehle."
"fr": "{user}: Utilisation: ~ban [user] [module/command]. Utilisez * pour tous les modules et commandes.",
"it": "{user}: Uso: ~ban [user] [module/command]. Utilizza * per tutti i moduli e commandi."
}, },
"already_banned": { "already_banned": {
"en": "{user}: {banned} is already banned from that module.", "en": "{user}: {banned} is already banned from that module.",
"cy": "{user}: {banned} eisoes wedi ei wahardd o'r modiwl.", "cy": "{user}: {banned} eisoes wedi ei wahardd o'r modiwl.",
"nl": "{user}: {banned} is al geband van deze module.", "nl": "{user}: {banned} is al geband van deze module.",
"de": "{user}: {banned} ist bereits von diesem Modul gebannt.", "de": "{user}: {banned} ist bereits von diesem Modul gebannt."
"fr": "{user}: {banned} est déjà interdit d'utiliser ce module.",
"it": "{user}: {banned} è già bandito da usare questo modulo."
}, },
"banned_success": { "banned_success": {
"en": "{user}: {banned} is now banned from {module}.", "en": "{user}: {banned} is now banned from {module}.",
"cy": "{user}: {banned} ei wahardd yn awr am {module}.", "cy": "{user}: {banned} ei wahardd yn awr am {module}.",
"nl": "{user}: {banned} mag {module} nu niet meer gebruiken.", "nl": "{user}: {banned} mag {module} nu niet meer gebruiken.",
"de": "{user}: {banned} ist nun von {module} gebannt.", "de": "{user}: {banned} ist nun von {module} gebannt."
"fr": "{user}: {banned} est maintenant interdit d'utiliser {module}.",
"it": "{user}: {banned} è stato adesso bandito da usare {module}."
}, },
"invalid_ban": { "invalid_ban": {
"en": "{user}: That isn't a valid module name.", "en": "{user}: That isn't a valid module name.",
"cy": "{user}: Nid oedd hwna'n modiwl dilys", "cy": "{user}: Nid oedd hwna'n modiwl dilys",
"nl": "{user}: Dat is geen geldige modulenaam.", "nl": "{user}: Dat is geen geldige modulenaam.",
"de": "{user}: Dies ist kein Name eines Moduls.", "de": "{user}: Dies ist nicht der Name eines Moduls."
"fr": "{user}: Ceci n'est pas un nom de module valide.",
"it": "{user}: Queso non è il nome di un modulo valido."
}, },
"unban_usage": { "unban_usage": {
"en": "{user}: Usage: ~unban [user] [module].", "en": "{user}: Usage: ~unban [user] [module].",
"cy": "{user}: Defnydd: ~unban [defnyddiwr] [modiwl].", "cy": "{user}: Defnydd: ~unban [defnyddiwr] [modiwl].",
"nl": "{user}: Gebruik: ~unban [gebruiker] [module].", "nl": "{user}: Gebruik: ~unban [gebruiker] [module].",
"de": "{user}: Benutzung: ~unban [Benutzer] [module].", "de": "{user}: Benutzung: ~unban [Benutzer] [module]."
"fr": "{user}: Utilisation: ~unban [user] [module].",
"it": "{user}: Uso: ~unban [user] [module]."
}, },
"invalid_unban": { "invalid_unban": {
"en": "{user}: {banned} is not banned from that module or it doesn't exist.", "en": "{user}: {banned} is not banned from that module or it doesn't exist.",
"cy": "{user}: Nid oedd {banned} wedi ei wahardd o'r modiwl, neu nid yw'n bodoli.", "cy": "{user}: Nid oedd {banned} wedi ei wahardd o'r modiwl, neu nid yw'n bodoli.",
"nl": "{user}: {banned} is niet geband van die module of de module bestaat niet.", "nl": "{user}: {banned} is niet geband van die module of de module bestaat niet.",
"de": "{user}: {banned} ist von diesem Modul nicht gebannt, oder es existiert nicht.", "de": "{user}: {banned} ist von diesem Modul nicht gebannt, oder es existiert nicht."
"fr": "{user}: {banned} n'est pas interdit d'utiliser ce module, ou il n'existe pas.",
"it": "{user}: {banned} non è stato bandito da questo modulo o non esiste."
}, },
"unbanned_success": { "unbanned_success": {
"en": "{user}: {banned} is no longer banned from {module}.", "en": "{user}: {banned} is no longer banned from {module}.",
"cy": "{user}: Nid yw {banned} yn cael ei wahardd mwyach.", "cy": "{user}: Nid yw {banned} yn cael ei wahardd mwyach.",
"nl": "{user}: {banned} mag {module} weer gebruiken.", "nl": "{user}: {banned} mag {module} weer gebruiken.",
"de": "{user}: {banned} wurde von {module} entbannt.", "de": "{user}: {banned} wurde von {module} entbannt."
"fr": "{user}: {banned} n'est plus interdit d'utiliser {module}.",
"it": "{user}: {banned} non è più bandito dall' utilizzare {module}."
}, },
"ignoring_channel": { "ignoring_channel": {
"en": "Now ignoring {module} in {channel}.", "en": "Now ignoring {module} in {channel}.",
"na'vi": "Oe ke stayawm {module}ur mì {channel}", "na'vi": "Oe ke stayawm {module}ur mì {channel}",
"cy": "Bellach yn anwybyddu {module} yn {channel}.", "cy": "Bellach yn anwybyddu {module} yn {channel}.",
"nl": "{module} wordt nu genegeerd in {channel}.", "nl": "{module} wordt nu genegeerd in {channel}.",
"de": "{module} in {channel} ist nun ausgeschaltet.", "de": "{module} in [channel} wird nun ignoriert."
"fr": "{module} dans {channel} maintenant ignoré.",
"it": "{module} in {channel} viene adesso ignorato."
}, },
"already_ignoring_channel": { "already_ignoring_channel": {
"en": "Already ignoring {module} in {channel}.", "en": "Already ignoring {module} in {channel}.",
"na'vi": "Oe ke stayawm {module}ur mì {channel} li", "na'vi": "Oe ke stayawm {module}ur mì {channel} li",
"cy": "Eisoes anwybyddu {module} yn {channel}", "cy": "Eisoes anwybyddu {module} yn {channel}",
"nl": "{module} wordt al genegeerd in {channel}.", "nl": "{module} wordt al genegeerd in {channel}.",
"de": "{module} in {channel} ist bereits ausgeschaltet.", "de": "{module} in {channel} wird bereits ignoriert."
"fr": "{module} dans {channel} déjà ignoré.",
"it": "{module} in {channel} già ignorato."
}, },
"module_not_exist": { "module_not_exist": {
"en": "{module} isn't loaded or doesn't exist.", "en": "{module} isn't loaded or doesn't exist.",
"na'vi": "Oel ke omum teri {module}it fu {module} ke fkeytok", "na'vi": "Oel ke omum teri {module}it fu {module} ke fkeytok",
"cy": "Dydy {module} ddim yn lwythodd, neu ddim yn bodoli.", "cy": "Dydy {module} ddim yn lwythodd, neu ddim yn bodoli.",
"nl": "{module} is niet geladen of bestaat niet.", "nl": "{module} is niet geladen of bestaat niet.",
"de": "{module} ist nicht geladen oder existiert nicht.", "de": "{module} ist nicht geladen oder existiert nicht."
"fr": "{module} n'est pas chargé ou n'existe pas.",
"it": "{module} non caricato o non esiste"
}, },
"unignoring_channel": { "unignoring_channel": {
"en": "No longer ignoring {module} in {channel}.", "en": "No longer ignoring {module} in {channel}.",
"na'vi": "Oel stayawm {module}ur mì {channel} set.", "na'vi": "Oel stayawm {module}ur mì {channel} set.",
"cy": "Nid anwybyddu {module} yn {channel} mwyach.", "cy": "Nid anwybyddu {module} yn {channel} mwyach.",
"nl": "{module} wordt niet meer genegeerd in {channel}.", "nl": "{module} wordt niet meer genegeerd in {channel}.",
"de": "{module} in {channel} ist nicht länger ausgeschaltet.", "de": "{module} in {channel} wird nicht länger ignoriert."
"fr": "{module} dans {channel} n'est plus ignoré à présent.",
"it": "{module} in {channel} non viene più ignorato."
}, },
"not_ignoring_channel": { "not_ignoring_channel": {
"en": "{module} wasn't being ignored in {channel}.", "en": "{module} wasn't being ignored in {channel}.",
"na'vi": "Oel stayawm {module}ur mì {channel} li.", "na'vi": "Oel stayawm {module}ur mì {channel} li.",
"cy": "Nid yw {module} yn cael ei anwybyddu yn {channel}.", "cy": "Nid yw {module} yn cael ei anwybyddu yn {channel}.",
"nl": "{module} werd niet genegeerd in {channel}.", "nl": "{module} werd niet genegeerd in {channel}.",
"de": "{module} war in {channel} nicht ausgeschaltet.", "de": "{module} wurde in {channel} nicht ignoriert."
"fr": "{module} n'était pas ignoré dans {channel}.",
"it": "{module} non veniva ignorato in {channel}"
} }
} }

View File

@ -1,8 +1,7 @@
{ {
"dbKeys": [ "imgur" ], "dbKeys": [ "imgur" ],
"dependencies": [ "web", "api", "link" ], "dependencies": [ "web", "api" ],
"imagelength": 5, "imagelength": 5,
"ricachelength": 7,
"nsfwwarn": true, "nsfwwarn": true,
"apikey": "86fd3a8da348b65", "apikey": "86fd3a8da348b65",
"highscore": "ricount", "highscore": "ricount",

View File

@ -5,29 +5,14 @@
var _ = require('underscore')._, var _ = require('underscore')._,
request = require('request'), request = require('request'),
async = require('async'), crypto = require('crypto');
crypto = require('crypto'),
humanise = require('humanize');
var imgur = function(dbot) { var imgur = function(dbot) {
this.ApiRoot = 'https://api.imgur.com/3/'; this.db = dbot.db.imgur;
this.ExcludeRes = [
{ 'w': 800, 'h': 600 },
{ 'w': 1024, 'h': 768 },
{ 'w': 1280, 'h': 768 },
{ 'w': 1280, 'h': 960 },
{ 'w': 1366, 'h': 768 },
{ 'w': 1600, 'h': 900 },
{ 'w': 1680, 'h': 1050 },
{ 'w': 1920, 'h': 1080 },
{ 'w': 1024, 'h': 640 }
];
this.riCache = [];
this.internalAPI = { this.internalAPI = {
'infoString': function(imgData) { 'infoString': function(imgData) {
info = ''; info = '';
if(!_.isUndefined(imgData) && _.has(imgData, 'data') && !_.isUndefined(imgData.data.type)) { if(imgData && _.has(imgData, 'data') && !_.isUndefined(imgData.data.type)) {
imgData = imgData.data; imgData = imgData.data;
if(imgData.title) { if(imgData.title) {
info += imgData.title + ' - '; info += imgData.title + ' - ';
@ -43,8 +28,6 @@ var imgur = function(dbot) {
} }
info += imgData.views + ' views ('; info += imgData.views + ' views (';
info += imgData.width + 'x' + imgData.height + ')'; info += imgData.width + 'x' + imgData.height + ')';
info += ' ('+humanise.filesize(imgData.size)+')';
} }
return info; return info;
@ -52,13 +35,13 @@ var imgur = function(dbot) {
'albumInfoString': function(albumData) { 'albumInfoString': function(albumData) {
var info = ''; var info = '';
if(!_.isUndefined(albumData) && _.has(albumData, 'data') && !_.isUndefined(albumData.data.id)) { if(albumData && _.has(albumData, 'data') && !_.isUndefined(albumData.data.id)) {
albumData = albumData.data; albumData = albumData.data;
if(albumData.title) { if(albumData.title) {
info += albumData.title + ' - '; info += albumData.title + ' - ';
} }
if(albumData.description) { if(albumData.description) {
info += albumData.description.split('\n')[0] + ' is '; info += albumData.description + ' is ';
} }
info += 'an album with ' + albumData.images_count + ' images '; info += 'an album with ' + albumData.images_count + ' images ';
info += 'and ' + albumData.views + ' views'; info += 'and ' + albumData.views + ' views';
@ -71,7 +54,7 @@ var imgur = function(dbot) {
'galleryInfoString': function(galData) { 'galleryInfoString': function(galData) {
var info = ''; var info = '';
if(!_.isUndefined(galData) && _.has(galData, 'data') && !_.isUndefined(galData.data.is_album)) { if(galData && _.has(galData, 'data') && !_.isUndefined(galData.data.is_album)) {
if(galData.data.is_album === true) { if(galData.data.is_album === true) {
info = this.internalAPI.albumInfoString(galData); info = this.internalAPI.albumInfoString(galData);
} else { } else {
@ -93,54 +76,32 @@ var imgur = function(dbot) {
var testSlug = random(5); var testSlug = random(5);
var testUrl = 'http://i.imgur.com/' + var testUrl = 'http://i.imgur.com/' +
testSlug + testSlug +
'.' + ext[_.random(0, ext.length - 1)], '.' + ext[_.random(0, ext.length - 1)];
fbman = false; this.db.totalHttpRequests += 1;
dbot.db.imgur.totalHttpRequests += 1; var image = request(testUrl, function(error, response, body) {
request(testUrl, function(error, response, body) {
// 492 is body.length of a removed image // 492 is body.length of a removed image
if(!error && response.statusCode == 200 && body.length != 492) { if(!error && response.statusCode == 200 && body.length != 492) {
dbot.db.imgur.totalImages += 1; this.db.totalImages += 1;
var hash = crypto.createHash('md5').update(body).digest("hex"); var hash = crypto.createHash('md5').update(body).digest("hex");
if(_.has(dbot.modules, 'quotes')){ if(_.has(dbot.modules, 'quotes')){
// autoadd: {"abcdef": "facebookman"} // autoadd: {"abcdef": "facebookman"}
if(_.has(dbot.config.modules.imgur.autoadd,hash)){ if(_.has(dbot.config.imgur.autoadd,hash)){
fbman = true; var category = dbot.config.imgur.autoadd[hash];
var category = this.config.autoadd[hash];
if (_.contains(category, testUrl)){ if (_.contains(category, testUrl)){
// there's probably less than 62^5 chance of this happening // there's probably less than 62^5 chance of this happening
} else { } else {
dbot.api.quotes.addQuote(category, testUrl, if(!_.has(dbot.db.quoteArrs, category)) dbot.db.quoteArrs[category] = [];
dbot.config.name, function() { }); dbot.db.quoteArrs[category].push(testUrl);
} }
} }
} }
callback(testUrl, testSlug, hash, fbman); callback(testUrl, testSlug,hash);
} else { } else {
this.api.getRandomImage(callback); this.api.getRandomImage(callback);
} }
}.bind(this)); }.bind(this));
}, },
'getGoodRandomImage': function(callback) {
this.api.getRandomImage(function(url, slug, hash, fbman) {
this.api.getImageInfo(slug, function(imgData) {
if(!_.isUndefined(imgData) &&
imgData.data &&
imgData.data.height > 500 && imgData.data.width > 500 &&
!_.any(this.ExcludeRes, function(res) {
return imgData.data.height == res.h && imgData.data.width == res.w;
})) {
callback(url, imgData);
} else if(fbman === true) {
callback(url, imgData);
} else {
this.api.getGoodRandomImage(callback);
}
}.bind(this));
}.bind(this));
},
'getImageInfoString': function(slug, callback) { 'getImageInfoString': function(slug, callback) {
this.api.getImageInfo(slug, function(imgData) { this.api.getImageInfo(slug, function(imgData) {
callback(this.internalAPI.infoString(imgData)); callback(this.internalAPI.infoString(imgData));
@ -152,10 +113,10 @@ var imgur = function(dbot) {
'url': 'https://api.imgur.com/3/image/' + slug + '.json', 'url': 'https://api.imgur.com/3/image/' + slug + '.json',
'json': true, 'json': true,
'headers': { 'headers': {
'Authorization': 'Client-ID ' + this.config.apikey 'Authorization': 'Client-ID ' + dbot.config.imgur.apikey
} }
}, function(err, response, body) { }, function(err, response, body) {
dbot.db.imgur.totalApiRequests += 1; this.db.totalApiRequests += 1;
callback(body); callback(body);
}.bind(this)); }.bind(this));
}, },
@ -165,7 +126,7 @@ var imgur = function(dbot) {
'url': 'https://api.imgur.com/3/album/' + slug + '.json', 'url': 'https://api.imgur.com/3/album/' + slug + '.json',
'json': true, 'json': true,
'headers': { 'headers': {
'Authorization': 'Client-ID ' + this.config.apikey 'Authorization': 'Client-ID ' + dbot.config.imgur.apikey
} }
}, function(err, response, body) { }, function(err, response, body) {
this.db.totalApiRequests += 1; this.db.totalApiRequests += 1;
@ -178,7 +139,7 @@ var imgur = function(dbot) {
'url': 'https://api.imgur.com/3/gallery/' + slug + '.json', 'url': 'https://api.imgur.com/3/gallery/' + slug + '.json',
'json': true, 'json': true,
'headers': { 'headers': {
'Authorization': 'Client-ID ' + this.config.apikey 'Authorization': 'Client-ID ' + dbot.config.imgur.apikey
} }
}, function(err, response, body) { }, function(err, response, body) {
this.db.totalApiRequests += 1; this.db.totalApiRequests += 1;
@ -193,95 +154,17 @@ var imgur = function(dbot) {
this.commands = { this.commands = {
'~ri': function(event) { '~ri': function(event) {
var local = event.user;
if(event.params[1]) {
local = event.params.splice(1, event.params.length - 1).join(' ').trim();
}
var postImage = function(link, imgData) {
var info = this.internalAPI.infoString(imgData);
event.reply('['+this.config.outputPrefix + '] ' + local + ': ' + link + ' [' + info + ']');
}.bind(this);
var newCacheImage = function(link, imgData) {
this.riCache.push([link, imgData]);
}.bind(this);
var callback = postImage;
if(this.riCache.length > 0) {
var image = this.riCache.pop();
postImage(image[0], image[1]);
callback = newCacheImage;
}
this.api.getGoodRandomImage(callback);
},
// Legacy RI
'~lri': function(event) {
var local = event.user;
if(event.params[1]) {
local = event.params.splice(1, event.params.length - 1).join(' ').trim();
}
this.api.getRandomImage(function(link, slug) { this.api.getRandomImage(function(link, slug) {
this.api.getImageInfo(slug, function(imgData) { this.api.getImageInfo(slug, function(imgData) {
var info = this.internalAPI.infoString(imgData); var info = this.internalAPI.infoString(imgData);
event.reply('['+this.config.outputPrefix + '] ' + local + ': ' + link + ' [' + info + ']'); event.reply(event.user + ': ' + link + ' [' + info + ']');
}.bind(this)); }.bind(this));
}.bind(this)); }.bind(this));
},
// Super RI
'~sri': function(event) {
var local = event.user;
if(event.params[1]) {
local = event.params.splice(1, event.params.length - 1).join(' ').trim();
}
request.get({
'url': this.ApiRoot + 'gallery/random/random/',
'json': true,
'headers': {
'Authorization': 'Client-ID ' + this.config.apikey
}
}, function(err, response, body) {
if(!_.isUndefined(body) && body.data && body.data[0] != undefined) {
var num = _.random(0, body.data.length - 1);
this.api.getGalleryInfo(body.data[num].id, function(gal) {
event.reply('['+this.config.outputPrefix + '] ' + local + ': ' + gal.data.link + ' [' +
this.internalAPI.galleryInfoString(gal) + ']');
}.bind(this));
}
}.bind(this));
},
'~imgur': function(event) {
var term = event.input[1];
request.get({
'url': this.ApiRoot + 'gallery/search/',
'json': true,
'headers': {
'Authorization': 'Client-ID ' + this.config.apikey
},
'qs': {
'q': term
}
}, function(err, response, body) {
if(!_.isUndefined(body) && body.data && body.data[0] != undefined) {
var num = _.random(0, body.data.length - 1);
this.api.getGalleryInfo(body.data[num].id, function(gal) {
event.reply(dbot.t('imgurinfo', {
'info': this.internalAPI.galleryInfoString(gal)
}) + ' - ' + gal.data.link);
}.bind(this));
} else {
event.reply(dbot.t('imgur_noresults'));
}
}.bind(this));
} }
} }
this.commands['~imgur'].regex = [/^imgur ([\d\w\s-]*)/, 2];
this.onLoad = function() { this.onLoad = function() {
var imgurHandler = function(matches, name, callback) { var imgurHandler = function(event, matches, name) {
if(matches[1]) { if(matches[1]) {
var dataCallback = function(data) { var dataCallback = function(data) {
var info; var info;
@ -293,7 +176,7 @@ var imgur = function(dbot) {
info = this.internalAPI.galleryInfoString(data); info = this.internalAPI.galleryInfoString(data);
} }
if(info) callback(dbot.t('imgurinfo', { 'info': info })); if(info) event.reply(dbot.t('imgurinfo', { 'info': info }));
}.bind(this); }.bind(this);
if(name == 'imgurimage') { if(name == 'imgurimage') {
@ -311,17 +194,9 @@ var imgur = function(dbot) {
dbot.api.link.addHandler('imgurimage', /https?:\/\/i\.imgur\.com\/([a-zA-Z0-9]+)\.([jpg|png|gif])/, imgurHandler); dbot.api.link.addHandler('imgurimage', /https?:\/\/i\.imgur\.com\/([a-zA-Z0-9]+)\.([jpg|png|gif])/, imgurHandler);
dbot.api.link.addHandler('imgurimage', /https?:\/\/imgur\.com\/([a-zA-Z0-9]+)/, imgurHandler); dbot.api.link.addHandler('imgurimage', /https?:\/\/imgur\.com\/([a-zA-Z0-9]+)/, imgurHandler);
async.times(this.config.ricachelength, function(n, next) {
this.api.getGoodRandomImage(function(link, imgData) {
this.riCache.push([ link, imgData ]);
next();
}.bind(this));
}.bind(this), function() {});
if(!_.has(dbot.db.imgur, 'totalHttpRequests')) dbot.db.imgur.totalHttpRequests = 0; if(!_.has(dbot.db.imgur, 'totalHttpRequests')) dbot.db.imgur.totalHttpRequests = 0;
if(!_.has(dbot.db.imgur, 'totalApiRequests')) dbot.db.imgur.totalApiRequests = 0; if(!_.has(dbot.db.imgur, 'totalApiRequests')) dbot.db.imgur.totalApiRequests = 0;
if(!_.has(dbot.db.imgur, 'totalImages')) dbot.db.imgur.totalImages = 0; if(!_.has(dbot.db.imgur, 'totalImages')) dbot.db.imgur.totalImages = 0;
this.db = dbot.db.imgur;
}.bind(this); }.bind(this);
}; };

View File

@ -3,7 +3,13 @@ var _ = require('underscore')._;
var pages = function(dbot) { var pages = function(dbot) {
return { return {
'/imgur/random': function(req, res) { '/imgur/random': function(req, res) {
var highScore = 0; var quoteCat = dbot.db.quoteArrs[dbot.config.imgur.highscore],
highScore = 0;
if(quoteCat) {
highScore = _.last(quoteCat);
}
res.render('imgurr', { "highscore" : highScore }); res.render('imgurr', { "highscore" : highScore });
}, },

View File

@ -4,19 +4,9 @@
"na'vi": "kxawm ke wivìntxu evengur", "na'vi": "kxawm ke wivìntxu evengur",
"cy": "Gallai fod yn anniogel ar gwaith", "cy": "Gallai fod yn anniogel ar gwaith",
"nl": "bevat mogelijk gevoelige beelden", "nl": "bevat mogelijk gevoelige beelden",
"de": "Könnte 18+ Material enthalten", "de": "Könnte 18+ Material enthalten"
"fr": "peut être risqué pour le travail (NSFW)",
"it": "può essere rischioso al lavoro (NSFW)"
}, },
"imgurinfo": { "imgurinfo": {
"en": "[{info}]", "en": "[{info}]"
"de": "[{info}]",
"fr": "[{info}]",
"it": "[{info}]"
},
"imgur_noresults": {
"en": "No results found.",
"de": "Kein Suchergebnis.",
"it": "Nessun risultato"
} }
} }

View File

@ -5,5 +5,6 @@
} }
}, },
"dependencies": [ "command" ], "dependencies": [ "command" ],
"ignorable": true "ignorable": true,
"help": "http://github.com/reality/depressionbot/blob/master/modules/js/README.md"
} }

View File

@ -4,38 +4,31 @@
* the channel. Also allows admins to run un-sandboxed Javascript code with * the channel. Also allows admins to run un-sandboxed Javascript code with
* access to the DepressionBot instance memory. * access to the DepressionBot instance memory.
*/ */
var VM = require('vm2').VM; var vm = require('vm');
var sbox = require('sandbox');
var js = function(dbot) { var js = function(dbot) {
var commands = { var commands = {
// Run JS code sandboxed, return result to channel. // Run JS code sandboxed, return result to channel.
'~js': function(event) { '~js': function(event) {
try { try {
var s = new VM({timeout: 1000, sandbox: {}}); var s = new sbox();
event.reply(s.run(event.input[1])); s.run(event.input[1], function(output) {
} catch(err) { event.reply(err); } event.reply(output.result);
}.bind(this));
} catch(err) {}
}, },
// Run JS code un-sandboxed, with access to DBot memory (admin-only). // Run JS code un-sandboxed, with access to DBot memory (admin-only).
'~ajs': function(event) { '~ajs': function(event) {
var callback = function() {
var args = Array.prototype.slice.call(arguments);
for(var i=0;i<args.length;i++) {
var arg = args[i];
if(_.isObject(arg) && !_.isArray(arg)) {
arg = '[object Object]: ' + _.keys(arg).join(', ');
}
event.reply('Callback[' + i + ']: ' + arg);
}
};
var ret = eval(event.input[1]); var ret = eval(event.input[1]);
if(ret !== undefined) { if(ret !== undefined) {
event.reply(ret); event.reply(ret);
} }
} }
}; };
commands['~js'].regex = [/^js (.*)/, 2]; commands['~js'].regex = [/^~js (.*)/, 2];
commands['~ajs'].regex = [/^ajs (.*)/, 2]; commands['~ajs'].regex = [/^~ajs (.*)/, 2];
commands['~ajs'].access = 'admin'; commands['~ajs'].access = 'admin';
this.name = 'js'; this.name = 'js';

View File

@ -1,5 +0,0 @@
{
"announce": [ { "server": "tripsit", "name": "#dbot" } ],
"dbKeys": [ "karma" ],
"dbType": "redis"
}

View File

@ -1,201 +0,0 @@
/**
* Module Name: Karma
* Description: Thanking, with Karma!
*/
var _ = require('underscore')._;
var karma = function(dbot) {
this.lastKarma = {};
this.internalAPI = {
'getKarma': function(item, callback) {
this.db.read('karma', item.toLowerCase(), callback);
}.bind(this),
'setKarma': function(item, value, callback) {
this.db.save('karma', item.toLowerCase(), {
'item': item.toLowerCase(),
'karma': value
}, callback);
}.bind(this)
};
this.commands = {
'karma': function(event) {
var item = event.params[1] || event.user;
this.internalAPI.getKarma(item, function(err, karma) {
if(!err && karma) {
karma = karma.karma;
} else {
karma = 0;
}
event.reply(dbot.t('karma', {
'item': item,
'karma': karma
}));
});
},
'setkarma': function(event) {
var item = event.params[1],
value = parseInt(event.params[2]);
this.internalAPI.setKarma(item, value, function(err, karma) {
event.reply(dbot.t('newkarma', {
'item': item,
'value': value
}));
});
},
'unkarmaiest': function(event) {
var karmas = {};
this.db.scan('karma', function(karma) {
if(karma && !_.isUndefined(karma.item)) {
karmas[karma.item] = karma.karma;
}
}.bind(this), function(err) {
var qSizes = _.chain(karmas)
.pairs()
.sortBy(function(category) { return category[1]; })
.first(10)
.value();
var qString = 'Unkarmaiest: ';
for(var i=0;i<qSizes.length;i++) {
qString += qSizes[i][0] + " (" + qSizes[i][1] + "), ";
}
event.reply(qString.slice(0, -2));
});
},
'karmaiest': function(event) {
var karmas = {};
this.db.scan('karma', function(karma) {
if(karma && !_.isUndefined(karma.item)) {
karmas[karma.item] = karma.karma;
}
}.bind(this), function(err) {
var qSizes = _.chain(karmas)
.pairs()
.sortBy(function(category) { return category[1]; })
.reverse()
.first(10)
.value();
var qString = 'Karmaiest: ';
for(var i=0;i<qSizes.length;i++) {
qString += qSizes[i][0] + " (" + qSizes[i][1] + "), ";
}
event.reply(qString.slice(0, -2));
});
},
'wattest': function(event) {
var karmas = {};
this.db.scan('karma', function(karma) {
if(karma && !_.isUndefined(karma.item)) {
if(karma.item.match(/_wat$/)) {
karmas[karma.item] = karma.karma;
}
}
}.bind(this), function(err) {
var qSizes = _.chain(karmas)
.pairs()
.sortBy(function(category) { return category[1]; })
.reverse()
.first(10)
.value();
var qString = 'Karmaiest: ';
for(var i=0;i<qSizes.length;i++) {
qString += qSizes[i][0] + " (" + qSizes[i][1] + "), ";
}
event.reply(qString.slice(0, -2));
});
}
};
this.commands.setkarma.access = 'admin';
this.listener = function(event) {
dbot.api.ignore.isUserBanned(event.rUser, 'karma', function(isBanned) {
if(!isBanned) {
var match = event.message.match(/^(.+)(\+\+|\-\-)$/);
if(event.user !== dbot.config.name && match && match[1].length < 25) {
match[1] = match[1].replace(/(\+|\-)/g,'').replace(/:/g,'').trim();
var timeout = 5000;
/* if(event.channel.name == '#stims' || event.channel.name == '##meth' || event.channel.name == '##sweden') {
timeout = 20000;
}*/
if(_.has(this.lastKarma, event.rUser.id) && this.lastKarma[event.rUser.id]+ timeout > Date.now()) {
return event.reply('Try again in a few seconds : - )');
} else if(event.rUser.currentNick.toLowerCase() === match[1].toLowerCase() || event.rUser.primaryNick.toLowerCase() === match[1].toLowerCase()) {
return event.reply('Stop playing with yourself : - )');
} else if(event.channel == event.user) {
return event.reply('Don\'t be a Secretive Sally : - )');
}
if(event.channel.name == '##wat') {
match[1] = match[1].replace(/_wat$/, '');
match[1] += '_wat';
}
this.internalAPI.getKarma(match[1], function(err, karma) {
if(!karma) {
karma = 0;
} else {
karma = karma.karma;
}
if(match[2] === '--') {
if(match[1].toLowerCase() =='weed') {
karma -= 2;
} else {
karma -= 1;
}
} else {
if(match[1].toLowerCase() == 'weed') {
karma += 2;
} else {
karma += 1;
}
}
this.internalAPI.setKarma(match[1], karma, function(err, karma) {
this.lastKarma[event.rUser.id] = Date.now();
var pre;
if(karma.karma > 0) {
pre = '[\u00039karma\u000f]';
karma.karma = '\u00039 '+karma.karma+'\u000f';
} else if(karma.karma < 0) {
pre = '[\u00034karma\u000f]';
karma.karma = '\u00034 '+karma.karma+'\u000f';
} else {
pre = '[\u00036karma\u000f]';
karma.karma = '\u00036 '+karma.karma+'\u000f';
}
event.reply(pre + ' ' + dbot.t('newkarma', {
'item': match[1],
'value': karma.karma
}));
if(_.has(dbot.modules, 'log')) {
dbot.api.log.logWithChannel(event.server, event.channel, event.rUser.primaryNick, event.message);
}
}.bind(this));
}.bind(this));
}
}
}.bind(this));
}.bind(this);
this.on = 'PRIVMSG';
};
exports.fetch = function(dbot) {
return new karma(dbot);
};

View File

@ -1,8 +0,0 @@
{
"karma": {
"en": "[karma] {item} has {karma} karma"
},
"newkarma": {
"en": "{item} now has{value} karma"
}
}

View File

@ -1,512 +1,278 @@
var _ = require('underscore')._, var _ = require('underscore')._;
uuid = require('node-uuid');
var commands = function (dbot) { var commands = function(dbot) {
var commands = { var commands = {
/*** Kick Management ***/ /*** Kick Management ***/
'~quiet': function (event) { '~quiet': function(event) {
var server = event.server, var server = event.server,
quieter = event.rUser, quieter = event.user,
duration = event.input[1], minutes = event.input[1],
channel = (event.input[2] || event.channel.name).trim(), channel = event.input[2],
quietee = event.input[3].trim(), quietee = event.input[3].trim();
reason = event.input[4] || "N/A";
this.api.quietUser(server, quieter, duration, channel, quietee, reason, function (response) { if(_.isUndefined(channel)) {
event.reply(response); channel = event.channel.name;
});
},
'~timeout': function (event) {
var server = event.server,
quieter = event.rUser,
duration = this.config.timeoutTime,
channel = event.channel.name,
quietee = event.input[1],
reason = event.input[2] || "N/A";
reason += ' #timeout';
dbot.api.users.resolveUser(server, quietee, function (err, user) {
if (!err && user) {
if (!_.has(this.recentTimeouts, user.id)) {
this.recentTimeouts[user.id] = 0;
}
this.recentTimeouts[user.id] += 1;
setTimeout(function () {
this.recentTimeouts[user.id] -= 1;
if (this.recentTimeouts[user.id] == 0) {
delete this.recentTimeouts[user.id];
} }
} channel = channel.trim();
.bind(this), 3600000);
if (this.recentTimeouts[user.id] == 3) { if(!_.isUndefined(minutes)) {
duration = null; minutes = parseFloat(minutes.trim());
reason += ' #permatimeout'; var msTimeout = new Date(new Date().getTime() + (minutes * 60000));
dbot.say(event.server, dbot.config.servers[event.server].admin_channel, quietee + ' has been given three timeouts in the last hour, and so has been quieted indefinitely in ' + channel + '. Please review.'); dbot.api.timers.addTimeout(msTimeout, function() {
} this.api.unquiet(server, quietee, channel);
}.bind(this));
this.api.quietUser(server, quieter, duration, channel, quietee, reason, function (response) { event.reply(dbot.t('tquieted', {
event.reply(response); 'quietee': quietee,
}); 'minutes': minutes
} }));
}
.bind(this));
},
'~unquiet': function (event) {
var server = event.server,
quieter = event.user,
channel = (event.input[1] || event.channel.name).trim(),
quietee = event.input[2].trim();
if (_.has(this.hosts[server], quietee)) {
if (_.include(this.config.quietBans, channel)) {
this.api.unban(server, this.hosts[server][quietee], channel);
} else {
this.api.unquiet(server, this.hosts[server][quietee], channel);
}
event.reply(dbot.t('unquieted', {
'quietee': quietee
}));
dbot.api.report.notify('unquiet', server, event.rUser, channel,
dbot.t('unquiet_notify', {
'unquieter': quieter,
'quietee': quietee
}), false, quietee);
}
},
'~ckick': function (event) {
var server = event.server,
kicker = event.user,
kickee = event.input[2],
channel = event.input[1],
reason = event.input[3];
if (_.isUndefined(channel)) {
channel = event.channel.name;
}
channel = channel.trim();
this.api.kick(server, kickee, channel, reason + ' (requested by ' + kicker + ')');
dbot.api.report.notify('kick', server, event.rUser, channel, dbot.t('ckicked', {
'kicker': kicker,
'kickee': kickee,
'reason': reason
}), false, kickee);
},
// Kick and ban from all channels on the network.
'~nban': function (event) {
if (!event.input)
return;
var server = event.server,
banner = event.user,
timeout = event.input[1],
banee = event.input[2],
reason = event.input[3],
adminChannel = dbot.config.servers[server].admin_channel,
channels = _.keys(dbot.instance.connections[server].channels),
network = event.server;
if (this.config.network_name[event.server]) {
network = this.config.network_name[event.server];
}
dbot.api.nickserv.getUserHost(event.server, banee, function (host) {
// Add host record entry
if (host) {
var didKill = false;
if ((reason.match('#line') || reason.match('#specialk') || reason.match('#kline')) && _.include(dbot.access.moderator(), event.rUser.primaryNick)) {
didKill = true;
var t = ' !P ';
if (timeout) {
t = ' !T ' + timeout + ' ';
}
dbot.say(event.server, 'operserv', 'akill add ' + banee + t + banee + ' banned by ' + banner + ': ' + reason);
}
// Do not ban if user was killed - redundant
if(!didKill) {
// Ban from current channel first
this.api.ban(server, host, event.channel);
this.api.kick(server, banee, event.channel, reason +
' (network-wide ban)');
channels = _.without(channels, event.channel);
if (!_.isUndefined(adminChannel)) {
channels = _.without(channels, adminChannel);
} else { } else {
adminChannel = event.channel.name; event.reply(dbot.t('quieted', { 'quietee': quietee }));
} }
// Ban the user from all channels this.api.quiet(server, quietee, channel);
var i = 0; },
var banChannel = function (channels) {
if (i >= channels.length) '~unquiet': function(event) {
return; var server = event.server,
var channel = channels[i]; quieter = event.user,
this.api.ban(server, host, channel); channel = event.input[1],
this.api.kick(server, banee, channel, reason + quietee = event.input[2].trim();
' (network-wide ban)');
i++; if(_.isUndefined(channel)) {
banChannel(channels); channel = event.channel.name;
} }
.bind(this); channel = channel.trim();
banChannel(channels);
}
this.hosts[event.server][banee] = host; this.api.unquiet(server, quietee, channel);
event.reply(dbot.t('unquieted', { 'quietee': quietee }));
},
// Create notify string '~ckick': function(event) {
if (!_.isUndefined(timeout)) { var server = event.server,
timeout = timeout.trim(); kicker = event.user,
kickee = event.input[2],
channel = event.input[1],
reason = event.input[3];
var msTimeout = new Date(new Date().getTime() + (parseFloat(timeout) * 3600000)); this.api.kick(server, kickee, channel, reason + ' (requested by ' + kicker + ')');
if (_.has(dbot.modules, 'remind')) {
msTimeout = dbot.api.remind.parseTime(timeout);
if (!msTimeout) {
return event.reply('Invalid time. Remember you must give e.g. 5m now.');
}
timeout = timeout.replace(/([\d]+)d/, '$1 days').replace(/([\d]+)h/, '$1 hours ').replace(/([\d]+)m/, '$1 minutes ').replace(/([\d]+)s/, '$1 seconds').trim();
} else {
timeout += ' hours';
}
// Do not schedule unbans if the user was killed as no ban was put in place dbot.api.report.notify(server, channel, dbot.t('ckicked', {
if(!didKill) { 'kicker': kicker,
if (!_.has(this.tempBans, event.server)) 'kickee': kickee,
this.tempBans[event.server] = {}; 'channel': channel,
this.tempBans[event.server][banee] = msTimeout; 'reason': reason
this.internalAPI.addTempBan(event.server, banee, msTimeout); }));
} },
var notifyString = dbot.t('tbanned', { '~cban': function(event) {
'network': network, var server = event.server,
banner = event.user,
banee = event.input[2],
channel = event.input[1],
reason = event.input[3];
this.api.ban(server, banee, channel);
this.api.kick(server, kickee, channel, reason + ' (requested by ' + banner + ')');
dbot.api.report.notify(server, channel, dbot.t('cbanned', {
'banner': banner, 'banner': banner,
'banee': banee, 'banee': banee,
'hours': timeout, 'channel': channel,
'host': host,
'reason': reason 'reason': reason
});
} else {
var notifyString = dbot.t('nbanned', {
'network': network,
'banner': banner,
'banee': banee,
'host': host,
'reason': reason
});
}
// Add db entry documenting ban
if (this.config.document_bans) {
var id = uuid.v4();
var banRecord = {
'id': id,
'time': new Date().getTime(),
'server': server,
'banee': banee,
'banner': banner,
'host': host,
'reason': reason
};
this.db.save('nbans', id, banRecord, function () {});
}
// Notify moderators, banee
if (!_.isUndefined(adminChannel)) {
channels = _.without(channels, adminChannel);
} else {
adminChannel = event.channel.name;
}
dbot.api.report.notify('ban', server, event.rUser, adminChannel, notifyString, false, banee);
dbot.say(event.server, adminChannel, notifyString);
if (!_.isUndefined(timeout)) {
dbot.say(event.server, banee, dbot.t('tbanned_notify', {
'network': network,
'banner': banner,
'reason': reason,
'hours': timeout,
'admin_channel': adminChannel
}));
} else {
dbot.say(event.server, banee, dbot.t('nbanned_notify', {
'network': network,
'banner': banner,
'reason': reason,
'hours': timeout,
'admin_channel': adminChannel
}));
}
// err
dbot.say(event.server, 'NickServ', 'FREEZE ' + banee + ' ON ' + reason);
} else {
event.reply(dbot.t('no_user', {
'user': banee
})); }));
} },
}
.bind(this));
},
'~nunban': function (event) { // Kick and ban from all channels on the network.
var unbanee = event.params[1], '~nban': function(event) {
host = event.params[2] || undefined, if(!event.input) return;
unbanner = event.rUser;
this.api.networkUnban(event.server, unbanee, unbanner, host, function (err) { var server = event.server,
if (err) { banner = event.user,
event.reply(dbot.t('nunban_error', { timeout = event.input[1],
'unbanee': unbanee banee = event.input[2],
})); reason = event.input[3],
} adminChannel = this.config.admin_channel[event.server];
}); channels = dbot.config.servers[server].channels,
}, network = event.server;
/*** Kick Stats ***/ if(this.config.network_name[event.server]) {
network = this.config.network_name[event.server];
// Give the number of times a given user has been kicked and has kicked
// other people.
'~kickcount': function (event) {
var username = event.params[1];
if (!_.has(dbot.db.kicks, username)) {
var kicks = '0';
} else {
var kicks = dbot.db.kicks[username];
}
if (!_.has(dbot.db.kickers, username)) {
var kicked = '0';
} else {
var kicked = dbot.db.kickers[username];
}
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
// who have kicked other people the most.
'~kickstats': function (event) {
var orderedKickLeague = function (list, topWhat) {
var kickArr = _.chain(list)
.pairs()
.sortBy(function (kick) {
return kick[1]
})
.reverse()
.first(10)
.value();
var kickString = "Top " + topWhat + ": ";
for (var i = 0; i < kickArr.length; i++) {
kickString += kickArr[i][0] + " (" + kickArr[i][1] + "), ";
}
return kickString.slice(0, -2);
};
event.reply(orderedKickLeague(dbot.db.kicks, 'Kicked'));
event.reply(orderedKickLeague(dbot.db.kickers, 'Kickers'));
},
'~votequiet': function (event) {
var target = event.input[1],
reason = event.input[2];
if (_.has(event.channel.nicks, target)) {
dbot.api.users.resolveUser(event.server, target, function (err, user) {
if (!err && user) {
if (_.include(dbot.access.power_user(), user.primaryNick) || target == dbot.config.name) {
return event.reply('User is immune to votequiet.');
} }
console.log(timeout);
console.log(banee);
console.log(reason);
if (!_.has(this.voteQuiets, user.id)) { dbot.api.nickserv.getUserHost(event.server, banee, function(host) {
this.voteQuiets[user.id] = { // Add host record entry
'user': user.id, if(host) {
'reason': reason, if(!_.has(this.hosts, event.server)) this.hosts[event.server] = {};
'channel': event.channel, this.hosts[event.server][banee] = host;
'yes': [event.rUser.primaryNick],
'no': []
};
event.reply(event.user + ' has started a vote to quiet ' + target + ' for "' + reason + '." Type either "~voteyes ' + target + '" or "~voteno ' + target + '" in the next 90 seconds.');
this.voteQuiets[user.id].timer = setTimeout(function () { // Create notify string
var vq = this.voteQuiets[user.id]; if(!_.isUndefined(timeout)) {
vq.spent = true; timeout = parseFloat(timeout.trim());
if (vq.yes.length >= 3 && vq.no.length < 2) {
event.reply('Attempt to quiet ' + target + ' succeeded. Count: Yes (' + vq.yes.length + '). No (' + vq.no.length + ').');
this.api.quietUser(event.server, event.rUser, '10m', event.channel, target, reason + '[votequiet]', function (response) { var msTimeout = new Date(new Date().getTime() + (timeout * 3600000));
clearTimeout(vq.timer); if(!_.has(this.tempBans, event.server)) this.tempBans[event.server] = {};
event.reply(response); this.tempBans[event.server][banee] = msTimeout;
}); this.internalAPI.addTempBan(event.server, banee, msTimeout);
} else {
event.reply('Attempt to quiet ' + target + ' failed. Count: Yes (' + vq.yes.length + '). No (' + vq.no.length + ').');
}
var nString = 'A votequiet was attempted on ' + target + ' in ' + event.channel + '. It was initiated by ' + event.rUser.primaryNick + '. ' + var notifyString = dbot.t('tbanned', {
vq.yes.join(', ') + ' voted yes (' + vq.yes.length + '). '; 'network': network,
if (vq.no.length > 0) { 'banner': banner,
nString += vq.no.join(', ') + ' voted no (' + vq.no.length + ').' 'banee': banee,
} 'hours': timeout,
'reason': reason
dbot.api.report.notify('votequiet', event.server, event.rUser, event.channel, nString, false, target); });
var quoteString = dbot.t('tban_quote', {
setTimeout(function () { 'banee': banee,
delete this.voteQuiets[user.id]; 'banner': banner,
} 'hours': timeout,
.bind(this), 600000); 'time': new Date().toUTCString(),
} 'reason': reason
.bind(this), 90000); });
} else { } else {
if (this.voteQuiets[user.id].spent) { var notifyString = dbot.t('nbanned', {
event.reply('A votequiet attempt has already been made on this user in the last 10 minutes.'); 'network': network,
} else { 'banner': banner,
var vq = this.voteQuiets[user.id] 'banee': banee,
if (!_.include(vq.yes, event.rUser.primaryNick)) { 'reason': reason
vq.yes.push(event.rUser.primaryNick); });
var quoteString = dbot.t('nban_quote', {
event.reply('There is already a votequiet attempt active for this user, adding yes vote to existing poll.'); 'banee': banee,
event.reply('Voted yes on votequiet for ' + target + '. New count: Yes (' + vq.yes.length + '). No (' + vq.no.length + ').'); 'banner': banner,
'time': new Date().toUTCString(),
if (vq.yes.length == 4) { 'reason': reason
event.reply('Attempt to quiet ' + target + ' succeeded. Count: Yes (' + vq.yes.length + '). No (' + vq.no.length + ').'); });
this.api.quietUser(event.server, event.rUser, '10m', event.channel, target, reason + '[votequiet]', function (response) {
clearTimeout(vq.timer);
vq.spent = true;
setTimeout(function () {
delete this.voteQuiets[user.id];
}
.bind(this), 600000);
event.reply(response);
});
} }
} else {
event.reply('There is already a votequiet attempt active for this user, and you already voted yes!');
}
}
}
} else {
event.reply('Target does not seem to be in the channel.');
}
}
.bind(this));
} else {
event.reply('Target does not seem to be in the channel.');
}
},
'~voteyes': function (event) { // Add qutoe category documenting ban
var target = event.params[1]; if(this.config.document_bans && _.has(dbot.modules, 'quotes')) {
dbot.db.quoteArrs['ban_' + banee.toLowerCase()] = [ quoteString ];
notifyString += ' ' + dbot.t('quote_recorded', { 'user': banee });
}
dbot.api.users.resolveUser(event.server, target, function (err, user) { // Notify moderators, banee
if (!err && user) { if(this.config.admin_channel[event.server]) {
if (user.id == event.rUser.id) { channels = _.without(channels, adminChannel);
return event.reply('You cannot vote on your own silencing. Be good.');
}
if (_.has(this.voteQuiets, user.id) && !this.voteQuiets[user.id].spent) {
var vq = this.voteQuiets[user.id];
if (event.channel != vq.channel) {
return event.reply('Vote must be in ' + vq.channel);
}
if (!_.include(vq.yes, event.rUser.primaryNick) && !_.include(vq.no, event.rUser.primaryNick)) {
vq.yes.push(event.rUser.primaryNick);
event.reply('Voted yes on votequiet for ' + target + '. New count: Yes (' + vq.yes.length + '). No (' + vq.no.length + ').');
if (vq.yes.length == 4) { dbot.api.report.notify(server, adminChannel, notifyString);
event.reply('Attempt to quiet ' + target + ' succeeded. Count: Yes (' + vq.yes.length + '). No (' + vq.no.length + ').'); dbot.say(event.server, adminChannel, notifyString);
this.api.quietUser(event.server, event.rUser, '10m', event.channel, target, vq.reason + '[votequiet]', function (response) {
clearTimeout(vq.timer); if(!_.isUndefined(timeout)) {
vq.spent = true; dbot.say(event.server, banee, dbot.t('tbanned_notify', {
setTimeout(function () { 'network': network,
delete this.voteQuiets[user.id]; 'banner': banner,
} 'reason': reason,
.bind(this), 600000); 'hours': timeout,
event.reply(response); 'admin_channel': adminChannel
}); }));
} } else {
dbot.say(event.server, banee, dbot.t('nbanned_notify', {
'network': network,
'banner': banner,
'reason': reason,
'hours': timeout,
'admin_channel': adminChannel
}));
}
}
// Ban the user from all channels
var i = 0;
var banChannel = function(channels) {
if(i >= channels.length) return;
var channel = channels[i];
this.api.ban(server, banee, channel);
this.api.kick(server, banee, channel, reason +
' (network-wide ban requested by ' + banner + ')');
setTimeout(function() {
i++; banChannel(channels);
}, 1000);
}.bind(this);
banChannel(channels);
} else {
event.reply(dbot.t('no_user', { 'user': banee }));
}
}.bind(this));
},
'~nunban': function(event) {
var unbanee = event.params[1],
unbanner = event.user;
this.api.networkUnban(event.server, unbanee, unbanner, function(err) {
if(err) {
event.reply(dbot.t('nunban_error', { 'unbanee': unbanee }));
}
});
},
/*** Kick Stats ***/
// Give the number of times a given user has been kicked and has kicked
// other people.
'~kickcount': function(event) {
var username = event.params[1];
if(!_.has(dbot.db.kicks, username)) {
var kicks = '0';
} else { } else {
event.reply('You have already voted.'); var kicks = dbot.db.kicks[username];
} }
} else {
event.reply('There is no active votequiet for this user. You can start one by typing "~votequiet ' + target + ' [reason].');
}
} else {
event.reply('No idea who that is m8');
}
}
.bind(this));
},
'~voteno': function (event) { if(!_.has(dbot.db.kickers, username)) {
var target = event.params[1]; var kicked = '0';
dbot.api.users.resolveUser(event.server, target, function (err, user) {
if (!err && user) {
if (user.id == event.rUser.id) {
return event.reply('You cannot vote on your own silencing. Be good.');
}
if (_.has(this.voteQuiets, user.id) && !this.voteQuiets[user.id].spent) {
var vq = this.voteQuiets[user.id];
if (event.channel != vq.channel) {
return event.reply('Vote must be in ' + vq.channel);
}
if (!_.include(vq.yes, event.rUser.primaryNick) && !_.include(vq.no, event.rUser.primaryNick)) {
vq.no.push(event.rUser.primaryNick);
event.reply('Voted no on votequiet for ' + target + '. New count: Yes (' + vq.yes.length + '). No (' + vq.no.length + ').');
} else { } else {
event.reply('You have already voted.'); var kicked = dbot.db.kickers[username];
} }
} else {
event.reply('There is no active votequiet for this user. You can start one by typing "~votequiet ' + target + ' [reason].'); event.reply(dbot.t('user_kicks', {
} 'user': username,
} else { 'kicks': kicks,
event.reply('No idea who that is m8'); 'kicked': kicked
}));
},
// Output a list of the people who have been kicked the most and those
// who have kicked other people the most.
'~kickstats': function(event) {
var orderedKickLeague = function(list, topWhat) {
var kickArr = _.chain(list)
.pairs()
.sortBy(function(kick) { return kick[1] })
.reverse()
.first(10)
.value();
var kickString = "Top " + topWhat + ": ";
for(var i=0;i<kickArr.length;i++) {
kickString += kickArr[i][0] + " (" + kickArr[i][1] + "), ";
}
return kickString.slice(0, -2);
};
event.reply(orderedKickLeague(dbot.db.kicks, 'Kicked'));
event.reply(orderedKickLeague(dbot.db.kickers, 'Kickers'));
} }
} };
.bind(this));
}
};
_.each(commands, function (command) { _.each(commands, function(command) {
command.access = 'moderator'; command.access = 'moderator';
}); });
commands['~kickcount'].access = 'regular'; commands['~kickcount'].access = 'regular';
commands['~kickstats'].access = 'regular'; commands['~kickstats'].access = 'regular';
commands['~votequiet'].access = 'regular';
commands['~voteyes'].access = 'regular';
commands['~voteno'].access = 'regular';
commands['~quiet'].access = 'voice';
commands['~timeout'].access = 'voice';
commands['~unquiet'].access = 'voice';
commands['~nban'].access = 'power_user';
commands['~nunban'].access = 'power_user';
commands['~ckick'].regex = /^ckick (#[^ ]+ )?([^ ]+) ?(.*)?$/; commands['~ckick'].regex = [/^~ckick ([^ ]+) ([^ ]+) (.+)$/, 4];
commands['~nban'].regex = /^nban (\d[\d\.dhmsy]+)? ?([^ ]+) (.+)$/; commands['~nban'].regex = /^~nban ([\d\.^ ]+)?([^ ]+) (.+)$/;
commands['~quiet'].regex = /^quiet (\d[\d\.hmsy]+)? ?(#[^ ]+ )?([^ ]+) ?(.*)?$/; commands['~quiet'].regex = /^~quiet ([\d\.^ ]+)?(#[^ ]+ )?([^ ]+) ?$/;
commands['~timeout'].regex = /^timeout ([^ ]+) ?(.*)?$/; commands['~unquiet'].regex = /^~unquiet (#[^ ]+ )?([^ ]+) ?$/;
commands['~unquiet'].regex = /^unquiet (#[^ ]+ )?([^ ]+) ?$/;
commands['~votequiet'].regex = [/^votequiet ([^ ]+) (.+)$/, 3];
return commands; return commands;
}; };
exports.fetch = function (dbot) { exports.fetch = function(dbot) {
return commands(dbot); return commands(dbot);
}; };

View File

@ -1,18 +1,15 @@
{ {
"dbKeys": [ "kicks", "kickers", "hosts", "tempBans" ], "dbKeys": [ "kicks", "kickers", "hosts", "tempBans" ],
"dependencies": [ "command", "report", "users" ], "dependencies": [ "command", "report", "users" ],
"help": "http://github.com/reality/depressionbot/blob/master/modules/kick/README.md",
"ignorable": true, "ignorable": true,
"countSilently": true, "countSilently": true,
"quietBans": [ "admin_channel": {
"#wherever" "aberwiki": "#fishbox"
], },
"network_name": { "network_name": {
"aberwiki": "OAOSIDL" "aberwiki": "OAOSIDL"
}, },
"chanserv": "ChanServ", "chanserv": "ChanServ",
"document_bans": false, "document_bans": false
"dbType": "redis",
"requireWebLogin": true,
"webAccess": "power_user",
"timeoutTime": "10m"
} }

View File

@ -1,270 +1,132 @@
var _ = require('underscore')._; var _ = require('underscore')._;
var kick = function (dbot) { var kick = function(dbot) {
if (!_.has(dbot.db, 'recentTimeouts')) {
dbot.db.recentTimeouts = {};
}
this.recentTimeouts = dbot.db.recentTimeouts;
this.api = {
'ban': function (server, host, channel) {
dbot.instance.connections[server].send('MODE ' + channel + ' +b *!*@' + host);
},
'quiet': function (server, host, channel) {
dbot.instance.connections[server].send('MODE ' + channel + ' +q *!*@' + host);
},
'unquiet': function (server, host, channel) {
dbot.instance.connections[server].send('MODE ' + channel + ' -q *!*@' + host);
},
'devoice': function (server, nick, channel) {
dbot.instance.connections[server].send('MODE ' + channel + ' -v ' + nick);
},
'voice': function (server, nick, channel) {
dbot.instance.connections[server].send('MODE ' + channel + ' +v ' + nick);
},
'kick': function (server, user, channel, msg) {
dbot.instance.connections[server].send('KICK ' + channel + ' ' + user + ' :' + msg);
},
'kill': function (server, user, reason) {
dbot.instance.connections[server].send('kill ' + user + ' ' + reason);
},
'unban': function (server, host, channel) {
// TODO: Wrest control from chanserv
//dbot.say(server, this.config.chanserv, 'unban ' + channel + ' *!*@' + host);
dbot.instance.connections[server].send('MODE ' + channel + ' -b *!*@' + host);
},
'quietUser': function (server, quieter, duration, channel, quietee, reason, callback) {
dbot.api.nickserv.getUserHost(server, quietee, function (host) {
// Add host record entry
if (host) {
this.hosts[server][quietee] = host;
if (!_.isUndefined(duration) && !_.isNull(duration)) {
duration = duration.trim();
var msTimeout = new Date(new Date().getTime() + (parseFloat(duration) * 60000));
if (_.has(dbot.modules, 'remind')) {
msTimeout = dbot.api.remind.parseTime(duration);
if (!msTimeout) {
return callback('Invalid time. Remember you must give e.g. 5m now.');
}
duration = duration.replace(/([\d]+)d/, '$1 years').replace(/([\d]+)d/, '$1 days').replace(/([\d]+)h/, '$1 hours ').replace(/([\d]+)m/, '$1 minutes ').replace(/([\d]+)s/, '$1 seconds').trim();
} else {
duration += ' minutes';
}
var vStatus = dbot.instance.connections[server].channels[channel].nicks[quietee].voice;
dbot.api.timers.addTimeout(msTimeout, function () {
if (_.has(this.hosts[server], quietee)) {
if (_.include(this.config.quietBans, channel)) {
this.api.unban(server, this.hosts[server][quietee], channel);
this.api.voice(server, quietee, channel);
} else {
this.api.unquiet(server, this.hosts[server][quietee], channel);
}
dbot.api.users.resolveUser(server, dbot.config.name, function (err, user) {
dbot.api.report.notify('unquiet', server, user, channel,
dbot.t('unquiet_notify', {
'unquieter': dbot.config.name,
'quietee': quietee
}), false, quietee);
});
}
}
.bind(this));
callback(dbot.t('tquieted', {
'quietee': quietee,
'minutes': duration
}));
dbot.api.report.notify('quiet', server, quieter.primaryNick, channel,
dbot.t('tquiet_notify', {
'minutes': duration,
'quieter': quieter.primaryNick,
'quietee': quietee,
'reason': reason
}), false, quietee);
} else {
callback(dbot.t('quieted', {
'quietee': quietee
}));
dbot.api.report.notify('quiet', server, quieter.primaryNick, channel,
dbot.t('quiet_notify', {
'quieter': quieter.primaryNick,
'quietee': quietee,
'reason': reason
}), false, quietee);
}
this.api.devoice(server, quietee, channel);
if (_.include(this.config.quietBans, channel)) {
this.api.ban(server, this.hosts[server][quietee], channel);
} else {
this.api.quiet(server, host, channel);
}
if (reason.indexOf('#warn') !== -1) {
dbot.api.warning.warn(server, quieter, quietee,
'Quieted in ' + channel + ' for ' + reason, channel,
function () {});
}
} else {
event.reply(dbot.t('no_user', {
'user': quietee
}));
}
}
.bind(this));
},
'networkUnban': function (server, unbanee, unbanner, manualHost, callback) {
var channels = dbot.config.servers[server].channels,
network = this.config.network_name[server] || server,
adminChannel = dbot.config.servers[server].admin_channel;
if (!_.isUndefined(manualHost)) {
this.hosts[server][unbanee] = manualHost;
}
if (_.has(this.hosts, server) && _.has(this.hosts[server], unbanee) && _.isString(this.hosts[server][unbanee])) {
var host = this.hosts[server][unbanee];
// Notify Staff
if (_.isUndefined(adminChannel)) {
adminChannel = event.channel.name;
}
var notifyString = dbot.t('nunbanned', {
'network': network,
'unbanee': unbanee,
'host': host,
'unbanner': unbanner.currentNick
});
dbot.api.report.notify('unban', server, unbanner, adminChannel, notifyString, false, unbanee);
dbot.say(server, adminChannel, notifyString);
// Notify Unbanee
dbot.say(server, unbanee, dbot.t('nunban_notify', {
'network': network,
'unbanee': unbanee,
'unbanner': unbanner.currentNick
}));
// Unban
var i = 0;
var unbanChannel = function (channels) {
if (i >= channels.length)
return;
var channel = channels[i];
this.api.unban(server, host, channel);
setTimeout(function () {
i++;
unbanChannel(channels);
}, 1000);
}
.bind(this);
unbanChannel(channels);
dbot.say(server, 'NickServ', 'FREEZE ' + unbanee + ' OFF');
callback(null); // Success
} else {
// Attempt to look up the host on-the-fly
dbot.api.nickserv.getUserHost(server, unbanee, unbanner, function (host) {
if (host) {
if (!_.has(this.hosts, server))
this.hosts[server] = {};
this.hosts[server][unbanee] = host;
this.api.networkUnban(server, unbanee, unbanner);
} else {
callback(true); // No host could be found
}
}
.bind(this));
}
}
};
this.internalAPI = {
'addTempBan': function (server, banee, timeout) {
dbot.api.users.resolveUser(server, dbot.config.name, function (err, bot) {
dbot.api.timers.addTimeout(timeout, function () {
this.api.networkUnban(server, banee, bot, undefined, function (err) {});
delete this.tempBans[server][banee];
}
.bind(this));
}
.bind(this));
}
.bind(this)
};
this.listener = function (event) {
if (event.kickee == dbot.config.name) {
dbot.instance.join(event, event.channel.name);
event.reply(dbot.t('kicked_dbot', {
'botname': dbot.config.name
}));
dbot.db.kicks[dbot.config.name] += 1;
} else {
if (!_.has(dbot.db.kicks, event.kickee)) {
dbot.db.kicks[event.kickee] = 1;
} else {
dbot.db.kicks[event.kickee] += 1;
}
if (!_.has(dbot.db.kickers, event.user)) {
dbot.db.kickers[event.user] = 1;
} else {
dbot.db.kickers[event.user] += 1;
}
if (!this.config.countSilently) {
event.reply(event.kickee + '-- (' + dbot.t('user_kicks', {
'user': event.kickee,
'kicks': dbot.db.kicks[event.kickee],
'kicked': dbot.db.kickers[event.kickee]
}) + ')');
}
}
}
.bind(this);
this.on = 'KICK';
this.onLoad = function () {
if (!_.has(dbot.db, 'hosts')) {
dbot.db.hosts = {};
_.each(dbot.config.servers, function (v, k) {
dbot.db.hosts[k] = {};
}, this);
}
if (!_.has(dbot.db, 'tempBans'))
dbot.db.tempBans = {};
this.hosts = dbot.db.hosts; this.hosts = dbot.db.hosts;
this.tempBans = dbot.db.tempBans; this.tempBans = dbot.db.tempBans;
this.voteQuiets = {};
_.each(this.tempBans, function (bans, server) { this.api = {
_.each(bans, function (timeout, nick) { 'ban': function(server, user, channel) {
timeout = new Date(timeout); dbot.say(server, this.config.chanserv, 'ban ' + channel + ' ' + user);
this.internalAPI.addTempBan(server, nick, timeout); },
}, this);
}, this);
if (_.has(dbot.modules, 'web')) { 'quiet': function(server, user, channel) {
dbot.api.web.addIndexLink('/bans', 'Ban List'); dbot.say(server, this.config.chanserv, 'quiet ' + channel + ' ' + user);
} },
}
.bind(this); 'unquiet': function(server, user, channel) {
dbot.say(server, this.config.chanserv, 'unquiet ' + channel + ' ' + user);
},
'kick': function(server, user, channel, msg) {
dbot.instance.connections[server].send('KICK ' + channel + ' ' + user + ' :' + msg);
},
'unban': function(server, host, channel) {
dbot.say(server, this.config.chanserv, 'unban ' + channel + ' *!*@' + host);
},
'networkUnban': function(server, unbanee, unbanner, callback) {
var channels = dbot.config.servers[server].channels,
network = this.config.network_name[server] || server,
adminChannel = this.config.admin_channel[server];
if(_.has(this.hosts, server) && _.has(this.hosts[server], unbanee)) {
var host = this.hosts[server][unbanee];
// Notify Staff
if(!_.isUndefined(adminChannel)) {
var notifyString = dbot.t('nunbanned', {
'network': network,
'unbanee': unbanee,
'unbanner': unbanner
});
dbot.api.report.notify(server, adminChannel, notifyString);
dbot.say(server, adminChannel, notifyString);
}
// Notify Unbanee
dbot.say(server, unbanee, dbot.t('nunban_notify', {
'network': network,
'unbanee': unbanee,
'unbanner': unbanner
}));
// Unban
var i = 0;
var unbanChannel = function(channels) {
if(i >= channels.length) return;
var channel = channels[i];
this.api.unban(server, host, channel);
setTimeout(function() {
i++; unbanChannel(channels);
}, 1000);
}.bind(this);
unbanChannel(channels);
callback(null); // Success
} else {
// Attempt to look up the host on-the-fly
dbot.api.nickserv.getUserHost(server, unbanee, function(host) {
if(host) {
if(!_.has(this.hosts, server)) this.hosts[server] = {};
this.hosts[server][unbanee] = host;
this.api.networkUnban(server, unbanee, unbanner);
} else {
callback(true); // No host could be found
}
});
}
}
};
this.internalAPI = {
'addTempBan': function(server, banee, timeout) {
dbot.api.timers.addTimeout(timeout, function() {
this.api.networkUnban(server, banee, dbot.config.name, function(err) {});
delete this.tempBans[server][banee];
}.bind(this));
}.bind(this)
};
this.listener = function(event) {
if(event.kickee == dbot.config.name) {
dbot.instance.join(event, event.channel);
event.reply(dbot.t('kicked_dbot', { 'botname': dbot.config.name }));
dbot.db.kicks[dbot.config.name] += 1;
} else {
if(!_.has(dbot.db.kicks, event.kickee)) {
dbot.db.kicks[event.kickee] = 1;
} else {
dbot.db.kicks[event.kickee] += 1;
}
if(!_.has(dbot.db.kickers, event.user)) {
dbot.db.kickers[event.user] = 1;
} else {
dbot.db.kickers[event.user] += 1;
}
if(!this.config.countSilently) {
event.reply(event.kickee + '-- (' + dbot.t('user_kicks', {
'user': event.kickee,
'kicks': dbot.db.kicks[event.kickee],
'kicked': dbot.db.kickers[event.kickee]
}) + ')');
}
}
}.bind(this);
this.on = 'KICK';
this.onLoad = function() {
_.each(this.tempBans, function(bans, server) {
_.each(bans, function(timeout, nick) {
timeout = new Date(timeout);
this.internalAPI.addTempBan(server, nick, timeout);
}, this);
}, this);
}.bind(this);
}; };
exports.fetch = function (dbot) { exports.fetch = function(dbot) {
return new kick(dbot); return new kick(dbot);
}; };

View File

@ -1,46 +0,0 @@
var _ = require('underscore')._;
var pages = function (dbot) {
return {
'/bans': function (req, res) {
res.render('servers', {
'servers': _.keys(dbot.config.servers)
});
},
'/underbans': function (req, res) {
this.db.search('nbans', {
'server': server
}, function (ban) {
if (ban.reason.match('#underban')) {
bans.push(ban);
}
}, function () {
res.render('bans', {
'server': server,
'bans': bans
});
});
},
'/bans/:server': function (req, res) {
var server = req.params.server,
bans = [];
this.db.search('nbans', {
'server': server
}, function (ban) {
bans.push(ban);
}, function () {
res.render('bans', {
'server': server,
'bans': bans
});
});
}
}
};
exports.fetch = function (dbot) {
return pages(dbot);
};

View File

@ -5,39 +5,16 @@
"na'vi": "Tuteol {user}it tsrame'i {kicks} hìmtxan ulte sute tsrame'i {kicked} hìmtxan.", "na'vi": "Tuteol {user}it tsrame'i {kicks} hìmtxan ulte sute tsrame'i {kicked} hìmtxan.",
"cy": "Cafwyd {user} ei gicio {kicks} gwaith ac wedi cicio pobl {kicked} gwaith.", "cy": "Cafwyd {user} ei gicio {kicks} gwaith ac wedi cicio pobl {kicked} gwaith.",
"nl": "{user} is {kicks} keer gekickt en heeft anderen {kicked} keer gekickt.", "nl": "{user} is {kicks} keer gekickt en heeft anderen {kicked} keer gekickt.",
"de": "{user} wurde {kicks} mal gekickt und hat {kicked} mal andere Benutzer gekickt.", "de": "{user} wurde {kicks} mal gekickt und hat {kicked} mal andere Benutzer gekickt."
"fr": "{user} a été kické {kicks} fois et a kické des personnes {kicked} fois.",
"it": "{user} ha ricevuto {kicks} pedata/e e ha dato {kicked} pedata/e a altri utenti"
}, },
"quieted": { "quieted": {
"en": "Quieted {quietee}. Remember: don't be a coconut.", "en": "Quieted {quietee}. Remember: don't be a coconut."
"fr": "{quietee} a été rendu silencieux. Rappelle-toi : ne sois pas têtu.",
"it": "{quietee} è stato silenziato. Ricordati: non essere testardo",
"de": "{quietee} stummgestellt. Denk dran: Sei kein Arschloch."
}, },
"tquieted": { "tquieted": {
"en": "Quieted {quietee} for {minutes}. Remember: don't be a coconut.", "en": "Quieted {quietee} for {minutes} minutes. Remember: don't be a coconut."
"fr": "{quietee} a été rendu silencieux pour {minutes} minutes. Rappelle-toi : ne sois pas têtu.",
"it": "{quietee} è stato silenziato per {minutes} minuto/i. Ricordati: non essere testardo",
"de": "{quietee} für {minutes} Minuten stummgestellt. Denk dran: Sei kein Arschloch."
},
"quiet_notify": {
"en": "{quieter} has quieted {quietee}. The reason given was \"{reason}\".",
"de": "{quieter} hat {quietee} stummgestellt. Der Grund ist \"{reason}\"."
},
"tquiet_notify": {
"en": "{quieter} has quieted {quietee} for {minutes} minutes. The reason given was \"{reason}\".",
"de": "{quieter} hat {quietee} für {minutes} Minuten stummgestellt. Der Grund ist \"{reason}\"."
}, },
"unquieted": { "unquieted": {
"en": "Unquieted {quietee}. Remember: don't be a coconut.", "en": "Unquieted {quietee}. Remember: don't be a coconut."
"fr": "{quietee} peut maintenant parler. Rappelle-toi : ne sois pas têtu.",
"it": "{quietee} può nuovamente parlare. Ricordati: non essere testardo.",
"de": "{quietee} ist nicht mehr stummgestellt. Denk dran: Sei kein Arschloch."
},
"unquiet_notify": {
"en": "{unquieter} has unquieted {quietee}.",
"de": "{unquieter} hat Stummstellung von {quietee} aufgehoben."
}, },
"kicked_dbot": { "kicked_dbot": {
"en": "Thou shalt not kick {botname}", "en": "Thou shalt not kick {botname}",
@ -45,71 +22,52 @@
"na'vi": "Ngal {botname}it ke tsun tsrive'i", "na'vi": "Ngal {botname}it ke tsun tsrive'i",
"cy": "Ni ddylech cicio {botname}", "cy": "Ni ddylech cicio {botname}",
"nl": "Gij zult {botname} niet kicken", "nl": "Gij zult {botname} niet kicken",
"de": "Du sollst {botname} nicht kicken", "de": "Du sollst {botname} nicht kicken"
"fr": "Tu ne kickeras pas {botname}",
"it": "Non dare pedata a {botname}"
}, },
"ckicked": { "ckicked": {
"en": "{kicker} has kicked {kickee}. The reason given was: \"{reason}\".", "en": "Attention: {kicker} has kicked {kickee} from {channel}. The reason given was: \"{reason}.\"",
"cy": "Sylw: {kicker} wedi cicio'r {kickee} o {channel}. Y rheswm a roddwyd oedd: \"{reason}\".", "cy": "Sylw: {kicker} wedi cicio'r {kickee} o {channel}. Y rheswm a roddwyd oedd: \"{reason}.\"",
"de": "Achtung: {kicker} hat {kickee} von {channel} verwiesen. Grund: \"{reason}\".", "de": "Achtung: {kicker} hat {kickee} von {channel} verwiesen. Grund: \"{reason}.\""
"fr": "Attention : {kicker} a kické {kickee} de {channel}. Raison donnée : \"{reason}\".",
"it": "Attenzione : {kicker} ha dato una pedata a {kickee} di {channel}. Motivo : \"{reason}\"."
}, },
"cbanned": { "cbanned": {
"en": "Attention: {banner} has banned {banee} from {channel}. The reason given was \"{reason}\".", "en": "Attention: {banner} has banned {banee} from {channel}. The reason given was \"{reason}.\"",
"cy": "Sylw: {banner} wedi gwahardd {banee} o {channel}. Y rheswm a roddwyd oedd: \"{reason}\".", "cy": "Sylw: {banner} wedi gwahardd {banee} o {channel}. Y rheswm a roddwyd oedd: \"{reason}.\"",
"de": "Achtung: {banner} hat {banee} von {channel} gebannt. Grund: \"{reason}\".", "de": "Achtung: {banner} hat {banee} von {channel} gebannt. Grund: \"{reason}.\""
"fr": "Attention : {banner} a banni {banee} de {channel}. Raison donnée : \"{reason}\".",
"it": "Attenzione : {banner} ha bandito {banee} da {channel}. Motivo : \"{reason}\"."
}, },
"tbanned": { "tbanned": {
"en": "Attention: {banner} has banned {banee} (host: {host}) from the {network} network for {hours}. The reason given was \"{reason}\".", "en": "Attention: {banner} has banned {banee} from the {network} network for {hours} hours. The reason given was \"{reason}.\""
"de": "Achtung: {banner} hat {banee} vom {network} Netzwerk für {hours} Stunden verbannt. Der Grund war \"{reason}\".",
"fr": "Attention : {banner} a banni {banee} du réseau {network} pour {hours} heures. Raison donnée : \"{reason}\".",
"it": "Attenzione : {banner} ha bandito {banee} dalla rete {network} per {hours} ora/e. Motivo : \"{reason}\"."
}, },
"tbanned_notify": { "tbanned_notify": {
"en": "You have been banned from the {network} network for {hours} by {banner}. The reason given was \"{reason}\". You can join {admin_channel} for more information or to discuss the ban.", "en": "You have been banned from the {network} network for {hours} hours by {banner}. The reason given was \"{reason}.\" You can join {admin_channel} for more information or to discuss the ban."
"de": "Du wurdest von {banner} im {network} Netzwerk für {hours} verbannt. Der Grund war \"{reason}\". Du kannst {admin_channel} beitreten um mehr Informatonen zu erhalten oder über die Verbannung zu diskutieren.",
"fr": "Vous avez été banni du réseau {network} pour {hours} heures par {banner}. La raison donnée était \"{reason}\". Vous pouvez rejoindre {admin_channel} pour plus d'information or pour discuter du ban.",
"it": "Sei stato bandito dalla rete {network} per {hours} ora/e da {banner}. Motivo: \"{reason}\". Puoi ricongiungere {admin_channel} per ulteriori informazioni o discutere sulla messa al bando."
}, },
"nbanned": { "nbanned": {
"en": "Attention: {banner} has banned {banee} (host: {host}) from the {network} network. The reason given was \"{reason}\".", "en": "Attention: {banner} has banned {banee} from the {network} network. The reason given was \"{reason}.\"",
"cy": "Sylw: {banner} wedi gwahardd {banee} ledled y rhwydwaith. Y rheswm a roddwyd oedd: \"{reason}\".", "cy": "Sylw: {banner} wedi gwahardd {banee} ledled y rhwydwaith. Y rheswm a roddwyd oedd: \"{reason}.\"",
"de": "Achtung: {banner} hat {banee} auf dem gesamten Netzwerk gebannt. Grund: \"{reason}\".", "de": "Achtung: {banner} hat {banee} auf dem gesamten Netzwerk gebannt. Grund: \"{reason}.\""
"fr": "Attention : {banner} a banni {banee} du réseau {network}. Raison donnée : \"{reason}\".",
"it": "Attentione : {banner} ha bandito {banee} dalla rete {network}. Motivo : \"{reason}\"."
}, },
"nbanned_notify": { "nbanned_notify": {
"en": "You have been banned from the {network} network by {banner}. The reason given was \"{reason}\". You can join {admin_channel} for more information or to discuss the ban.", "en": "You have been banned from the {network} network by {banner}. The reason given was \"{reason}.\" You can join {admin_channel} for more information or to discuss the ban."
"de": "Du wurdest von {banner} im {network} Netzwerk verbannt. Der Grund war \"{reason}\". Du kannst {admin_channel} beitreten um mehr Informatonen zu erhalten oder über die Verbannung zu diskutieren.",
"fr": "Vous avez été banni du réseau {network} par {banner}. La raison donnée était \"{reason}\". Vous pouvez rejoindre {admin_channel} pour plus d'information or pour discuter du ban.",
"it": "Sei stato bandito dalla rete {network} da {banner}. Motivo: \"{reason}\". Puoi ricongiungere {admin_channel} per ulteriori informazioni o discutere sulla messa al bando."
}, },
"no_user": { "nban_quote": {
"en": "{user} doesn't seem to be online on this server.", "en": "{banee} was banned from the network by {banner} on {time}. The reason given was \"{reason}.\"",
"de": "{user} scheint auf diesen Server nicht online zu sein.", "cy": "Cafodd {banee} ei wahardd o'r rhwydwaith gan {banner} ar {time}. Y rheswm a roddwyd oedd: \"{reason}.\"",
"fr": "{user} ne semble pas être connecté à ce serveur.", "de": "{banee} wurde von {banner} auf dem gesamten Netzwerk um {time} gebannt. Grund: \"{reason}.\""
"it": "{user} sembra non essere connesso a questo server" },
"no_user": {
"en": "{user} doesn't seem to be online on this server."
}, },
"nunbanned": { "nunbanned": {
"en": "Attention: {unbanee} (host: {host}) has been unbanned from the {network} network by {unbanner}.", "en": "Attention: {unbanee} has been unbanned from the {network} network by {unbanner}."
"de": "Achtung: {unbanee} wurde im {network} Netzwerk durch {unbanner} entsperrt.",
"fr": "Attention : {unbanee} a été débanni du réseau {network} par {unbanner}.",
"it": "Attenzione : {unbanee} è stato riammesso alla rete {network} da {unbanner}."
}, },
"nunban_notify": { "nunban_notify": {
"en": "You have been unbanned from the {network} network by {unbanner}.", "en": "You have been unbanned from the {network} network by {unbanner}."
"de": "Du wurdest im {network} Netzwerk durch {unbanner} entsperrt.",
"fr": "Vous avez été débanni du réseau {network} par {unbanner}.",
"it": "Sei stato riammesso alla rete {network} da {unbanner}."
}, },
"nunban_error": { "nunban_error": {
"en": "It appears {unbanee} was not banned using the ~nban command.", "en": "It appears {unbanee} was not banned using the ~nban command."
"de": "Es sieht so aus als ob {unbanee} nicht durch die Verwendung des ~nban Befehls verbannt wurde.", },
"fr": "Il semble que {unbanee} n'a pas été banni en utilisant la commande ~nban.", "quote_recorded": {
"it": "Sembar che {unbanee} non è stato bandito usano il commando ~nban." "en": "This has been recorded in ~ban_{user}.",
"cy": "Mae hyn wedi cael ei gofnodi yn ~ban_{user}.",
"de": "Dies wurde in ~ban_{user} aufgenommen."
} }
} }

View File

@ -1,9 +1,7 @@
{ {
"~ckick": "~ckick [#channel] [username] [reason]", "~ckick": "~ckick [#channel] [username] [reason]",
"~cban": "~cban [#channel] [username] [reason]", "~cban": "~cban [#channel] [username] [reason]",
"~nban": "~nban ([time in hours]) [username] [reason]", "~nban": "~nban [username] [reason]",
"~kickstats": "~kickstats", "~kickstats": "~kickstats",
"~kickcount": "~kickcount [user]", "~kickcount": "~kickcount [user]"
"~quiet": "~quiet (time) (#channel) username (reason)",
"~unquiet": "~unquiet (#channel) username"
} }

View File

@ -1,11 +0,0 @@
{
"action": "kill",
"sensitivity": 10,
"exempt": [],
"advert_content": [
"________ ______"
],
"cliconn_channel": "#dnsbl",
"cliconn_patterns": [],
"exempt_channels": []
}

View File

@ -1,159 +0,0 @@
/**
* Module name: kill_namespam
* Description: destroy those wot hilight too many nicks at once . usually
* advertising their rubbish irc server (do not)
*/
var _ = require('underscore')._;
var kill_namespam = function(dbot) {
this.saveConfig = function() { // eugh
dbot.customConfig.modules.kill_namespam = this.config;
dbot.modules.admin.internalAPI.saveConfig();
}.bind(this);
this.matchedKill = {};
this.listener = function(event) {
if(event.action == 'PRIVMSG') {
// Here we listen for atropos
if(event.channel == this.config.cliconn_channel) {
if(event.message.match('▶')) {
var matchedPattern = _.find(this.config.cliconn_patterns,
function(p) { try { return event.message.match(p); } catch(e) {}; }); // ok.jpg
if(matchedPattern) {
var nick = event.message.split(' ')[2];
dbot.api.nickserv.getUserHost(event.server, nick, function(host) {
var userIsAuthenticated = host && host.startsWith('tripsit/');
if (userIsAuthenticated) {
event.reply(dbot.t('clikill_spared', {
'user': nick,
'pattern': matchedPattern
}));
} else {
if(!this.matchedKill[host]) {
// Defer killing this connection until after they join a non-exempted channel
this.matchedKill[host] = {
ip: event.message.split(' ')[1],
server: event.server,
matchedPattern: matchedPattern,
rUser: event.rUser
};
}
}
}, true);
}
}
}
// This is the namespam
if(event.channel == event.user) return; // return if pm
if(_.includes(this.config.exempt, event.user)) return;
var message;
var naughty = false;
// Check distinctive spam content match
if(_.any(this.config.advert_content, function(spam) { return event.message.indexOf(spam) != -1; })) {
message = dbot.t('spamcont_act', {
'user': event.user,
'channel': event.channel,
'action': this.config.action
}) + ' ' + dbot.t('sasl_hint');
naughty = true;
}
// Name highlight spam
if(_.filter(event.message.split(' '), function(word) { return _.has(event.channel.nicks, word); }).length > this.config.sensitivity) {
message = dbot.t('namespam_act', {
'user': event.user,
'channel': event.channel,
'action': this.config.action,
'sensitivity': this.config.sensitivity
}) + ' ' + dbot.t('sasl_hint');
naughty = true;
}
if(naughty) {
switch(this.config.action) {
case 'kickban':
dbot.api.kick.ban(event.server, event.host, event.channel);
dbot.api.kick.kick(event.server, event.user, message);
break;
case 'kill':
dbot.api.kick.kill(event.server, event.user, message);
default: break;
}
dbot.api.report.notify('spam', event.server, event.user, event.channel, message, event.host, event.user);
}
} else if (event.action == 'JOIN') {
if(this.matchedKill[event.host]) {
if(this.config.exempt_channels.indexOf(event.channel) == -1) {
var kill = this.matchedKill[event.host];
delete this.matchedKill[event.host];
// Alternatively you can just do dbot.api.kick.kill(event.server, event.user, message);
dbot.say(event.server, 'operserv', 'akill add *@'+ kill.ip +' !P Naughty Nelly Auto-kill v6.2. Matched pattern: /'+ kill.matchedPattern +'/');
var msg = dbot.t('clikill_act', {
'ip': kill.ip,
'pattern': kill.matchedPattern
});
dbot.api.report.notify('autokill', kill.server, kill.rUser,
dbot.config.servers[kill.server].admin_channel, msg, kill.ip, kill.ip);
}
}
} else if (event.action == 'QUIT') {
if(this.matchedKill[event.host]) {
delete this.matchedKill[event.host];
}
}
}.bind(this);
this.on = ['PRIVMSG', 'JOIN', 'QUIT'];
this.commands = {
'~add_spamkill': function(event) {
this.config.advert_content.push(event.params.slice(1).join(' '))
this.saveConfig();
event.reply('Users daring to utter the above to be classified as spam.');
},
'~del_spamkill': function(event) {
this.config.advert_content = _.without(this.config.advert_content, event.params.slice(1).join(' '));
this.saveConfig();
event.reply('Users will no longer be killed for this utterance.');
},
'~add_clikill': function(event) {
var pattern = event.params.slice(1).join(' ');
this.config.cliconn_patterns.push(pattern);
this.saveConfig();
event.reply('Client connection notices matching pattern /'+ pattern +'/ shall henceforth get rekt.');
},
'~del_clikill': function(event) {
var pattern = event.params.slice(1).join(' ');
this.config.cliconn_patterns = _.without(this.config.cliconn_patterns, pattern);
this.saveConfig();
event.reply('Client connection notices matching pattern /'+ pattern +'/ will no longer get rekt.');
},
'~list_clikill': function(event) {
event.reply('Currently active "cliconn" kills (to use add/del, provide the pattern, not the index, and do not include the surrounding //');
_.each(this.config.cliconn_patterns, function(pattern, i) {
event.reply('['+i+'] /' + pattern + '/');
});
}
};
_.each(this.commands, function(c) {
c.access = 'moderator';
});
};
exports.fetch = function(dbot) {
return new kill_namespam(dbot);
};

View File

@ -1,17 +0,0 @@
{
"namespam_act": {
"en": "{user} triggered nickname hilight anti-spam (greater than {sensitivity}). Action: {action}."
},
"spamcont_act": {
"en": "{user} triggered advertising anti-spam (content). Action: {action}"
},
"clikill_act": {
"en": "Added K-Line for {ip}, due to matching pattern: /{pattern}/"
},
"clikill_spared": {
"en": "{user} spared from clikill matched pattern: /{pattern}/"
},
"sasl_hint": {
"en": "You have been killed by our spam filter. You can avoid broad VPN filters by using SASL."
}
}

View File

@ -1,66 +0,0 @@
## LastFM
Adds various LastFM functionalities.
### Description
This module provides a command which allows users to show stats of LastFM and such stuff.
### Dependencies
It has following dependencies:
+ [request](https://github.com/mikeal/request)
+ [async](https://github.com/caolan/async)
+ [moment](https://github.com/moment/moment)
### config.json
api_key and output prefix can be set.
Example:
```
{
"dependencies": [ "profile" ],
"api_key": "blah",
"outputPrefix": "\u000315,5last.fm\u000f"
}
```
### Commands
#### ~lastfm [user]
Display all scrobbles of a user.
Example:
+ ~lastfm reality
#### ~scrobbliest
Displays the users with the most scrobbles.
Example:
+ ~scrobbliest
#### ~suggestion
Displays a suggestion based on the listened scrobbles.
Example:
+ ~suggestion
#### ~listening
Displays the currently/last played song of the posting user.
Example:
+ ~listening
#### ~taste [user]
Compares two users (the posting user and the defined user).
Example:
+ ~taste reality
#### ~tastiest
Displays the users that matches the most in music taste.
Example:
+ ~tastiest
#### ~artists [user]
Compares two users (the posting user and the defined user) and displays their matching artists.
Example:
+ ~artists reality
### TODO

View File

@ -1,5 +0,0 @@
{
"dependencies": [ "profile", "youtube", "spotify" ],
"api_key": "blah",
"outputPrefix": "\u000315,5last.fm\u000f"
}

View File

@ -1,526 +0,0 @@
/**
* Module Name: Last.FM
* Description: Various lastfm functionality.
*/
var _ = require('underscore')._,
request = require('request'),
async = require('async'),
moment = require('moment');
var lastfm = function(dbot) {
this.ApiRoot = 'http://ws.audioscrobbler.com/2.0/';
this.internalAPI = {
'getLastFM': function(server, nick, callback) {
dbot.api.profile.getProfile(server, nick, function(err, user, profile) {
if(user) {
if(profile && _.has(profile.profile, 'lastfm') && _.isString(profile.profile.lastfm)) {
callback(user, profile.profile.lastfm.toLowerCase());
} else {
callback(user, null);
}
} else {
callback(null, null);
}
});
}
};
this.api = {
'getRandomArtistTrack': function(mbid, callback) {
request.get(this.ApiRoot, {
'qs': {
'method': 'artist.gettoptracks',
'mbid': mbid,
'api_key': this.config.api_key,
'format': 'json',
'limit': 10
},
'json': true
}, function(err, res, body) {
if(_.has(body, 'toptracks') && _.has(body.toptracks, 'track')) {
var tracks = body.toptracks.track;
choice = _.random(0, tracks.length - 1),
track = tracks[choice];
callback(null, track);
} else {
callback('idk', body);
}
});
},
'getSimilarArtists': function(mbid, callback) {
request.get(this.ApiRoot, {
'qs': {
'method': 'artist.getsimilar',
'mbid': mbid,
'api_key': this.config.api_key,
'format': 'json',
'limit': 10
},
'json': true
}, function(err, res, body) {
if(_.has(body, 'similarartists') && _.has(body.similarartists, 'artist')) {
callback(null, body.similarartists.artist);
} else {
callback('idk', body);
}
});
},
'getListening': function(username, callback) {
request.get(this.ApiRoot, {
'qs': {
'user': username,
'limit': 2,
'nowplaying': true,
'method': 'user.getrecenttracks',
'api_key': this.config.api_key,
'format': 'json'
},
'json': true
}, function(err, res, body) {
if(_.has(body, 'error') && body.error == 6) {
callback('no_user', null);
} else if(_.has(body, 'recenttracks') && _.has(body.recenttracks, 'track')
&& !_.isUndefined(body.recenttracks.track[0])) {
callback(null, body.recenttracks.track[0]);
} else {
callback('no_listen', null);
}
});
},
/*
'tasteCompare': function(user, oUser, callback) {
request.get(this.ApiRoot, {
'qs': {
'type1': 'user',
'type2': 'user',
'value1': user,
'value2': oUser,
'method': 'tasteometer.compare',
'api_key': this.config.api_key,
'format': 'json'
},
'json': true
}, function(err, res, body) {
console.log(body);
if(_.has(body, 'error') && body.error == 6 || body.error == 7) {
callback('no_user', user, null);
} else if(_.has(body, 'comparison') && _.has(body.comparison, 'result')) {
callback(null, body.comparison.result);
} else {
callback('idk', null);
}
});
},
*/
'getInfo': function(lfm, callback) {
request.get(this.ApiRoot, {
'qs': {
'user': lfm,
'method': 'user.getinfo',
'api_key': this.config.api_key,
'format': 'json'
},
'json': true
}, function(err, res, body) {
if(_.has(body, 'error') && body.error == 6 || body.error == 7) {
callback('no_user', null);
} else if(_.has(body, 'user')) {
callback(null, body.user);
} else {
callback('idk', null);
}
});
}
};
this.commands = {
'~lastfm': function(event) {
var user = event.rUser,
lfm = event.rProfile.lastfm;
if(event.res[0]) {
user = event.res[0].user;
lfm = event.res[0].lfm;
}
this.api.getInfo(lfm, function(err, profile) {
if(!err) {
console.log(profile);
event.reply(dbot.t('lfm_profile', {
'user': user.currentNick,
'plays': profile.playcount.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,"),
'date': moment(profile.registered['#text'] * 1000).format('DD/MM/YYYY'),
'link': profile.url
}));
} else {
if(err == 'no_user') {
event.reply(dbot.t('lfm_unknown'));
} else if(err == 'no_listen') {
event.reply(dbot.t('no_listen', { 'user': event.user }));
}
}
});
},
'~scrobbliest': function(event) {
dbot.api.profile.getAllProfilesWith('lastfm', function(profiles) {
if(profiles) {
var plays = [];
async.each(profiles, function(profile, done) {
this.api.getInfo(profile.profile.lastfm, function(err, lProfile) {
if(!err) {
plays.push({
'user': profile.id,
'plays': parseInt(lProfile.playcount)
});
}
done();
});
}.bind(this), function() {
var scrobbliest = _.chain(plays)
.sortBy(function(p) { return p.plays; })
.reverse()
.first(10)
.value();
async.each(scrobbliest, function(item, done) {
dbot.api.users.getUser(item.user, function(err, user) {
item.user = user;
done();
});
}, function() {
var output = dbot.t('lfm_scrobbliest');
_.each(scrobbliest, function(item) {
output += item.user.currentNick + ' (' +
item.plays.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,")+ '), ';
});
event.reply(output.slice(0, -2));
});
}.bind(this));
} else {
event.reply('no suitable profiles');
}
}.bind(this));
},
'~suggestion': function(event) {
this.api.getListening(event.rProfile.lastfm, function(err, track) {
if(!err) {
this.api.getSimilarArtists(track.artist.mbid, function(err, similar) {
if(!err) {
var choice = _.random(0, similar.length - 1);
this.api.getRandomArtistTrack(similar[choice].mbid, function(err, track) {
if(!err) {
var output = dbot.t('lfm_suggestion', {
'user': event.user,
'name': track.name,
'artist': track.artist.name
});
var term = track.name + ' ' + track.artist.name;
async.parallel({
youtube: function(cb) {
dbot.api.youtube.search(term, function(body) {
if(_.isObject(body) && _.has(body, 'items') && body.items.length > 0) {
var link = body.items[0].id.videoId
if(link) {
cb(null,"https://youtu.be/" + link);
} else {
cb(null, undefined);
}
}
});
},
spotify: function(cb) {
dbot.api.spotify.spotifySearch(term, function(body, url, uri) {
if(body) {
if (!dbot.modules.minify) {
cb(null, { url: url, uri:uri });
} else {
dbot.modules.minify.api.minify(url, "bitly", function(mini) {
cb(null, { url:mini || url, uri:uri });
});
}
} else {
cb(null, undefined);
}
});
}
}, function(err, results) {
if (results.youtube || results.spotify) output += " - "
if (results.youtube) output += results.youtube;
if (results.spotify) {
if (results.youtube) output += " | ";
output += results.spotify.url + " - " + results.spotify.uri;
}
event.reply(output);
});
} else {
event.reply('Couldn\'t get any suggested tracks.');
console.log(err);
}
});
} else {
event.reply('Couldn\'t find any similar artists to what you\'re listening to.');
console.log(err);
}
}.bind(this));
} else {
if(err == 'no_user') {
event.reply(dbot.t('lfm_unknown'));
} else if(err == 'no_listen') {
event.reply(dbot.t('no_listen', { 'user': event.user }));
}
}
}.bind(this));
},
'~listening': function(event) {
var user = event.rUser,
lfm = event.rProfile.lastfm;
if(event.res[0]) {
user = event.res[0].user;
lfm = event.res[0].lfm;
}
this.api.getListening(lfm, function(err, track) {
if(!err) {
var term = track.name + ' ' + track.artist['#text'],
output = '';
if(_.has(track, '@attr') && _.has(track['@attr'], 'nowplaying') && track['@attr'].nowplaying == 'true') {
output = dbot.t('now_listening', {
'user': user.currentNick,
'track': track.name,
'artist': track.artist['#text']
});
} else {
output = dbot.t('last_listened', {
'user': user.currentNick,
'track': track.name,
'artist': track.artist['#text']
});
}
async.parallel({
youtube: function(cb) {
dbot.api.youtube.search(term, function(body) {
if(_.isObject(body) && _.has(body, 'items') && body.items.length > 0) {
var link = body.items[0].id.videoId
if(link) {
cb(null,"https://youtu.be/" + link);
} else {
cb(null, undefined);
}
}
});
},
spotify: function(cb) {
dbot.api.spotify.spotifySearch(term, function(body, url, uri) {
if(body) {
if (!dbot.modules.minify) {
cb(null, { url: url, uri:uri });
} else {
dbot.modules.minify.api.minify(url, "bitly", function(mini) {
cb(null, { url:mini || url, uri:uri });
});
}
} else {
cb(null, undefined);
}
});
}
}, function(err, results) {
if (results.youtube || results.spotify) output += " - "
if (results.youtube) output += results.youtube;
if (results.spotify) {
if (results.youtube) output += " | ";
output += results.spotify.url + " - " + results.spotify.uri;
}
event.reply(output);
});
} else {
if(err == 'no_user') {
event.reply(dbot.t('lfm_unknown'));
} else if(err == 'no_listen') {
event.reply(dbot.t('no_listen', { 'user': user.currentNick }));
}
console.log(err);
}
});
},
/*
'~taste': function(event) {
var u1 = event.rUser,
lfm1 = event.rProfile.lastfm,
u2 = event.res[0].user,
lfm2 = event.res[0].lfm;
this.api.tasteCompare(event.rProfile.lastfm, lfm2, function(err, comp) {
if(!err) {
var score = Math.floor(comp.score * 100);
event.reply(dbot.t('taste_compat', {
'user1': event.user,
'user2': u2.currentNick,
'score': score
}));
} else {
if(err == 'no_user') {
event.reply('Unknown Last.FM user.');
} else {
event.reply('Well something went wrong and I don\'t know what it means');
}
}
});
},
'~tastiest': function(event) {
var sortGoodScores = function(goodScores) {
var tastiest = _.chain(goodScores)
.sortBy(function(p) { return p.score; })
.reverse()
.first(10)
.value();
async.each(tastiest, function(pair, done) {
if(!_.isObject(pair.p1)) { // fix this
dbot.api.users.getUser(pair.p1, function(err, user) {
pair.p1 = user;
dbot.api.users.getUser(pair.p2, function(err, user) {
pair.p2 = user;
done();
});
});
} else {
done();
}
}, function() {
var output = 'Most musically compatible users: ';
_.each(tastiest, function(pair) {
output += pair.p1.currentNick + ' & ' +
pair.p2.currentNick + ' (' + pair.score +
'%), ';
});
event.reply(output.slice(0, -2));
});
};
if(this.tastyCache && Date.now() - this.tastyCacheStamp <= 1800000) {
sortGoodScores(this.tastyCache);
} else {
event.reply('Updating tasty cache... Hold onto your coconuts...');
dbot.api.profile.getAllProfilesWith('lastfm', function(profiles) {
if(profiles) {
var scores = {}; // Using this structure first for easier testing in the async
async.eachSeries(profiles, function(p1, next) {
scores[p1.id] = {};
async.eachSeries(profiles, function(p2, subnext) {
if(p1.id == p2.id || p1.profile.lastfm == p2.profile.lastfm || _.has(scores, p2.id) && _.has(scores[p2.id], p1.id)) {
subnext();
} else {
this.api.tasteCompare(p1.profile.lastfm, p2.profile.lastfm, function(err, comp) {
if(!err) {
var score = Math.floor(comp.score * 100);
scores[p1.id][p2.id] = score;
}
subnext();
});
}
}.bind(this), function() { next(); });
}.bind(this), function(err) {
// Now we better structure the scores for sorting
var goodScores = [];
_.each(scores, function(subscores, p1) {
_.each(subscores, function(aScore, p2) {
goodScores.push({
'p1': p1,
'p2': p2,
'score': aScore
});
});
});
this.tastyCache = goodScores;
this.tastyCacheStamp = new Date().getTime();
sortGoodScores(goodScores);
}.bind(this));
} else {
event.reply('No suitable profiles');
}
}.bind(this));
}
},
*/
'~artists': function(event) {
var u1 = event.rUser,
lfm1 = event.rProfile.lastfm,
u2 = event.res[0].user,
lfm2 = event.res[0].lfm;
this.api.tasteCompare(event.rProfile.lastfm, lfm2, function(err, comp) {
if(!err) {
var artists = _.pluck(comp.artists.artist, 'name').join(', ');
event.reply(dbot.t('common_artists', {
'user1': event.user,
'user2': u2.currentNick,
'common': artists
}));
} else {
if(err == 'no_user') {
event.reply(dbot.t('lfm_unknown'));
} else {
event.reply('Well something went wrong and I don\'t know what it means');
}
}
});
}
};
//this.commands['~taste'].regex = [/^taste ([\d\w[\]{}^|\\`_-]+?)/, 2];
this.commands['~artists'].regex = [/^artists ([\d\w[\]{}^|\\`_-]+?)/, 2];
_.each(this.commands, function(command) {
command.resolver = function(event, callback) {
if(event.rProfile && _.has(event.rProfile, 'lastfm')) {
if(event.params[1]) {
this.internalAPI.getLastFM(event.server, event.params[1], function(user, lfm) {
if(user && lfm) {
event.res.push({
'user': user,
'lfm': lfm
});
callback(false);
} else {
if(!user) {
event.reply('Unknown user.');
} else {
event.reply(user.currentNick + ': Set a lastfm username with "~set lastfm username"');
}
callback(true);
}
});
} else {
callback(false);
}
} else {
event.reply(event.user + ': Set a lastfm username with "~set lastfm username"');
callback(true);
}
}.bind(this);
}, this);
};
exports.fetch = function(dbot) {
return new lastfm(dbot);
};

View File

@ -1,35 +0,0 @@
{
"now_listening": {
"en": "{user} is listening to {track} by {artist}",
"de": "{user} hört {track} von {artist}"
},
"last_listened": {
"en": "{user} last listened to {track} by {artist}",
"de": "{user} hörte zuletzt {track} von {artist}"
},
"no_listen": {
"en": "{user} doesn't seem to have listened to anything recently :'(",
"de": "{user} scheint in letzter Zeit nichts gehört zu haben :'("
},
"taste_compat": {
"en": "{user1} and {user2} are {score}% musically compatible!",
"de": "{user1} und {user2} sind {score}% musikalisch kompatibel!"
},
"common_artists": {
"en": "Artists {user1} and {user2} have in common: {common}",
"de": "Künstler, die {user1} und {user2} gemeinsam haben: {common}"
},
"lfm_suggestion": {
"en": "{user}: Try listening to {name} by {artist}",
"de": "{user}: Versuche mal, {name} von {artist} anzuhören"
},
"lfm_profile": {
"en": "{user} has scrobbled {plays} tracks since {date} - {link}"
},
"lfm_scrobbliest": {
"en": "Users with the most played tracks: "
},
"lfm_unknown": {
"en": "Unknown Last.FM user. Please set your Last.FM user by typing '~set lastfm <name>' where <name> is your Last.FM username."
}
}

View File

@ -1,5 +0,0 @@
{
"outputPrefix": "\u00033weed\u000f",
"app_key": "",
"app_id": ""
}

View File

@ -1,47 +0,0 @@
/**
* Module name: Leafly
* Description: Information from leafly
*/
var _ = require('underscore')._,
request = require('request');
var leafly = function(dbot) {
var ApiRoot = 'http://data.leafly.com/';
this.commands = {
'~strain': function(event) {
request.post(ApiRoot + 'strains', {
'headers': {
'app_key': this.config.app_key,
'app_id': this.config.app_id
},
'body': {
'page': 0,
'take': 1,
'sort': 'rating',
'search': event.input[1]
},
'json': true
}, function(error, response, body) {
if(_.isObject(body) && _.has(body, 'Strains') && body.Strains.length > 0) {
var strain = body.Strains[0],
flavours = _.pluck(strain.Flavors, 'Name').join(', ');
event.reply(dbot.t('strain', {
'name': strain.Name,
'flavours': flavours,
'link': strain.permalink
}));
} else {
event.reply(dbot.t('no_strains'));
}
}.bind(this));
}
};
this.commands['~strain'].regex = [/^strain (.+)$/, 2];
};
exports.fetch = function(dbot) {
return new leafly(dbot);
};

View File

@ -1,8 +0,0 @@
{
"strain": {
"en": "{name} tastes of {flavours} - {link}"
},
"no_strains": {
"en": "No strains found :("
}
}

View File

@ -1,5 +1,6 @@
{ {
"autoTitle": true, "autoTitle": false,
"dependencies": [ "command" ],
"ignorable": true, "ignorable": true,
"outputPrefix": "\u00032link\u000f", "outputPrefix": "\u00032link\u000f",
"help": "http://github.com/reality/depressionbot/blob/master/modules/link/README.md" "help": "http://github.com/reality/depressionbot/blob/master/modules/link/README.md"

View File

@ -26,8 +26,8 @@ var link = function(dbot) {
size = 0, size = 0,
page = request(link.replace('https', 'http'), function(error, response, body) { page = request(link.replace('https', 'http'), function(error, response, body) {
if(!error && response.statusCode == 200) { if(!error && response.statusCode == 200) {
body = body.replace(/(\r\n|\n\r|\n)/gim, " "); body = body.replace(/(\r\n|\n\r|\n)/gm, " ");
var title = body.valMatch(/<title>(.*?)<\\?\/title>/, 2); var title = body.valMatch(/<title>(.*)<\/title>/, 2);
if(title && title.length < 140) { if(title && title.length < 140) {
callback(ent.decode(title[1]).trim()); callback(ent.decode(title[1]).trim());
} }
@ -47,43 +47,16 @@ var link = function(dbot) {
encodeURI(query); encodeURI(query);
request(reqUrl, function(error, response, body) { request(reqUrl, function(error, response, body) {
console.log(reqUrl);
try { try {
var result = JSON.parse(body); var result = JSON.parse(body);
if(_.has(result, 'list') && result.list.length > 0) { if(_.has(result, 'result_type') && result.result_type != 'no_results') {
callback(result.list[0].word, result.list[0].definition.split('\n')[0]); callback(result.list[0].word, result.list[0].definition.split('\n')[0]);
} else { } else {
callback(false); callback(false);
} }
} catch(err) { } catch(err) { callback(false); }
console.log(err);
callback(false);
}
}); });
},
'parseLink': function(link, callback) {
var handler = false;
for(var i=0;i<this.handlers.length;i++) {
var matches = this.handlers[i].regex.exec(link);
if(matches) {
console.log(this.handlers[i].name);
handler = this.handlers[i];
break;
}
}
if(handler) {
this.handlers[i].callback(matches, this.handlers[i].name, function(parsed) {
callback(parsed);
});
} else {
this.api.getTitle(link, function(title) {
callback(dbot.t('link', { 'link': title } ));
});
}
} }
}; };
@ -102,8 +75,7 @@ var link = function(dbot) {
}, },
'~xkcd': function(event) { '~xkcd': function(event) {
//var comicId = event.params[1] || ""; var comicId = event.params[1] || "";
var comicId = event.params.slice(1).join(' ');
if(comicId == "*") { if(comicId == "*") {
request("http://xkcd.com/info.0.json", function(error, response, body){ request("http://xkcd.com/info.0.json", function(error, response, body){
@ -116,82 +88,23 @@ var link = function(dbot) {
} catch(err) { }; } catch(err) { };
}); });
} else { } else {
if (isNaN(parseInt(comicId))) { if(comicId !== "") {
request({ comicId = comicId + "/";
url: 'http://www.explainxkcd.com/wiki/api.php',
qs: {
action: 'query',
format: 'json',
generator: 'search',
gsrwhat: 'text',
gsrsearch: comicId,
prop: 'info|categories',
gsrlimit: 50
},
json: true
}, function(err, res, body) {
if(!body) {
event.reply(dbot.t("no-hits"));
return;
}
var pages = _.values(body.query.pages);
// page titles must be of the format "####: $$$$$$"
pages = _.filter(pages, p => p.title.indexOf(':') > 0);
if (pages.length > 0) {
// See if any of these matches are exact title matches
var match = false;
_.each(pages, function(p) {
var title = p.title.slice(p.title.indexOf(':')+2).trim();
if(title.toLowerCase() == comicId.toLowerCase()) {
match = p;
}
});
if (match) {
// We got a match! Get the ID and let's get tf out of here.
comicId = match.title.slice(0, match.title.indexOf(':'));
} else {
comicId = pages[0].title.slice(0, pages[0].title.indexOf(':'));
}
var link = "http://xkcd.com/"+comicId+"/info.0.json";
request(link, function(error, response, body) {
try {
if (response.statusCode == "200") {
data = JSON.parse(body);
event.reply(dbot.t("xkcd", data));
} else {
event.reply(dbot.t("no-hits"));
}
} catch(err) { };
});
} else {
event.reply(dbot.t("no-hits"));
}
});
} else {
if(comicId !== "") {
comicId = comicId + "/";
}
var link = "http://xkcd.com/"+comicId+"info.0.json";
request(link, function(error, response, body) {
try {
if (response.statusCode == "200") {
data = JSON.parse(body);
event.reply(dbot.t("xkcd", data));
} else {
event.reply(dbot.t("no-hits"));
}
} catch(err) { };
});
} }
var link = "http://xkcd.com/"+comicId+"info.0.json";
request(link, function(error, response, body) {
try {
if (response.statusCode == "200") {
data = JSON.parse(body);
event.reply(dbot.t("xkcd", data));
} else {
event.reply(dbot.t("no-hits"));
}
} catch(err) { };
});
} }
}, },
'~ud': function(event) { '~ud': function(event) {
@ -206,18 +119,27 @@ var link = function(dbot) {
}); });
} }
}; };
commands['~ud'].regex = [/ud (.+)/, 2]; commands['~ud'].regex = [/~ud (.+)/, 2];
this.commands = commands; this.commands = commands;
this.listener = function(event) { this.listener = function(event) {
var urlMatches = event.message.match(this.urlRegex); var urlMatches = event.message.match(this.urlRegex);
if(urlMatches !== null) { if(urlMatches !== null) {
this.links[event.channel.name] = urlMatches[0]; this.links[event.channel.name] = urlMatches[0];
console.log('DEBUG: got a link'); if(dbot.config.link.autoTitle == true) {
if(this.config.autoTitle == true) { var handlerFound = false;
this.api.parseLink(urlMatches[0], function(result) { for(var i=0;i<this.handlers.length;i++) {
event.reply(result); var matches = this.handlers[i].regex.exec(urlMatches[0]);
}); if(matches) {
this.handlers[i].callback(event, matches, this.handlers[i].name);
handlerFound = true; break;
}
}
if(!handlerFound) {
this.api.getTitle(urlMatches[0], function(title) {
event.reply(dbot.t('link', { 'link': title } ));
});
}
} }
} }
}.bind(this); }.bind(this);

View File

@ -4,29 +4,19 @@
"na'vi": "Oel ke tsun run 'upxare atxin.", "na'vi": "Oel ke tsun run 'upxare atxin.",
"cy": "Ni chanfuwyd teitl y dudalen", "cy": "Ni chanfuwyd teitl y dudalen",
"nl": "Er is geen paginatitel gevonden.", "nl": "Er is geen paginatitel gevonden.",
"de": "Kein Seitenname gefunden.", "de": "Kein Seitenname gefunden."
"fr": "Aucun titre de page trouvé.",
"it": "Nessun titolo di pagina trovato."
}, },
"xkcd": { "xkcd": {
"en": "xkcd {num}: {title} https://xkcd.com/{num}", "en": "xkcd {num}: {title} https://xkcd.com/{num}"
"fr": "xkcd {num}: {title} https://xkcd.com/{num}",
"it": "xkcd {num}: {title} https://xkcd.com/{num}",
"de": "xkcd {num}: {title} https://xkcd.com/{num}"
}, },
"no-hits": { "no-hits": {
"en": "No hits.", "en": "No hits.",
"na'vi": "Oel ke tsun rivum ayuoti.", "na'vi": "Oel ke tsun rivum ayuoti.",
"cy": "Dim canlyniadau.", "cy": "Dim canlyniadau.",
"nl": "Geen resultaten.", "nl": "Geen resultaten.",
"de": "Keine Treffer.", "de": "Keine Treffer."
"fr": "Aucun résultat.",
"it": "Nessun risultato."
}, },
"link": { "link": {
"en": "{link}", "en": "{link}"
"fr": "{link}",
"it": "{link}",
"de": "{link}"
} }
} }

Some files were not shown because too many files have changed in this diff Show More