tab -> 4 spaces
This commit is contained in:
parent
6fbd718af0
commit
148d4b0dc5
@ -6,4 +6,5 @@ insert_final_newline = true
|
||||
|
||||
[*.lua]
|
||||
charset = utf-8
|
||||
indent_style = tab
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
62
README.md
62
README.md
@ -292,26 +292,26 @@ Additionally, any method can be called as a key in the `bindings` table (for exa
|
||||
|
||||
```
|
||||
bindings.request(
|
||||
self,
|
||||
'sendMessage',
|
||||
{
|
||||
chat_id = 987654321,
|
||||
text = 'Quick brown fox.',
|
||||
reply_to_message_id = 54321,
|
||||
disable_web_page_preview = false,
|
||||
parse_method = 'Markdown'
|
||||
}
|
||||
self,
|
||||
'sendMessage',
|
||||
{
|
||||
chat_id = 987654321,
|
||||
text = 'Quick brown fox.',
|
||||
reply_to_message_id = 54321,
|
||||
disable_web_page_preview = false,
|
||||
parse_method = 'Markdown'
|
||||
}
|
||||
)
|
||||
|
||||
bindings.sendMessage(
|
||||
self,
|
||||
{
|
||||
chat_id = 987654321,
|
||||
text = 'Quick brown fox.',
|
||||
reply_to_message_id = 54321,
|
||||
disable_web_page_preview = false,
|
||||
parse_method = 'Markdown'
|
||||
}
|
||||
self,
|
||||
{
|
||||
chat_id = 987654321,
|
||||
text = 'Quick brown fox.',
|
||||
reply_to_message_id = 54321,
|
||||
disable_web_page_preview = false,
|
||||
parse_method = 'Markdown'
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
@ -342,20 +342,20 @@ Alone, the database will have this structure:
|
||||
|
||||
```
|
||||
{
|
||||
users = {
|
||||
["55994550"] = {
|
||||
id = 55994550,
|
||||
first_name = "Drew",
|
||||
username = "topkecleon"
|
||||
}
|
||||
},
|
||||
userdata = {
|
||||
["55994550"] = {
|
||||
nickname = "Worst coder ever",
|
||||
lastfm = "topkecleon"
|
||||
}
|
||||
},
|
||||
version = "3.11"
|
||||
users = {
|
||||
["55994550"] = {
|
||||
id = 55994550,
|
||||
first_name = "Drew",
|
||||
username = "topkecleon"
|
||||
}
|
||||
},
|
||||
userdata = {
|
||||
["55994550"] = {
|
||||
nickname = "Worst coder ever",
|
||||
lastfm = "topkecleon"
|
||||
}
|
||||
},
|
||||
version = "3.11"
|
||||
}
|
||||
```
|
||||
|
||||
|
286
config.lua
286
config.lua
@ -1,159 +1,159 @@
|
||||
-- For details on configuration values, see README.md#configuration.
|
||||
return {
|
||||
|
||||
-- Your authorization token from the botfather.
|
||||
bot_api_key = nil,
|
||||
-- Your Telegram ID.
|
||||
admin = nil,
|
||||
-- Two-letter language code.
|
||||
lang = 'en',
|
||||
-- The channel, group, or user to send error reports to.
|
||||
-- If this is not set, errors will be printed to the console.
|
||||
log_chat = nil,
|
||||
-- The port used to communicate with tg for administration.lua.
|
||||
-- If you change this, make sure you also modify launch-tg.sh.
|
||||
cli_port = 4567,
|
||||
-- The symbol that starts a command. Usually noted as '/' in documentation.
|
||||
cmd_pat = '/',
|
||||
-- If drua is used, should a user be blocked when he's blacklisted?
|
||||
drua_block_on_blacklist = false,
|
||||
-- The filename of the database. If left nil, defaults to $username.db.
|
||||
database_name = nil,
|
||||
-- The block of text returned by /start and /about..
|
||||
about_text = [[
|
||||
-- Your authorization token from the botfather.
|
||||
bot_api_key = nil,
|
||||
-- Your Telegram ID.
|
||||
admin = nil,
|
||||
-- Two-letter language code.
|
||||
lang = 'en',
|
||||
-- The channel, group, or user to send error reports to.
|
||||
-- If this is not set, errors will be printed to the console.
|
||||
log_chat = nil,
|
||||
-- The port used to communicate with tg for administration.lua.
|
||||
-- If you change this, make sure you also modify launch-tg.sh.
|
||||
cli_port = 4567,
|
||||
-- The symbol that starts a command. Usually noted as '/' in documentation.
|
||||
cmd_pat = '/',
|
||||
-- If drua is used, should a user be blocked when he's blacklisted?
|
||||
drua_block_on_blacklist = false,
|
||||
-- The filename of the database. If left nil, defaults to $username.db.
|
||||
database_name = nil,
|
||||
-- The block of text returned by /start and /about..
|
||||
about_text = [[
|
||||
I am otouto, the plugin-wielding, multipurpose Telegram bot.
|
||||
|
||||
Send /help to get started.
|
||||
]],
|
||||
]],
|
||||
|
||||
errors = { -- Generic error messages.
|
||||
generic = 'An unexpected error occurred.',
|
||||
connection = 'Connection error.',
|
||||
results = 'No results found.',
|
||||
argument = 'Invalid argument.',
|
||||
syntax = 'Invalid syntax.'
|
||||
},
|
||||
errors = { -- Generic error messages.
|
||||
generic = 'An unexpected error occurred.',
|
||||
connection = 'Connection error.',
|
||||
results = 'No results found.',
|
||||
argument = 'Invalid argument.',
|
||||
syntax = 'Invalid syntax.'
|
||||
},
|
||||
|
||||
-- https://datamarket.azure.com/dataset/bing/search
|
||||
bing_api_key = nil,
|
||||
-- http://console.developers.google.com
|
||||
google_api_key = nil,
|
||||
-- https://cse.google.com/cse
|
||||
google_cse_key = nil,
|
||||
-- http://openweathermap.org/appid
|
||||
owm_api_key = nil,
|
||||
-- http://last.fm/api
|
||||
lastfm_api_key = nil,
|
||||
-- http://api.biblia.com
|
||||
biblia_api_key = nil,
|
||||
-- http://thecatapi.com/docs.html
|
||||
thecatapi_key = nil,
|
||||
-- http://api.nasa.gov
|
||||
nasa_api_key = nil,
|
||||
-- http://tech.yandex.com/keys/get
|
||||
yandex_key = nil,
|
||||
-- Interval (in minutes) for hackernews.lua to update.
|
||||
hackernews_interval = 60,
|
||||
-- Whether hackernews.lua should update at load/reload.
|
||||
hackernews_onstart = false,
|
||||
-- Whether luarun should use serpent instead of dkjson for serialization.
|
||||
luarun_serpent = false,
|
||||
-- https://datamarket.azure.com/dataset/bing/search
|
||||
bing_api_key = nil,
|
||||
-- http://console.developers.google.com
|
||||
google_api_key = nil,
|
||||
-- https://cse.google.com/cse
|
||||
google_cse_key = nil,
|
||||
-- http://openweathermap.org/appid
|
||||
owm_api_key = nil,
|
||||
-- http://last.fm/api
|
||||
lastfm_api_key = nil,
|
||||
-- http://api.biblia.com
|
||||
biblia_api_key = nil,
|
||||
-- http://thecatapi.com/docs.html
|
||||
thecatapi_key = nil,
|
||||
-- http://api.nasa.gov
|
||||
nasa_api_key = nil,
|
||||
-- http://tech.yandex.com/keys/get
|
||||
yandex_key = nil,
|
||||
-- Interval (in minutes) for hackernews.lua to update.
|
||||
hackernews_interval = 60,
|
||||
-- Whether hackernews.lua should update at load/reload.
|
||||
hackernews_onstart = false,
|
||||
-- Whether luarun should use serpent instead of dkjson for serialization.
|
||||
luarun_serpent = false,
|
||||
|
||||
remind = {
|
||||
persist = true,
|
||||
max_length = 1000,
|
||||
max_duration = 526000,
|
||||
max_reminders_group = 10,
|
||||
max_reminders_private = 50
|
||||
},
|
||||
remind = {
|
||||
persist = true,
|
||||
max_length = 1000,
|
||||
max_duration = 526000,
|
||||
max_reminders_group = 10,
|
||||
max_reminders_private = 50
|
||||
},
|
||||
|
||||
chatter = {
|
||||
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.'
|
||||
},
|
||||
chatter = {
|
||||
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.'
|
||||
},
|
||||
|
||||
greetings = {
|
||||
["Hello, #NAME."] = {
|
||||
"hello",
|
||||
"hey",
|
||||
"hi",
|
||||
"good morning",
|
||||
"good day",
|
||||
"good afternoon",
|
||||
"good evening"
|
||||
},
|
||||
["Goodbye, #NAME."] = {
|
||||
"good%-?bye",
|
||||
"bye",
|
||||
"later",
|
||||
"see ya",
|
||||
"good night"
|
||||
},
|
||||
["Welcome back, #NAME."] = {
|
||||
"i'm home",
|
||||
"i'm back"
|
||||
},
|
||||
["You're welcome, #NAME."] = {
|
||||
"thanks",
|
||||
"thank you"
|
||||
}
|
||||
},
|
||||
greetings = {
|
||||
["Hello, #NAME."] = {
|
||||
"hello",
|
||||
"hey",
|
||||
"hi",
|
||||
"good morning",
|
||||
"good day",
|
||||
"good afternoon",
|
||||
"good evening"
|
||||
},
|
||||
["Goodbye, #NAME."] = {
|
||||
"good%-?bye",
|
||||
"bye",
|
||||
"later",
|
||||
"see ya",
|
||||
"good night"
|
||||
},
|
||||
["Welcome back, #NAME."] = {
|
||||
"i'm home",
|
||||
"i'm back"
|
||||
},
|
||||
["You're welcome, #NAME."] = {
|
||||
"thanks",
|
||||
"thank you"
|
||||
}
|
||||
},
|
||||
|
||||
reactions = {
|
||||
['shrug'] = '¯\\_(ツ)_/¯',
|
||||
['lenny'] = '( ͡° ͜ʖ ͡°)',
|
||||
['flip'] = '(╯°□°)╯︵ ┻━┻',
|
||||
['look'] = 'ಠ_ಠ',
|
||||
['shots'] = 'SHOTS FIRED',
|
||||
['facepalm'] = '(-‸ლ)'
|
||||
},
|
||||
reactions = {
|
||||
['shrug'] = '¯\\_(ツ)_/¯',
|
||||
['lenny'] = '( ͡° ͜ʖ ͡°)',
|
||||
['flip'] = '(╯°□°)╯︵ ┻━┻',
|
||||
['look'] = 'ಠ_ಠ',
|
||||
['shots'] = 'SHOTS FIRED',
|
||||
['facepalm'] = '(-‸ლ)'
|
||||
},
|
||||
|
||||
administration = {
|
||||
-- Whether moderators can set a group's message of the day.
|
||||
moderator_setmotd = false,
|
||||
-- Default antiflood values.
|
||||
antiflood = {
|
||||
text = 5,
|
||||
voice = 5,
|
||||
audio = 5,
|
||||
contact = 5,
|
||||
photo = 10,
|
||||
video = 10,
|
||||
location = 10,
|
||||
document = 10,
|
||||
sticker = 20
|
||||
}
|
||||
},
|
||||
administration = {
|
||||
-- Whether moderators can set a group's message of the day.
|
||||
moderator_setmotd = false,
|
||||
-- Default antiflood values.
|
||||
antiflood = {
|
||||
text = 5,
|
||||
voice = 5,
|
||||
audio = 5,
|
||||
contact = 5,
|
||||
photo = 10,
|
||||
video = 10,
|
||||
location = 10,
|
||||
document = 10,
|
||||
sticker = 20
|
||||
}
|
||||
},
|
||||
|
||||
plugins = { -- To enable a plugin, add its name to the list.
|
||||
'about',
|
||||
'blacklist',
|
||||
'calc',
|
||||
'cats',
|
||||
'commit',
|
||||
'control',
|
||||
'currency',
|
||||
'dice',
|
||||
'echo',
|
||||
'eightball',
|
||||
'gMaps',
|
||||
'hackernews',
|
||||
'imdb',
|
||||
'nick',
|
||||
'ping',
|
||||
'pun',
|
||||
'reddit',
|
||||
'shout',
|
||||
'slap',
|
||||
'time',
|
||||
'urbandictionary',
|
||||
'whoami',
|
||||
'wikipedia',
|
||||
'xkcd',
|
||||
-- Put new plugins above this line.
|
||||
'help',
|
||||
'greetings'
|
||||
}
|
||||
plugins = { -- To enable a plugin, add its name to the list.
|
||||
'about',
|
||||
'blacklist',
|
||||
'calc',
|
||||
'cats',
|
||||
'commit',
|
||||
'control',
|
||||
'currency',
|
||||
'dice',
|
||||
'echo',
|
||||
'eightball',
|
||||
'gMaps',
|
||||
'hackernews',
|
||||
'imdb',
|
||||
'nick',
|
||||
'ping',
|
||||
'pun',
|
||||
'reddit',
|
||||
'shout',
|
||||
'slap',
|
||||
'time',
|
||||
'urbandictionary',
|
||||
'whoami',
|
||||
'wikipedia',
|
||||
'xkcd',
|
||||
-- Put new plugins above this line.
|
||||
'help',
|
||||
'greetings'
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
while true; do
|
||||
lua main.lua
|
||||
echo 'otouto has stopped. ^C to exit.'
|
||||
sleep 5s
|
||||
lua main.lua
|
||||
echo 'otouto has stopped. ^C to exit.'
|
||||
sleep 5s
|
||||
done
|
||||
|
@ -1,10 +1,10 @@
|
||||
--[[
|
||||
bindings.lua (rev. 2016/05/28)
|
||||
otouto's bindings for the Telegram bot API.
|
||||
https://core.telegram.org/bots/api
|
||||
Copyright 2016 topkecleon. Published under the AGPLv3.
|
||||
bindings.lua (rev. 2016/05/28)
|
||||
otouto's bindings for the Telegram bot API.
|
||||
https://core.telegram.org/bots/api
|
||||
Copyright 2016 topkecleon. Published under the AGPLv3.
|
||||
|
||||
See the "Bindings" section of README.md for usage information.
|
||||
See the "Bindings" section of README.md for usage information.
|
||||
]]--
|
||||
|
||||
local bindings = {}
|
||||
@ -22,56 +22,56 @@ local MP_ENCODE = require('multipart-post').encode
|
||||
-- response with failure. Returns false and false with a connection error.
|
||||
-- To mimic old/normal behavior, it errs if used with an invalid method.
|
||||
function bindings:request(method, parameters, file)
|
||||
parameters = parameters or {}
|
||||
for k,v in pairs(parameters) do
|
||||
parameters[k] = tostring(v)
|
||||
end
|
||||
if file and next(file) ~= nil then
|
||||
local file_type, file_name = next(file)
|
||||
local file_file = io.open(file_name, 'r')
|
||||
local file_data = {
|
||||
filename = file_name,
|
||||
data = file_file:read('*a')
|
||||
}
|
||||
file_file:close()
|
||||
parameters[file_type] = file_data
|
||||
end
|
||||
if next(parameters) == nil then
|
||||
parameters = {''}
|
||||
end
|
||||
local response = {}
|
||||
local body, boundary = MP_ENCODE(parameters)
|
||||
local success, code = HTTPS.request{
|
||||
url = self.BASE_URL .. method,
|
||||
method = 'POST',
|
||||
headers = {
|
||||
["Content-Type"] = "multipart/form-data; boundary=" .. boundary,
|
||||
["Content-Length"] = #body,
|
||||
},
|
||||
source = ltn12.source.string(body),
|
||||
sink = ltn12.sink.table(response)
|
||||
}
|
||||
local data = table.concat(response)
|
||||
if not success or success == 1 then
|
||||
print(method .. ': Connection error. [' .. code .. ']')
|
||||
return false, false
|
||||
else
|
||||
local result = JSON.decode(data)
|
||||
if not result then
|
||||
return false, false
|
||||
elseif result.ok then
|
||||
return result
|
||||
else
|
||||
assert(result.description ~= 'Method not found', method .. ': Method not found.')
|
||||
return false, result
|
||||
end
|
||||
end
|
||||
parameters = parameters or {}
|
||||
for k,v in pairs(parameters) do
|
||||
parameters[k] = tostring(v)
|
||||
end
|
||||
if file and next(file) ~= nil then
|
||||
local file_type, file_name = next(file)
|
||||
local file_file = io.open(file_name, 'r')
|
||||
local file_data = {
|
||||
filename = file_name,
|
||||
data = file_file:read('*a')
|
||||
}
|
||||
file_file:close()
|
||||
parameters[file_type] = file_data
|
||||
end
|
||||
if next(parameters) == nil then
|
||||
parameters = {''}
|
||||
end
|
||||
local response = {}
|
||||
local body, boundary = MP_ENCODE(parameters)
|
||||
local success, code = HTTPS.request{
|
||||
url = self.BASE_URL .. method,
|
||||
method = 'POST',
|
||||
headers = {
|
||||
["Content-Type"] = "multipart/form-data; boundary=" .. boundary,
|
||||
["Content-Length"] = #body,
|
||||
},
|
||||
source = ltn12.source.string(body),
|
||||
sink = ltn12.sink.table(response)
|
||||
}
|
||||
local data = table.concat(response)
|
||||
if not success or success == 1 then
|
||||
print(method .. ': Connection error. [' .. code .. ']')
|
||||
return false, false
|
||||
else
|
||||
local result = JSON.decode(data)
|
||||
if not result then
|
||||
return false, false
|
||||
elseif result.ok then
|
||||
return result
|
||||
else
|
||||
assert(result.description ~= 'Method not found', method .. ': Method not found.')
|
||||
return false, result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function bindings.gen(_, key)
|
||||
return function(self, params, file)
|
||||
return bindings.request(self, key, params, file)
|
||||
end
|
||||
return function(self, params, file)
|
||||
return bindings.request(self, key, params, file)
|
||||
end
|
||||
end
|
||||
setmetatable(bindings, { __index = bindings.gen })
|
||||
|
||||
|
312
otouto/bot.lua
312
otouto/bot.lua
@ -7,190 +7,190 @@ bot.version = '3.13'
|
||||
-- Function to be run on start and reload.
|
||||
function bot:init(config)
|
||||
|
||||
bindings = require('otouto.bindings')
|
||||
utilities = require('otouto.utilities')
|
||||
bindings = require('otouto.bindings')
|
||||
utilities = require('otouto.utilities')
|
||||
|
||||
assert(
|
||||
config.bot_api_key,
|
||||
'You did not set your bot token in the config!'
|
||||
)
|
||||
self.BASE_URL = 'https://api.telegram.org/bot' .. config.bot_api_key .. '/'
|
||||
assert(
|
||||
config.bot_api_key,
|
||||
'You did not set your bot token in the config!'
|
||||
)
|
||||
self.BASE_URL = 'https://api.telegram.org/bot' .. config.bot_api_key .. '/'
|
||||
|
||||
-- Fetch bot information. Try until it succeeds.
|
||||
repeat
|
||||
print('Fetching bot information...')
|
||||
self.info = bindings.getMe(self)
|
||||
until self.info
|
||||
self.info = self.info.result
|
||||
-- Fetch bot information. Try until it succeeds.
|
||||
repeat
|
||||
print('Fetching bot information...')
|
||||
self.info = bindings.getMe(self)
|
||||
until self.info
|
||||
self.info = self.info.result
|
||||
|
||||
-- Load the "database"! ;)
|
||||
self.database_name = config.database_name or self.info.username .. '.db'
|
||||
if not self.database then
|
||||
self.database = utilities.load_data(self.database_name)
|
||||
end
|
||||
-- Load the "database"! ;)
|
||||
self.database_name = config.database_name or self.info.username .. '.db'
|
||||
if not self.database then
|
||||
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
|
||||
end
|
||||
-- End migration code.
|
||||
-- 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
|
||||
end
|
||||
-- End migration code.
|
||||
|
||||
-- Table to cache user info (usernames, IDs, etc).
|
||||
self.database.users = self.database.users or {}
|
||||
-- Table to store userdata (nicknames, lastfm usernames, etc).
|
||||
self.database.userdata = self.database.userdata or {}
|
||||
-- Table to store the IDs of blacklisted users.
|
||||
self.database.blacklist = self.database.blacklist or {}
|
||||
-- Save the bot's version in the database to make migration simpler.
|
||||
self.database.version = bot.version
|
||||
-- Add updated bot info to the user info cache.
|
||||
self.database.users[tostring(self.info.id)] = self.info
|
||||
-- Table to cache user info (usernames, IDs, etc).
|
||||
self.database.users = self.database.users or {}
|
||||
-- Table to store userdata (nicknames, lastfm usernames, etc).
|
||||
self.database.userdata = self.database.userdata or {}
|
||||
-- Table to store the IDs of blacklisted users.
|
||||
self.database.blacklist = self.database.blacklist or {}
|
||||
-- Save the bot's version in the database to make migration simpler.
|
||||
self.database.version = bot.version
|
||||
-- Add updated bot info to the user info cache.
|
||||
self.database.users[tostring(self.info.id)] = self.info
|
||||
|
||||
-- All plugins go into self.plugins. Plugins which accept forwarded messages
|
||||
-- and messages from blacklisted users also go into self.panoptic_plugins.
|
||||
self.plugins = {}
|
||||
self.panoptic_plugins = {}
|
||||
for _, pname in ipairs(config.plugins) do
|
||||
local plugin = require('otouto.plugins.'..pname)
|
||||
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 not plugin.triggers then plugin.triggers = {} end
|
||||
end
|
||||
-- All plugins go into self.plugins. Plugins which accept forwarded messages
|
||||
-- and messages from blacklisted users also go into self.panoptic_plugins.
|
||||
self.plugins = {}
|
||||
self.panoptic_plugins = {}
|
||||
for _, pname in ipairs(config.plugins) do
|
||||
local plugin = require('otouto.plugins.'..pname)
|
||||
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 not plugin.triggers then plugin.triggers = {} end
|
||||
end
|
||||
|
||||
print('@' .. self.info.username .. ', AKA ' .. self.info.first_name ..' ('..self.info.id..')')
|
||||
print('@' .. self.info.username .. ', AKA ' .. self.info.first_name ..' ('..self.info.id..')')
|
||||
|
||||
-- Set loop variables.
|
||||
self.last_update = self.last_update or 0 -- Update offset.
|
||||
self.last_cron = self.last_cron or os.date('%M') -- Last cron job.
|
||||
self.last_database_save = self.last_database_save or os.date('%H') -- Last db save.
|
||||
self.is_started = true
|
||||
-- Set loop variables.
|
||||
self.last_update = self.last_update or 0 -- Update offset.
|
||||
self.last_cron = self.last_cron or os.date('%M') -- Last cron job.
|
||||
self.last_database_save = self.last_database_save or os.date('%H') -- Last db save.
|
||||
self.is_started = true
|
||||
|
||||
end
|
||||
|
||||
-- Function to be run on each new message.
|
||||
function bot:on_msg_receive(msg, config)
|
||||
|
||||
-- Do not process old messages.
|
||||
if msg.date < os.time() - 5 then return end
|
||||
-- Do not process old messages.
|
||||
if msg.date < os.time() - 5 then return end
|
||||
|
||||
-- plugint is the array of plugins we'll check the message against.
|
||||
-- If the message is forwarded or from a blacklisted user, the bot will only
|
||||
-- check against panoptic plugins.
|
||||
local plugint = self.plugins
|
||||
local from_id_str = tostring(msg.from.id)
|
||||
-- plugint is the array of plugins we'll check the message against.
|
||||
-- If the message is forwarded or from a blacklisted user, the bot will only
|
||||
-- check against panoptic plugins.
|
||||
local plugint = self.plugins
|
||||
local from_id_str = tostring(msg.from.id)
|
||||
|
||||
-- Cache user info for those involved.
|
||||
self.database.users[from_id_str] = msg.from
|
||||
if msg.reply_to_message then
|
||||
self.database.users[tostring(msg.reply_to_message.from.id)] = msg.reply_to_message.from
|
||||
elseif msg.forward_from then
|
||||
-- Forwards only go to panoptic plugins.
|
||||
plugint = self.panoptic_plugins
|
||||
self.database.users[tostring(msg.forward_from.id)] = msg.forward_from
|
||||
elseif msg.new_chat_member then
|
||||
self.database.users[tostring(msg.new_chat_member.id)] = msg.new_chat_member
|
||||
elseif msg.left_chat_member then
|
||||
self.database.users[tostring(msg.left_chat_member.id)] = msg.left_chat_member
|
||||
end
|
||||
-- Cache user info for those involved.
|
||||
self.database.users[from_id_str] = msg.from
|
||||
if msg.reply_to_message then
|
||||
self.database.users[tostring(msg.reply_to_message.from.id)] = msg.reply_to_message.from
|
||||
elseif msg.forward_from then
|
||||
-- Forwards only go to panoptic plugins.
|
||||
plugint = self.panoptic_plugins
|
||||
self.database.users[tostring(msg.forward_from.id)] = msg.forward_from
|
||||
elseif msg.new_chat_member then
|
||||
self.database.users[tostring(msg.new_chat_member.id)] = msg.new_chat_member
|
||||
elseif msg.left_chat_member then
|
||||
self.database.users[tostring(msg.left_chat_member.id)] = msg.left_chat_member
|
||||
end
|
||||
|
||||
-- Messages from blacklisted users only go to panoptic plugins.
|
||||
if self.database.blacklist[from_id_str] then
|
||||
plugint = self.panoptic_plugins
|
||||
end
|
||||
-- Messages from blacklisted users only go to panoptic plugins.
|
||||
if self.database.blacklist[from_id_str] then
|
||||
plugint = self.panoptic_plugins
|
||||
end
|
||||
|
||||
-- If no text, use captions.
|
||||
msg.text = msg.text or msg.caption or ''
|
||||
msg.text_lower = msg.text:lower()
|
||||
if msg.reply_to_message then
|
||||
msg.reply_to_message.text = msg.reply_to_message.text or msg.reply_to_message.caption or ''
|
||||
end
|
||||
-- If no text, use captions.
|
||||
msg.text = msg.text or msg.caption or ''
|
||||
msg.text_lower = msg.text:lower()
|
||||
if msg.reply_to_message then
|
||||
msg.reply_to_message.text = msg.reply_to_message.text or msg.reply_to_message.caption or ''
|
||||
end
|
||||
|
||||
-- Support deep linking.
|
||||
if msg.text:match('^'..config.cmd_pat..'start .+') then
|
||||
msg.text = config.cmd_pat .. utilities.input(msg.text)
|
||||
msg.text_lower = msg.text:lower()
|
||||
end
|
||||
-- Support deep linking.
|
||||
if msg.text:match('^'..config.cmd_pat..'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,
|
||||
-- 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
|
||||
if string.match(msg.text_lower, trigger) then
|
||||
local success, result = pcall(function()
|
||||
return plugin.action(self, msg, config)
|
||||
end)
|
||||
if not success then
|
||||
-- If the plugin has an error message, send it. If it does
|
||||
-- not, use the generic one specified in config. If it's set
|
||||
-- to false, do nothing.
|
||||
if plugin.error then
|
||||
utilities.send_reply(self, msg, plugin.error)
|
||||
elseif plugin.error == nil then
|
||||
utilities.send_reply(self, msg, config.errors.generic)
|
||||
end
|
||||
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config)
|
||||
msg = nil
|
||||
return
|
||||
-- Continue if the return value is true.
|
||||
elseif result ~= true then
|
||||
msg = nil
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
msg = nil
|
||||
-- Do the thing.
|
||||
for _, plugin in ipairs(plugint) do
|
||||
for _, trigger in ipairs(plugin.triggers) do
|
||||
if string.match(msg.text_lower, trigger) then
|
||||
local success, result = pcall(function()
|
||||
return plugin.action(self, msg, config)
|
||||
end)
|
||||
if not success then
|
||||
-- If the plugin has an error message, send it. If it does
|
||||
-- not, use the generic one specified in config. If it's set
|
||||
-- to false, do nothing.
|
||||
if plugin.error then
|
||||
utilities.send_reply(self, msg, plugin.error)
|
||||
elseif plugin.error == nil then
|
||||
utilities.send_reply(self, msg, config.errors.generic)
|
||||
end
|
||||
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config)
|
||||
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
|
||||
function bot:run(config)
|
||||
bot.init(self, config)
|
||||
while self.is_started do
|
||||
-- Update loop.
|
||||
local res = bindings.getUpdates(self, { timeout = 20, offset = self.last_update + 1 } )
|
||||
if res then
|
||||
-- Iterate over every new message.
|
||||
for _,v in ipairs(res.result) do
|
||||
self.last_update = v.update_id
|
||||
if v.message then
|
||||
bot.on_msg_receive(self, v.message, config)
|
||||
end
|
||||
end
|
||||
else
|
||||
print('Connection error while fetching updates.')
|
||||
end
|
||||
bot.init(self, config)
|
||||
while self.is_started do
|
||||
-- Update loop.
|
||||
local res = bindings.getUpdates(self, { timeout = 20, offset = self.last_update + 1 } )
|
||||
if res then
|
||||
-- Iterate over every new message.
|
||||
for _,v in ipairs(res.result) do
|
||||
self.last_update = v.update_id
|
||||
if v.message then
|
||||
bot.on_msg_receive(self, v.message, config)
|
||||
end
|
||||
end
|
||||
else
|
||||
print('Connection error while fetching updates.')
|
||||
end
|
||||
|
||||
-- Run cron jobs every minute.
|
||||
if self.last_cron ~= os.date('%M') then
|
||||
self.last_cron = os.date('%M')
|
||||
for i,v in ipairs(self.plugins) do
|
||||
if v.cron then -- Call each plugin's cron function, if it has one.
|
||||
local result, err = pcall(function() v.cron(self, config) end)
|
||||
if not result then
|
||||
utilities.handle_exception(self, err, 'CRON: ' .. i, config)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Run cron jobs every minute.
|
||||
if self.last_cron ~= os.date('%M') then
|
||||
self.last_cron = os.date('%M')
|
||||
for i,v in ipairs(self.plugins) do
|
||||
if v.cron then -- Call each plugin's cron function, if it has one.
|
||||
local result, err = pcall(function() v.cron(self, config) end)
|
||||
if not result then
|
||||
utilities.handle_exception(self, err, 'CRON: ' .. i, config)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Save the "database" every hour.
|
||||
if self.last_database_save ~= os.date('%H') then
|
||||
self.last_database_save = os.date('%H')
|
||||
utilities.save_data(self.database_name, self.database)
|
||||
end
|
||||
end
|
||||
-- Save the database before exiting.
|
||||
utilities.save_data(self.database_name, self.database)
|
||||
print('Halted.')
|
||||
-- Save the "database" every hour.
|
||||
if self.last_database_save ~= os.date('%H') then
|
||||
self.last_database_save = os.date('%H')
|
||||
utilities.save_data(self.database_name, self.database)
|
||||
end
|
||||
end
|
||||
-- Save the database before exiting.
|
||||
utilities.save_data(self.database_name, self.database)
|
||||
print('Halted.')
|
||||
end
|
||||
|
||||
return bot
|
||||
|
@ -1,13 +1,13 @@
|
||||
--[[
|
||||
drua-tg
|
||||
Based on JuanPotato's lua-tg (https://github.com/juanpotato/lua-tg),
|
||||
modified to work more naturally from an API bot.
|
||||
drua-tg
|
||||
Based on JuanPotato's lua-tg (https://github.com/juanpotato/lua-tg),
|
||||
modified to work more naturally from an API bot.
|
||||
|
||||
Usage:
|
||||
drua = require('drua-tg')
|
||||
drua.IP = 'localhost' -- 'localhost' is default
|
||||
drua.PORT = 4567 -- 4567 is default
|
||||
drua.message(chat_id, text)
|
||||
Usage:
|
||||
drua = require('drua-tg')
|
||||
drua.IP = 'localhost' -- 'localhost' is default
|
||||
drua.PORT = 4567 -- 4567 is default
|
||||
drua.message(chat_id, text)
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
@ -35,150 +35,150 @@ SOFTWARE.
|
||||
local SOCKET = require('socket')
|
||||
|
||||
local comtab = {
|
||||
add = { 'chat_add_user %s %s', 'channel_invite %s %s' },
|
||||
kick = { 'chat_del_user %s %s', 'channel_kick %s %s' },
|
||||
rename = { 'rename_chat %s "%s"', 'rename_channel %s "%s"' },
|
||||
link = { 'export_chat_link %s', 'export_channel_link %s' },
|
||||
photo_set = { 'chat_set_photo %s %s', 'channel_set_photo %s %s' },
|
||||
photo_get = { [0] = 'load_user_photo %s', 'load_chat_photo %s', 'load_channel_photo %s' },
|
||||
info = { [0] = 'user_info %s', 'chat_info %s', 'channel_info %s' }
|
||||
add = { 'chat_add_user %s %s', 'channel_invite %s %s' },
|
||||
kick = { 'chat_del_user %s %s', 'channel_kick %s %s' },
|
||||
rename = { 'rename_chat %s "%s"', 'rename_channel %s "%s"' },
|
||||
link = { 'export_chat_link %s', 'export_channel_link %s' },
|
||||
photo_set = { 'chat_set_photo %s %s', 'channel_set_photo %s %s' },
|
||||
photo_get = { [0] = 'load_user_photo %s', 'load_chat_photo %s', 'load_channel_photo %s' },
|
||||
info = { [0] = 'user_info %s', 'chat_info %s', 'channel_info %s' }
|
||||
}
|
||||
|
||||
local format_target = function(target)
|
||||
target = tonumber(target)
|
||||
if target < -1000000000000 then
|
||||
target = 'channel#' .. math.abs(target) - 1000000000000
|
||||
return target, 2
|
||||
elseif target < 0 then
|
||||
target = 'chat#' .. math.abs(target)
|
||||
return target, 1
|
||||
else
|
||||
target = 'user#' .. target
|
||||
return target, 0
|
||||
end
|
||||
target = tonumber(target)
|
||||
if target < -1000000000000 then
|
||||
target = 'channel#' .. math.abs(target) - 1000000000000
|
||||
return target, 2
|
||||
elseif target < 0 then
|
||||
target = 'chat#' .. math.abs(target)
|
||||
return target, 1
|
||||
else
|
||||
target = 'user#' .. target
|
||||
return target, 0
|
||||
end
|
||||
end
|
||||
|
||||
local escape = function(text)
|
||||
text = text:gsub('\\', '\\\\')
|
||||
text = text:gsub('\n', '\\n')
|
||||
text = text:gsub('\t', '\\t')
|
||||
text = text:gsub('"', '\\"')
|
||||
return text
|
||||
text = text:gsub('\\', '\\\\')
|
||||
text = text:gsub('\n', '\\n')
|
||||
text = text:gsub('\t', '\\t')
|
||||
text = text:gsub('"', '\\"')
|
||||
return text
|
||||
end
|
||||
|
||||
local drua = {
|
||||
IP = 'localhost',
|
||||
PORT = 4567
|
||||
IP = 'localhost',
|
||||
PORT = 4567
|
||||
}
|
||||
|
||||
drua.send = function(command, do_receive)
|
||||
local s = SOCKET.connect(drua.IP, drua.PORT)
|
||||
assert(s, '\nUnable to connect to tg session.')
|
||||
s:send(command..'\n')
|
||||
local output
|
||||
if do_receive then
|
||||
output = string.match(s:receive('*l'), 'ANSWER (%d+)')
|
||||
output = s:receive(tonumber(output)):gsub('\n$', '')
|
||||
end
|
||||
s:close()
|
||||
return output
|
||||
local s = SOCKET.connect(drua.IP, drua.PORT)
|
||||
assert(s, '\nUnable to connect to tg session.')
|
||||
s:send(command..'\n')
|
||||
local output
|
||||
if do_receive then
|
||||
output = string.match(s:receive('*l'), 'ANSWER (%d+)')
|
||||
output = s:receive(tonumber(output)):gsub('\n$', '')
|
||||
end
|
||||
s:close()
|
||||
return output
|
||||
end
|
||||
|
||||
drua.message = function(target, text)
|
||||
target = format_target(target)
|
||||
text = escape(text)
|
||||
local command = 'msg %s "%s"'
|
||||
command = command:format(target, text)
|
||||
return drua.send(command)
|
||||
target = format_target(target)
|
||||
text = escape(text)
|
||||
local command = 'msg %s "%s"'
|
||||
command = command:format(target, text)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.send_photo = function(target, photo)
|
||||
target = format_target(target)
|
||||
local command = 'send_photo %s %s'
|
||||
command = command:format(target, photo)
|
||||
return drua.send(command)
|
||||
target = format_target(target)
|
||||
local command = 'send_photo %s %s'
|
||||
command = command:format(target, photo)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.add_user = function(chat, target)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
target = format_target(target)
|
||||
local command = comtab.add[a]:format(chat, target)
|
||||
return drua.send(command)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
target = format_target(target)
|
||||
local command = comtab.add[a]:format(chat, target)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.kick_user = function(chat, target)
|
||||
-- Get the group info so tg will recognize the target.
|
||||
drua.get_info(chat)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
target = format_target(target)
|
||||
local command = comtab.kick[a]:format(chat, target)
|
||||
return drua.send(command)
|
||||
-- Get the group info so tg will recognize the target.
|
||||
drua.get_info(chat)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
target = format_target(target)
|
||||
local command = comtab.kick[a]:format(chat, target)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.rename_chat = function(chat, name)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.rename[a]:format(chat, name)
|
||||
return drua.send(command)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.rename[a]:format(chat, name)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.export_link = function(chat)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.link[a]:format(chat)
|
||||
return drua.send(command, true)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.link[a]:format(chat)
|
||||
return drua.send(command, true)
|
||||
end
|
||||
|
||||
drua.get_photo = function(chat)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.photo_get[a]:format(chat)
|
||||
local output = drua.send(command, true)
|
||||
if output:match('FAIL') then
|
||||
return false
|
||||
else
|
||||
return output:match('Saved to (.+)')
|
||||
end
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.photo_get[a]:format(chat)
|
||||
local output = drua.send(command, true)
|
||||
if output:match('FAIL') then
|
||||
return false
|
||||
else
|
||||
return output:match('Saved to (.+)')
|
||||
end
|
||||
end
|
||||
|
||||
drua.set_photo = function(chat, photo)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.photo_set[a]:format(chat, photo)
|
||||
return drua.send(command)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.photo_set[a]:format(chat, photo)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.get_info = function(target)
|
||||
local a
|
||||
target, a = format_target(target)
|
||||
local command = comtab.info[a]:format(target)
|
||||
return drua.send(command, true)
|
||||
local a
|
||||
target, a = format_target(target)
|
||||
local command = comtab.info[a]:format(target)
|
||||
return drua.send(command, true)
|
||||
end
|
||||
|
||||
drua.channel_set_admin = function(chat, user, rank)
|
||||
chat = format_target(chat)
|
||||
user = format_target(user)
|
||||
local command = 'channel_set_admin %s %s %s'
|
||||
command = command:format(chat, user, rank)
|
||||
return drua.send(command)
|
||||
chat = format_target(chat)
|
||||
user = format_target(user)
|
||||
local command = 'channel_set_admin %s %s %s'
|
||||
command = command:format(chat, user, rank)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.channel_set_about = function(chat, text)
|
||||
chat = format_target(chat)
|
||||
text = escape(text)
|
||||
local command = 'channel_set_about %s "%s"'
|
||||
command = command:format(chat, text)
|
||||
return drua.send(command)
|
||||
chat = format_target(chat)
|
||||
text = escape(text)
|
||||
local command = 'channel_set_about %s "%s"'
|
||||
command = command:format(chat, text)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.block = function(user)
|
||||
return drua.send('block_user user#' .. user)
|
||||
return drua.send('block_user user#' .. user)
|
||||
end
|
||||
|
||||
drua.unblock = function(user)
|
||||
return drua.send('unblock_user user#' .. user)
|
||||
return drua.send('unblock_user user#' .. user)
|
||||
end
|
||||
|
||||
return drua
|
||||
|
@ -7,13 +7,13 @@ about.command = 'about'
|
||||
about.doc = 'Returns information about the bot.'
|
||||
|
||||
function about:init(config)
|
||||
about.text = config.about_text .. '\nBased on [otouto](http://github.com/topkecleon/otouto) v'..bot.version..' by topkecleon.'
|
||||
about.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('about'):t('start').table
|
||||
about.text = config.about_text .. '\nBased on [otouto](http://github.com/topkecleon/otouto) v'..bot.version..' by topkecleon.'
|
||||
about.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('about'):t('start').table
|
||||
end
|
||||
|
||||
function about:action(msg, config)
|
||||
utilities.send_message(self, msg.chat.id, about.text, true, nil, true)
|
||||
utilities.send_message(self, msg.chat.id, about.text, true, nil, true)
|
||||
end
|
||||
|
||||
return about
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,47 +10,47 @@ local utilities = require('otouto.utilities')
|
||||
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.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('apod', true).table
|
||||
apod.doc = [[
|
||||
/apod [YYYY-MM-DD]
|
||||
Returns the Astronomy Picture of the Day.
|
||||
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.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')
|
||||
end
|
||||
|
||||
function apod:action(msg, config)
|
||||
local input = utilities.input(msg.text)
|
||||
local url = apod.base_url
|
||||
local date = os.date('%F')
|
||||
if input then
|
||||
if input:match('^(%d+)%-(%d+)%-(%d+)$') then
|
||||
url = url .. '&date=' .. URL.escape(input)
|
||||
date = input
|
||||
end
|
||||
end
|
||||
local input = utilities.input(msg.text)
|
||||
local url = apod.base_url
|
||||
local date = os.date('%F')
|
||||
if input then
|
||||
if input:match('^(%d+)%-(%d+)%-(%d+)$') then
|
||||
url = url .. '&date=' .. URL.escape(input)
|
||||
date = input
|
||||
end
|
||||
end
|
||||
|
||||
local jstr, code = HTTPS.request(url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local jstr, code = HTTPS.request(url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local data = JSON.decode(jstr)
|
||||
if data.error then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(jstr)
|
||||
if data.error then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
local output = string.format(
|
||||
'<b>%s (</b><a href="%s">%s</a><b>)</b>\n%s',
|
||||
utilities.html_escape(data.title),
|
||||
utilities.html_escape(data.hdurl or data.url),
|
||||
date,
|
||||
utilities.html_escape(data.explanation)
|
||||
)
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, 'html')
|
||||
local output = string.format(
|
||||
'<b>%s (</b><a href="%s">%s</a><b>)</b>\n%s',
|
||||
utilities.html_escape(data.title),
|
||||
utilities.html_escape(data.hdurl or data.url),
|
||||
date,
|
||||
utilities.html_escape(data.explanation)
|
||||
)
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, 'html')
|
||||
end
|
||||
|
||||
return apod
|
||||
|
@ -5,8 +5,8 @@ local utilities = require('otouto.utilities')
|
||||
bandersnatch.command = 'bandersnatch'
|
||||
|
||||
function bandersnatch:init(config)
|
||||
bandersnatch.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('bandersnatch'):t('bc').table
|
||||
bandersnatch.doc = 'Shun the frumious Bandersnatch. \nAlias: ' .. config.cmd_pat .. 'bc'
|
||||
bandersnatch.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('bandersnatch'):t('bc').table
|
||||
bandersnatch.doc = 'Shun the frumious Bandersnatch. \nAlias: ' .. config.cmd_pat .. 'bc'
|
||||
end
|
||||
|
||||
local fullnames = { "Wimbledon Tennismatch", "Rinkydink Curdlesnoot", "Butawhiteboy Cantbekhan", "Benadryl Claritin", "Bombadil Rivendell", "Wanda's Crotchfruit", "Biblical Concubine", "Syphilis Cankersore", "Buckminster Fullerene", "Bourgeoisie Capitalist" }
|
||||
@ -17,15 +17,15 @@ local lastnames = { "Coddleswort", "Crumplesack", "Curdlesnoot", "Calldispatch",
|
||||
|
||||
function bandersnatch:action(msg)
|
||||
|
||||
local output
|
||||
local output
|
||||
|
||||
if math.random(10) == 10 then
|
||||
output = fullnames[math.random(#fullnames)]
|
||||
else
|
||||
output = firstnames[math.random(#firstnames)] .. ' ' .. lastnames[math.random(#lastnames)]
|
||||
end
|
||||
if math.random(10) == 10 then
|
||||
output = fullnames[math.random(#fullnames)]
|
||||
else
|
||||
output = firstnames[math.random(#firstnames)] .. ' ' .. lastnames[math.random(#lastnames)]
|
||||
end
|
||||
|
||||
utilities.send_message(self, msg.chat.id, '_'..output..'_', true, nil, true)
|
||||
utilities.send_message(self, msg.chat.id, '_'..output..'_', true, nil, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -5,12 +5,12 @@ local URL = require('socket.url')
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function bible:init(config)
|
||||
assert(config.biblia_api_key,
|
||||
'bible.lua requires a Biblia API key from http://api.biblia.com.'
|
||||
)
|
||||
assert(config.biblia_api_key,
|
||||
'bible.lua requires a Biblia API key from http://api.biblia.com.'
|
||||
)
|
||||
|
||||
bible.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('bible', true):t('b', true).table
|
||||
bible.doc = config.cmd_pat .. [[bible <reference>
|
||||
bible.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('bible', true):t('b', true).table
|
||||
bible.doc = config.cmd_pat .. [[bible <reference>
|
||||
Returns a verse from the American Standard Version of the Bible, or an apocryphal verse from the King James Version. Results from biblia.com.
|
||||
Alias: ]] .. config.cmd_pat .. 'b'
|
||||
end
|
||||
@ -19,30 +19,30 @@ bible.command = 'bible <reference>'
|
||||
|
||||
function bible:action(msg, config)
|
||||
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, bible.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, bible.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local url = 'http://api.biblia.com/v1/bible/content/ASV.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input)
|
||||
local url = 'http://api.biblia.com/v1/bible/content/ASV.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input)
|
||||
|
||||
local output, res = HTTP.request(url)
|
||||
local output, res = HTTP.request(url)
|
||||
|
||||
if not output or res ~= 200 or output:len() == 0 then
|
||||
url = 'http://api.biblia.com/v1/bible/content/KJVAPOC.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input)
|
||||
output, res = HTTP.request(url)
|
||||
end
|
||||
if not output or res ~= 200 or output:len() == 0 then
|
||||
url = 'http://api.biblia.com/v1/bible/content/KJVAPOC.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input)
|
||||
output, res = HTTP.request(url)
|
||||
end
|
||||
|
||||
if not output or res ~= 200 or output:len() == 0 then
|
||||
output = config.errors.results
|
||||
end
|
||||
if not output or res ~= 200 or output:len() == 0 then
|
||||
output = config.errors.results
|
||||
end
|
||||
|
||||
if output:len() > 4000 then
|
||||
output = 'The text is too long to post here. Try being more specific.'
|
||||
end
|
||||
if output:len() > 4000 then
|
||||
output = 'The text is too long to post here. Try being more specific.'
|
||||
end
|
||||
|
||||
utilities.send_reply(self, msg, output)
|
||||
utilities.send_reply(self, msg, output)
|
||||
|
||||
end
|
||||
|
||||
|
@ -14,65 +14,65 @@ bing.command = 'bing <query>'
|
||||
bing.search_url = 'https://api.datamarket.azure.com/Data.ashx/Bing/Search/Web?Query=\'%s\'&$format=json'
|
||||
|
||||
function bing:init(config)
|
||||
assert(config.bing_api_key,
|
||||
'bing.lua requires a Bing API key from http://datamarket.azure.com/dataset/bing/search.'
|
||||
)
|
||||
assert(config.bing_api_key,
|
||||
'bing.lua requires a Bing API key from http://datamarket.azure.com/dataset/bing/search.'
|
||||
)
|
||||
|
||||
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.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>
|
||||
Returns the top web results from Bing.
|
||||
Aliases: /g, /google
|
||||
]]
|
||||
bing.doc = bing.doc:gsub('/', config.cmd_pat)
|
||||
]]
|
||||
bing.doc = bing.doc:gsub('/', config.cmd_pat)
|
||||
|
||||
end
|
||||
|
||||
function bing:action(msg, config)
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, bing.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, bing.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local url = bing.search_url:format(URL.escape(input))
|
||||
local resbody = {}
|
||||
local _, code = https.request{
|
||||
url = url,
|
||||
headers = bing.headers,
|
||||
sink = ltn12.sink.table(resbody),
|
||||
}
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local url = bing.search_url:format(URL.escape(input))
|
||||
local resbody = {}
|
||||
local _, code = https.request{
|
||||
url = url,
|
||||
headers = bing.headers,
|
||||
sink = ltn12.sink.table(resbody),
|
||||
}
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local data = JSON.decode(table.concat(resbody))
|
||||
-- Four results in a group, eight in private.
|
||||
local limit = msg.chat.type == 'private' and 8 or 4
|
||||
-- No more results than provided.
|
||||
limit = limit > #data.d.results and #data.d.results or limit
|
||||
if limit == 0 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(table.concat(resbody))
|
||||
-- Four results in a group, eight in private.
|
||||
local limit = msg.chat.type == 'private' and 8 or 4
|
||||
-- No more results than provided.
|
||||
limit = limit > #data.d.results and #data.d.results or limit
|
||||
if limit == 0 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
local reslist = {}
|
||||
for i = 1, limit do
|
||||
table.insert(reslist, string.format(
|
||||
'• <a href="%s">%s</a>',
|
||||
utilities.html_escape(data.d.results[i].Url),
|
||||
utilities.html_escape(data.d.results[i].Title)
|
||||
))
|
||||
end
|
||||
local output = string.format(
|
||||
'<b>Search results for</b> <i>%s</i><b>:</b>\n%s',
|
||||
utilities.html_escape(input),
|
||||
table.concat(reslist, '\n')
|
||||
)
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||
local reslist = {}
|
||||
for i = 1, limit do
|
||||
table.insert(reslist, string.format(
|
||||
'• <a href="%s">%s</a>',
|
||||
utilities.html_escape(data.d.results[i].Url),
|
||||
utilities.html_escape(data.d.results[i].Title)
|
||||
))
|
||||
end
|
||||
local output = string.format(
|
||||
'<b>Search results for</b> <i>%s</i><b>:</b>\n%s',
|
||||
utilities.html_escape(input),
|
||||
table.concat(reslist, '\n')
|
||||
)
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||
end
|
||||
|
||||
return bing
|
||||
|
@ -3,92 +3,92 @@ local utilities = require('otouto.utilities')
|
||||
local blacklist = {}
|
||||
|
||||
function blacklist:init(config)
|
||||
blacklist.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('blacklist', true):t('unblacklist', true).table
|
||||
blacklist.error = false
|
||||
blacklist.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('blacklist', true):t('unblacklist', true).table
|
||||
blacklist.error = false
|
||||
end
|
||||
|
||||
function blacklist:action(msg, config)
|
||||
if msg.from.id ~= config.admin then return true end
|
||||
local targets = {}
|
||||
if msg.reply_to_message then
|
||||
table.insert(targets, {
|
||||
id = msg.reply_to_message.from.id,
|
||||
id_str = tostring(msg.reply_to_message.from.id),
|
||||
name = utilities.build_name(msg.reply_to_message.from.first_name, msg.reply_to_message.from.last_name)
|
||||
})
|
||||
else
|
||||
local input = utilities.input(msg.text)
|
||||
if input then
|
||||
for user in input:gmatch('%g+') do
|
||||
if self.database.users[user] then
|
||||
table.insert(targets, {
|
||||
id = self.database.users[user].id,
|
||||
id_str = tostring(self.database.users[user].id),
|
||||
name = utilities.build_name(self.database.users[user].first_name, self.database.users[user].last_name)
|
||||
})
|
||||
elseif tonumber(user) then
|
||||
local t = {
|
||||
id_str = user,
|
||||
id = tonumber(user)
|
||||
}
|
||||
if tonumber(user) < 0 then
|
||||
t.name = 'Group (' .. user .. ')'
|
||||
else
|
||||
t.name = 'Unknown (' .. user .. ')'
|
||||
end
|
||||
table.insert(targets, t)
|
||||
elseif user:match('^@') then
|
||||
local u = utilities.resolve_username(self, user)
|
||||
if u then
|
||||
table.insert(targets, {
|
||||
id = u.id,
|
||||
id_str = tostring(u.id),
|
||||
name = utilities.build_name(u.first_name, u.last_name)
|
||||
})
|
||||
else
|
||||
table.insert(targets, { err = 'Sorry, I do not recognize that username ('..user..').' })
|
||||
end
|
||||
else
|
||||
table.insert(targets, { err = 'Invalid username or ID ('..user..').' })
|
||||
end
|
||||
end
|
||||
else
|
||||
utilities.send_reply(self, msg, 'Please specify a user or users via reply, username, or ID, or a group or groups via ID.')
|
||||
return
|
||||
end
|
||||
end
|
||||
local output = ''
|
||||
if msg.text:match('^'..config.cmd_pat..'blacklist') then
|
||||
for _, target in ipairs(targets) do
|
||||
if target.err then
|
||||
output = output .. target.err .. '\n'
|
||||
elseif self.database.blacklist[target.id_str] then
|
||||
output = output .. target.name .. ' is already blacklisted.\n'
|
||||
else
|
||||
self.database.blacklist[target.id_str] = true
|
||||
output = output .. target.name .. ' is now blacklisted.\n'
|
||||
if config.drua_block_on_blacklist and target.id > 0 then
|
||||
require('otouto.drua-tg').block(target.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif msg.text:match('^'..config.cmd_pat..'unblacklist') then
|
||||
for _, target in ipairs(targets) do
|
||||
if target.err then
|
||||
output = output .. target.err .. '\n'
|
||||
elseif not self.database.blacklist[target.id_str] then
|
||||
output = output .. target.name .. ' is not blacklisted.\n'
|
||||
else
|
||||
self.database.blacklist[target.id_str] = nil
|
||||
output = output .. target.name .. ' is no longer blacklisted.\n'
|
||||
if config.drua_block_on_blacklist and target.id > 0 then
|
||||
require('otouto.drua-tg').unblock(target.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
utilities.send_reply(self, msg, output)
|
||||
if msg.from.id ~= config.admin then return true end
|
||||
local targets = {}
|
||||
if msg.reply_to_message then
|
||||
table.insert(targets, {
|
||||
id = msg.reply_to_message.from.id,
|
||||
id_str = tostring(msg.reply_to_message.from.id),
|
||||
name = utilities.build_name(msg.reply_to_message.from.first_name, msg.reply_to_message.from.last_name)
|
||||
})
|
||||
else
|
||||
local input = utilities.input(msg.text)
|
||||
if input then
|
||||
for user in input:gmatch('%g+') do
|
||||
if self.database.users[user] then
|
||||
table.insert(targets, {
|
||||
id = self.database.users[user].id,
|
||||
id_str = tostring(self.database.users[user].id),
|
||||
name = utilities.build_name(self.database.users[user].first_name, self.database.users[user].last_name)
|
||||
})
|
||||
elseif tonumber(user) then
|
||||
local t = {
|
||||
id_str = user,
|
||||
id = tonumber(user)
|
||||
}
|
||||
if tonumber(user) < 0 then
|
||||
t.name = 'Group (' .. user .. ')'
|
||||
else
|
||||
t.name = 'Unknown (' .. user .. ')'
|
||||
end
|
||||
table.insert(targets, t)
|
||||
elseif user:match('^@') then
|
||||
local u = utilities.resolve_username(self, user)
|
||||
if u then
|
||||
table.insert(targets, {
|
||||
id = u.id,
|
||||
id_str = tostring(u.id),
|
||||
name = utilities.build_name(u.first_name, u.last_name)
|
||||
})
|
||||
else
|
||||
table.insert(targets, { err = 'Sorry, I do not recognize that username ('..user..').' })
|
||||
end
|
||||
else
|
||||
table.insert(targets, { err = 'Invalid username or ID ('..user..').' })
|
||||
end
|
||||
end
|
||||
else
|
||||
utilities.send_reply(self, msg, 'Please specify a user or users via reply, username, or ID, or a group or groups via ID.')
|
||||
return
|
||||
end
|
||||
end
|
||||
local output = ''
|
||||
if msg.text:match('^'..config.cmd_pat..'blacklist') then
|
||||
for _, target in ipairs(targets) do
|
||||
if target.err then
|
||||
output = output .. target.err .. '\n'
|
||||
elseif self.database.blacklist[target.id_str] then
|
||||
output = output .. target.name .. ' is already blacklisted.\n'
|
||||
else
|
||||
self.database.blacklist[target.id_str] = true
|
||||
output = output .. target.name .. ' is now blacklisted.\n'
|
||||
if config.drua_block_on_blacklist and target.id > 0 then
|
||||
require('otouto.drua-tg').block(target.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif msg.text:match('^'..config.cmd_pat..'unblacklist') then
|
||||
for _, target in ipairs(targets) do
|
||||
if target.err then
|
||||
output = output .. target.err .. '\n'
|
||||
elseif not self.database.blacklist[target.id_str] then
|
||||
output = output .. target.name .. ' is not blacklisted.\n'
|
||||
else
|
||||
self.database.blacklist[target.id_str] = nil
|
||||
output = output .. target.name .. ' is no longer blacklisted.\n'
|
||||
if config.drua_block_on_blacklist and target.id > 0 then
|
||||
require('otouto.drua-tg').unblock(target.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
utilities.send_reply(self, msg, output)
|
||||
end
|
||||
|
||||
return blacklist
|
||||
|
@ -7,22 +7,22 @@ local utilities = require('otouto.utilities')
|
||||
calc.command = 'calc <expression>'
|
||||
|
||||
function calc:init(config)
|
||||
calc.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('calc', true).table
|
||||
calc.doc = config.cmd_pat .. [[calc <expression>
|
||||
calc.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('calc', true).table
|
||||
calc.doc = config.cmd_pat .. [[calc <expression>
|
||||
Returns solutions to mathematical expressions and conversions between common units. Results provided by mathjs.org.]]
|
||||
end
|
||||
|
||||
function calc:action(msg, config)
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, calc.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, calc.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local url = 'https://api.mathjs.org/v1/?expr=' .. URL.escape(input)
|
||||
local output = HTTPS.request(url)
|
||||
output = output and '`'..output..'`' or config.errors.connection
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
local url = 'https://api.mathjs.org/v1/?expr=' .. URL.escape(input)
|
||||
local output = HTTPS.request(url)
|
||||
output = output and '`'..output..'`' or config.errors.connection
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
end
|
||||
|
||||
return calc
|
||||
|
@ -7,22 +7,22 @@ local utilities = require('otouto.utilities')
|
||||
local catfact = {}
|
||||
|
||||
function catfact:init(config)
|
||||
catfact.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('catfact', true).table
|
||||
catfact.command = 'catfact'
|
||||
catfact.doc = 'Returns a cat fact.'
|
||||
catfact.url = 'http://catfacts-api.appspot.com/api/facts'
|
||||
catfact.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('catfact', true).table
|
||||
catfact.command = 'catfact'
|
||||
catfact.doc = 'Returns a cat fact.'
|
||||
catfact.url = 'http://catfacts-api.appspot.com/api/facts'
|
||||
end
|
||||
|
||||
function catfact:action(msg, config)
|
||||
local jstr, code = HTTP.request(catfact.url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(jstr)
|
||||
local output = '*Cat Fact*\n_' .. data.facts[1] .. '_'
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
local jstr, code = HTTP.request(catfact.url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(jstr)
|
||||
local output = '*Cat Fact*\n_' .. data.facts[1] .. '_'
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
end
|
||||
|
||||
return catfact
|
||||
|
@ -4,12 +4,12 @@ local HTTP = require('socket.http')
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function cats:init(config)
|
||||
if not config.thecatapi_key then
|
||||
print('Missing config value: thecatapi_key.')
|
||||
print('cats.lua will be enabled, but there are more features with a key.')
|
||||
end
|
||||
if not config.thecatapi_key then
|
||||
print('Missing config value: thecatapi_key.')
|
||||
print('cats.lua will be enabled, but there are more features with a key.')
|
||||
end
|
||||
|
||||
cats.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('cat').table
|
||||
cats.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('cat').table
|
||||
end
|
||||
|
||||
cats.command = 'cat'
|
||||
@ -17,21 +17,21 @@ cats.doc = 'Returns a cat!'
|
||||
|
||||
function cats:action(msg, config)
|
||||
|
||||
local url = 'http://thecatapi.com/api/images/get?format=html&type=jpg'
|
||||
if config.thecatapi_key then
|
||||
url = url .. '&api_key=' .. config.thecatapi_key
|
||||
end
|
||||
local url = 'http://thecatapi.com/api/images/get?format=html&type=jpg'
|
||||
if config.thecatapi_key then
|
||||
url = url .. '&api_key=' .. config.thecatapi_key
|
||||
end
|
||||
|
||||
local str, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local str, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
str = str:match('<img src="(.-)">')
|
||||
local output = '[Cat!]('..str..')'
|
||||
str = str:match('<img src="(.-)">')
|
||||
local output = '[Cat!]('..str..')'
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -4,9 +4,9 @@ local bindings = require('otouto.bindings')
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function channel:init(config)
|
||||
channel.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('ch', true).table
|
||||
channel.command = 'ch <channel> \\n <message>'
|
||||
channel.doc = config.cmd_pat .. [[ch <channel>
|
||||
channel.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('ch', true).table
|
||||
channel.command = 'ch <channel> \\n <message>'
|
||||
channel.doc = config.cmd_pat .. [[ch <channel>
|
||||
<message>
|
||||
|
||||
Sends a message to a channel. Channel may be specified via ID or username. Messages are markdown-enabled. Users may only send messages to channels for which they are the owner or an administrator.
|
||||
@ -20,41 +20,41 @@ The following markdown syntax is supported:
|
||||
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(self, { 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(self, 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
|
||||
end
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
-- 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(self, { 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(self, 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
|
||||
end
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
end
|
||||
|
||||
return channel
|
||||
|
@ -7,22 +7,22 @@ local utilities = require('otouto.utilities')
|
||||
local chuck = {}
|
||||
|
||||
function chuck:init(config)
|
||||
chuck.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('chuck', true):t('cn', true):t('chucknorris', true).table
|
||||
chuck.command = 'chuck'
|
||||
chuck.doc = 'Returns a fact about Chuck Norris.'
|
||||
chuck.url = 'http://api.icndb.com/jokes/random'
|
||||
chuck.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('chuck', true):t('cn', true):t('chucknorris', true).table
|
||||
chuck.command = 'chuck'
|
||||
chuck.doc = 'Returns a fact about Chuck Norris.'
|
||||
chuck.url = 'http://api.icndb.com/jokes/random'
|
||||
end
|
||||
|
||||
function chuck:action(msg, config)
|
||||
local jstr, code = HTTP.request(chuck.url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(jstr)
|
||||
local output = '*Chuck Norris Fact*\n_' .. data.value.joke .. '_'
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
local jstr, code = HTTP.request(chuck.url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(jstr)
|
||||
local output = '*Chuck Norris Fact*\n_' .. data.value.joke .. '_'
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
end
|
||||
|
||||
return chuck
|
||||
|
@ -7,30 +7,30 @@ local bindings = require('otouto.bindings')
|
||||
local cleverbot = {}
|
||||
|
||||
function cleverbot:init(config)
|
||||
cleverbot.name = '^' .. self.info.first_name:lower() .. ', '
|
||||
cleverbot.username = '^@' .. self.info.username:lower() .. ', '
|
||||
cleverbot.triggers = {
|
||||
'^' .. self.info.first_name:lower() .. ', ',
|
||||
'^@' .. self.info.username:lower() .. ', '
|
||||
}
|
||||
cleverbot.url = config.chatter.cleverbot_api
|
||||
cleverbot.error = false
|
||||
cleverbot.name = '^' .. self.info.first_name:lower() .. ', '
|
||||
cleverbot.username = '^@' .. self.info.username:lower() .. ', '
|
||||
cleverbot.triggers = {
|
||||
'^' .. self.info.first_name:lower() .. ', ',
|
||||
'^@' .. self.info.username:lower() .. ', '
|
||||
}
|
||||
cleverbot.url = config.chatter.cleverbot_api
|
||||
cleverbot.error = false
|
||||
end
|
||||
|
||||
function cleverbot:action(msg, config)
|
||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' })
|
||||
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(self, msg.chat.id, config.chatter.connection)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(jstr)
|
||||
if not data.clever then
|
||||
utilities.send_message(self, msg.chat.id, config.chatter.response)
|
||||
return
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, data.clever)
|
||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' })
|
||||
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(self, msg.chat.id, config.chatter.connection)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(jstr)
|
||||
if not data.clever then
|
||||
utilities.send_message(self, msg.chat.id, config.chatter.response)
|
||||
return
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, data.clever)
|
||||
end
|
||||
|
||||
return cleverbot
|
||||
|
@ -8,19 +8,19 @@ commit.command = 'commit'
|
||||
commit.doc = 'Returns a commit message from whatthecommit.com.'
|
||||
|
||||
function commit:init(config)
|
||||
commit.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('commit').table
|
||||
commit.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('commit').table
|
||||
end
|
||||
|
||||
function commit:action(msg)
|
||||
bindings.request(
|
||||
self,
|
||||
'sendMessage',
|
||||
{
|
||||
chat_id = msg.chat.id,
|
||||
text = '```\n' .. (http.request('http://whatthecommit.com/index.txt')) .. '\n```',
|
||||
parse_mode = 'Markdown'
|
||||
}
|
||||
)
|
||||
bindings.request(
|
||||
self,
|
||||
'sendMessage',
|
||||
{
|
||||
chat_id = msg.chat.id,
|
||||
text = '```\n' .. (http.request('http://whatthecommit.com/index.txt')) .. '\n```',
|
||||
parse_mode = 'Markdown'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
return commit
|
||||
|
@ -6,52 +6,52 @@ local utilities = require('otouto.utilities')
|
||||
local cmd_pat -- Prevents the command from being uncallable.
|
||||
|
||||
function control:init(config)
|
||||
cmd_pat = config.cmd_pat
|
||||
control.triggers = utilities.triggers(self.info.username, cmd_pat,
|
||||
{'^'..cmd_pat..'script'}):t('reload', true):t('halt').table
|
||||
cmd_pat = config.cmd_pat
|
||||
control.triggers = utilities.triggers(self.info.username, cmd_pat,
|
||||
{'^'..cmd_pat..'script'}):t('reload', true):t('halt').table
|
||||
end
|
||||
|
||||
function control:action(msg, config)
|
||||
|
||||
if msg.from.id ~= config.admin then
|
||||
return
|
||||
end
|
||||
if msg.from.id ~= config.admin then
|
||||
return
|
||||
end
|
||||
|
||||
if msg.date < os.time() - 2 then return end
|
||||
if msg.date < os.time() - 2 then return end
|
||||
|
||||
if msg.text_lower:match('^'..cmd_pat..'reload') then
|
||||
for pac, _ in pairs(package.loaded) do
|
||||
if pac:match('^otouto%.plugins%.') then
|
||||
package.loaded[pac] = nil
|
||||
end
|
||||
end
|
||||
package.loaded['otouto.bindings'] = nil
|
||||
package.loaded['otouto.utilities'] = nil
|
||||
package.loaded['otouto.drua-tg'] = nil
|
||||
package.loaded['config'] = nil
|
||||
if not msg.text_lower:match('%-config') then
|
||||
for k, v in pairs(require('config')) do
|
||||
config[k] = v
|
||||
end
|
||||
end
|
||||
bot.init(self, config)
|
||||
utilities.send_reply(self, msg, 'Bot reloaded!')
|
||||
elseif msg.text_lower:match('^'..cmd_pat..'halt') then
|
||||
self.is_started = false
|
||||
utilities.send_reply(self, msg, 'Stopping bot!')
|
||||
elseif msg.text_lower:match('^'..cmd_pat..'script') then
|
||||
local input = msg.text_lower:match('^'..cmd_pat..'script\n(.+)')
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, 'usage: ```\n'..cmd_pat..'script\n'..cmd_pat..'command <arg>\n...\n```', true)
|
||||
return
|
||||
end
|
||||
input = input .. '\n'
|
||||
for command in input:gmatch('(.-)\n') do
|
||||
command = utilities.trim(command)
|
||||
msg.text = command
|
||||
bot.on_msg_receive(self, msg, config)
|
||||
end
|
||||
end
|
||||
if msg.text_lower:match('^'..cmd_pat..'reload') then
|
||||
for pac, _ in pairs(package.loaded) do
|
||||
if pac:match('^otouto%.plugins%.') then
|
||||
package.loaded[pac] = nil
|
||||
end
|
||||
end
|
||||
package.loaded['otouto.bindings'] = nil
|
||||
package.loaded['otouto.utilities'] = nil
|
||||
package.loaded['otouto.drua-tg'] = nil
|
||||
package.loaded['config'] = nil
|
||||
if not msg.text_lower:match('%-config') then
|
||||
for k, v in pairs(require('config')) do
|
||||
config[k] = v
|
||||
end
|
||||
end
|
||||
bot.init(self, config)
|
||||
utilities.send_reply(self, msg, 'Bot reloaded!')
|
||||
elseif msg.text_lower:match('^'..cmd_pat..'halt') then
|
||||
self.is_started = false
|
||||
utilities.send_reply(self, msg, 'Stopping bot!')
|
||||
elseif msg.text_lower:match('^'..cmd_pat..'script') then
|
||||
local input = msg.text_lower:match('^'..cmd_pat..'script\n(.+)')
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, 'usage: ```\n'..cmd_pat..'script\n'..cmd_pat..'command <arg>\n...\n```', true)
|
||||
return
|
||||
end
|
||||
input = input .. '\n'
|
||||
for command in input:gmatch('(.-)\n') do
|
||||
command = utilities.trim(command)
|
||||
msg.text = command
|
||||
bot.on_msg_receive(self, msg, config)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
@ -6,8 +6,8 @@ local utilities = require('otouto.utilities')
|
||||
currency.command = 'cash [amount] <from> to <to>'
|
||||
|
||||
function currency:init(config)
|
||||
currency.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('cash', true).table
|
||||
currency.doc = config.cmd_pat .. [[cash [amount] <from> to <to>
|
||||
currency.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('cash', true).table
|
||||
currency.doc = config.cmd_pat .. [[cash [amount] <from> to <to>
|
||||
Example: ]] .. config.cmd_pat .. [[cash 5 USD to EUR
|
||||
Returns exchange rates for various currencies.
|
||||
Source: Google Finance.]]
|
||||
@ -15,44 +15,44 @@ end
|
||||
|
||||
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(self, msg.chat.id, currency.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
local input = msg.text:upper()
|
||||
if not input:match('%a%a%a TO %a%a%a') then
|
||||
utilities.send_message(self, msg.chat.id, currency.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
|
||||
local from = input:match('(%a%a%a) TO')
|
||||
local to = input:match('TO (%a%a%a)')
|
||||
local amount = utilities.get_word(input, 2)
|
||||
amount = tonumber(amount) or 1
|
||||
local result = 1
|
||||
local from = input:match('(%a%a%a) TO')
|
||||
local to = input:match('TO (%a%a%a)')
|
||||
local amount = utilities.get_word(input, 2)
|
||||
amount = tonumber(amount) or 1
|
||||
local result = 1
|
||||
|
||||
local url = 'https://www.google.com/finance/converter'
|
||||
local url = 'https://www.google.com/finance/converter'
|
||||
|
||||
if from ~= to then
|
||||
if from ~= to then
|
||||
|
||||
url = url .. '?from=' .. from .. '&to=' .. to .. '&a=' .. amount
|
||||
local str, res = HTTPS.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
url = url .. '?from=' .. from .. '&to=' .. to .. '&a=' .. amount
|
||||
local str, res = HTTPS.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
str = str:match('<span class=bld>(.*) %u+</span>')
|
||||
if not str then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
str = str:match('<span class=bld>(.*) %u+</span>')
|
||||
if not str then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
result = string.format('%.2f', str)
|
||||
result = string.format('%.2f', str)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
local output = amount .. ' ' .. from .. ' = ' .. result .. ' ' .. to .. '\n\n'
|
||||
output = output .. os.date('!%F %T UTC') .. '\nSource: Google Finance`'
|
||||
output = '```\n' .. output .. '\n```'
|
||||
local output = amount .. ' ' .. from .. ' = ' .. result .. ' ' .. to .. '\n\n'
|
||||
output = output .. os.date('!%F %T UTC') .. '\nSource: Google Finance`'
|
||||
output = '```\n' .. output .. '\n```'
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -5,49 +5,49 @@ local utilities = require('otouto.utilities')
|
||||
dice.command = 'roll <nDr>'
|
||||
|
||||
function dice:init(config)
|
||||
dice.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('roll', true).table
|
||||
dice.doc = config.cmd_pat .. [[roll <nDr>
|
||||
dice.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('roll', true).table
|
||||
dice.doc = config.cmd_pat .. [[roll <nDr>
|
||||
Returns a set of dice rolls, where n is the number of rolls and r is the range. If only a range is given, returns only one roll.]]
|
||||
end
|
||||
|
||||
function dice:action(msg)
|
||||
|
||||
local input = utilities.input(msg.text_lower)
|
||||
if not input then
|
||||
utilities.send_message(self, msg.chat.id, dice.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input(msg.text_lower)
|
||||
if not input then
|
||||
utilities.send_message(self, msg.chat.id, dice.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
|
||||
local count, range
|
||||
if input:match('^[%d]+d[%d]+$') then
|
||||
count, range = input:match('([%d]+)d([%d]+)')
|
||||
elseif input:match('^d?[%d]+$') then
|
||||
count = 1
|
||||
range = input:match('^d?([%d]+)$')
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, dice.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
local count, range
|
||||
if input:match('^[%d]+d[%d]+$') then
|
||||
count, range = input:match('([%d]+)d([%d]+)')
|
||||
elseif input:match('^d?[%d]+$') then
|
||||
count = 1
|
||||
range = input:match('^d?([%d]+)$')
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, dice.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
|
||||
count = tonumber(count)
|
||||
range = tonumber(range)
|
||||
count = tonumber(count)
|
||||
range = tonumber(range)
|
||||
|
||||
if range < 2 then
|
||||
utilities.send_reply(self, msg, 'The minimum range is 2.')
|
||||
return
|
||||
end
|
||||
if range > 1000 or count > 1000 then
|
||||
utilities.send_reply(self, msg, 'The maximum range and count are 1000.')
|
||||
return
|
||||
end
|
||||
if range < 2 then
|
||||
utilities.send_reply(self, msg, 'The minimum range is 2.')
|
||||
return
|
||||
end
|
||||
if range > 1000 or count > 1000 then
|
||||
utilities.send_reply(self, msg, 'The maximum range and count are 1000.')
|
||||
return
|
||||
end
|
||||
|
||||
local output = '*' .. count .. 'd' .. range .. '*\n`'
|
||||
for _ = 1, count do
|
||||
output = output .. math.random(range) .. '\t'
|
||||
end
|
||||
output = output .. '`'
|
||||
local output = '*' .. count .. 'd' .. range .. '*\n`'
|
||||
for _ = 1, count do
|
||||
output = output .. math.random(range) .. '\t'
|
||||
end
|
||||
output = output .. '`'
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, true, msg.message_id, true)
|
||||
utilities.send_message(self, msg.chat.id, output, true, msg.message_id, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -8,8 +8,8 @@ local utilities = require('otouto.utilities')
|
||||
dilbert.command = 'dilbert [date]'
|
||||
|
||||
function dilbert:init(config)
|
||||
dilbert.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('dilbert', true).table
|
||||
dilbert.doc = config.cmd_pat .. [[dilbert [YYYY-MM-DD]
|
||||
dilbert.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('dilbert', true).table
|
||||
dilbert.doc = config.cmd_pat .. [[dilbert [YYYY-MM-DD]
|
||||
Returns the latest Dilbert strip or that of the provided date.
|
||||
Dates before the first strip will return the first strip. Dates after the last trip will return the last strip.
|
||||
Source: dilbert.com]]
|
||||
@ -17,32 +17,32 @@ end
|
||||
|
||||
function dilbert:action(msg, config)
|
||||
|
||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'upload_photo' } )
|
||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'upload_photo' } )
|
||||
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then input = os.date('%F') end
|
||||
if not input:match('^%d%d%d%d%-%d%d%-%d%d$') then input = os.date('%F') end
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then input = os.date('%F') end
|
||||
if not input:match('^%d%d%d%d%-%d%d%-%d%d$') then input = os.date('%F') end
|
||||
|
||||
local url = 'http://dilbert.com/strip/' .. URL.escape(input)
|
||||
local str, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local url = 'http://dilbert.com/strip/' .. URL.escape(input)
|
||||
local str, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
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_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(self, { chat_id = msg.chat.id, caption = strip_title }, { photo = strip_file } )
|
||||
bindings.sendPhoto(self, { chat_id = msg.chat.id, caption = strip_title }, { photo = strip_file } )
|
||||
|
||||
end
|
||||
|
||||
|
@ -5,25 +5,25 @@ local utilities = require('otouto.utilities')
|
||||
echo.command = 'echo <text>'
|
||||
|
||||
function echo:init(config)
|
||||
echo.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('echo', true).table
|
||||
echo.doc = config.cmd_pat .. 'echo <text> \nRepeats a string of text.'
|
||||
echo.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('echo', true).table
|
||||
echo.doc = config.cmd_pat .. 'echo <text> \nRepeats a string of text.'
|
||||
end
|
||||
|
||||
function echo:action(msg)
|
||||
|
||||
local input = utilities.input_from_msg(msg)
|
||||
local input = utilities.input_from_msg(msg)
|
||||
|
||||
if not input then
|
||||
utilities.send_message(self, msg.chat.id, echo.doc, true, msg.message_id, true)
|
||||
else
|
||||
local output
|
||||
if msg.chat.type == 'supergroup' then
|
||||
output = utilities.style.enquote('Echo', input)
|
||||
else
|
||||
output = utilities.md_escape(utilities.char.zwnj..input)
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
end
|
||||
if not input then
|
||||
utilities.send_message(self, msg.chat.id, echo.doc, true, msg.message_id, true)
|
||||
else
|
||||
local output
|
||||
if msg.chat.type == 'supergroup' then
|
||||
output = utilities.style.enquote('Echo', input)
|
||||
else
|
||||
output = utilities.md_escape(utilities.char.zwnj..input)
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
@ -6,52 +6,52 @@ eightball.command = '8ball'
|
||||
eightball.doc = 'Returns an answer from a magic 8-ball!'
|
||||
|
||||
function eightball:init(config)
|
||||
eightball.triggers = utilities.triggers(self.info.username, config.cmd_pat,
|
||||
{'[Yy]/[Nn]%p*$'}):t('8ball', true).table
|
||||
eightball.triggers = utilities.triggers(self.info.username, config.cmd_pat,
|
||||
{'[Yy]/[Nn]%p*$'}):t('8ball', true).table
|
||||
end
|
||||
|
||||
local ball_answers = {
|
||||
"It is certain.",
|
||||
"It is decidedly so.",
|
||||
"Without a doubt.",
|
||||
"Yes, definitely.",
|
||||
"You may rely on it.",
|
||||
"As I see it, yes.",
|
||||
"Most likely.",
|
||||
"Outlook: good.",
|
||||
"Yes.",
|
||||
"Signs point to yes.",
|
||||
"Reply hazy try again.",
|
||||
"Ask again later.",
|
||||
"Better not tell you now.",
|
||||
"Cannot predict now.",
|
||||
"Concentrate and ask again.",
|
||||
"Don't count on it.",
|
||||
"My reply is no.",
|
||||
"My sources say no.",
|
||||
"Outlook: not so good.",
|
||||
"Very doubtful.",
|
||||
"There is a time and place for everything, but not now."
|
||||
"It is certain.",
|
||||
"It is decidedly so.",
|
||||
"Without a doubt.",
|
||||
"Yes, definitely.",
|
||||
"You may rely on it.",
|
||||
"As I see it, yes.",
|
||||
"Most likely.",
|
||||
"Outlook: good.",
|
||||
"Yes.",
|
||||
"Signs point to yes.",
|
||||
"Reply hazy try again.",
|
||||
"Ask again later.",
|
||||
"Better not tell you now.",
|
||||
"Cannot predict now.",
|
||||
"Concentrate and ask again.",
|
||||
"Don't count on it.",
|
||||
"My reply is no.",
|
||||
"My sources say no.",
|
||||
"Outlook: not so good.",
|
||||
"Very doubtful.",
|
||||
"There is a time and place for everything, but not now."
|
||||
}
|
||||
|
||||
local yesno_answers = {
|
||||
'Absolutely.',
|
||||
'In your dreams.',
|
||||
'Yes.',
|
||||
'No.'
|
||||
'Absolutely.',
|
||||
'In your dreams.',
|
||||
'Yes.',
|
||||
'No.'
|
||||
}
|
||||
|
||||
function eightball:action(msg)
|
||||
|
||||
local output
|
||||
local output
|
||||
|
||||
if msg.text_lower:match('y/n%p?$') then
|
||||
output = yesno_answers[math.random(#yesno_answers)]
|
||||
else
|
||||
output = ball_answers[math.random(#ball_answers)]
|
||||
end
|
||||
if msg.text_lower:match('y/n%p?$') then
|
||||
output = yesno_answers[math.random(#yesno_answers)]
|
||||
else
|
||||
output = ball_answers[math.random(#ball_answers)]
|
||||
end
|
||||
|
||||
utilities.send_reply(self, msg, output)
|
||||
utilities.send_reply(self, msg, output)
|
||||
|
||||
end
|
||||
|
||||
|
@ -5,13 +5,13 @@ local fortune = {}
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function fortune:init(config)
|
||||
local s = io.popen('fortune'):read('*all')
|
||||
assert(
|
||||
not s:match('not found$'),
|
||||
'fortune.lua requires the fortune program to be installed.'
|
||||
)
|
||||
local s = io.popen('fortune'):read('*all')
|
||||
assert(
|
||||
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
|
||||
fortune.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('fortune').table
|
||||
end
|
||||
|
||||
fortune.command = 'fortune'
|
||||
@ -19,11 +19,11 @@ fortune.doc = 'Returns a UNIX fortune.'
|
||||
|
||||
function fortune:action(msg)
|
||||
|
||||
local fortunef = io.popen('fortune')
|
||||
local output = fortunef:read('*all')
|
||||
output = '```\n' .. output .. '\n```'
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
fortunef:close()
|
||||
local fortunef = io.popen('fortune')
|
||||
local output = fortunef:read('*all')
|
||||
output = '```\n' .. output .. '\n```'
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
fortunef:close()
|
||||
|
||||
end
|
||||
|
||||
|
@ -9,58 +9,58 @@ local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function gImages:init(config)
|
||||
assert(config.google_api_key and config.google_cse_key,
|
||||
'gImages.lua requires a Google API key from http://console.developers.google.com and a Google Custom Search Engine key from http://cse.google.com/cse.'
|
||||
)
|
||||
assert(config.google_api_key and config.google_cse_key,
|
||||
'gImages.lua requires a Google API key from http://console.developers.google.com and a Google Custom Search Engine key from http://cse.google.com/cse.'
|
||||
)
|
||||
|
||||
gImages.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('image', true):t('i', true):t('insfw', true).table
|
||||
gImages.doc = config.cmd_pat .. [[image <query>
|
||||
gImages.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('image', true):t('i', true):t('insfw', true).table
|
||||
gImages.doc = config.cmd_pat .. [[image <query>
|
||||
Returns a randomized top result from Google Images. Safe search is enabled by default; use "]] .. config.cmd_pat .. [[insfw" to disable it. NSFW results will not display an image preview.
|
||||
Alias: ]] .. config.cmd_pat .. 'i'
|
||||
gImages.search_url = 'https://www.googleapis.com/customsearch/v1?&searchType=image&imgSize=xlarge&alt=json&num=8&start=1&key=' .. config.google_api_key .. '&cx=' .. config.google_cse_key
|
||||
gImages.search_url = 'https://www.googleapis.com/customsearch/v1?&searchType=image&imgSize=xlarge&alt=json&num=8&start=1&key=' .. config.google_api_key .. '&cx=' .. config.google_cse_key
|
||||
end
|
||||
|
||||
gImages.command = 'image <query>'
|
||||
|
||||
function gImages:action(msg, config)
|
||||
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, gImages.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, gImages.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local url = gImages.search_url
|
||||
local url = gImages.search_url
|
||||
|
||||
if not string.match(msg.text, '^'..config.cmd_pat..'i[mage]*nsfw') then
|
||||
url = url .. '&safe=high'
|
||||
end
|
||||
if not string.match(msg.text, '^'..config.cmd_pat..'i[mage]*nsfw') then
|
||||
url = url .. '&safe=high'
|
||||
end
|
||||
|
||||
url = url .. '&q=' .. URL.escape(input)
|
||||
url = url .. '&q=' .. URL.escape(input)
|
||||
|
||||
local jstr, res = HTTPS.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local jstr, res = HTTPS.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.searchInformation.totalResults == '0' then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.searchInformation.totalResults == '0' then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
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 .. ')'
|
||||
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:match('nsfw') then
|
||||
utilities.send_reply(self, '*NSFW*\n'..msg, output)
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
||||
end
|
||||
if msg.text:match('nsfw') then
|
||||
utilities.send_reply(self, '*NSFW*\n'..msg, output)
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
@ -6,34 +6,34 @@ local utilities = require('otouto.utilities')
|
||||
gMaps.command = 'location <query>'
|
||||
|
||||
function gMaps:init(config)
|
||||
gMaps.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('location', true):t('loc', true).table
|
||||
gMaps.doc = [[
|
||||
gMaps.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('location', true):t('loc', true).table
|
||||
gMaps.doc = [[
|
||||
/location <query>
|
||||
Returns a location from Google Maps.
|
||||
Alias: /loc
|
||||
]]
|
||||
gMaps.doc = gMaps.doc:gsub('/', config.cmd_pat)
|
||||
]]
|
||||
gMaps.doc = gMaps.doc:gsub('/', config.cmd_pat)
|
||||
end
|
||||
|
||||
function gMaps:action(msg, config)
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, gMaps.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, gMaps.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local coords = utilities.get_coords(input, config)
|
||||
if type(coords) == 'string' then
|
||||
utilities.send_reply(self, msg, coords)
|
||||
end
|
||||
local coords = utilities.get_coords(input, config)
|
||||
if type(coords) == 'string' then
|
||||
utilities.send_reply(self, msg, coords)
|
||||
end
|
||||
|
||||
bindings.sendLocation(self, {
|
||||
chat_id = msg.chat.id,
|
||||
latitude = coords.lat,
|
||||
longitude = coords.lon,
|
||||
reply_to_message_id = msg.message_id
|
||||
} )
|
||||
bindings.sendLocation(self, {
|
||||
chat_id = msg.chat.id,
|
||||
latitude = coords.lat,
|
||||
longitude = coords.lon,
|
||||
reply_to_message_id = msg.message_id
|
||||
} )
|
||||
end
|
||||
|
||||
return gMaps
|
||||
|
@ -3,30 +3,30 @@ local utilities = require('otouto.utilities')
|
||||
local greetings = {}
|
||||
|
||||
function greetings:init(config)
|
||||
greetings.triggers = {}
|
||||
for _, triggers in pairs(config.greetings) do
|
||||
for i = 1, #triggers do
|
||||
triggers[i] = '^' .. triggers[i] .. ',? ' .. self.info.first_name:lower() .. '%p*$'
|
||||
table.insert(greetings.triggers, triggers[i])
|
||||
end
|
||||
end
|
||||
greetings.triggers = {}
|
||||
for _, triggers in pairs(config.greetings) do
|
||||
for i = 1, #triggers do
|
||||
triggers[i] = '^' .. triggers[i] .. ',? ' .. self.info.first_name:lower() .. '%p*$'
|
||||
table.insert(greetings.triggers, triggers[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function greetings:action(msg, config)
|
||||
local nick
|
||||
if self.database.userdata[tostring(msg.from.id)] then
|
||||
nick = self.database.userdata[tostring(msg.from.id)].nickname
|
||||
end
|
||||
nick = nick or utilities.build_name(msg.from.first_name, msg.from.last_name)
|
||||
local nick
|
||||
if self.database.userdata[tostring(msg.from.id)] then
|
||||
nick = self.database.userdata[tostring(msg.from.id)].nickname
|
||||
end
|
||||
nick = nick or utilities.build_name(msg.from.first_name, msg.from.last_name)
|
||||
|
||||
for response, triggers in pairs(config.greetings) do
|
||||
for _, trigger in pairs(triggers) do
|
||||
if string.match(msg.text_lower, trigger) then
|
||||
utilities.send_message(self, msg.chat.id, response:gsub('#NAME', nick))
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
for response, triggers in pairs(config.greetings) do
|
||||
for _, trigger in pairs(triggers) do
|
||||
if string.match(msg.text_lower, trigger) then
|
||||
utilities.send_message(self, msg.chat.id, response:gsub('#NAME', nick))
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return greetings
|
||||
|
@ -8,68 +8,68 @@ local hackernews = {}
|
||||
hackernews.command = 'hackernews'
|
||||
|
||||
local function get_hackernews_results()
|
||||
local results = {}
|
||||
local jstr, code = HTTPS.request(hackernews.topstories_url)
|
||||
if code ~= 200 then return end
|
||||
local data = JSON.decode(jstr)
|
||||
for i = 1, 8 do
|
||||
local ijstr, icode = HTTPS.request(hackernews.res_url:format(data[i]))
|
||||
if icode ~= 200 then return end
|
||||
local idata = JSON.decode(ijstr)
|
||||
local result
|
||||
if idata.url then
|
||||
result = string.format(
|
||||
'\n• <code>[</code><a href="%s">%s</a><code>]</code> <a href="%s">%s</a>',
|
||||
utilities.html_escape(hackernews.art_url:format(idata.id)),
|
||||
idata.id,
|
||||
utilities.html_escape(idata.url),
|
||||
utilities.html_escape(idata.title)
|
||||
)
|
||||
else
|
||||
result = string.format(
|
||||
'\n• <code>[</code><a href="%s">%s</a><code>]</code> %s',
|
||||
utilities.html_escape(hackernews.art_url:format(idata.id)),
|
||||
idata.id,
|
||||
utilities.html_escape(idata.title)
|
||||
)
|
||||
end
|
||||
table.insert(results, result)
|
||||
end
|
||||
return results
|
||||
local results = {}
|
||||
local jstr, code = HTTPS.request(hackernews.topstories_url)
|
||||
if code ~= 200 then return end
|
||||
local data = JSON.decode(jstr)
|
||||
for i = 1, 8 do
|
||||
local ijstr, icode = HTTPS.request(hackernews.res_url:format(data[i]))
|
||||
if icode ~= 200 then return end
|
||||
local idata = JSON.decode(ijstr)
|
||||
local result
|
||||
if idata.url then
|
||||
result = string.format(
|
||||
'\n• <code>[</code><a href="%s">%s</a><code>]</code> <a href="%s">%s</a>',
|
||||
utilities.html_escape(hackernews.art_url:format(idata.id)),
|
||||
idata.id,
|
||||
utilities.html_escape(idata.url),
|
||||
utilities.html_escape(idata.title)
|
||||
)
|
||||
else
|
||||
result = string.format(
|
||||
'\n• <code>[</code><a href="%s">%s</a><code>]</code> %s',
|
||||
utilities.html_escape(hackernews.art_url:format(idata.id)),
|
||||
idata.id,
|
||||
utilities.html_escape(idata.title)
|
||||
)
|
||||
end
|
||||
table.insert(results, result)
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
function hackernews:init(config)
|
||||
hackernews.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hackernews', true):t('hn', true).table
|
||||
hackernews.doc = [[Returns four (if group) or eight (if private message) top stories from Hacker News.
|
||||
hackernews.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hackernews', true):t('hn', true).table
|
||||
hackernews.doc = [[Returns four (if group) or eight (if private message) top stories from Hacker News.
|
||||
Alias: ]] .. config.cmd_pat .. 'hn'
|
||||
hackernews.topstories_url = 'https://hacker-news.firebaseio.com/v0/topstories.json'
|
||||
hackernews.res_url = 'https://hacker-news.firebaseio.com/v0/item/%s.json'
|
||||
hackernews.art_url = 'https://news.ycombinator.com/item?id=%s'
|
||||
hackernews.last_update = 0
|
||||
if config.hackernews_onstart == true then
|
||||
hackernews.results = get_hackernews_results()
|
||||
if hackernews.results then hackernews.last_update = os.time() / 60 end
|
||||
end
|
||||
hackernews.topstories_url = 'https://hacker-news.firebaseio.com/v0/topstories.json'
|
||||
hackernews.res_url = 'https://hacker-news.firebaseio.com/v0/item/%s.json'
|
||||
hackernews.art_url = 'https://news.ycombinator.com/item?id=%s'
|
||||
hackernews.last_update = 0
|
||||
if config.hackernews_onstart == true then
|
||||
hackernews.results = get_hackernews_results()
|
||||
if hackernews.results then hackernews.last_update = os.time() / 60 end
|
||||
end
|
||||
end
|
||||
|
||||
function hackernews:action(msg, config)
|
||||
local now = os.time() / 60
|
||||
if not hackernews.results or hackernews.last_update + config.hackernews_interval < now then
|
||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' })
|
||||
hackernews.results = get_hackernews_results()
|
||||
if not hackernews.results then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
hackernews.last_update = now
|
||||
end
|
||||
-- Four results in a group, eight in private.
|
||||
local res_count = msg.chat.id == msg.from.id and 8 or 4
|
||||
local output = '<b>Top Stories from Hacker News:</b>'
|
||||
for i = 1, res_count do
|
||||
output = output .. hackernews.results[i]
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||
local now = os.time() / 60
|
||||
if not hackernews.results or hackernews.last_update + config.hackernews_interval < now then
|
||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' })
|
||||
hackernews.results = get_hackernews_results()
|
||||
if not hackernews.results then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
hackernews.last_update = now
|
||||
end
|
||||
-- Four results in a group, eight in private.
|
||||
local res_count = msg.chat.id == msg.from.id and 8 or 4
|
||||
local output = '<b>Top Stories from Hacker News:</b>'
|
||||
for i = 1, res_count do
|
||||
output = output .. hackernews.results[i]
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||
end
|
||||
|
||||
return hackernews
|
||||
|
@ -8,111 +8,111 @@ local utilities = require('otouto.utilities')
|
||||
local HTTPS = require('ssl.https')
|
||||
|
||||
function hearthstone:init(config)
|
||||
hearthstone.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hearthstone', true):t('hs').table
|
||||
hearthstone.command = 'hearthstone <query>'
|
||||
hearthstone.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hearthstone', true):t('hs').table
|
||||
hearthstone.command = 'hearthstone <query>'
|
||||
|
||||
if not self.database.hearthstone or os.time() > self.database.hearthstone.expiration then
|
||||
if not self.database.hearthstone or os.time() > self.database.hearthstone.expiration then
|
||||
|
||||
print('Downloading Hearthstone database...')
|
||||
print('Downloading Hearthstone database...')
|
||||
|
||||
local jstr, res = HTTPS.request('https://api.hearthstonejson.com/v1/latest/enUS/cards.json')
|
||||
if not jstr or res ~= 200 then
|
||||
print('Error connecting to hearthstonejson.com.')
|
||||
print('hearthstone.lua will not be enabled.')
|
||||
hearthstone.command = nil
|
||||
hearthstone.triggers = nil
|
||||
return
|
||||
end
|
||||
self.database.hearthstone = JSON.decode(jstr)
|
||||
self.database.hearthstone.expiration = os.time() + 600000
|
||||
local jstr, res = HTTPS.request('https://api.hearthstonejson.com/v1/latest/enUS/cards.json')
|
||||
if not jstr or res ~= 200 then
|
||||
print('Error connecting to hearthstonejson.com.')
|
||||
print('hearthstone.lua will not be enabled.')
|
||||
hearthstone.command = nil
|
||||
hearthstone.triggers = nil
|
||||
return
|
||||
end
|
||||
self.database.hearthstone = JSON.decode(jstr)
|
||||
self.database.hearthstone.expiration = os.time() + 600000
|
||||
|
||||
print('Download complete! It will be stored for a week.')
|
||||
print('Download complete! It will be stored for a week.')
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
hearthstone.doc = config.cmd_pat .. [[hearthstone <query>
|
||||
hearthstone.doc = config.cmd_pat .. [[hearthstone <query>
|
||||
Returns Hearthstone card info.
|
||||
Alias: ]] .. config.cmd_pat .. 'hs'
|
||||
end
|
||||
|
||||
local function format_card(card)
|
||||
|
||||
local ctype = card.type
|
||||
if card.race then
|
||||
ctype = card.race
|
||||
end
|
||||
if card.rarity then
|
||||
ctype = card.rarity .. ' ' .. ctype
|
||||
end
|
||||
if card.playerClass then
|
||||
ctype = ctype .. ' (' .. card.playerClass .. ')'
|
||||
elseif card.faction then
|
||||
ctype = ctype .. ' (' .. card.faction .. ')'
|
||||
end
|
||||
local ctype = card.type
|
||||
if card.race then
|
||||
ctype = card.race
|
||||
end
|
||||
if card.rarity then
|
||||
ctype = card.rarity .. ' ' .. ctype
|
||||
end
|
||||
if card.playerClass then
|
||||
ctype = ctype .. ' (' .. card.playerClass .. ')'
|
||||
elseif card.faction then
|
||||
ctype = ctype .. ' (' .. card.faction .. ')'
|
||||
end
|
||||
|
||||
local stats
|
||||
if card.cost then
|
||||
stats = card.cost .. 'c'
|
||||
if card.attack then
|
||||
stats = stats .. ' | ' .. card.attack .. 'a'
|
||||
end
|
||||
if card.health then
|
||||
stats = stats .. ' | ' .. card.health .. 'h'
|
||||
end
|
||||
if card.durability then
|
||||
stats = stats .. ' | ' .. card.durability .. 'd'
|
||||
end
|
||||
elseif card.health then
|
||||
stats = card.health .. 'h'
|
||||
end
|
||||
local stats
|
||||
if card.cost then
|
||||
stats = card.cost .. 'c'
|
||||
if card.attack then
|
||||
stats = stats .. ' | ' .. card.attack .. 'a'
|
||||
end
|
||||
if card.health then
|
||||
stats = stats .. ' | ' .. card.health .. 'h'
|
||||
end
|
||||
if card.durability then
|
||||
stats = stats .. ' | ' .. card.durability .. 'd'
|
||||
end
|
||||
elseif card.health then
|
||||
stats = card.health .. 'h'
|
||||
end
|
||||
|
||||
-- unused?
|
||||
local info
|
||||
if card.text then
|
||||
info = card.text:gsub('</?.->',''):gsub('%$','')
|
||||
if card.flavor then
|
||||
info = info .. '\n_' .. card.flavor .. '_'
|
||||
end
|
||||
elseif card.flavor then
|
||||
info = card.flavor
|
||||
else
|
||||
info = nil
|
||||
end
|
||||
-- unused?
|
||||
local info
|
||||
if card.text then
|
||||
info = card.text:gsub('</?.->',''):gsub('%$','')
|
||||
if card.flavor then
|
||||
info = info .. '\n_' .. card.flavor .. '_'
|
||||
end
|
||||
elseif card.flavor then
|
||||
info = card.flavor
|
||||
else
|
||||
info = nil
|
||||
end
|
||||
|
||||
local s = '*' .. card.name .. '*\n' .. ctype
|
||||
if stats then
|
||||
s = s .. '\n' .. stats
|
||||
end
|
||||
if info then
|
||||
s = s .. '\n' .. info
|
||||
end
|
||||
local s = '*' .. card.name .. '*\n' .. ctype
|
||||
if stats then
|
||||
s = s .. '\n' .. stats
|
||||
end
|
||||
if info then
|
||||
s = s .. '\n' .. info
|
||||
end
|
||||
|
||||
return s
|
||||
return s
|
||||
|
||||
end
|
||||
|
||||
function hearthstone:action(msg, config)
|
||||
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, hearthstone.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, hearthstone.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local output = ''
|
||||
for _,v in pairs(self.database.hearthstone) do
|
||||
if type(v) == 'table' and string.lower(v.name):match(input) then
|
||||
output = output .. format_card(v) .. '\n\n'
|
||||
end
|
||||
end
|
||||
local output = ''
|
||||
for _,v in pairs(self.database.hearthstone) do
|
||||
if type(v) == 'table' and string.lower(v.name):match(input) then
|
||||
output = output .. format_card(v) .. '\n\n'
|
||||
end
|
||||
end
|
||||
|
||||
output = utilities.trim(output)
|
||||
if output:len() == 0 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
output = utilities.trim(output)
|
||||
if output:len() == 0 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, true, msg.message_id, true)
|
||||
utilities.send_message(self, msg.chat.id, output, true, msg.message_id, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -3,51 +3,51 @@ local utilities = require('otouto.utilities')
|
||||
local help = {}
|
||||
|
||||
function help:init(config)
|
||||
help.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('help', true):t('h', true).table
|
||||
help.command = 'help [command]'
|
||||
help.doc = config.cmd_pat .. 'help [command] \nReturns usage information for a given command.'
|
||||
help.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('help', true):t('h', true).table
|
||||
help.command = 'help [command]'
|
||||
help.doc = config.cmd_pat .. 'help [command] \nReturns usage information for a given command.'
|
||||
end
|
||||
|
||||
function help:action(msg, config)
|
||||
local input = utilities.input(msg.text_lower)
|
||||
if input then
|
||||
if not help.help_word then
|
||||
for _, plugin in ipairs(self.plugins) do
|
||||
if plugin.command and plugin.doc and not plugin.help_word then
|
||||
plugin.help_word = utilities.get_word(plugin.command, 1)
|
||||
end
|
||||
end
|
||||
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(self, msg.chat.id, output, true, nil, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
utilities.send_reply(self, msg, 'Sorry, there is no help for that command.')
|
||||
else
|
||||
-- Generate the help message on first run.
|
||||
if not help.text then
|
||||
local commandlist = {}
|
||||
for _, plugin in ipairs(self.plugins) do
|
||||
if plugin.command then
|
||||
table.insert(commandlist, plugin.command)
|
||||
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('%[', '\\[')
|
||||
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(self, msg.from.id, help.text, true, nil, true)
|
||||
if not res then
|
||||
utilities.send_reply(self, msg, 'Please [message me privately](http://telegram.me/' .. self.info.username .. '?start=help) for a list of commands.', true)
|
||||
elseif msg.chat.type ~= 'private' then
|
||||
utilities.send_reply(self, msg, 'I have sent you the requested information in a private message.')
|
||||
end
|
||||
end
|
||||
local input = utilities.input(msg.text_lower)
|
||||
if input then
|
||||
if not help.help_word then
|
||||
for _, plugin in ipairs(self.plugins) do
|
||||
if plugin.command and plugin.doc and not plugin.help_word then
|
||||
plugin.help_word = utilities.get_word(plugin.command, 1)
|
||||
end
|
||||
end
|
||||
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(self, msg.chat.id, output, true, nil, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
utilities.send_reply(self, msg, 'Sorry, there is no help for that command.')
|
||||
else
|
||||
-- Generate the help message on first run.
|
||||
if not help.text then
|
||||
local commandlist = {}
|
||||
for _, plugin in ipairs(self.plugins) do
|
||||
if plugin.command then
|
||||
table.insert(commandlist, plugin.command)
|
||||
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('%[', '\\[')
|
||||
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(self, msg.from.id, help.text, true, nil, true)
|
||||
if not res then
|
||||
utilities.send_reply(self, msg, 'Please [message me privately](http://telegram.me/' .. self.info.username .. '?start=help) for a list of commands.', true)
|
||||
elseif msg.chat.type ~= 'private' then
|
||||
utilities.send_reply(self, msg, 'I have sent you the requested information in a private message.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return help
|
||||
|
@ -3,60 +3,60 @@ local utilities = require('otouto.utilities')
|
||||
local id = {}
|
||||
|
||||
function id:init(config)
|
||||
id.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('id', true).table
|
||||
id.command = 'id <user>'
|
||||
id.doc = config.cmd_pat .. [[id <user> ...
|
||||
id.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('id', true).table
|
||||
id.command = 'id <user>'
|
||||
id.doc = config.cmd_pat .. [[id <user> ...
|
||||
Returns the name, ID, and username (if applicable) for the given users.
|
||||
Arguments must be usernames and/or IDs. Input is also accepted via reply. If no input is given, returns info for the user.
|
||||
]]
|
||||
]]
|
||||
end
|
||||
|
||||
function id.format(t)
|
||||
if t.username then
|
||||
return string.format(
|
||||
'@%s, AKA <b>%s</b> <code>[%s]</code>.\n',
|
||||
t.username,
|
||||
utilities.build_name(t.first_name, t.last_name),
|
||||
t.id
|
||||
)
|
||||
else
|
||||
return string.format(
|
||||
'<b>%s</b> <code>[%s]</code>.\n',
|
||||
utilities.build_name(t.first_name, t.last_name),
|
||||
t.id
|
||||
)
|
||||
end
|
||||
if t.username then
|
||||
return string.format(
|
||||
'@%s, AKA <b>%s</b> <code>[%s]</code>.\n',
|
||||
t.username,
|
||||
utilities.build_name(t.first_name, t.last_name),
|
||||
t.id
|
||||
)
|
||||
else
|
||||
return string.format(
|
||||
'<b>%s</b> <code>[%s]</code>.\n',
|
||||
utilities.build_name(t.first_name, t.last_name),
|
||||
t.id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function id:action(msg)
|
||||
local output
|
||||
local input = utilities.input(msg.text)
|
||||
if msg.reply_to_message then
|
||||
output = id.format(msg.reply_to_message.from)
|
||||
elseif input then
|
||||
output = ''
|
||||
for user in input:gmatch('%g+') do
|
||||
if tonumber(user) then
|
||||
if self.database.users[user] then
|
||||
output = output .. id.format(self.database.users[user])
|
||||
else
|
||||
output = output .. 'I don\'t recognize that ID (' .. user .. ').\n'
|
||||
end
|
||||
elseif user:match('^@') then
|
||||
local t = utilities.resolve_username(self, user)
|
||||
if t then
|
||||
output = output .. id.format(t)
|
||||
else
|
||||
output = output .. 'I don\'t recognize that username (' .. user .. ').\n'
|
||||
end
|
||||
else
|
||||
output = output .. 'Invalid username or ID (' .. user .. ').\n'
|
||||
end
|
||||
end
|
||||
else
|
||||
output = id.format(msg.from)
|
||||
end
|
||||
utilities.send_reply(self, msg, output, 'html')
|
||||
local output
|
||||
local input = utilities.input(msg.text)
|
||||
if msg.reply_to_message then
|
||||
output = id.format(msg.reply_to_message.from)
|
||||
elseif input then
|
||||
output = ''
|
||||
for user in input:gmatch('%g+') do
|
||||
if tonumber(user) then
|
||||
if self.database.users[user] then
|
||||
output = output .. id.format(self.database.users[user])
|
||||
else
|
||||
output = output .. 'I don\'t recognize that ID (' .. user .. ').\n'
|
||||
end
|
||||
elseif user:match('^@') then
|
||||
local t = utilities.resolve_username(self, user)
|
||||
if t then
|
||||
output = output .. id.format(t)
|
||||
else
|
||||
output = output .. 'I don\'t recognize that username (' .. user .. ').\n'
|
||||
end
|
||||
else
|
||||
output = output .. 'Invalid username or ID (' .. user .. ').\n'
|
||||
end
|
||||
end
|
||||
else
|
||||
output = id.format(msg.from)
|
||||
end
|
||||
utilities.send_reply(self, msg, output, 'html')
|
||||
end
|
||||
|
||||
return id
|
||||
|
@ -8,39 +8,39 @@ local utilities = require('otouto.utilities')
|
||||
imdb.command = 'imdb <query>'
|
||||
|
||||
function imdb:init(config)
|
||||
imdb.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('imdb', true).table
|
||||
imdb.doc = config.cmd_pat .. 'imdb <query> \nReturns an IMDb entry.'
|
||||
imdb.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('imdb', true).table
|
||||
imdb.doc = config.cmd_pat .. 'imdb <query> \nReturns an IMDb entry.'
|
||||
end
|
||||
|
||||
function imdb:action(msg, config)
|
||||
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, imdb.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, imdb.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local url = 'http://www.omdbapi.com/?t=' .. URL.escape(input)
|
||||
local url = 'http://www.omdbapi.com/?t=' .. URL.escape(input)
|
||||
|
||||
local jstr, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local jstr, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local jdat = JSON.decode(jstr)
|
||||
local jdat = JSON.decode(jstr)
|
||||
|
||||
if jdat.Response ~= 'True' then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
if jdat.Response ~= 'True' then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
local output = '*' .. jdat.Title .. ' ('.. jdat.Year ..')*\n'
|
||||
output = output .. jdat.imdbRating ..'/10 | '.. jdat.Runtime ..' | '.. jdat.Genre ..'\n'
|
||||
output = output .. '_' .. jdat.Plot .. '_\n'
|
||||
output = output .. '[Read more.](http://imdb.com/title/' .. jdat.imdbID .. ')'
|
||||
local output = '*' .. jdat.Title .. ' ('.. jdat.Year ..')*\n'
|
||||
output = output .. jdat.imdbRating ..'/10 | '.. jdat.Runtime ..' | '.. jdat.Genre ..'\n'
|
||||
output = output .. '_' .. jdat.Plot .. '_\n'
|
||||
output = output .. '[Read more.](http://imdb.com/title/' .. jdat.imdbID .. ')'
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -7,37 +7,37 @@ local utilities = require('otouto.utilities')
|
||||
local isup = {}
|
||||
|
||||
function isup:init(config)
|
||||
isup.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('websitedown', true):t('isitup', true):t('isup', true).table
|
||||
isup.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('websitedown', true):t('isitup', true):t('isup', true).table
|
||||
|
||||
isup.doc = config.cmd_pat .. [[isup <url>
|
||||
isup.doc = config.cmd_pat .. [[isup <url>
|
||||
Returns the up or down status of a website.]]
|
||||
isup.command = 'isup <url>'
|
||||
isup.command = 'isup <url>'
|
||||
end
|
||||
|
||||
function isup:action(msg, config)
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, isup.doc)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, isup.doc)
|
||||
return
|
||||
end
|
||||
|
||||
local protocol = HTTP
|
||||
local url_lower = input:lower()
|
||||
if url_lower:match('^https') then
|
||||
protocol = HTTPS
|
||||
elseif not url_lower:match('^http') then
|
||||
input = 'http://' .. input
|
||||
end
|
||||
local _, code = protocol.request(input)
|
||||
code = tonumber(code)
|
||||
local output
|
||||
if not code or code > 399 then
|
||||
output = 'This website is down or nonexistent.'
|
||||
else
|
||||
output = 'This website is up.'
|
||||
end
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
local protocol = HTTP
|
||||
local url_lower = input:lower()
|
||||
if url_lower:match('^https') then
|
||||
protocol = HTTPS
|
||||
elseif not url_lower:match('^http') then
|
||||
input = 'http://' .. input
|
||||
end
|
||||
local _, code = protocol.request(input)
|
||||
code = tonumber(code)
|
||||
local output
|
||||
if not code or code > 399 then
|
||||
output = 'This website is down or nonexistent.'
|
||||
else
|
||||
output = 'This website is up.'
|
||||
end
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
end
|
||||
|
||||
return isup
|
||||
|
@ -9,12 +9,12 @@ local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function lastfm:init(config)
|
||||
assert(config.lastfm_api_key,
|
||||
'lastfm.lua requires a last.fm API key from http://last.fm/api.'
|
||||
)
|
||||
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.doc = config.cmd_pat .. [[np [username]
|
||||
lastfm.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lastfm', true):t('np', true):t('fmset', true).table
|
||||
lastfm.doc = config.cmd_pat .. [[np [username]
|
||||
Returns what you are or were last listening to. If you specify a username, info will be returned for that username.
|
||||
|
||||
]] .. config.cmd_pat .. [[fmset <username>
|
||||
@ -25,84 +25,84 @@ lastfm.command = 'lastfm'
|
||||
|
||||
function lastfm:action(msg, config)
|
||||
|
||||
local input = utilities.input(msg.text)
|
||||
local from_id_str = tostring(msg.from.id)
|
||||
self.database.userdata[from_id_str] = self.database.userdata[from_id_str] or {}
|
||||
local input = utilities.input(msg.text)
|
||||
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(self, msg.chat.id, lastfm.doc, true, msg.message_id, true)
|
||||
return
|
||||
elseif string.match(msg.text, '^'..config.cmd_pat..'fmset') then
|
||||
if not input then
|
||||
utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true)
|
||||
elseif input == '--' or input == utilities.char.em_dash then
|
||||
self.database.userdata[from_id_str].lastfm = nil
|
||||
utilities.send_reply(self, msg, 'Your last.fm username has been forgotten.')
|
||||
else
|
||||
self.database.userdata[from_id_str].lastfm = input
|
||||
utilities.send_reply(self, msg, 'Your last.fm username has been set to "' .. input .. '".')
|
||||
end
|
||||
return
|
||||
end
|
||||
if string.match(msg.text, '^'..config.cmd_pat..'lastfm') then
|
||||
utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true)
|
||||
return
|
||||
elseif string.match(msg.text, '^'..config.cmd_pat..'fmset') then
|
||||
if not input then
|
||||
utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true)
|
||||
elseif input == '--' or input == utilities.char.em_dash then
|
||||
self.database.userdata[from_id_str].lastfm = nil
|
||||
utilities.send_reply(self, msg, 'Your last.fm username has been forgotten.')
|
||||
else
|
||||
self.database.userdata[from_id_str].lastfm = input
|
||||
utilities.send_reply(self, msg, 'Your last.fm username has been set to "' .. input .. '".')
|
||||
end
|
||||
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 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
|
||||
username = input
|
||||
elseif self.database.userdata[from_id_str].lastfm then
|
||||
username = self.database.userdata[from_id_str].lastfm
|
||||
elseif msg.from.username then
|
||||
username = msg.from.username
|
||||
alert = '\n\nYour username has been set to ' .. username .. '.\nTo change it, use '..config.cmd_pat..'fmset <username>.'
|
||||
self.database.userdata[from_id_str].lastfm = username
|
||||
else
|
||||
utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with '..config.cmd_pat..'fmset.')
|
||||
return
|
||||
end
|
||||
local username
|
||||
local alert = ''
|
||||
if input then
|
||||
username = input
|
||||
elseif self.database.userdata[from_id_str].lastfm then
|
||||
username = self.database.userdata[from_id_str].lastfm
|
||||
elseif msg.from.username then
|
||||
username = msg.from.username
|
||||
alert = '\n\nYour username has been set to ' .. username .. '.\nTo change it, use '..config.cmd_pat..'fmset <username>.'
|
||||
self.database.userdata[from_id_str].lastfm = username
|
||||
else
|
||||
utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with '..config.cmd_pat..'fmset.')
|
||||
return
|
||||
end
|
||||
|
||||
url = url .. URL.escape(username)
|
||||
url = url .. URL.escape(username)
|
||||
|
||||
local jstr, res
|
||||
utilities.with_http_timeout(
|
||||
1, function ()
|
||||
jstr, res = HTTP.request(url)
|
||||
end)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local jstr, res
|
||||
utilities.with_http_timeout(
|
||||
1, function ()
|
||||
jstr, res = HTTP.request(url)
|
||||
end)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.error then
|
||||
utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with '..config.cmd_pat..'fmset.')
|
||||
return
|
||||
end
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.error then
|
||||
utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with '..config.cmd_pat..'fmset.')
|
||||
return
|
||||
end
|
||||
|
||||
jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track
|
||||
if not jdat then
|
||||
utilities.send_reply(self, msg, 'No history for this user.' .. alert)
|
||||
return
|
||||
end
|
||||
jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track
|
||||
if not jdat then
|
||||
utilities.send_reply(self, msg, 'No history for this user.' .. alert)
|
||||
return
|
||||
end
|
||||
|
||||
local output = input or msg.from.first_name
|
||||
output = '🎵 ' .. output
|
||||
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'
|
||||
else
|
||||
output = output .. ' last listened to:\n'
|
||||
end
|
||||
if jdat['@attr'] and jdat['@attr'].nowplaying then
|
||||
output = output .. ' is currently listening to:\n'
|
||||
else
|
||||
output = output .. ' last listened to:\n'
|
||||
end
|
||||
|
||||
local title = jdat.name or 'Unknown'
|
||||
local artist = 'Unknown'
|
||||
if jdat.artist then
|
||||
artist = jdat.artist['#text']
|
||||
end
|
||||
local title = jdat.name or 'Unknown'
|
||||
local artist = 'Unknown'
|
||||
if jdat.artist then
|
||||
artist = jdat.artist['#text']
|
||||
end
|
||||
|
||||
output = output .. title .. ' - ' .. artist .. alert
|
||||
utilities.send_message(self, msg.chat.id, output)
|
||||
output = output .. title .. ' - ' .. artist .. alert
|
||||
utilities.send_message(self, msg.chat.id, output)
|
||||
|
||||
end
|
||||
|
||||
|
@ -5,59 +5,59 @@ local URL = require('socket.url')
|
||||
local JSON, serpent
|
||||
|
||||
function luarun:init(config)
|
||||
luarun.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lua', true):t('return', true).table
|
||||
if config.luarun_serpent then
|
||||
serpent = require('serpent')
|
||||
luarun.serialize = function(t)
|
||||
return serpent.block(t, {comment=false})
|
||||
end
|
||||
else
|
||||
JSON = require('dkjson')
|
||||
luarun.serialize = function(t)
|
||||
return JSON.encode(t, {indent=true})
|
||||
end
|
||||
end
|
||||
luarun.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lua', true):t('return', true).table
|
||||
if config.luarun_serpent then
|
||||
serpent = require('serpent')
|
||||
luarun.serialize = function(t)
|
||||
return serpent.block(t, {comment=false})
|
||||
end
|
||||
else
|
||||
JSON = require('dkjson')
|
||||
luarun.serialize = function(t)
|
||||
return JSON.encode(t, {indent=true})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function luarun:action(msg, config)
|
||||
|
||||
if msg.from.id ~= config.admin then
|
||||
return true
|
||||
end
|
||||
if msg.from.id ~= config.admin then
|
||||
return true
|
||||
end
|
||||
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, 'Please enter a string to load.')
|
||||
return
|
||||
end
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, 'Please enter a string to load.')
|
||||
return
|
||||
end
|
||||
|
||||
if msg.text_lower:match('^'..config.cmd_pat..'return') then
|
||||
input = 'return ' .. input
|
||||
end
|
||||
if msg.text_lower:match('^'..config.cmd_pat..'return') then
|
||||
input = 'return ' .. input
|
||||
end
|
||||
|
||||
local output = loadstring( [[
|
||||
local bot = require('otouto.bot')
|
||||
local bindings = require('otouto.bindings')
|
||||
local utilities = require('otouto.utilities')
|
||||
local drua = require('otouto.drua-tg')
|
||||
local JSON = require('dkjson')
|
||||
local URL = require('socket.url')
|
||||
local HTTP = require('socket.http')
|
||||
local HTTPS = require('ssl.https')
|
||||
return function (self, msg, config) ]] .. input .. [[ end
|
||||
]] )()(self, msg, config)
|
||||
if output == nil then
|
||||
output = 'Done!'
|
||||
else
|
||||
if type(output) == 'table' then
|
||||
local s = luarun.serialize(output)
|
||||
if URL.escape(s):len() < 4000 then
|
||||
output = s
|
||||
end
|
||||
end
|
||||
output = '```\n' .. tostring(output) .. '\n```'
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, output, true, msg.message_id, true)
|
||||
local output = loadstring( [[
|
||||
local bot = require('otouto.bot')
|
||||
local bindings = require('otouto.bindings')
|
||||
local utilities = require('otouto.utilities')
|
||||
local drua = require('otouto.drua-tg')
|
||||
local JSON = require('dkjson')
|
||||
local URL = require('socket.url')
|
||||
local HTTP = require('socket.http')
|
||||
local HTTPS = require('ssl.https')
|
||||
return function (self, msg, config) ]] .. input .. [[ end
|
||||
]] )()(self, msg, config)
|
||||
if output == nil then
|
||||
output = 'Done!'
|
||||
else
|
||||
if type(output) == 'table' then
|
||||
local s = luarun.serialize(output)
|
||||
if URL.escape(s):len() < 4000 then
|
||||
output = s
|
||||
end
|
||||
end
|
||||
output = '```\n' .. tostring(output) .. '\n```'
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, output, true, msg.message_id, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -3,65 +3,65 @@ local me = {}
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function me:init(config)
|
||||
me.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('me', true).table
|
||||
me.command = 'me'
|
||||
me.doc = 'Returns userdata stored by the bot.'
|
||||
me.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('me', true).table
|
||||
me.command = 'me'
|
||||
me.doc = 'Returns userdata stored by the bot.'
|
||||
end
|
||||
|
||||
function me:action(msg, config)
|
||||
local user
|
||||
if msg.from.id == config.admin then
|
||||
if msg.reply_to_message then
|
||||
user = msg.reply_to_message.from
|
||||
else
|
||||
local input = utilities.input(msg.text)
|
||||
if input then
|
||||
if tonumber(input) then
|
||||
user = self.database.users[input]
|
||||
if not user then
|
||||
utilities.send_reply(self, msg, 'Unrecognized ID.')
|
||||
return
|
||||
end
|
||||
elseif input:match('^@') then
|
||||
user = utilities.resolve_username(self, input)
|
||||
if not user then
|
||||
utilities.send_reply(self, msg, 'Unrecognized username.')
|
||||
return
|
||||
end
|
||||
else
|
||||
utilities.send_reply(self, msg, 'Invalid username or ID.')
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
user = user or msg.from
|
||||
local userdata = self.database.userdata[tostring(user.id)] or {}
|
||||
local user
|
||||
if msg.from.id == config.admin then
|
||||
if msg.reply_to_message then
|
||||
user = msg.reply_to_message.from
|
||||
else
|
||||
local input = utilities.input(msg.text)
|
||||
if input then
|
||||
if tonumber(input) then
|
||||
user = self.database.users[input]
|
||||
if not user then
|
||||
utilities.send_reply(self, msg, 'Unrecognized ID.')
|
||||
return
|
||||
end
|
||||
elseif input:match('^@') then
|
||||
user = utilities.resolve_username(self, input)
|
||||
if not user then
|
||||
utilities.send_reply(self, msg, 'Unrecognized username.')
|
||||
return
|
||||
end
|
||||
else
|
||||
utilities.send_reply(self, msg, 'Invalid username or ID.')
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
user = user or msg.from
|
||||
local userdata = self.database.userdata[tostring(user.id)] or {}
|
||||
|
||||
local data = {}
|
||||
for k,v in pairs(userdata) do
|
||||
table.insert(data, string.format(
|
||||
'<b>%s</b> <code>%s</code>\n',
|
||||
utilities.html_escape(k),
|
||||
utilities.html_escape(v)
|
||||
))
|
||||
end
|
||||
local data = {}
|
||||
for k,v in pairs(userdata) do
|
||||
table.insert(data, string.format(
|
||||
'<b>%s</b> <code>%s</code>\n',
|
||||
utilities.html_escape(k),
|
||||
utilities.html_escape(v)
|
||||
))
|
||||
end
|
||||
|
||||
local output
|
||||
if #data == 0 then
|
||||
output = 'There is no data stored for this user.'
|
||||
else
|
||||
output = string.format(
|
||||
'<b>%s</b> <code>[%s]</code><b>:</b>\n',
|
||||
utilities.html_escape(utilities.build_name(
|
||||
user.first_name,
|
||||
user.last_name
|
||||
)),
|
||||
user.id
|
||||
) .. table.concat(data)
|
||||
end
|
||||
local output
|
||||
if #data == 0 then
|
||||
output = 'There is no data stored for this user.'
|
||||
else
|
||||
output = string.format(
|
||||
'<b>%s</b> <code>[%s]</code><b>:</b>\n',
|
||||
utilities.html_escape(utilities.build_name(
|
||||
user.first_name,
|
||||
user.last_name
|
||||
)),
|
||||
user.id
|
||||
) .. table.concat(data)
|
||||
end
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||
|
||||
end
|
||||
|
||||
|
@ -5,45 +5,45 @@ local utilities = require('otouto.utilities')
|
||||
nick.command = 'nick <nickname>'
|
||||
|
||||
function nick:init(config)
|
||||
nick.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('nick', true).table
|
||||
nick.doc = config.cmd_pat .. [[nick <nickname>
|
||||
nick.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('nick', true).table
|
||||
nick.doc = config.cmd_pat .. [[nick <nickname>
|
||||
Set your nickname. Use "]] .. config.cmd_pat .. 'nick --" to delete it.'
|
||||
end
|
||||
|
||||
function nick:action(msg, config)
|
||||
|
||||
local id_str, name
|
||||
local id_str, name
|
||||
|
||||
if msg.from.id == config.admin and msg.reply_to_message then
|
||||
id_str = tostring(msg.reply_to_message.from.id)
|
||||
name = utilities.build_name(msg.reply_to_message.from.first_name, msg.reply_to_message.from.last_name)
|
||||
else
|
||||
id_str = tostring(msg.from.id)
|
||||
name = utilities.build_name(msg.from.first_name, msg.from.last_name)
|
||||
end
|
||||
if msg.from.id == config.admin and msg.reply_to_message then
|
||||
id_str = tostring(msg.reply_to_message.from.id)
|
||||
name = utilities.build_name(msg.reply_to_message.from.first_name, msg.reply_to_message.from.last_name)
|
||||
else
|
||||
id_str = tostring(msg.from.id)
|
||||
name = utilities.build_name(msg.from.first_name, msg.from.last_name)
|
||||
end
|
||||
|
||||
self.database.userdata[id_str] = self.database.userdata[id_str] or {}
|
||||
self.database.userdata[id_str] = self.database.userdata[id_str] or {}
|
||||
|
||||
local output
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
if self.database.userdata[id_str].nickname then
|
||||
output = name .. '\'s nickname is "' .. self.database.userdata[id_str].nickname .. '".'
|
||||
else
|
||||
output = name .. ' currently has no nickname.'
|
||||
end
|
||||
elseif utilities.utf8_len(input) > 32 then
|
||||
output = 'The character limit for nicknames is 32.'
|
||||
elseif input == '--' or input == utilities.char.em_dash then
|
||||
self.database.userdata[id_str].nickname = nil
|
||||
output = name .. '\'s nickname has been deleted.'
|
||||
else
|
||||
input = input:gsub('\n', ' ')
|
||||
self.database.userdata[id_str].nickname = input
|
||||
output = name .. '\'s nickname has been set to "' .. input .. '".'
|
||||
end
|
||||
local output
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
if self.database.userdata[id_str].nickname then
|
||||
output = name .. '\'s nickname is "' .. self.database.userdata[id_str].nickname .. '".'
|
||||
else
|
||||
output = name .. ' currently has no nickname.'
|
||||
end
|
||||
elseif utilities.utf8_len(input) > 32 then
|
||||
output = 'The character limit for nicknames is 32.'
|
||||
elseif input == '--' or input == utilities.char.em_dash then
|
||||
self.database.userdata[id_str].nickname = nil
|
||||
output = name .. '\'s nickname has been deleted.'
|
||||
else
|
||||
input = input:gsub('\n', ' ')
|
||||
self.database.userdata[id_str].nickname = input
|
||||
output = name .. '\'s nickname has been set to "' .. input .. '".'
|
||||
end
|
||||
|
||||
utilities.send_reply(self, msg, output)
|
||||
utilities.send_reply(self, msg, output)
|
||||
|
||||
end
|
||||
|
||||
|
@ -8,34 +8,34 @@ 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/.-/.-$' }
|
||||
patterns.triggers = { config.cmd_pat .. '?s/.-/.-$' }
|
||||
end
|
||||
|
||||
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('"$', '')
|
||||
end
|
||||
local m1, m2 = msg.text:match('^/?s/(.-)/(.-)/?$')
|
||||
if not m2 then return true end
|
||||
local res
|
||||
res, output = pcall(
|
||||
function()
|
||||
return output:gsub(m1, m2)
|
||||
end
|
||||
)
|
||||
if res == false then
|
||||
utilities.send_reply(self, msg, 'Malformed pattern!')
|
||||
else
|
||||
output = utilities.trim(output:sub(1, 4000))
|
||||
output = utilities.style.enquote('Did you mean', output)
|
||||
utilities.send_reply(self, msg.reply_to_message, output, true)
|
||||
end
|
||||
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('"$', '')
|
||||
end
|
||||
local m1, m2 = msg.text:match('^/?s/(.-)/(.-)/?$')
|
||||
if not m2 then return true end
|
||||
local res
|
||||
res, output = pcall(
|
||||
function()
|
||||
return output:gsub(m1, m2)
|
||||
end
|
||||
)
|
||||
if res == false then
|
||||
utilities.send_reply(self, msg, 'Malformed pattern!')
|
||||
else
|
||||
output = utilities.trim(output:sub(1, 4000))
|
||||
output = utilities.style.enquote('Did you mean', output)
|
||||
utilities.send_reply(self, msg.reply_to_message, output, true)
|
||||
end
|
||||
end
|
||||
|
||||
return patterns
|
||||
|
@ -5,12 +5,12 @@ local ping = {}
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function ping:init(config)
|
||||
ping.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('ping'):t('annyong').table
|
||||
ping.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('ping'):t('annyong').table
|
||||
end
|
||||
|
||||
function ping:action(msg, config)
|
||||
local output = msg.text_lower:match('^'..config.cmd_pat..'ping') and 'Pong!' or 'Annyong.'
|
||||
utilities.send_message(self, msg.chat.id, output)
|
||||
local output = msg.text_lower:match('^'..config.cmd_pat..'ping') and 'Pong!' or 'Annyong.'
|
||||
utilities.send_message(self, msg.chat.id, output)
|
||||
end
|
||||
|
||||
return ping
|
||||
|
@ -8,8 +8,8 @@ local utilities = require('otouto.utilities')
|
||||
pokedex.command = 'pokedex <query>'
|
||||
|
||||
function pokedex:init(config)
|
||||
pokedex.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('pokedex', true):t('dex', true).table
|
||||
pokedex.doc = config.cmd_pat .. [[pokedex <query>
|
||||
pokedex.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('pokedex', true):t('dex', true).table
|
||||
pokedex.doc = config.cmd_pat .. [[pokedex <query>
|
||||
Returns a Pokedex entry from pokeapi.co.
|
||||
Queries must be a number of the name of a Pokémon.
|
||||
Alias: ]] .. config.cmd_pat .. 'dex'
|
||||
@ -17,54 +17,54 @@ end
|
||||
|
||||
function pokedex:action(msg, config)
|
||||
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, pokedex.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, pokedex.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' } )
|
||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' } )
|
||||
|
||||
local url = 'http://pokeapi.co'
|
||||
local url = 'http://pokeapi.co'
|
||||
|
||||
local dex_url = url .. '/api/v1/pokemon/' .. input
|
||||
local dex_jstr, res = HTTP.request(dex_url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local dex_url = url .. '/api/v1/pokemon/' .. input
|
||||
local dex_jstr, res = HTTP.request(dex_url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local dex_jdat = JSON.decode(dex_jstr)
|
||||
local dex_jdat = JSON.decode(dex_jstr)
|
||||
|
||||
if not dex_jdat.descriptions or not dex_jdat.descriptions[1] then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
if not dex_jdat.descriptions or not dex_jdat.descriptions[1] then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
local desc_url = url .. dex_jdat.descriptions[math.random(#dex_jdat.descriptions)].resource_uri
|
||||
local desc_jstr, _ = HTTP.request(desc_url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local desc_url = url .. dex_jdat.descriptions[math.random(#dex_jdat.descriptions)].resource_uri
|
||||
local desc_jstr, _ = HTTP.request(desc_url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local desc_jdat = JSON.decode(desc_jstr)
|
||||
local desc_jdat = JSON.decode(desc_jstr)
|
||||
|
||||
local poke_type
|
||||
for _,v in ipairs(dex_jdat.types) do
|
||||
local type_name = v.name:gsub("^%l", string.upper)
|
||||
if not poke_type then
|
||||
poke_type = type_name
|
||||
else
|
||||
poke_type = poke_type .. ' / ' .. type_name
|
||||
end
|
||||
end
|
||||
poke_type = poke_type .. ' type'
|
||||
local poke_type
|
||||
for _,v in ipairs(dex_jdat.types) do
|
||||
local type_name = v.name:gsub("^%l", string.upper)
|
||||
if not poke_type then
|
||||
poke_type = type_name
|
||||
else
|
||||
poke_type = poke_type .. ' / ' .. type_name
|
||||
end
|
||||
end
|
||||
poke_type = poke_type .. ' type'
|
||||
|
||||
local output = '*' .. dex_jdat.name .. '*\n#' .. dex_jdat.national_id .. ' | ' .. poke_type .. '\n_' .. desc_jdat.description:gsub('POKMON', 'Pokémon'):gsub('Pokmon', 'Pokémon') .. '_'
|
||||
local output = '*' .. dex_jdat.name .. '*\n#' .. dex_jdat.national_id .. ' | ' .. poke_type .. '\n_' .. desc_jdat.description:gsub('POKMON', 'Pokémon'):gsub('Pokmon', 'Pokémon') .. '_'
|
||||
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -3,110 +3,110 @@ local utilities = require('otouto.utilities')
|
||||
local pgc = {}
|
||||
|
||||
function pgc:init(config)
|
||||
pgc.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('gocalc', true).table
|
||||
pgc.doc = config.cmd_pat .. [[gocalc <required candy> <number of Pokémon> <number of candy>
|
||||
pgc.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('gocalc', true).table
|
||||
pgc.doc = config.cmd_pat .. [[gocalc <required candy> <number of Pokémon> <number of candy>
|
||||
Calculates the number of Pokémon that must be transferred before evolving, how many evolutions the user is able to perform, and how many Pokémon and candy will be left over.
|
||||
All arguments must be positive numbers. Batch jobs may be performed by separating valid sets of arguments by lines.
|
||||
Example (forty pidgeys and three hundred pidgey candies):
|
||||
]] .. config.cmd_pat .. 'gocalc 12 40 300'
|
||||
pgc.command = 'gocalc <required candy> <#pokemon> <#candy>'
|
||||
pgc.command = 'gocalc <required candy> <#pokemon> <#candy>'
|
||||
end
|
||||
|
||||
-- This function written by Juan Potato. MIT-licensed.
|
||||
local pidgey_calc = function(candies_to_evolve, mons, candies)
|
||||
local transferred = 0;
|
||||
local evolved = 0;
|
||||
local transferred = 0;
|
||||
local evolved = 0;
|
||||
|
||||
while true do
|
||||
if math.floor(candies / candies_to_evolve) == 0 or mons == 0 then
|
||||
break
|
||||
else
|
||||
mons = mons - 1
|
||||
candies = candies - candies_to_evolve + 1
|
||||
evolved = evolved + 1
|
||||
if mons == 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
while true do
|
||||
if math.floor(candies / candies_to_evolve) == 0 or mons == 0 then
|
||||
break
|
||||
else
|
||||
mons = mons - 1
|
||||
candies = candies - candies_to_evolve + 1
|
||||
evolved = evolved + 1
|
||||
if mons == 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while true do
|
||||
if (candies + mons) < (candies_to_evolve + 1) or mons == 0 then
|
||||
break
|
||||
end
|
||||
while candies < candies_to_evolve do
|
||||
transferred = transferred + 1
|
||||
mons = mons - 1
|
||||
candies = candies + 1
|
||||
end
|
||||
mons = mons - 1
|
||||
candies = candies - candies_to_evolve + 1
|
||||
evolved = evolved + 1
|
||||
end
|
||||
while true do
|
||||
if (candies + mons) < (candies_to_evolve + 1) or mons == 0 then
|
||||
break
|
||||
end
|
||||
while candies < candies_to_evolve do
|
||||
transferred = transferred + 1
|
||||
mons = mons - 1
|
||||
candies = candies + 1
|
||||
end
|
||||
mons = mons - 1
|
||||
candies = candies - candies_to_evolve + 1
|
||||
evolved = evolved + 1
|
||||
end
|
||||
|
||||
return {
|
||||
transfer = transferred,
|
||||
evolve = evolved,
|
||||
leftover_mons = mons,
|
||||
leftover_candy = candies
|
||||
}
|
||||
return {
|
||||
transfer = transferred,
|
||||
evolve = evolved,
|
||||
leftover_mons = mons,
|
||||
leftover_candy = candies
|
||||
}
|
||||
end
|
||||
|
||||
local single_job = function(input)
|
||||
local req_candy, mons, candies = input:match('^(%d+) (%d+) (%d+)$')
|
||||
req_candy = tonumber(req_candy)
|
||||
mons = tonumber(mons)
|
||||
candies = tonumber(candies)
|
||||
if not (req_candy and mons and candies) then
|
||||
return { err = 'Invalid input: Three numbers expected.' }
|
||||
elseif req_candy > 400 then
|
||||
return { err = 'Invalid required candy: Maximum is 400.' }
|
||||
elseif mons > 1000 then
|
||||
return { err = 'Invalid number of Pokémon: Maximum is 1000.' }
|
||||
elseif candies > 10000 then
|
||||
return { err = 'Invalid number of candies: Maximum is 10000.' }
|
||||
else
|
||||
return pidgey_calc(req_candy, mons, candies)
|
||||
end
|
||||
local req_candy, mons, candies = input:match('^(%d+) (%d+) (%d+)$')
|
||||
req_candy = tonumber(req_candy)
|
||||
mons = tonumber(mons)
|
||||
candies = tonumber(candies)
|
||||
if not (req_candy and mons and candies) then
|
||||
return { err = 'Invalid input: Three numbers expected.' }
|
||||
elseif req_candy > 400 then
|
||||
return { err = 'Invalid required candy: Maximum is 400.' }
|
||||
elseif mons > 1000 then
|
||||
return { err = 'Invalid number of Pokémon: Maximum is 1000.' }
|
||||
elseif candies > 10000 then
|
||||
return { err = 'Invalid number of candies: Maximum is 10000.' }
|
||||
else
|
||||
return pidgey_calc(req_candy, mons, candies)
|
||||
end
|
||||
end
|
||||
|
||||
function pgc:action(msg)
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, pgc.doc, true)
|
||||
return
|
||||
end
|
||||
input = input .. '\n'
|
||||
local output = ''
|
||||
local total_evolutions = 0
|
||||
for line in input:gmatch('(.-)\n') do
|
||||
local info = single_job(line)
|
||||
output = output .. '`' .. line .. '`\n'
|
||||
if info.err then
|
||||
output = output .. info.err .. '\n\n'
|
||||
else
|
||||
total_evolutions = total_evolutions + info.evolve
|
||||
local s = '*Transfer:* %s. \n*Evolve:* %s (%s XP, %s minutes). \n*Leftover:* %s mons, %s candy.\n\n'
|
||||
s = s:format(info.transfer, info.evolve, info.evolve..'k', info.evolve*0.5, info.leftover_mons, info.leftover_candy)
|
||||
output = output .. s
|
||||
end
|
||||
end
|
||||
local s = '*Total evolutions:* %s. \n*Recommendation:* %s'
|
||||
local recommendation
|
||||
local egg_count = math.floor(total_evolutions/60)
|
||||
if egg_count < 1 then
|
||||
recommendation = 'Wait until you have atleast sixty Pokémon to evolve before using a lucky egg.'
|
||||
else
|
||||
recommendation = string.format(
|
||||
'Use %s lucky egg%s for %s evolutions.',
|
||||
egg_count,
|
||||
egg_count == 1 and '' or 's',
|
||||
egg_count * 60
|
||||
)
|
||||
end
|
||||
s = s:format(total_evolutions, recommendation)
|
||||
output = output .. s
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, pgc.doc, true)
|
||||
return
|
||||
end
|
||||
input = input .. '\n'
|
||||
local output = ''
|
||||
local total_evolutions = 0
|
||||
for line in input:gmatch('(.-)\n') do
|
||||
local info = single_job(line)
|
||||
output = output .. '`' .. line .. '`\n'
|
||||
if info.err then
|
||||
output = output .. info.err .. '\n\n'
|
||||
else
|
||||
total_evolutions = total_evolutions + info.evolve
|
||||
local s = '*Transfer:* %s. \n*Evolve:* %s (%s XP, %s minutes). \n*Leftover:* %s mons, %s candy.\n\n'
|
||||
s = s:format(info.transfer, info.evolve, info.evolve..'k', info.evolve*0.5, info.leftover_mons, info.leftover_candy)
|
||||
output = output .. s
|
||||
end
|
||||
end
|
||||
local s = '*Total evolutions:* %s. \n*Recommendation:* %s'
|
||||
local recommendation
|
||||
local egg_count = math.floor(total_evolutions/60)
|
||||
if egg_count < 1 then
|
||||
recommendation = 'Wait until you have atleast sixty Pokémon to evolve before using a lucky egg.'
|
||||
else
|
||||
recommendation = string.format(
|
||||
'Use %s lucky egg%s for %s evolutions.',
|
||||
egg_count,
|
||||
egg_count == 1 and '' or 's',
|
||||
egg_count * 60
|
||||
)
|
||||
end
|
||||
s = s:format(total_evolutions, recommendation)
|
||||
output = output .. s
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
end
|
||||
|
||||
return pgc
|
||||
|
@ -21,7 +21,7 @@ Set your Pokémon Go team for statistical purposes. The team must be valid, and
|
||||
db.membership = {}
|
||||
end
|
||||
for _, set in pairs(db.membership) do
|
||||
setmetatable(set, utilities.set_meta)
|
||||
setmetatable(set, utilities.set_meta)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -6,37 +6,37 @@ local utilities = require('otouto.utilities')
|
||||
preview.command = 'preview <link>'
|
||||
|
||||
function preview:init(config)
|
||||
preview.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('preview', true).table
|
||||
preview.doc = config.cmd_pat .. 'preview <link> \nReturns a full-message, "unlinked" preview.'
|
||||
preview.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('preview', true).table
|
||||
preview.doc = config.cmd_pat .. 'preview <link> \nReturns a full-message, "unlinked" preview.'
|
||||
end
|
||||
|
||||
function preview:action(msg)
|
||||
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, preview.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, preview.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
input = utilities.get_word(input, 1)
|
||||
if not input:match('^https?://.+') then
|
||||
input = 'http://' .. input
|
||||
end
|
||||
input = utilities.get_word(input, 1)
|
||||
if not input:match('^https?://.+') then
|
||||
input = 'http://' .. input
|
||||
end
|
||||
|
||||
local res = HTTP.request(input)
|
||||
if not res then
|
||||
utilities.send_reply(self, msg, 'Please provide a valid link.')
|
||||
return
|
||||
end
|
||||
local res = HTTP.request(input)
|
||||
if not res then
|
||||
utilities.send_reply(self, msg, 'Please provide a valid link.')
|
||||
return
|
||||
end
|
||||
|
||||
if res:len() == 0 then
|
||||
utilities.send_reply(self, msg, 'Sorry, the link you provided is not letting us make a preview.')
|
||||
return
|
||||
end
|
||||
if res:len() == 0 then
|
||||
utilities.send_reply(self, msg, 'Sorry, the link you provided is not letting us make a preview.')
|
||||
return
|
||||
end
|
||||
|
||||
-- Invisible zero-width, non-joiner.
|
||||
local output = '<a href="' .. input .. '">' .. utilities.char.zwnj .. '</a>'
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, 'html')
|
||||
-- Invisible zero-width, non-joiner.
|
||||
local output = '<a href="' .. input .. '">' .. utilities.char.zwnj .. '</a>'
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, 'html')
|
||||
|
||||
end
|
||||
|
||||
|
@ -6,138 +6,138 @@ pun.command = 'pun'
|
||||
pun.doc = 'Returns a pun.'
|
||||
|
||||
function pun:init(config)
|
||||
pun.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('pun').table
|
||||
pun.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('pun').table
|
||||
end
|
||||
|
||||
local puns = {
|
||||
"The person who invented the door-knock won the No-bell prize.",
|
||||
"I couldn't work out how to fasten my seatbelt. Then it clicked.",
|
||||
"Never trust atoms; they make up everything.",
|
||||
"Singing in the shower is all fun and games until you get shampoo in your mouth - Then it becomes a soap opera.",
|
||||
"I can't believe I got fired from the calendar factory. All I did was take a day off.",
|
||||
"To the guy who invented zero: Thanks for nothing!",
|
||||
"Enough with the cripple jokes! I just can't stand them.",
|
||||
"I've accidentally swallowed some Scrabble tiles. My next crap could spell disaster.",
|
||||
"How does Moses make his tea? Hebrews it.",
|
||||
"Did you hear about the guy who got hit in the head with a can of soda? He was lucky it was a soft drink.",
|
||||
"When William joined the army he disliked the phrase 'fire at will'.",
|
||||
"There was a sign on the lawn at a rehab center that said 'Keep off the Grass'.",
|
||||
"I wondered why the baseball was getting bigger. Then it hit me.",
|
||||
"I can hear music coming out of my printer. I think the paper's jamming again.",
|
||||
"I have a few jokes about unemployed people, but none of them work",
|
||||
"Want to hear a construction joke? I'm working on it",
|
||||
"I always take a second pair of pants when I go golfing, in case I get a hole in one.",
|
||||
"I couldn't remember how to throw a boomerang, but then it came back to me.",
|
||||
"I've decided that my wifi will be my valentine. IDK, we just have this connection.",
|
||||
"A prisoner's favorite punctuation mark is the period. It marks the end of his sentence.",
|
||||
"I used to go fishing with Skrillex, but he kept dropping the bass.",
|
||||
"Two antennae met on a roof and got married. The wedding was okay, but the reception was incredible.",
|
||||
"A book just fell on my head. I've only got my shelf to blame.",
|
||||
"I dropped my steak on the floor. Now it's ground beef.",
|
||||
"I used to have a fear of hurdles, but I got over it.",
|
||||
"The outcome of war does not prove who is right, but only who is left.",
|
||||
"Darth Vader tries not to burn his food, but it always comes out a little on the dark side.",
|
||||
"The store keeps calling me to buy more furniture, but all I wanted was a one night stand.",
|
||||
"This girl said she recognized me from the vegetarian club, but I'd never met herbivore.",
|
||||
"Police arrested two kids yesterday, one was drinking battery acid, the other was eating fireworks. They charged one and let the other one off...",
|
||||
"No more Harry Potter jokes guys. I'm Sirius.",
|
||||
"It was hard getting over my addiction to hokey pokey, but I've turned myself around.",
|
||||
"It takes a lot of balls to golf the way I do.",
|
||||
"Why did everyone want to hang out with the mushroom? Because he was a fungi.",
|
||||
"How much does a hipster weigh? An instagram.",
|
||||
"I used to be addicted to soap, but I'm clean now.",
|
||||
"When life gives you melons, you’re probably dyslexic.",
|
||||
"What's with all the blind jokes? I just don't see the point.",
|
||||
"If Apple made a car, would it have Windows?",
|
||||
"Need an ark? I Noah guy.",
|
||||
"The scarecrow won an award because he was outstanding in his field.",
|
||||
"What's the difference between a man in a tux on a bicycle, and a man in a sweatsuit on a trycicle? A tire.",
|
||||
"What do you do with a sick chemist? If you can't helium, and you can't curium, you'll just have to barium.",
|
||||
"I'm reading a book about anti-gravity. It's impossible to put down.",
|
||||
"Trying to write with a broken pencil is pointless.",
|
||||
"When TVs go on vacation, they travel to remote islands.",
|
||||
"I was going to tell a midget joke, but it's too short.",
|
||||
"Jokes about German sausage are the wurst.",
|
||||
"How do you organize a space party? You planet.",
|
||||
"Sleeping comes so naturally to me, I could do it with my eyes closed.",
|
||||
"I'm glad I know sign language; it's pretty handy.",
|
||||
"Atheism is a non-prophet organization.",
|
||||
"Velcro: What a rip-off!",
|
||||
"If they made a Minecraft movie, it would be a blockbuster.",
|
||||
"I don't trust people with graph paper. They're always plotting something",
|
||||
"I had a friend who was addicted to brake fluid. He says he can stop anytime.",
|
||||
"The form said I had Type A blood, but it was a Type O.",
|
||||
"I went to to the shop to buy eight Sprites - I came home and realised I'd picked 7Up.",
|
||||
"There was an explosion at a pie factory. 3.14 people died.",
|
||||
"A man drove his car into a tree and found out how a Mercedes bends.",
|
||||
"The experienced carpenter really nailed it, but the new guy screwed everything up.",
|
||||
"I didn't like my beard at first, but then it grew on me.",
|
||||
"Smaller babies may be delivered by stork, but the heavier ones need a crane.",
|
||||
"What's the definition of a will? It's a dead giveaway.",
|
||||
"I was going to look for my missing watch, but I could never find the time.",
|
||||
"I hate elevators, and I often take steps to avoid them.",
|
||||
"Did you hear about the guy whose whole left side was cut off? He's all right now.",
|
||||
"It's not that the man did not know how to juggle, he just didn't have the balls to do it.",
|
||||
"I used to be a loan shark, but I lost interest",
|
||||
"I don't trust these stairs; they're always up to something.",
|
||||
"My friend's bakery burned down last night. Now his business is toast.",
|
||||
"Don't trust people that do acupuncture; they're back stabbers.",
|
||||
"The man who survived mustard gas and pepper spray is now a seasoned veteran.",
|
||||
"Police were called to a daycare where a three-year-old was resisting a rest.",
|
||||
"When Peter Pan punches, they Neverland",
|
||||
"The shoemaker did not deny his apprentice anything he needed. He gave him his awl.",
|
||||
"I did a theatrical performance about puns. It was a play on words.",
|
||||
"Show me a piano falling down a mineshaft and I'll show you A-flat minor.",
|
||||
"Have you ever tried to eat a clock? It's very time consuming.",
|
||||
"There was once a cross-eyed teacher who couldn't control his pupils.",
|
||||
"A new type of broom came out and it is sweeping the nation.",
|
||||
"I relish the fact that you've mustard the strength to ketchup to me.",
|
||||
"I knew a woman who owned a taser. Man, was she stunning!",
|
||||
"What did the grape say when it got stepped on? Nothing - but it let out a little whine.",
|
||||
"It was an emotional wedding. Even the cake was in tiers.",
|
||||
"When a clock is hungry it goes back four seconds.",
|
||||
"The dead batteries were given out free of charge.",
|
||||
"Why are there no knock-knock jokes about America? Because freedom rings.",
|
||||
"When the cannibal showed up late to dinner, they gave him the cold shoulder.",
|
||||
"I should have been sad when my flashlight died, but I was delighted.",
|
||||
"Why don't tennis players ever get married? Love means nothing to them.",
|
||||
"Pterodactyls can't be heard going to the bathroom because the P is silent.",
|
||||
"Mermaids make calls on their shell phones.",
|
||||
"What do you call an aardvark with three feet? A yaardvark.",
|
||||
"Captain Kirk has three ears: A right ear, a left ear, and a final front ear.",
|
||||
"How do celebrities stay cool? They have a lot of fans.",
|
||||
"Without geometry, life is pointless.",
|
||||
"Did you hear about the cow who tried to jump over a barbed-wire fence? It ended in udder destruction.",
|
||||
"The truth may ring like a bell, but it is seldom ever tolled.",
|
||||
"I used to work for the IRS, but my job was too taxing.",
|
||||
"I used to be a programmer, but then I lost my drive.",
|
||||
"Pediatricians are doctors with little patients.",
|
||||
"I finally fired my masseuse today. She always rubbed me the wrong way.",
|
||||
"I stayed up all night wondering where the sun went. Then it dawned on me.",
|
||||
"What's the difference between a man and his dog? The man wears a suit; the dog just pants.",
|
||||
"A psychic midget who escapes from prison is a small medium at large.",
|
||||
"I've been to the dentist several times, so I know the drill.",
|
||||
"The roundest knight at King Arthur's round table was Sir Cumference. He acquired his size from too much pi.",
|
||||
"She was only a whiskey maker, but he loved her still.",
|
||||
"Male deer have buck teeth.",
|
||||
"Whiteboards are remarkable.",
|
||||
"Visitors in Cuba are always Havana good time.",
|
||||
"Why does electricity shock people? It doesn't know how to conduct itself.",
|
||||
"Lancelot had a scary dream about his horse. It was a knight mare.",
|
||||
"A tribe of cannibals captured a missionary and ate him. Afterward, they all had violent food poisoning. This just goes to show that you can't keep a good man down.",
|
||||
"Heaven for gamblers is a paradise.",
|
||||
"Old wheels aren't thrown away, they're just retired.",
|
||||
"Horses are very stable animals.",
|
||||
"Banks don't crash, they just lose their balance.",
|
||||
"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 person who invented the door-knock won the No-bell prize.",
|
||||
"I couldn't work out how to fasten my seatbelt. Then it clicked.",
|
||||
"Never trust atoms; they make up everything.",
|
||||
"Singing in the shower is all fun and games until you get shampoo in your mouth - Then it becomes a soap opera.",
|
||||
"I can't believe I got fired from the calendar factory. All I did was take a day off.",
|
||||
"To the guy who invented zero: Thanks for nothing!",
|
||||
"Enough with the cripple jokes! I just can't stand them.",
|
||||
"I've accidentally swallowed some Scrabble tiles. My next crap could spell disaster.",
|
||||
"How does Moses make his tea? Hebrews it.",
|
||||
"Did you hear about the guy who got hit in the head with a can of soda? He was lucky it was a soft drink.",
|
||||
"When William joined the army he disliked the phrase 'fire at will'.",
|
||||
"There was a sign on the lawn at a rehab center that said 'Keep off the Grass'.",
|
||||
"I wondered why the baseball was getting bigger. Then it hit me.",
|
||||
"I can hear music coming out of my printer. I think the paper's jamming again.",
|
||||
"I have a few jokes about unemployed people, but none of them work",
|
||||
"Want to hear a construction joke? I'm working on it",
|
||||
"I always take a second pair of pants when I go golfing, in case I get a hole in one.",
|
||||
"I couldn't remember how to throw a boomerang, but then it came back to me.",
|
||||
"I've decided that my wifi will be my valentine. IDK, we just have this connection.",
|
||||
"A prisoner's favorite punctuation mark is the period. It marks the end of his sentence.",
|
||||
"I used to go fishing with Skrillex, but he kept dropping the bass.",
|
||||
"Two antennae met on a roof and got married. The wedding was okay, but the reception was incredible.",
|
||||
"A book just fell on my head. I've only got my shelf to blame.",
|
||||
"I dropped my steak on the floor. Now it's ground beef.",
|
||||
"I used to have a fear of hurdles, but I got over it.",
|
||||
"The outcome of war does not prove who is right, but only who is left.",
|
||||
"Darth Vader tries not to burn his food, but it always comes out a little on the dark side.",
|
||||
"The store keeps calling me to buy more furniture, but all I wanted was a one night stand.",
|
||||
"This girl said she recognized me from the vegetarian club, but I'd never met herbivore.",
|
||||
"Police arrested two kids yesterday, one was drinking battery acid, the other was eating fireworks. They charged one and let the other one off...",
|
||||
"No more Harry Potter jokes guys. I'm Sirius.",
|
||||
"It was hard getting over my addiction to hokey pokey, but I've turned myself around.",
|
||||
"It takes a lot of balls to golf the way I do.",
|
||||
"Why did everyone want to hang out with the mushroom? Because he was a fungi.",
|
||||
"How much does a hipster weigh? An instagram.",
|
||||
"I used to be addicted to soap, but I'm clean now.",
|
||||
"When life gives you melons, you’re probably dyslexic.",
|
||||
"What's with all the blind jokes? I just don't see the point.",
|
||||
"If Apple made a car, would it have Windows?",
|
||||
"Need an ark? I Noah guy.",
|
||||
"The scarecrow won an award because he was outstanding in his field.",
|
||||
"What's the difference between a man in a tux on a bicycle, and a man in a sweatsuit on a trycicle? A tire.",
|
||||
"What do you do with a sick chemist? If you can't helium, and you can't curium, you'll just have to barium.",
|
||||
"I'm reading a book about anti-gravity. It's impossible to put down.",
|
||||
"Trying to write with a broken pencil is pointless.",
|
||||
"When TVs go on vacation, they travel to remote islands.",
|
||||
"I was going to tell a midget joke, but it's too short.",
|
||||
"Jokes about German sausage are the wurst.",
|
||||
"How do you organize a space party? You planet.",
|
||||
"Sleeping comes so naturally to me, I could do it with my eyes closed.",
|
||||
"I'm glad I know sign language; it's pretty handy.",
|
||||
"Atheism is a non-prophet organization.",
|
||||
"Velcro: What a rip-off!",
|
||||
"If they made a Minecraft movie, it would be a blockbuster.",
|
||||
"I don't trust people with graph paper. They're always plotting something",
|
||||
"I had a friend who was addicted to brake fluid. He says he can stop anytime.",
|
||||
"The form said I had Type A blood, but it was a Type O.",
|
||||
"I went to to the shop to buy eight Sprites - I came home and realised I'd picked 7Up.",
|
||||
"There was an explosion at a pie factory. 3.14 people died.",
|
||||
"A man drove his car into a tree and found out how a Mercedes bends.",
|
||||
"The experienced carpenter really nailed it, but the new guy screwed everything up.",
|
||||
"I didn't like my beard at first, but then it grew on me.",
|
||||
"Smaller babies may be delivered by stork, but the heavier ones need a crane.",
|
||||
"What's the definition of a will? It's a dead giveaway.",
|
||||
"I was going to look for my missing watch, but I could never find the time.",
|
||||
"I hate elevators, and I often take steps to avoid them.",
|
||||
"Did you hear about the guy whose whole left side was cut off? He's all right now.",
|
||||
"It's not that the man did not know how to juggle, he just didn't have the balls to do it.",
|
||||
"I used to be a loan shark, but I lost interest",
|
||||
"I don't trust these stairs; they're always up to something.",
|
||||
"My friend's bakery burned down last night. Now his business is toast.",
|
||||
"Don't trust people that do acupuncture; they're back stabbers.",
|
||||
"The man who survived mustard gas and pepper spray is now a seasoned veteran.",
|
||||
"Police were called to a daycare where a three-year-old was resisting a rest.",
|
||||
"When Peter Pan punches, they Neverland",
|
||||
"The shoemaker did not deny his apprentice anything he needed. He gave him his awl.",
|
||||
"I did a theatrical performance about puns. It was a play on words.",
|
||||
"Show me a piano falling down a mineshaft and I'll show you A-flat minor.",
|
||||
"Have you ever tried to eat a clock? It's very time consuming.",
|
||||
"There was once a cross-eyed teacher who couldn't control his pupils.",
|
||||
"A new type of broom came out and it is sweeping the nation.",
|
||||
"I relish the fact that you've mustard the strength to ketchup to me.",
|
||||
"I knew a woman who owned a taser. Man, was she stunning!",
|
||||
"What did the grape say when it got stepped on? Nothing - but it let out a little whine.",
|
||||
"It was an emotional wedding. Even the cake was in tiers.",
|
||||
"When a clock is hungry it goes back four seconds.",
|
||||
"The dead batteries were given out free of charge.",
|
||||
"Why are there no knock-knock jokes about America? Because freedom rings.",
|
||||
"When the cannibal showed up late to dinner, they gave him the cold shoulder.",
|
||||
"I should have been sad when my flashlight died, but I was delighted.",
|
||||
"Why don't tennis players ever get married? Love means nothing to them.",
|
||||
"Pterodactyls can't be heard going to the bathroom because the P is silent.",
|
||||
"Mermaids make calls on their shell phones.",
|
||||
"What do you call an aardvark with three feet? A yaardvark.",
|
||||
"Captain Kirk has three ears: A right ear, a left ear, and a final front ear.",
|
||||
"How do celebrities stay cool? They have a lot of fans.",
|
||||
"Without geometry, life is pointless.",
|
||||
"Did you hear about the cow who tried to jump over a barbed-wire fence? It ended in udder destruction.",
|
||||
"The truth may ring like a bell, but it is seldom ever tolled.",
|
||||
"I used to work for the IRS, but my job was too taxing.",
|
||||
"I used to be a programmer, but then I lost my drive.",
|
||||
"Pediatricians are doctors with little patients.",
|
||||
"I finally fired my masseuse today. She always rubbed me the wrong way.",
|
||||
"I stayed up all night wondering where the sun went. Then it dawned on me.",
|
||||
"What's the difference between a man and his dog? The man wears a suit; the dog just pants.",
|
||||
"A psychic midget who escapes from prison is a small medium at large.",
|
||||
"I've been to the dentist several times, so I know the drill.",
|
||||
"The roundest knight at King Arthur's round table was Sir Cumference. He acquired his size from too much pi.",
|
||||
"She was only a whiskey maker, but he loved her still.",
|
||||
"Male deer have buck teeth.",
|
||||
"Whiteboards are remarkable.",
|
||||
"Visitors in Cuba are always Havana good time.",
|
||||
"Why does electricity shock people? It doesn't know how to conduct itself.",
|
||||
"Lancelot had a scary dream about his horse. It was a knight mare.",
|
||||
"A tribe of cannibals captured a missionary and ate him. Afterward, they all had violent food poisoning. This just goes to show that you can't keep a good man down.",
|
||||
"Heaven for gamblers is a paradise.",
|
||||
"Old wheels aren't thrown away, they're just retired.",
|
||||
"Horses are very stable animals.",
|
||||
"Banks don't crash, they just lose their balance.",
|
||||
"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."
|
||||
}
|
||||
|
||||
function pun:action(msg)
|
||||
|
||||
utilities.send_reply(self, msg, puns[math.random(#puns)])
|
||||
utilities.send_reply(self, msg, puns[math.random(#puns)])
|
||||
|
||||
end
|
||||
|
||||
|
@ -16,34 +16,34 @@ reactions.doc = 'Returns a list of "reaction" emoticon commands.'
|
||||
local help
|
||||
|
||||
function reactions:init(config)
|
||||
-- Generate a "help" message triggered by "/reactions".
|
||||
help = 'Reactions:\n'
|
||||
reactions.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('reactions').table
|
||||
local username = self.info.username:lower()
|
||||
for trigger,reaction in pairs(config.reactions) do
|
||||
help = help .. '• ' .. config.cmd_pat .. trigger .. ': ' .. reaction .. '\n'
|
||||
table.insert(reactions.triggers, '^'..config.cmd_pat..trigger)
|
||||
table.insert(reactions.triggers, '^'..config.cmd_pat..trigger..'@'..username)
|
||||
table.insert(reactions.triggers, config.cmd_pat..trigger..'$')
|
||||
table.insert(reactions.triggers, config.cmd_pat..trigger..'@'..username..'$')
|
||||
table.insert(reactions.triggers, '\n'..config.cmd_pat..trigger)
|
||||
table.insert(reactions.triggers, '\n'..config.cmd_pat..trigger..'@'..username)
|
||||
table.insert(reactions.triggers, config.cmd_pat..trigger..'\n')
|
||||
table.insert(reactions.triggers, config.cmd_pat..trigger..'@'..username..'\n')
|
||||
end
|
||||
-- Generate a "help" message triggered by "/reactions".
|
||||
help = 'Reactions:\n'
|
||||
reactions.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('reactions').table
|
||||
local username = self.info.username:lower()
|
||||
for trigger,reaction in pairs(config.reactions) do
|
||||
help = help .. '• ' .. config.cmd_pat .. trigger .. ': ' .. reaction .. '\n'
|
||||
table.insert(reactions.triggers, '^'..config.cmd_pat..trigger)
|
||||
table.insert(reactions.triggers, '^'..config.cmd_pat..trigger..'@'..username)
|
||||
table.insert(reactions.triggers, config.cmd_pat..trigger..'$')
|
||||
table.insert(reactions.triggers, config.cmd_pat..trigger..'@'..username..'$')
|
||||
table.insert(reactions.triggers, '\n'..config.cmd_pat..trigger)
|
||||
table.insert(reactions.triggers, '\n'..config.cmd_pat..trigger..'@'..username)
|
||||
table.insert(reactions.triggers, config.cmd_pat..trigger..'\n')
|
||||
table.insert(reactions.triggers, config.cmd_pat..trigger..'@'..username..'\n')
|
||||
end
|
||||
end
|
||||
|
||||
function reactions:action(msg, config)
|
||||
if string.match(msg.text_lower, config.cmd_pat..'reactions') then
|
||||
utilities.send_message(self, msg.chat.id, help)
|
||||
return
|
||||
end
|
||||
for trigger,reaction in pairs(config.reactions) do
|
||||
if string.match(msg.text_lower, config.cmd_pat..trigger) then
|
||||
utilities.send_message(self, msg.chat.id, reaction)
|
||||
return
|
||||
end
|
||||
end
|
||||
if string.match(msg.text_lower, config.cmd_pat..'reactions') then
|
||||
utilities.send_message(self, msg.chat.id, help)
|
||||
return
|
||||
end
|
||||
for trigger,reaction in pairs(config.reactions) do
|
||||
if string.match(msg.text_lower, config.cmd_pat..trigger) then
|
||||
utilities.send_message(self, msg.chat.id, reaction)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return reactions
|
||||
|
@ -8,29 +8,29 @@ local utilities = require('otouto.utilities')
|
||||
reddit.command = 'reddit [r/subreddit | query]'
|
||||
|
||||
function reddit:init(config)
|
||||
reddit.triggers = utilities.triggers(self.info.username, config.cmd_pat, {'^/r/'}):t('reddit', true):t('r', true):t('r/', true).table
|
||||
reddit.doc = config.cmd_pat .. [[reddit [r/subreddit | query]
|
||||
reddit.triggers = utilities.triggers(self.info.username, config.cmd_pat, {'^/r/'}):t('reddit', true):t('r', true):t('r/', true).table
|
||||
reddit.doc = config.cmd_pat .. [[reddit [r/subreddit | query]
|
||||
Returns the top posts or results for a given subreddit or query. If no argument is given, returns the top posts from r/all. Querying specific subreddits is not supported.
|
||||
Aliases: ]] .. config.cmd_pat .. 'r, /r/subreddit'
|
||||
end
|
||||
|
||||
local format_results = function(posts)
|
||||
local output = ''
|
||||
for _,v in ipairs(posts) do
|
||||
local post = v.data
|
||||
local title = post.title:gsub('%[', '('):gsub('%]', ')'):gsub('&', '&')
|
||||
if title:len() > 256 then
|
||||
title = title:sub(1, 253)
|
||||
title = utilities.trim(title) .. '...'
|
||||
end
|
||||
local short_url = 'redd.it/' .. post.id
|
||||
local s = '[' .. title .. '](' .. short_url .. ')'
|
||||
if post.domain and not post.is_self and not post.over_18 then
|
||||
s = '`[`[' .. post.domain .. '](' .. post.url:gsub('%)', '\\)') .. ')`]` ' .. s
|
||||
end
|
||||
output = output .. '• ' .. s .. '\n'
|
||||
end
|
||||
return output
|
||||
local output = ''
|
||||
for _,v in ipairs(posts) do
|
||||
local post = v.data
|
||||
local title = post.title:gsub('%[', '('):gsub('%]', ')'):gsub('&', '&')
|
||||
if title:len() > 256 then
|
||||
title = title:sub(1, 253)
|
||||
title = utilities.trim(title) .. '...'
|
||||
end
|
||||
local short_url = 'redd.it/' .. post.id
|
||||
local s = '[' .. title .. '](' .. short_url .. ')'
|
||||
if post.domain and not post.is_self and not post.over_18 then
|
||||
s = '`[`[' .. post.domain .. '](' .. post.url:gsub('%)', '\\)') .. ')`]` ' .. s
|
||||
end
|
||||
output = output .. '• ' .. s .. '\n'
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
reddit.subreddit_url = 'http://www.reddit.com/%s/.json?limit='
|
||||
@ -38,46 +38,46 @@ reddit.search_url = 'http://www.reddit.com/search.json?q=%s&limit='
|
||||
reddit.rall_url = 'http://www.reddit.com/.json?limit='
|
||||
|
||||
function reddit:action(msg, config)
|
||||
-- Eight results in PM, four results elsewhere.
|
||||
local limit = 4
|
||||
if msg.chat.type == 'private' then
|
||||
limit = 8
|
||||
end
|
||||
local text = msg.text_lower
|
||||
if text:match('^/r/.') then
|
||||
-- Normalize input so this hack works easily.
|
||||
text = msg.text_lower:gsub('^/r/', config.cmd_pat..'r r/')
|
||||
end
|
||||
local input = utilities.input(text)
|
||||
local source, url
|
||||
if input then
|
||||
if input:match('^r/.') then
|
||||
input = utilities.get_word(input, 1)
|
||||
url = reddit.subreddit_url:format(input) .. limit
|
||||
source = '*/' .. utilities.md_escape(input) .. '*\n'
|
||||
else
|
||||
input = utilities.input(msg.text)
|
||||
source = '*Results for* _' .. utilities.md_escape(input) .. '_ *:*\n'
|
||||
input = URL.escape(input)
|
||||
url = reddit.search_url:format(input) .. limit
|
||||
end
|
||||
else
|
||||
url = reddit.rall_url .. limit
|
||||
source = '*/r/all*\n'
|
||||
end
|
||||
local jstr, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
else
|
||||
local jdat = JSON.decode(jstr)
|
||||
if #jdat.data.children == 0 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
else
|
||||
local output = format_results(jdat.data.children)
|
||||
output = source .. output
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
end
|
||||
end
|
||||
-- Eight results in PM, four results elsewhere.
|
||||
local limit = 4
|
||||
if msg.chat.type == 'private' then
|
||||
limit = 8
|
||||
end
|
||||
local text = msg.text_lower
|
||||
if text:match('^/r/.') then
|
||||
-- Normalize input so this hack works easily.
|
||||
text = msg.text_lower:gsub('^/r/', config.cmd_pat..'r r/')
|
||||
end
|
||||
local input = utilities.input(text)
|
||||
local source, url
|
||||
if input then
|
||||
if input:match('^r/.') then
|
||||
input = utilities.get_word(input, 1)
|
||||
url = reddit.subreddit_url:format(input) .. limit
|
||||
source = '*/' .. utilities.md_escape(input) .. '*\n'
|
||||
else
|
||||
input = utilities.input(msg.text)
|
||||
source = '*Results for* _' .. utilities.md_escape(input) .. '_ *:*\n'
|
||||
input = URL.escape(input)
|
||||
url = reddit.search_url:format(input) .. limit
|
||||
end
|
||||
else
|
||||
url = reddit.rall_url .. limit
|
||||
source = '*/r/all*\n'
|
||||
end
|
||||
local jstr, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
else
|
||||
local jdat = JSON.decode(jstr)
|
||||
if #jdat.data.children == 0 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
else
|
||||
local output = format_results(jdat.data.children)
|
||||
output = source .. output
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return reddit
|
||||
|
@ -5,87 +5,87 @@ local utilities = require('otouto.utilities')
|
||||
remind.command = 'remind <duration> <message>'
|
||||
|
||||
function remind:init(config)
|
||||
self.database.reminders = self.database.reminders or {}
|
||||
self.database.reminders = self.database.reminders or {}
|
||||
|
||||
remind.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('remind', true).table
|
||||
remind.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('remind', true).table
|
||||
|
||||
config.remind = config.remind or {}
|
||||
setmetatable(config.remind, { __index = function() return 1000 end })
|
||||
config.remind = config.remind or {}
|
||||
setmetatable(config.remind, { __index = function() return 1000 end })
|
||||
|
||||
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.
|
||||
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(self, msg, remind.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, remind.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local duration = tonumber(utilities.get_word(input, 1))
|
||||
if not duration then
|
||||
utilities.send_reply(self, msg, remind.doc, true)
|
||||
return
|
||||
end
|
||||
local duration = tonumber(utilities.get_word(input, 1))
|
||||
if not duration then
|
||||
utilities.send_reply(self, msg, remind.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
if duration < 1 then
|
||||
duration = 1
|
||||
elseif duration > config.remind.max_duration then
|
||||
duration = config.remind.max_duration
|
||||
end
|
||||
local message = utilities.input(input)
|
||||
if not message then
|
||||
utilities.send_reply(self, msg, remind.doc, true)
|
||||
return
|
||||
end
|
||||
if duration < 1 then
|
||||
duration = 1
|
||||
elseif duration > config.remind.max_duration then
|
||||
duration = config.remind.max_duration
|
||||
end
|
||||
local message = utilities.input(input)
|
||||
if not message then
|
||||
utilities.send_reply(self, msg, remind.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
if #message > config.remind.max_length then
|
||||
utilities.send_reply(self, msg, 'The maximum length of reminders is ' .. config.remind.max_length .. '.')
|
||||
return
|
||||
end
|
||||
if #message > config.remind.max_length then
|
||||
utilities.send_reply(self, msg, 'The maximum length of reminders is ' .. config.remind.max_length .. '.')
|
||||
return
|
||||
end
|
||||
|
||||
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
|
||||
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
|
||||
output = 'Sorry, this group already has the maximum number of reminders.'
|
||||
else
|
||||
table.insert(self.database.reminders[chat_id_str], {
|
||||
time = os.time() + (duration * 60),
|
||||
message = message
|
||||
})
|
||||
output = string.format(
|
||||
'I will remind you in %s minute%s!',
|
||||
duration,
|
||||
duration == 1 and '' or 's'
|
||||
)
|
||||
end
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
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
|
||||
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
|
||||
output = 'Sorry, this group already has the maximum number of reminders.'
|
||||
else
|
||||
table.insert(self.database.reminders[chat_id_str], {
|
||||
time = os.time() + (duration * 60),
|
||||
message = message
|
||||
})
|
||||
output = string.format(
|
||||
'I will remind you in %s minute%s!',
|
||||
duration,
|
||||
duration == 1 and '' or 's'
|
||||
)
|
||||
end
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
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
|
||||
-- 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(self, chat_id, output, true, nil, true)
|
||||
-- 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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local time = os.time()
|
||||
-- Iterate over the group entries in the reminders database.
|
||||
for chat_id, group in pairs(self.database.reminders) 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(self, chat_id, output, true, nil, true)
|
||||
-- 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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return remind
|
||||
|
@ -5,30 +5,30 @@ local bindings = require('otouto.bindings')
|
||||
local rms = {}
|
||||
|
||||
function rms:init(config)
|
||||
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
|
||||
end
|
||||
for link in s:gmatch('<a href=".-%.%a%a%a">(.-)</a>') do
|
||||
table.insert(rms.LIST, link)
|
||||
end
|
||||
rms.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('rms').table
|
||||
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
|
||||
end
|
||||
for link in s:gmatch('<a href=".-%.%a%a%a">(.-)</a>') do
|
||||
table.insert(rms.LIST, link)
|
||||
end
|
||||
rms.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('rms').table
|
||||
end
|
||||
|
||||
function rms:action(msg, config)
|
||||
bindings.sendChatAction(self, { 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(self, { chat_id = msg.chat.id }, { photo = filename })
|
||||
bindings.sendChatAction(self, { 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(self, { chat_id = msg.chat.id }, { photo = filename })
|
||||
end
|
||||
|
||||
return rms
|
||||
|
@ -3,9 +3,9 @@ local setandget = {}
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function setandget:init(config)
|
||||
self.database.setandget = self.database.setandget or {}
|
||||
setandget.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('set', true):t('get', true).table
|
||||
setandget.doc = config.cmd_pat .. [[set <name> <value>
|
||||
self.database.setandget = self.database.setandget or {}
|
||||
setandget.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('set', true):t('get', true).table
|
||||
setandget.doc = config.cmd_pat .. [[set <name> <value>
|
||||
Stores a value with the given name. Use "]] .. config.cmd_pat .. [[set <name> --" to delete the stored value.
|
||||
]] .. config.cmd_pat .. [[get [name]
|
||||
Returns the stored value or a list of stored values.]]
|
||||
@ -15,56 +15,56 @@ setandget.command = 'set <name> <value>'
|
||||
|
||||
function setandget:action(msg, config)
|
||||
|
||||
local chat_id_str = tostring(msg.chat.id)
|
||||
local input = utilities.input(msg.text)
|
||||
self.database.setandget[chat_id_str] = self.database.setandget[chat_id_str] or {}
|
||||
local chat_id_str = tostring(msg.chat.id)
|
||||
local input = utilities.input(msg.text)
|
||||
self.database.setandget[chat_id_str] = self.database.setandget[chat_id_str] or {}
|
||||
|
||||
if msg.text_lower:match('^'..config.cmd_pat..'set') then
|
||||
if msg.text_lower:match('^'..config.cmd_pat..'set') then
|
||||
|
||||
if not input then
|
||||
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
|
||||
return
|
||||
end
|
||||
if not input then
|
||||
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
|
||||
return
|
||||
end
|
||||
|
||||
local name = utilities.get_word(input:lower(), 1)
|
||||
local value = utilities.input(input)
|
||||
local name = utilities.get_word(input:lower(), 1)
|
||||
local value = utilities.input(input)
|
||||
|
||||
if not name or not value then
|
||||
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
|
||||
elseif value == '--' or value == '—' then
|
||||
self.database.setandget[chat_id_str][name] = nil
|
||||
utilities.send_message(self, msg.chat.id, 'That value has been deleted.')
|
||||
else
|
||||
self.database.setandget[chat_id_str][name] = value
|
||||
utilities.send_message(self, msg.chat.id, '"' .. name .. '" has been set to "' .. value .. '".', true)
|
||||
end
|
||||
if not name or not value then
|
||||
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
|
||||
elseif value == '--' or value == '—' then
|
||||
self.database.setandget[chat_id_str][name] = nil
|
||||
utilities.send_message(self, msg.chat.id, 'That value has been deleted.')
|
||||
else
|
||||
self.database.setandget[chat_id_str][name] = value
|
||||
utilities.send_message(self, msg.chat.id, '"' .. name .. '" has been set to "' .. value .. '".', true)
|
||||
end
|
||||
|
||||
elseif msg.text_lower:match('^'..config.cmd_pat..'get') then
|
||||
elseif msg.text_lower:match('^'..config.cmd_pat..'get') then
|
||||
|
||||
if not input then
|
||||
local output
|
||||
if utilities.table_size(self.database.setandget[chat_id_str]) == 0 then
|
||||
output = 'No values have been stored here.'
|
||||
else
|
||||
output = '*List of stored values:*\n'
|
||||
for k,v in pairs(self.database.setandget[chat_id_str]) do
|
||||
output = output .. '• ' .. k .. ': `' .. v .. '`\n'
|
||||
end
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
return
|
||||
end
|
||||
if not input then
|
||||
local output
|
||||
if utilities.table_size(self.database.setandget[chat_id_str]) == 0 then
|
||||
output = 'No values have been stored here.'
|
||||
else
|
||||
output = '*List of stored values:*\n'
|
||||
for k,v in pairs(self.database.setandget[chat_id_str]) do
|
||||
output = output .. '• ' .. k .. ': `' .. v .. '`\n'
|
||||
end
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
return
|
||||
end
|
||||
|
||||
local output
|
||||
if self.database.setandget[chat_id_str][input:lower()] then
|
||||
output = '`' .. self.database.setandget[chat_id_str][input:lower()] .. '`'
|
||||
else
|
||||
output = 'There is no value stored by that name.'
|
||||
end
|
||||
local output
|
||||
if self.database.setandget[chat_id_str][input:lower()] then
|
||||
output = '`' .. self.database.setandget[chat_id_str][input:lower()] .. '`'
|
||||
else
|
||||
output = 'There is no value stored by that name.'
|
||||
end
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
@ -3,32 +3,32 @@ local shell = {}
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function shell:init(config)
|
||||
shell.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('run', true).table
|
||||
shell.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('run', true).table
|
||||
end
|
||||
|
||||
function shell:action(msg, config)
|
||||
|
||||
if msg.from.id ~= config.admin then
|
||||
return
|
||||
end
|
||||
if msg.from.id ~= config.admin then
|
||||
return
|
||||
end
|
||||
|
||||
local input = utilities.input(msg.text)
|
||||
input = input:gsub('—', '--')
|
||||
local input = utilities.input(msg.text)
|
||||
input = input:gsub('—', '--')
|
||||
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, 'Please specify a command to run.')
|
||||
return
|
||||
end
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, 'Please specify a command to run.')
|
||||
return
|
||||
end
|
||||
|
||||
local f = io.popen(input)
|
||||
local output = f:read('*all')
|
||||
f:close()
|
||||
if output:len() == 0 then
|
||||
output = 'Done!'
|
||||
else
|
||||
output = '```\n' .. output .. '\n```'
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, output, true, msg.message_id, true)
|
||||
local f = io.popen(input)
|
||||
local output = f:read('*all')
|
||||
f:close()
|
||||
if output:len() == 0 then
|
||||
output = 'Done!'
|
||||
else
|
||||
output = '```\n' .. output .. '\n```'
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, output, true, msg.message_id, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -6,45 +6,45 @@ shout.command = 'shout <text>'
|
||||
local utf8 = '('..utilities.char.utf_8..'*)'
|
||||
|
||||
function shout:init(config)
|
||||
shout.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('shout', true).table
|
||||
shout.doc = config.cmd_pat .. 'shout <text> \nShouts something. Input may be the replied-to message.'
|
||||
shout.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('shout', true).table
|
||||
shout.doc = config.cmd_pat .. 'shout <text> \nShouts something. Input may be the replied-to message.'
|
||||
end
|
||||
|
||||
function shout:action(msg)
|
||||
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, shout.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, shout.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
input = utilities.trim(input)
|
||||
input = input:upper()
|
||||
input = utilities.trim(input)
|
||||
input = input:upper()
|
||||
|
||||
local output = ''
|
||||
local inc = 0
|
||||
local ilen = 0
|
||||
for match in input:gmatch(utf8) do
|
||||
if ilen < 20 then
|
||||
ilen = ilen + 1
|
||||
output = output .. match .. ' '
|
||||
end
|
||||
end
|
||||
ilen = 0
|
||||
output = output .. '\n'
|
||||
for match in input:sub(2):gmatch(utf8) do
|
||||
if ilen < 19 then
|
||||
local spacing = ''
|
||||
for _ = 1, inc do
|
||||
spacing = spacing .. ' '
|
||||
end
|
||||
inc = inc + 1
|
||||
ilen = ilen + 1
|
||||
output = output .. match .. ' ' .. spacing .. match .. '\n'
|
||||
end
|
||||
end
|
||||
output = '```\n' .. utilities.trim(output) .. '\n```'
|
||||
utilities.send_message(self, msg.chat.id, output, true, false, true)
|
||||
local output = ''
|
||||
local inc = 0
|
||||
local ilen = 0
|
||||
for match in input:gmatch(utf8) do
|
||||
if ilen < 20 then
|
||||
ilen = ilen + 1
|
||||
output = output .. match .. ' '
|
||||
end
|
||||
end
|
||||
ilen = 0
|
||||
output = output .. '\n'
|
||||
for match in input:sub(2):gmatch(utf8) do
|
||||
if ilen < 19 then
|
||||
local spacing = ''
|
||||
for _ = 1, inc do
|
||||
spacing = spacing .. ' '
|
||||
end
|
||||
inc = inc + 1
|
||||
ilen = ilen + 1
|
||||
output = output .. match .. ' ' .. spacing .. match .. '\n'
|
||||
end
|
||||
end
|
||||
output = '```\n' .. utilities.trim(output) .. '\n```'
|
||||
utilities.send_message(self, msg.chat.id, output, true, false, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -5,160 +5,160 @@ local utilities = require('otouto.utilities')
|
||||
slap.command = 'slap [target]'
|
||||
|
||||
function slap:init(config)
|
||||
slap.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('slap', true).table
|
||||
slap.doc = config.cmd_pat .. 'slap [target] \nSlap somebody.'
|
||||
slap.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('slap', true).table
|
||||
slap.doc = config.cmd_pat .. 'slap [target] \nSlap somebody.'
|
||||
end
|
||||
|
||||
local slaps = {
|
||||
'VICTIM was shot by VICTOR.',
|
||||
'VICTIM was pricked to death.',
|
||||
'VICTIM walked into a cactus while trying to escape VICTOR.',
|
||||
'VICTIM drowned.',
|
||||
'VICTIM drowned whilst trying to escape VICTOR.',
|
||||
'VICTIM blew up.',
|
||||
'VICTIM was blown up by VICTOR.',
|
||||
'VICTIM hit the ground too hard.',
|
||||
'VICTIM fell from a high place.',
|
||||
'VICTIM fell off a ladder.',
|
||||
'VICTIM fell into a patch of cacti.',
|
||||
'VICTIM was doomed to fall by VICTOR.',
|
||||
'VICTIM was blown from a high place by VICTOR.',
|
||||
'VICTIM was squashed by a falling anvil.',
|
||||
'VICTIM went up in flames.',
|
||||
'VICTIM burned to death.',
|
||||
'VICTIM was burnt to a crisp whilst fighting VICTOR.',
|
||||
'VICTIM walked into a fire whilst fighting VICTOR.',
|
||||
'VICTIM tried to swim in lava.',
|
||||
'VICTIM tried to swim in lava while trying to escape VICTOR.',
|
||||
'VICTIM was struck by lightning.',
|
||||
'VICTIM was slain by VICTOR.',
|
||||
'VICTIM got finished off by VICTOR.',
|
||||
'VICTIM was killed by magic.',
|
||||
'VICTIM was killed by VICTOR using magic.',
|
||||
'VICTIM starved to death.',
|
||||
'VICTIM suffocated in a wall.',
|
||||
'VICTIM fell out of the world.',
|
||||
'VICTIM was knocked into the void by VICTOR.',
|
||||
'VICTIM withered away.',
|
||||
'VICTIM was pummeled by VICTOR.',
|
||||
'VICTIM was fragged by VICTOR.',
|
||||
'VICTIM was desynchronized.',
|
||||
'VICTIM was wasted.',
|
||||
'VICTIM was busted.',
|
||||
'VICTIM\'s bones are scraped clean by the desolate wind.',
|
||||
'VICTIM has died of dysentery.',
|
||||
'VICTIM fainted.',
|
||||
'VICTIM is out of usable Pokemon! VICTIM whited out!',
|
||||
'VICTIM is out of usable Pokemon! VICTIM blacked out!',
|
||||
'VICTIM whited out!',
|
||||
'VICTIM blacked out!',
|
||||
'VICTIM says goodbye to this cruel world.',
|
||||
'VICTIM got rekt.',
|
||||
'VICTIM was sawn in half by VICTOR.',
|
||||
'VICTIM died. I blame VICTOR.',
|
||||
'VICTIM was axe-murdered by VICTOR.',
|
||||
'VICTIM\'s melon was split by VICTOR.',
|
||||
'VICTIM was sliced and diced by VICTOR.',
|
||||
'VICTIM was split from crotch to sternum by VICTOR.',
|
||||
'VICTIM\'s death put another notch in VICTOR\'s axe.',
|
||||
'VICTIM died impossibly!',
|
||||
'VICTIM died from VICTOR\'s mysterious tropical disease.',
|
||||
'VICTIM escaped infection by dying.',
|
||||
'VICTIM played hot-potato with a grenade.',
|
||||
'VICTIM was knifed by VICTOR.',
|
||||
'VICTIM fell on his sword.',
|
||||
'VICTIM ate a grenade.',
|
||||
'VICTIM practiced being VICTOR\'s clay pigeon.',
|
||||
'VICTIM is what\'s for dinner!',
|
||||
'VICTIM was terminated by VICTOR.',
|
||||
'VICTIM was shot before being thrown out of a plane.',
|
||||
'VICTIM was not invincible.',
|
||||
'VICTIM has encountered an error.',
|
||||
'VICTIM died and reincarnated as a goat.',
|
||||
'VICTOR threw VICTIM off a building.',
|
||||
'VICTIM is sleeping with the fishes.',
|
||||
'VICTIM got a premature burial.',
|
||||
'VICTOR replaced all of VICTIM\'s music with Nickelback.',
|
||||
'VICTOR spammed VICTIM\'s email.',
|
||||
'VICTOR made VICTIM a knuckle sandwich.',
|
||||
'VICTOR slapped VICTIM with pure nothing.',
|
||||
'VICTOR hit VICTIM with a small, interstellar spaceship.',
|
||||
'VICTIM was quickscoped by VICTOR.',
|
||||
'VICTOR put VICTIM in check-mate.',
|
||||
'VICTOR RSA-encrypted VICTIM and deleted the private key.',
|
||||
'VICTOR put VICTIM in the friendzone.',
|
||||
'VICTOR slaps VICTIM with a DMCA takedown request!',
|
||||
'VICTIM became a corpse blanket for VICTOR.',
|
||||
'Death is when the monsters get you. Death comes for VICTIM.',
|
||||
'Cowards die many times before their death. VICTIM never tasted death but once.',
|
||||
'VICTIM died of hospital gangrene.',
|
||||
'VICTIM got a house call from Doctor VICTOR.',
|
||||
'VICTOR beheaded VICTIM.',
|
||||
'VICTIM got stoned...by an angry mob.',
|
||||
'VICTOR sued the pants off VICTIM.',
|
||||
'VICTIM was impeached.',
|
||||
'VICTIM was one-hit KO\'d by VICTOR.',
|
||||
'VICTOR sent VICTIM to /dev/null.',
|
||||
'VICTOR sent VICTIM down the memory hole.',
|
||||
'VICTIM was a mistake.',
|
||||
'"VICTIM was a mistake." - VICTOR',
|
||||
'VICTOR checkmated VICTIM in two moves.'
|
||||
'VICTIM was shot by VICTOR.',
|
||||
'VICTIM was pricked to death.',
|
||||
'VICTIM walked into a cactus while trying to escape VICTOR.',
|
||||
'VICTIM drowned.',
|
||||
'VICTIM drowned whilst trying to escape VICTOR.',
|
||||
'VICTIM blew up.',
|
||||
'VICTIM was blown up by VICTOR.',
|
||||
'VICTIM hit the ground too hard.',
|
||||
'VICTIM fell from a high place.',
|
||||
'VICTIM fell off a ladder.',
|
||||
'VICTIM fell into a patch of cacti.',
|
||||
'VICTIM was doomed to fall by VICTOR.',
|
||||
'VICTIM was blown from a high place by VICTOR.',
|
||||
'VICTIM was squashed by a falling anvil.',
|
||||
'VICTIM went up in flames.',
|
||||
'VICTIM burned to death.',
|
||||
'VICTIM was burnt to a crisp whilst fighting VICTOR.',
|
||||
'VICTIM walked into a fire whilst fighting VICTOR.',
|
||||
'VICTIM tried to swim in lava.',
|
||||
'VICTIM tried to swim in lava while trying to escape VICTOR.',
|
||||
'VICTIM was struck by lightning.',
|
||||
'VICTIM was slain by VICTOR.',
|
||||
'VICTIM got finished off by VICTOR.',
|
||||
'VICTIM was killed by magic.',
|
||||
'VICTIM was killed by VICTOR using magic.',
|
||||
'VICTIM starved to death.',
|
||||
'VICTIM suffocated in a wall.',
|
||||
'VICTIM fell out of the world.',
|
||||
'VICTIM was knocked into the void by VICTOR.',
|
||||
'VICTIM withered away.',
|
||||
'VICTIM was pummeled by VICTOR.',
|
||||
'VICTIM was fragged by VICTOR.',
|
||||
'VICTIM was desynchronized.',
|
||||
'VICTIM was wasted.',
|
||||
'VICTIM was busted.',
|
||||
'VICTIM\'s bones are scraped clean by the desolate wind.',
|
||||
'VICTIM has died of dysentery.',
|
||||
'VICTIM fainted.',
|
||||
'VICTIM is out of usable Pokemon! VICTIM whited out!',
|
||||
'VICTIM is out of usable Pokemon! VICTIM blacked out!',
|
||||
'VICTIM whited out!',
|
||||
'VICTIM blacked out!',
|
||||
'VICTIM says goodbye to this cruel world.',
|
||||
'VICTIM got rekt.',
|
||||
'VICTIM was sawn in half by VICTOR.',
|
||||
'VICTIM died. I blame VICTOR.',
|
||||
'VICTIM was axe-murdered by VICTOR.',
|
||||
'VICTIM\'s melon was split by VICTOR.',
|
||||
'VICTIM was sliced and diced by VICTOR.',
|
||||
'VICTIM was split from crotch to sternum by VICTOR.',
|
||||
'VICTIM\'s death put another notch in VICTOR\'s axe.',
|
||||
'VICTIM died impossibly!',
|
||||
'VICTIM died from VICTOR\'s mysterious tropical disease.',
|
||||
'VICTIM escaped infection by dying.',
|
||||
'VICTIM played hot-potato with a grenade.',
|
||||
'VICTIM was knifed by VICTOR.',
|
||||
'VICTIM fell on his sword.',
|
||||
'VICTIM ate a grenade.',
|
||||
'VICTIM practiced being VICTOR\'s clay pigeon.',
|
||||
'VICTIM is what\'s for dinner!',
|
||||
'VICTIM was terminated by VICTOR.',
|
||||
'VICTIM was shot before being thrown out of a plane.',
|
||||
'VICTIM was not invincible.',
|
||||
'VICTIM has encountered an error.',
|
||||
'VICTIM died and reincarnated as a goat.',
|
||||
'VICTOR threw VICTIM off a building.',
|
||||
'VICTIM is sleeping with the fishes.',
|
||||
'VICTIM got a premature burial.',
|
||||
'VICTOR replaced all of VICTIM\'s music with Nickelback.',
|
||||
'VICTOR spammed VICTIM\'s email.',
|
||||
'VICTOR made VICTIM a knuckle sandwich.',
|
||||
'VICTOR slapped VICTIM with pure nothing.',
|
||||
'VICTOR hit VICTIM with a small, interstellar spaceship.',
|
||||
'VICTIM was quickscoped by VICTOR.',
|
||||
'VICTOR put VICTIM in check-mate.',
|
||||
'VICTOR RSA-encrypted VICTIM and deleted the private key.',
|
||||
'VICTOR put VICTIM in the friendzone.',
|
||||
'VICTOR slaps VICTIM with a DMCA takedown request!',
|
||||
'VICTIM became a corpse blanket for VICTOR.',
|
||||
'Death is when the monsters get you. Death comes for VICTIM.',
|
||||
'Cowards die many times before their death. VICTIM never tasted death but once.',
|
||||
'VICTIM died of hospital gangrene.',
|
||||
'VICTIM got a house call from Doctor VICTOR.',
|
||||
'VICTOR beheaded VICTIM.',
|
||||
'VICTIM got stoned...by an angry mob.',
|
||||
'VICTOR sued the pants off VICTIM.',
|
||||
'VICTIM was impeached.',
|
||||
'VICTIM was one-hit KO\'d by VICTOR.',
|
||||
'VICTOR sent VICTIM to /dev/null.',
|
||||
'VICTOR sent VICTIM down the memory hole.',
|
||||
'VICTIM was a mistake.',
|
||||
'"VICTIM was a mistake." - VICTOR',
|
||||
'VICTOR checkmated VICTIM in two moves.'
|
||||
}
|
||||
|
||||
-- optimize later
|
||||
function slap:action(msg)
|
||||
local input = utilities.input(msg.text)
|
||||
local victor_id = msg.from.id
|
||||
local victim_id
|
||||
if msg.reply_to_message then
|
||||
victim_id = msg.reply_to_message.from.id
|
||||
else
|
||||
if input then
|
||||
if tonumber(input) then
|
||||
victim_id = tonumber(input)
|
||||
elseif input:match('^@') then
|
||||
local t = utilities.resolve_username(self, input)
|
||||
if t then
|
||||
victim_id = t.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- IDs
|
||||
if victim_id then
|
||||
if victim_id == victor_id then
|
||||
victor_id = self.info.id
|
||||
end
|
||||
else
|
||||
if not input then
|
||||
victor_id = self.info.id
|
||||
victim_id = msg.from.id
|
||||
end
|
||||
end
|
||||
-- Names
|
||||
local victor_name, victim_name
|
||||
if input and not victim_id then
|
||||
victim_name = input
|
||||
else
|
||||
local victim_id_str = tostring(victim_id)
|
||||
if self.database.userdata[victim_id_str] and self.database.userdata[victim_id_str].nickname then
|
||||
victim_name = self.database.userdata[victim_id_str].nickname
|
||||
elseif self.database.users[victim_id_str] then
|
||||
victim_name = utilities.build_name(self.database.users[victim_id_str].first_name, self.database.users[victim_id_str].last_name)
|
||||
else
|
||||
victim_name = victim_id_str
|
||||
end
|
||||
end
|
||||
local victor_id_str = tostring(victor_id)
|
||||
if self.database.userdata[victor_id_str] and self.database.userdata[victor_id_str].nickname then
|
||||
victor_name = self.database.userdata[victor_id_str].nickname
|
||||
elseif self.database.users[victor_id_str] then
|
||||
victor_name = utilities.build_name(self.database.users[victor_id_str].first_name, self.database.users[victor_id_str].last_name)
|
||||
else
|
||||
victor_name = self.info.first_name
|
||||
end
|
||||
local output = utilities.char.zwnj .. slaps[math.random(#slaps)]:gsub('VICTIM', victim_name):gsub('VICTOR', victor_name)
|
||||
utilities.send_message(self, msg.chat.id, output)
|
||||
local input = utilities.input(msg.text)
|
||||
local victor_id = msg.from.id
|
||||
local victim_id
|
||||
if msg.reply_to_message then
|
||||
victim_id = msg.reply_to_message.from.id
|
||||
else
|
||||
if input then
|
||||
if tonumber(input) then
|
||||
victim_id = tonumber(input)
|
||||
elseif input:match('^@') then
|
||||
local t = utilities.resolve_username(self, input)
|
||||
if t then
|
||||
victim_id = t.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- IDs
|
||||
if victim_id then
|
||||
if victim_id == victor_id then
|
||||
victor_id = self.info.id
|
||||
end
|
||||
else
|
||||
if not input then
|
||||
victor_id = self.info.id
|
||||
victim_id = msg.from.id
|
||||
end
|
||||
end
|
||||
-- Names
|
||||
local victor_name, victim_name
|
||||
if input and not victim_id then
|
||||
victim_name = input
|
||||
else
|
||||
local victim_id_str = tostring(victim_id)
|
||||
if self.database.userdata[victim_id_str] and self.database.userdata[victim_id_str].nickname then
|
||||
victim_name = self.database.userdata[victim_id_str].nickname
|
||||
elseif self.database.users[victim_id_str] then
|
||||
victim_name = utilities.build_name(self.database.users[victim_id_str].first_name, self.database.users[victim_id_str].last_name)
|
||||
else
|
||||
victim_name = victim_id_str
|
||||
end
|
||||
end
|
||||
local victor_id_str = tostring(victor_id)
|
||||
if self.database.userdata[victor_id_str] and self.database.userdata[victor_id_str].nickname then
|
||||
victor_name = self.database.userdata[victor_id_str].nickname
|
||||
elseif self.database.users[victor_id_str] then
|
||||
victor_name = utilities.build_name(self.database.users[victor_id_str].first_name, self.database.users[victor_id_str].last_name)
|
||||
else
|
||||
victor_name = self.info.first_name
|
||||
end
|
||||
local output = utilities.char.zwnj .. slaps[math.random(#slaps)]:gsub('VICTIM', victim_name):gsub('VICTOR', victor_name)
|
||||
utilities.send_message(self, msg.chat.id, output)
|
||||
end
|
||||
|
||||
return slap
|
||||
|
@ -8,71 +8,71 @@ local utilities = require('otouto.utilities')
|
||||
local starwars = {}
|
||||
|
||||
function starwars:init(config)
|
||||
starwars.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('starwars', true):t('sw', true).table
|
||||
starwars.doc = config.cmd_pat .. [[starwars <query>
|
||||
starwars.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('starwars', true):t('sw', true).table
|
||||
starwars.doc = config.cmd_pat .. [[starwars <query>
|
||||
Returns the opening crawl from the specified Star Wars film.
|
||||
Alias: ]] .. config.cmd_pat .. 'sw'
|
||||
starwars.command = 'starwars <query>'
|
||||
starwars.base_url = 'http://swapi.co/api/films/'
|
||||
starwars.command = 'starwars <query>'
|
||||
starwars.base_url = 'http://swapi.co/api/films/'
|
||||
end
|
||||
|
||||
local films_by_number = {
|
||||
['phantom menace'] = 4,
|
||||
['attack of the clones'] = 5,
|
||||
['revenge of the sith'] = 6,
|
||||
['new hope'] = 1,
|
||||
['empire strikes back'] = 2,
|
||||
['return of the jedi'] = 3,
|
||||
['force awakens'] = 7
|
||||
['phantom menace'] = 4,
|
||||
['attack of the clones'] = 5,
|
||||
['revenge of the sith'] = 6,
|
||||
['new hope'] = 1,
|
||||
['empire strikes back'] = 2,
|
||||
['return of the jedi'] = 3,
|
||||
['force awakens'] = 7
|
||||
}
|
||||
|
||||
local corrected_numbers = {
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
7
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
7
|
||||
}
|
||||
|
||||
function starwars:action(msg, config)
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, starwars.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, starwars.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' } )
|
||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' } )
|
||||
|
||||
local film
|
||||
if tonumber(input) then
|
||||
input = tonumber(input)
|
||||
film = corrected_numbers[input] or input
|
||||
else
|
||||
for title, number in pairs(films_by_number) do
|
||||
if string.match(input, title) then
|
||||
film = number
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
local film
|
||||
if tonumber(input) then
|
||||
input = tonumber(input)
|
||||
film = corrected_numbers[input] or input
|
||||
else
|
||||
for title, number in pairs(films_by_number) do
|
||||
if string.match(input, title) then
|
||||
film = number
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not film then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
if not film then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
local url = starwars.base_url .. film
|
||||
local jstr, code = HTTP.request(url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local url = starwars.base_url .. film
|
||||
local jstr, code = HTTP.request(url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local output = '*' .. JSON.decode(jstr).opening_crawl .. '*'
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
local output = '*' .. JSON.decode(jstr).opening_crawl .. '*'
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
end
|
||||
|
||||
return starwars
|
||||
|
@ -8,52 +8,52 @@ time.command = 'time <location>'
|
||||
time.base_url = 'https://maps.googleapis.com/maps/api/timezone/json?location=%s,%s×tamp=%s'
|
||||
|
||||
function time:init(config)
|
||||
time.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('time', true).table
|
||||
time.doc = config.cmd_pat .. [[time <location>
|
||||
time.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('time', true).table
|
||||
time.doc = config.cmd_pat .. [[time <location>
|
||||
Returns the time, date, and timezone for the given location.]]
|
||||
end
|
||||
|
||||
function time:action(msg, config)
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, time.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, time.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local coords = utilities.get_coords(input, config)
|
||||
if type(coords) == 'string' then
|
||||
utilities.send_reply(self, msg, coords)
|
||||
return
|
||||
end
|
||||
local coords = utilities.get_coords(input, config)
|
||||
if type(coords) == 'string' then
|
||||
utilities.send_reply(self, msg, coords)
|
||||
return
|
||||
end
|
||||
|
||||
local now = os.time()
|
||||
local utc = os.time(os.date('!*t', now))
|
||||
local url = time.base_url:format(coords.lat, coords.lon, utc)
|
||||
local jstr, code = HTTPS.request(url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local now = os.time()
|
||||
local utc = os.time(os.date('!*t', now))
|
||||
local url = time.base_url:format(coords.lat, coords.lon, utc)
|
||||
local jstr, code = HTTPS.request(url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local data = JSON.decode(jstr)
|
||||
if data.status == 'ZERO_RESULTS' then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(jstr)
|
||||
if data.status == 'ZERO_RESULTS' then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
local timestamp = now + data.rawOffset + data.dstOffset
|
||||
local utcoff = (data.rawOffset + data.dstOffset) / 3600
|
||||
if utcoff == math.abs(utcoff) then
|
||||
utcoff = '+' .. utilities.pretty_float(utcoff)
|
||||
else
|
||||
utcoff = utilities.pretty_float(utcoff)
|
||||
end
|
||||
local output = string.format('```\n%s\n%s (UTC%s)\n```',
|
||||
os.date('!%I:%M %p\n%A, %B %d, %Y', timestamp),
|
||||
data.timeZoneName,
|
||||
utcoff
|
||||
)
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
local timestamp = now + data.rawOffset + data.dstOffset
|
||||
local utcoff = (data.rawOffset + data.dstOffset) / 3600
|
||||
if utcoff == math.abs(utcoff) then
|
||||
utcoff = '+' .. utilities.pretty_float(utcoff)
|
||||
else
|
||||
utcoff = utilities.pretty_float(utcoff)
|
||||
end
|
||||
local output = string.format('```\n%s\n%s (UTC%s)\n```',
|
||||
os.date('!%I:%M %p\n%A, %B %d, %Y', timestamp),
|
||||
data.timeZoneName,
|
||||
utcoff
|
||||
)
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
end
|
||||
|
||||
return time
|
||||
|
@ -8,38 +8,38 @@ local utilities = require('otouto.utilities')
|
||||
translate.command = 'translate [text]'
|
||||
|
||||
function translate:init(config)
|
||||
assert(config.yandex_key,
|
||||
'translate.lua requires a Yandex translate API key from http://tech.yandex.com/keys/get.'
|
||||
)
|
||||
assert(config.yandex_key,
|
||||
'translate.lua requires a Yandex translate API key from http://tech.yandex.com/keys/get.'
|
||||
)
|
||||
|
||||
translate.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('translate', true):t('tl', true).table
|
||||
translate.doc = config.cmd_pat .. [[translate [text]
|
||||
translate.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('translate', true):t('tl', true).table
|
||||
translate.doc = config.cmd_pat .. [[translate [text]
|
||||
Translates input or the replied-to message into the bot's language.]]
|
||||
translate.base_url = 'https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. config.yandex_key .. '&lang=' .. config.lang .. '&text=%s'
|
||||
translate.base_url = 'https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. config.yandex_key .. '&lang=' .. config.lang .. '&text=%s'
|
||||
end
|
||||
|
||||
function translate:action(msg, config)
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, translate.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, translate.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local url = translate.base_url:format(URL.escape(input))
|
||||
local jstr, code = HTTPS.request(url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local url = translate.base_url:format(URL.escape(input))
|
||||
local jstr, code = HTTPS.request(url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local data = JSON.decode(jstr)
|
||||
if data.code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(jstr)
|
||||
if data.code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
utilities.send_reply(self, msg.reply_to_message or msg, utilities.style.enquote('Translation', data.text[1]), true)
|
||||
utilities.send_reply(self, msg.reply_to_message or msg, utilities.style.enquote('Translation', data.text[1]), true)
|
||||
end
|
||||
|
||||
return translate
|
||||
|
@ -9,42 +9,42 @@ urbandictionary.command = 'urbandictionary <query>'
|
||||
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.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||
:t('urbandictionary', true):t('ud', true):t('urban', true).table
|
||||
urbandictionary.doc = [[
|
||||
/urbandictionary <query>
|
||||
Returns a definition from Urban Dictionary.
|
||||
Aliases: /ud, /urban
|
||||
]]
|
||||
urbandictionary.doc = urbandictionary.doc:gsub('/', config.cmd_pat)
|
||||
]]
|
||||
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(self, msg, urbandictionary.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, urbandictionary.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local url = urbandictionary.base_url .. URL.escape(input)
|
||||
local jstr, code = HTTP.request(url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local url = urbandictionary.base_url .. URL.escape(input)
|
||||
local jstr, code = HTTP.request(url)
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local data = JSON.decode(jstr)
|
||||
local output
|
||||
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('_', '_\\__')
|
||||
)
|
||||
end
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
local data = JSON.decode(jstr)
|
||||
local output
|
||||
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('_', '_\\__')
|
||||
)
|
||||
end
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
end
|
||||
|
||||
return urbandictionary
|
||||
|
@ -6,12 +6,12 @@ local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function weather:init(config)
|
||||
assert(config.owm_api_key,
|
||||
'weather.lua requires an OpenWeatherMap API key from http://openweathermap.org/API.'
|
||||
)
|
||||
assert(config.owm_api_key,
|
||||
'weather.lua requires an OpenWeatherMap API key from http://openweathermap.org/API.'
|
||||
)
|
||||
|
||||
weather.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('weather', true).table
|
||||
weather.doc = config.cmd_pat .. [[weather <location>
|
||||
weather.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('weather', true).table
|
||||
weather.doc = config.cmd_pat .. [[weather <location>
|
||||
Returns the current weather conditions for a given location.]]
|
||||
end
|
||||
|
||||
@ -19,37 +19,37 @@ weather.command = 'weather <location>'
|
||||
|
||||
function weather:action(msg, config)
|
||||
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, weather.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, weather.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local coords = utilities.get_coords(input, config)
|
||||
if type(coords) == 'string' then
|
||||
utilities.send_reply(self, msg, coords)
|
||||
return
|
||||
end
|
||||
local coords = utilities.get_coords(input, config)
|
||||
if type(coords) == 'string' then
|
||||
utilities.send_reply(self, msg, coords)
|
||||
return
|
||||
end
|
||||
|
||||
local url = 'http://api.openweathermap.org/data/2.5/weather?APPID=' .. config.owm_api_key .. '&lat=' .. coords.lat .. '&lon=' .. coords.lon
|
||||
local url = 'http://api.openweathermap.org/data/2.5/weather?APPID=' .. config.owm_api_key .. '&lat=' .. coords.lat .. '&lon=' .. coords.lon
|
||||
|
||||
local jstr, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local jstr, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.cod ~= 200 then
|
||||
utilities.send_reply(self, msg, 'Error: City not found.')
|
||||
return
|
||||
end
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.cod ~= 200 then
|
||||
utilities.send_reply(self, msg, 'Error: City not found.')
|
||||
return
|
||||
end
|
||||
|
||||
local celsius = string.format('%.2f', jdat.main.temp - 273.15)
|
||||
local fahrenheit = string.format('%.2f', celsius * (9/5) + 32)
|
||||
local output = '`' .. celsius .. '°C | ' .. fahrenheit .. '°F, ' .. jdat.weather[1].description .. '.`'
|
||||
local celsius = string.format('%.2f', jdat.main.temp - 273.15)
|
||||
local fahrenheit = string.format('%.2f', celsius * (9/5) + 32)
|
||||
local output = '`' .. celsius .. '°C | ' .. fahrenheit .. '°F, ' .. jdat.weather[1].description .. '.`'
|
||||
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -6,54 +6,54 @@ local bindings = require('otouto.bindings')
|
||||
whoami.command = 'whoami'
|
||||
|
||||
function whoami:init(config)
|
||||
whoami.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('who'):t('whoami').table
|
||||
whoami.doc = [[
|
||||
whoami.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('who'):t('whoami').table
|
||||
whoami.doc = [[
|
||||
Returns user and chat info for you or the replied-to message.
|
||||
Alias: ]] .. config.cmd_pat .. 'who'
|
||||
end
|
||||
|
||||
function whoami:action(msg)
|
||||
-- Operate on the replied-to message, if it exists.
|
||||
msg = msg.reply_to_message or msg
|
||||
-- If it's a private conversation, bot is chat, unless bot is from.
|
||||
local chat = msg.from.id == msg.chat.id and self.info or msg.chat
|
||||
-- Names for the user and group, respectively. HTML-escaped.
|
||||
local from_name = utilities.html_escape(
|
||||
utilities.build_name(
|
||||
msg.from.first_name,
|
||||
msg.from.last_name
|
||||
)
|
||||
)
|
||||
local chat_name = utilities.html_escape(
|
||||
chat.title
|
||||
or utilities.build_name(chat.first_name, chat.last_name)
|
||||
)
|
||||
-- "Normalize" a group ID so it's not arbitrarily modified by the bot API.
|
||||
local chat_id = math.abs(chat.id)
|
||||
if chat_id > 1000000000000 then chat_id = chat_id - 1000000000000 end
|
||||
-- Do the thing.
|
||||
local output = string.format(
|
||||
'You are %s <code>[%s]</code>, and you are messaging %s <code>[%s]</code>.',
|
||||
msg.from.username and string.format(
|
||||
'@%s, also known as <b>%s</b>',
|
||||
msg.from.username,
|
||||
from_name
|
||||
) or '<b>' .. from_name .. '</b>',
|
||||
msg.from.id,
|
||||
msg.chat.username and string.format(
|
||||
'@%s, also known as <b>%s</b>',
|
||||
chat.username,
|
||||
chat_name
|
||||
) or '<b>' .. chat_name .. '</b>',
|
||||
chat_id
|
||||
)
|
||||
bindings.sendMessage(self, {
|
||||
chat_id = msg.chat.id,
|
||||
reply_to_message_id = msg.message_id,
|
||||
disable_web_page_preview = true,
|
||||
parse_mode = 'HTML',
|
||||
text = output
|
||||
})
|
||||
-- Operate on the replied-to message, if it exists.
|
||||
msg = msg.reply_to_message or msg
|
||||
-- If it's a private conversation, bot is chat, unless bot is from.
|
||||
local chat = msg.from.id == msg.chat.id and self.info or msg.chat
|
||||
-- Names for the user and group, respectively. HTML-escaped.
|
||||
local from_name = utilities.html_escape(
|
||||
utilities.build_name(
|
||||
msg.from.first_name,
|
||||
msg.from.last_name
|
||||
)
|
||||
)
|
||||
local chat_name = utilities.html_escape(
|
||||
chat.title
|
||||
or utilities.build_name(chat.first_name, chat.last_name)
|
||||
)
|
||||
-- "Normalize" a group ID so it's not arbitrarily modified by the bot API.
|
||||
local chat_id = math.abs(chat.id)
|
||||
if chat_id > 1000000000000 then chat_id = chat_id - 1000000000000 end
|
||||
-- Do the thing.
|
||||
local output = string.format(
|
||||
'You are %s <code>[%s]</code>, and you are messaging %s <code>[%s]</code>.',
|
||||
msg.from.username and string.format(
|
||||
'@%s, also known as <b>%s</b>',
|
||||
msg.from.username,
|
||||
from_name
|
||||
) or '<b>' .. from_name .. '</b>',
|
||||
msg.from.id,
|
||||
msg.chat.username and string.format(
|
||||
'@%s, also known as <b>%s</b>',
|
||||
chat.username,
|
||||
chat_name
|
||||
) or '<b>' .. chat_name .. '</b>',
|
||||
chat_id
|
||||
)
|
||||
bindings.sendMessage(self, {
|
||||
chat_id = msg.chat.id,
|
||||
reply_to_message_id = msg.message_id,
|
||||
disable_web_page_preview = true,
|
||||
parse_mode = 'HTML',
|
||||
text = output
|
||||
})
|
||||
end
|
||||
|
||||
return whoami
|
||||
|
@ -8,83 +8,83 @@ local utilities = require('otouto.utilities')
|
||||
wikipedia.command = 'wikipedia <query>'
|
||||
|
||||
function wikipedia:init(config)
|
||||
wikipedia.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('wikipedia', true):t('wiki', true):t('w', true).table
|
||||
wikipedia.doc = config.cmd_pat .. [[wikipedia <query>
|
||||
wikipedia.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('wikipedia', true):t('wiki', true):t('w', true).table
|
||||
wikipedia.doc = config.cmd_pat .. [[wikipedia <query>
|
||||
Returns an article from Wikipedia.
|
||||
Aliases: ]] .. config.cmd_pat .. 'w, ' .. config.cmd_pat .. 'wiki'
|
||||
wikipedia.search_url = 'https://' .. config.lang .. '.wikipedia.org/w/api.php?action=query&list=search&format=json&srsearch='
|
||||
wikipedia.res_url = 'https://' .. config.lang .. '.wikipedia.org/w/api.php?action=query&prop=extracts&format=json&exchars=4000&exsectionformat=plain&titles='
|
||||
wikipedia.art_url = 'https://' .. config.lang .. '.wikipedia.org/wiki/'
|
||||
wikipedia.search_url = 'https://' .. config.lang .. '.wikipedia.org/w/api.php?action=query&list=search&format=json&srsearch='
|
||||
wikipedia.res_url = 'https://' .. config.lang .. '.wikipedia.org/w/api.php?action=query&prop=extracts&format=json&exchars=4000&exsectionformat=plain&titles='
|
||||
wikipedia.art_url = 'https://' .. config.lang .. '.wikipedia.org/wiki/'
|
||||
end
|
||||
|
||||
function wikipedia:action(msg, config)
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, wikipedia.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, wikipedia.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local jstr, code = HTTPS.request(wikipedia.search_url .. URL.escape(input))
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local jstr, code = HTTPS.request(wikipedia.search_url .. URL.escape(input))
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local data = JSON.decode(jstr)
|
||||
if data.query.searchinfo.totalhits == 0 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
local data = JSON.decode(jstr)
|
||||
if data.query.searchinfo.totalhits == 0 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
local title
|
||||
for _, v in ipairs(data.query.search) do
|
||||
if not v.snippet:match('may refer to:') then
|
||||
title = v.title
|
||||
break
|
||||
end
|
||||
end
|
||||
if not title then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
local title
|
||||
for _, v in ipairs(data.query.search) do
|
||||
if not v.snippet:match('may refer to:') then
|
||||
title = v.title
|
||||
break
|
||||
end
|
||||
end
|
||||
if not title then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
local res_jstr, res_code = HTTPS.request(wikipedia.res_url .. URL.escape(title))
|
||||
if res_code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local res_jstr, res_code = HTTPS.request(wikipedia.res_url .. URL.escape(title))
|
||||
if res_code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local _, text = next(JSON.decode(res_jstr).query.pages)
|
||||
if not text then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
local _, text = next(JSON.decode(res_jstr).query.pages)
|
||||
if not text then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
text = text.extract
|
||||
-- Remove crap and take only the first paragraph.
|
||||
text = text:gsub('</?.->', ''):gsub('%[.+%]', '')
|
||||
local l = text:find('\n')
|
||||
if l then
|
||||
text = text:sub(1, l-1)
|
||||
end
|
||||
local url = wikipedia.art_url .. URL.escape(title)
|
||||
title = utilities.html_escape(title)
|
||||
-- If the beginning of the article is the title, embolden that.
|
||||
-- Otherwise, we'll add a title in bold.
|
||||
local short_title = title:gsub('%(.+%)', '')
|
||||
local combined_text, count = text:gsub('^'..short_title, '<b>'..short_title..'</b>')
|
||||
local body
|
||||
if count == 1 then
|
||||
body = combined_text
|
||||
else
|
||||
body = '<b>' .. title .. '</b>\n' .. text
|
||||
end
|
||||
local output = string.format(
|
||||
'%s\n<a href="%s">Read more.</a>',
|
||||
body,
|
||||
utilities.html_escape(url)
|
||||
)
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||
text = text.extract
|
||||
-- Remove crap and take only the first paragraph.
|
||||
text = text:gsub('</?.->', ''):gsub('%[.+%]', '')
|
||||
local l = text:find('\n')
|
||||
if l then
|
||||
text = text:sub(1, l-1)
|
||||
end
|
||||
local url = wikipedia.art_url .. URL.escape(title)
|
||||
title = utilities.html_escape(title)
|
||||
-- If the beginning of the article is the title, embolden that.
|
||||
-- Otherwise, we'll add a title in bold.
|
||||
local short_title = title:gsub('%(.+%)', '')
|
||||
local combined_text, count = text:gsub('^'..short_title, '<b>'..short_title..'</b>')
|
||||
local body
|
||||
if count == 1 then
|
||||
body = combined_text
|
||||
else
|
||||
body = '<b>' .. title .. '</b>\n' .. text
|
||||
end
|
||||
local output = string.format(
|
||||
'%s\n<a href="%s">Read more.</a>',
|
||||
body,
|
||||
utilities.html_escape(url)
|
||||
)
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||
end
|
||||
|
||||
return wikipedia
|
||||
|
@ -9,44 +9,44 @@ xkcd.base_url = 'https://xkcd.com/info.0.json'
|
||||
xkcd.strip_url = 'http://xkcd.com/%s/info.0.json'
|
||||
|
||||
function xkcd:init(config)
|
||||
xkcd.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('xkcd', true).table
|
||||
xkcd.doc = config.cmd_pat .. [[xkcd [i]
|
||||
xkcd.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('xkcd', true).table
|
||||
xkcd.doc = config.cmd_pat .. [[xkcd [i]
|
||||
Returns the latest xkcd strip and its alt text. If a number is given, returns that number strip. If "r" is passed in place of a number, returns a random strip.]]
|
||||
local jstr = HTTP.request(xkcd.base_url)
|
||||
if jstr then
|
||||
local data = JSON.decode(jstr)
|
||||
if data then
|
||||
xkcd.latest = data.num
|
||||
end
|
||||
end
|
||||
xkcd.latest = xkcd.latest or 1700
|
||||
local jstr = HTTP.request(xkcd.base_url)
|
||||
if jstr then
|
||||
local data = JSON.decode(jstr)
|
||||
if data then
|
||||
xkcd.latest = data.num
|
||||
end
|
||||
end
|
||||
xkcd.latest = xkcd.latest or 1700
|
||||
end
|
||||
|
||||
function xkcd:action(msg, config)
|
||||
local input = utilities.get_word(msg.text, 2)
|
||||
if input == 'r' then
|
||||
input = math.random(xkcd.latest)
|
||||
elseif tonumber(input) then
|
||||
input = tonumber(input)
|
||||
else
|
||||
input = xkcd.latest
|
||||
end
|
||||
local url = xkcd.strip_url:format(input)
|
||||
local jstr, code = HTTP.request(url)
|
||||
if code == 404 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
elseif code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
else
|
||||
local data = JSON.decode(jstr)
|
||||
local output = string.format('*%s (*[%s](%s)*)*\n_%s_',
|
||||
data.safe_title:gsub('*', '*\\**'),
|
||||
data.num,
|
||||
data.img,
|
||||
data.alt:gsub('_', '_\\__')
|
||||
)
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
||||
end
|
||||
local input = utilities.get_word(msg.text, 2)
|
||||
if input == 'r' then
|
||||
input = math.random(xkcd.latest)
|
||||
elseif tonumber(input) then
|
||||
input = tonumber(input)
|
||||
else
|
||||
input = xkcd.latest
|
||||
end
|
||||
local url = xkcd.strip_url:format(input)
|
||||
local jstr, code = HTTP.request(url)
|
||||
if code == 404 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
elseif code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
else
|
||||
local data = JSON.decode(jstr)
|
||||
local output = string.format('*%s (*[%s](%s)*)*\n_%s_',
|
||||
data.safe_title:gsub('*', '*\\**'),
|
||||
data.num,
|
||||
data.img,
|
||||
data.alt:gsub('_', '_\\__')
|
||||
)
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
||||
end
|
||||
end
|
||||
|
||||
return xkcd
|
||||
|
@ -8,12 +8,12 @@ local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
|
||||
function youtube:init(config)
|
||||
assert(config.google_api_key,
|
||||
'youtube.lua requires a Google API key from http://console.developers.google.com.'
|
||||
)
|
||||
assert(config.google_api_key,
|
||||
'youtube.lua requires a Google API key from http://console.developers.google.com.'
|
||||
)
|
||||
|
||||
youtube.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('youtube', true):t('yt', true).table
|
||||
youtube.doc = config.cmd_pat .. [[youtube <query>
|
||||
youtube.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('youtube', true):t('yt', true).table
|
||||
youtube.doc = config.cmd_pat .. [[youtube <query>
|
||||
Returns the top result from YouTube.
|
||||
Alias: ]] .. config.cmd_pat .. 'yt'
|
||||
end
|
||||
@ -22,32 +22,32 @@ youtube.command = 'youtube <query>'
|
||||
|
||||
function youtube:action(msg, config)
|
||||
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, youtube.doc, true)
|
||||
return
|
||||
end
|
||||
local input = utilities.input_from_msg(msg)
|
||||
if not input then
|
||||
utilities.send_reply(self, msg, youtube.doc, true)
|
||||
return
|
||||
end
|
||||
|
||||
local url = 'https://www.googleapis.com/youtube/v3/search?key=' .. config.google_api_key .. '&type=video&part=snippet&maxResults=4&q=' .. URL.escape(input)
|
||||
local url = 'https://www.googleapis.com/youtube/v3/search?key=' .. config.google_api_key .. '&type=video&part=snippet&maxResults=4&q=' .. URL.escape(input)
|
||||
|
||||
local jstr, res = HTTPS.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
local jstr, res = HTTPS.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.pageInfo.totalResults == 0 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.pageInfo.totalResults == 0 then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
local vid_url = 'https://www.youtube.com/watch?v=' .. jdat.items[1].id.videoId
|
||||
local vid_title = jdat.items[1].snippet.title
|
||||
vid_title = vid_title:gsub('%(.+%)',''):gsub('%[.+%]','')
|
||||
local output = '[' .. vid_title .. '](' .. vid_url .. ')'
|
||||
local vid_url = 'https://www.youtube.com/watch?v=' .. jdat.items[1].id.videoId
|
||||
local vid_title = jdat.items[1].snippet.title
|
||||
vid_title = vid_title:gsub('%(.+%)',''):gsub('%[.+%]','')
|
||||
local output = '[' .. vid_title .. '](' .. vid_url .. ')'
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
||||
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
||||
|
||||
end
|
||||
|
||||
|
@ -15,47 +15,47 @@ local bindings = require('otouto.bindings')
|
||||
-- Edit: To keep things working and allow for HTML messages, you can now pass a
|
||||
-- string for use_markdown and that will be sent as the parse mode.
|
||||
function utilities:send_message(chat_id, text, disable_web_page_preview, reply_to_message_id, use_markdown)
|
||||
local parse_mode
|
||||
if type(use_markdown) == 'string' then
|
||||
parse_mode = use_markdown
|
||||
elseif use_markdown == true then
|
||||
parse_mode = 'markdown'
|
||||
end
|
||||
return bindings.request(self, 'sendMessage', {
|
||||
chat_id = chat_id,
|
||||
text = text,
|
||||
disable_web_page_preview = disable_web_page_preview,
|
||||
reply_to_message_id = reply_to_message_id,
|
||||
parse_mode = parse_mode
|
||||
} )
|
||||
local parse_mode
|
||||
if type(use_markdown) == 'string' then
|
||||
parse_mode = use_markdown
|
||||
elseif use_markdown == true then
|
||||
parse_mode = 'markdown'
|
||||
end
|
||||
return bindings.request(self, 'sendMessage', {
|
||||
chat_id = chat_id,
|
||||
text = text,
|
||||
disable_web_page_preview = disable_web_page_preview,
|
||||
reply_to_message_id = reply_to_message_id,
|
||||
parse_mode = parse_mode
|
||||
} )
|
||||
end
|
||||
|
||||
function utilities:send_reply(old_msg, text, use_markdown)
|
||||
return utilities.send_message(self, old_msg.chat.id, text, true, old_msg.message_id, use_markdown)
|
||||
return utilities.send_message(self, old_msg.chat.id, text, true, old_msg.message_id, use_markdown)
|
||||
end
|
||||
|
||||
-- get the indexed word in a string
|
||||
function utilities.get_word(s, i)
|
||||
s = s or ''
|
||||
i = i or 1
|
||||
local n = 0
|
||||
for w in s:gmatch('%g+') do
|
||||
n = n + 1
|
||||
if n == i then return w end
|
||||
end
|
||||
return false
|
||||
s = s or ''
|
||||
i = i or 1
|
||||
local n = 0
|
||||
for w in s:gmatch('%g+') do
|
||||
n = n + 1
|
||||
if n == i then return w end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Returns the string after the first space.
|
||||
function utilities.input(s)
|
||||
if not s:find(' ') then
|
||||
return false
|
||||
end
|
||||
return s:sub(s:find(' ')+1)
|
||||
if not s:find(' ') then
|
||||
return false
|
||||
end
|
||||
return s:sub(s:find(' ')+1)
|
||||
end
|
||||
|
||||
function utilities.input_from_msg(msg)
|
||||
return utilities.input(msg.text) or (msg.reply_to_message and #msg.reply_to_message.text > 0 and msg.reply_to_message.text) or false
|
||||
return utilities.input(msg.text) or (msg.reply_to_message and #msg.reply_to_message.text > 0 and msg.reply_to_message.text) or false
|
||||
end
|
||||
|
||||
-- Calculates the length of the given string as UTF-8 characters
|
||||
@ -72,180 +72,180 @@ end
|
||||
|
||||
-- Trims whitespace from a string.
|
||||
function utilities.trim(str)
|
||||
local s = str:gsub('^%s*(.-)%s*$', '%1')
|
||||
return s
|
||||
local s = str:gsub('^%s*(.-)%s*$', '%1')
|
||||
return s
|
||||
end
|
||||
|
||||
-- Loads a JSON file as a table.
|
||||
function utilities.load_data(filename)
|
||||
local f = io.open(filename)
|
||||
if f then
|
||||
local s = f:read('*all')
|
||||
f:close()
|
||||
return JSON.decode(s)
|
||||
else
|
||||
return {}
|
||||
end
|
||||
local f = io.open(filename)
|
||||
if f then
|
||||
local s = f:read('*all')
|
||||
f:close()
|
||||
return JSON.decode(s)
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
-- Saves a table to a JSON file.
|
||||
function utilities.save_data(filename, data)
|
||||
local s = JSON.encode(data)
|
||||
local f = io.open(filename, 'w')
|
||||
f:write(s)
|
||||
f:close()
|
||||
local s = JSON.encode(data)
|
||||
local f = io.open(filename, 'w')
|
||||
f:write(s)
|
||||
f:close()
|
||||
end
|
||||
|
||||
-- Gets coordinates for a location. Used by gMaps.lua, time.lua, weather.lua.
|
||||
function utilities.get_coords(input, config)
|
||||
|
||||
local url = 'http://maps.googleapis.com/maps/api/geocode/json?address=' .. URL.escape(input)
|
||||
local url = 'http://maps.googleapis.com/maps/api/geocode/json?address=' .. URL.escape(input)
|
||||
|
||||
local jstr, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
return config.errors.connection
|
||||
end
|
||||
local jstr, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
return config.errors.connection
|
||||
end
|
||||
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.status == 'ZERO_RESULTS' then
|
||||
return config.errors.results
|
||||
end
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.status == 'ZERO_RESULTS' then
|
||||
return config.errors.results
|
||||
end
|
||||
|
||||
return {
|
||||
lat = jdat.results[1].geometry.location.lat,
|
||||
lon = jdat.results[1].geometry.location.lng
|
||||
}
|
||||
return {
|
||||
lat = jdat.results[1].geometry.location.lat,
|
||||
lon = jdat.results[1].geometry.location.lng
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
-- Get the number of values in a key/value table.
|
||||
function utilities.table_size(tab)
|
||||
local i = 0
|
||||
for _,_ in pairs(tab) do
|
||||
i = i + 1
|
||||
end
|
||||
return i
|
||||
local i = 0
|
||||
for _,_ in pairs(tab) do
|
||||
i = i + 1
|
||||
end
|
||||
return i
|
||||
end
|
||||
|
||||
-- Just an easy way to get a user's full name.
|
||||
-- Alternatively, abuse it to concat two strings like I do.
|
||||
function utilities.build_name(first, last)
|
||||
if last then
|
||||
return first .. ' ' .. last
|
||||
else
|
||||
return first
|
||||
end
|
||||
if last then
|
||||
return first .. ' ' .. last
|
||||
else
|
||||
return first
|
||||
end
|
||||
end
|
||||
|
||||
function utilities:resolve_username(input)
|
||||
input = input:gsub('^@', '')
|
||||
for _, user in pairs(self.database.users) do
|
||||
if user.username and user.username:lower() == input:lower() then
|
||||
local t = {}
|
||||
for key, val in pairs(user) do
|
||||
t[key] = val
|
||||
end
|
||||
return t
|
||||
end
|
||||
end
|
||||
input = input:gsub('^@', '')
|
||||
for _, user in pairs(self.database.users) do
|
||||
if user.username and user.username:lower() == input:lower() then
|
||||
local t = {}
|
||||
for key, val in pairs(user) do
|
||||
t[key] = val
|
||||
end
|
||||
return t
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function utilities:handle_exception(err, message, config)
|
||||
local output = string.format(
|
||||
'\n[%s]\n%s: %s\n%s\n',
|
||||
os.date('%F %T'),
|
||||
self.info.username,
|
||||
err or '',
|
||||
message
|
||||
)
|
||||
if config.log_chat then
|
||||
output = '```' .. output .. '```'
|
||||
utilities.send_message(self, config.log_chat, output, true, nil, true)
|
||||
else
|
||||
print(output)
|
||||
end
|
||||
local output = string.format(
|
||||
'\n[%s]\n%s: %s\n%s\n',
|
||||
os.date('%F %T'),
|
||||
self.info.username,
|
||||
err or '',
|
||||
message
|
||||
)
|
||||
if config.log_chat then
|
||||
output = '```' .. output .. '```'
|
||||
utilities.send_message(self, config.log_chat, output, true, nil, true)
|
||||
else
|
||||
print(output)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function utilities.download_file(url, filename)
|
||||
if not filename then
|
||||
filename = url:match('.+/(.-)$') or os.time()
|
||||
filename = '/tmp/' .. filename
|
||||
end
|
||||
local body = {}
|
||||
local doer = HTTP
|
||||
local do_redir = true
|
||||
if url:match('^https') then
|
||||
doer = HTTPS
|
||||
do_redir = false
|
||||
end
|
||||
local _, res = doer.request{
|
||||
url = url,
|
||||
sink = ltn12.sink.table(body),
|
||||
redirect = do_redir
|
||||
}
|
||||
if res ~= 200 then return false end
|
||||
local file = io.open(filename, 'w+')
|
||||
file:write(table.concat(body))
|
||||
file:close()
|
||||
return filename
|
||||
if not filename then
|
||||
filename = url:match('.+/(.-)$') or os.time()
|
||||
filename = '/tmp/' .. filename
|
||||
end
|
||||
local body = {}
|
||||
local doer = HTTP
|
||||
local do_redir = true
|
||||
if url:match('^https') then
|
||||
doer = HTTPS
|
||||
do_redir = false
|
||||
end
|
||||
local _, res = doer.request{
|
||||
url = url,
|
||||
sink = ltn12.sink.table(body),
|
||||
redirect = do_redir
|
||||
}
|
||||
if res ~= 200 then return false end
|
||||
local file = io.open(filename, 'w+')
|
||||
file:write(table.concat(body))
|
||||
file:close()
|
||||
return filename
|
||||
end
|
||||
|
||||
function utilities.md_escape(text)
|
||||
return text:gsub('_', '\\_')
|
||||
:gsub('%[', '\\['):gsub('%]', '\\]')
|
||||
:gsub('%*', '\\*'):gsub('`', '\\`')
|
||||
return text:gsub('_', '\\_')
|
||||
:gsub('%[', '\\['):gsub('%]', '\\]')
|
||||
:gsub('%*', '\\*'):gsub('`', '\\`')
|
||||
end
|
||||
|
||||
function utilities.html_escape(text)
|
||||
return text:gsub('&', '&'):gsub('<', '<'):gsub('>', '>')
|
||||
return text:gsub('&', '&'):gsub('<', '<'):gsub('>', '>')
|
||||
end
|
||||
|
||||
utilities.triggers_meta = {}
|
||||
utilities.triggers_meta.__index = utilities.triggers_meta
|
||||
function utilities.triggers_meta:t(pattern, has_args)
|
||||
local username = self.username:lower()
|
||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'$')
|
||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'@'..username..'$')
|
||||
if has_args then
|
||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'%s+[^%s]*')
|
||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'@'..username..'%s+[^%s]*')
|
||||
end
|
||||
return self
|
||||
local username = self.username:lower()
|
||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'$')
|
||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'@'..username..'$')
|
||||
if has_args then
|
||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'%s+[^%s]*')
|
||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'@'..username..'%s+[^%s]*')
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function utilities.triggers(username, cmd_pat, trigger_table)
|
||||
local self = setmetatable({}, utilities.triggers_meta)
|
||||
self.username = username
|
||||
self.cmd_pat = cmd_pat
|
||||
self.table = trigger_table or {}
|
||||
return self
|
||||
local self = setmetatable({}, utilities.triggers_meta)
|
||||
self.username = username
|
||||
self.cmd_pat = cmd_pat
|
||||
self.table = trigger_table or {}
|
||||
return self
|
||||
end
|
||||
|
||||
function utilities.with_http_timeout(timeout, fun)
|
||||
local original = HTTP.TIMEOUT
|
||||
HTTP.TIMEOUT = timeout
|
||||
fun()
|
||||
HTTP.TIMEOUT = original
|
||||
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))
|
||||
else
|
||||
return tostring(x)
|
||||
end
|
||||
if x % 1 == 0 then
|
||||
return tostring(math.floor(x))
|
||||
else
|
||||
return tostring(x)
|
||||
end
|
||||
end
|
||||
|
||||
-- This table will store unsavory characters that are not properly displayed,
|
||||
-- or are just not fun to type.
|
||||
utilities.char = {
|
||||
zwnj = '',
|
||||
arabic = '[\216-\219][\128-\191]',
|
||||
rtl_override = '',
|
||||
rtl_mark = '',
|
||||
em_dash = '—',
|
||||
utf_8 = '[%z\1-\127\194-\244][\128-\191]',
|
||||
zwnj = '',
|
||||
arabic = '[\216-\219][\128-\191]',
|
||||
rtl_override = '',
|
||||
rtl_mark = '',
|
||||
em_dash = '—',
|
||||
utf_8 = '[%z\1-\127\194-\244][\128-\191]',
|
||||
}
|
||||
|
||||
utilities.set_meta = {}
|
||||
@ -283,7 +283,7 @@ end
|
||||
-- More to be added.
|
||||
utilities.style = {}
|
||||
utilities.style.enquote = function(title, body)
|
||||
return '*' .. title:gsub('*', '\\*') .. ':*\n"' .. utilities.md_escape(body) .. '"'
|
||||
return '*' .. title:gsub('*', '\\*') .. ':*\n"' .. utilities.md_escape(body) .. '"'
|
||||
end
|
||||
|
||||
return utilities
|
||||
|
@ -4,8 +4,8 @@
|
||||
# config.lua), delete state file after stop, wait five seconds, and restart.
|
||||
|
||||
while true; do
|
||||
tg/bin/telegram-cli -P 4567 -E
|
||||
[ -f ~/.telegram-cli/state ] && rm ~/.telegram-cli/state
|
||||
echo 'tg has stopped. ^C to exit.'
|
||||
sleep 5s
|
||||
tg/bin/telegram-cli -P 4567 -E
|
||||
[ -f ~/.telegram-cli/state ] && rm ~/.telegram-cli/state
|
||||
echo 'tg has stopped. ^C to exit.'
|
||||
sleep 5s
|
||||
done
|
||||
|
Reference in New Issue
Block a user