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:
topkecleon 2016-10-04 10:07:15 -04:00
parent bc6727275c
commit 9f760114bd
43 changed files with 324 additions and 356 deletions

View File

@ -67,7 +67,7 @@ Send /help to get started.
max_reminders_private = 50
},
chatter = {
cleverbot = {
cleverbot_api = 'https://brawlbot.tk/apis/chatter-bot-api/cleverbot.php?text=',
connection = 'I don\'t feel like talking right now.',
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.
-- Defaults to config.log_chat if left empty.
log_chat = nil,
-- Default autoban setting.
-- A user is banned after being autokicked this many times in a day.
autoban = 3,
-- Default antiflood values.
antiflood = {
text = 5,

View File

@ -5,19 +5,7 @@
See the "Bindings" section of README.md for usage information.
Copyright 2016 topkecleon <drew@otou.to>
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.
This code is licensed under the GNU AGPLv3. See /LICENSE for details.
]]--
local bindings = {}
@ -25,7 +13,7 @@ local bindings = {}
local https = require('ssl.https')
local json = require('dkjson')
local ltn12 = require('ltn12')
local mp_encode = require('multipart-post').encode
local mp = require('multipart-post')
function bindings.init(token)
bindings.BASE_URL = 'https://api.telegram.org/bot' .. token .. '/'
@ -58,7 +46,7 @@ function bindings.request(method, parameters, file)
parameters = {''}
end
local response = {}
local body, boundary = mp_encode(parameters)
local body, boundary = mp.encode(parameters)
local success, code = https.request{
url = bindings.BASE_URL .. method,
method = 'POST',
@ -79,8 +67,9 @@ function bindings.request(method, parameters, file)
return false, false
elseif result.ok then
return result
elseif result.description == 'Method not found' then
error(method .. ': Method not found.')
else
assert(result.description ~= 'Method not found', method .. ': Method not found.')
return false, result
end
end

View File

@ -3,26 +3,14 @@
The heart and sole of otouto, ie the init and main loop.
Copyright 2016 topkecleon <drew@otou.to>
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.
This code is licensed under the GNU AGPLv3. See /LICENSE for details.
]]--
local bot = {}
local bindings -- Bot API bindings.
local utilities -- Miscellaneous and shared plugins.
bot.version = '3.13'
bot.version = '3.14'
-- Function to be run on start and reload.
function bot:init(config)
@ -45,14 +33,11 @@ function bot:init(config)
self.database = utilities.load_data(self.database_name)
end
-- Migration code 1.12 -> 1.13
-- Back to administration global ban list; copy over current blacklist.
if self.database.version ~= '3.13' then
if self.database.administration then
self.database.administration.globalbans = self.database.administration.globalbans or self.database.blacklist or {}
utilities.save_data(self.database_name, self.database)
self.database = utilities.load_data(self.database_name)
end
-- Migration code 1.13 -> 1.14
-- "database.reminders" -> "database.remind"
if self.database.version ~= '3.14' then
self.database.remind = self.database.reminders
self.database.reminders = nil
end
-- End migration code.
@ -76,7 +61,9 @@ function bot:init(config)
table.insert(self.plugins, plugin)
if plugin.init then plugin.init(self, config) 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
end
@ -129,13 +116,11 @@ function bot:on_msg_receive(msg, config)
end
-- 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_lower = msg.text:lower()
end
-- If the message is forwarded or comes from a blacklisted yser,
-- Do the thing.
for _, plugin in ipairs(plugint) 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)
end
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config.log_chat)
msg = nil
return
-- Continue if the return value is true.
elseif result ~= true then
msg = nil
return
end
end
end
end
msg = nil
end
-- main

View File

@ -5,19 +5,7 @@
For more documentation, read the the manual (otou.to/rtfm).
Copyright 2016 topkecleon <drew@otou.to>
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.
This code is licensed under the GNU AGPLv3. See /LICENSE for details.
]]--
--[[
@ -36,6 +24,10 @@
target's autokick counter. Added configuration for default flag settings.
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')
@ -50,7 +42,6 @@ function administration:init(config)
self.database.administration = {
admins = {},
groups = {},
activity = {},
autokick_timer = os.date('%d'),
globalbans = {}
}
@ -66,22 +57,8 @@ function administration:init(config)
administration.flags = administration.init_flags(config.cmd_pat)
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.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.
administration.error = false
@ -385,16 +362,15 @@ function administration.init_command(self_, config_)
local from_id_str = tostring(msg.from.id)
local chat_id_str = tostring(msg.chat.id)
if rank < 2 then
if rank == 0 then -- banned
user.do_kick = true
user.dont_unban = true
user.reason = 'banned'
user.output = 'Sorry, you are banned from ' .. msg.chat.title .. '.'
elseif rank == 1 then
local from_name = utilities.build_name(msg.from.first_name, msg.from.last_name)
-- banned
if rank == 0 then
user.do_kick = true
user.dont_unban = true
user.reason = 'banned'
user.output = 'Sorry, you are banned from ' .. msg.chat.title .. '.'
elseif group.flags[2] and ( -- antisquig
if group.flags[2] and ( -- antisquig
msg.text:match(utilities.char.arabic)
or msg.text:match(utilities.char.rtl_override)
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)
else
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)
end
end
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
drua.set_photo(msg.chat.id, group.photo)
else
@ -541,7 +517,7 @@ function administration.init_command(self_, config_)
group.photo = drua.get_photo(msg.chat.id)
end
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
drua.set_photo(msg.chat.id, group.photo)
else
@ -592,16 +568,6 @@ function administration.init_command(self_, config_)
utilities.send_message(msg.new_chat_member.id, output, true, nil, true)
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
end
@ -613,26 +579,28 @@ function administration.init_command(self_, config_)
command = 'groups \\[query]',
privilege = 1,
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)
local input = utilities.input(msg.text)
local search_res = ''
local grouplist = ''
for _, chat_id_str in ipairs(self.database.administration.activity) do
local group = self.database.administration.groups[chat_id_str]
local group_list = {}
local result_list = {}
for _, group in pairs(self.database.administration.groups) do
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
search_res = search_res .. '• [' .. utilities.md_escape(group.name) .. '](' .. group.link .. ')\n'
table.insert(result_list, line)
end
end
end
local output
if search_res ~= '' then
output = '*Groups matching* _' .. input .. '_ *:*\n' .. search_res
elseif grouplist ~= '' then
output = '*Groups:*\n' .. grouplist
if #result_list > 0 then
table.sort(result_list)
output = '*Groups matching* _' .. input:gsub('_', '_\\__') .. '_*:*\n' .. table.concat(result_list, '\n')
elseif #group_list > 0 then
table.sort(group_list)
output = '*Groups:*\n' .. table.concat(group_list, '\n')
else
output = 'There are currently no listed groups.'
end
@ -764,13 +732,17 @@ function administration.init_command(self_, config_)
doc = 'Returns the group\'s list of rules, or a specific rule.',
action = function(self, msg, group, config)
local output
local input = utilities.get_word(msg.text_lower, 2)
input = tonumber(input)
local output = ''
local input = utilities.input(msg.text)
if #group.rules > 0 then
if input and group.rules[input] then
output = '*' .. input .. '.* ' .. group.rules[input]
else
if input then
for i in input:gmatch('%g+') do
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'
for i,v in ipairs(group.rules) do
output = output .. '*' .. i .. '.* ' .. v .. '\n'
@ -958,7 +930,7 @@ function administration.init_command(self_, config_)
local output = '*MOTD for ' .. msg.chat.title .. ':*\n' .. input
utilities.send_message(msg.chat.id, output, true, nil, true)
end
if group.grouptype == 'supergroup' then
if msg.chat.type == 'supergroup' then
administration.update_desc(self, msg.chat.id, config)
end
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.bans[target.id_str] = nil
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 }
if chat_member and chat_member.result.status == 'member' then
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'
group.mods[target.id_str] = nil
end
if group.grouptype == 'supergroup' then
if msg.chat.type == 'supergroup' then
drua.channel_set_admin(msg.chat.id, target.id, 0, s)
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
utilities.send_reply(msg, target.name .. ' is the new governor.')
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 }
if chat_member and chat_member.result.status == 'member' then
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
utilities.send_reply(msg, target.name .. ' is no longer the governor.')
end
if group.grouptype == 'supergroup' then
if msg.chat.type == 'supergroup' then
drua.channel_set_admin(msg.chat.id, target.id, 0)
administration.update_desc(self, msg.chat.id, config)
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'
else
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)
end
end
@ -1482,43 +1454,41 @@ This would add a group and enable the unlisted flag, antibot, and antiflood.
elseif group then
utilities.send_reply(msg, 'I am already administrating this group.')
else
local output = 'I am now administrating this group.'
local flags = {}
self.database.administration.groups[tostring(msg.chat.id)] = {
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
flags[i] = config.administration.flags[i]
group.flags[i] = config.administration.flags[i]
end
local input = utilities.input(msg.text)
local output = 'I am now administrating this group.'
if input then
for i in input:gmatch('%g+') do
local n = tonumber(i)
if n and administration.flags[n] and flags[n] ~= true then
flags[n] = true
if n and administration.flags[n] and group.flags[n] ~= true then
group.flags[n] = true
output = output .. '\n' .. administration.flags[n].short
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)
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)
utilities.send_reply(msg, output)
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
local chat_name = self.database.administration.groups[input].name
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) .. '_.'
else
if input == tostring(msg.chat.id) then

View File

@ -11,12 +11,9 @@ apod.command = 'apod [date]'
function apod:init(config)
apod.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('apod', true).table
apod.doc = [[
/apod [YYYY-MM-DD]
apod.doc = config.cmd_pat .. [[apod [YYYY-MM-DD]
Returns the Astronomy Picture of the Day.
Source: nasa.gov
]]
apod.doc = apod.doc:gsub('/', config.cmd_pat)
Source: nasa.gov]]
apod.base_url = 'https://api.nasa.gov/planetary/apod?api_key=' .. (config.nasa_api_key or 'DEMO_KEY')
end

View File

@ -21,7 +21,7 @@ function bible:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, bible.doc, true)
utilities.send_reply(msg, bible.doc, 'html')
return
end

View File

@ -21,11 +21,9 @@ function bing:init(config)
bing.headers = { ["Authorization"] = "Basic " .. mime.b64(":" .. config.bing_api_key) }
bing.triggers = utilities.triggers(self.info.username, config.cmd_pat)
:t('bing', true):t('g', true):t('google', true).table
bing.doc = [[
/bing <query>
bing.doc = [[/bing <query>
Returns the top web results from Bing.
Aliases: /g, /google
]]
Aliases: /g, /google]]
bing.doc = bing.doc:gsub('/', config.cmd_pat)
end
@ -33,7 +31,7 @@ end
function bing:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, bing.doc, true)
utilities.send_reply(msg, bing.doc, 'html')
return
end

View File

@ -15,7 +15,7 @@ end
function calc:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, calc.doc, true)
utilities.send_reply(msg, calc.doc, 'html')
return
end

View File

@ -2,6 +2,7 @@ local cats = {}
local HTTP = require('socket.http')
local utilities = require('otouto.utilities')
local bindings = require('otouto.bindings')
function cats:init(config)
if not config.thecatapi_key then
@ -29,9 +30,7 @@ function cats:action(msg, config)
end
str = str:match('<img src="(.-)">')
local output = '[Cat!]('..str..')'
utilities.send_message(msg.chat.id, output, false, nil, true)
bindings.sendPhoto{chat_id = msg.chat.id, photo = str}
end

View File

@ -16,45 +16,55 @@ The following markdown syntax is supported:
_italic text_
[text](URL)
`inline fixed-width code`
```pre-formatted fixed-width code block```]]
```pre-formatted fixed-width code block```]]
end
function channel:action(msg, config)
-- An exercise in using zero early returns. :)
local input = utilities.input(msg.text)
local output
if input then
local chat_id = utilities.get_word(input, 1)
local admin_list, t = bindings.getChatAdministrators{ chat_id = chat_id }
if admin_list then
local is_admin = false
for _, admin in ipairs(admin_list.result) do
if admin.user.id == msg.from.id then
is_admin = true
end
end
if is_admin then
local text = input:match('\n(.+)')
if text then
local success, result = utilities.send_message(chat_id, text, true, nil, true)
if success then
output = 'Your message has been sent!'
else
output = 'Sorry, I was unable to send your message.\n`' .. result.description .. '`'
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
if not input then
utilities.send_reply(msg, channel.doc, 'html')
return
end
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 }
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
for _, admin in ipairs(admin_list.result) do
if admin.user.id == msg.from.id then
is_admin = true
end
end
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(.+)')
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)
if success then
utilities.send_reply(msg, 'Your message has been sent!')
else
utilities.send_reply(msg, 'Sorry, I was unable to send your message.\n`' .. result.description .. '`', true)
end
utilities.send_reply(msg, output, true)
end
return channel

View File

@ -13,7 +13,7 @@ function cleverbot:init(config)
'^' .. self.info.first_name:lower() .. ', ',
'^@' .. self.info.username:lower() .. ', '
}
cleverbot.url = config.chatter.cleverbot_api
cleverbot.url = config.cleverbot.cleverbot_api
cleverbot.error = false
end
@ -22,12 +22,12 @@ function cleverbot:action(msg, config)
local input = msg.text_lower:gsub(cleverbot.name, ''):gsub(cleverbot.name, '')
local jstr, code = HTTPS.request(cleverbot.url .. URL.escape(input))
if code ~= 200 then
utilities.send_message(msg.chat.id, config.chatter.connection)
utilities.send_message(msg.chat.id, config.cleverbot.connection)
return
end
local data = JSON.decode(jstr)
if not data.clever then
utilities.send_message(msg.chat.id, config.chatter.response)
utilities.send_message(msg.chat.id, config.cleverbot.response)
return
end
utilities.send_message(msg.chat.id, data.clever)

View File

@ -12,9 +12,10 @@ function commit:init(config)
end
function commit:action(msg)
local output = http.request('http://whatthecommit.com/index.txt') or 'Minor text fixes'
bindings.sendMessage{
chat_id = msg.chat.id,
text = '```\n' .. (http.request('http://whatthecommit.com/index.txt')) .. '\n```',
text = '```\n' .. output .. '\n```',
parse_mode = 'Markdown'
}
end

View File

@ -17,7 +17,7 @@ function currency:action(msg, config)
local input = msg.text:upper()
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
end

View File

@ -14,7 +14,7 @@ function dice:action(msg)
local input = utilities.input(msg.text_lower)
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
end
@ -25,7 +25,7 @@ function dice:action(msg)
count = 1
range = input:match('^d?([%d]+)$')
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
end

View File

@ -30,19 +30,10 @@ function dilbert:action(msg, config)
return
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="(.-)"/>')
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

View File

@ -10,22 +10,18 @@ function echo:init(config)
end
function echo:action(msg)
local input = utilities.input_from_msg(msg)
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
local output
if msg.chat.type == 'supergroup' then
output = utilities.style.enquote('Echo', input)
output = '<b>Echo:</b>\n"' .. utilities.html_escape(input) .. '"'
else
output = utilities.md_escape(utilities.char.zwnj..input)
output = utilities.html_escape(utilities.char.zwnj..input)
end
utilities.send_message(msg.chat.id, output, true, nil, true)
utilities.send_message(msg.chat.id, output, true, nil, 'html')
end
end
return echo

View File

@ -10,7 +10,6 @@ function fortune:init(config)
not s:match('not found$'),
'fortune.lua requires the fortune program to be installed.'
)
fortune.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('fortune').table
end

View File

@ -11,6 +11,7 @@ local HTTPS = require('ssl.https')
local URL = require('socket.url')
local JSON = require('dkjson')
local utilities = require('otouto.utilities')
local bindings = require('otouto.bindings')
function gImages:init(config)
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)
if not input then
utilities.send_reply(msg, gImages.doc, true)
utilities.send_reply(msg, gImages.doc, 'html')
return
end
@ -59,13 +60,12 @@ function gImages:action(msg, config)
local i = math.random(jdat.queries.request[1].count)
local img_url = jdat.items[i].link
local img_title = jdat.items[i].title
local output = '[' .. img_title .. '](' .. img_url .. ')'
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)
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

View File

@ -19,7 +19,7 @@ end
function gMaps:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, gMaps.doc, true)
utilities.send_reply(msg, gMaps.doc, 'html')
return
end

View File

@ -95,7 +95,7 @@ function hearthstone:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, hearthstone.doc, true)
utilities.send_reply(msg, hearthstone.doc, 'html')
return
end

View File

@ -20,8 +20,8 @@ function help:action(msg, config)
end
for _,plugin in ipairs(self.plugins) do
if plugin.help_word == input:gsub('^/', '') then
local output = '*Help for* _' .. plugin.help_word .. '_*:*\n' .. plugin.doc
utilities.send_message(msg.chat.id, output, true, nil, true)
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, 'html')
return
end
end
@ -36,14 +36,14 @@ function help:action(msg, config)
end
end
table.sort(commandlist)
help.text = '*Available commands:*\n' .. config.cmd_pat .. table.concat(commandlist, '\n'..config.cmd_pat) .. '\nArguments: <required> [optional]'
help.text = help.text:gsub('%[', '\\[')
local comlist = '\n' .. config.cmd_pat .. table.concat(commandlist, '\n' .. config.cmd_pat) .. '\nArguments: <required> [optional]'
help.text = '<b>Available commands:</b>' .. utilities.html_escape(comlist)
end
-- Attempt to send the help message via PM.
-- 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
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
utilities.send_reply(msg, 'I have sent you the requested information in a private message.')
end

View File

@ -16,7 +16,7 @@ function imdb:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, imdb.doc, true)
utilities.send_reply(msg, imdb.doc, 'html')
return
end

View File

@ -18,7 +18,7 @@ end
function isup:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, isup.doc, true)
utilities.send_reply(msg, isup.doc, 'html')
return
end

View File

@ -9,19 +9,25 @@ local JSON = require('dkjson')
local utilities = require('otouto.utilities')
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.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]
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>
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)
@ -29,12 +35,12 @@ function lastfm:action(msg, config)
local from_id_str = tostring(msg.from.id)
self.database.userdata[from_id_str] = self.database.userdata[from_id_str] or {}
if string.match(msg.text, '^'..config.cmd_pat..'lastfm') then
utilities.send_message(msg.chat.id, lastfm.doc, true, msg.message_id, true)
if string.match(msg.text_lower, '^'..config.cmd_pat..'lastfm') then
utilities.send_message(msg.chat.id, lastfm.doc, true, msg.message_id, 'html')
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
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
self.database.userdata[from_id_str].lastfm = nil
utilities.send_reply(msg, 'Your last.fm username has been forgotten.')
@ -45,8 +51,6 @@ function lastfm:action(msg, config)
return
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 alert = ''
if input then
@ -62,13 +66,11 @@ function lastfm:action(msg, config)
return
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
utilities.send_reply(msg, config.errors.connection)
return
@ -80,29 +82,51 @@ function lastfm:action(msg, config)
return
end
jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track
if not jdat then
local track = jdat.recenttracks.track[1] or jdat.recenttracks.track
if not track then
utilities.send_reply(msg, 'No history for this user.' .. alert)
return
end
local output = input or msg.from.first_name
output = '🎵 ' .. output
if jdat['@attr'] and jdat['@attr'].nowplaying then
output = output .. ' is currently listening to:\n'
local output = utilities.html_escape(input or msg.from.first_name)
if track['@attr'] and track['@attr'].nowplaying then
output = output .. ' is currently listening to:'
else
output = output .. ' last listened to:\n'
output = output .. ' last listened to:'
end
local title = jdat.name or 'Unknown'
local artist = 'Unknown'
if jdat.artist then
artist = jdat.artist['#text']
if msg.text_lower:match('^' .. config.cmd_pat .. 'npfull') then
output = '<b>' .. utilities.html_escape(output) .. '</b>'
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
else
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 .. title .. ' - ' .. artist .. alert
utilities.send_message(msg.chat.id, output)
output = output .. alert
utilities.send_message(msg.chat.id, output, nil, nil, 'html')
end

View File

@ -8,7 +8,7 @@ patterns.doc = [[
s/<pattern>/<substitution>
Replace all matches for the given pattern.
Uses Lua patterns.
]]
]]
function patterns:init(config)
patterns.triggers = { config.cmd_pat .. '?s/.-/.-$' }
@ -18,8 +18,7 @@ function patterns:action(msg)
if not msg.reply_to_message then return true end
local output = msg.reply_to_message.text
if msg.reply_to_message.from.id == self.info.id then
output = output:gsub('Did you mean:\n"', '')
output = output:gsub('"$', '')
output = output:match('^Did you mean:\n"(.+)"$') or output
end
local m1, m2 = msg.text:match('^/?s/(.-)/(.-)/?$')
if not m2 then return true end
@ -33,8 +32,8 @@ function patterns:action(msg)
utilities.send_reply(msg, 'Malformed pattern!')
else
output = utilities.trim(output:sub(1, 4000))
output = utilities.style.enquote('Did you mean', output)
utilities.send_reply(msg.reply_to_message, output, true)
output = '<b>Did you mean:</b>\n"' .. utilities.html_escape(output) .. '"'
utilities.send_reply(msg.reply_to_message, output, 'html')
end
end

View File

@ -19,7 +19,7 @@ function pokedex:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, pokedex.doc, true)
utilities.send_reply(msg, pokedex.doc, 'html')
return
end

View File

@ -73,7 +73,7 @@ end
function pgc:action(msg)
local input = utilities.input(msg.text)
if not input then
utilities.send_reply(msg, pgc.doc, true)
utilities.send_reply(msg, pgc.doc, 'html')
return
end
input = input .. '\n'

View File

@ -14,7 +14,7 @@ function preview:action(msg)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, preview.doc, true)
utilities.send_reply(msg, preview.doc, 'html')
return
end

View File

@ -132,7 +132,8 @@ local puns = {
"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.",
"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)

View File

@ -1,9 +1,9 @@
local reddit = {}
local HTTP = require('socket.http')
local URL = require('socket.url')
local JSON = require('dkjson')
local utilities = require('otouto.utilities')
local HTTPS = require('ssl.https')
reddit.command = 'reddit [r/subreddit | query]'
@ -65,7 +65,7 @@ function reddit:action(msg, config)
url = reddit.rall_url .. limit
source = '*/r/all*\n'
end
local jstr, res = HTTP.request(url)
local jstr, res = HTTPS.request(url)
if res ~= 200 then
utilities.send_reply(msg, config.errors.connection)
else

View File

@ -5,26 +5,31 @@ local utilities = require('otouto.utilities')
remind.command = 'remind <duration> <message>'
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.doc = config.cmd_pat .. [[remind <duration> <message>
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.]]
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
function remind:action(msg, config)
local input = utilities.input(msg.text)
if not input then
utilities.send_reply(msg, remind.doc, true)
utilities.send_reply(msg, remind.doc, 'html')
return
end
local duration = tonumber(utilities.get_word(input, 1))
if not duration then
utilities.send_reply(msg, remind.doc, true)
utilities.send_reply(msg, remind.doc, 'html')
return
end
@ -40,7 +45,7 @@ function remind:action(msg, config)
elseif utilities.input(input) then
message = utilities.input(input)
else
utilities.send_reply(msg, remind.doc, true)
utilities.send_reply(msg, remind.doc, 'html')
return
end
@ -51,13 +56,13 @@ function remind:action(msg, config)
local chat_id_str = tostring(msg.chat.id)
local output
self.database.reminders[chat_id_str] = self.database.reminders[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
self.database.remind[chat_id_str] = self.database.remind[chat_id_str] or {}
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.'
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.'
else
table.insert(self.database.reminders[chat_id_str], {
table.insert(self.database.remind[chat_id_str], {
time = os.time() + (duration * 60),
message = message
})
@ -73,14 +78,14 @@ end
function remind:cron(config)
local time = os.time()
-- 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.
for k, reminder in pairs(group) do
-- If the reminder is past-due, send it and nullify it.
-- Otherwise, add it to the replacement table.
if time > reminder.time then
local output = utilities.style.enquote('Reminder', reminder.message)
local res = utilities.send_message(chat_id, output, true, nil, true)
local output = '<b>Reminder:</b>\n"' .. utilities.html_escape(reminder.message) .. '"'
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 res or not config.remind.persist then
group[k] = nil

View File

@ -5,30 +5,22 @@ local bindings = require('otouto.bindings')
local rms = {}
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.LIST = {}
local s, r = https.request(rms.BASE_URL)
if r ~= 200 then
print('Error connecting to rms.sexy.\nrmspic.lua will not be enabled.')
return
rms.triggers = {}
end
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
rms.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('rms').table
end
function rms:action(msg, config)
bindings.sendChatAction{ chat_id = msg.chat.id, action = 'upload_photo' }
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 })
bindings.sendPhoto{chat_id = msg.chat.id, photo = rms.LIST[math.random(#rms.LIST)]}
end
return rms

View File

@ -22,7 +22,7 @@ function setandget:action(msg, config)
if msg.text_lower:match('^'..config.cmd_pat..'set') 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
end
@ -30,7 +30,7 @@ function setandget:action(msg, config)
local value = utilities.input(input)
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
self.database.setandget[chat_id_str][name] = nil
utilities.send_message(msg.chat.id, 'That value has been deleted.')

View File

@ -14,7 +14,7 @@ function shout:action(msg)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, shout.doc, true)
utilities.send_reply(msg, shout.doc, 'html')
return
end

View File

@ -40,7 +40,7 @@ local corrected_numbers = {
function starwars:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, starwars.doc, true)
utilities.send_reply(msg, starwars.doc, 'html')
return
end

View File

@ -16,7 +16,7 @@ end
function time:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, time.doc, true)
utilities.send_reply(msg, time.doc, 'html')
return
end

View File

@ -22,7 +22,7 @@ end
function translate:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, translate.doc, true)
utilities.send_reply(msg, translate.doc, 'html')
return
end
@ -39,7 +39,9 @@ function translate:action(msg, config)
return
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
return translate

View File

@ -11,18 +11,16 @@ urbandictionary.base_url = 'http://api.urbandictionary.com/v0/define?term='
function urbandictionary:init(config)
urbandictionary.triggers = utilities.triggers(self.info.username, config.cmd_pat)
:t('urbandictionary', true):t('ud', true):t('urban', true).table
urbandictionary.doc = [[
/urbandictionary <query>
urbandictionary.doc = [[/urbandictionary <query>
Returns a definition from Urban Dictionary.
Aliases: /ud, /urban
]]
Aliases: /ud, /urban]]
urbandictionary.doc = urbandictionary.doc:gsub('/', config.cmd_pat)
end
function urbandictionary:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, urbandictionary.doc, true)
utilities.send_reply(msg, urbandictionary.doc, 'html')
return
end
@ -38,13 +36,13 @@ function urbandictionary:action(msg, config)
if data.result_type == 'no_results' then
output = config.errors.results
else
output = string.format('*%s*\n\n%s\n\n_%s_',
data.list[1].word:gsub('*', '*\\**'),
utilities.trim(utilities.md_escape(data.list[1].definition)),
utilities.trim((data.list[1].example or '')):gsub('_', '_\\__')
output = string.format('<b>%s</b>\n\n%s\n\n<i>%s</i>',
utilities.html_escape(data.list[1].word),
utilities.trim(utilities.html_escape(data.list[1].definition)),
utilities.trim(utilities.html_escape(data.list[1].example or ''))
)
end
utilities.send_reply(msg, output, true)
utilities.send_reply(msg, output, 'html')
end
return urbandictionary

44
otouto/plugins/wait.lua Normal file
View 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

View File

@ -21,7 +21,7 @@ function weather:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, weather.doc, true)
utilities.send_reply(msg, weather.doc, 'html')
return
end

View File

@ -20,7 +20,7 @@ end
function wikipedia:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, wikipedia.doc, true)
utilities.send_reply(msg, wikipedia.doc, 'html')
return
end

View File

@ -24,7 +24,7 @@ function youtube:action(msg, config)
local input = utilities.input_from_msg(msg)
if not input then
utilities.send_reply(msg, youtube.doc, true)
utilities.send_reply(msg, youtube.doc, 'html')
return
end

View File

@ -3,23 +3,9 @@
Functions shared among otouto plugins.
Copyright 2016 topkecleon <drew@otou.to>
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.
This code is licensed under the GNU AGPLv3. See /LICENSE for details.
]]--
local utilities = {}
local HTTP = require('socket.http')
local ltn12 = require('ltn12')
local HTTPS = require('ssl.https')
@ -30,6 +16,8 @@ local bindings = require('otouto.bindings')
-- If no built-in utf8 is available, load the library.
local utf8 = utf8 or require('lua-utf8')
local utilities = {}
-- For the sake of ease to new contributors and familiarity to old contributors,
-- 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
@ -159,7 +147,7 @@ end
-- Get the number of values in a key/value table.
function utilities.table_size(tab)
local i = 0
for _,_ in pairs(tab) do
for _ in pairs(tab) do
i = i + 1
end
return i
@ -260,13 +248,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.pretty_float(x)
if x % 1 == 0 then
return tostring(math.floor(x))
@ -317,13 +298,6 @@ function utilities.set_meta:__len()
return self.__count
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.
-- Useful for fixing improper encoding caused by bad JSON escaping.
function utilities.fix_utf8(str)