From 8b7c55088af687314c077b723952ff46eefdfdda Mon Sep 17 00:00:00 2001 From: Andreas Bielawski Date: Thu, 8 Sep 2016 01:35:10 +0200 Subject: [PATCH 1/9] =?UTF-8?q?Code-Cleanup=20f=C3=BCr=20Utilities,=20fix?= =?UTF-8?q?=20#12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- otouto/plugins/app_store.lua | 2 +- otouto/plugins/bitly_create.lua | 4 +- otouto/plugins/channels.lua | 2 +- otouto/plugins/control.lua | 2 +- otouto/plugins/creds.lua | 2 +- otouto/plugins/dhl.lua | 4 +- otouto/plugins/gImages.lua | 15 +++- otouto/plugins/games.lua | 2 +- otouto/plugins/github_feed.lua | 10 +-- otouto/plugins/id.lua | 30 ++++---- otouto/plugins/imgblacklist.lua | 2 +- otouto/plugins/luarun.lua | 2 +- otouto/plugins/lyrics.lua | 2 +- otouto/plugins/plugins.lua | 18 ++++- otouto/plugins/quotes.lua | 8 -- otouto/plugins/rss.lua | 10 +-- otouto/plugins/site_header.lua | 2 +- otouto/plugins/stats.lua | 2 +- otouto/plugins/tagesschau_eil.lua | 2 +- otouto/plugins/twitter_send.lua | 10 +-- otouto/utilities.lua | 124 +++--------------------------- 21 files changed, 85 insertions(+), 170 deletions(-) diff --git a/otouto/plugins/app_store.lua b/otouto/plugins/app_store.lua index a3b0980..3b9fb6f 100644 --- a/otouto/plugins/app_store.lua +++ b/otouto/plugins/app_store.lua @@ -43,7 +43,7 @@ function app_store:send_appstore_data(data) else game_center = '' end - local category_count = tablelength(data.genres) + local category_count = #data.genres if category_count == 1 then category = '\nKategorie: '..data.genres[1] else diff --git a/otouto/plugins/bitly_create.lua b/otouto/plugins/bitly_create.lua index 9ae823d..9d2c7df 100644 --- a/otouto/plugins/bitly_create.lua +++ b/otouto/plugins/bitly_create.lua @@ -124,10 +124,10 @@ function bitly_create:action(msg, config, matches) end if matches[2] == nil then - long_url = url_encode(matches[1]) + long_url = URL.encode(matches[1]) domain = 'bit.ly' else - long_url = url_encode(matches[2]) + long_url = URL.encode(matches[2]) domain = matches[1] end utilities.send_reply(msg, bitly_create:create_bitlink(long_url, domain, bitly_access_token)) diff --git a/otouto/plugins/channels.lua b/otouto/plugins/channels.lua index e16e041..bb62de6 100644 --- a/otouto/plugins/channels.lua +++ b/otouto/plugins/channels.lua @@ -47,7 +47,7 @@ function channels:pre_process(msg, config) end function channels:action(msg, config, matches) - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end diff --git a/otouto/plugins/control.lua b/otouto/plugins/control.lua index abf1ca9..616d120 100644 --- a/otouto/plugins/control.lua +++ b/otouto/plugins/control.lua @@ -11,7 +11,7 @@ end function control:action(msg, config) - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then return end diff --git a/otouto/plugins/creds.lua b/otouto/plugins/creds.lua index 5da43cc..9c19a39 100644 --- a/otouto/plugins/creds.lua +++ b/otouto/plugins/creds.lua @@ -89,7 +89,7 @@ end function creds_manager:action(msg, config, matches) local receiver = msg.from.id - if receiver ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end diff --git a/otouto/plugins/dhl.lua b/otouto/plugins/dhl.lua index b7cabc6..4852fe8 100644 --- a/otouto/plugins/dhl.lua +++ b/otouto/plugins/dhl.lua @@ -16,9 +16,9 @@ function dhl:sendungsstatus(id) local res,code = https.request(url) if code ~= 200 then return "Fehler beim Abrufen von mobil.dhl.de" end local status = string.match(res, "
(.-)
") - local status = all_trim(status) + local status = utilities.trim(status) local zeit = string.match(res, "
(.-)
") - local zeit = all_trim(zeit) + local zeit = utilities.trim(zeit) if not zeit or zeit == '
' then return status end diff --git a/otouto/plugins/gImages.lua b/otouto/plugins/gImages.lua index 1fd8260..78af76a 100644 --- a/otouto/plugins/gImages.lua +++ b/otouto/plugins/gImages.lua @@ -23,6 +23,19 @@ end gImages.command = 'img ' +function gImages:is_blacklisted(msg) + _blacklist = redis:smembers("telegram:img_blacklist") + local var = false + for v,word in pairs(_blacklist) do + if string.find(string.lower(msg), string.lower(word)) then + print("Wort steht auf der Blacklist!") + var = true + break + end + end + return var +end + -- Yes, the callback is copied from below, but I can't think of another method :\ function gImages:callback(callback, msg, self, config, input) if not msg then return end @@ -150,7 +163,7 @@ function gImages:action(msg, config, matches) end print ('Checking if search contains blacklisted word: '..input) - if is_blacklisted(input) then + if gImages:is_blacklisted(input) then utilities.send_reply(msg, 'Vergiss es! ._.') return end diff --git a/otouto/plugins/games.lua b/otouto/plugins/games.lua index 0e34912..ddbe85f 100644 --- a/otouto/plugins/games.lua +++ b/otouto/plugins/games.lua @@ -79,7 +79,7 @@ function games:send_game_data(game_id, self, msg) if xml.find(result, 'Genres') then local genres = xml.find(result, 'Genres') - local genre_count = tablelength(genres)-1 + local genre_count = #genres-1 if genre_count == 1 then genre = '\nGenre: '..genres[1][1] else diff --git a/otouto/plugins/github_feed.lua b/otouto/plugins/github_feed.lua index 1c5f2c5..78a2d98 100644 --- a/otouto/plugins/github_feed.lua +++ b/otouto/plugins/github_feed.lua @@ -180,7 +180,7 @@ function gh_feed:action(msg, config, matches) -- For channels if matches[1] == 'sub' and matches[2] and matches[3] then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end @@ -194,7 +194,7 @@ function gh_feed:action(msg, config, matches) utilities.send_reply(msg, output, true) return elseif matches[1] == 'del' and matches[2] and matches[3] then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end @@ -227,7 +227,7 @@ function gh_feed:action(msg, config, matches) end if matches[1] == 'sub' and matches[2] then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end @@ -235,7 +235,7 @@ function gh_feed:action(msg, config, matches) utilities.send_reply(msg, output, true) return elseif matches[1] == 'del' and matches[2] then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end @@ -247,7 +247,7 @@ function gh_feed:action(msg, config, matches) utilities.send_reply(msg, list_subs, true, keyboard) return elseif matches[1] == 'sync' then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end diff --git a/otouto/plugins/id.lua b/otouto/plugins/id.lua index f88b4e9..0becc6d 100644 --- a/otouto/plugins/id.lua +++ b/otouto/plugins/id.lua @@ -66,27 +66,27 @@ function id:action(msg, config, matches) end local chat_id = msg.chat.id - local user = 'Du bist @%s, auch bekannt als *%s* `[%s]`' + local user = 'Du bist @%s, auch bekannt als %s [%s]' if msg.from.username then - user = user:format(utilities.markdown_escape(msg.from.username), msg.from.name, msg.from.id) + user = user:format(utilities.html_escape(msg.from.username), msg.from.name, msg.from.id) else - user = 'Du bist *%s* `[%s]`,' + user = 'Du bist %s [%s],' user = user:format(msg.from.name, msg.from.id) end - local group = '@%s, auch bekannt als *%s* `[%s]`.' + local group = '@%s, auch bekannt als %s [%s].' if msg.chat.type == 'private' then - group = group:format(utilities.markdown_escape(self.info.username), self.info.first_name, self.info.id) + group = group:format(utilities.html_escape(self.info.username), self.info.first_name, self.info.id) elseif msg.chat.username then - group = group:format(utilities.markdown_escape(msg.chat.username), msg.chat.title, chat_id) + group = group:format(utilities.html_escape(msg.chat.username), msg.chat.title, chat_id) else - group = '*%s* `[%s]`.' + group = '%s [%s].' group = group:format(msg.chat.title, chat_id) end local output = user .. ', und du bist in der Gruppe ' .. group - utilities.send_message(msg.chat.id, output, true, msg.message_id, true) + utilities.send_message(msg.chat.id, output, true, msg.message_id, 'HTML') elseif matches[1] == "chat" then if msg.chat.type ~= 'group' and msg.chat.type ~= 'supergroup' then utilities.send_reply(msg, 'Das hier ist keine Gruppe!') @@ -118,21 +118,21 @@ function id:action(msg, config, matches) local result = id:get_member_count(msg, chat_id) local member_count = result.result if member_count == 1 then - member_count = 'ist *1 Mitglied' + member_count = 'ist 1 Mitglied' else - member_count = 'sind *'..member_count..' Mitglieder' + member_count = 'sind '..member_count..' Mitglieder' end - local text = 'IDs für *'..chat_name..'* `['..chat_id..']`\nHier '..member_count..':*\n---------\n' + local text = 'IDs für '..chat_name..' ['..chat_id..']\nHier '..member_count..':\n---------\n' for k,user in pairs(users_info) do if table.contains(admins, tostring(user.id)) then - text = text..'*'..user.name..'* `['..user.id..']` _Administrator_\n' + text = text..''..user.name..' ['..user.id..'] Administrator\n' elseif tostring(creator_id) == user.id then - text = text..'*'..user.name..'* `['..user.id..']` _Gründer_\n' + text = text..''..user.name..' ['..user.id..'] Gründer\n' else - text = text..'*'..user.name..'* `['..user.id..']`\n' + text = text..''..user.name..' ['..user.id..']\n' end end - utilities.send_reply(msg, text..'_(Bots sind nicht gelistet)_', true) + utilities.send_reply(msg, text..'(Bots sind nicht gelistet)', 'HTML') end end diff --git a/otouto/plugins/imgblacklist.lua b/otouto/plugins/imgblacklist.lua index f94393f..1f94a83 100644 --- a/otouto/plugins/imgblacklist.lua +++ b/otouto/plugins/imgblacklist.lua @@ -49,7 +49,7 @@ function imgblacklist:remove_blacklist(word) end function imgblacklist:action(msg, config, matches) - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end diff --git a/otouto/plugins/luarun.lua b/otouto/plugins/luarun.lua index a15c750..75bcd12 100644 --- a/otouto/plugins/luarun.lua +++ b/otouto/plugins/luarun.lua @@ -27,7 +27,7 @@ end function luarun:action(msg, config) - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then return true end diff --git a/otouto/plugins/lyrics.lua b/otouto/plugins/lyrics.lua index 88584a8..b69e7ee 100644 --- a/otouto/plugins/lyrics.lua +++ b/otouto/plugins/lyrics.lua @@ -16,7 +16,7 @@ lyrics.command = 'lyrics ' function lyrics:getLyrics(text) local apikey = cred_data.lyricsnmusic_apikey - local q = url_encode(text) + local q = URL.encode(text) local b = http.request("http://api.lyricsnmusic.com/songs?api_key="..apikey.."&q=" .. q) response = json.decode(b) local reply = "" diff --git a/otouto/plugins/plugins.lua b/otouto/plugins/plugins.lua index 77dd3f0..e231eb7 100644 --- a/otouto/plugins/plugins.lua +++ b/otouto/plugins/plugins.lua @@ -24,6 +24,18 @@ end plugin_manager.command = 'plugins ' +-- Returns at table of lua files inside plugins +function plugin_manager:plugins_names() + local files = {} + for k, v in pairs(scandir("otouto/plugins")) do + -- Ends with .lua + if (v:match(".lua$")) then + files[#files+1] = v + end + end + return files +end + -- Returns the key (index) in the config.enabled_plugins table function plugin_manager:plugin_enabled(name, chat) for k,v in pairs(enabled_plugins) do @@ -37,7 +49,7 @@ end -- Returns true if file exists in plugins folder function plugin_manager:plugin_exists(name) - for k,v in pairs(plugins_names()) do + for k,v in pairs(plugin_manager:plugins_names()) do if name..'.lua' == v then return true end @@ -47,7 +59,7 @@ end function plugin_manager:list_plugins() local text = '' - for k, v in pairs(plugins_names()) do + for k, v in pairs(plugin_manager:plugins_names()) do -- ✔ enabled, ❌ disabled local status = '❌' -- Check if is enabled @@ -161,7 +173,7 @@ function plugin_manager:reenable_plugin_on_chat(msg, plugin) end function plugin_manager:action(msg, config, matches) - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end diff --git a/otouto/plugins/quotes.lua b/otouto/plugins/quotes.lua index 35e8c31..d56c75d 100644 --- a/otouto/plugins/quotes.lua +++ b/otouto/plugins/quotes.lua @@ -21,10 +21,6 @@ end quotes.command = 'quote' function quotes:save_quote(msg) - if msg.text:sub(11):isempty() then - return "Benutzung: /addquote [Zitat]" - end - local quote = msg.text:sub(11) local hash = get_redis_hash(msg, 'quotes') print('Saving quote to redis set '..hash) @@ -33,10 +29,6 @@ function quotes:save_quote(msg) end function quotes:delete_quote(msg) - if msg.text:sub(11):isempty() then - return "Benutzung: /delquote [Zitat]" - end - local quote = msg.text:sub(11) local hash = get_redis_hash(msg, 'quotes') print('Deleting quote from redis set '..hash) diff --git a/otouto/plugins/rss.lua b/otouto/plugins/rss.lua index e9c2fb9..5c44a5b 100644 --- a/otouto/plugins/rss.lua +++ b/otouto/plugins/rss.lua @@ -211,7 +211,7 @@ function rss:action(msg, config, matches) -- For channels if matches[1] == 'sub' and matches[2] and matches[3] then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end @@ -225,7 +225,7 @@ function rss:action(msg, config, matches) utilities.send_reply(msg, output, 'HTML') return elseif matches[1] == 'del' and matches[2] and matches[3] then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end @@ -258,7 +258,7 @@ function rss:action(msg, config, matches) end if matches[1] == 'sub' and matches[2] then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end @@ -266,7 +266,7 @@ function rss:action(msg, config, matches) utilities.send_reply(msg, output, 'HTML') return elseif matches[1] == 'del' and matches[2] then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end @@ -278,7 +278,7 @@ function rss:action(msg, config, matches) utilities.send_reply(msg, list_subs, 'HTML', keyboard) return elseif matches[1] == 'sync' then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end diff --git a/otouto/plugins/site_header.lua b/otouto/plugins/site_header.lua index eeca8e1..2670273 100644 --- a/otouto/plugins/site_header.lua +++ b/otouto/plugins/site_header.lua @@ -8,7 +8,7 @@ function site_header:init(config) end function site_header:action(msg, config, matches) - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) end diff --git a/otouto/plugins/stats.lua b/otouto/plugins/stats.lua index 3e24137..baa5b1d 100644 --- a/otouto/plugins/stats.lua +++ b/otouto/plugins/stats.lua @@ -136,7 +136,7 @@ function stats:action(msg, config, matches) end if matches[2] == "chat" then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return else diff --git a/otouto/plugins/tagesschau_eil.lua b/otouto/plugins/tagesschau_eil.lua index 6859280..ce4a62f 100644 --- a/otouto/plugins/tagesschau_eil.lua +++ b/otouto/plugins/tagesschau_eil.lua @@ -64,7 +64,7 @@ function tagesschau_eil:action(msg, config) local output = tagesschau_eil:deabonnieren(id) utilities.send_reply(msg, output, true) elseif input:match('(sync)$') then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end diff --git a/otouto/plugins/twitter_send.lua b/otouto/plugins/twitter_send.lua index 6ceb3f1..325d35e 100644 --- a/otouto/plugins/twitter_send.lua +++ b/otouto/plugins/twitter_send.lua @@ -248,7 +248,7 @@ end function twitter_send:action(msg, config, matches) if matches[1] == "twwhitelist add" then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return else @@ -265,7 +265,7 @@ function twitter_send:action(msg, config, matches) end if matches[1] == "twwhitelist del" then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return else @@ -288,7 +288,7 @@ function twitter_send:action(msg, config, matches) -- Thanks to the great doc at https://github.com/ignacio/LuaOAuth#a-more-involved-example if not oauth_token and not oauth_token_secret then if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return else @@ -312,7 +312,7 @@ function twitter_send:action(msg, config, matches) if matches[1] == 'auth' and matches[2] then if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end @@ -327,7 +327,7 @@ function twitter_send:action(msg, config, matches) if matches[1] == 'unauth' then if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then - if msg.from.id ~= config.admin then + if not is_sudo(msg, config) then utilities.send_reply(msg, config.errors.sudo) return end diff --git a/otouto/utilities.lua b/otouto/utilities.lua index a46b418..2bc3b88 100644 --- a/otouto/utilities.lua +++ b/otouto/utilities.lua @@ -342,38 +342,21 @@ function utilities.input_from_msg(msg) return utilities.input(msg.text) or (msg.reply_to_message and #msg.reply_to_message.text > 0 and msg.reply_to_message.text) or false end --- Calculates the length of the given string as UTF-8 characters -function utilities.utf8_len(s) - local chars = 0 - for i = 1, string.len(s) do - local b = string.byte(s, i) - if b < 128 or b >= 192 then - chars = chars + 1 - end - end - return chars -end - -- Trims whitespace from a string. function utilities.trim(str) local s = str:gsub('^%s*(.-)%s*$', '%1') return s end --- Returns true if the string is empty +-- Returns true if the string is blank/empty function string:isempty() - return self == nil or self == '' -end - --- Returns true if the string is blank -function string:isblank() self = self:trim() - return self:isempty() + return self == nil or self == '' end function get_name(msg) local name = msg.from.first_name - if name == nil then + if not name then name = msg.from.id end return name @@ -391,10 +374,6 @@ function convert_timestamp(timestamp, date_format) return os.date(date_format, timestamp) end -function string.starts(String, Start) - return Start == string.sub(String,1,string.len(Start)) -end - -- Saves file to $HOME/tmp/. If file_name isn't provided, -- will get the text after the last "/" for filename -- and content-type for extension @@ -497,19 +476,6 @@ function utilities.build_name(first, last) end end -function utilities:resolve_username(input) - input = input:gsub('^@', '') - for _, user in pairs(self.database.users) do - if user.username and user.username:lower() == input:lower() then - local t = {} - for key, val in pairs(user) do - t[key] = val - end - return t - end - end -end - function utilities:handle_exception(err, message, log_chat) local output = string.format( '[%s]\n%s: %s\n%s\n', @@ -527,19 +493,12 @@ function utilities:handle_exception(err, message, log_chat) end --- MOVED TO DOWNLOAD_TO_FILE -function utilities.download_file(url, filename) - return download_to_file(url, filename) -end - function utilities.md_escape(text) return text:gsub('_', '\\_') :gsub('%[', '\\['):gsub('%]', '\\]') :gsub('%*', '\\*'):gsub('`', '\\`') end -utilities.markdown_escape = utilities.md_escape - function utilities.html_escape(text) return text:gsub('&', '&'):gsub('<', '<'):gsub('>', '>') end @@ -565,13 +524,6 @@ function utilities.triggers(username, cmd_pat, trigger_table) return self end -function utilities.with_http_timeout(timeout, fun) - local original = http.TIMEOUT - http.TIMEOUT = timeout - fun() - http.TIMEOUT = original -end - function utilities.enrich_user(user) user.id_str = tostring(user.id) user.name = utilities.build_name(user.first_name, user.last_name) @@ -594,11 +546,11 @@ function utilities.enrich_message(msg) if msg.forward_from then msg.forward_from = utilities.enrich_user(msg.forward_from) end - if msg.new_chat_participant then - msg.new_chat_participant = utilities.enrich_user(msg.new_chat_participant) + if msg.new_chat_member then + msg.new_chat_member = utilities.enrich_user(msg.new_chat_member) end - if msg.left_chat_participant then - msg.left_chat_participant = utilities.enrich_user(msg.left_chat_participant) + if msg.left_chat_member then + msg.left_chat_member = utilities.enrich_user(msg.left_chat_member) end return msg end @@ -632,29 +584,6 @@ function scandir(directory) return t end --- Returns at table of lua files inside plugins -function plugins_names() - local files = {} - for k, v in pairs(scandir("otouto/plugins")) do - -- Ends with .lua - if (v:match(".lua$")) then - files[#files+1] = v - end - end - return files -end - --- Function name explains what it does. -function file_exists(name) - local f = io.open(name,"r") - if f ~= nil then - io.close(f) - return true - else - return false - end -end - -- Returns a table with matches or nil function match_pattern(pattern, text) if text then @@ -793,17 +722,6 @@ function get_redis_hash(msg, var) end end --- remove whitespace -function all_trim(s) - return s:match( "^%s*(.-)%s*$" ) -end - -function tablelength(T) - local count = 0 - for _ in pairs(T) do count = count + 1 end - return count -end - function round(num, idp) if idp and idp>0 then local mult = 10^idp @@ -823,6 +741,9 @@ function comma_value(amount) return formatted end +function string.starts(String,Start) + return string.sub(String,1,string.len(Start))==Start +end function string.ends(str, fin) return fin=='' or string.sub(str,-string.len(fin)) == fin @@ -1034,19 +955,6 @@ function makeHumanTime(totalseconds) end end -function is_blacklisted(msg) - _blacklist = redis:smembers("telegram:img_blacklist") - local var = false - for v,word in pairs(_blacklist) do - if string.find(string.lower(msg), string.lower(word)) then - print("Wort steht auf der Blacklist!") - var = true - break - end - end - return var -end - function unescape(str) str = string.gsub( str, '<', '<' ) str = string.gsub( str, '>', '>' ) @@ -1065,16 +973,6 @@ function unescape(str) return str end -function url_encode(str) - if (str) then - str = string.gsub (str, "\n", "\r\n") - str = string.gsub (str, "([^%w %-%_%.%~])", - function (c) return string.format ("%%%02X", string.byte(c)) end) - str = string.gsub (str, " ", "+") - end - return str -end - function table.contains(table, element) for _, value in pairs(table) do if value == element then @@ -1103,4 +1001,4 @@ function utilities.fix_utf8(str) end -return utilities +return utilities \ No newline at end of file From 4e01c276734a550f04fb46aeadfb28139928d5fc Mon Sep 17 00:00:00 2001 From: Andreas Bielawski Date: Thu, 8 Sep 2016 01:48:14 +0200 Subject: [PATCH 2/9] InlineQuerys mit > 200 Zeichen werden jetzt ignoriert --- otouto/bot.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/otouto/bot.lua b/otouto/bot.lua index b66c104..5a3febc 100644 --- a/otouto/bot.lua +++ b/otouto/bot.lua @@ -189,6 +189,11 @@ function bot:process_inline_query(inline_query, config) -- When an inline query inline_query.query = inline_query.query:gsub('"', '\\"') end + if string.len(inline_query.query) > 200 then + abort_inline_query(inline_query) + return + end + for n=1, #self.plugins do local plugin = self.plugins[n] match_inline_plugins(self, inline_query, config, plugin) From 271c9c5f846fcdadac9501e0426f4a6077512b99 Mon Sep 17 00:00:00 2001 From: Andreas Bielawski Date: Thu, 8 Sep 2016 15:15:19 +0200 Subject: [PATCH 3/9] Kleinere Verbesserungen --- otouto/bot.lua | 1 - otouto/plugins/media.lua | 2 ++ otouto/utilities.lua | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/otouto/bot.lua b/otouto/bot.lua index 5a3febc..4bdb26f 100644 --- a/otouto/bot.lua +++ b/otouto/bot.lua @@ -229,7 +229,6 @@ function bot:run(config) -- Run cron jobs every minute. if self.last_cron ~= os.date('%M') then self.last_cron = os.date('%M') - utilities.save_data(self.info.username..'.db', self.database) -- Save the database. for n=1, #self.plugins do local v = self.plugins[n] if v.cron then -- Call each plugin's cron function, if it has one. diff --git a/otouto/plugins/media.lua b/otouto/plugins/media.lua index 5244a0b..44423ee 100644 --- a/otouto/plugins/media.lua +++ b/otouto/plugins/media.lua @@ -1,5 +1,7 @@ local media = {} +local mime = (loadfile "./otouto/mimetype.lua")() + media.triggers = { "(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(gif))$", "^(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(mp4))$", diff --git a/otouto/utilities.lua b/otouto/utilities.lua index 2bc3b88..ef18b6a 100644 --- a/otouto/utilities.lua +++ b/otouto/utilities.lua @@ -30,7 +30,6 @@ json = require("dkjson") pcall(json.use_lpeg) serpent = require("serpent") redis = (loadfile "./otouto/redis.lua")() -mime = (loadfile "./otouto/mimetype.lua")() OAuth = require "OAuth" helpers = require "OAuth.helpers" From 2f95b6b562bc89de53554ad10be34eda3bec684a Mon Sep 17 00:00:00 2001 From: Andreas Bielawski Date: Thu, 8 Sep 2016 16:13:47 +0200 Subject: [PATCH 4/9] =?UTF-8?q?-=20Fixe=20string:isempty()=20-=20Tagesscha?= =?UTF-8?q?u:=20HTTP-Fehlercode=20wird=20jetzt=20vor=20dem=20JSON-Encoding?= =?UTF-8?q?=20gepr=C3=BCft?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- otouto/plugins/tagesschau.lua | 4 ++-- otouto/utilities.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/otouto/plugins/tagesschau.lua b/otouto/plugins/tagesschau.lua index 1c74e42..2eb61d6 100644 --- a/otouto/plugins/tagesschau.lua +++ b/otouto/plugins/tagesschau.lua @@ -16,10 +16,10 @@ end function tagesschau:get_tagesschau_article(article) local url = BASE_URL..'/'..article..'.json' - local res,code = https.request(url) - local data = json.decode(res) + local res, code = https.request(url) if code == 404 then return "Artikel nicht gefunden!" end if code ~= 200 then return "HTTP-Fehler" end + local data = json.decode(res) if not data then return "HTTP-Fehler" end if data.type ~= "story" then print('Typ "'..data.type..'" wird nicht unterstützt') diff --git a/otouto/utilities.lua b/otouto/utilities.lua index ef18b6a..0516d3e 100644 --- a/otouto/utilities.lua +++ b/otouto/utilities.lua @@ -349,7 +349,7 @@ end -- Returns true if the string is blank/empty function string:isempty() - self = self:trim() + self = utilities.trim(self) return self == nil or self == '' end From 93b1a1eab2768d7e74d946b0175dd61329803789 Mon Sep 17 00:00:00 2001 From: Andreas Bielawski Date: Thu, 8 Sep 2016 16:50:42 +0200 Subject: [PATCH 5/9] =?UTF-8?q?Fixes=20f=C3=BCr=20CallbackQuerys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- otouto/bot.lua | 6 ++++-- otouto/plugins/pocket.lua | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/otouto/bot.lua b/otouto/bot.lua index 4bdb26f..5c9a63f 100644 --- a/otouto/bot.lua +++ b/otouto/bot.lua @@ -132,7 +132,7 @@ function bot:on_callback_receive(callback, msg, config) -- whenever a new callba -- Check if whitelist is enabled and user/chat is whitelisted local whitelist = redis:get('whitelist:enabled') - if whitelist and not is_sudo(msg, config) then + if whitelist and not is_sudo(callback, config) then local hash = 'whitelist:user#id'..user_id local allowed = redis:get(hash) or false if not allowed then @@ -160,10 +160,12 @@ function bot:on_callback_receive(callback, msg, config) -- whenever a new callba for n=1, #self.plugins do local plugin = self.plugins[n] if plugin.name == called_plugin then - if is_plugin_disabled_on_chat(plugin.name, msg) then return end + if is_plugin_disabled_on_chat(plugin.name, msg) then utilities.answer_callback_query(callback, 'Plugin wurde in diesem Chat deaktiviert.') return end plugin:callback(callback, msg, self, config, param) end end + + utilities.answer_callback_query(callback, 'Ungültiger CallbackQuery: Kein Plugin gefunden.') end -- NOTE: To enable InlineQuerys, send /setinline to @BotFather diff --git a/otouto/plugins/pocket.lua b/otouto/plugins/pocket.lua index beb69af..6d07a16 100644 --- a/otouto/plugins/pocket.lua +++ b/otouto/plugins/pocket.lua @@ -74,6 +74,7 @@ function pocket:add_pocket_item(access_token, url) local code = result.item.response_code local text = title..' ('..given_url..') hinzugefügt!' + if not code then return text end if code ~= "200" and code ~= "0" then text = text..'\nAber die Seite liefert Fehler '..code..' zurück.' end return text end From e02323e0b2e81543212c6a439c2bbd192e31839b Mon Sep 17 00:00:00 2001 From: topkecleon Date: Fri, 9 Sep 2016 05:01:38 -0400 Subject: [PATCH 6/9] readme stuff --- README.md | 255 +++++++++++++++++++++++++++++++--------- install-dependencies.sh | 2 +- 2 files changed, 198 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 5622e43..22aff5d 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,16 @@ # otouto The plugin-wielding, multipurpose Telegram bot. -[Public Bot](http://telegram.me/mokubot) | [Official Channel](http://telegram.me/otouto) | [Bot Development Group](http://telegram.me/BotDevelopment) +[Public Bot](http://telegram.me/mokubot) | +[Official Channel](http://telegram.me/otouto) | +[Bot Development Group](http://telegram.me/BotDevelopment) -otouto is a plugin-based, IRC-style bot written in Lua for the [Telegram Bot API](http://core.telegram.org/bots/api). +otouto is a plugin-based, IRC-style bot written in Lua for the +[Telegram Bot API](http://core.telegram.org/bots/api). -otouto (including all plugins and documentation) is free software; you are free to redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3. See **LICENSE** for details. +otouto (including all plugins and documentation) is free software; you are free +to redistribute it and/or modify it under the terms of the GNU Affero General +Public License, version 3. See **LICENSE** for details. **The Manual** @@ -20,40 +25,56 @@ otouto (including all plugins and documentation) is free software; you are free ## Setup To get your bot running as soon as possible, see [Quick start](#quick-start). -otouto uses Lua (5.3 is recommended) and the following Lua libraries: luasocket, luasec, multipart-post, dkjson, and lpeg. If you are using Lua 5.2, luautf8 is also required. It is recommended you install these with Luarocks. This can be done easily on Ubuntu with the `install-dependencies.sh` script. +otouto uses Lua (5.3 is recommended) and the following Lua libraries: luasocket, +luasec, multipart-post, dkjson, and lpeg. If you are using Lua 5.2, luautf8 is +also required. It is recommended you install these with Luarocks. This can be +done easily on Ubuntu with the `install-dependencies.sh` script. -To get started, clone the repository and set the following values in `config.lua`: +To get started, clone the repository and set the following values in +`config.lua`: - `bot_api_key` as your bot authentication token from the BotFather. - `admin` as your Telegram ID. -Some plugins are not enabled by default. If you wish to enable them, add their names (sans file extension) to the `plugins` table in the configuration file. +Some plugins are not enabled by default. If you wish to enable them, add their +names (sans file extension) to the `plugins` table in the configuration file. -When you are ready to start the bot, run the `launch.sh` script. This script will automatically restart the bot five seconds after being stopped. If this behavior is undesired, start the bot manually with `lua main.lua`. +When you are ready to start the bot, run the `launch.sh` script. This script +will automatically restart the bot five seconds after being stopped. If this +behavior is undesired, start the bot manually with `lua main.lua`. -To stop the bot, send "/halt" through Telegram. You can exit with Ctrl-C (or two Ctrl-C if using `launch.sh`), but this is not recommended as it risks data loss. +To stop the bot, send "/halt" through Telegram. You can exit with Ctrl-C (or two +Ctrl-C if using `launch.sh`), but this is not recommended as it risks data loss. -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 and/or other configuration values not set by default. See [Configuration](#configuration) for details. +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 and/or other configuration values not set by +default. See [Configuration](#configuration) for details. ### Quick start 1. Clone the repository. `git clone http://otou.to/code otouto` -2. Install dependencies: Lua and the following Lua libs: luasocket, luasec, multipart-post, dkjson, and lpeg.† +2. Install dependencies: Lua and the following Lua libs: luasocket, luasec, +multipart-post, dkjson, and lpeg.† 3. Add your bot token and Telegram ID to `config.lua`. 4. Start the bot with `./launch.sh`. -**†** On Ubuntu, this can be done easily with the `install-dependencies.sh` script. +**†** On Ubuntu, this can be done easily with the `install-dependencies.sh` +script. ## Configuration -otouto is configured in the `config.lua` file. It is the single point of configuration for the bot, and contains any necessary user-specific variables, such as API keys, custom error messages, and enabled plugins. +otouto is configured in the `config.lua` file. It is the single point of +configuration for the bot, and contains any necessary user-specific variables, +such as API keys, custom error messages, and enabled plugins. -This section includes an exhaustive list of possible configuration values for otouto and official plugins. +This section includes an exhaustive list of possible configuration values for +otouto and official plugins. ### Bot configuration values | Name | Default | Description | |:--------------|:--------|:---------------------------------------------------| -| `bot_api_key` | `""` | Telegram bot API token. | +| `bot_api_key` | nil | Telegram bot API token. | | `admin` | nil | Telegram ID of the bot owner. | | `log_chat` | nil | Telegram ID of the recipient for error messages. | | `cmd_pat` | `"/"` | Character (or string) to be used for bot commands. | @@ -61,7 +82,8 @@ This section includes an exhaustive list of possible configuration values for ot | `about_text` | ... | Informational text to be returned by /about. | #### Error messages -These are the generic error messages used by most plugins. These belong in a table named `errors`. +These are the generic error messages used by most plugins. These belong in a +table named `errors`. | Name | Default | |:-------------|:----------------------------------| @@ -72,7 +94,8 @@ These are the generic error messages used by most plugins. These belong in a tab | `syntax` | `"Invalid syntax."` | #### Plugins table -This table is an array of the names of enabled plugins. To enable a plugin, add its name to the list. +This table is an array of the names of enabled plugins. To enable a plugin, add +its name to the list. ### Plugin configuration values @@ -92,7 +115,9 @@ This table is an array of the names of enabled plugins. To enable a plugin, add | `hackernews_interval` | The lifespan, in minutes, for each set of results hackernews.lua before refreshing. | | `hackernews_onstart` | Whether hackernews.lua should fetch articles at load (rather than waiting for demand). | -Some plugins have many configuration values which warrant their own section of the configuration file. That section will be the name of the plugin, without the file extension. They are listed below. +Some plugins have many configuration values which warrant their own section of +the configuration file. That section will be the name of the plugin, without the +file extension. They are listed below. #### remind.lua @@ -113,13 +138,24 @@ Some plugins have many configuration values which warrant their own section of t | `response` | `"I don't know what to say to that."` | Generic response for when the API has no response. | #### greetings.lua -The `greetings` table is a list of custom responses for the greetings plugin. Each value is an array of triggers, and the key for that array is the response. The default values are inserted by the greetings plugin if there is no user configuration. In the responses, `#NAME` is replaced with the user's name or nickname. The bot's name is automatically appended to all triggers. Triggers are not case sensitive. +The `greetings` table is a list of custom responses for the greetings plugin. +Each value is an array of triggers, and the key for that array is the response. +The default values are inserted by the greetings plugin if there is no user +configuration. In the responses, `#NAME` is replaced with the user's name or +nickname. The bot's name is automatically appended to all triggers. Triggers are +not case sensitive. #### reactions.lua -The `reactions` table is also a list of custom responses, for the reactions plugin. Each value is a key/value pair, where the key is the trigger, and the value is the reaction. The reactions plugin differs from the greetings plugin by how it is triggered: A reaction command must be at the beginning or end of a line. Reactions may be formatted with HTML. Configuration values should be pre-escaped. +The `reactions` table is also a list of custom responses, for the reactions +plugin. Each value is a key/value pair, where the key is the trigger, and the +value is the reaction. The reactions plugin differs from the greetings plugin by +how it is triggered: A reaction command must be at the beginning or end of a +line. Reactions may be formatted with HTML. Configuration values should be +pre-escaped. ## Control plugins -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 | |:----------------|:-----------|:---------------------------------------------------| @@ -131,13 +167,28 @@ Some plugins are designed to be used by the bot's owner. Here are some examples, | `luarun.lua` | /lua | Executes Lua commands in the bot's environment. | ## Group Administration -The administration plugin enables self-hosted, single-realm group administration, supporting both normal groups and supergroups whch are owned by the bot owner. This works by sending TCP commands to an instance of tg running on the owner's account. +The administration plugin enables self-hosted, single-realm group +administration, supporting both normal groups and supergroups whch are owned by +the bot owner. This works by sending TCP commands to an instance of tg running +on the owner's account. -To get started, compile the `test` branch of [tg-cli](http://github.com/vysheng/tg). On Ubuntu and Debian, this can be done easily with the `tg-install.sh` script. +To get started, compile the `test` branch of +[tg-cli](http://github.com/vysheng/tg). On Ubuntu and Debian, this can be done +easily with the `tg-install.sh` script. -Once the compilation is finished, enable the `administration` plugin in your config file. 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 compilation is finished, enable the `administration` plugin in your +config file. 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? | |:------------|:------------------------------------------------|:----------|:----------| @@ -183,7 +234,8 @@ Internal commands can only be run within an administrated group. | 4 | Administrator | Can globally ban/unban users, promote/demote governors. | Global | | 5 | Owner | Can add/remove groups, broadcast, promote/demote administrators. | Global | -Obviously, each greater rank inherits the privileges of the lower, positive ranks. +Obviously, each greater rank inherits the privileges of the lower, positive +ranks. ### Flags @@ -197,7 +249,13 @@ Obviously, each greater rank inherits the privileges of the lower, positive rank | 6 | antihammer | Allows globally-banned users to enter a group. | #### antiflood -antiflood (flag 5) provides a system of automatic flood protection by removing users who post too much. It is entirely configurable by a group's governor, an administrator, or the bot owner. For each message to a particular group, a user is awarded a certain number of "points". The number of points is different for each message type. When the user reaches 100 points, he is removed. Points are reset each minute. In this way, if a user posts twenty messages within one minute, he is removed. +antiflood (flag 5) provides a system of automatic flood protection by removing +users who post too much. It is entirely configurable by a group's governor, an +administrator, or the bot owner. For each message to a particular group, a user +is awarded a certain number of "points". The number of points is different for +each message type. When the user reaches 100 points, he is removed. Points are +reset each minute. In this way, if a user posts twenty messages within one +minute, he is removed. **Default antiflood values:** @@ -213,7 +271,10 @@ antiflood (flag 5) provides a system of automatic flood protection by removing u | video | 10 | | sticker | 20 | -Additionally, antiflood can be configured to automatically ban a user after he has been automatically kicked from a single group a certain number of times in one day. This is configurable as the antiflood value `autoban` and is set to three by default. +Additionally, antiflood can be configured to automatically ban a user after he +has been automatically kicked from a single group a certain number of times in +one day. This is configurable as the antiflood value `autoban` and is set to +three by default. ## List of plugins @@ -264,9 +325,12 @@ Additionally, antiflood can be configured to automatically ban a user after he h | `catfact.lua` | /catfact | Returns a fact about cats. | ## Plugins -otouto uses a robust plugin system, similar to yagop's [Telegram-Bot](http://github.com/yagop/telegram-bot). +otouto uses a robust plugin system, similar to yagop's +[Telegram-Bot](http://github.com/yagop/telegram-bot). -Most plugins are intended for public use, but a few are for other purposes, like those for [use by the bot's owner](#control-plugins). See [here](#list-of-plugins) for a list of plugins. +Most plugins are intended for public use, but a few are for other purposes, like +those for [use by the bot's owner](#control-plugins). See +[here](#list-of-plugins) for a list of plugins. There are five standard plugin components. @@ -283,26 +347,48 @@ There are five standard plugin components. | `help_word` | Keyword for command-specific help. Generated if absent. | -No component is required, but some depend on others. For example, `action` will never be run if there's no `triggers`, and `doc` will never be seen if there's no `command`. +No component is required, but some depend on others. For example, `action` will +never be run if there's no `triggers`, and `doc` will never be seen if there's +no `command`. If a plugin's `action` returns `true`, `on_msg_receive` will continue its loop. -When an action or cron function fails, the exception is caught and passed to the `handle_exception` utilty and is either printed to the console or send to the chat/channel defined in `log_chat` in config.lua. +When an action or cron function fails, the exception is caught and passed to the +`handle_exception` utilty and is either printed to the console or send to the +chat/channel defined in `log_chat` in config.lua. -The `panoptic` value is a boolean (or nil; its absence means false) to state whether the plugin should be included in the `panoptic_plugins` table. Plugins in this table are the only plugins whose triggers are checked against a message's text if that message is forwarded or from a blacklisted user. +The `panoptic` value is a boolean (or nil; its absence means false) to state +whether the plugin should be included in the `panoptic_plugins` table. Plugins +in this table are the only plugins whose triggers are checked against a +message's text if that message is forwarded or from a blacklisted user. -Interactions with the bot API are straightforward. See the [Bindings section](#bindings) for details. +Interactions with the bot API are straightforward. See the +[Bindings section](#bindings) for details. -Several functions used in multiple plugins are defined in utilities.lua. Refer to that file for usage and documentation. +Several functions used in multiple plugins are defined in utilities.lua. Refer +to that file for usage and documentation. ## Bindings -Calls to the Telegram bot API are performed with the `bindings.lua` file through the multipart-post library. otouto's bindings file supports all standard API methods and all arguments. Its main function, `bindings.request`, accepts three arguments: `method`, `parameters`, `file`. Before using it, initialize the bindings module with its `init` function, passing your bot token as the argument. +Calls to the Telegram bot API are performed with the `bindings.lua` file through +the multipart-post library. otouto's bindings file supports all standard API +methods and all arguments. Its main function, `bindings.request`, accepts three +arguments: `method`, `parameters`, `file`. Before using it, initialize the +bindings module with its `init` function, passing your bot token as the +argument. -`method` is the name of the API method. `parameters` (optional) is a table of key/value pairs of the method's parameters to be sent with the method. `file` (super-optional) is a table of a single key/value pair, where the key is the name of the parameter and the value is the filename (if these are included in `parameters` instead, otouto will attempt to send the filename as a file ID). +`method` is the name of the API method. `parameters` (optional) is a table of +key/value pairs of the method's parameters to be sent with the method. `file` +(super optional) is a table of a single key/value pair, where the key is the +name of the parameter and the value is the filename (if these are included in +`parameters` instead, otouto will attempt to send the filename as a file ID). -Additionally, any method can be called as a key in the `bindings` table (for example, `bindings.getMe`). The `bindings.gen` function (which is also the __index function in its metatable) will forward its arguments to `bindings.request` in their proper form. In this way, the following two function calls are equivalent: +Additionally, any method can be called as a key in the `bindings` table +(for example, `bindings.getMe`). The `bindings.gen` function (which is also the +`__index` function in its metatable) will forward its arguments to +`bindings.request` in their proper form. In this way, the following two function +calls are equivalent: -``` +```lua bindings.request( 'sendMessage', { @@ -323,32 +409,54 @@ bindings.sendMessage{ } ``` -Furthermore, `utilities.lua` provides two "shortcut" functions to mimic the behavior of otouto's old bindings: `send_message` and `send_reply`. `send_message` accepts these arguments: `self`, `chat_id`, `text`, `disable_web_page_preview`, `reply_to_message_id`, `use_markdown`. The following function call is equivalent to the two above: +Furthermore, `utilities.lua` provides two "shortcut" functions to mimic the +behavior of otouto's old bindings: `send_message` and `send_reply`. +`send_message` accepts these arguments: `self`, `chat_id`, `text`, +`disable_web_page_preview`, `reply_to_message_id`, `use_markdown`. The following +function call is equivalent to the two above: -``` +```lua utilities.send_message(987654321, 'Quick brown fox.', false, 54321, true) ``` Uploading a file for the `sendPhoto` method would look like this: -``` +```lua bindings.sendPhoto({ chat_id = 987654321 }, { photo = 'dankmeme.jpg' } ) ``` and using `sendPhoto` with a file ID would look like this: -``` -bindings.sendPhoto{ chat_id = 987654321, photo = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789' } +```lua +bindings.sendPhoto{ + chat_id = 987654321, + photo = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789' +} ``` -Upon success, bindings will return the deserialized result from the API. Upon failure, it will return false and the result. In the case of a connection error, it will return two false values. If an invalid method name is given, bindings will throw an exception. This is to mimic the behavior of more conventional bindings as well as to prevent "silent errors". +Upon success, bindings will return the deserialized result from the API. Upon +failure, it will return false and the result. In the case of a connection error, +it will return two false values. If an invalid method name is given, bindings +will throw an exception. This is to mimic the behavior of more conventional +bindings as well as to prevent "silent errors". ## Database -otouto doesn't use one. This isn't because of dedication to lightweightedness or some clever design choice. Interfacing with databases through Lua is never a simple, easy-to-learn process. As one of the goals of otouto is that it should be a bot which is easy to write plugins for, our approach to storing data is to treat our datastore like any ordinary Lua data structure. The "database" is a table accessible in the `database` value of the bot instance (usually `self.database`), and is saved as a JSON-encoded plaintext file each hour, or when the bot is told to halt. This way, keeping and interacting with persistent data is no different than interacting with a Lua table -- with one exception: Keys in tables used as associative arrays must not be numbers. If the index keys are too sparse, the JSON encoder/decoder will either change them to keys or throw an error. +otouto doesn't use one. This isn't because of dedication to lightweightedness or +some clever design choice. Interfacing with databases through Lua is never a +simple, easy-to-learn process. As one of the goals of otouto is that it should +be a bot which is easy to write plugins for, our approach to storing data is to +treat our datastore like any ordinary Lua data structure. The "database" is a +table accessible in the `database` value of the bot instance (usually +`self.database`), and is saved as a JSON-encoded plaintext file each hour, or +when the bot is told to halt. This way, keeping and interacting with persistent +data is no different than interacting with a Lua table -- with one exception: +Keys in tables used as associative arrays must not be numbers. If the index keys +are too sparse, the JSON encoder/decoder will either change them to keys or +throw an error. Alone, the database will have this structure: -``` +```lua { users = { ["55994550"] = { @@ -367,19 +475,27 @@ Alone, the database will have this structure: } ``` -`database.users` will store user information (usernames, IDs, etc) when the bot sees the user. Each table's key is the user's ID as a string. +`database.users` will store user information (usernames, IDs, etc) when the bot +sees the user. Each table's key is the user's ID as a string. `database.userdata` is meant to store miscellanea from various plugins. -`database.version` stores the last bot version that used it. This is to simplify migration to the next version of the bot an easy, automatic process. +`database.version` stores the last bot version that used it. This is to simplify +migration to the next version of the bot an easy, automatic process. -Data from other plugins is usually saved in a table with the same name of that plugin. For example, administration.lua stores data in `database.administration`. +Data from other plugins is usually saved in a table with the same name of that +plugin. For example, administration.lua stores data in +`database.administration`. ## Output style -otouto plugins should maintain a consistent visual style in their output. This provides a recognizable and comfortable user experience. +otouto plugins should maintain a consistent visual style in their output. This +provides a recognizable and comfortable user experience. ### Titles -Title lines should be **bold**, including any names and trailing punctuation (such as colons). The exception to this rule is if the title line includes a query, which should be _italic_. It is also acceptable to have a link somewhere inside a title, usually within parentheses. eg: +Title lines should be **bold**, including any names and trailing punctuation +(such as colons). The exception to this rule is if the title line includes a +query, which should be _italic_. It is also acceptable to have a link somewhere +inside a title, usually within parentheses. eg: > **Star Wars: Episode IV - A New Hope (1977)** > @@ -388,7 +504,8 @@ Title lines should be **bold**, including any names and trailing punctuation (su > **Changelog for otouto (**[Github](http://github.com/topkecleon/otouto)**):** ### Lists -Numerated lists should be done with the number and its following punctuation bolded. Unnumbered lists should use the bullet character ( • ). eg: +Numerated lists should be done with the number and its following punctuation +bolded. Unnumbered lists should use the bullet character ( • ). eg: > **1.** Life as a quick brown fox. > @@ -401,22 +518,44 @@ and > • The art of jumping over lazy dogs. ### Links -Always name your links. Even then, use them with discretion. Excessive links make a post look messy. Links are reasonable when a user may want to learn more about something, but should be avoided when all desirable information is provided. One appropriate use of linking is to provide a preview of an image, as xkcd.lua and apod.lua do. +Always name your links. Even then, use them with discretion. Excessive links +make a post look messy. Links are reasonable when a user may want to learn more +about something, but should be avoided when all desirable information is +provided. One appropriate use of linking is to provide a preview of an image, as +xkcd.lua and apod.lua do. ### Other Stuff -User IDs should appear within brackets, monospaced (`[123456789]`). Descriptions and information should be in plain text, but "flavor" text should be italic. The standard size for arbitrary lists (such as search results) is eight within a private conversation and four elsewhere. This is a trivial pair of numbers (leftover from the deprecated Google search API), but consistency is noticeable and desirable. +User IDs should appear within brackets, monospaced (`[123456789]`). Descriptions +and information should be in plain text, but "flavor" text should be italic. The +standard size for arbitrary lists (such as search results) is eight within a +private conversation and four elsewhere. This is a trivial pair of numbers +(leftover from the deprecated Google search API), but consistency is noticeable +and desirable. ## Contributors -Everybody is free to contribute to otouto. If you are interested, you are invited to [fork the repo](http://github.com/topkecleon/otouto/fork) and start making pull requests. If you have an idea and you are not sure how to implement it, open an issue or bring it up in the [Bot Development group](http://telegram.me/BotDevelopment). +Everybody is free to contribute to otouto. If you are interested, you are +invited to [fork the repo](http://github.com/topkecleon/otouto/fork) and start +making pull requests. If you have an idea and you are not sure how to implement +it, open an issue or bring it up in the +[Bot Development group](http://telegram.me/BotDevelopment). -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:drew@otou.to). +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:drew@otou.to). [List of contributors.](https://github.com/topkecleon/otouto/graphs/contributors) -There are a a few ways to contribute if you are not a programmer. For one, your feedback is always appreciated. Drop me a line on Telegram or on Twitter. Secondly, we are always looking for new ideas for plugins. Most new plugins start with community input. Feel free to suggest them on Github or in the Bot Dev group. You can also donate Bitcoin to the following address: +There are a a few ways to contribute if you are not a programmer. For one, your +feedback is always appreciated. Drop me a line on Telegram or on Twitter. +Secondly, we are always looking for new ideas for plugins. Most new plugins +start with community input. Feel free to suggest them on Github or in the Bot +Dev group. You can also donate Bitcoin to the following address: `1BxegZJ73hPu218UrtiY8druC7LwLr82gS` -Contributions are appreciated in all forms. Monetary contributions will go toward server costs. Donators will be eternally honored (at their discretion) on this page. +Contributions are appreciated in all forms. Monetary contributions will go +toward server costs. Donators will be eternally honored (at their discretion) on +this page. | Donators (in chronological order) | |:----------------------------------------------| diff --git a/install-dependencies.sh b/install-dependencies.sh index 458d2c8..0b31eb1 100755 --- a/install-dependencies.sh +++ b/install-dependencies.sh @@ -14,7 +14,7 @@ fi echo "This script is intended for Ubuntu. It may work in Debian." echo "This script will request root privileges to install the following packages:" echo "lua$luaver liblua$luaver-dev git libssl-dev fortune-mod fortunes unzip make" -echo "It will also request root privileges to install Luarocks to to /usr/local/" +echo "It will also request root privileges to install Luarocks to /usr/local/" echo "along with the following rocks:" echo $rocklist echo "Press enter to continue. Use Ctrl-C to exit." From 331510694f20b28276f553a0d714c9ed4e3b659d Mon Sep 17 00:00:00 2001 From: topkecleon Date: Fri, 9 Sep 2016 05:08:39 -0400 Subject: [PATCH 7/9] address #80 --- otouto/plugins/gImages.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/otouto/plugins/gImages.lua b/otouto/plugins/gImages.lua index 0d897b0..7ad0271 100644 --- a/otouto/plugins/gImages.lua +++ b/otouto/plugins/gImages.lua @@ -57,9 +57,9 @@ function gImages:action(msg, config) if msg.text:match('nsfw') then - utilities.send_reply('*NSFW*\n'..msg, output) + utilities.send_message(msg, '*NSFW*\n'..output, true, msg.message_id, true) else - utilities.send_message(msg.chat.id, output, false, nil, true) + utilities.send_message(msg, output, false, msg.message_id, true) end end From 4067bef4737a0038f1b4a2d68127ac453e12a6c0 Mon Sep 17 00:00:00 2001 From: topkecleon Date: Fri, 9 Sep 2016 05:13:20 -0400 Subject: [PATCH 8/9] further improvements to a dead plugin --- otouto/plugins/gImages.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/otouto/plugins/gImages.lua b/otouto/plugins/gImages.lua index 7ad0271..85eccd2 100644 --- a/otouto/plugins/gImages.lua +++ b/otouto/plugins/gImages.lua @@ -18,6 +18,8 @@ function gImages:init(config) 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' gImages.search_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 + -- Put this up here in case config changes after triggers are generated. + gImages.nsfw_trigger = '^' .. config.cmd_pat .. 'insfw' end gImages.command = 'image ' @@ -56,7 +58,7 @@ function gImages:action(msg, config) local output = '[' .. img_title .. '](' .. img_url .. ')' - if msg.text:match('nsfw') then + if msg.text:match(gImages.nsfw_trigger) then utilities.send_message(msg, '*NSFW*\n'..output, true, msg.message_id, true) else utilities.send_message(msg, output, false, msg.message_id, true) From 4a657dc7a04731e750b1063f656b3e6ffe31e120 Mon Sep 17 00:00:00 2001 From: topkecleon Date: Fri, 9 Sep 2016 05:15:00 -0400 Subject: [PATCH 9/9] ^ --- otouto/plugins/gImages.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/otouto/plugins/gImages.lua b/otouto/plugins/gImages.lua index 85eccd2..0d0a16f 100644 --- a/otouto/plugins/gImages.lua +++ b/otouto/plugins/gImages.lua @@ -58,7 +58,7 @@ function gImages:action(msg, config) local output = '[' .. img_title .. '](' .. img_url .. ')' - if msg.text:match(gImages.nsfw_trigger) then + if msg.text_lower:match(gImages.nsfw_trigger) then utilities.send_message(msg, '*NSFW*\n'..output, true, msg.message_id, true) else utilities.send_message(msg, output, false, msg.message_id, true)