3
0
mirror of https://github.com/reality/dbot.git synced 2025-08-02 17:37:27 +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
config.json
db.json
# ignore npm

11
.gitmodules vendored
View File

@ -1,6 +1,9 @@
[submodule "jsbot"]
path = jsbot
url = git://github.com/reality/jsbot.git
path = jsbot
url = git://github.com/reality/jsbot.git
[submodule "modules/github"]
path = modules/github
url = git://github.com/zuzak/dbot-github.git
path = modules/github
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
writing documentation.
## Getting Started
Requirements:
To get started with DBot, you first need to decide on a database system to use.
DBot uses the [databank](http://github.com/e14n/databank) library, and each
module can be configured to use any database driver databank supports in its
respective config.json file. There is currently no default database driver
option.
- Node JS
- [JSBot](http://github.com/reality/JSBot "JSBot"), a Javascript library which
handles the IRC protocol
- Underscore JS library
- Various modules have their own requirements also.
The default for all modules is the 'redis' driver, and you can simply install
the Redis server to get going.
### External Modules
Once you have that set up, you can install DBot's dependencies, configure and
run the bot for the first time with the following command:
```
./install
```
## 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!
JSBot and externally developed modules can be imported by running the following
commands in the cloned repository:
git submodule init
git submodule update

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"
_.each(dbot.modules, function(module) { "RESCORE EVERYTHING" });
"He called his bot depressionbot, and that's when he was happy."

View File

@ -15,13 +15,10 @@
"admins": [ "batman" ],
"moderators": [ "whatever" ],
"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",
"debugMode": false,
"debugLevel": 1,
"dbType": "redis",
"redisPort": 6379,
"timezone": "Europe/London",
"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
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 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
@ -55,18 +46,12 @@ loaded by the standard DBot process.
Unload a currently loaded module. This removes the module, and then triggers a
reload of all modules.
#### setconfig [path] [value]
Set a config value at path to be a certain value persistently. For example, if
you want to change the web module to listen on port 9001, you can run _setconfig
web.webPort 9001_.
#### ban [user] [command]
Ban a user from using a command. Command may be replaced with '\*,' which will
ban a user from use of all commands. Users banned from all commands will still
be subject to module listeners.
#### pushconfig [path] [value]
Push a new value to an existing config array. For example, if you want to add
the user 'batman62' to the DBot moderators, you can run _pushconfig moderators
batman62_.
#### 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.
#### unban [user] [command]
Unban a user from using a given command. If a user was previously banned using
the '\*' wildcard, they may also be unbanned from such by replacing command with
an asterisk here as well.

View File

@ -1,62 +1,12 @@
/**
* Module Name: Admin
* 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'),
_ = require('underscore')._;
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) {

View File

@ -1,12 +1,49 @@
var fs = require('fs'),
_ = require('underscore')._,
sys = require('sys'),
process = require('process'),
exec = require('child_process').exec;
var commands = function(dbot) {
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 = {
// Join a channel
'~join': function(event) {
@ -41,23 +78,16 @@ var commands = function(dbot) {
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
'~greload': function(event) {
exec("git pull", function (error, stdout, stderr) {
exec("git submodule update", function (error, stdout, stderr) {
event.reply(dbot.t('gpull'));
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));
},
@ -90,15 +120,9 @@ var commands = function(dbot) {
if(_.has(dbot.status, moduleName)) {
var status = dbot.status[moduleName];
if(status === true) {
event.reply(dbot.t('status_good', {
'module': moduleName,
'reason': status
}));
event.reply(dbot.t("status_good",{"module":moduleName, "reason": status}));
} else {
event.reply(dbot.t('status_bad', {
'module': moduleName,
'reason': status
}));
event.reply(dbot.t("status_bad",{"module":moduleName, "reason": status}));
}
} else {
event.reply(dbot.t("status_unloaded"));
@ -109,9 +133,7 @@ var commands = function(dbot) {
'~reload': function(event) {
dbot.db = JSON.parse(fs.readFileSync('db.json', 'utf-8'));
dbot.reloadModules();
process.nextTick(function() {
event.reply(dbot.t('reload'));
});
event.reply(dbot.t('reload'));
},
// Say something in a channel
@ -128,21 +150,18 @@ var commands = function(dbot) {
'~load': function(event) {
var moduleName = event.params[1];
if(!_.include(dbot.config.moduleNames, moduleName)) {
dbot.customConfig.moduleNames.push(moduleName);
this.internalAPI.saveConfig();
dbot.config.moduleNames.push(moduleName);
dbot.reloadModules();
process.nextTick(function() {
if(dbot.status[moduleName] === true) {
event.reply(dbot.t('load_module', { 'moduleName': moduleName }));
} else {
event.reply(dbot.t('load_failed', { 'module': moduleName }));
}
});
if(dbot.status[moduleName] === true) {
event.reply(dbot.t('load_module', {'moduleName': moduleName}));
} else {
event.reply(dbot.t("load_failed",{"module": moduleName}));
}
} else {
if(moduleName == 'web') {
event.reply(dbot.t('already_loaded_web'));
} 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);
delete require.cache[cacheKey];
} catch(err) { }
dbot.customConfig.moduleNames = _.without(dbot.config.moduleNames, moduleName);
this.internalAPI.saveConfig();
dbot.config.moduleNames = _.without(dbot.config.moduleNames, moduleName);
dbot.reloadModules();
process.nextTick(function() {
event.reply(dbot.t('unload_module', { 'moduleName': moduleName }));
});
event.reply(dbot.t('unload_module', {'moduleName': moduleName}));
} else {
event.reply(dbot.t('unload_error', { 'moduleName': moduleName }));
event.reply(dbot.t('unload_error', {'moduleName': moduleName}));
}
},
/*** Config options ***/
'~setconfig': function(event) {
var configPath = event.input[1],
newOption = event.input[2];
var configPathString = event.params[1],
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)) {
this.internalAPI.getCurrentConfig(configPath, function(config) {
if(config !== null) {
// Convert to boolean type if config item boolean
if(_.isBoolean(config)) {
newOption = (newOption == "true");
}
if(configPath == false || _.isUndefined(configPath.value)) {
event.reply(dbot.t("no_config_key"));
return;
}
var currentOption = configPath.value;
// Convert to integer type is config item integer
if(_.isNumber(config)) {
newOption = parseInt(newOption);
}
// Convert to boolean type if config item boolean
if(_.isBoolean(currentOption)) {
newOption = (newOption == "true");
}
if(_.isArray(config)) {
event.reply(dbot.t("config_array", { "alternate": "pushconfig" }));
}
} 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 }));
}
}
// Convert to integer type is config item integer
if(_.isNumber(currentOption)) {
newOption = parseInt(newOption);
}
this.internalAPI.setConfig(configPath, newOption, function(err) {
event.reply(configPath + ": " + config + " -> " + newOption);
});
}.bind(this));
if(_.isArray(currentOption)) {
event.reply(dbot.t("config_array",{"alternate": "pushconfig"}));
}
event.reply(configPathString + ": " + currentOption + " -> " + newOption);
configPath['user'][configKey] = newOption;
dbot.reloadModules();
} else {
event.reply(dbot.t("config_lock"));
}
},
'~pushconfig': function(event) {
var configPath = event.input[1],
newOption = event.input[2];
var configPathString = event.params[1],
configKey = _.last(configPathString.split('.')),
newOption = event.params[2];
if(!_.include(noChangeConfig, configPath)) {
this.internalAPI.getCurrentConfig(configPath, function(config) {
if(config !== null) {
if(_.isArray(config)) {
event.reply(configPath + ": " + config + " << " + newOption);
config.push(newOption);
this.internalAPI.setConfig(configPath, config, function(err) {});
} 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"));
}
},
if(!_.include(noChangeConfig, configKey)) {
var configPath = getCurrentConfig(configPathString);
if(configPath == false || _.isUndefined(configPath.value)) {
event.reply(dbot.t("no_config_key"));
return;
}
var currentArray = configPath.value;
'~rmconfig': function(event) {
var configPath = event.input[1],
rmOption = event.input[2];
if(!_.isArray(currentArray)) {
event.reply(dbot.t("config_array",{"alternate": "setconfig"}));
return;
}
if(!_.include(noChangeConfig, configPath)) {
this.internalAPI.getCurrentConfig(configPath, function(config) {
if(config !== null) {
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"));
event.reply(configPathString + ": " + currentArray + " << " + newOption);
currentArray.push(newOption);
dbot.reloadModules();
}
},
'~showconfig': function(event) {
var configPath = event.params[1];
if(configPath.indexOf('servers') != -1) { return false; }
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}));
var configPathString = event.params[1];
var configPath = getCurrentConfig(configPathString);
if(configPathString) {
var configKey = _.last(configPathString.split('.'));
if(!configKey) {
event.reply(dbot.t("no_config_path"));
return;
}
configPath = configPath.split('.');
if(_.has(dbot.config.modules, configPath[0])) {
configPath.splice(0, 0, 'modules');
} else {
configPath.pop();
}
event.params[1] = configPath.join('.');
commands['~showconfig'](event);
}
}.bind(this));
if(_.isArray(configPath.value)) {
event.reply(configKey + ': ' + configPath.value);
} else if(_.isObject(configPath.value)) {
event.reply(dbot.t("config_keys_location",{"path":configPathString,"value":Object.keys(configPath.value)}));
} else {
event.reply(configKey + ': ' + configPath.value);
}
} else {
event.reply(dbot.t("config_keys_location", {
"path": "root",
"value": _.keys(dbot.config)
}));
event.reply(dbot.t("config_keys_location",{"path":"root","value":Object.keys(configPath['default'])}));
}
},
'~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';
});
commands['~showconfig'].access = 'admin';
commands['~join'].access = 'power_user';
commands['~part'].access = 'power_user';
commands['~showconfig'].access = 'moderator';
commands['~join'].access = 'moderator';
commands['~part'].access = 'moderator';
commands['~opme'].access = 'moderator';
commands['~forceopme'].access = 'power_user';
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];
commands['~say'].access = 'moderator';
return commands;
};

View File

@ -1,5 +1,5 @@
{
"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)",
"cy": "Wedi ymuno {channel}",
"nl": "{channel} binnengekomen",
"de": "{channel} beigetreten",
"fr": "{channel} rejoint",
"it": "Aderito a {channel}"
"de": "{channel} beigetreten"
},
"part": {
"en": "Left {channel}",
@ -15,9 +13,7 @@
"na'vi": "Hum {channel}",
"cy": "Wedi gadael {channel}",
"nl": "{channel} verlaten",
"de": "{channel} verlassen",
"fr": "{channel} quitté",
"it": "uscito da {channel}"
"de": "{channel} verlassen"
},
"gpull": {
"en": "Git pulled that shit.",
@ -25,9 +21,7 @@
"na'vi": "Gìtìl fì'uti stamarsìm.",
"cy": "Wedi tynnu git yr cach na i gyd",
"nl": "Git heeft die zooi binnengehaald.",
"de": "Git hat es gezogen",
"fr": "Git a pullé cette merde",
"it": "Git ha pullato questa coglionata"
"de": "Git hat es gezogen"
},
"reload": {
"en": "Reloaded that shit.",
@ -35,9 +29,7 @@
"na'vi": "Oel fìuti stìyeftxaw.",
"cy": "Ail-lwytho'r cach na",
"nl": "Die zooi opnieuw geladen.",
"de": "Neu geladen",
"fr": "Bordel rechargé",
"it": "Ricaricato questa puttanata"
"de": "Neu geladen"
},
"load_module": {
"en": "Loaded new module: {moduleName}",
@ -45,9 +37,7 @@
"na'vi": "Oel {moduleName}it amip stìyeftxaw.",
"cy": "Wedi llwytho modiwl newydd: {moduleName}",
"nl": "Nieuwe module geladen: {moduleName}",
"de": "Neues Modul geladen: {moduleName}",
"fr": "Nouveau module chargé : {moduleName}",
"it": "Caricato nuovo modulo: {moduleName}"
"de": "Neues Modul geladen: {moduleName}"
},
"unload_module": {
"en": "Turned off module: {moduleName}",
@ -55,9 +45,7 @@
"na'vi": "Oel {moduleName} tswìya'.",
"cy": "Wedi troi ffwrdd y modiwl: {moduleName}",
"nl": "Module uitgeschakeld: {moduleName}",
"de": "Modul ausgeschaltet: {moduleName}",
"fr": "Module déchargé : {moduleName}",
"it": "Inabilitato modulo: {moduleName}"
"de": "Modul ausgeschaltet: {moduleName}"
},
"unload_error": {
"en": "{moduleName} isn't loaded. Idiot.",
@ -65,9 +53,7 @@
"na'vi": "Oel {moduleName}it omum. Nga skxawng lu.",
"cy": "Di {moduleName} ddim wedi llwytho. Twpsyn",
"nl": "{moduleName} is niet geladen. Idioot.",
"de": "{moduleName} ist nicht geladen, du Idiot.",
"fr": "{moduleName} n'est pas chargé. Idiot.",
"it": "{moduleName} non è caricato. Idiota"
"de": "{moduleName} ist nicht geladen, du Idiot."
},
"banned": {
"en": "{user} banned from {command}",
@ -75,9 +61,7 @@
"na'vi": "{command}ìri {user} ke tung.",
"cy": "{user} wedi ei gohurio o {command}",
"nl": "{user} mag {command} niet meer gebruiken",
"de": "{user} wurde von {command} gebannt",
"fr": "{user} a été interdit d'utiliser {command}",
"it": "{user} bandito da {command}"
"de": "{user} wurde von {command} gebannt"
},
"unbanned": {
"en": "{user} unbanned from {command}",
@ -85,9 +69,7 @@
"na'vi": "{command}ìri {user} tung set.",
"cy": "{user} wedi ei dad-wahardd o {command}",
"nl": "{user} mag {command} weer gebruiken",
"de": "{user} wurde von {command} entbannt",
"fr": "{user} peut de nouveau utiliser {command}",
"it": "{user} riammesso da {command}"
"de": "{user} wurde von {command} entbannt"
},
"unban_error": {
"en": "{user} wasn't banned from that command, fool.",
@ -95,9 +77,7 @@
"na'vi": "{user} fìtsu'oti tamung srekrr, nga skxawng lu.",
"cy": "Nid oedd {user} wedi ei wahardd o'r gorchymyn yna, twpsyn",
"nl": "{user} mag dat commando sowieso al gebruiken, mafketel.",
"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."
"de": "{user} wurde nicht von {command} gebannt, du Trottel"
},
"qlock": {
"en": "Locked quote category: {category}",
@ -105,126 +85,84 @@
"na'vi": "{category}ìri oel 'upxareti fmoli",
"cy": "Categori wedi cloi: {category}",
"nl": "Quote categorie vergrendeld: {category}",
"de": "Zitat-Kategorie geschlossen: {category}",
"fr": "Catégorie de citations verrouillée : {category}",
"it": "Categoria di citazione bloccata : {category}"
"de": "Zitat-Kategorie geschlossen: {category}"
},
"already_in_channel": {
"en": "I'm already in {channel}",
"na'vi": "Oel {channel}it tok li",
"cy": "Rydw i eisoes yn {channel}",
"nl": "Ik ben al in {channel}",
"de": "Ich bin schon in {channel}",
"fr": "Je suis déjà dans {channel}",
"it": "Sono già in {channel}"
"de": "Ich bin schon in {channel}"
},
"not_in_channel": {
"en": "I'm not in {channel}",
"na'vi": "Oel {channel}it ke tok",
"cy": "Rydw i ddim yn {channel}",
"nl": "Ik ben niet aanwezig in {channel}",
"de": "Ich bin noch nicht in {channel}",
"fr": "Je ne suis pas dans {channel}",
"it": "Non sono in {channel}"
"de": "Ich bin noch nicht in {channel}"
},
"already_loaded_web": {
"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)",
"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)",
"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)"
"de": "WARUM KANN DAS NICHT GELADEN WERDEN? (bereits geladen)"
},
"already_loaded": {
"en": "{moduleName} is already loaded.",
"na'vi": "Oel omum teri {moduleName}it li.",
"cy": "{moduleName} eisoes yn lwytho",
"nl": "{moduleName} is al geladen.",
"de": "{moduleName} ist bereits geladen.",
"fr": "{moduleName} est déjà chargé.",
"it": "{moduleName} già caricato."
"de": "{moduleName} ist bereits geladen."
},
"no_version": {
"en": "No version information or queried module not loaded.",
"cy": "Dim gwybodaeth fersiwn neu modiwl holodd dim yn lwytho",
"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"
"de": "Keine Informationen verfügbar oder gewünschtes Modul wurde noch nicht geladen."
},
"status_good": {
"en": "{module} status: Shit looks good",
"cy": "{module} statws: Cachu yn edrych yn dda",
"de": "Sieht gut aus",
"fr": "Statut de {module}: Cette merde tourne bien",
"it": "Stato di {modulo}: Funky gallo come sono bello stamattina"
"de": "Sieht gut aus"
},
"status_bad": {
"en": "{module} status: Failed to load: {reason}",
"cy": "{module} statws: Methu i lwytho: {reason}",
"de": "{module} Status: Konnte nicht geladen werden: {reason}",
"fr": "Statut de {module}: échec de chargement : {reason}",
"it": "Stato di {module}: Caricamento fallito: {reason}"
"de": "{module} Status: Konnte nicht geladen werden: {reason}"
},
"status_unloaded": {
"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",
"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"
"de": "Entweder ist das Modul nicht auf der Liste oder die Kacke ist am dampfen"
},
"load_failed": {
"en": "Failed to load {module}. See 'status {module}'.",
"cy": "Methu i lwytho {module}. Gwelwch '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}'."
"de": "Konnte {module} nicht laden. Siehe 'status {module}'."
},
"no_config_key": {
"en": "{path} doesn't exist bro",
"cy": "{path} cyfluniad yn bodoli, fy mrawd",
"de": "{path} existiert nicht, Bruder",
"fr": "{path} n'existe pas, fréro",
"it": "{path} non esiste, fratello"
"en": "Config key doesn't exist bro",
"cy": "Nid yw allwedd cyfluniad yn bodoli, fy mrawd",
"de": "Einstellung existiert nicht, Bruder"
},
"config_array": {
"en": "Config option is an array. Try '{alternate}'.",
"cy": "Opsiwn cyfluniad ydy'r amrywiaeth. Rhowch gynnig ar '{alternate}'.",
"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}'."
"de": "Einstellung ist ein Array, probiere '{alternate}' aus."
},
"config_lock": {
"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.",
"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."
"de": "Diese Option kann während der Benutzung des Bots nicht verändert werden"
},
"no_config_path": {
"en": "Config path doesn't exist bro",
"cy": "Nid yw llwybr cyfluniad yn bodoli, fy mrawd",
"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}."
"de": "Konfigurationspfad nicht vorhanden, Bruder"
},
"config_keys_location": {
"en": "Config keys in {path}: {value}",
"cy": "Allweddi cyfluniad yn {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}"
"de": "Die Konfiguration in {path}: {value}"
}
}

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) {
args[callbackIndex] = function() {
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);
};
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
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
#### ~usage [command]

View File

@ -2,52 +2,64 @@ var _ = require('underscore')._;
var api = function(dbot) {
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?
*/
'hasAccess': function(event, command, callback) {
var accessNeeded = dbot.commands[command].access,
allowedNicks,
user = event.rUser;
'hasAccess': function(server, user, command, callback) {
var accessNeeded = dbot.commands[command].access;
if(_.isUndefined(accessNeeded) || accessNeeded == null) {
return callback(true);
} else if(!_.isFunction(accessNeeded)) {
if(_.has(dbot.access, accessNeeded)) {
accessNeeded = dbot.access[accessNeeded];
if(accessNeeded == 'admin' || accessNeeded == 'moderator' || accessNeeded == 'power_user') {
var allowedNicks = dbot.config.admins;
if(accessNeeded == 'moderator') allowedNicks = _.union(allowedNicks, dbot.config.moderators);
if(accessNeeded == 'power_user') allowedNicks = _.union(allowedNicks, dbot.config.power_users);
if(!_.include(allowedNicks, user)) {
callback(false);
} 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 {
if(_.has(dbot.modules, 'nickserv') && this.config.useNickserv == 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);
}
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.
*/
'applyRegex': function(commandName, event) {
var applies = false;
event.message = event.message.substring(1);
if(_.has(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]);
if(q) {
applies = true;
@ -64,6 +76,16 @@ var api = function(dbot) {
applies = true;
}
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
* ignoring that command.
*/
var _ = require('underscore')._,
cDomain = require('domain').create();
var _ = require('underscore')._;
var command = function(dbot) {
this.dbot = dbot;
/**
* Run the appropriate command given the input.
*/
this.listener = function(event) {
var commandName = event.params[0];
if(commandName.charAt(0) != this.config.commandPrefix || this.config.passiveMode == true) {
return;
}
commandName = commandName.substring(1);
this.api.hasAccess(event, commandName, function(hasAccess) {
dbot.api.ignore.isUserIgnoring(event.rUser, commandName, function(isIgnoring) {
dbot.api.ignore.isUserBanned(event.rUser, commandName, function(isBanned) {
if(!_.has(dbot.commands, commandName)) {
if(_.has(dbot.modules, 'quotes')) {
commandName = '~';
} else {
return;
}
}
if(isBanned) {
if(this.config.banOutput && commandName != this.config.commandPrefix) {
event.reply(dbot.t('command_ban', {'user': event.user}));
}
} else if(!hasAccess) {
if(this.config.accessOutput) {
event.reply(dbot.t('access_denied', { 'user': event.user }));
}
} else if(!isIgnoring && _.has(dbot.commands, commandName) && !dbot.commands[commandName].disabled) {
if(!_.has(dbot.commands, commandName)) {
if(_.has(dbot.modules, 'quotes')) {
var key = event.message.substring(1);
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;
}
if(this.api.isBanned(event.user, commandName)) {
event.reply(dbot.t('command_ban', {'user': event.user}));
} else {
this.api.hasAccess(event.server, event.user, commandName, function(result) {
if(result) {
if(!this.api.isIgnoring(event.user, commandName) &&
!this.api.isIgnoring(event.channel, commandName) &&
dbot.commands[commandName].disabled !== true) {
if(this.api.applyRegex(commandName, event)) {
try {
var command = dbot.commands[commandName];
var results = command.apply(dbot.modules[command.module], [event]);
if(_.has(command, 'hooks') && results !== false) {
_.each(command['hooks'], function(hook) {
hook.apply(hook.module, _.values(results));
}, this);
}
});
return;
} else {
return;
}
}
} catch(err) {
if(dbot.config.debugMode == true) {
var stack = err.stack.split('\n').slice(1, dbot.config.debugLevel + 1);
if(this.api.applyRegex(commandName, event)) {
try {
cDomain.run(function() {
var command = dbot.commands[commandName],
results;
if(_.has(command, 'resolver')) {
event.res = [];
command.resolver(event, function(err) {
if(!err) {
results = command.apply(dbot.modules[command.module], [event]);
}
event.reply('- Error in ' + commandName + ':');
event.reply('- Message: ' + err);
_.each(stack, function(stackLine, index) {
event.reply('- Stack[' + index + ']: ' +
stackLine.trim());
});
} 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());
});
}
}
if(!_.include(['reload', 'load', 'unload', 'setconfig'], commandName)) dbot.api.event.emit('command', [ event ]);
} else {
if(commandName !== this.config.commandPrefix) {
if(_.has(dbot.usage, commandName)) {
event.reply('Usage: ' + dbot.usage[commandName]);
} else {
event.reply(dbot.t('syntax_error'));
dbot.api.event.emit('command', [ event ]);
dbot.save();
} else {
if(commandName !== '~') {
if(_.has(dbot.usage, commandName)) {
event.reply('Usage: ' + dbot.usage[commandName]);
} else {
event.reply(dbot.t('syntax_error'));
}
}
}
}
}
}.bind(this));
}.bind(this));
}.bind(this));
}
}.bind(this);
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) {

View File

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

View File

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

View File

@ -1,78 +1,55 @@
{
"command_ban": {
"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.",
"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.",
"de": "{user} darf diesen Befehl nicht benutzen. 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."
"de": "{user} wurde von diesem Befehl gebannt. Verbrennung einleiten"
},
"syntax_error": {
"syntax_error": {
"en": "Invalid syntax. Initiate incineration.",
"es": "Sintaxis no válida. Iniciar incineración.",
"na'vi": "Ngeyä pamrel keyawr lu. Nga skxawng lu.",
"cy": "Cystrawen annilys. Cychwyn orfflosgiad",
"nl": "Ongeldige syntax. Bereid het verbrandingsritueel voor.",
"de": "Syntax ungültig. Verbrennung einleiten",
"fr": "Syntaxe invalide. Initier l'incinération.",
"it": "Sintassi non valida. Iniziare incenerimento"
"de": "Syntax ungültig. Verbrennung einleiten"
},
"usage": {
"en": "Usage for {command}: {usage}.",
"na'vi": "Nga tsun sivar ìlä {command}: {usage}.",
"cy": "Defnydd o {command}: {usage}.",
"nl": "{command} wordt op de volgende manier gebruikt: {usage}.",
"de": "Benutzung von {command}: [usage}.",
"fr": "Utilisation de {command}: {usage}.",
"it": "Utilizzo di {command}: {usage}."
"de": "Benutzung von {command}: [usage}."
},
"no_usage_info": {
"en": "No usage information found for {command}.",
"na'vi": "Oel ke tsun sivar {comamnd}it",
"cy": "Ni chanfuwyd gwybodaeth am ddefnydd o {command}",
"nl": "Geen gebruiksinformatie gevonden voor {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}"
"de": "Keine Gebrauchsanweisung gefunden für {command}."
},
"help_link": {
"en": "Help for {module}: {link}",
"na'vi": "{module}ä srungìl {link} it tok",
"cy": "Cymorth am {module}: {link}",
"nl": "Hulp voor {module}: {link}",
"de": "Hilfe für {module}: {link}",
"fr": "Aide pour {module}: {link}",
"it": "Aiuto per {module}: {link}"
"de": "Hilfe für {module}: {link}"
},
"no_help": {
"en": "No help found for {module}.",
"na'vi": "Fì{module}ìri oel ke tsun run srungit",
"cy": "Ni chanfuwyd cymorth am {module}",
"nl": "Geen hulp gevonden voor {module}.",
"de": "Keine Hilfe gefunden für {module}.",
"fr": "Aucune aide trouvée pour {module}.",
"it": "Nessun aiuto trovato per {module}."
"de": "Keine Hilfe gefunden für {module}."
},
"loaded_modules": {
"en": "Loaded modules: {modules}.",
"cy": "Modiwlau sy'n lwythodd: {modules}.",
"nl": "Geladen modules: {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."
"de": "Module geladen: {modules}."
},
"module_commands": {
"en": "Commands in {module}: {commands}.",
"fr": "Commandes de {module}: {commands}.",
"it": "Commandi di {module}: {commands}.",
"de": "Befehle in {module}: {commands}."
"en": "Commands 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) {
this.listener = function(event) {
var matches = event.message.match(/\u0001[\w]+\u0001/);
if(matches) {
// We need the CTCP command
var question = matches[0];
// Cut \u0001 characters from command
question = question.slice(1,question.length-1);
switch(question) {
case 'CLIENTINFO':
event.replyNotice("\u0001CLIENTINFO SOURCE VERSION USERINFO\u0001");
break;
case 'FINGER':
event.replyNotice("\u0001FINGER STOP FINGERING ME BRO\u0001");
break;
case 'SOURCE':
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");
}
var commands = {
"\x01VERSION\x01": function(event) {
// the current client version
event.replyNotice("\x01VERSION " + dbot.config.version + "\x01");
},
"\x01CLIENTINFO\x01": function(event){
// a list of all supported CTCP commands
event.replyNotice("\x01CLIENTINFO SOURCE VERSION USERINFO\x01");
},
"\x01SOURCE\x01": function(event){
event.replyNotice("\x01SOURCE https://github.com/reality/depressionbot\x01");
},
"\x01USERINFO\x01": function(event){
// a "witty" saying set by the user
event.replyNotice("\z01USERINFO " + dbot.config.name + "\x01");
}
};
}
this.commands = commands;
this.on = 'PRIVMSG';
};

View File

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

View File

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

View File

@ -17,14 +17,14 @@ var parseDiceSpec = function (specString) {
var normalizeDiceSpec = function (specString) {
var diceSpec = parseDiceSpec(specString);
if (diceSpec["sides"] > 10000) {
return false;
}
if (diceSpec["count"] > 1000) {
return false;
}
if (diceSpec["sides"] > 10000) {
return false;
}
if (diceSpec["count"] > 1000) {
return false;
}
if (diceSpec["count"] > 1) {
var count = diceSpec["count"];
} else {
@ -74,7 +74,7 @@ var dice = function(dbot) {
event.reply(rolls[i][0] + ": invalid dice spec");
} else {
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) {
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
* Description: Performs and reports on basic DNS functions.
*/
var dnsm = require('dns'),
request = require('request'),
http = require('http');
var dnsmod = require('dns');
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 = {
'~lookup': function(event) {
domain = event.params[1];
dnsm.lookup(domain, function (error, addr) {
dnsmod.lookup(domain, function (error, addr) {
if (error) {
event.reply(dbot.t("lookup-error",{"domain": domain, "code": error.code}));
} else {
@ -43,52 +16,20 @@ var dns = function(dbot) {
}
});
},
'~rdns': function(event) {
ip = event.params[1];
dnsm.reverse(ip, function (error, domain) {
dnsmod.reverse(ip, function (error, domain) {
if (error) {
event.reply(dbot.t("rdns-error",{"domain": domain, "ip": ip, "error": error.code}));
} else {
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;
if(dbot.config.modules.dns.dnsblconn == true) {
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';
}
this.on = 'PRIVMSG';
};
exports.fetch = function(dbot) {

View File

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

View File

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

View File

@ -5,9 +5,7 @@
"na'vi": "{user}: Sar: ~ignore ['u]. U, nga ke tìng mikyun: {modules}.",
"cy": "{user}: Defnydd: ~ignore [modiwl]. Modiwlau a allech anwybyddu yw: {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}.",
"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}."
"de": "{user}: Benutzung: ~ignore [module]. Module, die ignoriert werden können: {modules}."
},
"already_ignoring": {
"en": "{user}: You're already ignoring that module.",
@ -15,9 +13,7 @@
"na'vi": "{user}: 'uri nga ke tìng mikyun srekrr.",
"cy": "{user}: Mi rwyt ti'n anwybyddu'r modiwl yna'n barod.",
"nl": "{user}: Je negeert deze module al.",
"de": "{user}: Dieses Modul ist bereits ausgeschaltet.",
"fr": "{user}: Vous ignorez déjà ce module.",
"it": "{user}: Stai già ignorando questo modulo"
"de": "{user}: Dieses Modul wird bereits ignoriert."
},
"ignored": {
"en": "{user}: Now ignoring {module}.",
@ -25,9 +21,7 @@
"na'vi": "{user}: Nga ke terìng mikyun {module}ne set.",
"cy": "{user}: Nawr yn anwybyddu {module}",
"nl": "{user}: {module} wordt nu genegeerd.",
"de": "{user}: {module} wird nun ausgeschaltet.",
"fr": "{user}: {module} désormais ignoré.",
"it": "{user}: {module} sarà adesso ignorato"
"de": "{user}: {module} wird nun ignoriert."
},
"invalid_ignore": {
"en": "{user}: That isn't a valid module name.",
@ -35,9 +29,7 @@
"na'vi": "{user}: Tsatstxo eyawr ke lu.",
"cy": "{user}: Nid oedd hwna'n modiwl dilys",
"nl": "{user}: Dat is geen geldige modulenaam.",
"de": "{user}: Dies ist kein Name eines Moduls.",
"fr": "{user}: Ceci ne correspond pas à un nom de module valide.",
"it": "{user}: Questo non è un nome di modulo valido"
"de": "{user}: Dies ist nicht der Name eines Moduls."
},
"unignore_usage": {
"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}.",
"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}.",
"de": "{user}: Benutzung: ~unignore [module]. Module, die im Moment ausgeschaltet sind: {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]."
"de": "{user}: Benutzung: ~unignore [module]. Module, die im Moment ignoriert werden: {modules}."
},
"invalid_unignore": {
"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.",
"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.",
"de": "{user}: Dieses Modul ist entweder ausgeschaltet 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."
"de": "{user}: Dieses Modul wird entweder nicht ignoriert oder existiert nicht."
},
"unignored": {
"en": "{user}: No longer ignoring {module}.",
@ -75,109 +53,83 @@
"na'vi": "{user}: Nga terìng mikyun {module}ne set",
"cy": "{user}: Ddim yn anwybyddu {module} bellach",
"nl": "{user}: {module} wordt niet langer genegeerd.",
"de": "{user}: {module} ist nicht länger ausgeschaltet.",
"fr": "{user}: {module} n'est plus ignoré à présent.",
"it": "{user}: {module} non viene attualmente più ignorato"
"de": "{user}: {module} wird nicht länger ignoriert."
},
"ban_usage": {
"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.",
"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.",
"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."
"de": "{user}: Benutzung ~ban [Benutzer] [module/Befehl]. Benutze * für alle Module und Befehle."
},
"already_banned": {
"en": "{user}: {banned} is already banned from that module.",
"cy": "{user}: {banned} eisoes wedi ei wahardd o'r modiwl.",
"nl": "{user}: {banned} is al geband van deze module.",
"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."
"de": "{user}: {banned} ist bereits von diesem Modul gebannt."
},
"banned_success": {
"en": "{user}: {banned} is now banned from {module}.",
"cy": "{user}: {banned} ei wahardd yn awr am {module}.",
"nl": "{user}: {banned} mag {module} nu niet meer gebruiken.",
"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}."
"de": "{user}: {banned} ist nun von {module} gebannt."
},
"invalid_ban": {
"en": "{user}: That isn't a valid module name.",
"cy": "{user}: Nid oedd hwna'n modiwl dilys",
"nl": "{user}: Dat is geen geldige modulenaam.",
"de": "{user}: Dies ist kein Name eines Moduls.",
"fr": "{user}: Ceci n'est pas un nom de module valide.",
"it": "{user}: Queso non è il nome di un modulo valido."
"de": "{user}: Dies ist nicht der Name eines Moduls."
},
"unban_usage": {
"en": "{user}: Usage: ~unban [user] [module].",
"cy": "{user}: Defnydd: ~unban [defnyddiwr] [modiwl].",
"nl": "{user}: Gebruik: ~unban [gebruiker] [module].",
"de": "{user}: Benutzung: ~unban [Benutzer] [module].",
"fr": "{user}: Utilisation: ~unban [user] [module].",
"it": "{user}: Uso: ~unban [user] [module]."
"de": "{user}: Benutzung: ~unban [Benutzer] [module]."
},
"invalid_unban": {
"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.",
"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.",
"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."
"de": "{user}: {banned} ist von diesem Modul nicht gebannt, oder es existiert nicht."
},
"unbanned_success": {
"en": "{user}: {banned} is no longer banned from {module}.",
"cy": "{user}: Nid yw {banned} yn cael ei wahardd mwyach.",
"nl": "{user}: {banned} mag {module} weer gebruiken.",
"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}."
"de": "{user}: {banned} wurde von {module} entbannt."
},
"ignoring_channel": {
"en": "Now ignoring {module} in {channel}.",
"na'vi": "Oe ke stayawm {module}ur mì {channel}",
"cy": "Bellach yn anwybyddu {module} yn {channel}.",
"nl": "{module} wordt nu genegeerd in {channel}.",
"de": "{module} in {channel} ist nun ausgeschaltet.",
"fr": "{module} dans {channel} maintenant ignoré.",
"it": "{module} in {channel} viene adesso ignorato."
"de": "{module} in [channel} wird nun ignoriert."
},
"already_ignoring_channel": {
"en": "Already ignoring {module} in {channel}.",
"na'vi": "Oe ke stayawm {module}ur mì {channel} li",
"cy": "Eisoes anwybyddu {module} yn {channel}",
"nl": "{module} wordt al genegeerd in {channel}.",
"de": "{module} in {channel} ist bereits ausgeschaltet.",
"fr": "{module} dans {channel} déjà ignoré.",
"it": "{module} in {channel} già ignorato."
"de": "{module} in {channel} wird bereits ignoriert."
},
"module_not_exist": {
"en": "{module} isn't loaded or doesn't exist.",
"na'vi": "Oel ke omum teri {module}it fu {module} ke fkeytok",
"cy": "Dydy {module} ddim yn lwythodd, neu ddim yn bodoli.",
"nl": "{module} is niet geladen of bestaat niet.",
"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"
"de": "{module} ist nicht geladen oder existiert nicht."
},
"unignoring_channel": {
"en": "No longer ignoring {module} in {channel}.",
"na'vi": "Oel stayawm {module}ur mì {channel} set.",
"cy": "Nid anwybyddu {module} yn {channel} mwyach.",
"nl": "{module} wordt niet meer genegeerd in {channel}.",
"de": "{module} in {channel} ist nicht länger ausgeschaltet.",
"fr": "{module} dans {channel} n'est plus ignoré à présent.",
"it": "{module} in {channel} non viene più ignorato."
"de": "{module} in {channel} wird nicht länger ignoriert."
},
"not_ignoring_channel": {
"en": "{module} wasn't being ignored in {channel}.",
"na'vi": "Oel stayawm {module}ur mì {channel} li.",
"cy": "Nid yw {module} yn cael ei anwybyddu yn {channel}.",
"nl": "{module} werd niet genegeerd in {channel}.",
"de": "{module} war in {channel} nicht ausgeschaltet.",
"fr": "{module} n'était pas ignoré dans {channel}.",
"it": "{module} non veniva ignorato in {channel}"
"de": "{module} wurde in {channel} nicht ignoriert."
}
}

View File

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

View File

@ -5,29 +5,14 @@
var _ = require('underscore')._,
request = require('request'),
async = require('async'),
crypto = require('crypto'),
humanise = require('humanize');
crypto = require('crypto');
var imgur = function(dbot) {
this.ApiRoot = 'https://api.imgur.com/3/';
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.db = dbot.db.imgur;
this.internalAPI = {
'infoString': function(imgData) {
info = '';
if(!_.isUndefined(imgData) && _.has(imgData, 'data') && !_.isUndefined(imgData.data.type)) {
if(imgData && _.has(imgData, 'data') && !_.isUndefined(imgData.data.type)) {
imgData = imgData.data;
if(imgData.title) {
info += imgData.title + ' - ';
@ -43,8 +28,6 @@ var imgur = function(dbot) {
}
info += imgData.views + ' views (';
info += imgData.width + 'x' + imgData.height + ')';
info += ' ('+humanise.filesize(imgData.size)+')';
}
return info;
@ -52,13 +35,13 @@ var imgur = function(dbot) {
'albumInfoString': function(albumData) {
var info = '';
if(!_.isUndefined(albumData) && _.has(albumData, 'data') && !_.isUndefined(albumData.data.id)) {
if(albumData && _.has(albumData, 'data') && !_.isUndefined(albumData.data.id)) {
albumData = albumData.data;
if(albumData.title) {
info += albumData.title + ' - ';
}
if(albumData.description) {
info += albumData.description.split('\n')[0] + ' is ';
info += albumData.description + ' is ';
}
info += 'an album with ' + albumData.images_count + ' images ';
info += 'and ' + albumData.views + ' views';
@ -71,7 +54,7 @@ var imgur = function(dbot) {
'galleryInfoString': function(galData) {
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) {
info = this.internalAPI.albumInfoString(galData);
} else {
@ -93,52 +76,30 @@ var imgur = function(dbot) {
var testSlug = random(5);
var testUrl = 'http://i.imgur.com/' +
testSlug +
'.' + ext[_.random(0, ext.length - 1)],
fbman = false;
dbot.db.imgur.totalHttpRequests += 1;
request(testUrl, function(error, response, body) {
'.' + ext[_.random(0, ext.length - 1)];
this.db.totalHttpRequests += 1;
var image = request(testUrl, function(error, response, body) {
// 492 is body.length of a removed image
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");
if(_.has(dbot.modules, 'quotes')){
// autoadd: {"abcdef": "facebookman"}
if(_.has(dbot.config.modules.imgur.autoadd,hash)){
fbman = true;
var category = this.config.autoadd[hash];
if(_.has(dbot.config.imgur.autoadd,hash)){
var category = dbot.config.imgur.autoadd[hash];
if (_.contains(category, testUrl)){
// there's probably less than 62^5 chance of this happening
} else {
dbot.api.quotes.addQuote(category, testUrl,
dbot.config.name, function() { });
if(!_.has(dbot.db.quoteArrs, category)) dbot.db.quoteArrs[category] = [];
dbot.db.quoteArrs[category].push(testUrl);
}
}
}
callback(testUrl, testSlug, hash, fbman);
callback(testUrl, testSlug,hash);
} else {
this.api.getRandomImage(callback);
}
}.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));
}.bind(this));
},
'getImageInfoString': function(slug, callback) {
@ -152,10 +113,10 @@ var imgur = function(dbot) {
'url': 'https://api.imgur.com/3/image/' + slug + '.json',
'json': true,
'headers': {
'Authorization': 'Client-ID ' + this.config.apikey
'Authorization': 'Client-ID ' + dbot.config.imgur.apikey
}
}, function(err, response, body) {
dbot.db.imgur.totalApiRequests += 1;
this.db.totalApiRequests += 1;
callback(body);
}.bind(this));
},
@ -165,7 +126,7 @@ var imgur = function(dbot) {
'url': 'https://api.imgur.com/3/album/' + slug + '.json',
'json': true,
'headers': {
'Authorization': 'Client-ID ' + this.config.apikey
'Authorization': 'Client-ID ' + dbot.config.imgur.apikey
}
}, function(err, response, body) {
this.db.totalApiRequests += 1;
@ -178,7 +139,7 @@ var imgur = function(dbot) {
'url': 'https://api.imgur.com/3/gallery/' + slug + '.json',
'json': true,
'headers': {
'Authorization': 'Client-ID ' + this.config.apikey
'Authorization': 'Client-ID ' + dbot.config.imgur.apikey
}
}, function(err, response, body) {
this.db.totalApiRequests += 1;
@ -193,95 +154,17 @@ var imgur = function(dbot) {
this.commands = {
'~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.getImageInfo(slug, function(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));
},
// 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() {
var imgurHandler = function(matches, name, callback) {
var imgurHandler = function(event, matches, name) {
if(matches[1]) {
var dataCallback = function(data) {
var info;
@ -293,7 +176,7 @@ var imgur = function(dbot) {
info = this.internalAPI.galleryInfoString(data);
}
if(info) callback(dbot.t('imgurinfo', { 'info': info }));
if(info) event.reply(dbot.t('imgurinfo', { 'info': info }));
}.bind(this);
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?:\/\/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, 'totalApiRequests')) dbot.db.imgur.totalApiRequests = 0;
if(!_.has(dbot.db.imgur, 'totalImages')) dbot.db.imgur.totalImages = 0;
this.db = dbot.db.imgur;
}.bind(this);
};

View File

@ -3,7 +3,13 @@ var _ = require('underscore')._;
var pages = function(dbot) {
return {
'/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 });
},

View File

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

View File

@ -5,5 +5,6 @@
}
},
"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
* access to the DepressionBot instance memory.
*/
var VM = require('vm2').VM;
var vm = require('vm');
var sbox = require('sandbox');
var js = function(dbot) {
var commands = {
// Run JS code sandboxed, return result to channel.
'~js': function(event) {
try {
var s = new VM({timeout: 1000, sandbox: {}});
event.reply(s.run(event.input[1]));
} catch(err) { event.reply(err); }
var s = new sbox();
s.run(event.input[1], function(output) {
event.reply(output.result);
}.bind(this));
} catch(err) {}
},
// Run JS code un-sandboxed, with access to DBot memory (admin-only).
'~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]);
if(ret !== undefined) {
event.reply(ret);
}
}
};
commands['~js'].regex = [/^js (.*)/, 2];
commands['~ajs'].regex = [/^ajs (.*)/, 2];
commands['~js'].regex = [/^~js (.*)/, 2];
commands['~ajs'].regex = [/^~ajs (.*)/, 2];
commands['~ajs'].access = 'admin';
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')._,
uuid = require('node-uuid');
var _ = require('underscore')._;
var commands = function (dbot) {
var commands = {
/*** Kick Management ***/
'~quiet': function (event) {
var server = event.server,
quieter = event.rUser,
duration = event.input[1],
channel = (event.input[2] || event.channel.name).trim(),
quietee = event.input[3].trim(),
reason = event.input[4] || "N/A";
var commands = function(dbot) {
var commands = {
/*** Kick Management ***/
'~quiet': function(event) {
var server = event.server,
quieter = event.user,
minutes = event.input[1],
channel = event.input[2],
quietee = event.input[3].trim();
this.api.quietUser(server, quieter, duration, channel, quietee, reason, function (response) {
event.reply(response);
});
},
'~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];
if(_.isUndefined(channel)) {
channel = event.channel.name;
}
}
.bind(this), 3600000);
channel = channel.trim();
if (this.recentTimeouts[user.id] == 3) {
duration = null;
reason += ' #permatimeout';
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.');
}
this.api.quietUser(server, quieter, duration, channel, quietee, reason, function (response) {
event.reply(response);
});
}
}
.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);
if(!_.isUndefined(minutes)) {
minutes = parseFloat(minutes.trim());
var msTimeout = new Date(new Date().getTime() + (minutes * 60000));
dbot.api.timers.addTimeout(msTimeout, function() {
this.api.unquiet(server, quietee, channel);
}.bind(this));
event.reply(dbot.t('tquieted', {
'quietee': quietee,
'minutes': minutes
}));
} else {
adminChannel = event.channel.name;
event.reply(dbot.t('quieted', { 'quietee': quietee }));
}
// 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, host, channel);
this.api.kick(server, banee, channel, reason +
' (network-wide ban)');
i++;
banChannel(channels);
this.api.quiet(server, quietee, channel);
},
'~unquiet': function(event) {
var server = event.server,
quieter = event.user,
channel = event.input[1],
quietee = event.input[2].trim();
if(_.isUndefined(channel)) {
channel = event.channel.name;
}
.bind(this);
banChannel(channels);
}
channel = channel.trim();
this.hosts[event.server][banee] = host;
this.api.unquiet(server, quietee, channel);
event.reply(dbot.t('unquieted', { 'quietee': quietee }));
},
// Create notify string
if (!_.isUndefined(timeout)) {
timeout = timeout.trim();
'~ckick': function(event) {
var server = event.server,
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));
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';
}
this.api.kick(server, kickee, channel, reason + ' (requested by ' + kicker + ')');
// Do not schedule unbans if the user was killed as no ban was put in place
if(!didKill) {
if (!_.has(this.tempBans, event.server))
this.tempBans[event.server] = {};
this.tempBans[event.server][banee] = msTimeout;
this.internalAPI.addTempBan(event.server, banee, msTimeout);
}
dbot.api.report.notify(server, channel, dbot.t('ckicked', {
'kicker': kicker,
'kickee': kickee,
'channel': channel,
'reason': reason
}));
},
var notifyString = dbot.t('tbanned', {
'network': network,
'~cban': function(event) {
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,
'banee': banee,
'hours': timeout,
'host': host,
'channel': channel,
'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) {
var unbanee = event.params[1],
host = event.params[2] || undefined,
unbanner = event.rUser;
// Kick and ban from all channels on the network.
'~nban': function(event) {
if(!event.input) return;
this.api.networkUnban(event.server, unbanee, unbanner, host, function (err) {
if (err) {
event.reply(dbot.t('nunban_error', {
'unbanee': unbanee
}));
}
});
},
var server = event.server,
banner = event.user,
timeout = event.input[1],
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 ***/
// 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.');
if(this.config.network_name[event.server]) {
network = this.config.network_name[event.server];
}
console.log(timeout);
console.log(banee);
console.log(reason);
if (!_.has(this.voteQuiets, user.id)) {
this.voteQuiets[user.id] = {
'user': user.id,
'reason': reason,
'channel': event.channel,
'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.');
dbot.api.nickserv.getUserHost(event.server, banee, function(host) {
// Add host record entry
if(host) {
if(!_.has(this.hosts, event.server)) this.hosts[event.server] = {};
this.hosts[event.server][banee] = host;
this.voteQuiets[user.id].timer = setTimeout(function () {
var vq = this.voteQuiets[user.id];
vq.spent = true;
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 + ').');
// Create notify string
if(!_.isUndefined(timeout)) {
timeout = parseFloat(timeout.trim());
var msTimeout = new Date(new Date().getTime() + (timeout * 3600000));
if(!_.has(this.tempBans, event.server)) this.tempBans[event.server] = {};
this.tempBans[event.server][banee] = msTimeout;
this.internalAPI.addTempBan(event.server, banee, msTimeout);
this.api.quietUser(event.server, event.rUser, '10m', event.channel, target, reason + '[votequiet]', function (response) {
clearTimeout(vq.timer);
event.reply(response);
});
} 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 + '. ' +
vq.yes.join(', ') + ' voted yes (' + vq.yes.length + '). ';
if (vq.no.length > 0) {
nString += vq.no.join(', ') + ' voted no (' + vq.no.length + ').'
}
dbot.api.report.notify('votequiet', event.server, event.rUser, event.channel, nString, false, target);
setTimeout(function () {
delete this.voteQuiets[user.id];
}
.bind(this), 600000);
}
.bind(this), 90000);
} else {
if (this.voteQuiets[user.id].spent) {
event.reply('A votequiet attempt has already been made on this user in the last 10 minutes.');
} else {
var vq = this.voteQuiets[user.id]
if (!_.include(vq.yes, event.rUser.primaryNick)) {
vq.yes.push(event.rUser.primaryNick);
event.reply('There is already a votequiet attempt active for this user, adding yes vote to existing poll.');
event.reply('Voted yes on votequiet for ' + target + '. New count: Yes (' + vq.yes.length + '). No (' + vq.no.length + ').');
if (vq.yes.length == 4) {
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);
});
var notifyString = dbot.t('tbanned', {
'network': network,
'banner': banner,
'banee': banee,
'hours': timeout,
'reason': reason
});
var quoteString = dbot.t('tban_quote', {
'banee': banee,
'banner': banner,
'hours': timeout,
'time': new Date().toUTCString(),
'reason': reason
});
} else {
var notifyString = dbot.t('nbanned', {
'network': network,
'banner': banner,
'banee': banee,
'reason': reason
});
var quoteString = dbot.t('nban_quote', {
'banee': banee,
'banner': banner,
'time': new Date().toUTCString(),
'reason': reason
});
}
} 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) {
var target = event.params[1];
// Add qutoe category documenting ban
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) {
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.yes.push(event.rUser.primaryNick);
event.reply('Voted yes on votequiet for ' + target + '. New count: Yes (' + vq.yes.length + '). No (' + vq.no.length + ').');
// Notify moderators, banee
if(this.config.admin_channel[event.server]) {
channels = _.without(channels, adminChannel);
if (vq.yes.length == 4) {
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, vq.reason + '[votequiet]', function (response) {
clearTimeout(vq.timer);
vq.spent = true;
setTimeout(function () {
delete this.voteQuiets[user.id];
}
.bind(this), 600000);
event.reply(response);
});
}
dbot.api.report.notify(server, adminChannel, notifyString);
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
}));
}
}
// 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 {
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) {
var target = event.params[1];
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 + ').');
if(!_.has(dbot.db.kickers, username)) {
var kicked = '0';
} 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].');
}
} else {
event.reply('No idea who that is m8');
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'));
}
}
.bind(this));
}
};
};
_.each(commands, function (command) {
command.access = 'moderator';
});
_.each(commands, function(command) {
command.access = 'moderator';
});
commands['~kickcount'].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['~kickcount'].access = 'regular';
commands['~kickstats'].access = 'regular';
commands['~ckick'].regex = /^ckick (#[^ ]+ )?([^ ]+) ?(.*)?$/;
commands['~nban'].regex = /^nban (\d[\d\.dhmsy]+)? ?([^ ]+) (.+)$/;
commands['~quiet'].regex = /^quiet (\d[\d\.hmsy]+)? ?(#[^ ]+ )?([^ ]+) ?(.*)?$/;
commands['~timeout'].regex = /^timeout ([^ ]+) ?(.*)?$/;
commands['~unquiet'].regex = /^unquiet (#[^ ]+ )?([^ ]+) ?$/;
commands['~votequiet'].regex = [/^votequiet ([^ ]+) (.+)$/, 3];
commands['~ckick'].regex = [/^~ckick ([^ ]+) ([^ ]+) (.+)$/, 4];
commands['~nban'].regex = /^~nban ([\d\.^ ]+)?([^ ]+) (.+)$/;
commands['~quiet'].regex = /^~quiet ([\d\.^ ]+)?(#[^ ]+ )?([^ ]+) ?$/;
commands['~unquiet'].regex = /^~unquiet (#[^ ]+ )?([^ ]+) ?$/;
return commands;
return commands;
};
exports.fetch = function (dbot) {
return commands(dbot);
exports.fetch = function(dbot) {
return commands(dbot);
};

View File

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

View File

@ -1,270 +1,132 @@
var _ = require('underscore')._;
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 = {};
var kick = function(dbot) {
this.hosts = dbot.db.hosts;
this.tempBans = dbot.db.tempBans;
this.voteQuiets = {};
this.api = {
'ban': function(server, user, channel) {
dbot.say(server, this.config.chanserv, 'ban ' + channel + ' ' + user);
},
_.each(this.tempBans, function (bans, server) {
_.each(bans, function (timeout, nick) {
timeout = new Date(timeout);
this.internalAPI.addTempBan(server, nick, timeout);
}, this);
}, this);
'quiet': function(server, user, channel) {
dbot.say(server, this.config.chanserv, 'quiet ' + channel + ' ' + user);
},
if (_.has(dbot.modules, 'web')) {
dbot.api.web.addIndexLink('/bans', 'Ban List');
}
}
.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) {
return new kick(dbot);
exports.fetch = function(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.",
"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.",
"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"
"de": "{user} wurde {kicks} mal gekickt und hat {kicked} mal andere Benutzer gekickt."
},
"quieted": {
"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."
"en": "Quieted {quietee}. Remember: don't be a coconut."
},
"tquieted": {
"en": "Quieted {quietee} for {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}\"."
"en": "Quieted {quietee} for {minutes} minutes. Remember: don't be a coconut."
},
"unquieted": {
"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."
"en": "Unquieted {quietee}. Remember: don't be a coconut."
},
"kicked_dbot": {
"en": "Thou shalt not kick {botname}",
@ -45,71 +22,52 @@
"na'vi": "Ngal {botname}it ke tsun tsrive'i",
"cy": "Ni ddylech cicio {botname}",
"nl": "Gij zult {botname} niet kicken",
"de": "Du sollst {botname} nicht kicken",
"fr": "Tu ne kickeras pas {botname}",
"it": "Non dare pedata a {botname}"
"de": "Du sollst {botname} nicht kicken"
},
"ckicked": {
"en": "{kicker} has kicked {kickee}. The reason given was: \"{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}\".",
"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}\"."
"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}.\"",
"de": "Achtung: {kicker} hat {kickee} von {channel} verwiesen. Grund: \"{reason}.\""
},
"cbanned": {
"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}\".",
"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}\"."
"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}.\"",
"de": "Achtung: {banner} hat {banee} von {channel} gebannt. Grund: \"{reason}.\""
},
"tbanned": {
"en": "Attention: {banner} has banned {banee} (host: {host}) from the {network} network for {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}\"."
"en": "Attention: {banner} has banned {banee} from the {network} network for {hours} hours. The reason given was \"{reason}.\""
},
"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.",
"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."
"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."
},
"nbanned": {
"en": "Attention: {banner} has banned {banee} (host: {host}) from the {network} network. The reason given was \"{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}\".",
"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}\"."
"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}.\"",
"de": "Achtung: {banner} hat {banee} auf dem gesamten Netzwerk gebannt. Grund: \"{reason}.\""
},
"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.",
"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."
"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."
},
"no_user": {
"en": "{user} doesn't seem to be online on this server.",
"de": "{user} scheint auf diesen Server nicht online zu sein.",
"fr": "{user} ne semble pas être connecté à ce serveur.",
"it": "{user} sembra non essere connesso a questo server"
"nban_quote": {
"en": "{banee} was banned from the network by {banner} on {time}. The reason given was \"{reason}.\"",
"cy": "Cafodd {banee} ei wahardd o'r rhwydwaith gan {banner} ar {time}. Y rheswm a roddwyd oedd: \"{reason}.\"",
"de": "{banee} wurde von {banner} auf dem gesamten Netzwerk um {time} gebannt. Grund: \"{reason}.\""
},
"no_user": {
"en": "{user} doesn't seem to be online on this server."
},
"nunbanned": {
"en": "Attention: {unbanee} (host: {host}) 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}."
"en": "Attention: {unbanee} has been unbanned from the {network} network by {unbanner}."
},
"nunban_notify": {
"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}."
"en": "You have been unbanned from the {network} network by {unbanner}."
},
"nunban_error": {
"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.",
"it": "Sembar che {unbanee} non è stato bandito usano il commando ~nban."
"en": "It appears {unbanee} was not banned using the ~nban command."
},
"quote_recorded": {
"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]",
"~cban": "~cban [#channel] [username] [reason]",
"~nban": "~nban ([time in hours]) [username] [reason]",
"~nban": "~nban [username] [reason]",
"~kickstats": "~kickstats",
"~kickcount": "~kickcount [user]",
"~quiet": "~quiet (time) (#channel) username (reason)",
"~unquiet": "~unquiet (#channel) username"
"~kickcount": "~kickcount [user]"
}

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,
"outputPrefix": "\u00032link\u000f",
"help": "http://github.com/reality/depressionbot/blob/master/modules/link/README.md"

View File

@ -9,15 +9,15 @@ var request = require('request'),
var link = function(dbot) {
this.urlRegex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
this.links = {};
this.links = {};
this.handlers = [];
this.api = {
'addHandler': function(name, regex, handler) {
this.handlers.push({
'name': name,
'regex': regex,
'callback': handler
this.handlers.push({
'name': name,
'regex': regex,
'callback': handler
});
},
@ -26,8 +26,8 @@ var link = function(dbot) {
size = 0,
page = request(link.replace('https', 'http'), function(error, response, body) {
if(!error && response.statusCode == 200) {
body = body.replace(/(\r\n|\n\r|\n)/gim, " ");
var title = body.valMatch(/<title>(.*?)<\\?\/title>/, 2);
body = body.replace(/(\r\n|\n\r|\n)/gm, " ");
var title = body.valMatch(/<title>(.*)<\/title>/, 2);
if(title && title.length < 140) {
callback(ent.decode(title[1]).trim());
}
@ -43,50 +43,23 @@ var link = function(dbot) {
},
'udLookup': function(query, callback) {
var reqUrl = 'http://api.urbandictionary.com/v0/define?term=' +
encodeURI(query);
var reqUrl = 'http://api.urbandictionary.com/v0/define?term=' +
encodeURI(query);
request(reqUrl, function(error, response, body) {
console.log(reqUrl);
try {
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]);
} else {
callback(false);
}
} catch(err) {
console.log(err);
callback(false);
}
} catch(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 } ));
});
}
}
};
var commands = {
'~title': function(event) {
var link = this.links[event.channel.name];
@ -100,10 +73,9 @@ var link = function(dbot) {
event.reply(dbot.t('link', { 'link': title} ));
});
},
'~xkcd': function(event) {
//var comicId = event.params[1] || "";
var comicId = event.params.slice(1).join(' ');
var comicId = event.params[1] || "";
if(comicId == "*") {
request("http://xkcd.com/info.0.json", function(error, response, body){
@ -114,86 +86,27 @@ var link = function(dbot) {
dbot.commands['~xkcd'](event);
}
} catch(err) { };
});
});
} else {
if (isNaN(parseInt(comicId))) {
request({
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) { };
});
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) { };
});
}
},
'~ud': function(event) {
var query = event.input[1];
@ -206,18 +119,27 @@ var link = function(dbot) {
});
}
};
commands['~ud'].regex = [/ud (.+)/, 2];
commands['~ud'].regex = [/~ud (.+)/, 2];
this.commands = commands;
this.listener = function(event) {
var urlMatches = event.message.match(this.urlRegex);
if(urlMatches !== null) {
this.links[event.channel.name] = urlMatches[0];
console.log('DEBUG: got a link');
if(this.config.autoTitle == true) {
this.api.parseLink(urlMatches[0], function(result) {
event.reply(result);
});
if(dbot.config.link.autoTitle == true) {
var handlerFound = false;
for(var i=0;i<this.handlers.length;i++) {
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);

View File

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

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