diff --git a/README.md b/README.md index 97dc010..82a3885 100755 --- a/README.md +++ b/README.md @@ -6,383 +6,150 @@ The public bot runs on [@mokubot](https://telegram.me/mokubot). otouto is licensed under the GNU General Public License. A copy of the license has been included in [LICENSE](https://github.com/topkecleon/otouto/blob/master/LICENSE). ##What is it? -otouto is an independently-developed Telegram API bot written in Lua. otouto was created in February 2015, open-sourced in June, and is being augmented to this day. +otouto is an independently developed Telegram API bot written in Lua. Originally conceived as a tg-cli script in February of 2015, otouto has since been migrated to the API, open-sourced, and it being developed to this day. -Bot commands and functions use a comprehensive plugin system, similar to that of (yagop's telegram-bot)[github.com/yagop/telegram-bot]. The aim of the project is to host every desirable feature in one bot. +otouto uses a robust plugin system, similar to that of yagop's [telegram-bot](github.com/yagop/telegram-bot). The aim of the project is to contain any desirable feature inside one universal bot. + +* * * ##Plugins -Below are listed many (but not all) of otouto's plugins. This list will be updated as more plugins are added. - -###**echo.lua** - ->**Command:** /echo <text> - ->**Function:** Repeats a string of text. - ->**Notes:** Replaces letters with corresponding characters from the Cyrillic alphabet. - -###**ping.lua** - ->**Command:** /ping - ->**Function:** The simplest plugin ever! - -###**gSearch.lua** - ->**Command:** /google [query] - ->**Function:** Returns four or eight Google results, depending on whether it is run in a group chat or a private message. - ->**Aliases:** /g, /gnsfw, /googlensfw - ->**Notes:** If "nsfw" is appended to the command, Safe Search will not be used. - -###**gImages.lua** - ->**Command:** /images [query] - ->**Function:** Returns a random top result from Google Image. - ->**Aliases:** /i, /gimages, /gnsfw - ->**Notes:** If "nsfw" is appended to the command, Safe Search and image preview will not be used. - -###**gMaps.lua** - ->**Command:** /location [query] - ->**Function:** Returns location data from Google Maps. - ->**Aliases:** /loc - -###**translate.lua** - ->**Command:** /translate [text] - ->**Function:** Translates the replied-to message or the given string to the configured language. - -###**youtube.lua** - ->**Command:** /youtube [query] - ->**Function:** Returns the top video result from YouTube. - ->**Aliases:** /yt - -###**wikipedia.lua** - ->**Command:** /wikipedia [query] - ->**Function:** Returns the top paragraph of and the link to a Wikipedia article. - ->**Aliases:** /wiki - -###**lastfm.lua** - ->**Command:** /lastfm - ->**Function**: Returns help for the last.fm actions. - ->**Actions**: - ->>**/np** [username] - ->>Returns the current- or last-played song for the given username. If no username is given, it will use your configured last.fm username or your Telegram username. - - ->>**/fmset** <username> - ->>Sets your last.fm username. Use /fmset - to delete it. - -###**hackernews.lua** - ->**Command:** /hackernews - ->**Function:** Returns the top four or eight headlines on Hacker News, depending on whether it is run in a group chat or private message. - ->**Aliases:** /hn - -###**imdb.lua** - ->**Command:** /imdb <query> - ->**Function:** Returns movie information from IMDb. - -###**calc.lua** - ->**Command:** /calc <expression> - ->**Function:** Returns solutions to mathematical expressions and conversions between common units. Results provided by mathjs.org. - -###**bible.lua** - ->**Command:** /bible <reference> - ->**Function:** Returns a Bible verse. Results provided by biblia.com - ->**Aliases:** /b - -###**urbandictionary.lua** - ->**Command:** /urbandictionary <query> - ->**Function:** Returns the top definition from Urban Dictionary. - ->**Aliases:** /ud, /urban - -###**time.lua** - ->**Command:** /time <query> - ->**Function:** Returns the time, date, and timezone for a given location. - -###**weather.lua** - ->**Command:** /weather <query> - ->**Function:** Returns the current weather conditions for a given location. - -###**nick.lua** - ->**Command:** /nick <nickname> - ->**Function:** Set your nickname. Use "/nick -" to delete it. - -###**whoami.lua** - ->**Command:** /whoami - ->**Function:** Returns user and chat info for your or the replied-to message. - -###**8ball.lua** - ->**Command:** /8ball - ->**Function:** Returns an answer from a magic 8-ball. - -###**dice.lua** - ->**Command:** /roll <nDr> - ->**Function:** Returns RNG dice rolls. Uses D&D notation. - ->**Examples:** - ->>/roll 4D20 - ->>/roll 6 - -###**reddit.lua** - ->**Command:** /reddit [r/subreddit | query] - ->**Function:** Returns the top four or eight results, depending on whether it is run in a group chat or private message, from a given subreddit, query, or r/all. - ->**Aliases:** /r - ->**Notes:** You may also get results for a subreddit by entering "/r/subreddit". - ->**Examples:** - ->> /reddit zelda - ->> /reddit r/gaming - ->>/r/talesfromtechsupport - -###**xkcd.lua** - ->**Command:** /xkcd [query] - ->**Function:** Returns an xkcd strip and it's alt text. If not query is given, it will use a random strip. - -###**slap.lua** - ->**Command:** /slap <target> - ->**Function:** Give someone a good slap (or worse). - -###**commit.lua** - ->**Command:** /commit - ->**Function:** Returns a commit message from whatthecommit.com. - -###**fortune.lua** - ->**Command:** /fortune - ->**Function:** Returns a UNIX fortune. - -###**pun.lua** - ->**Command:** /pun - ->**Function:** Returns a pun. - -###**pokedex.lua** - ->**Command:** /pokedex <query> - ->**Function:** Returns a Pokedex entry. - ->**Aliases:** /dex - -###**currency.lua** - ->**Command:** /cash [amount] <from> to <from> - ->**Function:** Converts an amount of one currency to another. - ->**Examples:** - ->>/cash 5 USD to EUR - ->>/cash BTC to GBP - -###**cats.lua** - ->**Command:** /cat - ->**Function:** Returns a cat pic. - -###**hearthstone.lua** - ->**Command:** /hearthstone <query> - ->**Function:** Returns Hearthstone card info. - ->**Aliases:** /hs - -###**admin.lua** - ->**Command:** /admin [command] - ->**Function:** Runs an admin command or returns a list of them. - ->**Notes:** Only usable by the configured admin. - -###**blacklist.lua** - ->**Command:** /blacklist [id] - ->**Function:** Blacklists or unblacklists the specified ID or replied-to user. - ->**Notes:** Only usable by the configured admin. +Here is a list of most otouto plugins. + +| Plugin | Command | Function | Alias | +|--------|---------|----------|-------| +| help.lua | /help | Returns a list of commands. | /h | +| about.lua | /about | Returns the about text as configured in config.lua. | +| ping.lua | /ping | The simplest plugin ever! | +| echo.lua | /echo | Repeats a string of text. | +| gSearch.lua | /google | Returns Google web results. | /g, /gnsfw | +| gImages.lua | /images | Returns a Google image result. | /i, /insfw | +| gMaps.lua | /location | Returns location data from Google Maps. | /loc | +| youtube.lua | /youtube | Returns the top video result from YouTube. | /yt | +| wikipedia.lua | /wikipedia | Returns the summary of a Wikipedia article. | /wiki | +| 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. | +| hackernews.lua | /hackernews | Returns the latest posts from Hacker News. | /hn | +| imdb.lua | /imdb | Returns film information from IMDb. | +| hearthstone.lua | /hearthstone | Returns data for Hearthstone cards matching the query. | /hs | +| calc.lua | /calc | Returns solutions to math expressions and conversions between common units. | +| bible.lua | /bible | Returns a Bible verse. | /b | +| urbandictionary.lua | /urbandictionary | Returns the top definition from Urban Dictionary. | /ud, /urban | +| time.lua | /time | Returns the time, date, and a timezone for a location. | +| weather.lua | /weather | Returns current weather conditions for a given location. | +| nick.lua | /nick | Set your nickname. /nick - will delete it. | +| 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. | +| dice.lua | /roll | Returns RNG dice rolls. Uses D&D notation. | +| reddit.lua | /reddit [r/subreddit \| query] | Returns the top results from a given subreddit, query, or r/all. | /r | +| xkcd.lua | /xkcd [query] | Returns an xkcd strip and its alt text. | +| slap.lua | /slap | Gives someone a slap (or worse). | +| commit.lua | /commit | Returns a commit message from whatthecommit.com. | +| fortune.lua | /fortune | Returns a UNIX fortune. | +| pun.lua | /pun | Returns a pun. | +| pokedex.lua | /pokedex | Returns a Pokedex entry. | /dex | +| currency.lua | /cash [amount] to | Converts one currency to another. | +| cats.lua | /cat | Returns a cat picture. | +| reactions.lua | /reactions | Returns a list of reaction emoticons which can be used through the bot. | +| control.lua | /reload | Reloads all plugins, libraries, and configuration files. | +| control.lua | /halt | Stops the bot. If the bot was run with launch.sh, this will restart it. | +| blacklist.lua | /blacklist | Blacklists or unblacklists a user, via reply or ID, from using your bot. | +| shell.lua | /shell | Runs a shell command and returns the output. Use with caution. | +| luarun.lua | /lua | Runs a string a Lua code and returns the output, if applicable. Use with caution. otouto does not use a sandbox. | + +* * * ##Liberbot Plugins -Some plugins are only useful when the bot is used in a Liberbot group: moderation.lua, antisquig.lua, floodcontrol.lua. +Some plugins are only useful when the bot is used in a Liberbot group, like floodcontrol.lua and moderation.lua. -floodcontrol.lua makes the bot compliant to Liberbot's bot floodcontrol. It should prevent your bot from being globally banned from Liberbot groups. +**floodcontrol.lua** makes the bot compliant with Liberbot's floodcontrol function. When the bot has posted too many messages to a single group in a given period of time, Liberbot will send it a message telling it to cease posting in that group. Here is an example floodcontrol command: -moderation.lua allows realm administrators to assign moderators for a group. This only works if the bot is made a realm administrator. +`/floodcontrol {"groupid":987654321,"duration":600}` -You must configure this plugin in the "moderation" section of config.lua, in the following way: +The bot will accept these commands from both Liberbot and the configured administrator. + +**moderation.lua** allows the owner to use the bot to moderate a Liberbot realm, or set of groups. This works by adding the bot to the realm's admin group and making it an administrator. + +You must configure the plugin in the "moderation" section of config.lua, in the following way: ``` moderation = { - admins = { - ['123456789'] = 'Adam', - ['1337420'] = 'Eve' - }, - admin_group = -8675309, - realm_name = 'My Realm' + admins = { + ['123456789'] = 'Adam', + ['246813579'] = 'Eve' + }, + admin_group = -987654321, + realm_name = 'My Realm' } ``` -Where Adam and Eve are realm administrators, and their IDs are set as the keys in the form of strings. admin_group is the ID, a negative number, of the realm administration group. realm_name is the name as a string. +Where Adam and Eve are realm administrators, and their IDs are set as their keys in the form of strings. admin_group is the group ID of the admin group, as a negative number. realm_name is the name of your Libebot realm. -Once this is set up, put the bot in the admin group and run /add and /modlist to get started. - -antisquig.lua is an extension to moderation.lua. It will automatically kick a user who posts Arabic script. - -##Other Plugins -There are other plugins not listed above: help.lua, about.lua, chatter.lua, greetings.lua. - -help.lua is self-explanatory. When the plugin loads, it compiles a list of commands, and will return them. - -about.lua returns the content of the about_text string in config.lua. - -chatter.lua will let the user interact with a chatterbot, if he replies to a message sent by the bot. - -greetings.lua is where things get tricky. It allows the bot to respond to several greetings with a preconfigured response. This is configured in the "greetings" section of config.lua: - -``` -greetings = { - ['Hello, #NAME.'] = { - 'hello', - 'hey', - 'hi' - }, - ['Goodbye, #NAME.'] = { - 'goodbye', - 'bye', - } -} -``` +Once this is set up, put your bot in the admin group and run /add and /modhelp to get started. Where the key is the preconfigured response (where #NAME will be replaced with the user's name or nickname) and the strings in the table are the expected greetings (followed by the bot's name and possible punctuation). +* * * + ##Setup -You **must** have Lua, lua-socket and lua-sec installed. For uploading photos and other files, you must have curl installed. The fortune.lua plugin requires that fortune is installed. +You **must** have Lua (5.2+), LuaSocket, and LuaSec installed. For uploading photos and other files, you must have curl installed. The fortune.lua plugin requires that fortune is installed. -For weather.lua, lastfm.lua, and bible.lua to work, you must have API keys for openweathermap.org, last.fm, and biblia.com, respectively. cats.lua uses an API key to get more results, though it is not required. +For weather.lua, lastfm.lua, and bible.lua to work, you must have API keys for [OpenWeatherMap](http://openweathermap.org), [last.fm](http://last.fm), and [Biblia.com](http://biblia.com), respectively. cats.lua uses an API key (via [The Cat API](http://thecatapi.com)) to get more results, though it is not required. -For gImages.lua to work, you must have a Google API key, a Google Custom Search Engine key, and have it configured to show image results. +**Before you do anything, open config.lua in a text editor and make the following changes:** ->**Before you do anything, edit config.lua and make the following changes:** - ->* Edit bot_api_key with your authentication token from Botfather. ->* Set admin as your Telegram ID as a number. +> • Set bot_api_key to the authentication token you received from the Botfather. +> +> • Set admin as your Telegram ID. You may also want to set your time_offset (a positive or negative number, in seconds, representing your computer's difference from UTC), your lang (lowercase, two-letter code representing your language), and modify your about_text. Some plugins will not be enabled by default, as they are for specific uses. If you want to use them, add them to the plugins table. -To start the bot, run +To start the bot, run `./launch.sh`. To stop the bot, press Ctrl+c twice. -`./launch.sh` +You may also start the bot with `lua bot.lua`, but then it will not restart automatically. -To stop the bot, press Ctrl+C twice. - -You may also start the bot manually with - -`lua bot.lua` - -though that will not cause it to automatically restart. +* * * ##Support -Do not contact me through private messages for support. +Do not attempt to contact any developer privately for support. You will be blocked and likely reported. -For otouto, bot, and other Lua support in general, join the Bot Development group. Send "/join 16314802" to [@Liberbot](https://telegram.me/liberbot). If this does not work the first time, you may need to send it up to seven more times, thanks to Telegram's automatic spam-prevention mechanism. +For support for otouto and bots in general, join my Bot Development group. Follow [this link](http://telegram.me/mokubot?start=glist) and follow the Bot Development link. + +* * * ##Development -Everyone is free to contribute to otouto. If you would like to write a plugin, here I will lay out various things that are important to know about the plugin system. +Everybody is free to contribute to otouto. Here I will explain various things that are important to know about the plugin system. -Every plugin has four components, and half of them are optional: action, triggers, doc, cron. +A plugin can have four components, and two of them are optional: action, triggers, doc, cron. -triggers is a table of strings using Lua patterns which, when matched by a message's text, will "trigger" the action function. This is not optional. +| Component | Description | Optional? | +|-----------|-------------|-----------| +| action | The main function of a plugin. It accepts the `msg` table. | No. | +| triggers | A table of strings which, when one is matched in a message's text, will cause `action` to be run. | No. | +| doc | The help text to be returned when a plugin is run with improper syntax or arguments. The first line is also what goes in the help text. | Yes | +| cron | A function to be run every five seconds. | Yes | -action is the main function of a plugin. It accepts the "msg" table, which is all the components of the message, as an argument. This is not optional. - -doc is the documentation. The first line is the expected command and arguments. Arguments in square braces are considered optional and those in angled braces are considered required. This is optional. - -cron is a function run every five seconds. This is optional. - -The on_msg_receive function adds a few variables to the "msg" table: msg.from.id_str, msg.to.id_str, msg.text_lower. These are self-explanatory and make code a lot neater. +The on_msg_receive function adds a few variables to the "msg" table: msg.from.id_str, msg.to.id_str, msg.text_lower. These are self-explanatory and can make your code a lot neater. Return values from the action function are optional, but when they are used, they determine the fate of the message. When false/nil is returned, on_msg_receive stops and the script moves on to waiting for the next message. When true is returned, on_msg_receive continues going through the plugins for a match. When a table is returned, that table becomes the "msg" table, and on_msg_receive continues. When a plugin action or cron function fails, the script will catch the error and print it, and, if applicable, the text which triggered the plugin, and continue. ----- +* * * Interactions with the Telegram bot API are straightforward. Every function is named the same as the API method it utilizes. The order of expected arguments is laid out in bindings.lua. There are three functions which are not API methods: sendRequest, curlRequest, and sendReply. The first two are used by the other functions. sendReply is used directly. It expects the "msg" table as its first argument, and a string of text as its second. It will send a reply without image preview to the initial message. ----- +* * * Several functions and methods used by multiple plugins and possibly the main script are kept in utilities.lua. Refer to that file for documentation. ----- - otouto uses dkjson, a pure-Lua JSON parser. This is provided with the code and does not need to be downloaded or installed separately. + +* * * + +##Contributors +The creator and maintainer of otouto is [topkecleon](http://github.com/topkecleon). He can be contacted via [Telegram](http://telegram.me/topkecleon), [Twitter](http://twitter.com/topkecleon), or [email](mailto:topkecleon@outlook.com). + +Other developers who have contributed to otouto are [Juan Potato](http://github.com/JuanPotato), [Tiago Danin](http://github.com/TiagoDanin), [Ender](http://github.com/luksireiku), and [Iman Daneshi](http://github.com/Imandaneshi). + diff --git a/bindings.lua b/bindings.lua index 1e08228..aced791 100755 --- a/bindings.lua +++ b/bindings.lua @@ -95,15 +95,9 @@ forwardMessage = function(chat_id, from_chat_id, message_id) end curlRequest = function(curl_command) + -- Use at your own risk. Will not check for success. - local dat = io.popen(curl_command):read('*all') - local tab = JSON.decode(dat) - - if not tab.ok then - return false, tab.description - end - - return tab + io.popen(curl_command) end diff --git a/bot.lua b/bot.lua index edf51f2..7fa8542 100755 --- a/bot.lua +++ b/bot.lua @@ -3,13 +3,13 @@ HTTPS = require('ssl.https') URL = require('socket.url') JSON = require('dkjson') -version = '3.0.1' +version = '3.1' bot_init = function() -- The function run when the bot is started or reloaded. - config = dofile("config.lua") -- Load configuration file. - dofile("bindings.lua") -- Load Telegram bindings. - dofile("utilities.lua") -- Load miscellaneous and cross-plugin functions. + config = dofile('config.lua') -- Load configuration file. + dofile('bindings.lua') -- Load Telegram bindings. + dofile('utilities.lua') -- Load miscellaneous and cross-plugin functions. bot = nil while not bot do -- Get bot info and retry if unable to connect. @@ -19,7 +19,7 @@ bot_init = function() -- The function run when the bot is started or reloaded. plugins = {} -- Load plugins. for i,v in ipairs(config.plugins) do - local p = dofile("plugins/"..v) + local p = dofile('plugins/'..v) table.insert(plugins, p) end @@ -40,6 +40,10 @@ on_msg_receive = function(msg) -- The fn run whenever a message is received. if msg.date < os.time() - 5 then return end -- Do not process old messages. if not msg.text then msg.text = msg.caption or '' end + if msg.text:match('^/start .+') then + msg.text = '/' .. msg.text:input() + end + for i,v in ipairs(plugins) do for k,w in pairs(v.triggers) do if string.match(msg.text:lower(), w) then diff --git a/config.lua b/config.lua index d8c7574..6457acd 100755 --- a/config.lua +++ b/config.lua @@ -8,6 +8,7 @@ return { thecatapi_key = '', time_offset = 0, lang = 'en', + cli_port = 4567, admin = 00000000, admin_name = 'John Smith', about_text = [[ @@ -94,6 +95,7 @@ telegram.me/otouto 'bandersnatch.lua', 'currency.lua', 'cats.lua', + 'hearthstone.lua', 'shout.lua', -- Put new plugins here. 'help.lua', diff --git a/plugins/antisquig.lua b/plugins/antisquig.lua deleted file mode 100755 index 9e0e180..0000000 --- a/plugins/antisquig.lua +++ /dev/null @@ -1,49 +0,0 @@ - -- An extension to moderation.lua. This plugin is useless without it. - -- Put this at the very top of your plugin list, even before blacklist.lua. - - -- Developed by the incredible JuanPotato, creator of the Python CLI bot Botato. - -antisquig = {} - -local triggers = { - '[\216-\219][\128-\191]' -} - -local action = function(msg) - - local moddat = load_data('moderation.json') - - if not moddat[msg.chat.id_str] then - return true - end - - if moddat[msg.chat.id_str][msg.from.id_str] or config.moderation.admins[msg.from.id_str] then - return true - end - - if antisquig[msg.from.id] == true then - return - end - antisquig[msg.from.id] = true - - sendReply(msg, config.errors.antisquig) - sendMessage(config.moderation.admin_group, '/kick ' .. msg.from.id .. ' from ' .. math.abs(msg.chat.id)) - sendMessage(config.moderation.admin_group, 'ANTISQUIG: ' .. msg.from.first_name .. ' kicked from ' .. msg.chat.title .. '.') - -end - - -- When a user is kicked for squigglies, his ID is added to this table. - -- That user will not be kicked again as long as his ID is in the table. - -- The table is emptied every five seconds. - -- Thus the bot will not spam the group or admin group when a user posts more than one infringing messages. -local cron = function() - - antisquig = {} - -end - -return { - action = action, - triggers = triggers, - cron = cron -} diff --git a/plugins/bible.lua b/plugins/bible.lua index 63d7669..f981d76 100755 --- a/plugins/bible.lua +++ b/plugins/bible.lua @@ -10,8 +10,9 @@ local doc = [[ ]] local triggers = { - '^/b[ible]*[@'..bot.username..']*$', - '^/b[ible]*[@'..bot.username..']* ' + '^/bible*[@'..bot.username..']*', + '^/b[@'..bot.username..']* ', + '^/b[@'..bot.username..']*$' } local action = function(msg) diff --git a/plugins/eightball.lua b/plugins/eightball.lua index fddc34b..a8095b3 100755 --- a/plugins/eightball.lua +++ b/plugins/eightball.lua @@ -47,7 +47,7 @@ local action = function(msg) local message - if msg.text_lower:match('y/n%p?$') then + if msg.text:lower():match('y/n%p?$') then message = yesno_answers[math.random(#yesno_answers)] else message = ball_answers[math.random(#ball_answers)] diff --git a/plugins/gImages.lua b/plugins/gImages.lua index 4ae0eed..a1900a8 100755 --- a/plugins/gImages.lua +++ b/plugins/gImages.lua @@ -17,8 +17,10 @@ local doc = [[ ]] local triggers = { - '^/i[mage]*[nsfw]*[@'..bot.username..']*$', - '^/i[mage]*[nsfw]*[@'..bot.username..']* ' + '^/image[@'..bot.username..']*', + '^/i[@'..bot.username..']* ', + '^/i[@'..bot.username..']*$', + '^/insfw[@'..bot.username..']*' } local action = function(msg) diff --git a/plugins/gMaps.lua b/plugins/gMaps.lua index 6edf648..5a049b2 100755 --- a/plugins/gMaps.lua +++ b/plugins/gMaps.lua @@ -4,8 +4,9 @@ local doc = [[ ]] triggers = { - '^/loc[ation]*[@'..bot.username..']*$', - '^/loc[ation]*[@'..bot.username..']* ' + '^/location[@'..bot.username..']*', + '^/loc[@'..bot.username..']* ', + '^/loc[@'..bot.username..']*$' } local action = function(msg) diff --git a/plugins/gSearch.lua b/plugins/gSearch.lua index d11330e..a246eb6 100755 --- a/plugins/gSearch.lua +++ b/plugins/gSearch.lua @@ -4,8 +4,10 @@ local doc = [[ ]] local triggers = { - '^/g[oogle]*[nsfw]*[@'..bot.username..']*$', - '^/g[oogle]*[nsfw]*[@'..bot.username..']* ' + '^/g[@'..bot.username..']*$', + '^/g[@'..bot.username..']* ', + '^/google[@'..bot.username..']*', + '^/gnsfw[@'..bot.username..']*' } local action = function(msg) diff --git a/plugins/hearthstone.lua b/plugins/hearthstone.lua index 977f215..aa1ec80 100755 --- a/plugins/hearthstone.lua +++ b/plugins/hearthstone.lua @@ -25,7 +25,9 @@ local doc = [[ ]] local triggers = { - '^/h[earth]*s[tone]*[@'..bot.username..']*' + '^/hearthstone[@'..bot.username..']*', + '^/hs[@'..bot.username..']*$', + '^/hs[@'..bot.username..']* ' } local format_card = function(card) diff --git a/plugins/help.lua b/plugins/help.lua index e00b36d..040d417 100755 --- a/plugins/help.lua +++ b/plugins/help.lua @@ -13,7 +13,8 @@ end local help_text = help_text .. 'Arguments: [optional]' local triggers = { - '^/h[elp]*[@'..bot.username..']*$', + '^/help[@'..bot.username..']*', + '^/h[@'..bot.username..']*$', '^/start[@'..bot.username..']*' } diff --git a/plugins/lastfm.lua b/plugins/lastfm.lua index 1980ae9..22d05e7 100755 --- a/plugins/lastfm.lua +++ b/plugins/lastfm.lua @@ -43,12 +43,16 @@ local action = function(msg) 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 output = '' if input then username = input elseif lastfm[msg.from.id_str] then username = lastfm[msg.from.id_str] elseif msg.from.username then username = msg.from.username + output = '\n\nYour username has been set to ' .. username .. '.\nTo change it, use /fmset .' + lastfm[msg.from.id_str] = username + save_data('lastfm.json', lastfm) else sendReply(msg, 'Please specify your last.fm username or set it with /fmset.') return @@ -64,13 +68,13 @@ local action = function(msg) local jdat = JSON.decode(jstr) if jdat.error then - sendReply(msg, jdat.error) + sendReply(msg, config.errors.results) return end local jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track if not jdat then - sendReply(msg, 'No history for this user.') + sendReply(msg, 'No history for this user.' .. output) return end @@ -89,7 +93,7 @@ local action = function(msg) artist = jdat.artist['#text'] end - message = message .. title .. ' - ' .. artist + message = message .. title .. ' - ' .. artist .. output sendMessage(msg.chat.id, message) end diff --git a/plugins/moderation.lua b/plugins/moderation.lua index f94d2f3..1ebfa1d 100755 --- a/plugins/moderation.lua +++ b/plugins/moderation.lua @@ -3,24 +3,13 @@ -- Put this near the top, after blacklist. -- If you want to enable antisquig, put that at the top, before blacklist. - local triggers = { - '^/modhelp[@'..bot.username..']*$', - '^/modlist[@'..bot.username..']*$', - '^/modcast[@'..bot.username..']*', - '^/modadd[@'..bot.username..']*$', - '^/modrem[@'..bot.username..']*$', - '^/modprom[@'..bot.username..']*$', - '^/moddem[@'..bot.username..']*', - '^/modkick[@'..bot.username..']*', - '^/modban[@'..bot.username..']*', - } +moddat = load_data('moderation.json') +antisquig = {} local commands = { ['^/modhelp[@'..bot.username..']*$'] = function(msg) - local moddat = load_data('moderation.json') - if not moddat[msg.chat.id_str] then return config.errors.moderation end @@ -31,10 +20,10 @@ local commands = { /modkick - Kick a user from this group. /modban - Ban a user from this group. Administrator commands: - /add - Add this group to the moderation system. - /remove - Remove this group from the moderation system. - /promote - Promote a user to a moderator. - /demote - Demote a moderator to a user. + /modadd - Add this group to the moderation system. + /modrem - Remove this group from the moderation system. + /modprom - Promote a user to a moderator. + /moddem - Demote a moderator to a user. /modcast - Send a broadcast to every moderated group. ]] @@ -44,8 +33,6 @@ local commands = { ['^/modlist[@'..bot.username..']*$'] = function(msg) - local moddat = load_data('moderation.json') - if not moddat[msg.chat.id_str] then return config.errors.moderation end @@ -84,8 +71,6 @@ local commands = { return config.errors.not_admin end - local moddat = load_data('moderation.json') - for k,v in pairs(moddat) do sendMessage(k, message) end @@ -100,8 +85,6 @@ local commands = { return config.errors.not_admin end - local moddat = load_data('moderation.json') - if moddat[msg.chat.id_str] then return 'I am already moderating this group.' end @@ -118,8 +101,6 @@ local commands = { return config.errors.not_admin end - local moddat = load_data('moderation.json') - if not moddat[msg.chat.id_str] then return config.errors.moderation end @@ -132,8 +113,6 @@ local commands = { ['^/modprom[@'..bot.username..']*$'] = function(msg) - local moddat = load_data('moderation.json') - if not moddat[msg.chat.id_str] then return config.errors.moderation end @@ -166,8 +145,6 @@ local commands = { ['^/moddem[@'..bot.username..']*'] = function(msg) - local moddat = load_data('moderation.json') - if not moddat[msg.chat.id_str] then return config.errors.moderation end @@ -204,8 +181,6 @@ local commands = { ['/modkick[@'..bot.username..']*'] = function(msg) - local moddat = load_data('moderation.json') - if not moddat[msg.chat.id_str] then return config.errors.moderation end @@ -240,8 +215,6 @@ local commands = { ['^/modban[@'..bot.username..']*'] = function(msg) - local moddat = load_data('moderation.json') - if not moddat[msg.chat.id_str] then return config.errors.moderation end @@ -276,21 +249,61 @@ local commands = { } +if config.antisquig then + commands['[\216-\219][\128-\191]'] = function(msg) + + if not moddat[msg.chat.id_str] then return true end + if config.moderation.admins[msg.from.id_str] then return true end + if moddat[msg.chat.id_str][msg.from.id_str] then return true end + + if antisquig[msg.from.id] == true then + return + end + antisquig[msg.from.id] = true + + sendReply(msg, config.errors.antisquig) + sendMessage(config.moderation.admin_group, '/kick ' .. msg.from.id .. ' from ' .. math.abs(msg.chat.id)) + sendMessage(config.moderation.admin_group, 'ANTISQUIG: ' .. msg.from.first_name .. ' kicked from ' .. msg.chat.title .. '.') + + + end +end + +local triggers = {} +for k,v in pairs(commands) do + table.insert(triggers, k) +end + local action = function(msg) for k,v in pairs(commands) do if string.match(msg.text_lower, k) then local output = v(msg) - if output then + if output == true then + return true + elseif output then sendReply(msg, output) end return end end + return true + +end + + -- When a user is kicked for squigglies, his ID is added to this table. + -- That user will not be kicked again as long as his ID is in the table. + -- The table is emptied every five seconds. + -- Thus the bot will not spam the group or admin group when a user posts more than one infringing messages. +local cron = function() + + antisquig = {} + end return { action = action, - triggers = triggers + triggers = triggers, + cron = cron } diff --git a/plugins/pokedex.lua b/plugins/pokedex.lua index 73e14e1..bed2c37 100755 --- a/plugins/pokedex.lua +++ b/plugins/pokedex.lua @@ -4,7 +4,8 @@ local doc = [[ ]] local triggers = { - '^/[poke]*dex[@'..bot.username..']*' + '^/pokedex[@'..bot.username..']*', + '^/dex[@'..bot.username..']*' } local action = function(msg) diff --git a/plugins/reactions.lua b/plugins/reactions.lua index 4d1405d..ec90c98 100755 --- a/plugins/reactions.lua +++ b/plugins/reactions.lua @@ -9,13 +9,13 @@ local triggers = { ['(╯°□°)╯︵ ┻━┻'] = '/flip$', ['┌(┌ ^o^)┐'] = '/homo$', ['ಠ_ಠ'] = '/look$', - ['SHOTS FIRED'] = '/shot$' + ['SHOTS FIRED'] = '/shots?$' } -- Generate a "help" message triggered by "/reactions". local help = '' for k,v in pairs(triggers) do - help = help .. v:gsub('%$', ': ') .. k .. '\n' + help = help .. v:gsub('%$', ': '):gsub('?', '') .. k .. '\n' end triggers[help] = '^/reactions$' diff --git a/plugins/reddit.lua b/plugins/reddit.lua index 7122061..df72e1e 100755 --- a/plugins/reddit.lua +++ b/plugins/reddit.lua @@ -4,8 +4,9 @@ local doc = [[ ]] local triggers = { - '^/r[eddit]*[@'..bot.username..']*$', - '^/r[eddit]*[@'..bot.username..']* ', + '^/reddit[@'..bot.username..']*', + '^/r[@'..bot.username..']*$', + '^/r[@'..bot.username..']* ', '^/r/' } diff --git a/plugins/urbandictionary.lua b/plugins/urbandictionary.lua index d7feb15..ee1879e 100755 --- a/plugins/urbandictionary.lua +++ b/plugins/urbandictionary.lua @@ -4,7 +4,9 @@ local doc = [[ ]] local triggers = { - '^/u[rban]*d[ictionary]*[@'..bot.username..']*', + '^/urbandictionary[@'..bot.username..']*', + '^/ud[@'..bot.username..']*$', + '^/ud[@'..bot.username..']* ', '^/urban[@'..bot.username..']*' } diff --git a/plugins/wikipedia.lua b/plugins/wikipedia.lua index 35463a4..bcbc986 100755 --- a/plugins/wikipedia.lua +++ b/plugins/wikipedia.lua @@ -4,8 +4,10 @@ local doc = [[ ]] local triggers = { - '^/w[iki[pedia]*]*[@'..bot.username..']*$', - '^/w[iki[pedia]*]*[@'..bot.username..']* ' + '^/wikipedia[@'..bot.username..']*', + '^/wiki[@'..bot.username..']*', + '^/w[@'..bot.username..']*$', + '^/w[@'..bot.username..']* ' } local action = function(msg) diff --git a/plugins/youtube.lua b/plugins/youtube.lua index a288951..b87c86d 100755 --- a/plugins/youtube.lua +++ b/plugins/youtube.lua @@ -6,7 +6,9 @@ local doc = [[ ]] local triggers = { - '^/y[ou]*t[ube]*[@'..bot.username..']*' + '^/youtube[@'..bot.username..']*', + '^/yt[@'..bot.username..']*$', + '^/yt[@'..bot.username..']* ' } local action = function(msg)