otouto 3.14
All help messages and many other things moved from markdown to html. Eventually, I'd like only things made from user input to use markdown. cats.lua, rmspic.lua, and dilbert.lua moved to sendPhoto with URL. xkcd.lua and apod.lua not moved to retain formatting. Probably a lot of other stuff that I forget about. I should commit more often.
This commit is contained in:
parent
bc6727275c
commit
9f760114bd
@ -67,7 +67,7 @@ Send /help to get started.
|
|||||||
max_reminders_private = 50
|
max_reminders_private = 50
|
||||||
},
|
},
|
||||||
|
|
||||||
chatter = {
|
cleverbot = {
|
||||||
cleverbot_api = 'https://brawlbot.tk/apis/chatter-bot-api/cleverbot.php?text=',
|
cleverbot_api = 'https://brawlbot.tk/apis/chatter-bot-api/cleverbot.php?text=',
|
||||||
connection = 'I don\'t feel like talking right now.',
|
connection = 'I don\'t feel like talking right now.',
|
||||||
response = 'I don\'t know what to say to that.'
|
response = 'I don\'t know what to say to that.'
|
||||||
@ -113,6 +113,9 @@ Send /help to get started.
|
|||||||
-- Conversation, group, or channel for kick/ban notifications.
|
-- Conversation, group, or channel for kick/ban notifications.
|
||||||
-- Defaults to config.log_chat if left empty.
|
-- Defaults to config.log_chat if left empty.
|
||||||
log_chat = nil,
|
log_chat = nil,
|
||||||
|
-- Default autoban setting.
|
||||||
|
-- A user is banned after being autokicked this many times in a day.
|
||||||
|
autoban = 3,
|
||||||
-- Default antiflood values.
|
-- Default antiflood values.
|
||||||
antiflood = {
|
antiflood = {
|
||||||
text = 5,
|
text = 5,
|
||||||
|
@ -5,19 +5,7 @@
|
|||||||
See the "Bindings" section of README.md for usage information.
|
See the "Bindings" section of README.md for usage information.
|
||||||
|
|
||||||
Copyright 2016 topkecleon <drew@otou.to>
|
Copyright 2016 topkecleon <drew@otou.to>
|
||||||
|
This code is licensed under the GNU AGPLv3. See /LICENSE for details.
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of the GNU Affero General Public License version 3 as
|
|
||||||
published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program; if not, write to the Free Software Foundation,
|
|
||||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
local bindings = {}
|
local bindings = {}
|
||||||
@ -25,7 +13,7 @@ local bindings = {}
|
|||||||
local https = require('ssl.https')
|
local https = require('ssl.https')
|
||||||
local json = require('dkjson')
|
local json = require('dkjson')
|
||||||
local ltn12 = require('ltn12')
|
local ltn12 = require('ltn12')
|
||||||
local mp_encode = require('multipart-post').encode
|
local mp = require('multipart-post')
|
||||||
|
|
||||||
function bindings.init(token)
|
function bindings.init(token)
|
||||||
bindings.BASE_URL = 'https://api.telegram.org/bot' .. token .. '/'
|
bindings.BASE_URL = 'https://api.telegram.org/bot' .. token .. '/'
|
||||||
@ -58,7 +46,7 @@ function bindings.request(method, parameters, file)
|
|||||||
parameters = {''}
|
parameters = {''}
|
||||||
end
|
end
|
||||||
local response = {}
|
local response = {}
|
||||||
local body, boundary = mp_encode(parameters)
|
local body, boundary = mp.encode(parameters)
|
||||||
local success, code = https.request{
|
local success, code = https.request{
|
||||||
url = bindings.BASE_URL .. method,
|
url = bindings.BASE_URL .. method,
|
||||||
method = 'POST',
|
method = 'POST',
|
||||||
@ -79,8 +67,9 @@ function bindings.request(method, parameters, file)
|
|||||||
return false, false
|
return false, false
|
||||||
elseif result.ok then
|
elseif result.ok then
|
||||||
return result
|
return result
|
||||||
|
elseif result.description == 'Method not found' then
|
||||||
|
error(method .. ': Method not found.')
|
||||||
else
|
else
|
||||||
assert(result.description ~= 'Method not found', method .. ': Method not found.')
|
|
||||||
return false, result
|
return false, result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,26 +3,14 @@
|
|||||||
The heart and sole of otouto, ie the init and main loop.
|
The heart and sole of otouto, ie the init and main loop.
|
||||||
|
|
||||||
Copyright 2016 topkecleon <drew@otou.to>
|
Copyright 2016 topkecleon <drew@otou.to>
|
||||||
|
This code is licensed under the GNU AGPLv3. See /LICENSE for details.
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of the GNU Affero General Public License version 3 as
|
|
||||||
published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program; if not, write to the Free Software Foundation,
|
|
||||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
local bot = {}
|
local bot = {}
|
||||||
local bindings -- Bot API bindings.
|
local bindings -- Bot API bindings.
|
||||||
local utilities -- Miscellaneous and shared plugins.
|
local utilities -- Miscellaneous and shared plugins.
|
||||||
|
|
||||||
bot.version = '3.13'
|
bot.version = '3.14'
|
||||||
|
|
||||||
-- Function to be run on start and reload.
|
-- Function to be run on start and reload.
|
||||||
function bot:init(config)
|
function bot:init(config)
|
||||||
@ -45,14 +33,11 @@ function bot:init(config)
|
|||||||
self.database = utilities.load_data(self.database_name)
|
self.database = utilities.load_data(self.database_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Migration code 1.12 -> 1.13
|
-- Migration code 1.13 -> 1.14
|
||||||
-- Back to administration global ban list; copy over current blacklist.
|
-- "database.reminders" -> "database.remind"
|
||||||
if self.database.version ~= '3.13' then
|
if self.database.version ~= '3.14' then
|
||||||
if self.database.administration then
|
self.database.remind = self.database.reminders
|
||||||
self.database.administration.globalbans = self.database.administration.globalbans or self.database.blacklist or {}
|
self.database.reminders = nil
|
||||||
utilities.save_data(self.database_name, self.database)
|
|
||||||
self.database = utilities.load_data(self.database_name)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
-- End migration code.
|
-- End migration code.
|
||||||
|
|
||||||
@ -76,7 +61,9 @@ function bot:init(config)
|
|||||||
table.insert(self.plugins, plugin)
|
table.insert(self.plugins, plugin)
|
||||||
if plugin.init then plugin.init(self, config) end
|
if plugin.init then plugin.init(self, config) end
|
||||||
if plugin.panoptic then table.insert(self.panoptic_plugins, plugin) end
|
if plugin.panoptic then table.insert(self.panoptic_plugins, plugin) end
|
||||||
if plugin.doc then plugin.doc = '```\n'..plugin.doc..'\n```' end
|
if plugin.doc then
|
||||||
|
plugin.doc = '<pre>'..utilities.html_escape(plugin.doc)..'</pre>'
|
||||||
|
end
|
||||||
if not plugin.triggers then plugin.triggers = {} end
|
if not plugin.triggers then plugin.triggers = {} end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -129,13 +116,11 @@ function bot:on_msg_receive(msg, config)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Support deep linking.
|
-- Support deep linking.
|
||||||
if msg.text:match('^'..config.cmd_pat..'start .+') then
|
if msg.text:match('^/start .+') then
|
||||||
msg.text = config.cmd_pat .. utilities.input(msg.text)
|
msg.text = config.cmd_pat .. utilities.input(msg.text)
|
||||||
msg.text_lower = msg.text:lower()
|
msg.text_lower = msg.text:lower()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- If the message is forwarded or comes from a blacklisted yser,
|
|
||||||
|
|
||||||
-- Do the thing.
|
-- Do the thing.
|
||||||
for _, plugin in ipairs(plugint) do
|
for _, plugin in ipairs(plugint) do
|
||||||
for _, trigger in ipairs(plugin.triggers) do
|
for _, trigger in ipairs(plugin.triggers) do
|
||||||
@ -153,18 +138,14 @@ function bot:on_msg_receive(msg, config)
|
|||||||
utilities.send_reply(msg, config.errors.generic)
|
utilities.send_reply(msg, config.errors.generic)
|
||||||
end
|
end
|
||||||
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config.log_chat)
|
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config.log_chat)
|
||||||
msg = nil
|
|
||||||
return
|
return
|
||||||
-- Continue if the return value is true.
|
-- Continue if the return value is true.
|
||||||
elseif result ~= true then
|
elseif result ~= true then
|
||||||
msg = nil
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
msg = nil
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- main
|
-- main
|
||||||
|
@ -5,19 +5,7 @@
|
|||||||
For more documentation, read the the manual (otou.to/rtfm).
|
For more documentation, read the the manual (otou.to/rtfm).
|
||||||
|
|
||||||
Copyright 2016 topkecleon <drew@otou.to>
|
Copyright 2016 topkecleon <drew@otou.to>
|
||||||
|
This code is licensed under the GNU AGPLv3. See /LICENSE for details.
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of the GNU Affero General Public License version 3 as
|
|
||||||
published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program; if not, write to the Free Software Foundation,
|
|
||||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
@ -36,6 +24,10 @@
|
|||||||
target's autokick counter. Added configuration for default flag settings.
|
target's autokick counter. Added configuration for default flag settings.
|
||||||
|
|
||||||
1.13.2 - /desc can now be used with a query.
|
1.13.2 - /desc can now be used with a query.
|
||||||
|
|
||||||
|
1.13.3 - Removed activity array. Group listings sorted alphabetically.
|
||||||
|
Removed unneeded "founded" and "grouptype" variables from group data. Added
|
||||||
|
default autoban setting to config.
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
local drua = require('otouto.drua-tg')
|
local drua = require('otouto.drua-tg')
|
||||||
@ -50,7 +42,6 @@ function administration:init(config)
|
|||||||
self.database.administration = {
|
self.database.administration = {
|
||||||
admins = {},
|
admins = {},
|
||||||
groups = {},
|
groups = {},
|
||||||
activity = {},
|
|
||||||
autokick_timer = os.date('%d'),
|
autokick_timer = os.date('%d'),
|
||||||
globalbans = {}
|
globalbans = {}
|
||||||
}
|
}
|
||||||
@ -66,22 +57,8 @@ function administration:init(config)
|
|||||||
administration.flags = administration.init_flags(config.cmd_pat)
|
administration.flags = administration.init_flags(config.cmd_pat)
|
||||||
administration.init_command(self, config)
|
administration.init_command(self, config)
|
||||||
|
|
||||||
-- Migration 3.13 -> 3.13.1
|
|
||||||
for _, group in pairs(self.database.administration.groups) do
|
|
||||||
for i = 7, 9 do
|
|
||||||
if group.flags[i] == nil then
|
|
||||||
group.flags[i] = config.administration.flags[i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
group.antiflood = group.antiflood or {}
|
|
||||||
for k, v in pairs(config.administration.antiflood) do
|
|
||||||
group.antiflood[k] = group.antiflood[k] or config.administration.antiflood[k]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- End migration
|
|
||||||
|
|
||||||
administration.doc = 'Returns a list of administrated groups.\nUse '..config.cmd_pat..'ahelp for more administrative commands.'
|
|
||||||
administration.command = 'groups [query]'
|
administration.command = 'groups [query]'
|
||||||
|
administration.doc = 'Returns a list of administrated groups.\nUse '..config.cmd_pat..'ahelp for more administrative commands.'
|
||||||
|
|
||||||
-- In the worst case, don't send errors in reply to random messages.
|
-- In the worst case, don't send errors in reply to random messages.
|
||||||
administration.error = false
|
administration.error = false
|
||||||
@ -385,16 +362,15 @@ function administration.init_command(self_, config_)
|
|||||||
local from_id_str = tostring(msg.from.id)
|
local from_id_str = tostring(msg.from.id)
|
||||||
local chat_id_str = tostring(msg.chat.id)
|
local chat_id_str = tostring(msg.chat.id)
|
||||||
|
|
||||||
if rank < 2 then
|
if rank == 0 then -- banned
|
||||||
local from_name = utilities.build_name(msg.from.first_name, msg.from.last_name)
|
|
||||||
|
|
||||||
-- banned
|
|
||||||
if rank == 0 then
|
|
||||||
user.do_kick = true
|
user.do_kick = true
|
||||||
user.dont_unban = true
|
user.dont_unban = true
|
||||||
user.reason = 'banned'
|
user.reason = 'banned'
|
||||||
user.output = 'Sorry, you are banned from ' .. msg.chat.title .. '.'
|
user.output = 'Sorry, you are banned from ' .. msg.chat.title .. '.'
|
||||||
elseif group.flags[2] and ( -- antisquig
|
elseif rank == 1 then
|
||||||
|
local from_name = utilities.build_name(msg.from.first_name, msg.from.last_name)
|
||||||
|
|
||||||
|
if group.flags[2] and ( -- antisquig
|
||||||
msg.text:match(utilities.char.arabic)
|
msg.text:match(utilities.char.arabic)
|
||||||
or msg.text:match(utilities.char.rtl_override)
|
or msg.text:match(utilities.char.rtl_override)
|
||||||
or msg.text:match(utilities.char.rtl_mark)
|
or msg.text:match(utilities.char.rtl_mark)
|
||||||
@ -526,12 +502,12 @@ function administration.init_command(self_, config_)
|
|||||||
drua.rename_chat(msg.chat.id, group.name)
|
drua.rename_chat(msg.chat.id, group.name)
|
||||||
else
|
else
|
||||||
group.name = msg.new_chat_title
|
group.name = msg.new_chat_title
|
||||||
if group.grouptype == 'supergroup' then
|
if msg.chat.type == 'supergroup' then
|
||||||
administration.update_desc(self, msg.chat.id, config)
|
administration.update_desc(self, msg.chat.id, config)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif msg.new_chat_photo then
|
elseif msg.new_chat_photo then
|
||||||
if group.grouptype == 'group' then
|
if msg.chat.type == 'group' then
|
||||||
if rank < (group.flags[9] and 2 or 3) then
|
if rank < (group.flags[9] and 2 or 3) then
|
||||||
drua.set_photo(msg.chat.id, group.photo)
|
drua.set_photo(msg.chat.id, group.photo)
|
||||||
else
|
else
|
||||||
@ -541,7 +517,7 @@ function administration.init_command(self_, config_)
|
|||||||
group.photo = drua.get_photo(msg.chat.id)
|
group.photo = drua.get_photo(msg.chat.id)
|
||||||
end
|
end
|
||||||
elseif msg.delete_chat_photo then
|
elseif msg.delete_chat_photo then
|
||||||
if group.grouptype == 'group' then
|
if msg.chat.type == 'group' then
|
||||||
if rank < (group.flags[9] and 2 or 3) then
|
if rank < (group.flags[9] and 2 or 3) then
|
||||||
drua.set_photo(msg.chat.id, group.photo)
|
drua.set_photo(msg.chat.id, group.photo)
|
||||||
else
|
else
|
||||||
@ -592,16 +568,6 @@ function administration.init_command(self_, config_)
|
|||||||
utilities.send_message(msg.new_chat_member.id, output, true, nil, true)
|
utilities.send_message(msg.new_chat_member.id, output, true, nil, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Last active time for group listing.
|
|
||||||
if msg.text:len() > 0 then
|
|
||||||
for i,v in pairs(self.database.administration.activity) do
|
|
||||||
if v == chat_id_str then
|
|
||||||
table.remove(self.database.administration.activity, i)
|
|
||||||
table.insert(self.database.administration.activity, 1, chat_id_str)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -613,26 +579,28 @@ function administration.init_command(self_, config_)
|
|||||||
command = 'groups \\[query]',
|
command = 'groups \\[query]',
|
||||||
privilege = 1,
|
privilege = 1,
|
||||||
interior = false,
|
interior = false,
|
||||||
doc = 'Returns a list of groups matching the query, or a list of all administrated groups.',
|
doc = 'Returns a list of groups matching a query, or a list of all administrated groups.',
|
||||||
|
|
||||||
action = function(self, msg, _, config)
|
action = function(self, msg, _, config)
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
local search_res = ''
|
local group_list = {}
|
||||||
local grouplist = ''
|
local result_list = {}
|
||||||
for _, chat_id_str in ipairs(self.database.administration.activity) do
|
for _, group in pairs(self.database.administration.groups) do
|
||||||
local group = self.database.administration.groups[chat_id_str]
|
|
||||||
if (not group.flags[1]) and group.link then -- no unlisted or unlinked groups
|
if (not group.flags[1]) and group.link then -- no unlisted or unlinked groups
|
||||||
grouplist = grouplist .. '• [' .. utilities.md_escape(group.name) .. '](' .. group.link .. ')\n'
|
local line = '• [' .. utilities.md_escape(group.name) .. '](' .. group.link .. ')'
|
||||||
|
table.insert(group_list, line)
|
||||||
if input and string.match(group.name:lower(), input:lower()) then
|
if input and string.match(group.name:lower(), input:lower()) then
|
||||||
search_res = search_res .. '• [' .. utilities.md_escape(group.name) .. '](' .. group.link .. ')\n'
|
table.insert(result_list, line)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local output
|
local output
|
||||||
if search_res ~= '' then
|
if #result_list > 0 then
|
||||||
output = '*Groups matching* _' .. input .. '_ *:*\n' .. search_res
|
table.sort(result_list)
|
||||||
elseif grouplist ~= '' then
|
output = '*Groups matching* _' .. input:gsub('_', '_\\__') .. '_*:*\n' .. table.concat(result_list, '\n')
|
||||||
output = '*Groups:*\n' .. grouplist
|
elseif #group_list > 0 then
|
||||||
|
table.sort(group_list)
|
||||||
|
output = '*Groups:*\n' .. table.concat(group_list, '\n')
|
||||||
else
|
else
|
||||||
output = 'There are currently no listed groups.'
|
output = 'There are currently no listed groups.'
|
||||||
end
|
end
|
||||||
@ -764,13 +732,17 @@ function administration.init_command(self_, config_)
|
|||||||
doc = 'Returns the group\'s list of rules, or a specific rule.',
|
doc = 'Returns the group\'s list of rules, or a specific rule.',
|
||||||
|
|
||||||
action = function(self, msg, group, config)
|
action = function(self, msg, group, config)
|
||||||
local output
|
local output = ''
|
||||||
local input = utilities.get_word(msg.text_lower, 2)
|
local input = utilities.input(msg.text)
|
||||||
input = tonumber(input)
|
|
||||||
if #group.rules > 0 then
|
if #group.rules > 0 then
|
||||||
if input and group.rules[input] then
|
if input then
|
||||||
output = '*' .. input .. '.* ' .. group.rules[input]
|
for i in input:gmatch('%g+') do
|
||||||
else
|
if group.rules[tonumber(i)] then
|
||||||
|
output = output .. '*' .. i .. '.* ' .. group.rules[tonumber(i)] .. '\n'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if output == '' or not input then
|
||||||
output = '*Rules for ' .. msg.chat.title .. ':*\n'
|
output = '*Rules for ' .. msg.chat.title .. ':*\n'
|
||||||
for i,v in ipairs(group.rules) do
|
for i,v in ipairs(group.rules) do
|
||||||
output = output .. '*' .. i .. '.* ' .. v .. '\n'
|
output = output .. '*' .. i .. '.* ' .. v .. '\n'
|
||||||
@ -958,7 +930,7 @@ function administration.init_command(self_, config_)
|
|||||||
local output = '*MOTD for ' .. msg.chat.title .. ':*\n' .. input
|
local output = '*MOTD for ' .. msg.chat.title .. ':*\n' .. input
|
||||||
utilities.send_message(msg.chat.id, output, true, nil, true)
|
utilities.send_message(msg.chat.id, output, true, nil, true)
|
||||||
end
|
end
|
||||||
if group.grouptype == 'supergroup' then
|
if msg.chat.type == 'supergroup' then
|
||||||
administration.update_desc(self, msg.chat.id, config)
|
administration.update_desc(self, msg.chat.id, config)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -1195,7 +1167,7 @@ Use this command to configure the point values for each message type. When a use
|
|||||||
group.mods[target.id_str] = true
|
group.mods[target.id_str] = true
|
||||||
group.bans[target.id_str] = nil
|
group.bans[target.id_str] = nil
|
||||||
end
|
end
|
||||||
if group.grouptype == 'supergroup' then
|
if msg.chat.type == 'supergroup' then
|
||||||
local chat_member = bindings.getChatMember{ chat_id = msg.chat.id, user_id = target.id }
|
local chat_member = bindings.getChatMember{ chat_id = msg.chat.id, user_id = target.id }
|
||||||
if chat_member and chat_member.result.status == 'member' then
|
if chat_member and chat_member.result.status == 'member' then
|
||||||
drua.channel_set_admin(msg.chat.id, target.id, 2, s)
|
drua.channel_set_admin(msg.chat.id, target.id, 2, s)
|
||||||
@ -1234,7 +1206,7 @@ Use this command to configure the point values for each message type. When a use
|
|||||||
output = output .. target.name .. ' is no longer a moderator.\n'
|
output = output .. target.name .. ' is no longer a moderator.\n'
|
||||||
group.mods[target.id_str] = nil
|
group.mods[target.id_str] = nil
|
||||||
end
|
end
|
||||||
if group.grouptype == 'supergroup' then
|
if msg.chat.type == 'supergroup' then
|
||||||
drua.channel_set_admin(msg.chat.id, target.id, 0, s)
|
drua.channel_set_admin(msg.chat.id, target.id, 0, s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1270,7 +1242,7 @@ Use this command to configure the point values for each message type. When a use
|
|||||||
group.governor = target.id
|
group.governor = target.id
|
||||||
utilities.send_reply(msg, target.name .. ' is the new governor.')
|
utilities.send_reply(msg, target.name .. ' is the new governor.')
|
||||||
end
|
end
|
||||||
if group.grouptype == 'supergroup' then
|
if msg.chat.type == 'supergroup' then
|
||||||
local chat_member = bindings.getChatMember{ chat_id = msg.chat.id, user_id = target.id }
|
local chat_member = bindings.getChatMember{ chat_id = msg.chat.id, user_id = target.id }
|
||||||
if chat_member and chat_member.result.status == 'member' then
|
if chat_member and chat_member.result.status == 'member' then
|
||||||
drua.channel_set_admin(msg.chat.id, target.id, 2)
|
drua.channel_set_admin(msg.chat.id, target.id, 2)
|
||||||
@ -1305,7 +1277,7 @@ Use this command to configure the point values for each message type. When a use
|
|||||||
group.governor = msg.from.id
|
group.governor = msg.from.id
|
||||||
utilities.send_reply(msg, target.name .. ' is no longer the governor.')
|
utilities.send_reply(msg, target.name .. ' is no longer the governor.')
|
||||||
end
|
end
|
||||||
if group.grouptype == 'supergroup' then
|
if msg.chat.type == 'supergroup' then
|
||||||
drua.channel_set_admin(msg.chat.id, target.id, 0)
|
drua.channel_set_admin(msg.chat.id, target.id, 0)
|
||||||
administration.update_desc(self, msg.chat.id, config)
|
administration.update_desc(self, msg.chat.id, config)
|
||||||
end
|
end
|
||||||
@ -1447,7 +1419,7 @@ Use this command to configure the point values for each message type. When a use
|
|||||||
output = output .. target.name .. ' is not an administrator.\n'
|
output = output .. target.name .. ' is not an administrator.\n'
|
||||||
else
|
else
|
||||||
for chat_id, group in pairs(self.database.administration.groups) do
|
for chat_id, group in pairs(self.database.administration.groups) do
|
||||||
if group.grouptype == 'supergroup' then
|
if tonumber(chat_id) < -1000000000000 then
|
||||||
drua.channel_set_admin(chat_id, target.id, 0, s)
|
drua.channel_set_admin(chat_id, target.id, 0, s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1482,43 +1454,41 @@ This would add a group and enable the unlisted flag, antibot, and antiflood.
|
|||||||
elseif group then
|
elseif group then
|
||||||
utilities.send_reply(msg, 'I am already administrating this group.')
|
utilities.send_reply(msg, 'I am already administrating this group.')
|
||||||
else
|
else
|
||||||
local output = 'I am now administrating this group.'
|
self.database.administration.groups[tostring(msg.chat.id)] = {
|
||||||
local flags = {}
|
name = msg.chat.title,
|
||||||
|
photo = drua.get_photo(msg.chat.id),
|
||||||
|
link = drua.export_link(msg.chat.id),
|
||||||
|
governor = msg.from.id,
|
||||||
|
mods = {},
|
||||||
|
bans = {},
|
||||||
|
autoban = config.administration.autoban,
|
||||||
|
autokicks = {},
|
||||||
|
antiflood = {},
|
||||||
|
flags = {},
|
||||||
|
rules = {},
|
||||||
|
tempbans = {}
|
||||||
|
}
|
||||||
|
group = self.database.administration.groups[tostring(msg.chat.id)]
|
||||||
|
for k, v in pairs(config.administration.antiflood) do
|
||||||
|
group.antiflood[k] = config.administration.antiflood[k]
|
||||||
|
end
|
||||||
for i = 1, #administration.flags do
|
for i = 1, #administration.flags do
|
||||||
flags[i] = config.administration.flags[i]
|
group.flags[i] = config.administration.flags[i]
|
||||||
end
|
end
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
|
local output = 'I am now administrating this group.'
|
||||||
if input then
|
if input then
|
||||||
for i in input:gmatch('%g+') do
|
for i in input:gmatch('%g+') do
|
||||||
local n = tonumber(i)
|
local n = tonumber(i)
|
||||||
if n and administration.flags[n] and flags[n] ~= true then
|
if n and administration.flags[n] and group.flags[n] ~= true then
|
||||||
flags[n] = true
|
group.flags[n] = true
|
||||||
output = output .. '\n' .. administration.flags[n].short
|
output = output .. '\n' .. administration.flags[n].short
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.database.administration.groups[tostring(msg.chat.id)] = {
|
|
||||||
mods = {},
|
|
||||||
governor = msg.from.id,
|
|
||||||
bans = {},
|
|
||||||
flags = flags,
|
|
||||||
rules = {},
|
|
||||||
grouptype = msg.chat.type,
|
|
||||||
name = msg.chat.title,
|
|
||||||
link = drua.export_link(msg.chat.id),
|
|
||||||
photo = drua.get_photo(msg.chat.id),
|
|
||||||
founded = os.time(),
|
|
||||||
autokicks = {},
|
|
||||||
autoban = 3,
|
|
||||||
antiflood = {}
|
|
||||||
}
|
|
||||||
for k, v in pairs(config.administration.antiflood) do
|
|
||||||
self.database.administration.groups[tostring(msg.chat.id)].antiflood[k] = config.administration.antiflood[k]
|
|
||||||
end
|
|
||||||
administration.update_desc(self, msg.chat.id, config)
|
administration.update_desc(self, msg.chat.id, config)
|
||||||
table.insert(self.database.administration.activity, tostring(msg.chat.id))
|
|
||||||
utilities.send_reply(msg, output)
|
|
||||||
drua.channel_set_admin(msg.chat.id, self.info.id, 2)
|
drua.channel_set_admin(msg.chat.id, self.info.id, 2)
|
||||||
|
utilities.send_reply(msg, output)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
@ -1537,11 +1507,6 @@ This would add a group and enable the unlisted flag, antibot, and antiflood.
|
|||||||
if self.database.administration.groups[input] then
|
if self.database.administration.groups[input] then
|
||||||
local chat_name = self.database.administration.groups[input].name
|
local chat_name = self.database.administration.groups[input].name
|
||||||
self.database.administration.groups[input] = nil
|
self.database.administration.groups[input] = nil
|
||||||
for i,v in ipairs(self.database.administration.activity) do
|
|
||||||
if v == input then
|
|
||||||
table.remove(self.database.administration.activity, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
output = 'I am no longer administrating _' .. utilities.md_escape(chat_name) .. '_.'
|
output = 'I am no longer administrating _' .. utilities.md_escape(chat_name) .. '_.'
|
||||||
else
|
else
|
||||||
if input == tostring(msg.chat.id) then
|
if input == tostring(msg.chat.id) then
|
||||||
|
@ -11,12 +11,9 @@ apod.command = 'apod [date]'
|
|||||||
|
|
||||||
function apod:init(config)
|
function apod:init(config)
|
||||||
apod.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('apod', true).table
|
apod.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('apod', true).table
|
||||||
apod.doc = [[
|
apod.doc = config.cmd_pat .. [[apod [YYYY-MM-DD]
|
||||||
/apod [YYYY-MM-DD]
|
|
||||||
Returns the Astronomy Picture of the Day.
|
Returns the Astronomy Picture of the Day.
|
||||||
Source: nasa.gov
|
Source: nasa.gov]]
|
||||||
]]
|
|
||||||
apod.doc = apod.doc:gsub('/', config.cmd_pat)
|
|
||||||
apod.base_url = 'https://api.nasa.gov/planetary/apod?api_key=' .. (config.nasa_api_key or 'DEMO_KEY')
|
apod.base_url = 'https://api.nasa.gov/planetary/apod?api_key=' .. (config.nasa_api_key or 'DEMO_KEY')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ function bible:action(msg, config)
|
|||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, bible.doc, true)
|
utilities.send_reply(msg, bible.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -21,11 +21,9 @@ function bing:init(config)
|
|||||||
bing.headers = { ["Authorization"] = "Basic " .. mime.b64(":" .. config.bing_api_key) }
|
bing.headers = { ["Authorization"] = "Basic " .. mime.b64(":" .. config.bing_api_key) }
|
||||||
bing.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
bing.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('bing', true):t('g', true):t('google', true).table
|
:t('bing', true):t('g', true):t('google', true).table
|
||||||
bing.doc = [[
|
bing.doc = [[/bing <query>
|
||||||
/bing <query>
|
|
||||||
Returns the top web results from Bing.
|
Returns the top web results from Bing.
|
||||||
Aliases: /g, /google
|
Aliases: /g, /google]]
|
||||||
]]
|
|
||||||
bing.doc = bing.doc:gsub('/', config.cmd_pat)
|
bing.doc = bing.doc:gsub('/', config.cmd_pat)
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -33,7 +31,7 @@ end
|
|||||||
function bing:action(msg, config)
|
function bing:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, bing.doc, true)
|
utilities.send_reply(msg, bing.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ end
|
|||||||
function calc:action(msg, config)
|
function calc:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, calc.doc, true)
|
utilities.send_reply(msg, calc.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ local cats = {}
|
|||||||
|
|
||||||
local HTTP = require('socket.http')
|
local HTTP = require('socket.http')
|
||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
local bindings = require('otouto.bindings')
|
||||||
|
|
||||||
function cats:init(config)
|
function cats:init(config)
|
||||||
if not config.thecatapi_key then
|
if not config.thecatapi_key then
|
||||||
@ -29,9 +30,7 @@ function cats:action(msg, config)
|
|||||||
end
|
end
|
||||||
|
|
||||||
str = str:match('<img src="(.-)">')
|
str = str:match('<img src="(.-)">')
|
||||||
local output = '[Cat!]('..str..')'
|
bindings.sendPhoto{chat_id = msg.chat.id, photo = str}
|
||||||
|
|
||||||
utilities.send_message(msg.chat.id, output, false, nil, true)
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -16,45 +16,55 @@ The following markdown syntax is supported:
|
|||||||
_italic text_
|
_italic text_
|
||||||
[text](URL)
|
[text](URL)
|
||||||
`inline fixed-width code`
|
`inline fixed-width code`
|
||||||
```pre-formatted fixed-width code block```]]
|
```pre-formatted fixed-width code block```]]
|
||||||
end
|
end
|
||||||
|
|
||||||
function channel:action(msg, config)
|
function channel:action(msg, config)
|
||||||
-- An exercise in using zero early returns. :)
|
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
local output
|
if not input then
|
||||||
if input then
|
utilities.send_reply(msg, channel.doc, 'html')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local chat_id = utilities.get_word(input, 1)
|
local chat_id = utilities.get_word(input, 1)
|
||||||
|
local chat, t = bindings.getChat{chat_id = chat_id}
|
||||||
|
if not chat then
|
||||||
|
utilities.send_reply(msg, 'Sorry, I was unable to retrieve information for that channel.\n`' .. t.description .. '`', true)
|
||||||
|
return
|
||||||
|
elseif chat.result.type ~= 'channel' then
|
||||||
|
utilities.send_reply(msg, 'Sorry, that group does not appear to be a channel.')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local admin_list, t = bindings.getChatAdministrators{ chat_id = chat_id }
|
local admin_list, t = bindings.getChatAdministrators{ chat_id = chat_id }
|
||||||
if admin_list then
|
if not admin_list then
|
||||||
|
utilities.send_reply(msg, 'Sorry, I was unable to retrieve a list of administrators for that channel.\n`' .. t.description .. '`', true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local is_admin = false
|
local is_admin = false
|
||||||
for _, admin in ipairs(admin_list.result) do
|
for _, admin in ipairs(admin_list.result) do
|
||||||
if admin.user.id == msg.from.id then
|
if admin.user.id == msg.from.id then
|
||||||
is_admin = true
|
is_admin = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if is_admin then
|
if not is_admin then
|
||||||
|
utilities.send_reply(msg, 'Sorry, you do not appear to be an administrator for that channel.')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local text = input:match('\n(.+)')
|
local text = input:match('\n(.+)')
|
||||||
if text then
|
if not text then
|
||||||
|
utilities.send_reply(msg, 'Please enter a message to be sent on a new line. Markdown is supported.')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local success, result = utilities.send_message(chat_id, text, true, nil, true)
|
local success, result = utilities.send_message(chat_id, text, true, nil, true)
|
||||||
if success then
|
if success then
|
||||||
output = 'Your message has been sent!'
|
utilities.send_reply(msg, 'Your message has been sent!')
|
||||||
else
|
else
|
||||||
output = 'Sorry, I was unable to send your message.\n`' .. result.description .. '`'
|
utilities.send_reply(msg, 'Sorry, I was unable to send your message.\n`' .. result.description .. '`', true)
|
||||||
end
|
end
|
||||||
else
|
|
||||||
output = 'Please enter a message to be sent. Markdown is supported.'
|
|
||||||
end
|
|
||||||
else
|
|
||||||
output = 'Sorry, you do not appear to be an administrator for that channel.'
|
|
||||||
end
|
|
||||||
else
|
|
||||||
output = 'Sorry, I was unable to retrieve a list of administrators for that channel.\n`' .. t.description .. '`'
|
|
||||||
end
|
|
||||||
else
|
|
||||||
output = channel.doc
|
|
||||||
end
|
|
||||||
utilities.send_reply(msg, output, true)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return channel
|
return channel
|
||||||
|
@ -13,7 +13,7 @@ function cleverbot:init(config)
|
|||||||
'^' .. self.info.first_name:lower() .. ', ',
|
'^' .. self.info.first_name:lower() .. ', ',
|
||||||
'^@' .. self.info.username:lower() .. ', '
|
'^@' .. self.info.username:lower() .. ', '
|
||||||
}
|
}
|
||||||
cleverbot.url = config.chatter.cleverbot_api
|
cleverbot.url = config.cleverbot.cleverbot_api
|
||||||
cleverbot.error = false
|
cleverbot.error = false
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -22,12 +22,12 @@ function cleverbot:action(msg, config)
|
|||||||
local input = msg.text_lower:gsub(cleverbot.name, ''):gsub(cleverbot.name, '')
|
local input = msg.text_lower:gsub(cleverbot.name, ''):gsub(cleverbot.name, '')
|
||||||
local jstr, code = HTTPS.request(cleverbot.url .. URL.escape(input))
|
local jstr, code = HTTPS.request(cleverbot.url .. URL.escape(input))
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_message(msg.chat.id, config.chatter.connection)
|
utilities.send_message(msg.chat.id, config.cleverbot.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
if not data.clever then
|
if not data.clever then
|
||||||
utilities.send_message(msg.chat.id, config.chatter.response)
|
utilities.send_message(msg.chat.id, config.cleverbot.response)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
utilities.send_message(msg.chat.id, data.clever)
|
utilities.send_message(msg.chat.id, data.clever)
|
||||||
|
@ -12,9 +12,10 @@ function commit:init(config)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function commit:action(msg)
|
function commit:action(msg)
|
||||||
|
local output = http.request('http://whatthecommit.com/index.txt') or 'Minor text fixes'
|
||||||
bindings.sendMessage{
|
bindings.sendMessage{
|
||||||
chat_id = msg.chat.id,
|
chat_id = msg.chat.id,
|
||||||
text = '```\n' .. (http.request('http://whatthecommit.com/index.txt')) .. '\n```',
|
text = '```\n' .. output .. '\n```',
|
||||||
parse_mode = 'Markdown'
|
parse_mode = 'Markdown'
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -17,7 +17,7 @@ function currency:action(msg, config)
|
|||||||
|
|
||||||
local input = msg.text:upper()
|
local input = msg.text:upper()
|
||||||
if not input:match('%a%a%a TO %a%a%a') then
|
if not input:match('%a%a%a TO %a%a%a') then
|
||||||
utilities.send_message(msg.chat.id, currency.doc, true, msg.message_id, true)
|
utilities.send_message(msg.chat.id, currency.doc, true, msg.message_id, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ function dice:action(msg)
|
|||||||
|
|
||||||
local input = utilities.input(msg.text_lower)
|
local input = utilities.input(msg.text_lower)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_message(msg.chat.id, dice.doc, true, msg.message_id, true)
|
utilities.send_message(msg.chat.id, dice.doc, true, msg.message_id, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ function dice:action(msg)
|
|||||||
count = 1
|
count = 1
|
||||||
range = input:match('^d?([%d]+)$')
|
range = input:match('^d?([%d]+)$')
|
||||||
else
|
else
|
||||||
utilities.send_message(msg.chat.id, dice.doc, true, msg.message_id, true)
|
utilities.send_message(msg.chat.id, dice.doc, true, msg.message_id, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -30,19 +30,10 @@ function dilbert:action(msg, config)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local strip_filename = '/tmp/' .. input .. '.gif'
|
|
||||||
local strip_file = io.open(strip_filename)
|
|
||||||
if strip_file then
|
|
||||||
strip_file:close()
|
|
||||||
strip_file = strip_filename
|
|
||||||
else
|
|
||||||
local strip_url = str:match('<meta property="og:image" content="(.-)"/>')
|
|
||||||
strip_file = utilities.download_file(strip_url, '/tmp/' .. input .. '.gif')
|
|
||||||
end
|
|
||||||
|
|
||||||
local strip_title = str:match('<meta property="article:publish_date" content="(.-)"/>')
|
local strip_title = str:match('<meta property="article:publish_date" content="(.-)"/>')
|
||||||
|
|
||||||
bindings.sendPhoto({ chat_id = msg.chat.id, caption = strip_title }, { photo = strip_file })
|
local strip_url = str:match('<meta property="og:image" content="(.-)"/>')
|
||||||
|
bindings.sendPhoto{chat_id = msg.chat.id, photo = strip_url, caption = strip_title}
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -10,22 +10,18 @@ function echo:init(config)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function echo:action(msg)
|
function echo:action(msg)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
|
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_message(msg.chat.id, echo.doc, true, msg.message_id, true)
|
utilities.send_message(msg.chat.id, echo.doc, true, msg.message_id, 'html')
|
||||||
else
|
else
|
||||||
local output
|
local output
|
||||||
if msg.chat.type == 'supergroup' then
|
if msg.chat.type == 'supergroup' then
|
||||||
output = utilities.style.enquote('Echo', input)
|
output = '<b>Echo:</b>\n"' .. utilities.html_escape(input) .. '"'
|
||||||
else
|
else
|
||||||
output = utilities.md_escape(utilities.char.zwnj..input)
|
output = utilities.html_escape(utilities.char.zwnj..input)
|
||||||
end
|
end
|
||||||
utilities.send_message(msg.chat.id, output, true, nil, true)
|
utilities.send_message(msg.chat.id, output, true, nil, 'html')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return echo
|
return echo
|
||||||
|
@ -10,7 +10,6 @@ function fortune:init(config)
|
|||||||
not s:match('not found$'),
|
not s:match('not found$'),
|
||||||
'fortune.lua requires the fortune program to be installed.'
|
'fortune.lua requires the fortune program to be installed.'
|
||||||
)
|
)
|
||||||
|
|
||||||
fortune.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('fortune').table
|
fortune.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('fortune').table
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ local HTTPS = require('ssl.https')
|
|||||||
local URL = require('socket.url')
|
local URL = require('socket.url')
|
||||||
local JSON = require('dkjson')
|
local JSON = require('dkjson')
|
||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
local bindings = require('otouto.bindings')
|
||||||
|
|
||||||
function gImages:init(config)
|
function gImages:init(config)
|
||||||
assert(config.google_api_key and config.google_cse_key,
|
assert(config.google_api_key and config.google_cse_key,
|
||||||
@ -32,7 +33,7 @@ function gImages:action(msg, config)
|
|||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, gImages.doc, true)
|
utilities.send_reply(msg, gImages.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -59,13 +60,12 @@ function gImages:action(msg, config)
|
|||||||
local i = math.random(jdat.queries.request[1].count)
|
local i = math.random(jdat.queries.request[1].count)
|
||||||
local img_url = jdat.items[i].link
|
local img_url = jdat.items[i].link
|
||||||
local img_title = jdat.items[i].title
|
local img_title = jdat.items[i].title
|
||||||
local output = '[' .. img_title .. '](' .. img_url .. ')'
|
|
||||||
|
|
||||||
|
|
||||||
if msg.text_lower:match(gImages.nsfw_trigger) then
|
if msg.text_lower:match(gImages.nsfw_trigger) then
|
||||||
|
local output = '[' .. img_title .. '](' .. img_url .. ')'
|
||||||
utilities.send_message(msg.chat.id, '*NSFW*\n'..output, true, msg.message_id, true)
|
utilities.send_message(msg.chat.id, '*NSFW*\n'..output, true, msg.message_id, true)
|
||||||
else
|
else
|
||||||
utilities.send_message(msg.chat.id, output, false, msg.message_id, true)
|
bindings.sendPhoto{chat_id = msg.chat.id, photo = img_url, caption = img_title}
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -19,7 +19,7 @@ end
|
|||||||
function gMaps:action(msg, config)
|
function gMaps:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, gMaps.doc, true)
|
utilities.send_reply(msg, gMaps.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ function hearthstone:action(msg, config)
|
|||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, hearthstone.doc, true)
|
utilities.send_reply(msg, hearthstone.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -20,8 +20,8 @@ function help:action(msg, config)
|
|||||||
end
|
end
|
||||||
for _,plugin in ipairs(self.plugins) do
|
for _,plugin in ipairs(self.plugins) do
|
||||||
if plugin.help_word == input:gsub('^/', '') then
|
if plugin.help_word == input:gsub('^/', '') then
|
||||||
local output = '*Help for* _' .. plugin.help_word .. '_*:*\n' .. plugin.doc
|
local output = '<b>Help for</b> <i>' .. plugin.help_word .. '</i><b>:</b>\n' .. plugin.doc
|
||||||
utilities.send_message(msg.chat.id, output, true, nil, true)
|
utilities.send_message(msg.chat.id, output, true, nil, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -36,14 +36,14 @@ function help:action(msg, config)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.sort(commandlist)
|
table.sort(commandlist)
|
||||||
help.text = '*Available commands:*\n• ' .. config.cmd_pat .. table.concat(commandlist, '\n• '..config.cmd_pat) .. '\nArguments: <required> [optional]'
|
local comlist = '\n• ' .. config.cmd_pat .. table.concat(commandlist, '\n• ' .. config.cmd_pat) .. '\nArguments: <required> [optional]'
|
||||||
help.text = help.text:gsub('%[', '\\[')
|
help.text = '<b>Available commands:</b>' .. utilities.html_escape(comlist)
|
||||||
end
|
end
|
||||||
-- Attempt to send the help message via PM.
|
-- Attempt to send the help message via PM.
|
||||||
-- If msg is from a group, tell the group whether the PM was successful.
|
-- If msg is from a group, tell the group whether the PM was successful.
|
||||||
local res = utilities.send_message(msg.from.id, help.text, true, nil, true)
|
local res = utilities.send_message(msg.from.id, help.text, true, nil, 'html')
|
||||||
if not res then
|
if not res then
|
||||||
utilities.send_reply(msg, 'Please [message me privately](http://telegram.me/' .. self.info.username .. '?start=help) for a list of commands.', true)
|
utilities.send_reply(msg, 'Please <a href="http://telegram.me/' .. self.info.username .. '?start=help">message me privately</a> for a list of commands.', 'html')
|
||||||
elseif msg.chat.type ~= 'private' then
|
elseif msg.chat.type ~= 'private' then
|
||||||
utilities.send_reply(msg, 'I have sent you the requested information in a private message.')
|
utilities.send_reply(msg, 'I have sent you the requested information in a private message.')
|
||||||
end
|
end
|
||||||
|
@ -16,7 +16,7 @@ function imdb:action(msg, config)
|
|||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, imdb.doc, true)
|
utilities.send_reply(msg, imdb.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ end
|
|||||||
function isup:action(msg, config)
|
function isup:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, isup.doc, true)
|
utilities.send_reply(msg, isup.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -9,19 +9,25 @@ local JSON = require('dkjson')
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function lastfm:init(config)
|
function lastfm:init(config)
|
||||||
assert(config.lastfm_api_key,
|
assert(
|
||||||
|
config.lastfm_api_key,
|
||||||
'lastfm.lua requires a last.fm API key from http://last.fm/api.'
|
'lastfm.lua requires a last.fm API key from http://last.fm/api.'
|
||||||
)
|
)
|
||||||
|
|
||||||
lastfm.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lastfm', true):t('np', true):t('fmset', true).table
|
lastfm.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lastfm', true):t('np', true):t('npfull', true):t('fmset', true).table
|
||||||
lastfm.doc = config.cmd_pat .. [[np [username]
|
lastfm.doc = config.cmd_pat .. [[np [username]
|
||||||
Returns what you are or were last listening to. If you specify a username, info will be returned for that username.
|
Returns what you are or were last listening to. If you specify a username, info will be returned for that username.
|
||||||
|
|
||||||
|
]] .. config.cmd_pat .. [[npfull [username]
|
||||||
|
Works like ]] .. config.cmd_pat .. [[np, but returns more info, differently formatted and including album art, if available.
|
||||||
|
|
||||||
]] .. config.cmd_pat .. [[fmset <username>
|
]] .. config.cmd_pat .. [[fmset <username>
|
||||||
Sets your last.fm username. Otherwise, ]] .. config.cmd_pat .. [[np will use your Telegram username. Use "]] .. config.cmd_pat .. [[fmset --" to delete it.]]
|
Sets your last.fm username. Otherwise, ]] .. config.cmd_pat .. [[np will use your Telegram username. Use "]] .. config.cmd_pat .. [[fmset --" to delete it.]]
|
||||||
end
|
|
||||||
|
|
||||||
lastfm.command = 'lastfm'
|
lastfm.command = 'lastfm'
|
||||||
|
|
||||||
|
lastfm.base_url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key=' .. config.lastfm_api_key .. '&user='
|
||||||
|
end
|
||||||
|
|
||||||
function lastfm:action(msg, config)
|
function lastfm:action(msg, config)
|
||||||
|
|
||||||
@ -29,12 +35,12 @@ function lastfm:action(msg, config)
|
|||||||
local from_id_str = tostring(msg.from.id)
|
local from_id_str = tostring(msg.from.id)
|
||||||
self.database.userdata[from_id_str] = self.database.userdata[from_id_str] or {}
|
self.database.userdata[from_id_str] = self.database.userdata[from_id_str] or {}
|
||||||
|
|
||||||
if string.match(msg.text, '^'..config.cmd_pat..'lastfm') then
|
if string.match(msg.text_lower, '^'..config.cmd_pat..'lastfm') then
|
||||||
utilities.send_message(msg.chat.id, lastfm.doc, true, msg.message_id, true)
|
utilities.send_message(msg.chat.id, lastfm.doc, true, msg.message_id, 'html')
|
||||||
return
|
return
|
||||||
elseif string.match(msg.text, '^'..config.cmd_pat..'fmset') then
|
elseif string.match(msg.text_lower, '^'..config.cmd_pat..'fmset') then
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_message(msg.chat.id, lastfm.doc, true, msg.message_id, true)
|
utilities.send_message(msg.chat.id, lastfm.doc, true, msg.message_id, 'html')
|
||||||
elseif input == '--' or input == utilities.char.em_dash then
|
elseif input == '--' or input == utilities.char.em_dash then
|
||||||
self.database.userdata[from_id_str].lastfm = nil
|
self.database.userdata[from_id_str].lastfm = nil
|
||||||
utilities.send_reply(msg, 'Your last.fm username has been forgotten.')
|
utilities.send_reply(msg, 'Your last.fm username has been forgotten.')
|
||||||
@ -45,8 +51,6 @@ function lastfm:action(msg, config)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key=' .. config.lastfm_api_key .. '&user='
|
|
||||||
|
|
||||||
local username
|
local username
|
||||||
local alert = ''
|
local alert = ''
|
||||||
if input then
|
if input then
|
||||||
@ -62,13 +66,11 @@ function lastfm:action(msg, config)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
url = url .. URL.escape(username)
|
local orig = HTTP.TIMEOUT
|
||||||
|
HTTP.TIMEOUT = 1
|
||||||
|
local jstr, res = HTTP.request(lastfm.base_url .. URL.escape(username))
|
||||||
|
HTTP.TIMEOUT = orig
|
||||||
|
|
||||||
local jstr, res
|
|
||||||
utilities.with_http_timeout(
|
|
||||||
1, function ()
|
|
||||||
jstr, res = HTTP.request(url)
|
|
||||||
end)
|
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(msg, config.errors.connection)
|
utilities.send_reply(msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
@ -80,29 +82,51 @@ function lastfm:action(msg, config)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track
|
local track = jdat.recenttracks.track[1] or jdat.recenttracks.track
|
||||||
if not jdat then
|
if not track then
|
||||||
utilities.send_reply(msg, 'No history for this user.' .. alert)
|
utilities.send_reply(msg, 'No history for this user.' .. alert)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = input or msg.from.first_name
|
local output = utilities.html_escape(input or msg.from.first_name)
|
||||||
output = '🎵 ' .. output
|
if track['@attr'] and track['@attr'].nowplaying then
|
||||||
|
output = output .. ' is currently listening to:'
|
||||||
if jdat['@attr'] and jdat['@attr'].nowplaying then
|
|
||||||
output = output .. ' is currently listening to:\n'
|
|
||||||
else
|
else
|
||||||
output = output .. ' last listened to:\n'
|
output = output .. ' last listened to:'
|
||||||
end
|
end
|
||||||
|
|
||||||
local title = jdat.name or 'Unknown'
|
if msg.text_lower:match('^' .. config.cmd_pat .. 'npfull') then
|
||||||
local artist = 'Unknown'
|
|
||||||
if jdat.artist then
|
output = '<b>' .. utilities.html_escape(output) .. '</b>'
|
||||||
artist = jdat.artist['#text']
|
if track.name and #track.name > 0 then
|
||||||
|
output = output .. '\n🎵 ' .. utilities.html_escape(track.name)
|
||||||
|
else
|
||||||
|
output = output .. '\n🎵 Unknown'
|
||||||
|
end
|
||||||
|
if track.artist and track.artist['#text'] and #track.artist['#text'] > 0 then
|
||||||
|
output = output .. '\n👤 ' .. utilities.html_escape(track.artist['#text'])
|
||||||
|
end
|
||||||
|
if track.album and track.album['#text'] and #track.album['#text'] > 0 then
|
||||||
|
output = output .. '\n💿 ' .. utilities.html_escape(track.album['#text'])
|
||||||
|
end
|
||||||
|
-- album art
|
||||||
|
if track.image and track.image[3] and #track.image[3]['#text'] > 0 then
|
||||||
|
output = '<a href="' .. utilities.html_escape(track.image[3]['#text']) .. '">' .. utilities.char.zwnj .. '</a>' .. output
|
||||||
end
|
end
|
||||||
|
|
||||||
output = output .. title .. ' - ' .. artist .. alert
|
else
|
||||||
utilities.send_message(msg.chat.id, output)
|
|
||||||
|
output = output .. '\n'
|
||||||
|
if track.artist and track.artist['#text'] and #track.artist['#text'] > 0 then
|
||||||
|
output = output .. utilities.html_escape(track.artist['#text']) .. ' - '
|
||||||
|
end
|
||||||
|
output = output .. utilities.html_escape((track.name or 'Unknown'))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
output = output .. alert
|
||||||
|
|
||||||
|
utilities.send_message(msg.chat.id, output, nil, nil, 'html')
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ patterns.doc = [[
|
|||||||
s/<pattern>/<substitution>
|
s/<pattern>/<substitution>
|
||||||
Replace all matches for the given pattern.
|
Replace all matches for the given pattern.
|
||||||
Uses Lua patterns.
|
Uses Lua patterns.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
function patterns:init(config)
|
function patterns:init(config)
|
||||||
patterns.triggers = { config.cmd_pat .. '?s/.-/.-$' }
|
patterns.triggers = { config.cmd_pat .. '?s/.-/.-$' }
|
||||||
@ -18,8 +18,7 @@ function patterns:action(msg)
|
|||||||
if not msg.reply_to_message then return true end
|
if not msg.reply_to_message then return true end
|
||||||
local output = msg.reply_to_message.text
|
local output = msg.reply_to_message.text
|
||||||
if msg.reply_to_message.from.id == self.info.id then
|
if msg.reply_to_message.from.id == self.info.id then
|
||||||
output = output:gsub('Did you mean:\n"', '')
|
output = output:match('^Did you mean:\n"(.+)"$') or output
|
||||||
output = output:gsub('"$', '')
|
|
||||||
end
|
end
|
||||||
local m1, m2 = msg.text:match('^/?s/(.-)/(.-)/?$')
|
local m1, m2 = msg.text:match('^/?s/(.-)/(.-)/?$')
|
||||||
if not m2 then return true end
|
if not m2 then return true end
|
||||||
@ -33,8 +32,8 @@ function patterns:action(msg)
|
|||||||
utilities.send_reply(msg, 'Malformed pattern!')
|
utilities.send_reply(msg, 'Malformed pattern!')
|
||||||
else
|
else
|
||||||
output = utilities.trim(output:sub(1, 4000))
|
output = utilities.trim(output:sub(1, 4000))
|
||||||
output = utilities.style.enquote('Did you mean', output)
|
output = '<b>Did you mean:</b>\n"' .. utilities.html_escape(output) .. '"'
|
||||||
utilities.send_reply(msg.reply_to_message, output, true)
|
utilities.send_reply(msg.reply_to_message, output, 'html')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ function pokedex:action(msg, config)
|
|||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, pokedex.doc, true)
|
utilities.send_reply(msg, pokedex.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ end
|
|||||||
function pgc:action(msg)
|
function pgc:action(msg)
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, pgc.doc, true)
|
utilities.send_reply(msg, pgc.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
input = input .. '\n'
|
input = input .. '\n'
|
||||||
|
@ -14,7 +14,7 @@ function preview:action(msg)
|
|||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, preview.doc, true)
|
utilities.send_reply(msg, preview.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -132,7 +132,8 @@ local puns = {
|
|||||||
"The career of a skier can go downhill very fast.",
|
"The career of a skier can go downhill very fast.",
|
||||||
"In democracy, it's your vote that counts. In feudalism, it's your count that votes.",
|
"In democracy, it's your vote that counts. In feudalism, it's your count that votes.",
|
||||||
"A sea lion is nothing but an ionized seal.",
|
"A sea lion is nothing but an ionized seal.",
|
||||||
"The vegetables from my garden aren't that great. I guess you could say they're mediokra."
|
"The vegetables from my garden aren't that great. I guess you could say they're mediokra.",
|
||||||
|
"Did you hear about the restaurant on the International Space Station? It lacks atmosphere, but the food is out of this world."
|
||||||
}
|
}
|
||||||
|
|
||||||
function pun:action(msg)
|
function pun:action(msg)
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
local reddit = {}
|
local reddit = {}
|
||||||
|
|
||||||
local HTTP = require('socket.http')
|
|
||||||
local URL = require('socket.url')
|
local URL = require('socket.url')
|
||||||
local JSON = require('dkjson')
|
local JSON = require('dkjson')
|
||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
local HTTPS = require('ssl.https')
|
||||||
|
|
||||||
reddit.command = 'reddit [r/subreddit | query]'
|
reddit.command = 'reddit [r/subreddit | query]'
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ function reddit:action(msg, config)
|
|||||||
url = reddit.rall_url .. limit
|
url = reddit.rall_url .. limit
|
||||||
source = '*/r/all*\n'
|
source = '*/r/all*\n'
|
||||||
end
|
end
|
||||||
local jstr, res = HTTP.request(url)
|
local jstr, res = HTTPS.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(msg, config.errors.connection)
|
utilities.send_reply(msg, config.errors.connection)
|
||||||
else
|
else
|
||||||
|
@ -5,26 +5,31 @@ local utilities = require('otouto.utilities')
|
|||||||
remind.command = 'remind <duration> <message>'
|
remind.command = 'remind <duration> <message>'
|
||||||
|
|
||||||
function remind:init(config)
|
function remind:init(config)
|
||||||
self.database.reminders = self.database.reminders or {}
|
self.database.remind = self.database.remind or {}
|
||||||
|
|
||||||
remind.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('remind', true).table
|
remind.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('remind', true).table
|
||||||
|
|
||||||
remind.doc = config.cmd_pat .. [[remind <duration> <message>
|
remind.doc = config.cmd_pat .. [[remind <duration> <message>
|
||||||
Repeats a message after a duration of time, in minutes.
|
Repeats a message after a duration of time, in minutes.
|
||||||
The maximum length of a reminder is %s characters. The maximum duration of a timer is %s minutes. The maximum number of reminders for a group is %s. The maximum number of reminders in private is %s.]]
|
The maximum length of a reminder is %s characters. The maximum duration of a timer is %s minutes. The maximum number of reminders for a group is %s. The maximum number of reminders in private is %s.]]
|
||||||
remind.doc = remind.doc:format(config.remind.max_length, config.remind.max_duration, config.remind.max_reminders_group, config.remind.max_reminders_private)
|
remind.doc = remind.doc:format(
|
||||||
|
config.remind.max_length,
|
||||||
|
config.remind.max_duration,
|
||||||
|
config.remind.max_reminders_group,
|
||||||
|
config.remind.max_reminders_private
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function remind:action(msg, config)
|
function remind:action(msg, config)
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, remind.doc, true)
|
utilities.send_reply(msg, remind.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local duration = tonumber(utilities.get_word(input, 1))
|
local duration = tonumber(utilities.get_word(input, 1))
|
||||||
if not duration then
|
if not duration then
|
||||||
utilities.send_reply(msg, remind.doc, true)
|
utilities.send_reply(msg, remind.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -40,7 +45,7 @@ function remind:action(msg, config)
|
|||||||
elseif utilities.input(input) then
|
elseif utilities.input(input) then
|
||||||
message = utilities.input(input)
|
message = utilities.input(input)
|
||||||
else
|
else
|
||||||
utilities.send_reply(msg, remind.doc, true)
|
utilities.send_reply(msg, remind.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -51,13 +56,13 @@ function remind:action(msg, config)
|
|||||||
|
|
||||||
local chat_id_str = tostring(msg.chat.id)
|
local chat_id_str = tostring(msg.chat.id)
|
||||||
local output
|
local output
|
||||||
self.database.reminders[chat_id_str] = self.database.reminders[chat_id_str] or {}
|
self.database.remind[chat_id_str] = self.database.remind[chat_id_str] or {}
|
||||||
if msg.chat.type == 'private' and utilities.table_size(self.database.reminders[chat_id_str]) >= config.remind.max_reminders_private then
|
if msg.chat.type == 'private' and utilities.table_size(self.database.remind[chat_id_str]) >= config.remind.max_reminders_private then
|
||||||
output = 'Sorry, you already have the maximum number of reminders.'
|
output = 'Sorry, you already have the maximum number of reminders.'
|
||||||
elseif msg.chat.type ~= 'private' and utilities.table_size(self.database.reminders[chat_id_str]) >= config.remind.max_reminders_group then
|
elseif msg.chat.type ~= 'private' and utilities.table_size(self.database.remind[chat_id_str]) >= config.remind.max_reminders_group then
|
||||||
output = 'Sorry, this group already has the maximum number of reminders.'
|
output = 'Sorry, this group already has the maximum number of reminders.'
|
||||||
else
|
else
|
||||||
table.insert(self.database.reminders[chat_id_str], {
|
table.insert(self.database.remind[chat_id_str], {
|
||||||
time = os.time() + (duration * 60),
|
time = os.time() + (duration * 60),
|
||||||
message = message
|
message = message
|
||||||
})
|
})
|
||||||
@ -73,14 +78,14 @@ end
|
|||||||
function remind:cron(config)
|
function remind:cron(config)
|
||||||
local time = os.time()
|
local time = os.time()
|
||||||
-- Iterate over the group entries in the reminders database.
|
-- Iterate over the group entries in the reminders database.
|
||||||
for chat_id, group in pairs(self.database.reminders) do
|
for chat_id, group in pairs(self.database.remind) do
|
||||||
-- Iterate over each reminder.
|
-- Iterate over each reminder.
|
||||||
for k, reminder in pairs(group) do
|
for k, reminder in pairs(group) do
|
||||||
-- If the reminder is past-due, send it and nullify it.
|
-- If the reminder is past-due, send it and nullify it.
|
||||||
-- Otherwise, add it to the replacement table.
|
-- Otherwise, add it to the replacement table.
|
||||||
if time > reminder.time then
|
if time > reminder.time then
|
||||||
local output = utilities.style.enquote('Reminder', reminder.message)
|
local output = '<b>Reminder:</b>\n"' .. utilities.html_escape(reminder.message) .. '"'
|
||||||
local res = utilities.send_message(chat_id, output, true, nil, true)
|
local res = utilities.send_message(chat_id, output, true, nil, 'html')
|
||||||
-- If the message fails to send, save it for later (if enabled in config).
|
-- If the message fails to send, save it for later (if enabled in config).
|
||||||
if res or not config.remind.persist then
|
if res or not config.remind.persist then
|
||||||
group[k] = nil
|
group[k] = nil
|
||||||
|
@ -5,30 +5,22 @@ local bindings = require('otouto.bindings')
|
|||||||
local rms = {}
|
local rms = {}
|
||||||
|
|
||||||
function rms:init(config)
|
function rms:init(config)
|
||||||
|
rms.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('rms').table
|
||||||
|
rms.command = 'rms'
|
||||||
rms.BASE_URL = 'https://rms.sexy/img/'
|
rms.BASE_URL = 'https://rms.sexy/img/'
|
||||||
rms.LIST = {}
|
rms.LIST = {}
|
||||||
local s, r = https.request(rms.BASE_URL)
|
local s, r = https.request(rms.BASE_URL)
|
||||||
if r ~= 200 then
|
if r ~= 200 then
|
||||||
print('Error connecting to rms.sexy.\nrmspic.lua will not be enabled.')
|
print('Error connecting to rms.sexy.\nrmspic.lua will not be enabled.')
|
||||||
return
|
rms.triggers = {}
|
||||||
end
|
end
|
||||||
for link in s:gmatch('<a href=".-%.%a%a%a">(.-)</a>') do
|
for link in s:gmatch('<a href=".-%.%a%a%a">(.-)</a>') do
|
||||||
table.insert(rms.LIST, link)
|
table.insert(rms.LIST, rms.BASE_URL .. link)
|
||||||
end
|
end
|
||||||
rms.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('rms').table
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function rms:action(msg, config)
|
function rms:action(msg, config)
|
||||||
bindings.sendChatAction{ chat_id = msg.chat.id, action = 'upload_photo' }
|
bindings.sendPhoto{chat_id = msg.chat.id, photo = rms.LIST[math.random(#rms.LIST)]}
|
||||||
local choice = rms.LIST[math.random(#rms.LIST)]
|
|
||||||
local filename = '/tmp/' .. choice
|
|
||||||
local image_file = io.open(filename)
|
|
||||||
if image_file then
|
|
||||||
image_file:close()
|
|
||||||
else
|
|
||||||
utilities.download_file(rms.BASE_URL .. choice, filename)
|
|
||||||
end
|
|
||||||
bindings.sendPhoto({ chat_id = msg.chat.id }, { photo = filename })
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return rms
|
return rms
|
||||||
|
@ -22,7 +22,7 @@ function setandget:action(msg, config)
|
|||||||
if msg.text_lower:match('^'..config.cmd_pat..'set') then
|
if msg.text_lower:match('^'..config.cmd_pat..'set') then
|
||||||
|
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_message(msg.chat.id, setandget.doc, true, nil, true)
|
utilities.send_message(msg.chat.id, setandget.doc, true, nil, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ function setandget:action(msg, config)
|
|||||||
local value = utilities.input(input)
|
local value = utilities.input(input)
|
||||||
|
|
||||||
if not name or not value then
|
if not name or not value then
|
||||||
utilities.send_message(msg.chat.id, setandget.doc, true, nil, true)
|
utilities.send_message(msg.chat.id, setandget.doc, true, nil, 'html')
|
||||||
elseif value == '--' or value == '—' then
|
elseif value == '--' or value == '—' then
|
||||||
self.database.setandget[chat_id_str][name] = nil
|
self.database.setandget[chat_id_str][name] = nil
|
||||||
utilities.send_message(msg.chat.id, 'That value has been deleted.')
|
utilities.send_message(msg.chat.id, 'That value has been deleted.')
|
||||||
|
@ -14,7 +14,7 @@ function shout:action(msg)
|
|||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, shout.doc, true)
|
utilities.send_reply(msg, shout.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ local corrected_numbers = {
|
|||||||
function starwars:action(msg, config)
|
function starwars:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, starwars.doc, true)
|
utilities.send_reply(msg, starwars.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ end
|
|||||||
function time:action(msg, config)
|
function time:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, time.doc, true)
|
utilities.send_reply(msg, time.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ end
|
|||||||
function translate:action(msg, config)
|
function translate:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, translate.doc, true)
|
utilities.send_reply(msg, translate.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -39,7 +39,9 @@ function translate:action(msg, config)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
utilities.send_reply(msg.reply_to_message or msg, utilities.style.enquote('Translation', data.text[1]), true)
|
local output = '<b>Translation:</b>\n"' .. utilities.html_escape(data.text[1]) .. '"'
|
||||||
|
|
||||||
|
utilities.send_reply(msg.reply_to_message or msg, output, 'html')
|
||||||
end
|
end
|
||||||
|
|
||||||
return translate
|
return translate
|
||||||
|
@ -11,18 +11,16 @@ urbandictionary.base_url = 'http://api.urbandictionary.com/v0/define?term='
|
|||||||
function urbandictionary:init(config)
|
function urbandictionary:init(config)
|
||||||
urbandictionary.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
urbandictionary.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('urbandictionary', true):t('ud', true):t('urban', true).table
|
:t('urbandictionary', true):t('ud', true):t('urban', true).table
|
||||||
urbandictionary.doc = [[
|
urbandictionary.doc = [[/urbandictionary <query>
|
||||||
/urbandictionary <query>
|
|
||||||
Returns a definition from Urban Dictionary.
|
Returns a definition from Urban Dictionary.
|
||||||
Aliases: /ud, /urban
|
Aliases: /ud, /urban]]
|
||||||
]]
|
|
||||||
urbandictionary.doc = urbandictionary.doc:gsub('/', config.cmd_pat)
|
urbandictionary.doc = urbandictionary.doc:gsub('/', config.cmd_pat)
|
||||||
end
|
end
|
||||||
|
|
||||||
function urbandictionary:action(msg, config)
|
function urbandictionary:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, urbandictionary.doc, true)
|
utilities.send_reply(msg, urbandictionary.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -38,13 +36,13 @@ function urbandictionary:action(msg, config)
|
|||||||
if data.result_type == 'no_results' then
|
if data.result_type == 'no_results' then
|
||||||
output = config.errors.results
|
output = config.errors.results
|
||||||
else
|
else
|
||||||
output = string.format('*%s*\n\n%s\n\n_%s_',
|
output = string.format('<b>%s</b>\n\n%s\n\n<i>%s</i>',
|
||||||
data.list[1].word:gsub('*', '*\\**'),
|
utilities.html_escape(data.list[1].word),
|
||||||
utilities.trim(utilities.md_escape(data.list[1].definition)),
|
utilities.trim(utilities.html_escape(data.list[1].definition)),
|
||||||
utilities.trim((data.list[1].example or '')):gsub('_', '_\\__')
|
utilities.trim(utilities.html_escape(data.list[1].example or ''))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
utilities.send_reply(msg, output, true)
|
utilities.send_reply(msg, output, 'html')
|
||||||
end
|
end
|
||||||
|
|
||||||
return urbandictionary
|
return urbandictionary
|
||||||
|
44
otouto/plugins/wait.lua
Normal file
44
otouto/plugins/wait.lua
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
local utilities = require('otouto.utilities')
|
||||||
|
local bot = require('otouto.bot')
|
||||||
|
|
||||||
|
local wait = {}
|
||||||
|
|
||||||
|
function wait:init(config)
|
||||||
|
self.database.wait = self.database.wait or {}
|
||||||
|
wait.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('wait', true).table
|
||||||
|
wait.command = '/wait <duration> <command> [args]'
|
||||||
|
wait.doc = config.cmd_pat .. [[wait <duration> <command> [args]
|
||||||
|
Postpone a command for a given duration, in minutes.
|
||||||
|
Max duration is 10000.]]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ex: /wait 15 /calc 5 * 10
|
||||||
|
function wait:action(msg, config)
|
||||||
|
local duration = utilities.get_word(msg.text, 2)
|
||||||
|
duration = tonumber(duration)
|
||||||
|
local input = msg.text
|
||||||
|
repeat
|
||||||
|
input = input:gsub('^' .. config.cmd_pat .. '[Ww][Aa][Ii][Tt] %g+ ', '')
|
||||||
|
until not input:match('^' .. config.cmd_pat .. '[Ww][Aa][Ii][Tt] %g+ ')
|
||||||
|
if not input or not duration or duration > 10000 then
|
||||||
|
utilities.send_reply(msg, wait.doc, 'html')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
msg.date = msg.date + ( duration * 60 )
|
||||||
|
msg.text = input
|
||||||
|
table.insert(self.database.wait, msg)
|
||||||
|
utilities.send_reply(msg, 'Queued.')
|
||||||
|
end
|
||||||
|
|
||||||
|
function wait:cron(config)
|
||||||
|
local now = os.time() + 1
|
||||||
|
for k, msg in pairs(self.database.wait) do
|
||||||
|
if msg.date < now then
|
||||||
|
msg.date = os.time()
|
||||||
|
bot.on_msg_receive(self, msg, config)
|
||||||
|
self.database.wait[k] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return wait
|
@ -21,7 +21,7 @@ function weather:action(msg, config)
|
|||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, weather.doc, true)
|
utilities.send_reply(msg, weather.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ end
|
|||||||
function wikipedia:action(msg, config)
|
function wikipedia:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, wikipedia.doc, true)
|
utilities.send_reply(msg, wikipedia.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ function youtube:action(msg, config)
|
|||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(msg, youtube.doc, true)
|
utilities.send_reply(msg, youtube.doc, 'html')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -3,23 +3,9 @@
|
|||||||
Functions shared among otouto plugins.
|
Functions shared among otouto plugins.
|
||||||
|
|
||||||
Copyright 2016 topkecleon <drew@otou.to>
|
Copyright 2016 topkecleon <drew@otou.to>
|
||||||
|
This code is licensed under the GNU AGPLv3. See /LICENSE for details.
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of the GNU Affero General Public License version 3 as
|
|
||||||
published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program; if not, write to the Free Software Foundation,
|
|
||||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
local utilities = {}
|
|
||||||
|
|
||||||
local HTTP = require('socket.http')
|
local HTTP = require('socket.http')
|
||||||
local ltn12 = require('ltn12')
|
local ltn12 = require('ltn12')
|
||||||
local HTTPS = require('ssl.https')
|
local HTTPS = require('ssl.https')
|
||||||
@ -30,6 +16,8 @@ local bindings = require('otouto.bindings')
|
|||||||
-- If no built-in utf8 is available, load the library.
|
-- If no built-in utf8 is available, load the library.
|
||||||
local utf8 = utf8 or require('lua-utf8')
|
local utf8 = utf8 or require('lua-utf8')
|
||||||
|
|
||||||
|
local utilities = {}
|
||||||
|
|
||||||
-- For the sake of ease to new contributors and familiarity to old contributors,
|
-- For the sake of ease to new contributors and familiarity to old contributors,
|
||||||
-- we'll provide a couple of aliases to real bindings here.
|
-- we'll provide a couple of aliases to real bindings here.
|
||||||
-- Edit: To keep things working and allow for HTML messages, you can now pass a
|
-- Edit: To keep things working and allow for HTML messages, you can now pass a
|
||||||
@ -159,7 +147,7 @@ end
|
|||||||
-- Get the number of values in a key/value table.
|
-- Get the number of values in a key/value table.
|
||||||
function utilities.table_size(tab)
|
function utilities.table_size(tab)
|
||||||
local i = 0
|
local i = 0
|
||||||
for _,_ in pairs(tab) do
|
for _ in pairs(tab) do
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
return i
|
return i
|
||||||
@ -260,13 +248,6 @@ function utilities.triggers(username, cmd_pat, trigger_table)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities.with_http_timeout(timeout, fun)
|
|
||||||
local original = HTTP.TIMEOUT
|
|
||||||
HTTP.TIMEOUT = timeout
|
|
||||||
fun()
|
|
||||||
HTTP.TIMEOUT = original
|
|
||||||
end
|
|
||||||
|
|
||||||
function utilities.pretty_float(x)
|
function utilities.pretty_float(x)
|
||||||
if x % 1 == 0 then
|
if x % 1 == 0 then
|
||||||
return tostring(math.floor(x))
|
return tostring(math.floor(x))
|
||||||
@ -317,13 +298,6 @@ function utilities.set_meta:__len()
|
|||||||
return self.__count
|
return self.__count
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Styling functions to keep things consistent and easily changeable across plugins.
|
|
||||||
-- More to be added.
|
|
||||||
utilities.style = {}
|
|
||||||
utilities.style.enquote = function(title, body)
|
|
||||||
return '*' .. title:gsub('*', '\\*') .. ':*\n"' .. utilities.md_escape(body) .. '"'
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Converts a gross string back into proper UTF-8.
|
-- Converts a gross string back into proper UTF-8.
|
||||||
-- Useful for fixing improper encoding caused by bad JSON escaping.
|
-- Useful for fixing improper encoding caused by bad JSON escaping.
|
||||||
function utilities.fix_utf8(str)
|
function utilities.fix_utf8(str)
|
||||||
|
Reference in New Issue
Block a user