Merge pull request #63 from bb010g/explicit-config

Explicit config
This commit is contained in:
Drew 2016-06-06 23:28:23 -04:00
commit 1de9e7f968
53 changed files with 611 additions and 604 deletions

108
README.md
View File

@ -35,15 +35,15 @@ When you are ready to start the bot, run `./launch.sh`. To stop the bot, send "/
Note that certain plugins, such as translate.lua and greetings.lua, will require privacy mode to be disabled. Additionally, some plugins may require or make use of various API keys: Note that certain plugins, such as translate.lua and greetings.lua, will require privacy mode to be disabled. Additionally, some plugins may require or make use of various API keys:
- bing.lua: [Bing Search API](http://datamarket.azure.com/dataset/bing/search) key (`bing_api_key`) - `bing.lua`: [Bing Search API](http://datamarket.azure.com/dataset/bing/search) key (`bing_api_key`)
- gImages.lua & youtube.lua: Google [API](http://console.developers.google.com) and [CSE](https://cse.google.com/cse) keys (`google_api_key`, `google_cse_key`) - `gImages.lua` & `youtube.lua`: Google [API](http://console.developers.google.com) and [CSE](https://cse.google.com/cse) keys (`google_api_key`, `google_cse_key`)
- weather.lua: [OpenWeatherMap](http://openweathermap.org) API key (`owm_api_key`) - `weather.lua`: [OpenWeatherMap](http://openweathermap.org) API key (`owm_api_key`)
- lastfm.lua: [last.fm](http://last.fm/api) API key (`lastfm_api_key`) - `lastfm.lua`: [last.fm](http://last.fm/api) API key (`lastfm_api_key`)
- bible.lua: [Biblia](http://api.biblia.com) API key (`biblia_api_key`) - `bible.lua`: [Biblia](http://api.biblia.com) API key (`biblia_api_key`)
- cats.lua: [The Cat API](http://thecatapi.com) API key (optional) (`thecatapi_key`) - `cats.lua`: [The Cat API](http://thecatapi.com) API key (optional) (`thecatapi_key`)
- apod.lua: [NASA](http://api.nasa.gov) API key (`nasa_api_key`) - `apod.lua`: [NASA](http://api.nasa.gov) API key (`nasa_api_key`)
- translate.lua: [Yandex](http://tech.yandex.com/keys/get) API key (`yandex_key`) - `translate.lua`: [Yandex](http://tech.yandex.com/keys/get) API key (`yandex_key`)
- chatter.lua: [SimSimi](http://developer.simsimi.com/signUp) API key (`simsimi_key`) - `chatter.lua`: [SimSimi](http://developer.simsimi.com/signUp) API key (`simsimi_key`)
* * * * * *
@ -51,13 +51,13 @@ Note that certain plugins, such as translate.lua and greetings.lua, will require
Some plugins are designed to be used by the bot's owner. Here are some examples, how they're used, and what they do. Some plugins are designed to be used by the bot's owner. Here are some examples, how they're used, and what they do.
| Plugin | Command | Function | | Plugin | Command | Function |
|:--------------|:-----------|:---------------------------------------------------| |:----------------|:-----------|:---------------------------------------------------|
| control.lua | /reload | Reloads all plugins and configuration. | | `control.lua` | /reload | Reloads all plugins and configuration. |
| | /halt | Shuts down the bot after saving the database. | | | /halt | Shuts down the bot after saving the database. |
| | /script | Runs a list a bot commands, separated by newlines. | | | /script | Runs a list a bot commands, separated by newlines. |
| blacklist.lua | /blacklist | Blocks people from using the bot. | | `blacklist.lua` | /blacklist | Blocks people from using the bot. |
| shell.lua | /run | Executes shell commands on the host system. | | `shell.lua` | /run | Executes shell commands on the host system. |
| luarun.lua | /lua | Executes Lua commands in the bot's environment. | | `luarun.lua` | /lua | Executes Lua commands in the bot's environment. |
* * * * * *
@ -68,7 +68,7 @@ To get started, run `./tg-install.sh`. Note that this script is written for Ubun
Once the installation is finished, enable the `administration` plugin in your config file. **The administration plugin must be loaded before the `about` and `blacklist` plugins.** You may have reason to change the default TCP port (4567); if that is the case, remember to change it in `tg-launch.sh` as well. Run `./tg-launch.sh` in a separate screen/tmux window. You'll have to enter your phone number and go through the login process the first time. The script is set to restart tg after two seconds, so you'll need to Ctrl+C after exiting. Once the installation is finished, enable the `administration` plugin in your config file. **The administration plugin must be loaded before the `about` and `blacklist` plugins.** You may have reason to change the default TCP port (4567); if that is the case, remember to change it in `tg-launch.sh` as well. Run `./tg-launch.sh` in a separate screen/tmux window. You'll have to enter your phone number and go through the login process the first time. The script is set to restart tg after two seconds, so you'll need to Ctrl+C after exiting.
While tg is running, you may start/reload otouto with administration.lua enabled, and have access to a wide variety of administrative commands and automata. The administration "database" is stored in `administration.json`. To start using otouto to administrate a group (note that you must be the owner (or an administrator)), send `/gadd` to that group. For a list of commands, use `/ahelp`. Below I'll describe various functions now available to you. While tg is running, you may start/reload otouto with `administration.lua` enabled, and have access to a wide variety of administrative commands and automata. The administration "database" is stored in `administration.json`. To start using otouto to administrate a group (note that you must be the owner (or an administrator)), send `/gadd` to that group. For a list of commands, use `/ahelp`. Below I'll describe various functions now available to you.
| Command | Function | Privilege | Internal? | | Command | Function | Privilege | Internal? |
|:------------|:------------------------------------------------|:----------|:----------| |:------------|:------------------------------------------------|:----------|:----------|
@ -152,45 +152,45 @@ Additionally, antiflood can be configured to automatically ban a user after he h
## List of plugins ## List of plugins
| Plugin | Command | Function | Aliases | | Plugin | Command | Function | Aliases |
|:--------------------|:------------------------------|:--------------------------------------------------------|:--------| |:----------------------|:------------------------------|:--------------------------------------------------------|:--------|
| help.lua | /help [command] | Returns a list of commands or command-specific help. | /h | | `help.lua` | /help [command] | Returns a list of commands or command-specific help. | /h |
| about.lua | /about | Returns the about text as configured in config.lua. | | `about.lua` | /about | Returns the about text as configured in config.lua. |
| ping.lua | /ping | The simplest plugin ever! | | `ping.lua` | /ping | The simplest plugin ever! |
| echo.lua | /echo text | Repeats a string of text. | | `echo.lua` | /echo text | Repeats a string of text. |
| bing.lua | /bing query | Returns Bing web results. | /g | | `bing.lua` | /bing query | Returns Bing web results. | /g |
| gImages.lua | /images query | Returns a Google image result. | /i | | `gImages.lua` | /images query | Returns a Google image result. | /i |
| gMaps.lua | /location query | Returns location data from Google Maps. | /loc | | `gMaps.lua` | /location query | Returns location data from Google Maps. | /loc |
| youtube.lua | /youtube query | Returns the top video result from YouTube. | /yt | | `youtube.lua` | /youtube query | Returns the top video result from YouTube. | /yt |
| wikipedia.lua | /wikipedia query | Returns the summary of a Wikipedia article. | /w | | `wikipedia.lua` | /wikipedia query | Returns the summary of a Wikipedia article. | /w |
| lastfm.lua | /np [username] | Returns the song you are currently listening to. | | `lastfm.lua` | /np [username] | Returns the song you are currently listening to. |
| lastfm.lua | /fmset [username] | Sets your username for /np. /fmset -- will delete it. | | `lastfm.lua` | /fmset [username] | Sets your username for /np. /fmset -- will delete it. |
| hackernews.lua | /hackernews | Returns the latest posts from Hacker News. | /hn | | `hackernews.lua` | /hackernews | Returns the latest posts from Hacker News. | /hn |
| imdb.lua | /imdb query | Returns film information from IMDb. | | `imdb.lua` | /imdb query | Returns film information from IMDb. |
| hearthstone.lua | /hearthstone query | Returns data for Hearthstone cards matching the query. | /hs | | `hearthstone.lua` | /hearthstone query | Returns data for Hearthstone cards matching the query. | /hs |
| calc.lua | /calc expression | Returns conversions and solutions to math expressions. | | `calc.lua` | /calc expression | Returns conversions and solutions to math expressions. |
| bible.lua | /bible reference | Returns a Bible verse. | /b | | `bible.lua` | /bible reference | Returns a Bible verse. | /b |
| urbandictionary.lua | /urban query | Returns the top definition from Urban Dictionary. | /ud | | `urbandictionary.lua` | /urban query | Returns the top definition from Urban Dictionary. | /ud |
| time.lua | /time query | Returns the time, date, and a timezone for a location. | | `time.lua` | /time query | Returns the time, date, and a timezone for a location. |
| weather.lua | /weather query | Returns current weather conditions for a given location. | | `weather.lua` | /weather query | Returns current weather conditions for a given location. |
| nick.lua | /nick nickname | Set your nickname. /nick - will delete it. | | `nick.lua` | /nick nickname | Set your nickname. /nick - will delete it. |
| whoami.lua | /whoami | Returns user and chat info for you or the replied-to user. | /who | | `whoami.lua` | /whoami | Returns user and chat info for you or the replied-to user. | /who |
| eightball.lua | /8ball | Returns an answer from a magic 8-ball. | | `eightball.lua` | /8ball | Returns an answer from a magic 8-ball. |
| dice.lua | /roll nDr | Returns RNG dice rolls. Uses D&D notation. | | `dice.lua` | /roll nDr | Returns RNG dice rolls. Uses D&D notation. |
| reddit.lua | /reddit [r/subreddit ¦ query] | Returns the top results from a subreddit, query, or r/all. | /r | | `reddit.lua` | /reddit [r/subreddit ¦ query] | Returns the top results from a subreddit, query, or r/all. | /r |
| xkcd.lua | /xkcd [query] | Returns an xkcd strip and its alt text. | | `xkcd.lua` | /xkcd [query] | Returns an xkcd strip and its alt text. |
| slap.lua | /slap target | Gives someone a slap (or worse). | | `slap.lua` | /slap target | Gives someone a slap (or worse). |
| commit.lua | /commit | Returns a commit message from whatthecommit.com. | | `commit.lua` | /commit | Returns a commit message from whatthecommit.com. |
| fortune.lua | /fortune | Returns a UNIX fortune. | | `fortune.lua` | /fortune | Returns a UNIX fortune. |
| pun.lua | /pun | Returns a pun. | | `pun.lua` | /pun | Returns a pun. |
| pokedex.lua | /pokedex query | Returns a Pokedex entry. | /dex | | `pokedex.lua` | /pokedex query | Returns a Pokedex entry. | /dex |
| currency.lua | /cash [amount] cur to cur | Converts one currency to another. | | `currency.lua` | /cash [amount] cur to cur | Converts one currency to another. |
| cats.lua | /cat | Returns a cat picture. | | `cats.lua` | /cat | Returns a cat picture. |
| reactions.lua | /reactions | Returns a list of emoticons which can be posted by the bot. | | `reactions.lua` | /reactions | Returns a list of emoticons which can be posted by the bot. |
| apod.lua | /apod [date] | Returns the NASA Astronomy Picture of the Day. | | `apod.lua` | /apod [date] | Returns the NASA Astronomy Picture of the Day. |
| dilbert.lua | /dilbert [date] | Returns a Dilbert strip. | | `dilbert.lua` | /dilbert [date] | Returns a Dilbert strip. |
| patterns.lua | /s/from/to/ | Search-and-replace using Lua patterns. | | `patterns.lua` | /s/from/to/ | Search-and-replace using Lua patterns. |
| me.lua | /me | Returns user-specific data stored by the bot. | | `me.lua` | /me | Returns user-specific data stored by the bot. |
| remind.lua | /remind <duration> <message> | Reminds a user of something after a duration of minutes. | | `remind.lua` | /remind <duration> <message> | Reminds a user of something after a duration of minutes. |
* * * * * *

36
bot.lua
View File

@ -6,18 +6,16 @@ local utilities -- Load miscellaneous and cross-plugin functions.
bot.version = '3.8' bot.version = '3.8'
function bot:init() -- The function run when the bot is started or reloaded. function bot:init(config) -- The function run when the bot is started or reloaded.
bindings = require('bindings') bindings = require('bindings')
utilities = require('utilities') utilities = require('utilities')
self.config = require('config') -- Load configuration file.
assert( assert(
self.config.bot_api_key and self.config.bot_api_key ~= '', config.bot_api_key and config.bot_api_key ~= '',
'You did not set your bot token in config.lua!' 'You did not set your bot token in the config!'
) )
self.BASE_URL = 'https://api.telegram.org/bot' .. self.config.bot_api_key .. '/' self.BASE_URL = 'https://api.telegram.org/bot' .. config.bot_api_key .. '/'
-- Fetch bot information. Try until it succeeds. -- Fetch bot information. Try until it succeeds.
repeat repeat
@ -35,10 +33,10 @@ function bot:init() -- The function run when the bot is started or reloaded.
self.database.users[tostring(self.info.id)] = self.info self.database.users[tostring(self.info.id)] = self.info
self.plugins = {} -- Load plugins. self.plugins = {} -- Load plugins.
for _,v in ipairs(self.config.plugins) do for _,v in ipairs(config.plugins) do
local p = require('plugins.'..v) local p = require('plugins.'..v)
table.insert(self.plugins, p) table.insert(self.plugins, p)
if p.init then p.init(self) end if p.init then p.init(self, config) end
end end
print('@' .. self.info.username .. ', AKA ' .. self.info.first_name ..' ('..self.info.id..')') print('@' .. self.info.username .. ', AKA ' .. self.info.first_name ..' ('..self.info.id..')')
@ -49,7 +47,7 @@ function bot:init() -- The function run when the bot is started or reloaded.
end end
function bot:on_msg_receive(msg) -- The fn run whenever a message is received. function bot:on_msg_receive(msg, config) -- The fn run whenever a message is received.
-- Cache user info for those involved. -- Cache user info for those involved.
utilities.create_user_entry(self, msg.from) utilities.create_user_entry(self, msg.from)
@ -63,20 +61,20 @@ function bot:on_msg_receive(msg) -- The fn run whenever a message is received.
msg = utilities.enrich_message(msg) msg = utilities.enrich_message(msg)
if msg.text:match('^/start .+') then if msg.text:match('^'..config.cmd_pat..'start .+') then
msg.text = '/' .. utilities.input(msg.text) msg.text = config.cmd_pat .. utilities.input(msg.text)
msg.text_lower = msg.text:lower() msg.text_lower = msg.text:lower()
end end
for _,v in ipairs(self.plugins) do for _,v in ipairs(self.plugins) do
for _,w in pairs(v.triggers) do for _,w in pairs(v.triggers) do
if string.match(msg.text:lower(), w) then if string.match(msg.text_lower, w) then
local success, result = pcall(function() local success, result = pcall(function()
return v.action(self, msg) return v.action(self, msg, config)
end) end)
if not success then if not success then
utilities.send_reply(self, msg, 'Sorry, an unexpected error occurred.') utilities.send_reply(self, msg, 'Sorry, an unexpected error occurred.')
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text) utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config)
return return
end end
-- If the action returns a table, make that table the new msg. -- If the action returns a table, make that table the new msg.
@ -92,8 +90,8 @@ function bot:on_msg_receive(msg) -- The fn run whenever a message is received.
end end
function bot:run() function bot:run(config)
bot.init(self) -- Actually start the script. Run the bot_init function. bot.init(self, config) -- Actually start the script.
while self.is_started do -- Start a loop while the bot should be running. while self.is_started do -- Start a loop while the bot should be running.
@ -102,7 +100,7 @@ function bot:run()
for _,v in ipairs(res.result) do -- Go through every new message. for _,v in ipairs(res.result) do -- Go through every new message.
self.last_update = v.update_id self.last_update = v.update_id
if v.message then if v.message then
bot.on_msg_receive(self, v.message) bot.on_msg_receive(self, v.message, config)
end end
end end
else else
@ -114,9 +112,9 @@ function bot:run()
utilities.save_data(self.info.username..'.db', self.database) -- Save the database. utilities.save_data(self.info.username..'.db', self.database) -- Save the database.
for i,v in ipairs(self.plugins) do for i,v in ipairs(self.plugins) do
if v.cron then -- Call each plugin's cron function, if it has one. if v.cron then -- Call each plugin's cron function, if it has one.
local result, err = pcall(function() v.cron(self) end) local result, err = pcall(function() v.cron(self, config) end)
if not result then if not result then
utilities.handle_exception(self, err, 'CRON: ' .. i) utilities.handle_exception(self, err, 'CRON: ' .. i, config)
end end
end end
end end

View File

@ -18,6 +18,8 @@ I am otouto, the plugin-wielding, multipurpose Telegram bot.
Send /help to get started. Send /help to get started.
]], ]],
-- The symbol that starts a command. Usually noted as '/' in documentation.
cmd_pat = '/',
-- https://datamarket.azure.com/dataset/bing/search -- https://datamarket.azure.com/dataset/bing/search
bing_api_key = '', bing_api_key = '',

View File

@ -1,5 +1,6 @@
local bot = require('bot') local bot = require('bot')
local instance = {} local instance = {}
local config = require('config')
return bot.run(instance) return bot.run(instance, config)

View File

@ -10,18 +10,18 @@ about.triggers = {
'' ''
} }
function about:action(msg) function about:action(msg, config)
-- Filthy hack, but here is where we'll stop forwarded messages from hitting -- Filthy hack, but here is where we'll stop forwarded messages from hitting
-- other plugins. -- other plugins.
if msg.forward_from then return end if msg.forward_from then return end
local output = self.config.about_text .. '\nBased on otouto v'..bot.version..' by topkecleon.' local output = config.about_text .. '\nBased on otouto v'..bot.version..' by topkecleon.'
if (msg.new_chat_participant and msg.new_chat_participant.id == self.info.id) if (msg.new_chat_participant and msg.new_chat_participant.id == self.info.id)
or msg.text_lower:match('^/about') or msg.text_lower:match('^'..config.cmd_pat..'about')
or msg.text_lower:match('^/about@'..self.info.username:lower()) or msg.text_lower:match('^'..config.cmd_pat..'about@'..self.info.username:lower())
or msg.text_lower:match('^/start') then or msg.text_lower:match('^'..config.cmd_pat..'start') then
utilities.send_message(self, msg.chat.id, output, true) utilities.send_message(self, msg.chat.id, output, true)
return return
end end

View File

@ -48,7 +48,7 @@ local utilities = require('utilities')
local administration = {} local administration = {}
function administration:init() function administration:init(config)
-- Build the administration db if nonexistent. -- Build the administration db if nonexistent.
if not self.database.administration then if not self.database.administration then
self.database.administration = { self.database.administration = {
@ -64,19 +64,22 @@ function administration:init()
flood = {} flood = {}
} }
drua.PORT = self.config.cli_port or 4567 drua.PORT = config.cli_port or 4567
administration.init_command(self) administration.init_flags(config.cmd_pat)
administration.init_command(self, config)
administration.doc = '`Returns a list of administrated groups.\nUse '..config.cmd_pat..'ahelp for more administrative commands.`'
end end
administration.flags = { function administration.init_flags(cmd_pat) return {
[1] = { [1] = {
name = 'unlisted', name = 'unlisted',
desc = 'Removes this group from the group listing.', desc = 'Removes this group from the group listing.',
short = 'This group is unlisted.', short = 'This group is unlisted.',
enabled = 'This group is no longer listed in /groups.', enabled = 'This group is no longer listed in '..cmd_pat..'groups.',
disabled = 'This group is now listed in /groups.' disabled = 'This group is now listed in '..cmd_pat..'groups.'
}, },
[2] = { [2] = {
name = 'antisquig', name = 'antisquig',
@ -105,7 +108,7 @@ administration.flags = {
name = 'antiflood', name = 'antiflood',
desc = 'Prevents flooding by rate-limiting messages per user.', desc = 'Prevents flooding by rate-limiting messages per user.',
short = 'This group automatically removes users who flood.', short = 'This group automatically removes users who flood.',
enabled = 'Users will now be removed automatically for excessive messages. Use /antiflood to configure limits.', enabled = 'Users will now be removed automatically for excessive messages. Use '..cmd_pat..'antiflood to configure limits.',
disabled = 'Users will no longer be removed automatically for excessive messages.', disabled = 'Users will no longer be removed automatically for excessive messages.',
kicked = 'You were automatically kicked from GROUPNAME for flooding.' kicked = 'You were automatically kicked from GROUPNAME for flooding.'
}, },
@ -116,7 +119,7 @@ administration.flags = {
enabled = 'This group will no longer remove users for being globally banned.', enabled = 'This group will no longer remove users for being globally banned.',
disabled = 'This group will now remove users for being globally banned.' disabled = 'This group will now remove users for being globally banned.'
} }
} } end
administration.antiflood = { administration.antiflood = {
text = 10, text = 10,
@ -139,13 +142,13 @@ administration.ranks = {
[5] = 'Owner' [5] = 'Owner'
} }
function administration:get_rank(target, chat) function administration:get_rank(target, chat, config)
target = tostring(target) target = tostring(target)
chat = tostring(chat) chat = tostring(chat)
-- Return 5 if the target is the bot or its owner. -- Return 5 if the target is the bot or its owner.
if tonumber(target) == self.config.admin or tonumber(target) == self.info.id then if tonumber(target) == config.admin or tonumber(target) == self.info.id then
return 5 return 5
end end
@ -180,10 +183,10 @@ function administration:get_rank(target, chat)
end end
function administration:get_target(msg) function administration:get_target(msg, config)
local target = utilities.user_from_message(self, msg) local target = utilities.user_from_message(self, msg)
if target.id then if target.id then
target.rank = administration.get_rank(self, target.id_str, msg.chat.id) target.rank = administration.get_rank(self, target.id_str, msg.chat.id, config)
end end
return target return target
end end
@ -197,7 +200,7 @@ function administration:mod_format(id)
return output return output
end end
function administration:get_desc(chat_id) function administration:get_desc(chat_id, config)
local group = self.database.administration.groups[tostring(chat_id)] local group = self.database.administration.groups[tostring(chat_id)]
local t = {} local t = {}
@ -237,12 +240,12 @@ function administration:get_desc(chat_id)
if modstring ~= '' then if modstring ~= '' then
table.insert(t, '*Moderators:*\n' .. utilities.trim(modstring)) table.insert(t, '*Moderators:*\n' .. utilities.trim(modstring))
end end
table.insert(t, 'Run /ahelp@' .. self.info.username .. ' for a list of commands.') table.insert(t, 'Run '..config..'ahelp@' .. self.info.username .. ' for a list of commands.')
return table.concat(t, '\n\n') return table.concat(t, '\n\n')
end end
function administration:update_desc(chat) function administration:update_desc(chat, config)
local group = self.database.administration.groups[tostring(chat)] local group = self.database.administration.groups[tostring(chat)]
local desc = 'Welcome to ' .. group.name .. '!\n' local desc = 'Welcome to ' .. group.name .. '!\n'
if group.motd then desc = desc .. group.motd .. '\n' end if group.motd then desc = desc .. group.motd .. '\n' end
@ -250,12 +253,12 @@ function administration:update_desc(chat)
local gov = self.database.users[tostring(group.governor)] local gov = self.database.users[tostring(group.governor)]
desc = desc .. '\nGovernor: ' .. utilities.build_name(gov.first_name, gov.last_name) .. ' [' .. gov.id .. ']\n' desc = desc .. '\nGovernor: ' .. utilities.build_name(gov.first_name, gov.last_name) .. ' [' .. gov.id .. ']\n'
end end
local s = '\n/desc@' .. self.info.username .. ' for more information.' local s = '\n'..config.cmd_pat..'desc@' .. self.info.username .. ' for more information.'
desc = desc:sub(1, 250-s:len()) .. s desc = desc:sub(1, 250-s:len()) .. s
drua.channel_set_about(chat, desc) drua.channel_set_about(chat, desc)
end end
function administration:kick_user(chat, target, reason) function administration:kick_user(chat, target, reason, config)
drua.kick_user(chat, target) drua.kick_user(chat, target)
local victim = target local victim = target
if self.database.users[tostring(target)] then if self.database.users[tostring(target)] then
@ -265,10 +268,10 @@ function administration:kick_user(chat, target, reason)
) )
end end
local group = self.database.administration.groups[tostring(chat)].name local group = self.database.administration.groups[tostring(chat)].name
utilities.handle_exception(self, victim..' kicked from '..group, reason) utilities.handle_exception(self, victim..' kicked from '..group, reason, config)
end end
function administration.init_command(self_) function administration.init_command(self_, config)
administration.commands = { administration.commands = {
{ -- generic, mostly autokicks { -- generic, mostly autokicks
@ -277,9 +280,10 @@ function administration.init_command(self_)
privilege = 0, privilege = 0,
interior = true, interior = true,
action = function(self, msg, group) action = function(self, msg, group, config)
local rank = administration.get_rank(self, msg.from.id, msg.chat.id) local rank = administration.get_rank(self, msg.from.id, msg.chat.id)
local rank = administration.get_rank(self, msg.from.id, msg.chat.id, config)
local user = {} local user = {}
if rank < 2 then if rank < 2 then
@ -360,7 +364,7 @@ function administration.init_command(self_)
-- the original guy. -- the original guy.
if msg.new_chat_participant.id ~= msg.from.id then if msg.new_chat_participant.id ~= msg.from.id then
new_user = {} new_user = {}
new_rank = administration.get_rank(self,noob.id, msg.chat.id) new_rank = administration.get_rank(self,noob.id, msg.chat.id, config)
end end
if new_rank == 0 then if new_rank == 0 then
@ -399,7 +403,7 @@ function administration.init_command(self_)
else else
group.name = msg.new_chat_title group.name = msg.new_chat_title
if group.grouptype == 'supergroup' then if group.grouptype == 'supergroup' then
administration.update_desc(self, msg.chat.id) administration.update_desc(self, msg.chat.id, config)
end end
end end
elseif msg.new_chat_photo then elseif msg.new_chat_photo then
@ -425,7 +429,7 @@ function administration.init_command(self_)
end end
if new_user ~= user and new_user.do_kick then if new_user ~= user and new_user.do_kick then
administration.kick_user(self, msg.chat.id, msg.new_chat_participant.id, new_user.reason) administration.kick_user(self, msg.chat.id, msg.new_chat_participant.id, new_user.reason, config)
if new_user.output then if new_user.output then
utilities.send_message(self, msg.new_chat_participant.id, new_user.output) utilities.send_message(self, msg.new_chat_participant.id, new_user.output)
end end
@ -450,7 +454,7 @@ function administration.init_command(self_)
end end
if user.do_kick then if user.do_kick then
administration.kick_user(self, msg.chat.id, msg.from.id, user.reason) administration.kick_user(self, msg.chat.id, msg.from.id, user.reason, config)
if user.output then if user.output then
utilities.send_message(self, msg.from.id, user.output) utilities.send_message(self, msg.from.id, user.output)
end end
@ -460,7 +464,7 @@ function administration.init_command(self_)
end end
if msg.new_chat_participant and not new_user.do_kick then if msg.new_chat_participant and not new_user.do_kick then
local output = administration.get_desc(self, msg.chat.id) local output = administration.get_desc(self, msg.chat.id, config)
utilities.send_message(self, msg.new_chat_participant.id, output, true, nil, true) utilities.send_message(self, msg.new_chat_participant.id, output, true, nil, true)
end end
@ -480,14 +484,14 @@ function administration.init_command(self_)
}, },
{ -- /groups { -- /groups
triggers = utilities.triggers(self_.info.username):t('groups').table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('groups').table,
command = 'groups', command = 'groups',
privilege = 1, privilege = 1,
interior = false, interior = false,
doc = 'Returns a list of administrated groups.', doc = 'Returns a list of administrated groups.',
action = function(self, msg) action = function(self, msg, group, config)
local output = '' local output = ''
for _,v in ipairs(self.database.administration.activity) do for _,v in ipairs(self.database.administration.activity) do
local group = self.database.administration.groups[v] local group = self.database.administration.groups[v]
@ -509,22 +513,22 @@ function administration.init_command(self_)
}, },
{ -- /ahelp { -- /ahelp
triggers = utilities.triggers(self_.info.username):t('ahelp', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('ahelp', true).table,
command = 'ahelp \\[command]', command = 'ahelp \\[command]',
privilege = 1, privilege = 1,
interior = false, interior = false,
doc = 'Returns a list of realm-related commands for your rank (in a private message), or command-specific help.', doc = 'Returns a list of realm-related commands for your rank (in a private message), or command-specific help.',
action = function(self, msg) action = function(self, msg, group, config)
local rank = administration.get_rank(self, msg.from.id, msg.chat.id) local rank = administration.get_rank(self, msg.from.id, msg.chat.id, config)
local input = utilities.get_word(msg.text_lower, 2) local input = utilities.get_word(msg.text_lower, 2)
if input then if input then
input = input:gsub('^/', '') input = input:gsub('^'..config.cmd_pat..'', '')
local doc local doc
for _,action in ipairs(administration.commands) do for _,action in ipairs(administration.commands) do
if action.keyword == input then if action.keyword == input then
doc = '/' .. action.command:gsub('\\','') .. '\n' .. action.doc doc = ''..config.cmd_pat..'' .. action.command:gsub('\\','') .. '\n' .. action.doc
break break
end end
end end
@ -532,14 +536,14 @@ function administration.init_command(self_)
local output = '*Help for* _' .. input .. '_ :\n```\n' .. doc .. '\n```' local output = '*Help for* _' .. input .. '_ :\n```\n' .. doc .. '\n```'
utilities.send_message(self, msg.chat.id, output, true, nil, true) utilities.send_message(self, msg.chat.id, output, true, nil, true)
else else
local output = 'Sorry, there is no help for that command.\n/ahelp@'..self.info.username local output = 'Sorry, there is no help for that command.\n'..config.cmd_pat..'ahelp@'..self.info.username
utilities.send_reply(self, msg, output) utilities.send_reply(self, msg, output)
end end
else else
local output = '*Commands for ' .. administration.ranks[rank] .. ':*\n' local output = '*Commands for ' .. administration.ranks[rank] .. ':*\n'
for i = 1, rank do for i = 1, rank do
for _, val in ipairs(self.admin_temp.help[i]) do for _, val in ipairs(self.admin_temp.help[i]) do
output = output .. '/' .. val .. '\n' output = output .. '' .. config.cmd_pat .. val .. '\n'
end end
end end
output = output .. 'Arguments: <required> \\[optional]' output = output .. 'Arguments: <required> \\[optional]'
@ -555,14 +559,14 @@ function administration.init_command(self_)
}, },
{ -- /ops { -- /ops
triggers = utilities.triggers(self_.info.username):t('ops'):t('oplist').table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('ops'):t('oplist').table,
command = 'ops', command = 'ops',
privilege = 1, privilege = 1,
interior = true, interior = true,
doc = 'Returns a list of moderators and the governor for the group.', doc = 'Returns a list of moderators and the governor for the group.',
action = function(self, msg, group) action = function(self, msg, group, config)
local modstring = '' local modstring = ''
for k,_ in pairs(group.mods) do for k,_ in pairs(group.mods) do
modstring = modstring .. administration.mod_format(self, k) modstring = modstring .. administration.mod_format(self, k)
@ -585,15 +589,15 @@ function administration.init_command(self_)
}, },
{ -- /desc { -- /desc
triggers = utilities.triggers(self_.info.username):t('desc'):t('description').table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('desc'):t('description').table,
command = 'description', command = 'description',
privilege = 1, privilege = 1,
interior = true, interior = true,
doc = 'Returns a description of the group (in a private message), including its motd, rules, flags, governor, and moderators.', doc = 'Returns a description of the group (in a private message), including its motd, rules, flags, governor, and moderators.',
action = function(self, msg) action = function(self, msg, group, config)
local output = administration.get_desc(self, msg.chat.id) local output = administration.get_desc(self, msg.chat.id, config)
if utilities.send_message(self, msg.from.id, output, true, nil, true) then if utilities.send_message(self, msg.from.id, output, true, nil, true) then
if msg.from.id ~= msg.chat.id then if msg.from.id ~= msg.chat.id then
utilities.send_reply(self, msg, 'I have sent you the requested information in a private message.') utilities.send_reply(self, msg, 'I have sent you the requested information in a private message.')
@ -605,14 +609,14 @@ function administration.init_command(self_)
}, },
{ -- /rules { -- /rules
triggers = utilities.triggers(self_.info.username):t('rules?', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('rules?', true).table,
command = 'rules \\[i]', command = 'rules \\[i]',
privilege = 1, privilege = 1,
interior = true, interior = true,
doc = 'Returns the group\'s list of rules, or a specific rule.', doc = 'Returns the group\'s list of rules, or a specific rule.',
action = function(self, msg, group) action = function(self, msg, group, config)
local output local output
local input = utilities.get_word(msg.text_lower, 2) local input = utilities.get_word(msg.text_lower, 2)
input = tonumber(input) input = tonumber(input)
@ -633,14 +637,14 @@ function administration.init_command(self_)
}, },
{ -- /motd { -- /motd
triggers = utilities.triggers(self_.info.username):t('motd').table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('motd').table,
command = 'motd', command = 'motd',
privilege = 1, privilege = 1,
interior = true, interior = true,
doc = 'Returns the group\'s message of the day.', doc = 'Returns the group\'s message of the day.',
action = function(self, msg, group) action = function(self, msg, group, config)
local output = 'No MOTD has been set for ' .. msg.chat.title .. '.' local output = 'No MOTD has been set for ' .. msg.chat.title .. '.'
if group.motd then if group.motd then
output = '*MOTD for ' .. msg.chat.title .. ':*\n' .. group.motd output = '*MOTD for ' .. msg.chat.title .. ':*\n' .. group.motd
@ -650,14 +654,14 @@ function administration.init_command(self_)
}, },
{ -- /link { -- /link
triggers = utilities.triggers(self_.info.username):t('link').table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('link').table,
command = 'link', command = 'link',
privilege = 1, privilege = 1,
interior = true, interior = true,
doc = 'Returns the group\'s link.', doc = 'Returns the group\'s link.',
action = function(self, msg, group) action = function(self, msg, group, config)
local output = 'No link has been set for ' .. msg.chat.title .. '.' local output = 'No link has been set for ' .. msg.chat.title .. '.'
if group.link then if group.link then
output = '[' .. msg.chat.title .. '](' .. group.link .. ')' output = '[' .. msg.chat.title .. '](' .. group.link .. ')'
@ -667,18 +671,18 @@ function administration.init_command(self_)
}, },
{ -- /kickme { -- /kickme
triggers = utilities.triggers(self_.info.username):t('leave'):t('kickme').table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('leave'):t('kickme').table,
command = 'kickme', command = 'kickme',
privilege = 1, privilege = 1,
interior = true, interior = true,
doc = 'Removes the user from the group.', doc = 'Removes the user from the group.',
action = function(self, msg) action = function(self, msg, group, config)
if administration.get_rank(self, msg.from.id) == 5 then if administration.get_rank(self, msg.from.id, nil, config) == 5 then
utilities.send_reply(self, msg, 'I can\'t let you do that, '..msg.from.name..'.') utilities.send_reply(self, msg, 'I can\'t let you do that, '..msg.from.name..'.')
else else
administration.kick_user(self, msg.chat.id, msg.from.id, 'kickme') administration.kick_user(self, msg.chat.id, msg.from.id, 'kickme', config)
utilities.send_message(self, msg.chat.id, 'Goodbye, ' .. msg.from.name .. '!', true) utilities.send_message(self, msg.chat.id, 'Goodbye, ' .. msg.from.name .. '!', true)
if msg.chat.type == 'supergroup' then if msg.chat.type == 'supergroup' then
bindings.unbanChatMember(self, { chat_id = msg.chat.id, user_id = msg.from.id } ) bindings.unbanChatMember(self, { chat_id = msg.chat.id, user_id = msg.from.id } )
@ -688,21 +692,21 @@ function administration.init_command(self_)
}, },
{ -- /kick { -- /kick
triggers = utilities.triggers(self_.info.username):t('kick', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('kick', true).table,
command = 'kick <user>', command = 'kick <user>',
privilege = 2, privilege = 2,
interior = true, interior = true,
doc = 'Removes a user from the group. The target may be specified via reply, username, or ID.', doc = 'Removes a user from the group. The target may be specified via reply, username, or ID.',
action = function(self, msg) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
elseif target.rank > 1 then elseif target.rank > 1 then
utilities.send_reply(self, msg, target.name .. ' is too privileged to be kicked.') utilities.send_reply(self, msg, target.name .. ' is too privileged to be kicked.')
else else
administration.kick_user(self, msg.chat.id, target.id, 'kicked by ' .. msg.from.name) administration.kick_user(self, msg.chat.id, target.id, 'kicked by ' .. msg.from.name, config)
utilities.send_message(self, msg.chat.id, target.name .. ' has been kicked.') utilities.send_message(self, msg.chat.id, target.name .. ' has been kicked.')
if msg.chat.type == 'supergroup' then if msg.chat.type == 'supergroup' then
bindings.unbanChatMember(self, { chat_id = msg.chat.id, user_id = target.id } ) bindings.unbanChatMember(self, { chat_id = msg.chat.id, user_id = target.id } )
@ -712,15 +716,15 @@ function administration.init_command(self_)
}, },
{ -- /ban { -- /ban
triggers = utilities.triggers(self_.info.username):t('ban', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('ban', true).table,
command = 'ban <user>', command = 'ban <user>',
privilege = 2, privilege = 2,
interior = true, interior = true,
doc = 'Bans a user from the group. The target may be specified via reply, username, or ID.', doc = 'Bans a user from the group. The target may be specified via reply, username, or ID.',
action = function(self, msg, group) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
elseif target.rank > 1 then elseif target.rank > 1 then
@ -728,7 +732,7 @@ function administration.init_command(self_)
elseif group.bans[target.id_str] then elseif group.bans[target.id_str] then
utilities.send_reply(self, msg, target.name .. ' is already banned.') utilities.send_reply(self, msg, target.name .. ' is already banned.')
else else
administration.kick_user(self, msg.chat.id, target.id, 'banned by '..msg.from.name) administration.kick_user(self, msg.chat.id, target.id, 'banned by '..msg.from.name, config)
utilities.send_reply(self, msg, target.name .. ' has been banned.') utilities.send_reply(self, msg, target.name .. ' has been banned.')
group.bans[target.id_str] = true group.bans[target.id_str] = true
end end
@ -736,15 +740,15 @@ function administration.init_command(self_)
}, },
{ -- /unban { -- /unban
triggers = utilities.triggers(self_.info.username):t('unban', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('unban', true).table,
command = 'unban <user>', command = 'unban <user>',
privilege = 2, privilege = 2,
interior = true, interior = true,
doc = 'Unbans a user from the group. The target may be specified via reply, username, or ID.', doc = 'Unbans a user from the group. The target may be specified via reply, username, or ID.',
action = function(self, msg, group) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
else else
@ -762,15 +766,15 @@ function administration.init_command(self_)
}, },
{ -- /setrules { -- /setrules
triggers = utilities.triggers(self_.info.username):t('setrules', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('setrules', true).table,
command = 'setrules <rules>', command = 'setrules <rules>',
privilege = 3, privilege = 3,
interior = true, interior = true,
doc = 'Sets the group\'s rules. Rules will be automatically numbered. Separate rules with a new line. Markdown is supported. Pass "--" to delete the rules.', doc = 'Sets the group\'s rules. Rules will be automatically numbered. Separate rules with a new line. Markdown is supported. Pass "--" to delete the rules.',
action = function(self, msg, group) action = function(self, msg, group, config)
local input = msg.text:match('^/setrules[@'..self.info.username..']*(.+)') local input = msg.text:match('^'..config.cmd_pat..'setrules[@'..self.info.username..']*(.+)')
if input == ' --' or input == ' ' .. utilities.char.em_dash then if input == ' --' or input == ' ' .. utilities.char.em_dash then
group.rules = {} group.rules = {}
utilities.send_reply(self, msg, 'The rules have been cleared.') utilities.send_reply(self, msg, 'The rules have been cleared.')
@ -792,16 +796,16 @@ function administration.init_command(self_)
}, },
{ -- /changerule { -- /changerule
triggers = utilities.triggers(self_.info.username):t('changerule', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('changerule', true).table,
command = 'changerule <i> <rule>', command = 'changerule <i> <rule>',
privilege = 3, privilege = 3,
interior = true, interior = true,
doc = 'Changes a single rule. Pass "--" to delete the rule. If i is a number for which there is no rule, adds a rule by the next incremented number.', doc = 'Changes a single rule. Pass "--" to delete the rule. If i is a number for which there is no rule, adds a rule by the next incremented number.',
action = function(self, msg, group) action = function(self, msg, group, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
local output = 'usage: `/changerule <i> <newrule>`' local output = 'usage: `'..config.cmd_pat..'changerule <i> <newrule>`'
if input then if input then
local rule_num = tonumber(input:match('^%d+')) local rule_num = tonumber(input:match('^%d+'))
local new_rule = utilities.input(input) local new_rule = utilities.input(input)
@ -829,14 +833,14 @@ function administration.init_command(self_)
}, },
{ -- /setmotd { -- /setmotd
triggers = utilities.triggers(self_.info.username):t('setmotd', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('setmotd', true).table,
command = 'setmotd <motd>', command = 'setmotd <motd>',
privilege = 2, privilege = 2,
interior = true, interior = true,
doc = 'Sets the group\'s message of the day. Markdown is supported. Pass "--" to delete the message.', doc = 'Sets the group\'s message of the day. Markdown is supported. Pass "--" to delete the message.',
action = function(self, msg, group) action = function(self, msg, group, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input and msg.reply_to_message and msg.reply_to_message.text:len() > 0 then if not input and msg.reply_to_message and msg.reply_to_message.text:len() > 0 then
input = msg.reply_to_message.text input = msg.reply_to_message.text
@ -852,7 +856,7 @@ function administration.init_command(self_)
utilities.send_message(self, msg.chat.id, output, true, nil, true) utilities.send_message(self, msg.chat.id, output, true, nil, true)
end end
if group.grouptype == 'supergroup' then if group.grouptype == 'supergroup' then
administration.update_desc(self, msg.chat.id) administration.update_desc(self, msg.chat.id, config)
end end
else else
utilities.send_reply(self, msg, 'Please specify the new message of the day.') utilities.send_reply(self, msg, 'Please specify the new message of the day.')
@ -861,14 +865,14 @@ function administration.init_command(self_)
}, },
{ -- /setlink { -- /setlink
triggers = utilities.triggers(self_.info.username):t('setlink', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('setlink', true).table,
command = 'setlink <link>', command = 'setlink <link>',
privilege = 3, privilege = 3,
interior = true, interior = true,
doc = 'Sets the group\'s join link. Pass "--" to regenerate the link.', doc = 'Sets the group\'s join link. Pass "--" to regenerate the link.',
action = function(self, msg, group) action = function(self, msg, group, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if input == '--' or input == utilities.char.em_dash then if input == '--' or input == utilities.char.em_dash then
group.link = drua.export_link(msg.chat.id) group.link = drua.export_link(msg.chat.id)
@ -884,16 +888,16 @@ function administration.init_command(self_)
}, },
{ -- /alist { -- /alist
triggers = utilities.triggers(self_.info.username):t('alist').table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('alist').table,
command = 'alist', command = 'alist',
privilege = 3, privilege = 3,
interior = true, interior = true,
doc = 'Returns a list of administrators. Owner is denoted with a star character.', doc = 'Returns a list of administrators. Owner is denoted with a star character.',
action = function(self, msg) action = function(self, msg, config)
local output = '*Administrators:*\n' local output = '*Administrators:*\n'
output = output .. administration.mod_format(self, self.config.admin):gsub('\n', '\n') output = output .. administration.mod_format(self, config.admin):gsub('\n', '\n')
for id,_ in pairs(self.database.administration.admins) do for id,_ in pairs(self.database.administration.admins) do
output = output .. administration.mod_format(self, id) output = output .. administration.mod_format(self, id)
end end
@ -902,14 +906,14 @@ function administration.init_command(self_)
}, },
{ -- /flags { -- /flags
triggers = utilities.triggers(self_.info.username):t('flags?', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('flags?', true).table,
command = 'flag \\[i]', command = 'flag \\[i]',
privilege = 3, privilege = 3,
interior = true, interior = true,
doc = 'Returns a list of flags or toggles the specified flag.', doc = 'Returns a list of flags or toggles the specified flag.',
action = function(self, msg, group) action = function(self, msg, group, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if input then if input then
input = utilities.get_word(input, 1) input = utilities.get_word(input, 1)
@ -934,16 +938,16 @@ function administration.init_command(self_)
}, },
{ -- /antiflood { -- /antiflood
triggers = utilities.triggers(self_.info.username):t('antiflood', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('antiflood', true).table,
command = 'antiflood \\[<type> <i>]', command = 'antiflood \\[<type> <i>]',
privilege = 3, privilege = 3,
interior = true, interior = true,
doc = 'Returns a list of antiflood values or sets one.', doc = 'Returns a list of antiflood values or sets one.',
action = function(self, msg, group) action = function(self, msg, group, config)
if not group.flags[5] then if not group.flags[5] then
utilities.send_message(self, msg.chat.id, 'antiflood is not enabled. Use `/flag 5` to enable it.', true, nil, true) utilities.send_message(self, msg.chat.id, 'antiflood is not enabled. Use `'..config.cmd_pat..'flag 5` to enable it.', true, nil, true)
else else
if not group.antiflood then if not group.antiflood then
group.antiflood = JSON.decode(JSON.encode(administration.antiflood)) group.antiflood = JSON.decode(JSON.encode(administration.antiflood))
@ -962,7 +966,7 @@ function administration.init_command(self_)
output = '*' .. key:gsub('^%l', string.upper) .. '* messages are now worth *' .. val .. '* points.' output = '*' .. key:gsub('^%l', string.upper) .. '* messages are now worth *' .. val .. '* points.'
end end
else else
output = 'usage: `/antiflood <type> <i>`\nexample: `/antiflood text 5`\nUse this command to configure the point values for each message type. When a user reaches 100 points, he is kicked. The points are reset each minute. The current values are:\n' output = 'usage: `'..config.cmd_pat..'antiflood <type> <i>`\nexample: `'..config.cmd_pat..'antiflood text 5`\nUse this command to configure the point values for each message type. When a user reaches 100 points, he is kicked. The points are reset each minute. The current values are:\n'
for k,v in pairs(group.antiflood) do for k,v in pairs(group.antiflood) do
output = output .. '*'..k..':* `'..v..'`\n' output = output .. '*'..k..':* `'..v..'`\n'
end end
@ -974,15 +978,15 @@ function administration.init_command(self_)
}, },
{ -- /mod { -- /mod
triggers = utilities.triggers(self_.info.username):t('mod', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('mod', true).table,
command = 'mod <user>', command = 'mod <user>',
privilege = 3, privilege = 3,
interior = true, interior = true,
doc = 'Promotes a user to a moderator. The target may be specified via reply, username, or ID.', doc = 'Promotes a user to a moderator. The target may be specified via reply, username, or ID.',
action = function(self, msg, group) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
else else
@ -1001,15 +1005,15 @@ function administration.init_command(self_)
}, },
{ -- /demod { -- /demod
triggers = utilities.triggers(self_.info.username):t('demod', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('demod', true).table,
command = 'demod <user>', command = 'demod <user>',
privilege = 3, privilege = 3,
interior = true, interior = true,
doc = 'Demotes a moderator to a user. The target may be specified via reply, username, or ID.', doc = 'Demotes a moderator to a user. The target may be specified via reply, username, or ID.',
action = function(self, msg, group) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
else else
@ -1027,15 +1031,15 @@ function administration.init_command(self_)
}, },
{ -- /gov { -- /gov
triggers = utilities.triggers(self_.info.username):t('gov', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('gov', true).table,
command = 'gov <user>', command = 'gov <user>',
privilege = 4, privilege = 4,
interior = true, interior = true,
doc = 'Promotes a user to the governor. The current governor will be replaced. The target may be specified via reply, username, or ID.', doc = 'Promotes a user to the governor. The current governor will be replaced. The target may be specified via reply, username, or ID.',
action = function(self, msg, group) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
else else
@ -1049,22 +1053,22 @@ function administration.init_command(self_)
end end
if group.grouptype == 'supergroup' then if group.grouptype == 'supergroup' then
drua.channel_set_admin(msg.chat.id, target.id, 2) drua.channel_set_admin(msg.chat.id, target.id, 2)
administration.update_desc(self, msg.chat.id) administration.update_desc(self, msg.chat.id, config)
end end
end end
end end
}, },
{ -- /degov { -- /degov
triggers = utilities.triggers(self_.info.username):t('degov', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('degov', true).table,
command = 'degov <user>', command = 'degov <user>',
privilege = 4, privilege = 4,
interior = true, interior = true,
doc = 'Demotes the governor to a user. The administrator will become the new governor. The target may be specified via reply, username, or ID.', doc = 'Demotes the governor to a user. The administrator will become the new governor. The target may be specified via reply, username, or ID.',
action = function(self, msg, group) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
else else
@ -1076,22 +1080,22 @@ function administration.init_command(self_)
end end
if group.grouptype == 'supergroup' then if group.grouptype == 'supergroup' then
drua.channel_set_admin(msg.chat.id, target.id, 0) drua.channel_set_admin(msg.chat.id, target.id, 0)
administration.update_desc(self, msg.chat.id) administration.update_desc(self, msg.chat.id, config)
end end
end end
end end
}, },
{ -- /hammer { -- /hammer
triggers = utilities.triggers(self_.info.username):t('hammer', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('hammer', true).table,
command = 'hammer <user>', command = 'hammer <user>',
privilege = 4, privilege = 4,
interior = false, interior = false,
doc = 'Bans a user from all groups. The target may be specified via reply, username, or ID.', doc = 'Bans a user from all groups. The target may be specified via reply, username, or ID.',
action = function(self, msg, group) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
elseif target.rank > 3 then elseif target.rank > 3 then
@ -1099,7 +1103,7 @@ function administration.init_command(self_)
elseif self.database.blacklist[target.id_str] then elseif self.database.blacklist[target.id_str] then
utilities.send_reply(self, msg, target.name .. ' is already globally banned.') utilities.send_reply(self, msg, target.name .. ' is already globally banned.')
else else
administration.kick_user(self, msg.chat.id, target.id, 'hammered by '..msg.from.name) administration.kick_user(self, msg.chat.id, target.id, 'hammered by '..msg.from.name, config)
self.database.blacklist[target.id_str] = true self.database.blacklist[target.id_str] = true
for k,v in pairs(self.database.administration.groups) do for k,v in pairs(self.database.administration.groups) do
if not v.flags[6] then if not v.flags[6] then
@ -1119,15 +1123,15 @@ function administration.init_command(self_)
}, },
{ -- /unhammer { -- /unhammer
triggers = utilities.triggers(self_.info.username):t('unhammer', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('unhammer', true).table,
command = 'unhammer <user>', command = 'unhammer <user>',
privilege = 4, privilege = 4,
interior = false, interior = false,
doc = 'Removes a global ban. The target may be specified via reply, username, or ID.', doc = 'Removes a global ban. The target may be specified via reply, username, or ID.',
action = function(self, msg) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
elseif not self.database.blacklist[target.id_str] then elseif not self.database.blacklist[target.id_str] then
@ -1143,15 +1147,15 @@ function administration.init_command(self_)
}, },
{ -- /admin { -- /admin
triggers = utilities.triggers(self_.info.username):t('admin', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('admin', true).table,
command = 'admin <user>', command = 'admin <user>',
privilege = 5, privilege = 5,
interior = false, interior = false,
doc = 'Promotes a user to an administrator. The target may be specified via reply, username, or ID.', doc = 'Promotes a user to an administrator. The target may be specified via reply, username, or ID.',
action = function(self, msg, group) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
elseif target.rank >= 4 then elseif target.rank >= 4 then
@ -1170,15 +1174,15 @@ function administration.init_command(self_)
}, },
{ -- /deadmin { -- /deadmin
triggers = utilities.triggers(self_.info.username):t('deadmin', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('deadmin', true).table,
command = 'deadmin <user>', command = 'deadmin <user>',
privilege = 5, privilege = 5,
interior = false, interior = false,
doc = 'Demotes an administrator to a user. The target may be specified via reply, username, or ID.', doc = 'Demotes an administrator to a user. The target may be specified via reply, username, or ID.',
action = function(self, msg) action = function(self, msg, group, config)
local target = administration.get_target(self, msg) local target = administration.get_target(self, msg, config)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)
else else
@ -1198,14 +1202,14 @@ function administration.init_command(self_)
}, },
{ -- /gadd { -- /gadd
triggers = utilities.triggers(self_.info.username):t('gadd', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('gadd', true).table,
command = 'gadd [i] ...', command = 'gadd [i] ...',
privilege = 5, privilege = 5,
interior = false, interior = false,
doc = 'Adds a group to the administration system. Pass numbers as arguments to enable those flags immediately. For example, this would add the group and enable the unlisted flag, antibot, and antiflood:\n/gadd 1 4 5', doc = 'Adds a group to the administration system. Pass numbers as arguments to enable those flags immediately. For example, this would add the group and enable the unlisted flag, antibot, and antiflood:\n/gadd 1 4 5',
action = function(self, msg) action = function(self, msg, group, config)
if self.database.administration.groups[msg.chat.id_str] then if self.database.administration.groups[msg.chat.id_str] then
utilities.send_reply(self, msg, 'I am already administrating this group.') utilities.send_reply(self, msg, 'I am already administrating this group.')
else else
@ -1237,7 +1241,7 @@ function administration.init_command(self_)
autokicks = {}, autokicks = {},
autoban = 3 autoban = 3
} }
administration.update_desc(self, msg.chat.id) administration.update_desc(self, msg.chat.id, config)
table.insert(self.database.administration.activity, msg.chat.id_str) table.insert(self.database.administration.activity, msg.chat.id_str)
utilities.send_reply(self, msg, 'I am now administrating this group.') utilities.send_reply(self, msg, 'I am now administrating this group.')
drua.channel_set_admin(msg.chat.id, self.info.id, 2) drua.channel_set_admin(msg.chat.id, self.info.id, 2)
@ -1246,14 +1250,14 @@ function administration.init_command(self_)
}, },
{ -- /grem { -- /grem
triggers = utilities.triggers(self_.info.username):t('grem', true):t('gremove', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('grem', true):t('gremove', true).table,
command = 'gremove \\[chat]', command = 'gremove \\[chat]',
privilege = 5, privilege = 5,
interior = false, interior = false,
doc = 'Removes a group from the administration system.', doc = 'Removes a group from the administration system.',
action = function(self, msg) action = function(self, msg, group, config)
local input = utilities.input(msg.text) or msg.chat.id_str local input = utilities.input(msg.text) or msg.chat.id_str
local output local output
if self.database.administration.groups[input] then if self.database.administration.groups[input] then
@ -1277,14 +1281,14 @@ function administration.init_command(self_)
}, },
{ -- /glist { -- /glist
triggers = utilities.triggers(self_.info.username):t('glist', false).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('glist', false).table,
command = 'glist', command = 'glist',
privilege = 5, privilege = 5,
interior = false, interior = false,
doc = 'Returns a list (in a private message) of all administrated groups with their governors and links.', doc = 'Returns a list (in a private message) of all administrated groups with their governors and links.',
action = function(self, msg) action = function(self, msg, group, config)
local output = '' local output = ''
if utilities.table_size(self.database.administration.groups) > 0 then if utilities.table_size(self.database.administration.groups) > 0 then
for k,v in pairs(self.database.administration.groups) do for k,v in pairs(self.database.administration.groups) do
@ -1306,14 +1310,14 @@ function administration.init_command(self_)
}, },
{ -- /broadcast { -- /broadcast
triggers = utilities.triggers(self_.info.username):t('broadcast', true).table, triggers = utilities.triggers(self_.info.username, config.cmd_pat):t('broadcast', true).table,
command = 'broadcast <message>', command = 'broadcast <message>',
privilege = 5, privilege = 5,
interior = false, interior = false,
doc = 'Broadcasts a message to all administrated groups.', doc = 'Broadcasts a message to all administrated groups.',
action = function(self, msg) action = function(self, msg, group, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
utilities.send_reply(self, msg, 'Give me something to broadcast.') utilities.send_reply(self, msg, 'Give me something to broadcast.')
@ -1357,17 +1361,17 @@ function administration.init_command(self_)
end end
end end
function administration:action(msg) function administration:action(msg, config)
for _,command in ipairs(administration.commands) do for _,command in ipairs(administration.commands) do
for _,trigger in pairs(command.triggers) do for _,trigger in pairs(command.triggers) do
if msg.text_lower:match(trigger) then if msg.text_lower:match(trigger) then
if command.interior and not self.database.administration.groups[msg.chat.id_str] then if command.interior and not self.database.administration.groups[msg.chat.id_str] then
break break
end end
if administration.get_rank(self, msg.from.id, msg.chat.id) < command.privilege then if administration.get_rank(self, msg.from.id, msg.chat.id, config) < command.privilege then
break break
end end
local res = command.action(self, msg, self.database.administration.groups[msg.chat.id_str]) local res = command.action(self, msg, self.database.administration.groups[msg.chat.id_str], config)
if res ~= true then if res ~= true then
return res return res
end end
@ -1388,6 +1392,5 @@ function administration:cron()
end end
administration.command = 'groups' administration.command = 'groups'
administration.doc = '`Returns a list of administrated groups.\nUse /ahelp for more administrative commands.`'
return administration return administration

View File

@ -8,33 +8,33 @@ local URL = require('socket.url')
local utilities = require('utilities') local utilities = require('utilities')
apod.command = 'apod [date]' apod.command = 'apod [date]'
apod.doc = [[```
/apod [query] function apod:init(config)
apod.triggers = utilities.triggers(self.info.username, config.cmd_pat)
:t('apod', true):t('apodhd', true):t('apodtext', true).table
apod.doc = [[```
]]..config.cmd_pat..[[apod [query]
Returns the Astronomy Picture of the Day. Returns the Astronomy Picture of the Day.
If the query is a date, in the format YYYY-MM-DD, the APOD of that day is returned. If the query is a date, in the format YYYY-MM-DD, the APOD of that day is returned.
/apodhd [query] ]]..config.cmd_pat..[[apodhd [query]
Returns the image in HD, if available. Returns the image in HD, if available.
/apodtext [query] ]]..config.cmd_pat..[[apodtext [query]
Returns the explanation of the APOD. Returns the explanation of the APOD.
Source: nasa.gov Source: nasa.gov
```]] ```]]
function apod:init()
apod.triggers = utilities.triggers(self.info.username)
:t('apod', true):t('apodhd', true):t('apodtext', true).table
end end
function apod:action(msg) function apod:action(msg, config)
if not self.config.nasa_api_key then if not config.nasa_api_key then
self.config.nasa_api_key = 'DEMO_KEY' config.nasa_api_key = 'DEMO_KEY'
end end
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
local date = '*' local date = '*'
local disable_page_preview = false local disable_page_preview = false
local url = 'https://api.nasa.gov/planetary/apod?api_key=' .. self.config.nasa_api_key local url = 'https://api.nasa.gov/planetary/apod?api_key=' .. config.nasa_api_key
if input then if input then
if input:match('(%d+)%-(%d+)%-(%d+)$') then if input:match('(%d+)%-(%d+)%-(%d+)$') then
@ -52,26 +52,26 @@ function apod:action(msg)
local jstr, res = HTTPS.request(url) local jstr, res = HTTPS.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)
if jdat.error then if jdat.error then
utilities.send_reply(msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
end end
local img_url = jdat.url local img_url = jdat.url
if string.match(msg.text, '^/apodhd*') then if string.match(msg.text, '^'..config.cmd_pat..'apodhd*') then
img_url = jdat.hdurl or jdat.url img_url = jdat.hdurl or jdat.url
end end
local output = date .. '[' .. jdat.title .. '](' .. img_url .. ')' local output = date .. '[' .. jdat.title .. '](' .. img_url .. ')'
if string.match(msg.text, '^/apodtext*') then if string.match(msg.text, '^'..config.cmd_pat..'apodtext*') then
output = output .. '\n' .. jdat.explanation output = output .. '\n' .. jdat.explanation
disable_page_preview = true disable_page_preview = true
end end

View File

@ -3,13 +3,13 @@ local bandersnatch = {}
local utilities = require('utilities') local utilities = require('utilities')
bandersnatch.command = 'bandersnatch' bandersnatch.command = 'bandersnatch'
bandersnatch.doc = [[```
Shun the frumious Bandersnatch.
Alias: /bc
```]]
function bandersnatch:init() function bandersnatch:init(config)
bandersnatch.triggers = utilities.triggers(self.info.username):t('bandersnatch'):t('bc').table bandersnatch.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('bandersnatch'):t('bc').table
bandersnatch.doc = [[```
Shun the frumious Bandersnatch.
Alias: ]]..config.cmd_pat..[[bc
```]]
end end
local fullnames = { "Wimbledon Tennismatch", "Rinkydink Curdlesnoot", "Butawhiteboy Cantbekhan", "Benadryl Claritin", "Bombadil Rivendell", "Wanda's Crotchfruit", "Biblical Concubine", "Syphilis Cankersore", "Buckminster Fullerene", "Bourgeoisie Capitalist" } local fullnames = { "Wimbledon Tennismatch", "Rinkydink Curdlesnoot", "Butawhiteboy Cantbekhan", "Benadryl Claritin", "Bombadil Rivendell", "Wanda's Crotchfruit", "Biblical Concubine", "Syphilis Cankersore", "Buckminster Fullerene", "Bourgeoisie Capitalist" }

View File

@ -4,24 +4,24 @@ local HTTP = require('socket.http')
local URL = require('socket.url') local URL = require('socket.url')
local utilities = require('utilities') local utilities = require('utilities')
function bible:init() function bible:init(config)
if not self.config.biblia_api_key then if not config.biblia_api_key then
print('Missing config value: biblia_api_key.') print('Missing config value: biblia_api_key.')
print('bible.lua will not be enabled.') print('bible.lua will not be enabled.')
return return
end end
bible.triggers = utilities.triggers(self.info.username):t('bible', true):t('b', true).table bible.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('bible', true):t('b', true).table
bible.doc = [[```
]]..config.cmd_pat..[[bible <reference>
Returns a verse from the American Standard Version of the Bible, or an apocryphal verse from the King James Version. Results from biblia.com.
Alias: ]]..config.cmd_pat..[[b
```]]
end end
bible.command = 'bible <reference>' bible.command = 'bible <reference>'
bible.doc = [[```
/bible <reference>
Returns a verse from the American Standard Version of the Bible, or an apocryphal verse from the King James Version. Results from biblia.com.
Alias: /b
```]]
function bible:action(msg) function bible:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -29,17 +29,17 @@ function bible:action(msg)
return return
end end
local url = 'http://api.biblia.com/v1/bible/content/ASV.txt?key=' .. self.config.biblia_api_key .. '&passage=' .. URL.escape(input) local url = 'http://api.biblia.com/v1/bible/content/ASV.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input)
local output, res = HTTP.request(url) local output, res = HTTP.request(url)
if not output or res ~= 200 or output:len() == 0 then if not output or res ~= 200 or output:len() == 0 then
url = 'http://api.biblia.com/v1/bible/content/KJVAPOC.txt?key=' .. self.config.biblia_api_key .. '&passage=' .. URL.escape(input) url = 'http://api.biblia.com/v1/bible/content/KJVAPOC.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input)
output, res = HTTP.request(url) output, res = HTTP.request(url)
end end
if not output or res ~= 200 or output:len() == 0 then if not output or res ~= 200 or output:len() == 0 then
output = self.config.errors.results output = config.errors.results
end end
if output:len() > 4000 then if output:len() > 4000 then

View File

@ -15,12 +15,12 @@ blacklist.triggers = {
'' ''
} }
function blacklist:action(msg) function blacklist:action(msg, config)
if self.database.blacklist[msg.from.id_str] then return end if self.database.blacklist[msg.from.id_str] then return end
if self.database.blacklist[msg.chat.id_str] then return end if self.database.blacklist[msg.chat.id_str] then return end
if not msg.text:match('^/blacklist') then return true end if not msg.text:match('^'..config.cmd_pat..'blacklist') then return true end
if msg.from.id ~= self.config.admin then return end if msg.from.id ~= config.admin then return end
local target = utilities.user_from_message(self, msg) local target = utilities.user_from_message(self, msg)
if target.err then if target.err then

View File

@ -5,16 +5,16 @@ local HTTPS = require('ssl.https')
local utilities = require('utilities') local utilities = require('utilities')
calc.command = 'calc <expression>' calc.command = 'calc <expression>'
calc.doc = [[```
/calc <expression> function calc:init(config)
calc.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('calc', true).table
calc.doc = [[```
]]..config.cmd_pat..[[calc <expression>
Returns solutions to mathematical expressions and conversions between common units. Results provided by mathjs.org. Returns solutions to mathematical expressions and conversions between common units. Results provided by mathjs.org.
```]] ```]]
function calc:init()
calc.triggers = utilities.triggers(self.info.username):t('calc', true).table
end end
function calc:action(msg) function calc:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -30,7 +30,7 @@ function calc:action(msg)
local output = HTTPS.request(url) local output = HTTPS.request(url)
if not output then if not output then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end

View File

@ -3,28 +3,28 @@ local cats = {}
local HTTP = require('socket.http') local HTTP = require('socket.http')
local utilities = require('utilities') local utilities = require('utilities')
function cats:init() function cats:init(config)
if not self.config.thecatapi_key then if not config.thecatapi_key then
print('Missing config value: thecatapi_key.') print('Missing config value: thecatapi_key.')
print('cats.lua will be enabled, but there are more features with a key.') print('cats.lua will be enabled, but there are more features with a key.')
end end
cats.triggers = utilities.triggers(self.info.username):t('cat').table cats.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('cat').table
end end
cats.command = 'cat' cats.command = 'cat'
cats.doc = '`Returns a cat!`' cats.doc = '`Returns a cat!`'
function cats:action(msg) function cats:action(msg, config)
local url = 'http://thecatapi.com/api/images/get?format=html&type=jpg' local url = 'http://thecatapi.com/api/images/get?format=html&type=jpg'
if self.config.thecatapi_key then if config.thecatapi_key then
url = url .. '&api_key=' .. self.config.thecatapi_key url = url .. '&api_key=' .. config.thecatapi_key
end end
local str, res = HTTP.request(url) local str, res = HTTP.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(msg, self.config.errors.connection) utilities.send_reply(self, msg, onfig.errors.connection)
return return
end end

View File

@ -6,10 +6,9 @@ local HTTP = require('socket.http')
local URL = require('socket.url') local URL = require('socket.url')
local JSON = require('dkjson') local JSON = require('dkjson')
local bindings = require('bindings') local bindings = require('bindings')
local utilities = require('utilities')
function chatter:init() function chatter:init(config)
if not self.config.simsimi_key then if not config.simsimi_key then
print('Missing config value: simsimi_key.') print('Missing config value: simsimi_key.')
print('chatter.lua will not be enabled.') print('chatter.lua will not be enabled.')
return return
@ -22,7 +21,7 @@ end
chatter.base_url = 'http://%sapi.simsimi.com/request.p?key=%s&lc=%s&ft=1.0&text=%s' chatter.base_url = 'http://%sapi.simsimi.com/request.p?key=%s&lc=%s&ft=1.0&text=%s'
function chatter:action(msg) function chatter:action(msg, config)
if msg.text == '' then return true end if msg.text == '' then return true end
@ -34,7 +33,7 @@ function chatter:action(msg)
--Uncomment the following line for Al Gore-like conversation. --Uncomment the following line for Al Gore-like conversation.
--or (msg.reply_to_message and msg.reply_to_message.from.id == self.info.id) --or (msg.reply_to_message and msg.reply_to_message.from.id == self.info.id)
) )
or msg.text:match('^/') or msg.text:match('^'..config.CMD_PAT)
or msg.text == '' or msg.text == ''
) then ) then
return true return true
@ -47,17 +46,17 @@ function chatter:action(msg)
local sandbox = self.config.simsimi_trial and 'sandbox.' or '' local sandbox = self.config.simsimi_trial and 'sandbox.' or ''
local url = chatter.base_url:format(sandbox, self.config.simsimi_key, self.config.lang, URL.escape(input)) local url = chatter.base_url:format(sandbox, config.simsimi_key, self.config.lang, URL.escape(input))
local jstr, res = HTTP.request(url) local jstr, res = HTTP.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_message(self, msg.chat.id, self.config.errors.chatter_connection) utilities.send_message(self, msg.chat.id, config.errors.chatter_connection)
return return
end end
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)
if not jdat.response or jdat.response:match('^I HAVE NO RESPONSE.') then if not jdat.response or jdat.response:match('^I HAVE NO RESPONSE.') then
utilities.send_message(self, msg.chat.id, self.config.errors.chatter_response) utilities.send_message(self, msg.chat.id, config.errors.chatter_response)
return return
end end
local output = jdat.response local output = jdat.response

View File

@ -7,8 +7,8 @@ local utilities = require('utilities')
commit.command = 'commit' commit.command = 'commit'
commit.doc = '`Returns a commit message from whatthecommit.com.`' commit.doc = '`Returns a commit message from whatthecommit.com.`'
function commit:init() function commit:init(config)
commit.triggers = utilities.triggers(self.info.username):t('commit').table commit.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('commit').table
end end
local commits = { local commits = {

View File

@ -3,37 +3,43 @@ local control = {}
local bot = require('bot') local bot = require('bot')
local utilities = require('utilities') local utilities = require('utilities')
function control:init() local cmd_pat -- Prevents the command from being uncallable.
control.triggers = utilities.triggers(self.info.username):t('reload'):t('halt').table
table.insert(control.triggers, '^/script') function control:init(config)
cmd_pat = config.cmd_pat
control.triggers = utilities.triggers(self.info.username, cmd_pat,
{'^'..cmd_pat..'script'}):t('reload', true):t('halt').table
end end
function control:action(msg) function control:action(msg, config)
if msg.from.id ~= self.config.admin then if msg.from.id ~= config.admin then
return return
end end
if msg.date < os.time() - 1 then return end if msg.date < os.time() - 1 then return end
if msg.text:match('^'..utilities.INVOCATION_PATTERN..'reload') then if msg.text_lower:match('^'..cmd_pat..'reload') then
for pac, _ in pairs(package.loaded) do for pac, _ in pairs(package.loaded) do
if pac:match('^plugins%.') then if pac:match('^plugins%.') then
package.loaded[pac] = nil package.loaded[pac] = nil
end end
end
package.loaded['bindings'] = nil package.loaded['bindings'] = nil
package.loaded['utilities'] = nil package.loaded['utilities'] = nil
package.loaded['config'] = nil package.loaded['config'] = nil
end if msg.text_lower:match('%+config') then for k, v in pairs(require('config')) do
bot.init(self) config[k] = v
end end
bot.init(self, config)
utilities.send_reply(self, msg, 'Bot reloaded!') utilities.send_reply(self, msg, 'Bot reloaded!')
elseif msg.text:match('^'..utilities.INVOCATION_PATTERN..'halt') then elseif msg.text_lower:match('^'..cmd_pat..'halt') then
self.is_started = false self.is_started = false
utilities.send_reply(self, msg, 'Stopping bot!') utilities.send_reply(self, msg, 'Stopping bot!')
elseif msg.text:match('^'..utilities.INVOCATION_PATTERN..'script') then elseif msg.text_lower:match('^'..cmd_pat..'script') then
local input = msg.text:match('^'..utilities.INVOCATION_PATTERN..'script\n(.+)') local input = msg.text_lower:match('^'..cmd_pat..'script\n(.+)')
if not input then if not input then
utilities.send_reply(self, msg, 'usage: ```\n/script\n/command <arg>\n...\n```', true) utilities.send_reply(self, msg, 'usage: ```\n'..cmd_pat..'script\n'..cmd_pat..'command <arg>\n...\n```', true)
return return
end end
input = input .. '\n' input = input .. '\n'

View File

@ -4,18 +4,18 @@ local HTTPS = require('ssl.https')
local utilities = require('utilities') local utilities = require('utilities')
currency.command = 'cash [amount] <from> to <to>' currency.command = 'cash [amount] <from> to <to>'
currency.doc = [[```
/cash [amount] <from> to <to> function currency:init(config)
Example: /cash 5 USD to EUR currency.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('cash', true).table
currency.doc = [[```
]]..config.cmd_pat..[[cash [amount] <from> to <to>
Example: ]]..config.cmd_pat..[[cash 5 USD to EUR
Returns exchange rates for various currencies. Returns exchange rates for various currencies.
Source: Google Finance. Source: Google Finance.
```]] ```]]
function currency:init()
currency.triggers = utilities.triggers(self.info.username):t('cash', true).table
end end
function currency:action(msg) function currency:action(msg, config)
local input = msg.text:upper() local input = msg.text:upper()
if not input:match('%a%a%a TO %a%a%a') then if not input:match('%a%a%a TO %a%a%a') then
@ -36,13 +36,13 @@ function currency:action(msg)
url = url .. '?from=' .. from .. '&to=' .. to .. '&a=' .. amount url = url .. '?from=' .. from .. '&to=' .. to .. '&a=' .. amount
local str, res = HTTPS.request(url) local str, res = HTTPS.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
str = str:match('<span class=bld>(.*) %u+</span>') str = str:match('<span class=bld>(.*) %u+</span>')
if not str then if not str then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
end end

View File

@ -3,13 +3,13 @@ local dice = {}
local utilities = require('utilities') local utilities = require('utilities')
dice.command = 'roll <nDr>' dice.command = 'roll <nDr>'
dice.doc = [[```
/roll <nDr> function dice:init(config)
dice.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('roll', true).table
dice.doc = [[```
]]..config.cmd_pat..[[roll <nDr>
Returns a set of dice rolls, where n is the number of rolls and r is the range. If only a range is given, returns only one roll. Returns a set of dice rolls, where n is the number of rolls and r is the range. If only a range is given, returns only one roll.
```]] ```]]
function dice:init()
dice.triggers = utilities.triggers(self.info.username):t('roll', true).table
end end
function dice:action(msg) function dice:action(msg)

View File

@ -6,18 +6,18 @@ local bindings = require('bindings')
local utilities = require('utilities') local utilities = require('utilities')
dilbert.command = 'dilbert [date]' dilbert.command = 'dilbert [date]'
dilbert.doc = [[```
/dilbert [YYYY-MM-DD] function dilbert:init(config)
dilbert.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('dilbert', true).table
dilbert.doc = [[```
]]..config.cmd_pat..[[dilbert [YYYY-MM-DD]
Returns the latest Dilbert strip or that of the provided date. Returns the latest Dilbert strip or that of the provided date.
Dates before the first strip will return the first strip. Dates after the last trip will return the last strip. Dates before the first strip will return the first strip. Dates after the last trip will return the last strip.
Source: dilbert.com Source: dilbert.com
```]] ```]]
function dilbert:init()
dilbert.triggers = utilities.triggers(self.info.username):t('dilbert', true).table
end end
function dilbert:action(msg) function dilbert:action(msg, config)
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'upload_photo' } ) bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'upload_photo' } )
@ -28,7 +28,7 @@ function dilbert:action(msg)
local url = 'http://dilbert.com/strip/' .. URL.escape(input) local url = 'http://dilbert.com/strip/' .. URL.escape(input)
local str, res = HTTP.request(url) local str, res = HTTP.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end

View File

@ -3,13 +3,13 @@ local echo = {}
local utilities = require('utilities') local utilities = require('utilities')
echo.command = 'echo <text>' echo.command = 'echo <text>'
echo.doc = [[```
/echo <text> function echo:init(config)
echo.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('echo', true).table
echo.doc = [[```
]]..config.cmd_pat..[[echo <text>
Repeats a string of text. Repeats a string of text.
```]] ```]]
function echo:init()
echo.triggers = utilities.triggers(self.info.username):t('echo', true).table
end end
function echo:action(msg) function echo:action(msg)

View File

@ -5,8 +5,9 @@ local utilities = require('utilities')
eightball.command = '8ball' eightball.command = '8ball'
eightball.doc = '`Returns an answer from a magic 8-ball!`' eightball.doc = '`Returns an answer from a magic 8-ball!`'
function eightball:init() function eightball:init(config)
eightball.triggers = utilities.triggers(self.info.username, {'[Yy]/[Nn]%p*$'}):t('8ball', true).table eightball.triggers = utilities.triggers(self.info.username, config.cmd_pat,
{'[Yy]/[Nn]%p*$'}):t('8ball', true).table
end end
local ball_answers = { local ball_answers = {

View File

@ -4,7 +4,7 @@ local fortune = {}
local utilities = require('utilities') local utilities = require('utilities')
function fortune:init() function fortune:init(config)
local s = io.popen('fortune'):read('*all') local s = io.popen('fortune'):read('*all')
if s:match('not found$') then if s:match('not found$') then
print('fortune is not installed on this computer.') print('fortune is not installed on this computer.')
@ -12,7 +12,7 @@ function fortune:init()
return return
end end
fortune.triggers = utilities.triggers(self.info.username):t('fortune').table fortune.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('fortune').table
end end
fortune.command = 'fortune' fortune.command = 'fortune'

View File

@ -8,28 +8,28 @@ local URL = require('socket.url')
local JSON = require('dkjson') local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
function gImages:init() function gImages:init(config)
if not self.config.google_api_key then if not config.google_api_key then
print('Missing config value: google_api_key.') print('Missing config value: google_api_key.')
print('gImages.lua will not be enabled.') print('gImages.lua will not be enabled.')
return return
elseif not self.config.google_cse_key then elseif not config.google_cse_key then
print('Missing config value: google_cse_key.') print('Missing config value: google_cse_key.')
print('gImages.lua will not be enabled.') print('gImages.lua will not be enabled.')
return return
end end
gImages.triggers = utilities.triggers(self.info.username):t('image', true):t('i', true):t('insfw', true).table gImages.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('image', true):t('i', true):t('insfw', true).table
gImages.doc = [[```
]]..config.cmd_pat..[[image <query>
Returns a randomized top result from Google Images. Safe search is enabled by default; use "]]..config.cmd_pat..[[insfw" to disable it. NSFW results will not display an image preview.
Alias: ]]..config.cmd_pat..[[i
```]]
end end
gImages.command = 'image <query>' gImages.command = 'image <query>'
gImages.doc = [[```
/image <query>
Returns a randomized top result from Google Images. Safe search is enabled by default; use "/insfw" to disable it. NSFW results will not display an image preview.
Alias: /i
```]]
function gImages:action(msg) function gImages:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -41,9 +41,9 @@ function gImages:action(msg)
end end
end end
local url = 'https://www.googleapis.com/customsearch/v1?&searchType=image&imgSize=xlarge&alt=json&num=8&start=1&key=' .. self.config.google_api_key .. '&cx=' .. self.config.google_cse_key local url = 'https://www.googleapis.com/customsearch/v1?&searchType=image&imgSize=xlarge&alt=json&num=8&start=1&key=' .. config.google_api_key .. '&cx=' .. config.google_cse_key
if not string.match(msg.text, '^/i[mage]*nsfw') then if not string.match(msg.text, '^'..config.cmd_pat..'i[mage]*nsfw') then
url = url .. '&safe=high' url = url .. '&safe=high'
end end
@ -51,13 +51,13 @@ function gImages:action(msg)
local jstr, res = HTTPS.request(url) local jstr, res = HTTPS.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)
if jdat.searchInformation.totalResults == '0' then if jdat.searchInformation.totalResults == '0' then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
end end

View File

@ -4,17 +4,17 @@ local bindings = require('bindings')
local utilities = require('utilities') local utilities = require('utilities')
gMaps.command = 'location <query>' gMaps.command = 'location <query>'
gMaps.doc = [[```
/location <query>
Returns a location from Google Maps.
Alias: /loc
```]]
function gMaps:init() function gMaps:init(config)
gMaps.triggers = utilities.triggers(self.info.username):t('location', true):t('loc', true).table gMaps.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('location', true):t('loc', true).table
gMaps.doc = [[```
]]..config.cmd_pat..[[location <query>
Returns a location from Google Maps.
Alias: ]]..config.cmd_pat..[[loc
```]]
end end
function gMaps:action(msg) function gMaps:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -26,7 +26,7 @@ function gMaps:action(msg)
end end
end end
local coords = utilities.get_coords(self, input) local coords = utilities.get_coords(input, config)
if type(coords) == 'string' then if type(coords) == 'string' then
utilities.send_reply(self, msg, coords) utilities.send_reply(self, msg, coords)
return return

View File

@ -6,17 +6,17 @@ local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
gSearch.command = 'google <query>' gSearch.command = 'google <query>'
gSearch.doc = [[```
/google <query>
Returns four (if group) or eight (if private message) results from Google. Safe search is enabled by default, use "/gnsfw" to disable it.
Alias: /g
```]]
function gSearch:init() function gSearch:init(config)
gSearch.triggers = utilities.triggers(self.info.username):t('g', true):t('google', true):t('gnsfw', true).table gSearch.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('g', true):t('google', true):t('gnsfw', true).table
gSearch.doc = [[```
]]..config.cmd_pat..[[google <query>
Returns four (if group) or eight (if private message) results from Google. Safe search is enabled by default, use "]]..config.cmd_pat..[[gnsfw" to disable it.
Alias: ]]..config.cmd_pat..[[g
```]]
end end
function gSearch:action(msg) function gSearch:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -36,7 +36,7 @@ function gSearch:action(msg)
url = url .. '&rsz=4' url = url .. '&rsz=4'
end end
if not string.match(msg.text, '^/g[oogle]*nsfw') then if not string.match(msg.text, '^'..config.cmd_pat..'g[oogle]*nsfw') then
url = url .. '&safe=active' url = url .. '&safe=active'
end end
@ -44,17 +44,17 @@ function gSearch:action(msg)
local jstr, res = HTTPS.request(url) local jstr, res = HTTPS.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)
if not jdat.responseData then if not jdat.responseData then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
if not jdat.responseData.results[1] then if not jdat.responseData.results[1] then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
end end

View File

@ -6,9 +6,8 @@ local greetings = {}
local utilities = require('utilities') local utilities = require('utilities')
function greetings:init() function greetings:init(config)
if not self.config.greetings then config.greetings = config.greetings or {
self.config.greetings = {
['Hello, #NAME.'] = { ['Hello, #NAME.'] = {
'hello', 'hello',
'hey', 'hey',
@ -34,18 +33,17 @@ function greetings:init()
'thank you' 'thank you'
} }
} }
end
greetings.triggers = { greetings.triggers = {
self.info.first_name:lower() .. '%p*$' self.info.first_name:lower() .. '%p*$'
} }
end end
function greetings:action(msg) function greetings:action(msg, config)
local nick = self.database.users[msg.from.id_str].nickname or msg.from.first_name local nick = self.database.users[msg.from.id_str].nickname or msg.from.first_name
for trigger,responses in pairs(self.config.greetings) do for trigger,responses in pairs(config.greetings) do
for _,response in pairs(responses) do for _,response in pairs(responses) do
if msg.text_lower:match(response..',? '..self.info.first_name:lower()) then if msg.text_lower:match(response..',? '..self.info.first_name:lower()) then
utilities.send_message(self, msg.chat.id, utilities.latcyr(trigger:gsub('#NAME', nick))) utilities.send_message(self, msg.chat.id, utilities.latcyr(trigger:gsub('#NAME', nick)))

View File

@ -6,22 +6,22 @@ local bindings = require('bindings')
local utilities = require('utilities') local utilities = require('utilities')
hackernews.command = 'hackernews' hackernews.command = 'hackernews'
hackernews.doc = [[```
Returns four (if group) or eight (if private message) top stories from Hacker News.
Alias: /hn
```]]
function hackernews:init() function hackernews:init(config)
hackernews.triggers = utilities.triggers(self.info.username):t('hackernews', true):t('hn', true).table hackernews.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hackernews', true):t('hn', true).table
hackernews.doc = [[```
Returns four (if group) or eight (if private message) top stories from Hacker News.
Alias: ]]..config.cmd_pat..[[hn
```]]
end end
function hackernews:action(msg) function hackernews:action(msg, config)
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' } ) bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' } )
local jstr, res = HTTPS.request('https://hacker-news.firebaseio.com/v0/topstories.json') local jstr, res = HTTPS.request('https://hacker-news.firebaseio.com/v0/topstories.json')
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
@ -37,7 +37,7 @@ function hackernews:action(msg)
local res_url = 'https://hacker-news.firebaseio.com/v0/item/' .. jdat[i] .. '.json' local res_url = 'https://hacker-news.firebaseio.com/v0/item/' .. jdat[i] .. '.json'
jstr, res = HTTPS.request(res_url) jstr, res = HTTPS.request(res_url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local res_jdat = JSON.decode(jstr) local res_jdat = JSON.decode(jstr)
@ -47,7 +47,7 @@ function hackernews:action(msg)
end end
local url = res_jdat.url local url = res_jdat.url
if not url then if not url then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
if url:find('%(') then if url:find('%(') then

View File

@ -6,7 +6,7 @@ local hearthstone = {}
local JSON = require('dkjson') local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
function hearthstone:init() function hearthstone:init(config)
if not self.database.hearthstone or os.time() > self.database.hearthstone.expiration then if not self.database.hearthstone or os.time() > self.database.hearthstone.expiration then
print('Downloading Hearthstone database...') print('Downloading Hearthstone database...')
@ -36,15 +36,15 @@ function hearthstone:init()
end end
hearthstone.triggers = utilities.triggers(self.info.username):t('hearthstone', true):t('hs').table hearthstone.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hearthstone', true):t('hs').table
hearthstone.doc = [[```
]]..config.cmd_pat..[[hearthstone <query>
Returns Hearthstone card info.
Alias: ]]..config.cmd_pat..[[hs
```]]
end end
hearthstone.command = 'hearthstone <query>' hearthstone.command = 'hearthstone <query>'
hearthstone.doc = [[```
/hearthstone <query>
Returns Hearthstone card info.
Alias: /hs
```]]
local function format_card(card) local function format_card(card)
@ -102,7 +102,7 @@ local function format_card(card)
end end
function hearthstone:action(msg) function hearthstone:action(msg, config)
local input = utilities.input(msg.text_lower) local input = utilities.input(msg.text_lower)
if not input then if not input then
@ -119,7 +119,7 @@ function hearthstone:action(msg)
output = utilities.trim(output) output = utilities.trim(output)
if output:len() == 0 then if output:len() == 0 then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
end end

View File

@ -7,26 +7,26 @@ local utilities = require('utilities')
local help_text local help_text
function help:init() function help:init(config)
local commandlist = {} local commandlist = {}
help_text = '*Available commands:*\n/' help_text = '*Available commands:*\n'..config.cmd_pat
for _,plugin in ipairs(self.plugins) do for _,plugin in ipairs(self.plugins) do
if plugin.command then if plugin.command then
table.insert(commandlist, plugin.command) table.insert(commandlist, plugin.command)
--help_text = help_text .. '\n• /' .. plugin.command:gsub('%[', '\\[') --help_text = help_text .. '\n• '..config.cmd_pat .. plugin.command:gsub('%[', '\\[')
end end
end end
table.insert(commandlist, 'help [command]') table.insert(commandlist, 'help [command]')
table.sort(commandlist) table.sort(commandlist)
help_text = help_text .. table.concat(commandlist, '\n/') .. '\nArguments: <required> [optional]' help_text = help_text .. table.concat(commandlist, '\n'..config.cmd_pat) .. '\nArguments: <required> [optional]'
help_text = help_text:gsub('%[', '\\[') help_text = help_text:gsub('%[', '\\[')
help.triggers = utilities.triggers(self.info.username):t('help', true):t('h', true).table help.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('help', true):t('h', true).table
end end

View File

@ -6,16 +6,16 @@ local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
imdb.command = 'imdb <query>' imdb.command = 'imdb <query>'
imdb.doc = [[```
/imdb <query> function imdb:init(config)
imdb.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('imdb', true).table
imdb.doc = [[```
]]..config.cmd_pat..[[imdb <query>
Returns an IMDb entry. Returns an IMDb entry.
```]] ```]]
function imdb:init()
imdb.triggers = utilities.triggers(self.info.username):t('imdb', true).table
end end
function imdb:action(msg) function imdb:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -31,14 +31,14 @@ function imdb:action(msg)
local jstr, res = HTTP.request(url) local jstr, res = HTTP.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)
if jdat.Response ~= 'True' then if jdat.Response ~= 'True' then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
end end

View File

@ -8,33 +8,33 @@ local URL = require('socket.url')
local JSON = require('dkjson') local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
function lastfm:init() function lastfm:init(config)
if not self.config.lastfm_api_key then if not config.lastfm_api_key then
print('Missing config value: lastfm_api_key.') print('Missing config value: lastfm_api_key.')
print('lastfm.lua will not be enabled.') print('lastfm.lua will not be enabled.')
return return
end end
lastfm.triggers = utilities.triggers(self.info.username):t('lastfm', true):t('np', true):t('fmset', true).table lastfm.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lastfm', true):t('np', true):t('fmset', true).table
lastfm.doc = [[```
]]..config.cmd_pat..[[np [username]
Returns what you are or were last listening to. If you specify a username, info will be returned for that username.
]]..config.cmd_pat..[[fmset <username>
Sets your last.fm username. Otherwise, ]]..config.cmd_pat..[[np will use your Telegram username. Use "]]..config.cmd_pat..[[fmset --" to delete it.
```]]
end end
lastfm.command = 'lastfm' lastfm.command = 'lastfm'
lastfm.doc = [[```
/np [username]
Returns what you are or were last listening to. If you specify a username, info will be returned for that username.
/fmset <username> function lastfm:action(msg, config)
Sets your last.fm username. Otherwise, /np will use your Telegram username. Use "/fmset --" to delete it.
```]]
function lastfm:action(msg)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if string.match(msg.text, '^/lastfm') then if string.match(msg.text, '^'..config.cmd_pat..'lastfm') then
utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true) utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true)
return return
elseif string.match(msg.text, '^/fmset') then elseif string.match(msg.text, '^'..config.cmd_pat..'fmset') then
if not input then if not input then
utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true) utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true)
elseif input == '--' or input == utilities.char.em_dash then elseif input == '--' or input == utilities.char.em_dash then
@ -47,7 +47,7 @@ function lastfm:action(msg)
return return
end end
local url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key=' .. self.config.lastfm_api_key .. '&user=' local url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key=' .. config.lastfm_api_key .. '&user='
local username local username
local alert = '' local alert = ''
@ -57,10 +57,10 @@ function lastfm:action(msg)
username = self.database.users[msg.from.id_str].lastfm username = self.database.users[msg.from.id_str].lastfm
elseif msg.from.username then elseif msg.from.username then
username = msg.from.username username = msg.from.username
alert = '\n\nYour username has been set to ' .. username .. '.\nTo change it, use /fmset <username>.' alert = '\n\nYour username has been set to ' .. username .. '.\nTo change it, use '..config.cmd_pat..'fmset <username>.'
self.database.users[msg.from.id_str].lastfm = username self.database.users[msg.from.id_str].lastfm = username
else else
utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with /fmset.') utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with '..config.cmd_pat..'fmset.')
return return
end end
@ -72,13 +72,13 @@ function lastfm:action(msg)
jstr, res = HTTP.request(url) jstr, res = HTTP.request(url)
end) end)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)
if jdat.error then if jdat.error then
utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with /fmset.') utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with '..config.cmd_pat..'fmset.')
return return
end end

View File

@ -4,13 +4,13 @@ local utilities = require('utilities')
local URL = require('socket.url') local URL = require('socket.url')
local JSON = require('dkjson') local JSON = require('dkjson')
function luarun:init() function luarun:init(config)
luarun.triggers = utilities.triggers(self.info.username):t('lua', true):t('return', true).table luarun.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lua', true):t('return', true).table
end end
function luarun:action(msg) function luarun:action(msg, config)
if msg.from.id ~= self.config.admin then if msg.from.id ~= config.admin then
return true return true
end end
@ -20,7 +20,7 @@ function luarun:action(msg)
return return
end end
if msg.text_lower:match('^/return') then if msg.text_lower:match('^'..config.cmd_pat..'return') then
input = 'return ' .. input input = 'return ' .. input
end end
@ -32,8 +32,8 @@ function luarun:action(msg)
local URL = require('socket.url') local URL = require('socket.url')
local HTTP = require('socket.http') local HTTP = require('socket.http')
local HTTPS = require('ssl.https') local HTTPS = require('ssl.https')
return function (self, msg) ]] .. input .. [[ end return function (self, msg, config) ]] .. input .. [[ end
]] )()(self, msg) ]] )()(self, msg, config)
if output == nil then if output == nil then
output = 'Done!' output = 'Done!'
else else

View File

@ -2,15 +2,15 @@ local me = {}
local utilities = require('utilities') local utilities = require('utilities')
function me:init() function me:init(config)
me.triggers = utilities.triggers(self.info.username):t('me', true).table me.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('me', true).table
end end
function me:action(msg) function me:action(msg, config)
local target = self.database.users[msg.from.id_str] local target = self.database.users[msg.from.id_str]
if msg.from.id == self.config.admin and (msg.reply_to_message or utilities.input(msg.text)) then if msg.from.id == config.admin and (msg.reply_to_message or utilities.input(msg.text)) then
target = utilities.user_from_message(self, msg, true) target = utilities.user_from_message(self, msg, true)
if target.err then if target.err then
utilities.send_reply(self, msg, target.err) utilities.send_reply(self, msg, target.err)

View File

@ -3,20 +3,20 @@ local nick = {}
local utilities = require('utilities') local utilities = require('utilities')
nick.command = 'nick <nickname>' nick.command = 'nick <nickname>'
nick.doc = [[```
/nick <nickname>
Set your nickname. Use "/nick --" to delete it.
```]]
function nick:init() function nick:init(config)
nick.triggers = utilities.triggers(self.info.username):t('nick', true).table nick.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('nick', true).table
nick.doc = [[```
]]..config.cmd_pat..[[nick <nickname>
Set your nickname. Use "]]..config.cmd_pat..[[nick --" to delete it.
```]]
end end
function nick:action(msg) function nick:action(msg, config)
local target = msg.from local target = msg.from
if msg.from.id == self.config.admin and msg.reply_to_message then if msg.from.id == config.admin and msg.reply_to_message then
target = msg.reply_to_message.from target = msg.reply_to_message.from
target.id_str = tostring(target.id) target.id_str = tostring(target.id)
target.name = target.first_name target.name = target.first_name

View File

@ -4,12 +4,12 @@ local ping = {}
local utilities = require('utilities') local utilities = require('utilities')
function ping:init() function ping:init(config)
ping.triggers = utilities.triggers(self.info.username):t('ping'):t('annyong').table ping.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('ping'):t('annyong').table
end end
function ping:action(msg) function ping:action(msg, config)
local output = msg.text_lower:match('^/ping') and 'Pong!' or 'Annyong.' local output = msg.text_lower:match('^'..config.cmd_pat..'ping') and 'Pong!' or 'Annyong.'
utilities.send_message(self, msg.chat.id, output) utilities.send_message(self, msg.chat.id, output)
end end

View File

@ -6,17 +6,17 @@ local bindings = require('bindings')
local utilities = require('utilities') local utilities = require('utilities')
pokedex.command = 'pokedex <query>' pokedex.command = 'pokedex <query>'
pokedex.doc = [[```
/pokedex <query>
Returns a Pokedex entry from pokeapi.co.
Alias: /dex
```]]
function pokedex:init() function pokedex:init(config)
pokedex.triggers = utilities.triggers(self.info.username):t('pokedex', true):t('dex', true).table pokedex.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('pokedex', true):t('dex', true).table
pokedex.doc = [[```
]]..config.cmd_pat..[[pokedex <query>
Returns a Pokedex entry from pokeapi.co.
Alias: ]]..config.cmd_pat..[[dex
```]]
end end
function pokedex:action(msg) function pokedex:action(msg, config)
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' } ) bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' } )
@ -35,7 +35,7 @@ function pokedex:action(msg)
local dex_url = url .. '/api/v1/pokemon/' .. input local dex_url = url .. '/api/v1/pokemon/' .. input
local dex_jstr, res = HTTP.request(dex_url) local dex_jstr, res = HTTP.request(dex_url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
@ -44,7 +44,7 @@ function pokedex:action(msg)
local desc_url = url .. dex_jdat.descriptions[math.random(#dex_jdat.descriptions)].resource_uri local desc_url = url .. dex_jdat.descriptions[math.random(#dex_jdat.descriptions)].resource_uri
local desc_jstr, _ = HTTP.request(desc_url) local desc_jstr, _ = HTTP.request(desc_url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end

View File

@ -4,13 +4,13 @@ local HTTP = require('socket.http')
local utilities = require('utilities') local utilities = require('utilities')
preview.command = 'preview <link>' preview.command = 'preview <link>'
preview.doc = [[```
/preview <link> function preview:init(config)
preview.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('preview', true).table
preview.doc = [[```
]]..config.cmd_pat..[[preview <link>
Returns a full-message, "unlinked" preview. Returns a full-message, "unlinked" preview.
```]] ```]]
function preview:init()
preview.triggers = utilities.triggers(self.info.username):t('preview', true).table
end end
function preview:action(msg) function preview:action(msg)

View File

@ -5,8 +5,8 @@ local utilities = require('utilities')
pun.command = 'pun' pun.command = 'pun'
pun.doc = '`Returns a pun.`' pun.doc = '`Returns a pun.`'
function pun:init() function pun:init(config)
pun.triggers = utilities.triggers(self.info.username):t('pun').table pun.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('pun').table
end end
local puns = { local puns = {

View File

@ -25,24 +25,24 @@ local mapping = {
local help local help
function reactions:init() function reactions:init(config)
-- Generate a "help" message triggered by "/reactions". -- Generate a "help" message triggered by "/reactions".
help = 'Reactions:\n' help = 'Reactions:\n'
reactions.triggers = utilities.triggers(self.info.username):t('reactions').table reactions.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('reactions').table
for trigger,reaction in pairs(mapping) do for trigger,reaction in pairs(mapping) do
help = help .. '' .. utilities.INVOCATION_PATTERN .. trigger:gsub('.%?', '') .. ': ' .. reaction .. '\n' help = help .. '' .. config.cmd_pat .. trigger:gsub('.%?', '') .. ': ' .. reaction .. '\n'
table.insert(reactions.triggers, utilities.INVOCATION_PATTERN..trigger) table.insert(reactions.triggers, config.cmd_pat..trigger)
table.insert(reactions.triggers, utilities.INVOCATION_PATTERN..trigger..'@'..self.info.username:lower()) table.insert(reactions.triggers, config.cmd_pat..trigger..'@'..self.info.username:lower())
end end
end end
function reactions:action(msg) function reactions:action(msg, config)
if string.match(msg.text_lower, utilities.INVOCATION_PATTERN..'reactions') then if string.match(msg.text_lower, config.cmd_pat..'reactions') then
utilities.send_message(self, msg.chat.id, help) utilities.send_message(self, msg.chat.id, help)
return return
end end
for trigger,reaction in pairs(mapping) do for trigger,reaction in pairs(mapping) do
if string.match(msg.text_lower, utilities.INVOCATION_PATTERN..trigger) then if string.match(msg.text_lower, config.cmd_pat..trigger) then
utilities.send_message(self, msg.chat.id, reaction) utilities.send_message(self, msg.chat.id, reaction)
return return
end end

View File

@ -6,14 +6,14 @@ local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
reddit.command = 'reddit [r/subreddit | query]' reddit.command = 'reddit [r/subreddit | query]'
reddit.doc = [[```
/reddit [r/subreddit | query]
Returns the top posts or results for a given subreddit or query. If no argument is given, returns the top posts from r/all. Querying specific subreddits is not supported.
Aliases: /r, /r/subreddit
```]]
function reddit:init() function reddit:init(config)
reddit.triggers = utilities.triggers(self.info.username, {'^/r/'}):t('reddit', true):t('r', true):t('r/', true).table reddit.triggers = utilities.triggers(self.info.username, config.cmd_pat, {'^/r/'}):t('reddit', true):t('r', true):t('r/', true).table
reddit.doc = [[```
]]..config.cmd_pat..[[reddit [r/subreddit | query]
Returns the top posts or results for a given subreddit or query. If no argument is given, returns the top posts from r/all. Querying specific subreddits is not supported.
Aliases: ]]..config.cmd_pat..[[r, /r/subreddit
```]]
end end
local format_results = function(posts) local format_results = function(posts)
@ -39,7 +39,7 @@ reddit.subreddit_url = 'http://www.reddit.com/%s/.json?limit='
reddit.search_url = 'http://www.reddit.com/search.json?q=%s&limit=' reddit.search_url = 'http://www.reddit.com/search.json?q=%s&limit='
reddit.rall_url = 'http://www.reddit.com/.json?limit=' reddit.rall_url = 'http://www.reddit.com/.json?limit='
function reddit:action(msg) function reddit:action(msg, config)
-- Eight results in PM, four results elsewhere. -- Eight results in PM, four results elsewhere.
local limit = 4 local limit = 4
if msg.chat.type == 'private' then if msg.chat.type == 'private' then
@ -48,7 +48,7 @@ function reddit:action(msg)
local text = msg.text_lower local text = msg.text_lower
if text:match('^/r/.') then if text:match('^/r/.') then
-- Normalize input so this hack works easily. -- Normalize input so this hack works easily.
text = msg.text_lower:gsub('^/r/', '/r r/') text = msg.text_lower:gsub('^/r/', config.cmd_pat..'r r/')
end end
local input = utilities.input(text) local input = utilities.input(text)
local source, url local source, url
@ -69,11 +69,11 @@ function reddit:action(msg)
end end
local jstr, res = HTTP.request(url) local jstr, res = HTTP.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
else else
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)
if #jdat.data.children == 0 then if #jdat.data.children == 0 then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
else else
local output = format_results(jdat.data.children) local output = format_results(jdat.data.children)
output = source .. output output = source .. output

View File

@ -3,15 +3,15 @@ local remind = {}
local utilities = require('utilities') local utilities = require('utilities')
remind.command = 'remind <duration> <message>' remind.command = 'remind <duration> <message>'
remind.doc = [[```
/remind <duration> <message>
Repeats a message after a duration of time, in minutes.
```]]
function remind:init() function remind:init(config)
self.database.reminders = self.database.reminders or {} self.database.reminders = self.database.reminders or {}
remind.triggers = utilities.triggers(self.info.username):t('remind', true).table remind.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('remind', true).table
remind.doc = [[```
]]..config.cmd_pat..[[remind <duration> <message>
Repeats a message after a duration of time, in minutes.
```]]
end end
function remind:action(msg) function remind:action(msg)

View File

@ -2,26 +2,25 @@ local setandget = {}
local utilities = require('utilities') local utilities = require('utilities')
function setandget:init() function setandget:init(config)
self.database.setandget = self.database.setandget or {} self.database.setandget = self.database.setandget or {}
setandget.triggers = utilities.triggers(self.info.username):t('set', true):t('get', true).table setandget.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('set', true):t('get', true).table
setandget.doc = [[```
]]..config.cmd_pat..[[set <name> <value>
Stores a value with the given name. Use "]]..config.cmd_pat..[[set <name> --" to delete the stored value.
]]..config.cmd_pat..[[get [name]
Returns the stored value or a list of stored values.
```]]
end end
setandget.command = 'set <name> <value>' setandget.command = 'set <name> <value>'
setandget.doc = [[```
/set <name> <value>
Stores a value with the given name. Use "/set <name> --" to delete the stored value.
/get [name]
Returns the stored value or a list of stored values.
```]]
function setandget:action(msg, config)
function setandget:action(msg)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
self.database.setandget[msg.chat.id_str] = self.database.setandget[msg.chat.id_str] or {} self.database.setandget[msg.chat.id_str] = self.database.setandget[msg.chat.id_str] or {}
if msg.text_lower:match('^/set') then if msg.text_lower:match('^'..config.cmd_pat..'set') then
if not input then if not input then
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true) utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
@ -41,7 +40,7 @@ function setandget:action(msg)
utilities.send_message(self, msg.chat.id, '"' .. name .. '" has been set to "' .. value .. '".', true) utilities.send_message(self, msg.chat.id, '"' .. name .. '" has been set to "' .. value .. '".', true)
end end
elseif msg.text_lower:match('^/get') then elseif msg.text_lower:match('^'..config.cmd_pat..'get') then
if not input then if not input then
local output local output

View File

@ -2,13 +2,13 @@ local shell = {}
local utilities = require('utilities') local utilities = require('utilities')
function shell:init() function shell:init(config)
shell.triggers = utilities.triggers(self.info.username):t('run', true).table shell.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('run', true).table
end end
function shell:action(msg) function shell:action(msg, config)
if msg.from.id ~= self.config.admin then if msg.from.id ~= config.admin then
return return
end end

View File

@ -3,13 +3,13 @@ local shout = {}
local utilities = require('utilities') local utilities = require('utilities')
shout.command = 'shout <text>' shout.command = 'shout <text>'
shout.doc = [[```
/shout <text> function shout:init(config)
shout.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('shout', true).table
shout.doc = [[```
]]..config.CMD_PAT..[[shout <text>
Shouts something. Input may be the replied-to message. Shouts something. Input may be the replied-to message.
```]] ```]]
function shout:init()
shout.triggers = utilities.triggers(self.info.username):t('shout', true).table
end end
function shout:action(msg) function shout:action(msg)

View File

@ -3,13 +3,13 @@ local slap = {}
local utilities = require('utilities') local utilities = require('utilities')
slap.command = 'slap [target]' slap.command = 'slap [target]'
slap.doc = [[```
/slap [target] function slap:init(config)
slap.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('slap', true).table
slap.doc = [[```
]]..config.cmd_pat..[[slap [target]
Slap somebody. Slap somebody.
```]] ```]]
function slap:init()
slap.triggers = utilities.triggers(self.info.username):t('slap', true).table
end end
local slaps = { local slaps = {

View File

@ -5,16 +5,16 @@ local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
time.command = 'time <location>' time.command = 'time <location>'
time.doc = [[```
/time <location> function time:init(config)
time.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('time', true).table
time.doc = [[```
]]..config.cmd_pat..[[time <location>
Returns the time, date, and timezone for the given location. Returns the time, date, and timezone for the given location.
```]] ```]]
function time:init()
time.triggers = utilities.triggers(self.info.username):t('time', true).table
end end
function time:action(msg) function time:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -26,7 +26,7 @@ function time:action(msg)
end end
end end
local coords = utilities.get_coords(self, input) local coords = utilities.get_coords(input, config)
if type(coords) == 'string' then if type(coords) == 'string' then
utilities.send_reply(self, msg, coords) utilities.send_reply(self, msg, coords)
return return
@ -39,7 +39,7 @@ function time:action(msg)
local jstr, res = HTTPS.request(url) local jstr, res = HTTPS.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end

View File

@ -6,16 +6,16 @@ local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
translate.command = 'translate [text]' translate.command = 'translate [text]'
translate.doc = [[```
/translate [text] function translate:init(config)
translate.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('translate', true):t('tl', true).table
translate.doc = [[```
]]..config.cmd_pat..[[translate [text]
Translates input or the replied-to message into the bot's language. Translates input or the replied-to message into the bot's language.
```]] ```]]
function translate:init()
translate.triggers = utilities.triggers(self.info.username):t('translate', true):t('tl', true).table
end end
function translate:action(msg) function translate:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -27,17 +27,17 @@ function translate:action(msg)
end end
end end
local url = 'https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. self.config.yandex_key .. '&lang=' .. self.config.lang .. '&text=' .. URL.escape(input) local url = 'https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. config.yandex_key .. '&lang=' .. config.lang .. '&text=' .. URL.escape(input)
local str, res = HTTPS.request(url) local str, res = HTTPS.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local jdat = JSON.decode(str) local jdat = JSON.decode(str)
if jdat.code ~= 200 then if jdat.code ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end

View File

@ -6,17 +6,18 @@ local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
urbandictionary.command = 'urbandictionary <query>' urbandictionary.command = 'urbandictionary <query>'
urbandictionary.doc = [[```
/urbandictionary <query>
Returns a definition from Urban Dictionary.
Aliases: /ud, /urban
```]]
function urbandictionary:init() function urbandictionary:init(config)
urbandictionary.triggers = utilities.triggers(self.info.username):t('urbandictionary', true):t('ud', true):t('urban', true).table urbandictionary.triggers = utilities.triggers(self.info.username, config.cmd_pat)
:t('urbandictionary', true):t('ud', true):t('urban', true).table
urbandictionary.doc = [[```
]]..config.cmd_pat..[[urbandictionary <query>
Returns a definition from Urban Dictionary.
Aliases: ]]..config.cmd_pat..[[ud, ]]..config.cmd_pat..[[urban
```]]
end end
function urbandictionary:action(msg) function urbandictionary:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -32,13 +33,13 @@ function urbandictionary:action(msg)
local jstr, res = HTTP.request(url) local jstr, res = HTTP.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)
if jdat.result_type == "no_results" then if jdat.result_type == "no_results" then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
end end

View File

@ -4,23 +4,23 @@ local HTTP = require('socket.http')
local JSON = require('dkjson') local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
function weather:init() function weather:init(config)
if not self.config.owm_api_key then if not config.owm_api_key then
print('Missing config value: owm_api_key.') print('Missing config value: owm_api_key.')
print('weather.lua will not be enabled.') print('weather.lua will not be enabled.')
return return
end end
weather.triggers = utilities.triggers(self.info.username):t('weather', true).table weather.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('weather', true).table
weather.doc = [[```
]]..config.cmd_pat..[[weather <location>
Returns the current weather conditions for a given location.
```]]
end end
weather.command = 'weather <location>' weather.command = 'weather <location>'
weather.doc = [[```
/weather <location>
Returns the current weather conditions for a given location.
```]]
function weather:action(msg) function weather:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -32,17 +32,17 @@ function weather:action(msg)
end end
end end
local coords = utilities.get_coords(self, input) local coords = utilities.get_coords(input, config)
if type(coords) == 'string' then if type(coords) == 'string' then
utilities.send_reply(self, msg, coords) utilities.send_reply(self, msg, coords)
return return
end end
local url = 'http://api.openweathermap.org/data/2.5/weather?APPID=' .. self.config.owm_api_key .. '&lat=' .. coords.lat .. '&lon=' .. coords.lon local url = 'http://api.openweathermap.org/data/2.5/weather?APPID=' .. config.owm_api_key .. '&lat=' .. coords.lat .. '&lon=' .. coords.lon
local jstr, res = HTTP.request(url) local jstr, res = HTTP.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end

View File

@ -3,13 +3,13 @@ local whoami = {}
local utilities = require('utilities') local utilities = require('utilities')
whoami.command = 'whoami' whoami.command = 'whoami'
whoami.doc = [[```
Returns user and chat info for you or the replied-to message.
Alias: /who
```]]
function whoami:init() function whoami:init(config)
whoami.triggers = utilities.triggers(self.info.username):t('who', true):t('whoami').table whoami.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('who', true):t('whoami').table
whoami.doc = [[```
Returns user and chat info for you or the replied-to message.
Alias: ]]..config.cmd_pat..[[who
```]]
end end
function whoami:action(msg) function whoami:action(msg)

View File

@ -6,14 +6,14 @@ local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
wikipedia.command = 'wikipedia <query>' wikipedia.command = 'wikipedia <query>'
wikipedia.doc = [[```
/wikipedia <query>
Returns an article from Wikipedia.
Aliases: /w, /wiki
```]]
function wikipedia:init() function wikipedia:init(config)
wikipedia.triggers = utilities.triggers(self.info.username):t('wikipedia', true):t('wiki', true):t('w', true).table wikipedia.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('wikipedia', true):t('wiki', true):t('w', true).table
wikipedia.doc = [[```
]]..config.cmd_pat..[[wikipedia <query>
Returns an article from Wikipedia.
Aliases: ]]..config.cmd_pat..[[w, ]]..config.cmd_pat..[[wiki
```]]
end end
local get_title = function(search) local get_title = function(search)
@ -25,7 +25,7 @@ local get_title = function(search)
return false return false
end end
function wikipedia:action(msg) function wikipedia:action(msg, config)
-- Get the query. If it's not in the message, check the replied-to message. -- Get the query. If it's not in the message, check the replied-to message.
-- If those don't exist, send the help text. -- If those don't exist, send the help text.
@ -50,19 +50,19 @@ function wikipedia:action(msg)
jstr, res = HTTPS.request(search_url .. URL.escape(input)) jstr, res = HTTPS.request(search_url .. URL.escape(input))
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
jdat = JSON.decode(jstr) jdat = JSON.decode(jstr)
if jdat.query.searchinfo.totalhits == 0 then if jdat.query.searchinfo.totalhits == 0 then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
end end
local title = get_title(jdat.query.search) local title = get_title(jdat.query.search)
if not title then if not title then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
end end
@ -70,7 +70,7 @@ function wikipedia:action(msg)
jstr, res = HTTPS.request(res_url .. URL.escape(title)) jstr, res = HTTPS.request(res_url .. URL.escape(title))
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
@ -78,7 +78,7 @@ function wikipedia:action(msg)
local text = JSON.decode(jstr).query.pages local text = JSON.decode(jstr).query.pages
_, text = next(text) _, text = next(text)
if not text then if not text then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
else else
text = text.extract text = text.extract

View File

@ -5,20 +5,20 @@ local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
xkcd.command = 'xkcd [i]' xkcd.command = 'xkcd [i]'
xkcd.doc = [[```
/xkcd [i] function xkcd:init(config)
xkcd.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('xkcd', true).table
xkcd.doc = [[```
]]..config.cmd_pat..[[xkcd [i]
Returns the latest xkcd strip and its alt text. If a number is given, returns that number strip. If "r" is passed in place of a number, returns a random strip. Returns the latest xkcd strip and its alt text. If a number is given, returns that number strip. If "r" is passed in place of a number, returns a random strip.
```]] ```]]
function xkcd:init()
xkcd.triggers = utilities.triggers(self.info.username):t('xkcd', true).table
end end
function xkcd:action(msg) function xkcd:action(msg, config)
local jstr, res = HTTP.request('http://xkcd.com/info.0.json') local jstr, res = HTTP.request('http://xkcd.com/info.0.json')
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local latest = JSON.decode(jstr).num local latest = JSON.decode(jstr).num
@ -44,7 +44,7 @@ function xkcd:action(msg)
jstr, res = HTTP.request(res_url) jstr, res = HTTP.request(res_url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)

View File

@ -7,24 +7,24 @@ local URL = require('socket.url')
local JSON = require('dkjson') local JSON = require('dkjson')
local utilities = require('utilities') local utilities = require('utilities')
function youtube:init() function youtube:init(config)
if not self.config.google_api_key then if not config.google_api_key then
print('Missing config value: google_api_key.') print('Missing config value: google_api_key.')
print('youtube.lua will not be enabled.') print('youtube.lua will not be enabled.')
return return
end end
youtube.triggers = utilities.triggers(self.info.username):t('youtube', true):t('yt', true).table youtube.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('youtube', true):t('yt', true).table
youtube.doc = [[```
]]..config.cmd_pat..[[youtube <query>
Returns the top result from YouTube.
Alias: ]]..config.cmd_pat..[[yt
```]]
end end
youtube.command = 'youtube <query>' youtube.command = 'youtube <query>'
youtube.doc = [[```
/youtube <query>
Returns the top result from YouTube.
Alias: /yt
```]]
function youtube:action(msg) function youtube:action(msg, config)
local input = utilities.input(msg.text) local input = utilities.input(msg.text)
if not input then if not input then
@ -36,17 +36,17 @@ function youtube:action(msg)
end end
end end
local url = 'https://www.googleapis.com/youtube/v3/search?key=' .. self.config.google_api_key .. '&type=video&part=snippet&maxResults=4&q=' .. URL.escape(input) local url = 'https://www.googleapis.com/youtube/v3/search?key=' .. config.google_api_key .. '&type=video&part=snippet&maxResults=4&q=' .. URL.escape(input)
local jstr, res = HTTPS.request(url) local jstr, res = HTTPS.request(url)
if res ~= 200 then if res ~= 200 then
utilities.send_reply(self, msg, self.config.errors.connection) utilities.send_reply(self, msg, config.errors.connection)
return return
end end
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)
if jdat.pageInfo.totalResults == 0 then if jdat.pageInfo.totalResults == 0 then
utilities.send_reply(self, msg, self.config.errors.results) utilities.send_reply(self, msg, config.errors.results)
return return
end end

View File

@ -137,18 +137,18 @@ function utilities.save_data(filename, data)
end end
-- Gets coordinates for a location. Used by gMaps.lua, time.lua, weather.lua. -- Gets coordinates for a location. Used by gMaps.lua, time.lua, weather.lua.
function utilities:get_coords(input) function utilities.get_coords(input, config)
local url = 'http://maps.googleapis.com/maps/api/geocode/json?address=' .. URL.escape(input) local url = 'http://maps.googleapis.com/maps/api/geocode/json?address=' .. URL.escape(input)
local jstr, res = HTTP.request(url) local jstr, res = HTTP.request(url)
if res ~= 200 then if res ~= 200 then
return self.config.errors.connection return config.errors.connection
end end
local jdat = JSON.decode(jstr) local jdat = JSON.decode(jstr)
if jdat.status == 'ZERO_RESULTS' then if jdat.status == 'ZERO_RESULTS' then
return self.config.errors.results return config.errors.results
end end
return { return {
@ -231,15 +231,15 @@ function utilities:user_from_message(msg, no_extra)
end end
function utilities:handle_exception(err, message) function utilities:handle_exception(err, message, config)
if not err then err = '' end if not err then err = '' end
local output = '\n[' .. os.date('%F %T', os.time()) .. ']\n' .. self.info.username .. ': ' .. err .. '\n' .. message .. '\n' local output = '\n[' .. os.date('%F %T', os.time()) .. ']\n' .. self.info.username .. ': ' .. err .. '\n' .. message .. '\n'
if self.config.log_chat then if config.log_chat then
output = '```' .. output .. '```' output = '```' .. output .. '```'
utilities.send_message(self, self.config.log_chat, output, true, nil, true) utilities.send_message(self, config.log_chat, output, true, nil, true)
else else
print(output) print(output)
end end
@ -281,24 +281,23 @@ end
utilities.md_escape = utilities.markdown_escape utilities.md_escape = utilities.markdown_escape
utilities.INVOCATION_PATTERN = '/'
utilities.triggers_meta = {} utilities.triggers_meta = {}
utilities.triggers_meta.__index = utilities.triggers_meta utilities.triggers_meta.__index = utilities.triggers_meta
function utilities.triggers_meta:t(pattern, has_args) function utilities.triggers_meta:t(pattern, has_args)
local username = self.username:lower() local username = self.username:lower()
table.insert(self.table, '^'..utilities.INVOCATION_PATTERN..pattern..'$') table.insert(self.table, '^'..self.cmd_pat..pattern..'$')
table.insert(self.table, '^'..utilities.INVOCATION_PATTERN..pattern..'@'..username..'$') table.insert(self.table, '^'..self.cmd_pat..pattern..'@'..username..'$')
if has_args then if has_args then
table.insert(self.table, '^'..utilities.INVOCATION_PATTERN..pattern..'%s+[^%s]*') table.insert(self.table, '^'..self.cmd_pat..pattern..'%s+[^%s]*')
table.insert(self.table, '^'..utilities.INVOCATION_PATTERN..pattern..'@'..username..'%s+[^%s]*') table.insert(self.table, '^'..self.cmd_pat..pattern..'@'..username..'%s+[^%s]*')
end end
return self return self
end end
function utilities.triggers(username, trigger_table) function utilities.triggers(username, cmd_pat, trigger_table)
local self = setmetatable({}, utilities.triggers_meta) local self = setmetatable({}, utilities.triggers_meta)
self.username = username self.username = username
self.cmd_pat = cmd_pat
self.table = trigger_table or {} self.table = trigger_table or {}
return self return self
end end