tab -> 4 spaces
This commit is contained in:
parent
6fbd718af0
commit
148d4b0dc5
@ -6,4 +6,5 @@ insert_final_newline = true
|
|||||||
|
|
||||||
[*.lua]
|
[*.lua]
|
||||||
charset = utf-8
|
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(
|
bindings.request(
|
||||||
self,
|
self,
|
||||||
'sendMessage',
|
'sendMessage',
|
||||||
{
|
{
|
||||||
chat_id = 987654321,
|
chat_id = 987654321,
|
||||||
text = 'Quick brown fox.',
|
text = 'Quick brown fox.',
|
||||||
reply_to_message_id = 54321,
|
reply_to_message_id = 54321,
|
||||||
disable_web_page_preview = false,
|
disable_web_page_preview = false,
|
||||||
parse_method = 'Markdown'
|
parse_method = 'Markdown'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
bindings.sendMessage(
|
bindings.sendMessage(
|
||||||
self,
|
self,
|
||||||
{
|
{
|
||||||
chat_id = 987654321,
|
chat_id = 987654321,
|
||||||
text = 'Quick brown fox.',
|
text = 'Quick brown fox.',
|
||||||
reply_to_message_id = 54321,
|
reply_to_message_id = 54321,
|
||||||
disable_web_page_preview = false,
|
disable_web_page_preview = false,
|
||||||
parse_method = 'Markdown'
|
parse_method = 'Markdown'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -342,20 +342,20 @@ Alone, the database will have this structure:
|
|||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
users = {
|
users = {
|
||||||
["55994550"] = {
|
["55994550"] = {
|
||||||
id = 55994550,
|
id = 55994550,
|
||||||
first_name = "Drew",
|
first_name = "Drew",
|
||||||
username = "topkecleon"
|
username = "topkecleon"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
userdata = {
|
userdata = {
|
||||||
["55994550"] = {
|
["55994550"] = {
|
||||||
nickname = "Worst coder ever",
|
nickname = "Worst coder ever",
|
||||||
lastfm = "topkecleon"
|
lastfm = "topkecleon"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
version = "3.11"
|
version = "3.11"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
286
config.lua
286
config.lua
@ -1,159 +1,159 @@
|
|||||||
-- For details on configuration values, see README.md#configuration.
|
-- For details on configuration values, see README.md#configuration.
|
||||||
return {
|
return {
|
||||||
|
|
||||||
-- Your authorization token from the botfather.
|
-- Your authorization token from the botfather.
|
||||||
bot_api_key = nil,
|
bot_api_key = nil,
|
||||||
-- Your Telegram ID.
|
-- Your Telegram ID.
|
||||||
admin = nil,
|
admin = nil,
|
||||||
-- Two-letter language code.
|
-- Two-letter language code.
|
||||||
lang = 'en',
|
lang = 'en',
|
||||||
-- The channel, group, or user to send error reports to.
|
-- The channel, group, or user to send error reports to.
|
||||||
-- If this is not set, errors will be printed to the console.
|
-- If this is not set, errors will be printed to the console.
|
||||||
log_chat = nil,
|
log_chat = nil,
|
||||||
-- The port used to communicate with tg for administration.lua.
|
-- The port used to communicate with tg for administration.lua.
|
||||||
-- If you change this, make sure you also modify launch-tg.sh.
|
-- If you change this, make sure you also modify launch-tg.sh.
|
||||||
cli_port = 4567,
|
cli_port = 4567,
|
||||||
-- The symbol that starts a command. Usually noted as '/' in documentation.
|
-- The symbol that starts a command. Usually noted as '/' in documentation.
|
||||||
cmd_pat = '/',
|
cmd_pat = '/',
|
||||||
-- If drua is used, should a user be blocked when he's blacklisted?
|
-- If drua is used, should a user be blocked when he's blacklisted?
|
||||||
drua_block_on_blacklist = false,
|
drua_block_on_blacklist = false,
|
||||||
-- The filename of the database. If left nil, defaults to $username.db.
|
-- The filename of the database. If left nil, defaults to $username.db.
|
||||||
database_name = nil,
|
database_name = nil,
|
||||||
-- The block of text returned by /start and /about..
|
-- The block of text returned by /start and /about..
|
||||||
about_text = [[
|
about_text = [[
|
||||||
I am otouto, the plugin-wielding, multipurpose Telegram bot.
|
I am otouto, the plugin-wielding, multipurpose Telegram bot.
|
||||||
|
|
||||||
Send /help to get started.
|
Send /help to get started.
|
||||||
]],
|
]],
|
||||||
|
|
||||||
errors = { -- Generic error messages.
|
errors = { -- Generic error messages.
|
||||||
generic = 'An unexpected error occurred.',
|
generic = 'An unexpected error occurred.',
|
||||||
connection = 'Connection error.',
|
connection = 'Connection error.',
|
||||||
results = 'No results found.',
|
results = 'No results found.',
|
||||||
argument = 'Invalid argument.',
|
argument = 'Invalid argument.',
|
||||||
syntax = 'Invalid syntax.'
|
syntax = 'Invalid syntax.'
|
||||||
},
|
},
|
||||||
|
|
||||||
-- https://datamarket.azure.com/dataset/bing/search
|
-- https://datamarket.azure.com/dataset/bing/search
|
||||||
bing_api_key = nil,
|
bing_api_key = nil,
|
||||||
-- http://console.developers.google.com
|
-- http://console.developers.google.com
|
||||||
google_api_key = nil,
|
google_api_key = nil,
|
||||||
-- https://cse.google.com/cse
|
-- https://cse.google.com/cse
|
||||||
google_cse_key = nil,
|
google_cse_key = nil,
|
||||||
-- http://openweathermap.org/appid
|
-- http://openweathermap.org/appid
|
||||||
owm_api_key = nil,
|
owm_api_key = nil,
|
||||||
-- http://last.fm/api
|
-- http://last.fm/api
|
||||||
lastfm_api_key = nil,
|
lastfm_api_key = nil,
|
||||||
-- http://api.biblia.com
|
-- http://api.biblia.com
|
||||||
biblia_api_key = nil,
|
biblia_api_key = nil,
|
||||||
-- http://thecatapi.com/docs.html
|
-- http://thecatapi.com/docs.html
|
||||||
thecatapi_key = nil,
|
thecatapi_key = nil,
|
||||||
-- http://api.nasa.gov
|
-- http://api.nasa.gov
|
||||||
nasa_api_key = nil,
|
nasa_api_key = nil,
|
||||||
-- http://tech.yandex.com/keys/get
|
-- http://tech.yandex.com/keys/get
|
||||||
yandex_key = nil,
|
yandex_key = nil,
|
||||||
-- Interval (in minutes) for hackernews.lua to update.
|
-- Interval (in minutes) for hackernews.lua to update.
|
||||||
hackernews_interval = 60,
|
hackernews_interval = 60,
|
||||||
-- Whether hackernews.lua should update at load/reload.
|
-- Whether hackernews.lua should update at load/reload.
|
||||||
hackernews_onstart = false,
|
hackernews_onstart = false,
|
||||||
-- Whether luarun should use serpent instead of dkjson for serialization.
|
-- Whether luarun should use serpent instead of dkjson for serialization.
|
||||||
luarun_serpent = false,
|
luarun_serpent = false,
|
||||||
|
|
||||||
remind = {
|
remind = {
|
||||||
persist = true,
|
persist = true,
|
||||||
max_length = 1000,
|
max_length = 1000,
|
||||||
max_duration = 526000,
|
max_duration = 526000,
|
||||||
max_reminders_group = 10,
|
max_reminders_group = 10,
|
||||||
max_reminders_private = 50
|
max_reminders_private = 50
|
||||||
},
|
},
|
||||||
|
|
||||||
chatter = {
|
chatter = {
|
||||||
cleverbot_api = 'https://brawlbot.tk/apis/chatter-bot-api/cleverbot.php?text=',
|
cleverbot_api = 'https://brawlbot.tk/apis/chatter-bot-api/cleverbot.php?text=',
|
||||||
connection = 'I don\'t feel like talking right now.',
|
connection = 'I don\'t feel like talking right now.',
|
||||||
response = 'I don\'t know what to say to that.'
|
response = 'I don\'t know what to say to that.'
|
||||||
},
|
},
|
||||||
|
|
||||||
greetings = {
|
greetings = {
|
||||||
["Hello, #NAME."] = {
|
["Hello, #NAME."] = {
|
||||||
"hello",
|
"hello",
|
||||||
"hey",
|
"hey",
|
||||||
"hi",
|
"hi",
|
||||||
"good morning",
|
"good morning",
|
||||||
"good day",
|
"good day",
|
||||||
"good afternoon",
|
"good afternoon",
|
||||||
"good evening"
|
"good evening"
|
||||||
},
|
},
|
||||||
["Goodbye, #NAME."] = {
|
["Goodbye, #NAME."] = {
|
||||||
"good%-?bye",
|
"good%-?bye",
|
||||||
"bye",
|
"bye",
|
||||||
"later",
|
"later",
|
||||||
"see ya",
|
"see ya",
|
||||||
"good night"
|
"good night"
|
||||||
},
|
},
|
||||||
["Welcome back, #NAME."] = {
|
["Welcome back, #NAME."] = {
|
||||||
"i'm home",
|
"i'm home",
|
||||||
"i'm back"
|
"i'm back"
|
||||||
},
|
},
|
||||||
["You're welcome, #NAME."] = {
|
["You're welcome, #NAME."] = {
|
||||||
"thanks",
|
"thanks",
|
||||||
"thank you"
|
"thank you"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
reactions = {
|
reactions = {
|
||||||
['shrug'] = '¯\\_(ツ)_/¯',
|
['shrug'] = '¯\\_(ツ)_/¯',
|
||||||
['lenny'] = '( ͡° ͜ʖ ͡°)',
|
['lenny'] = '( ͡° ͜ʖ ͡°)',
|
||||||
['flip'] = '(╯°□°)╯︵ ┻━┻',
|
['flip'] = '(╯°□°)╯︵ ┻━┻',
|
||||||
['look'] = 'ಠ_ಠ',
|
['look'] = 'ಠ_ಠ',
|
||||||
['shots'] = 'SHOTS FIRED',
|
['shots'] = 'SHOTS FIRED',
|
||||||
['facepalm'] = '(-‸ლ)'
|
['facepalm'] = '(-‸ლ)'
|
||||||
},
|
},
|
||||||
|
|
||||||
administration = {
|
administration = {
|
||||||
-- Whether moderators can set a group's message of the day.
|
-- Whether moderators can set a group's message of the day.
|
||||||
moderator_setmotd = false,
|
moderator_setmotd = false,
|
||||||
-- Default antiflood values.
|
-- Default antiflood values.
|
||||||
antiflood = {
|
antiflood = {
|
||||||
text = 5,
|
text = 5,
|
||||||
voice = 5,
|
voice = 5,
|
||||||
audio = 5,
|
audio = 5,
|
||||||
contact = 5,
|
contact = 5,
|
||||||
photo = 10,
|
photo = 10,
|
||||||
video = 10,
|
video = 10,
|
||||||
location = 10,
|
location = 10,
|
||||||
document = 10,
|
document = 10,
|
||||||
sticker = 20
|
sticker = 20
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
plugins = { -- To enable a plugin, add its name to the list.
|
plugins = { -- To enable a plugin, add its name to the list.
|
||||||
'about',
|
'about',
|
||||||
'blacklist',
|
'blacklist',
|
||||||
'calc',
|
'calc',
|
||||||
'cats',
|
'cats',
|
||||||
'commit',
|
'commit',
|
||||||
'control',
|
'control',
|
||||||
'currency',
|
'currency',
|
||||||
'dice',
|
'dice',
|
||||||
'echo',
|
'echo',
|
||||||
'eightball',
|
'eightball',
|
||||||
'gMaps',
|
'gMaps',
|
||||||
'hackernews',
|
'hackernews',
|
||||||
'imdb',
|
'imdb',
|
||||||
'nick',
|
'nick',
|
||||||
'ping',
|
'ping',
|
||||||
'pun',
|
'pun',
|
||||||
'reddit',
|
'reddit',
|
||||||
'shout',
|
'shout',
|
||||||
'slap',
|
'slap',
|
||||||
'time',
|
'time',
|
||||||
'urbandictionary',
|
'urbandictionary',
|
||||||
'whoami',
|
'whoami',
|
||||||
'wikipedia',
|
'wikipedia',
|
||||||
'xkcd',
|
'xkcd',
|
||||||
-- Put new plugins above this line.
|
-- Put new plugins above this line.
|
||||||
'help',
|
'help',
|
||||||
'greetings'
|
'greetings'
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
lua main.lua
|
lua main.lua
|
||||||
echo 'otouto has stopped. ^C to exit.'
|
echo 'otouto has stopped. ^C to exit.'
|
||||||
sleep 5s
|
sleep 5s
|
||||||
done
|
done
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
--[[
|
--[[
|
||||||
bindings.lua (rev. 2016/05/28)
|
bindings.lua (rev. 2016/05/28)
|
||||||
otouto's bindings for the Telegram bot API.
|
otouto's bindings for the Telegram bot API.
|
||||||
https://core.telegram.org/bots/api
|
https://core.telegram.org/bots/api
|
||||||
Copyright 2016 topkecleon. Published under the AGPLv3.
|
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 = {}
|
local bindings = {}
|
||||||
@ -22,56 +22,56 @@ local MP_ENCODE = require('multipart-post').encode
|
|||||||
-- response with failure. Returns false and false with a connection error.
|
-- response with failure. Returns false and false with a connection error.
|
||||||
-- To mimic old/normal behavior, it errs if used with an invalid method.
|
-- To mimic old/normal behavior, it errs if used with an invalid method.
|
||||||
function bindings:request(method, parameters, file)
|
function bindings:request(method, parameters, file)
|
||||||
parameters = parameters or {}
|
parameters = parameters or {}
|
||||||
for k,v in pairs(parameters) do
|
for k,v in pairs(parameters) do
|
||||||
parameters[k] = tostring(v)
|
parameters[k] = tostring(v)
|
||||||
end
|
end
|
||||||
if file and next(file) ~= nil then
|
if file and next(file) ~= nil then
|
||||||
local file_type, file_name = next(file)
|
local file_type, file_name = next(file)
|
||||||
local file_file = io.open(file_name, 'r')
|
local file_file = io.open(file_name, 'r')
|
||||||
local file_data = {
|
local file_data = {
|
||||||
filename = file_name,
|
filename = file_name,
|
||||||
data = file_file:read('*a')
|
data = file_file:read('*a')
|
||||||
}
|
}
|
||||||
file_file:close()
|
file_file:close()
|
||||||
parameters[file_type] = file_data
|
parameters[file_type] = file_data
|
||||||
end
|
end
|
||||||
if next(parameters) == nil then
|
if next(parameters) == nil then
|
||||||
parameters = {''}
|
parameters = {''}
|
||||||
end
|
end
|
||||||
local response = {}
|
local response = {}
|
||||||
local body, boundary = MP_ENCODE(parameters)
|
local body, boundary = MP_ENCODE(parameters)
|
||||||
local success, code = HTTPS.request{
|
local success, code = HTTPS.request{
|
||||||
url = self.BASE_URL .. method,
|
url = self.BASE_URL .. method,
|
||||||
method = 'POST',
|
method = 'POST',
|
||||||
headers = {
|
headers = {
|
||||||
["Content-Type"] = "multipart/form-data; boundary=" .. boundary,
|
["Content-Type"] = "multipart/form-data; boundary=" .. boundary,
|
||||||
["Content-Length"] = #body,
|
["Content-Length"] = #body,
|
||||||
},
|
},
|
||||||
source = ltn12.source.string(body),
|
source = ltn12.source.string(body),
|
||||||
sink = ltn12.sink.table(response)
|
sink = ltn12.sink.table(response)
|
||||||
}
|
}
|
||||||
local data = table.concat(response)
|
local data = table.concat(response)
|
||||||
if not success or success == 1 then
|
if not success or success == 1 then
|
||||||
print(method .. ': Connection error. [' .. code .. ']')
|
print(method .. ': Connection error. [' .. code .. ']')
|
||||||
return false, false
|
return false, false
|
||||||
else
|
else
|
||||||
local result = JSON.decode(data)
|
local result = JSON.decode(data)
|
||||||
if not result then
|
if not result then
|
||||||
return false, false
|
return false, false
|
||||||
elseif result.ok then
|
elseif result.ok then
|
||||||
return result
|
return result
|
||||||
else
|
else
|
||||||
assert(result.description ~= 'Method not found', method .. ': Method not found.')
|
assert(result.description ~= 'Method not found', method .. ': Method not found.')
|
||||||
return false, result
|
return false, result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function bindings.gen(_, key)
|
function bindings.gen(_, key)
|
||||||
return function(self, params, file)
|
return function(self, params, file)
|
||||||
return bindings.request(self, key, params, file)
|
return bindings.request(self, key, params, file)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
setmetatable(bindings, { __index = bindings.gen })
|
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 to be run on start and reload.
|
||||||
function bot:init(config)
|
function bot:init(config)
|
||||||
|
|
||||||
bindings = require('otouto.bindings')
|
bindings = require('otouto.bindings')
|
||||||
utilities = require('otouto.utilities')
|
utilities = require('otouto.utilities')
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
config.bot_api_key,
|
config.bot_api_key,
|
||||||
'You did not set your bot token in the config!'
|
'You did not set your bot token in the config!'
|
||||||
)
|
)
|
||||||
self.BASE_URL = 'https://api.telegram.org/bot' .. config.bot_api_key .. '/'
|
self.BASE_URL = 'https://api.telegram.org/bot' .. config.bot_api_key .. '/'
|
||||||
|
|
||||||
-- Fetch bot information. Try until it succeeds.
|
-- Fetch bot information. Try until it succeeds.
|
||||||
repeat
|
repeat
|
||||||
print('Fetching bot information...')
|
print('Fetching bot information...')
|
||||||
self.info = bindings.getMe(self)
|
self.info = bindings.getMe(self)
|
||||||
until self.info
|
until self.info
|
||||||
self.info = self.info.result
|
self.info = self.info.result
|
||||||
|
|
||||||
-- Load the "database"! ;)
|
-- Load the "database"! ;)
|
||||||
self.database_name = config.database_name or self.info.username .. '.db'
|
self.database_name = config.database_name or self.info.username .. '.db'
|
||||||
if not self.database then
|
if not self.database then
|
||||||
self.database = utilities.load_data(self.database_name)
|
self.database = utilities.load_data(self.database_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Migration code 1.12 -> 1.13
|
-- Migration code 1.12 -> 1.13
|
||||||
-- Back to administration global ban list; copy over current blacklist.
|
-- Back to administration global ban list; copy over current blacklist.
|
||||||
if self.database.version ~= '3.13' then
|
if self.database.version ~= '3.13' then
|
||||||
if self.database.administration then
|
if self.database.administration then
|
||||||
self.database.administration.globalbans = self.database.administration.globalbans or self.database.blacklist or {}
|
self.database.administration.globalbans = self.database.administration.globalbans or self.database.blacklist or {}
|
||||||
utilities.save_data(self.database_name, self.database)
|
utilities.save_data(self.database_name, self.database)
|
||||||
self.database = utilities.load_data(self.database_name)
|
self.database = utilities.load_data(self.database_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- End migration code.
|
-- End migration code.
|
||||||
|
|
||||||
-- Table to cache user info (usernames, IDs, etc).
|
-- Table to cache user info (usernames, IDs, etc).
|
||||||
self.database.users = self.database.users or {}
|
self.database.users = self.database.users or {}
|
||||||
-- Table to store userdata (nicknames, lastfm usernames, etc).
|
-- Table to store userdata (nicknames, lastfm usernames, etc).
|
||||||
self.database.userdata = self.database.userdata or {}
|
self.database.userdata = self.database.userdata or {}
|
||||||
-- Table to store the IDs of blacklisted users.
|
-- Table to store the IDs of blacklisted users.
|
||||||
self.database.blacklist = self.database.blacklist or {}
|
self.database.blacklist = self.database.blacklist or {}
|
||||||
-- Save the bot's version in the database to make migration simpler.
|
-- Save the bot's version in the database to make migration simpler.
|
||||||
self.database.version = bot.version
|
self.database.version = bot.version
|
||||||
-- Add updated bot info to the user info cache.
|
-- Add updated bot info to the user info cache.
|
||||||
self.database.users[tostring(self.info.id)] = self.info
|
self.database.users[tostring(self.info.id)] = self.info
|
||||||
|
|
||||||
-- All plugins go into self.plugins. Plugins which accept forwarded messages
|
-- All plugins go into self.plugins. Plugins which accept forwarded messages
|
||||||
-- and messages from blacklisted users also go into self.panoptic_plugins.
|
-- and messages from blacklisted users also go into self.panoptic_plugins.
|
||||||
self.plugins = {}
|
self.plugins = {}
|
||||||
self.panoptic_plugins = {}
|
self.panoptic_plugins = {}
|
||||||
for _, pname in ipairs(config.plugins) do
|
for _, pname in ipairs(config.plugins) do
|
||||||
local plugin = require('otouto.plugins.'..pname)
|
local plugin = require('otouto.plugins.'..pname)
|
||||||
table.insert(self.plugins, plugin)
|
table.insert(self.plugins, plugin)
|
||||||
if plugin.init then plugin.init(self, config) end
|
if plugin.init then plugin.init(self, config) end
|
||||||
if plugin.panoptic then table.insert(self.panoptic_plugins, plugin) end
|
if plugin.panoptic then table.insert(self.panoptic_plugins, plugin) end
|
||||||
if plugin.doc then plugin.doc = '```\n'..plugin.doc..'\n```' end
|
if plugin.doc then plugin.doc = '```\n'..plugin.doc..'\n```' end
|
||||||
if not plugin.triggers then plugin.triggers = {} end
|
if not plugin.triggers then plugin.triggers = {} end
|
||||||
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.
|
-- Set loop variables.
|
||||||
self.last_update = self.last_update or 0 -- Update offset.
|
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_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.last_database_save = self.last_database_save or os.date('%H') -- Last db save.
|
||||||
self.is_started = true
|
self.is_started = true
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Function to be run on each new message.
|
-- Function to be run on each new message.
|
||||||
function bot:on_msg_receive(msg, config)
|
function bot:on_msg_receive(msg, config)
|
||||||
|
|
||||||
-- Do not process old messages.
|
-- Do not process old messages.
|
||||||
if msg.date < os.time() - 5 then return end
|
if msg.date < os.time() - 5 then return end
|
||||||
|
|
||||||
-- plugint is the array of plugins we'll check the message against.
|
-- 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
|
-- If the message is forwarded or from a blacklisted user, the bot will only
|
||||||
-- check against panoptic plugins.
|
-- check against panoptic plugins.
|
||||||
local plugint = self.plugins
|
local plugint = self.plugins
|
||||||
local from_id_str = tostring(msg.from.id)
|
local from_id_str = tostring(msg.from.id)
|
||||||
|
|
||||||
-- Cache user info for those involved.
|
-- Cache user info for those involved.
|
||||||
self.database.users[from_id_str] = msg.from
|
self.database.users[from_id_str] = msg.from
|
||||||
if msg.reply_to_message then
|
if msg.reply_to_message then
|
||||||
self.database.users[tostring(msg.reply_to_message.from.id)] = msg.reply_to_message.from
|
self.database.users[tostring(msg.reply_to_message.from.id)] = msg.reply_to_message.from
|
||||||
elseif msg.forward_from then
|
elseif msg.forward_from then
|
||||||
-- Forwards only go to panoptic plugins.
|
-- Forwards only go to panoptic plugins.
|
||||||
plugint = self.panoptic_plugins
|
plugint = self.panoptic_plugins
|
||||||
self.database.users[tostring(msg.forward_from.id)] = msg.forward_from
|
self.database.users[tostring(msg.forward_from.id)] = msg.forward_from
|
||||||
elseif msg.new_chat_member then
|
elseif msg.new_chat_member then
|
||||||
self.database.users[tostring(msg.new_chat_member.id)] = msg.new_chat_member
|
self.database.users[tostring(msg.new_chat_member.id)] = msg.new_chat_member
|
||||||
elseif msg.left_chat_member then
|
elseif msg.left_chat_member then
|
||||||
self.database.users[tostring(msg.left_chat_member.id)] = msg.left_chat_member
|
self.database.users[tostring(msg.left_chat_member.id)] = msg.left_chat_member
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Messages from blacklisted users only go to panoptic plugins.
|
-- Messages from blacklisted users only go to panoptic plugins.
|
||||||
if self.database.blacklist[from_id_str] then
|
if self.database.blacklist[from_id_str] then
|
||||||
plugint = self.panoptic_plugins
|
plugint = self.panoptic_plugins
|
||||||
end
|
end
|
||||||
|
|
||||||
-- If no text, use captions.
|
-- If no text, use captions.
|
||||||
msg.text = msg.text or msg.caption or ''
|
msg.text = msg.text or msg.caption or ''
|
||||||
msg.text_lower = msg.text:lower()
|
msg.text_lower = msg.text:lower()
|
||||||
if msg.reply_to_message then
|
if msg.reply_to_message then
|
||||||
msg.reply_to_message.text = msg.reply_to_message.text or msg.reply_to_message.caption or ''
|
msg.reply_to_message.text = msg.reply_to_message.text or msg.reply_to_message.caption or ''
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Support deep linking.
|
-- Support deep linking.
|
||||||
if msg.text:match('^'..config.cmd_pat..'start .+') then
|
if msg.text:match('^'..config.cmd_pat..'start .+') then
|
||||||
msg.text = config.cmd_pat .. utilities.input(msg.text)
|
msg.text = config.cmd_pat .. utilities.input(msg.text)
|
||||||
msg.text_lower = msg.text:lower()
|
msg.text_lower = msg.text:lower()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- If the message is forwarded or comes from a blacklisted yser,
|
-- If the message is forwarded or comes from a blacklisted yser,
|
||||||
|
|
||||||
-- Do the thing.
|
-- Do the thing.
|
||||||
for _, plugin in ipairs(plugint) do
|
for _, plugin in ipairs(plugint) do
|
||||||
for _, trigger in ipairs(plugin.triggers) do
|
for _, trigger in ipairs(plugin.triggers) do
|
||||||
if string.match(msg.text_lower, trigger) then
|
if string.match(msg.text_lower, trigger) then
|
||||||
local success, result = pcall(function()
|
local success, result = pcall(function()
|
||||||
return plugin.action(self, msg, config)
|
return plugin.action(self, msg, config)
|
||||||
end)
|
end)
|
||||||
if not success then
|
if not success then
|
||||||
-- If the plugin has an error message, send it. If it does
|
-- If the plugin has an error message, send it. If it does
|
||||||
-- not, use the generic one specified in config. If it's set
|
-- not, use the generic one specified in config. If it's set
|
||||||
-- to false, do nothing.
|
-- to false, do nothing.
|
||||||
if plugin.error then
|
if plugin.error then
|
||||||
utilities.send_reply(self, msg, plugin.error)
|
utilities.send_reply(self, msg, plugin.error)
|
||||||
elseif plugin.error == nil then
|
elseif plugin.error == nil then
|
||||||
utilities.send_reply(self, msg, config.errors.generic)
|
utilities.send_reply(self, msg, config.errors.generic)
|
||||||
end
|
end
|
||||||
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config)
|
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config)
|
||||||
msg = nil
|
msg = nil
|
||||||
return
|
return
|
||||||
-- Continue if the return value is true.
|
-- Continue if the return value is true.
|
||||||
elseif result ~= true then
|
elseif result ~= true then
|
||||||
msg = nil
|
msg = nil
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
msg = nil
|
msg = nil
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- main
|
-- main
|
||||||
function bot:run(config)
|
function bot:run(config)
|
||||||
bot.init(self, config)
|
bot.init(self, config)
|
||||||
while self.is_started do
|
while self.is_started do
|
||||||
-- Update loop.
|
-- Update loop.
|
||||||
local res = bindings.getUpdates(self, { timeout = 20, offset = self.last_update + 1 } )
|
local res = bindings.getUpdates(self, { timeout = 20, offset = self.last_update + 1 } )
|
||||||
if res then
|
if res then
|
||||||
-- Iterate over every new message.
|
-- Iterate over every new message.
|
||||||
for _,v in ipairs(res.result) do
|
for _,v in ipairs(res.result) do
|
||||||
self.last_update = v.update_id
|
self.last_update = v.update_id
|
||||||
if v.message then
|
if v.message then
|
||||||
bot.on_msg_receive(self, v.message, config)
|
bot.on_msg_receive(self, v.message, config)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
print('Connection error while fetching updates.')
|
print('Connection error while fetching updates.')
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Run cron jobs every minute.
|
-- Run cron jobs every minute.
|
||||||
if self.last_cron ~= os.date('%M') then
|
if self.last_cron ~= os.date('%M') then
|
||||||
self.last_cron = os.date('%M')
|
self.last_cron = os.date('%M')
|
||||||
for i,v in ipairs(self.plugins) do
|
for i,v in ipairs(self.plugins) do
|
||||||
if v.cron then -- Call each plugin's cron function, if it has one.
|
if v.cron then -- Call each plugin's cron function, if it has one.
|
||||||
local result, err = pcall(function() v.cron(self, config) end)
|
local result, err = pcall(function() v.cron(self, config) end)
|
||||||
if not result then
|
if not result then
|
||||||
utilities.handle_exception(self, err, 'CRON: ' .. i, config)
|
utilities.handle_exception(self, err, 'CRON: ' .. i, config)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Save the "database" every hour.
|
-- Save the "database" every hour.
|
||||||
if self.last_database_save ~= os.date('%H') then
|
if self.last_database_save ~= os.date('%H') then
|
||||||
self.last_database_save = os.date('%H')
|
self.last_database_save = os.date('%H')
|
||||||
utilities.save_data(self.database_name, self.database)
|
utilities.save_data(self.database_name, self.database)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Save the database before exiting.
|
-- Save the database before exiting.
|
||||||
utilities.save_data(self.database_name, self.database)
|
utilities.save_data(self.database_name, self.database)
|
||||||
print('Halted.')
|
print('Halted.')
|
||||||
end
|
end
|
||||||
|
|
||||||
return bot
|
return bot
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
--[[
|
--[[
|
||||||
drua-tg
|
drua-tg
|
||||||
Based on JuanPotato's lua-tg (https://github.com/juanpotato/lua-tg),
|
Based on JuanPotato's lua-tg (https://github.com/juanpotato/lua-tg),
|
||||||
modified to work more naturally from an API bot.
|
modified to work more naturally from an API bot.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
drua = require('drua-tg')
|
drua = require('drua-tg')
|
||||||
drua.IP = 'localhost' -- 'localhost' is default
|
drua.IP = 'localhost' -- 'localhost' is default
|
||||||
drua.PORT = 4567 -- 4567 is default
|
drua.PORT = 4567 -- 4567 is default
|
||||||
drua.message(chat_id, text)
|
drua.message(chat_id, text)
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
@ -35,150 +35,150 @@ SOFTWARE.
|
|||||||
local SOCKET = require('socket')
|
local SOCKET = require('socket')
|
||||||
|
|
||||||
local comtab = {
|
local comtab = {
|
||||||
add = { 'chat_add_user %s %s', 'channel_invite %s %s' },
|
add = { 'chat_add_user %s %s', 'channel_invite %s %s' },
|
||||||
kick = { 'chat_del_user %s %s', 'channel_kick %s %s' },
|
kick = { 'chat_del_user %s %s', 'channel_kick %s %s' },
|
||||||
rename = { 'rename_chat %s "%s"', 'rename_channel %s "%s"' },
|
rename = { 'rename_chat %s "%s"', 'rename_channel %s "%s"' },
|
||||||
link = { 'export_chat_link %s', 'export_channel_link %s' },
|
link = { 'export_chat_link %s', 'export_channel_link %s' },
|
||||||
photo_set = { 'chat_set_photo %s %s', 'channel_set_photo %s %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' },
|
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' }
|
info = { [0] = 'user_info %s', 'chat_info %s', 'channel_info %s' }
|
||||||
}
|
}
|
||||||
|
|
||||||
local format_target = function(target)
|
local format_target = function(target)
|
||||||
target = tonumber(target)
|
target = tonumber(target)
|
||||||
if target < -1000000000000 then
|
if target < -1000000000000 then
|
||||||
target = 'channel#' .. math.abs(target) - 1000000000000
|
target = 'channel#' .. math.abs(target) - 1000000000000
|
||||||
return target, 2
|
return target, 2
|
||||||
elseif target < 0 then
|
elseif target < 0 then
|
||||||
target = 'chat#' .. math.abs(target)
|
target = 'chat#' .. math.abs(target)
|
||||||
return target, 1
|
return target, 1
|
||||||
else
|
else
|
||||||
target = 'user#' .. target
|
target = 'user#' .. target
|
||||||
return target, 0
|
return target, 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local escape = function(text)
|
local escape = function(text)
|
||||||
text = text:gsub('\\', '\\\\')
|
text = text:gsub('\\', '\\\\')
|
||||||
text = text:gsub('\n', '\\n')
|
text = text:gsub('\n', '\\n')
|
||||||
text = text:gsub('\t', '\\t')
|
text = text:gsub('\t', '\\t')
|
||||||
text = text:gsub('"', '\\"')
|
text = text:gsub('"', '\\"')
|
||||||
return text
|
return text
|
||||||
end
|
end
|
||||||
|
|
||||||
local drua = {
|
local drua = {
|
||||||
IP = 'localhost',
|
IP = 'localhost',
|
||||||
PORT = 4567
|
PORT = 4567
|
||||||
}
|
}
|
||||||
|
|
||||||
drua.send = function(command, do_receive)
|
drua.send = function(command, do_receive)
|
||||||
local s = SOCKET.connect(drua.IP, drua.PORT)
|
local s = SOCKET.connect(drua.IP, drua.PORT)
|
||||||
assert(s, '\nUnable to connect to tg session.')
|
assert(s, '\nUnable to connect to tg session.')
|
||||||
s:send(command..'\n')
|
s:send(command..'\n')
|
||||||
local output
|
local output
|
||||||
if do_receive then
|
if do_receive then
|
||||||
output = string.match(s:receive('*l'), 'ANSWER (%d+)')
|
output = string.match(s:receive('*l'), 'ANSWER (%d+)')
|
||||||
output = s:receive(tonumber(output)):gsub('\n$', '')
|
output = s:receive(tonumber(output)):gsub('\n$', '')
|
||||||
end
|
end
|
||||||
s:close()
|
s:close()
|
||||||
return output
|
return output
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.message = function(target, text)
|
drua.message = function(target, text)
|
||||||
target = format_target(target)
|
target = format_target(target)
|
||||||
text = escape(text)
|
text = escape(text)
|
||||||
local command = 'msg %s "%s"'
|
local command = 'msg %s "%s"'
|
||||||
command = command:format(target, text)
|
command = command:format(target, text)
|
||||||
return drua.send(command)
|
return drua.send(command)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.send_photo = function(target, photo)
|
drua.send_photo = function(target, photo)
|
||||||
target = format_target(target)
|
target = format_target(target)
|
||||||
local command = 'send_photo %s %s'
|
local command = 'send_photo %s %s'
|
||||||
command = command:format(target, photo)
|
command = command:format(target, photo)
|
||||||
return drua.send(command)
|
return drua.send(command)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.add_user = function(chat, target)
|
drua.add_user = function(chat, target)
|
||||||
local a
|
local a
|
||||||
chat, a = format_target(chat)
|
chat, a = format_target(chat)
|
||||||
target = format_target(target)
|
target = format_target(target)
|
||||||
local command = comtab.add[a]:format(chat, target)
|
local command = comtab.add[a]:format(chat, target)
|
||||||
return drua.send(command)
|
return drua.send(command)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.kick_user = function(chat, target)
|
drua.kick_user = function(chat, target)
|
||||||
-- Get the group info so tg will recognize the target.
|
-- Get the group info so tg will recognize the target.
|
||||||
drua.get_info(chat)
|
drua.get_info(chat)
|
||||||
local a
|
local a
|
||||||
chat, a = format_target(chat)
|
chat, a = format_target(chat)
|
||||||
target = format_target(target)
|
target = format_target(target)
|
||||||
local command = comtab.kick[a]:format(chat, target)
|
local command = comtab.kick[a]:format(chat, target)
|
||||||
return drua.send(command)
|
return drua.send(command)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.rename_chat = function(chat, name)
|
drua.rename_chat = function(chat, name)
|
||||||
local a
|
local a
|
||||||
chat, a = format_target(chat)
|
chat, a = format_target(chat)
|
||||||
local command = comtab.rename[a]:format(chat, name)
|
local command = comtab.rename[a]:format(chat, name)
|
||||||
return drua.send(command)
|
return drua.send(command)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.export_link = function(chat)
|
drua.export_link = function(chat)
|
||||||
local a
|
local a
|
||||||
chat, a = format_target(chat)
|
chat, a = format_target(chat)
|
||||||
local command = comtab.link[a]:format(chat)
|
local command = comtab.link[a]:format(chat)
|
||||||
return drua.send(command, true)
|
return drua.send(command, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.get_photo = function(chat)
|
drua.get_photo = function(chat)
|
||||||
local a
|
local a
|
||||||
chat, a = format_target(chat)
|
chat, a = format_target(chat)
|
||||||
local command = comtab.photo_get[a]:format(chat)
|
local command = comtab.photo_get[a]:format(chat)
|
||||||
local output = drua.send(command, true)
|
local output = drua.send(command, true)
|
||||||
if output:match('FAIL') then
|
if output:match('FAIL') then
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
return output:match('Saved to (.+)')
|
return output:match('Saved to (.+)')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.set_photo = function(chat, photo)
|
drua.set_photo = function(chat, photo)
|
||||||
local a
|
local a
|
||||||
chat, a = format_target(chat)
|
chat, a = format_target(chat)
|
||||||
local command = comtab.photo_set[a]:format(chat, photo)
|
local command = comtab.photo_set[a]:format(chat, photo)
|
||||||
return drua.send(command)
|
return drua.send(command)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.get_info = function(target)
|
drua.get_info = function(target)
|
||||||
local a
|
local a
|
||||||
target, a = format_target(target)
|
target, a = format_target(target)
|
||||||
local command = comtab.info[a]:format(target)
|
local command = comtab.info[a]:format(target)
|
||||||
return drua.send(command, true)
|
return drua.send(command, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.channel_set_admin = function(chat, user, rank)
|
drua.channel_set_admin = function(chat, user, rank)
|
||||||
chat = format_target(chat)
|
chat = format_target(chat)
|
||||||
user = format_target(user)
|
user = format_target(user)
|
||||||
local command = 'channel_set_admin %s %s %s'
|
local command = 'channel_set_admin %s %s %s'
|
||||||
command = command:format(chat, user, rank)
|
command = command:format(chat, user, rank)
|
||||||
return drua.send(command)
|
return drua.send(command)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.channel_set_about = function(chat, text)
|
drua.channel_set_about = function(chat, text)
|
||||||
chat = format_target(chat)
|
chat = format_target(chat)
|
||||||
text = escape(text)
|
text = escape(text)
|
||||||
local command = 'channel_set_about %s "%s"'
|
local command = 'channel_set_about %s "%s"'
|
||||||
command = command:format(chat, text)
|
command = command:format(chat, text)
|
||||||
return drua.send(command)
|
return drua.send(command)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.block = function(user)
|
drua.block = function(user)
|
||||||
return drua.send('block_user user#' .. user)
|
return drua.send('block_user user#' .. user)
|
||||||
end
|
end
|
||||||
|
|
||||||
drua.unblock = function(user)
|
drua.unblock = function(user)
|
||||||
return drua.send('unblock_user user#' .. user)
|
return drua.send('unblock_user user#' .. user)
|
||||||
end
|
end
|
||||||
|
|
||||||
return drua
|
return drua
|
||||||
|
@ -7,13 +7,13 @@ about.command = 'about'
|
|||||||
about.doc = 'Returns information about the bot.'
|
about.doc = 'Returns information about the bot.'
|
||||||
|
|
||||||
function about:init(config)
|
function about:init(config)
|
||||||
about.text = config.about_text .. '\nBased on [otouto](http://github.com/topkecleon/otouto) v'..bot.version..' by topkecleon.'
|
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)
|
about.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('about'):t('start').table
|
:t('about'):t('start').table
|
||||||
end
|
end
|
||||||
|
|
||||||
function about:action(msg, config)
|
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
|
end
|
||||||
|
|
||||||
return about
|
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]'
|
apod.command = 'apod [date]'
|
||||||
|
|
||||||
function apod:init(config)
|
function apod:init(config)
|
||||||
apod.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('apod', true).table
|
apod.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('apod', true).table
|
||||||
apod.doc = [[
|
apod.doc = [[
|
||||||
/apod [YYYY-MM-DD]
|
/apod [YYYY-MM-DD]
|
||||||
Returns the Astronomy Picture of the Day.
|
Returns the Astronomy Picture of the Day.
|
||||||
Source: nasa.gov
|
Source: nasa.gov
|
||||||
]]
|
]]
|
||||||
apod.doc = apod.doc:gsub('/', config.cmd_pat)
|
apod.doc = apod.doc:gsub('/', config.cmd_pat)
|
||||||
apod.base_url = 'https://api.nasa.gov/planetary/apod?api_key=' .. (config.nasa_api_key or 'DEMO_KEY')
|
apod.base_url = 'https://api.nasa.gov/planetary/apod?api_key=' .. (config.nasa_api_key or 'DEMO_KEY')
|
||||||
end
|
end
|
||||||
|
|
||||||
function apod:action(msg, config)
|
function apod:action(msg, config)
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
local url = apod.base_url
|
local url = apod.base_url
|
||||||
local date = os.date('%F')
|
local date = os.date('%F')
|
||||||
if input then
|
if input then
|
||||||
if input:match('^(%d+)%-(%d+)%-(%d+)$') then
|
if input:match('^(%d+)%-(%d+)%-(%d+)$') then
|
||||||
url = url .. '&date=' .. URL.escape(input)
|
url = url .. '&date=' .. URL.escape(input)
|
||||||
date = input
|
date = input
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local jstr, code = HTTPS.request(url)
|
local jstr, code = HTTPS.request(url)
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
if data.error then
|
if data.error then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = string.format(
|
local output = string.format(
|
||||||
'<b>%s (</b><a href="%s">%s</a><b>)</b>\n%s',
|
'<b>%s (</b><a href="%s">%s</a><b>)</b>\n%s',
|
||||||
utilities.html_escape(data.title),
|
utilities.html_escape(data.title),
|
||||||
utilities.html_escape(data.hdurl or data.url),
|
utilities.html_escape(data.hdurl or data.url),
|
||||||
date,
|
date,
|
||||||
utilities.html_escape(data.explanation)
|
utilities.html_escape(data.explanation)
|
||||||
)
|
)
|
||||||
utilities.send_message(self, msg.chat.id, output, false, nil, 'html')
|
utilities.send_message(self, msg.chat.id, output, false, nil, 'html')
|
||||||
end
|
end
|
||||||
|
|
||||||
return apod
|
return apod
|
||||||
|
@ -5,8 +5,8 @@ local utilities = require('otouto.utilities')
|
|||||||
bandersnatch.command = 'bandersnatch'
|
bandersnatch.command = 'bandersnatch'
|
||||||
|
|
||||||
function bandersnatch:init(config)
|
function bandersnatch:init(config)
|
||||||
bandersnatch.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('bandersnatch'):t('bc').table
|
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.doc = 'Shun the frumious Bandersnatch. \nAlias: ' .. config.cmd_pat .. 'bc'
|
||||||
end
|
end
|
||||||
|
|
||||||
local fullnames = { "Wimbledon Tennismatch", "Rinkydink Curdlesnoot", "Butawhiteboy Cantbekhan", "Benadryl Claritin", "Bombadil Rivendell", "Wanda's Crotchfruit", "Biblical Concubine", "Syphilis Cankersore", "Buckminster Fullerene", "Bourgeoisie Capitalist" }
|
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)
|
function bandersnatch:action(msg)
|
||||||
|
|
||||||
local output
|
local output
|
||||||
|
|
||||||
if math.random(10) == 10 then
|
if math.random(10) == 10 then
|
||||||
output = fullnames[math.random(#fullnames)]
|
output = fullnames[math.random(#fullnames)]
|
||||||
else
|
else
|
||||||
output = firstnames[math.random(#firstnames)] .. ' ' .. lastnames[math.random(#lastnames)]
|
output = firstnames[math.random(#firstnames)] .. ' ' .. lastnames[math.random(#lastnames)]
|
||||||
end
|
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
|
||||||
|
|
||||||
|
@ -5,12 +5,12 @@ local URL = require('socket.url')
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function bible:init(config)
|
function bible:init(config)
|
||||||
assert(config.biblia_api_key,
|
assert(config.biblia_api_key,
|
||||||
'bible.lua requires a Biblia API key from http://api.biblia.com.'
|
'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.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('bible', true):t('b', true).table
|
||||||
bible.doc = config.cmd_pat .. [[bible <reference>
|
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.
|
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'
|
Alias: ]] .. config.cmd_pat .. 'b'
|
||||||
end
|
end
|
||||||
@ -19,30 +19,30 @@ bible.command = 'bible <reference>'
|
|||||||
|
|
||||||
function bible:action(msg, config)
|
function bible:action(msg, config)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, bible.doc, true)
|
utilities.send_reply(self, msg, bible.doc, true)
|
||||||
return
|
return
|
||||||
end
|
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
|
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)
|
url = 'http://api.biblia.com/v1/bible/content/KJVAPOC.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input)
|
||||||
output, res = HTTP.request(url)
|
output, res = HTTP.request(url)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not output or res ~= 200 or output:len() == 0 then
|
if not output or res ~= 200 or output:len() == 0 then
|
||||||
output = config.errors.results
|
output = config.errors.results
|
||||||
end
|
end
|
||||||
|
|
||||||
if output:len() > 4000 then
|
if output:len() > 4000 then
|
||||||
output = 'The text is too long to post here. Try being more specific.'
|
output = 'The text is too long to post here. Try being more specific.'
|
||||||
end
|
end
|
||||||
|
|
||||||
utilities.send_reply(self, msg, output)
|
utilities.send_reply(self, msg, output)
|
||||||
|
|
||||||
end
|
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'
|
bing.search_url = 'https://api.datamarket.azure.com/Data.ashx/Bing/Search/Web?Query=\'%s\'&$format=json'
|
||||||
|
|
||||||
function bing:init(config)
|
function bing:init(config)
|
||||||
assert(config.bing_api_key,
|
assert(config.bing_api_key,
|
||||||
'bing.lua requires a Bing API key from http://datamarket.azure.com/dataset/bing/search.'
|
'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.headers = { ["Authorization"] = "Basic " .. mime.b64(":" .. config.bing_api_key) }
|
||||||
bing.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
bing.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('bing', true):t('g', true):t('google', true).table
|
:t('bing', true):t('g', true):t('google', true).table
|
||||||
bing.doc = [[
|
bing.doc = [[
|
||||||
/bing <query>
|
/bing <query>
|
||||||
Returns the top web results from Bing.
|
Returns the top web results from Bing.
|
||||||
Aliases: /g, /google
|
Aliases: /g, /google
|
||||||
]]
|
]]
|
||||||
bing.doc = bing.doc:gsub('/', config.cmd_pat)
|
bing.doc = bing.doc:gsub('/', config.cmd_pat)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function bing:action(msg, config)
|
function bing:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, bing.doc, true)
|
utilities.send_reply(self, msg, bing.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local url = bing.search_url:format(URL.escape(input))
|
local url = bing.search_url:format(URL.escape(input))
|
||||||
local resbody = {}
|
local resbody = {}
|
||||||
local _, code = https.request{
|
local _, code = https.request{
|
||||||
url = url,
|
url = url,
|
||||||
headers = bing.headers,
|
headers = bing.headers,
|
||||||
sink = ltn12.sink.table(resbody),
|
sink = ltn12.sink.table(resbody),
|
||||||
}
|
}
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local data = JSON.decode(table.concat(resbody))
|
local data = JSON.decode(table.concat(resbody))
|
||||||
-- Four results in a group, eight in private.
|
-- Four results in a group, eight in private.
|
||||||
local limit = msg.chat.type == 'private' and 8 or 4
|
local limit = msg.chat.type == 'private' and 8 or 4
|
||||||
-- No more results than provided.
|
-- No more results than provided.
|
||||||
limit = limit > #data.d.results and #data.d.results or limit
|
limit = limit > #data.d.results and #data.d.results or limit
|
||||||
if limit == 0 then
|
if limit == 0 then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local reslist = {}
|
local reslist = {}
|
||||||
for i = 1, limit do
|
for i = 1, limit do
|
||||||
table.insert(reslist, string.format(
|
table.insert(reslist, string.format(
|
||||||
'• <a href="%s">%s</a>',
|
'• <a href="%s">%s</a>',
|
||||||
utilities.html_escape(data.d.results[i].Url),
|
utilities.html_escape(data.d.results[i].Url),
|
||||||
utilities.html_escape(data.d.results[i].Title)
|
utilities.html_escape(data.d.results[i].Title)
|
||||||
))
|
))
|
||||||
end
|
end
|
||||||
local output = string.format(
|
local output = string.format(
|
||||||
'<b>Search results for</b> <i>%s</i><b>:</b>\n%s',
|
'<b>Search results for</b> <i>%s</i><b>:</b>\n%s',
|
||||||
utilities.html_escape(input),
|
utilities.html_escape(input),
|
||||||
table.concat(reslist, '\n')
|
table.concat(reslist, '\n')
|
||||||
)
|
)
|
||||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||||
end
|
end
|
||||||
|
|
||||||
return bing
|
return bing
|
||||||
|
@ -3,92 +3,92 @@ local utilities = require('otouto.utilities')
|
|||||||
local blacklist = {}
|
local blacklist = {}
|
||||||
|
|
||||||
function blacklist:init(config)
|
function blacklist:init(config)
|
||||||
blacklist.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
blacklist.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('blacklist', true):t('unblacklist', true).table
|
:t('blacklist', true):t('unblacklist', true).table
|
||||||
blacklist.error = false
|
blacklist.error = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function blacklist:action(msg, config)
|
function blacklist:action(msg, config)
|
||||||
if msg.from.id ~= config.admin then return true end
|
if msg.from.id ~= config.admin then return true end
|
||||||
local targets = {}
|
local targets = {}
|
||||||
if msg.reply_to_message then
|
if msg.reply_to_message then
|
||||||
table.insert(targets, {
|
table.insert(targets, {
|
||||||
id = msg.reply_to_message.from.id,
|
id = msg.reply_to_message.from.id,
|
||||||
id_str = tostring(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)
|
name = utilities.build_name(msg.reply_to_message.from.first_name, msg.reply_to_message.from.last_name)
|
||||||
})
|
})
|
||||||
else
|
else
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
if input then
|
if input then
|
||||||
for user in input:gmatch('%g+') do
|
for user in input:gmatch('%g+') do
|
||||||
if self.database.users[user] then
|
if self.database.users[user] then
|
||||||
table.insert(targets, {
|
table.insert(targets, {
|
||||||
id = self.database.users[user].id,
|
id = self.database.users[user].id,
|
||||||
id_str = tostring(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)
|
name = utilities.build_name(self.database.users[user].first_name, self.database.users[user].last_name)
|
||||||
})
|
})
|
||||||
elseif tonumber(user) then
|
elseif tonumber(user) then
|
||||||
local t = {
|
local t = {
|
||||||
id_str = user,
|
id_str = user,
|
||||||
id = tonumber(user)
|
id = tonumber(user)
|
||||||
}
|
}
|
||||||
if tonumber(user) < 0 then
|
if tonumber(user) < 0 then
|
||||||
t.name = 'Group (' .. user .. ')'
|
t.name = 'Group (' .. user .. ')'
|
||||||
else
|
else
|
||||||
t.name = 'Unknown (' .. user .. ')'
|
t.name = 'Unknown (' .. user .. ')'
|
||||||
end
|
end
|
||||||
table.insert(targets, t)
|
table.insert(targets, t)
|
||||||
elseif user:match('^@') then
|
elseif user:match('^@') then
|
||||||
local u = utilities.resolve_username(self, user)
|
local u = utilities.resolve_username(self, user)
|
||||||
if u then
|
if u then
|
||||||
table.insert(targets, {
|
table.insert(targets, {
|
||||||
id = u.id,
|
id = u.id,
|
||||||
id_str = tostring(u.id),
|
id_str = tostring(u.id),
|
||||||
name = utilities.build_name(u.first_name, u.last_name)
|
name = utilities.build_name(u.first_name, u.last_name)
|
||||||
})
|
})
|
||||||
else
|
else
|
||||||
table.insert(targets, { err = 'Sorry, I do not recognize that username ('..user..').' })
|
table.insert(targets, { err = 'Sorry, I do not recognize that username ('..user..').' })
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
table.insert(targets, { err = 'Invalid username or ID ('..user..').' })
|
table.insert(targets, { err = 'Invalid username or ID ('..user..').' })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
utilities.send_reply(self, msg, 'Please specify a user or users via reply, username, or ID, or a group or groups via ID.')
|
utilities.send_reply(self, msg, 'Please specify a user or users via reply, username, or ID, or a group or groups via ID.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local output = ''
|
local output = ''
|
||||||
if msg.text:match('^'..config.cmd_pat..'blacklist') then
|
if msg.text:match('^'..config.cmd_pat..'blacklist') then
|
||||||
for _, target in ipairs(targets) do
|
for _, target in ipairs(targets) do
|
||||||
if target.err then
|
if target.err then
|
||||||
output = output .. target.err .. '\n'
|
output = output .. target.err .. '\n'
|
||||||
elseif self.database.blacklist[target.id_str] then
|
elseif self.database.blacklist[target.id_str] then
|
||||||
output = output .. target.name .. ' is already blacklisted.\n'
|
output = output .. target.name .. ' is already blacklisted.\n'
|
||||||
else
|
else
|
||||||
self.database.blacklist[target.id_str] = true
|
self.database.blacklist[target.id_str] = true
|
||||||
output = output .. target.name .. ' is now blacklisted.\n'
|
output = output .. target.name .. ' is now blacklisted.\n'
|
||||||
if config.drua_block_on_blacklist and target.id > 0 then
|
if config.drua_block_on_blacklist and target.id > 0 then
|
||||||
require('otouto.drua-tg').block(target.id)
|
require('otouto.drua-tg').block(target.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif msg.text:match('^'..config.cmd_pat..'unblacklist') then
|
elseif msg.text:match('^'..config.cmd_pat..'unblacklist') then
|
||||||
for _, target in ipairs(targets) do
|
for _, target in ipairs(targets) do
|
||||||
if target.err then
|
if target.err then
|
||||||
output = output .. target.err .. '\n'
|
output = output .. target.err .. '\n'
|
||||||
elseif not self.database.blacklist[target.id_str] then
|
elseif not self.database.blacklist[target.id_str] then
|
||||||
output = output .. target.name .. ' is not blacklisted.\n'
|
output = output .. target.name .. ' is not blacklisted.\n'
|
||||||
else
|
else
|
||||||
self.database.blacklist[target.id_str] = nil
|
self.database.blacklist[target.id_str] = nil
|
||||||
output = output .. target.name .. ' is no longer blacklisted.\n'
|
output = output .. target.name .. ' is no longer blacklisted.\n'
|
||||||
if config.drua_block_on_blacklist and target.id > 0 then
|
if config.drua_block_on_blacklist and target.id > 0 then
|
||||||
require('otouto.drua-tg').unblock(target.id)
|
require('otouto.drua-tg').unblock(target.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
utilities.send_reply(self, msg, output)
|
utilities.send_reply(self, msg, output)
|
||||||
end
|
end
|
||||||
|
|
||||||
return blacklist
|
return blacklist
|
||||||
|
@ -7,22 +7,22 @@ local utilities = require('otouto.utilities')
|
|||||||
calc.command = 'calc <expression>'
|
calc.command = 'calc <expression>'
|
||||||
|
|
||||||
function calc:init(config)
|
function calc:init(config)
|
||||||
calc.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('calc', true).table
|
calc.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('calc', true).table
|
||||||
calc.doc = config.cmd_pat .. [[calc <expression>
|
calc.doc = config.cmd_pat .. [[calc <expression>
|
||||||
Returns solutions to mathematical expressions and conversions between common units. Results provided by mathjs.org.]]
|
Returns solutions to mathematical expressions and conversions between common units. Results provided by mathjs.org.]]
|
||||||
end
|
end
|
||||||
|
|
||||||
function calc:action(msg, config)
|
function calc:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, calc.doc, true)
|
utilities.send_reply(self, msg, calc.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local url = 'https://api.mathjs.org/v1/?expr=' .. URL.escape(input)
|
local url = 'https://api.mathjs.org/v1/?expr=' .. URL.escape(input)
|
||||||
local output = HTTPS.request(url)
|
local output = HTTPS.request(url)
|
||||||
output = output and '`'..output..'`' or config.errors.connection
|
output = output and '`'..output..'`' or config.errors.connection
|
||||||
utilities.send_reply(self, msg, output, true)
|
utilities.send_reply(self, msg, output, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
return calc
|
return calc
|
||||||
|
@ -7,22 +7,22 @@ local utilities = require('otouto.utilities')
|
|||||||
local catfact = {}
|
local catfact = {}
|
||||||
|
|
||||||
function catfact:init(config)
|
function catfact:init(config)
|
||||||
catfact.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
catfact.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('catfact', true).table
|
:t('catfact', true).table
|
||||||
catfact.command = 'catfact'
|
catfact.command = 'catfact'
|
||||||
catfact.doc = 'Returns a cat fact.'
|
catfact.doc = 'Returns a cat fact.'
|
||||||
catfact.url = 'http://catfacts-api.appspot.com/api/facts'
|
catfact.url = 'http://catfacts-api.appspot.com/api/facts'
|
||||||
end
|
end
|
||||||
|
|
||||||
function catfact:action(msg, config)
|
function catfact:action(msg, config)
|
||||||
local jstr, code = HTTP.request(catfact.url)
|
local jstr, code = HTTP.request(catfact.url)
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
local output = '*Cat Fact*\n_' .. data.facts[1] .. '_'
|
local output = '*Cat Fact*\n_' .. data.facts[1] .. '_'
|
||||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
return catfact
|
return catfact
|
||||||
|
@ -4,12 +4,12 @@ local HTTP = require('socket.http')
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function cats:init(config)
|
function cats:init(config)
|
||||||
if not config.thecatapi_key then
|
if not config.thecatapi_key then
|
||||||
print('Missing config value: thecatapi_key.')
|
print('Missing config value: thecatapi_key.')
|
||||||
print('cats.lua will be enabled, but there are more features with a key.')
|
print('cats.lua will be enabled, but there are more features with a key.')
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
cats.command = 'cat'
|
cats.command = 'cat'
|
||||||
@ -17,21 +17,21 @@ cats.doc = 'Returns a cat!'
|
|||||||
|
|
||||||
function cats:action(msg, config)
|
function cats:action(msg, config)
|
||||||
|
|
||||||
local url = 'http://thecatapi.com/api/images/get?format=html&type=jpg'
|
local url = 'http://thecatapi.com/api/images/get?format=html&type=jpg'
|
||||||
if config.thecatapi_key then
|
if config.thecatapi_key then
|
||||||
url = url .. '&api_key=' .. config.thecatapi_key
|
url = url .. '&api_key=' .. config.thecatapi_key
|
||||||
end
|
end
|
||||||
|
|
||||||
local str, res = HTTP.request(url)
|
local str, res = HTTP.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
str = str:match('<img src="(.-)">')
|
str = str:match('<img src="(.-)">')
|
||||||
local output = '[Cat!]('..str..')'
|
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
|
end
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ local bindings = require('otouto.bindings')
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function channel:init(config)
|
function channel:init(config)
|
||||||
channel.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('ch', true).table
|
channel.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('ch', true).table
|
||||||
channel.command = 'ch <channel> \\n <message>'
|
channel.command = 'ch <channel> \\n <message>'
|
||||||
channel.doc = config.cmd_pat .. [[ch <channel>
|
channel.doc = config.cmd_pat .. [[ch <channel>
|
||||||
<message>
|
<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.
|
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
|
end
|
||||||
|
|
||||||
function channel:action(msg, config)
|
function channel:action(msg, config)
|
||||||
-- An exercise in using zero early returns. :)
|
-- An exercise in using zero early returns. :)
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
local output
|
local output
|
||||||
if input then
|
if input then
|
||||||
local chat_id = utilities.get_word(input, 1)
|
local chat_id = utilities.get_word(input, 1)
|
||||||
local admin_list, t = bindings.getChatAdministrators(self, { chat_id = chat_id } )
|
local admin_list, t = bindings.getChatAdministrators(self, { chat_id = chat_id } )
|
||||||
if admin_list then
|
if admin_list then
|
||||||
local is_admin = false
|
local is_admin = false
|
||||||
for _, admin in ipairs(admin_list.result) do
|
for _, admin in ipairs(admin_list.result) do
|
||||||
if admin.user.id == msg.from.id then
|
if admin.user.id == msg.from.id then
|
||||||
is_admin = true
|
is_admin = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if is_admin then
|
if is_admin then
|
||||||
local text = input:match('\n(.+)')
|
local text = input:match('\n(.+)')
|
||||||
if text then
|
if text then
|
||||||
local success, result = utilities.send_message(self, chat_id, text, true, nil, true)
|
local success, result = utilities.send_message(self, chat_id, text, true, nil, true)
|
||||||
if success then
|
if success then
|
||||||
output = 'Your message has been sent!'
|
output = 'Your message has been sent!'
|
||||||
else
|
else
|
||||||
output = 'Sorry, I was unable to send your message.\n`' .. result.description .. '`'
|
output = 'Sorry, I was unable to send your message.\n`' .. result.description .. '`'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
output = 'Please enter a message to be sent. Markdown is supported.'
|
output = 'Please enter a message to be sent. Markdown is supported.'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
output = 'Sorry, you do not appear to be an administrator for that channel.'
|
output = 'Sorry, you do not appear to be an administrator for that channel.'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
output = 'Sorry, I was unable to retrieve a list of administrators for that channel.\n`' .. t.description .. '`'
|
output = 'Sorry, I was unable to retrieve a list of administrators for that channel.\n`' .. t.description .. '`'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
output = channel.doc
|
output = channel.doc
|
||||||
end
|
end
|
||||||
utilities.send_reply(self, msg, output, true)
|
utilities.send_reply(self, msg, output, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
return channel
|
return channel
|
||||||
|
@ -7,22 +7,22 @@ local utilities = require('otouto.utilities')
|
|||||||
local chuck = {}
|
local chuck = {}
|
||||||
|
|
||||||
function chuck:init(config)
|
function chuck:init(config)
|
||||||
chuck.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
chuck.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('chuck', true):t('cn', true):t('chucknorris', true).table
|
:t('chuck', true):t('cn', true):t('chucknorris', true).table
|
||||||
chuck.command = 'chuck'
|
chuck.command = 'chuck'
|
||||||
chuck.doc = 'Returns a fact about Chuck Norris.'
|
chuck.doc = 'Returns a fact about Chuck Norris.'
|
||||||
chuck.url = 'http://api.icndb.com/jokes/random'
|
chuck.url = 'http://api.icndb.com/jokes/random'
|
||||||
end
|
end
|
||||||
|
|
||||||
function chuck:action(msg, config)
|
function chuck:action(msg, config)
|
||||||
local jstr, code = HTTP.request(chuck.url)
|
local jstr, code = HTTP.request(chuck.url)
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
local output = '*Chuck Norris Fact*\n_' .. data.value.joke .. '_'
|
local output = '*Chuck Norris Fact*\n_' .. data.value.joke .. '_'
|
||||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
return chuck
|
return chuck
|
||||||
|
@ -7,30 +7,30 @@ local bindings = require('otouto.bindings')
|
|||||||
local cleverbot = {}
|
local cleverbot = {}
|
||||||
|
|
||||||
function cleverbot:init(config)
|
function cleverbot:init(config)
|
||||||
cleverbot.name = '^' .. self.info.first_name:lower() .. ', '
|
cleverbot.name = '^' .. self.info.first_name:lower() .. ', '
|
||||||
cleverbot.username = '^@' .. self.info.username:lower() .. ', '
|
cleverbot.username = '^@' .. self.info.username:lower() .. ', '
|
||||||
cleverbot.triggers = {
|
cleverbot.triggers = {
|
||||||
'^' .. self.info.first_name:lower() .. ', ',
|
'^' .. self.info.first_name:lower() .. ', ',
|
||||||
'^@' .. self.info.username:lower() .. ', '
|
'^@' .. self.info.username:lower() .. ', '
|
||||||
}
|
}
|
||||||
cleverbot.url = config.chatter.cleverbot_api
|
cleverbot.url = config.chatter.cleverbot_api
|
||||||
cleverbot.error = false
|
cleverbot.error = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function cleverbot:action(msg, config)
|
function cleverbot:action(msg, config)
|
||||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' })
|
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' })
|
||||||
local input = msg.text_lower:gsub(cleverbot.name, ''):gsub(cleverbot.name, '')
|
local input = msg.text_lower:gsub(cleverbot.name, ''):gsub(cleverbot.name, '')
|
||||||
local jstr, code = HTTPS.request(cleverbot.url .. URL.escape(input))
|
local jstr, code = HTTPS.request(cleverbot.url .. URL.escape(input))
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_message(self, msg.chat.id, config.chatter.connection)
|
utilities.send_message(self, msg.chat.id, config.chatter.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
if not data.clever then
|
if not data.clever then
|
||||||
utilities.send_message(self, msg.chat.id, config.chatter.response)
|
utilities.send_message(self, msg.chat.id, config.chatter.response)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
utilities.send_message(self, msg.chat.id, data.clever)
|
utilities.send_message(self, msg.chat.id, data.clever)
|
||||||
end
|
end
|
||||||
|
|
||||||
return cleverbot
|
return cleverbot
|
||||||
|
@ -8,19 +8,19 @@ commit.command = 'commit'
|
|||||||
commit.doc = 'Returns a commit message from whatthecommit.com.'
|
commit.doc = 'Returns a commit message from whatthecommit.com.'
|
||||||
|
|
||||||
function commit:init(config)
|
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
|
end
|
||||||
|
|
||||||
function commit:action(msg)
|
function commit:action(msg)
|
||||||
bindings.request(
|
bindings.request(
|
||||||
self,
|
self,
|
||||||
'sendMessage',
|
'sendMessage',
|
||||||
{
|
{
|
||||||
chat_id = msg.chat.id,
|
chat_id = msg.chat.id,
|
||||||
text = '```\n' .. (http.request('http://whatthecommit.com/index.txt')) .. '\n```',
|
text = '```\n' .. (http.request('http://whatthecommit.com/index.txt')) .. '\n```',
|
||||||
parse_mode = 'Markdown'
|
parse_mode = 'Markdown'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
return commit
|
return commit
|
||||||
|
@ -6,52 +6,52 @@ local utilities = require('otouto.utilities')
|
|||||||
local cmd_pat -- Prevents the command from being uncallable.
|
local cmd_pat -- Prevents the command from being uncallable.
|
||||||
|
|
||||||
function control:init(config)
|
function control:init(config)
|
||||||
cmd_pat = config.cmd_pat
|
cmd_pat = config.cmd_pat
|
||||||
control.triggers = utilities.triggers(self.info.username, cmd_pat,
|
control.triggers = utilities.triggers(self.info.username, cmd_pat,
|
||||||
{'^'..cmd_pat..'script'}):t('reload', true):t('halt').table
|
{'^'..cmd_pat..'script'}):t('reload', true):t('halt').table
|
||||||
end
|
end
|
||||||
|
|
||||||
function control:action(msg, config)
|
function control:action(msg, config)
|
||||||
|
|
||||||
if msg.from.id ~= config.admin then
|
if msg.from.id ~= config.admin then
|
||||||
return
|
return
|
||||||
end
|
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
|
if msg.text_lower:match('^'..cmd_pat..'reload') then
|
||||||
for pac, _ in pairs(package.loaded) do
|
for pac, _ in pairs(package.loaded) do
|
||||||
if pac:match('^otouto%.plugins%.') then
|
if pac:match('^otouto%.plugins%.') then
|
||||||
package.loaded[pac] = nil
|
package.loaded[pac] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
package.loaded['otouto.bindings'] = nil
|
package.loaded['otouto.bindings'] = nil
|
||||||
package.loaded['otouto.utilities'] = nil
|
package.loaded['otouto.utilities'] = nil
|
||||||
package.loaded['otouto.drua-tg'] = nil
|
package.loaded['otouto.drua-tg'] = nil
|
||||||
package.loaded['config'] = nil
|
package.loaded['config'] = nil
|
||||||
if not msg.text_lower:match('%-config') then
|
if not msg.text_lower:match('%-config') then
|
||||||
for k, v in pairs(require('config')) do
|
for k, v in pairs(require('config')) do
|
||||||
config[k] = v
|
config[k] = v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
bot.init(self, config)
|
bot.init(self, config)
|
||||||
utilities.send_reply(self, msg, 'Bot reloaded!')
|
utilities.send_reply(self, msg, 'Bot reloaded!')
|
||||||
elseif msg.text_lower:match('^'..cmd_pat..'halt') then
|
elseif msg.text_lower:match('^'..cmd_pat..'halt') then
|
||||||
self.is_started = false
|
self.is_started = false
|
||||||
utilities.send_reply(self, msg, 'Stopping bot!')
|
utilities.send_reply(self, msg, 'Stopping bot!')
|
||||||
elseif msg.text_lower:match('^'..cmd_pat..'script') then
|
elseif msg.text_lower:match('^'..cmd_pat..'script') then
|
||||||
local input = msg.text_lower:match('^'..cmd_pat..'script\n(.+)')
|
local input = msg.text_lower:match('^'..cmd_pat..'script\n(.+)')
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, 'usage: ```\n'..cmd_pat..'script\n'..cmd_pat..'command <arg>\n...\n```', true)
|
utilities.send_reply(self, msg, 'usage: ```\n'..cmd_pat..'script\n'..cmd_pat..'command <arg>\n...\n```', true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
input = input .. '\n'
|
input = input .. '\n'
|
||||||
for command in input:gmatch('(.-)\n') do
|
for command in input:gmatch('(.-)\n') do
|
||||||
command = utilities.trim(command)
|
command = utilities.trim(command)
|
||||||
msg.text = command
|
msg.text = command
|
||||||
bot.on_msg_receive(self, msg, config)
|
bot.on_msg_receive(self, msg, config)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@ local utilities = require('otouto.utilities')
|
|||||||
currency.command = 'cash [amount] <from> to <to>'
|
currency.command = 'cash [amount] <from> to <to>'
|
||||||
|
|
||||||
function currency:init(config)
|
function currency:init(config)
|
||||||
currency.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('cash', true).table
|
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.doc = config.cmd_pat .. [[cash [amount] <from> to <to>
|
||||||
Example: ]] .. config.cmd_pat .. [[cash 5 USD to EUR
|
Example: ]] .. config.cmd_pat .. [[cash 5 USD to EUR
|
||||||
Returns exchange rates for various currencies.
|
Returns exchange rates for various currencies.
|
||||||
Source: Google Finance.]]
|
Source: Google Finance.]]
|
||||||
@ -15,44 +15,44 @@ end
|
|||||||
|
|
||||||
function currency:action(msg, config)
|
function currency:action(msg, config)
|
||||||
|
|
||||||
local input = msg.text:upper()
|
local input = msg.text:upper()
|
||||||
if not input:match('%a%a%a TO %a%a%a') then
|
if not input:match('%a%a%a TO %a%a%a') then
|
||||||
utilities.send_message(self, msg.chat.id, currency.doc, true, msg.message_id, true)
|
utilities.send_message(self, msg.chat.id, currency.doc, true, msg.message_id, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local from = input:match('(%a%a%a) TO')
|
local from = input:match('(%a%a%a) TO')
|
||||||
local to = input:match('TO (%a%a%a)')
|
local to = input:match('TO (%a%a%a)')
|
||||||
local amount = utilities.get_word(input, 2)
|
local amount = utilities.get_word(input, 2)
|
||||||
amount = tonumber(amount) or 1
|
amount = tonumber(amount) or 1
|
||||||
local result = 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
|
url = url .. '?from=' .. from .. '&to=' .. to .. '&a=' .. amount
|
||||||
local str, res = HTTPS.request(url)
|
local str, res = HTTPS.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
str = str:match('<span class=bld>(.*) %u+</span>')
|
str = str:match('<span class=bld>(.*) %u+</span>')
|
||||||
if not str then
|
if not str then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
result = string.format('%.2f', str)
|
result = string.format('%.2f', str)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = amount .. ' ' .. from .. ' = ' .. result .. ' ' .. to .. '\n\n'
|
local output = amount .. ' ' .. from .. ' = ' .. result .. ' ' .. to .. '\n\n'
|
||||||
output = output .. os.date('!%F %T UTC') .. '\nSource: Google Finance`'
|
output = output .. os.date('!%F %T UTC') .. '\nSource: Google Finance`'
|
||||||
output = '```\n' .. output .. '\n```'
|
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
|
end
|
||||||
|
|
||||||
|
@ -5,49 +5,49 @@ local utilities = require('otouto.utilities')
|
|||||||
dice.command = 'roll <nDr>'
|
dice.command = 'roll <nDr>'
|
||||||
|
|
||||||
function dice:init(config)
|
function dice:init(config)
|
||||||
dice.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('roll', true).table
|
dice.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('roll', true).table
|
||||||
dice.doc = config.cmd_pat .. [[roll <nDr>
|
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.]]
|
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
|
end
|
||||||
|
|
||||||
function dice:action(msg)
|
function dice:action(msg)
|
||||||
|
|
||||||
local input = utilities.input(msg.text_lower)
|
local input = utilities.input(msg.text_lower)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_message(self, msg.chat.id, dice.doc, true, msg.message_id, true)
|
utilities.send_message(self, msg.chat.id, dice.doc, true, msg.message_id, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local count, range
|
local count, range
|
||||||
if input:match('^[%d]+d[%d]+$') then
|
if input:match('^[%d]+d[%d]+$') then
|
||||||
count, range = input:match('([%d]+)d([%d]+)')
|
count, range = input:match('([%d]+)d([%d]+)')
|
||||||
elseif input:match('^d?[%d]+$') then
|
elseif input:match('^d?[%d]+$') then
|
||||||
count = 1
|
count = 1
|
||||||
range = input:match('^d?([%d]+)$')
|
range = input:match('^d?([%d]+)$')
|
||||||
else
|
else
|
||||||
utilities.send_message(self, msg.chat.id, dice.doc, true, msg.message_id, true)
|
utilities.send_message(self, msg.chat.id, dice.doc, true, msg.message_id, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
count = tonumber(count)
|
count = tonumber(count)
|
||||||
range = tonumber(range)
|
range = tonumber(range)
|
||||||
|
|
||||||
if range < 2 then
|
if range < 2 then
|
||||||
utilities.send_reply(self, msg, 'The minimum range is 2.')
|
utilities.send_reply(self, msg, 'The minimum range is 2.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if range > 1000 or count > 1000 then
|
if range > 1000 or count > 1000 then
|
||||||
utilities.send_reply(self, msg, 'The maximum range and count are 1000.')
|
utilities.send_reply(self, msg, 'The maximum range and count are 1000.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = '*' .. count .. 'd' .. range .. '*\n`'
|
local output = '*' .. count .. 'd' .. range .. '*\n`'
|
||||||
for _ = 1, count do
|
for _ = 1, count do
|
||||||
output = output .. math.random(range) .. '\t'
|
output = output .. math.random(range) .. '\t'
|
||||||
end
|
end
|
||||||
output = output .. '`'
|
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
|
end
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@ local utilities = require('otouto.utilities')
|
|||||||
dilbert.command = 'dilbert [date]'
|
dilbert.command = 'dilbert [date]'
|
||||||
|
|
||||||
function dilbert:init(config)
|
function dilbert:init(config)
|
||||||
dilbert.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('dilbert', true).table
|
dilbert.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('dilbert', true).table
|
||||||
dilbert.doc = config.cmd_pat .. [[dilbert [YYYY-MM-DD]
|
dilbert.doc = config.cmd_pat .. [[dilbert [YYYY-MM-DD]
|
||||||
Returns the latest Dilbert strip or that of the provided date.
|
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.
|
Dates before the first strip will return the first strip. Dates after the last trip will return the last strip.
|
||||||
Source: dilbert.com]]
|
Source: dilbert.com]]
|
||||||
@ -17,32 +17,32 @@ end
|
|||||||
|
|
||||||
function dilbert:action(msg, config)
|
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)
|
local input = utilities.input(msg.text)
|
||||||
if not input then input = os.date('%F') end
|
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
|
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 url = 'http://dilbert.com/strip/' .. URL.escape(input)
|
||||||
local str, res = HTTP.request(url)
|
local str, res = HTTP.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local strip_filename = '/tmp/' .. input .. '.gif'
|
local strip_filename = '/tmp/' .. input .. '.gif'
|
||||||
local strip_file = io.open(strip_filename)
|
local strip_file = io.open(strip_filename)
|
||||||
if strip_file then
|
if strip_file then
|
||||||
strip_file:close()
|
strip_file:close()
|
||||||
strip_file = strip_filename
|
strip_file = strip_filename
|
||||||
else
|
else
|
||||||
local strip_url = str:match('<meta property="og:image" content="(.-)"/>')
|
local strip_url = str:match('<meta property="og:image" content="(.-)"/>')
|
||||||
strip_file = utilities.download_file(strip_url, '/tmp/' .. input .. '.gif')
|
strip_file = utilities.download_file(strip_url, '/tmp/' .. input .. '.gif')
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
@ -5,25 +5,25 @@ local utilities = require('otouto.utilities')
|
|||||||
echo.command = 'echo <text>'
|
echo.command = 'echo <text>'
|
||||||
|
|
||||||
function echo:init(config)
|
function echo:init(config)
|
||||||
echo.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('echo', true).table
|
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.doc = config.cmd_pat .. 'echo <text> \nRepeats a string of text.'
|
||||||
end
|
end
|
||||||
|
|
||||||
function echo:action(msg)
|
function echo:action(msg)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
|
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_message(self, msg.chat.id, echo.doc, true, msg.message_id, true)
|
utilities.send_message(self, msg.chat.id, echo.doc, true, msg.message_id, true)
|
||||||
else
|
else
|
||||||
local output
|
local output
|
||||||
if msg.chat.type == 'supergroup' then
|
if msg.chat.type == 'supergroup' then
|
||||||
output = utilities.style.enquote('Echo', input)
|
output = utilities.style.enquote('Echo', input)
|
||||||
else
|
else
|
||||||
output = utilities.md_escape(utilities.char.zwnj..input)
|
output = utilities.md_escape(utilities.char.zwnj..input)
|
||||||
end
|
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
|
end
|
||||||
|
@ -6,52 +6,52 @@ eightball.command = '8ball'
|
|||||||
eightball.doc = 'Returns an answer from a magic 8-ball!'
|
eightball.doc = 'Returns an answer from a magic 8-ball!'
|
||||||
|
|
||||||
function eightball:init(config)
|
function eightball:init(config)
|
||||||
eightball.triggers = utilities.triggers(self.info.username, config.cmd_pat,
|
eightball.triggers = utilities.triggers(self.info.username, config.cmd_pat,
|
||||||
{'[Yy]/[Nn]%p*$'}):t('8ball', true).table
|
{'[Yy]/[Nn]%p*$'}):t('8ball', true).table
|
||||||
end
|
end
|
||||||
|
|
||||||
local ball_answers = {
|
local ball_answers = {
|
||||||
"It is certain.",
|
"It is certain.",
|
||||||
"It is decidedly so.",
|
"It is decidedly so.",
|
||||||
"Without a doubt.",
|
"Without a doubt.",
|
||||||
"Yes, definitely.",
|
"Yes, definitely.",
|
||||||
"You may rely on it.",
|
"You may rely on it.",
|
||||||
"As I see it, yes.",
|
"As I see it, yes.",
|
||||||
"Most likely.",
|
"Most likely.",
|
||||||
"Outlook: good.",
|
"Outlook: good.",
|
||||||
"Yes.",
|
"Yes.",
|
||||||
"Signs point to yes.",
|
"Signs point to yes.",
|
||||||
"Reply hazy try again.",
|
"Reply hazy try again.",
|
||||||
"Ask again later.",
|
"Ask again later.",
|
||||||
"Better not tell you now.",
|
"Better not tell you now.",
|
||||||
"Cannot predict now.",
|
"Cannot predict now.",
|
||||||
"Concentrate and ask again.",
|
"Concentrate and ask again.",
|
||||||
"Don't count on it.",
|
"Don't count on it.",
|
||||||
"My reply is no.",
|
"My reply is no.",
|
||||||
"My sources say no.",
|
"My sources say no.",
|
||||||
"Outlook: not so good.",
|
"Outlook: not so good.",
|
||||||
"Very doubtful.",
|
"Very doubtful.",
|
||||||
"There is a time and place for everything, but not now."
|
"There is a time and place for everything, but not now."
|
||||||
}
|
}
|
||||||
|
|
||||||
local yesno_answers = {
|
local yesno_answers = {
|
||||||
'Absolutely.',
|
'Absolutely.',
|
||||||
'In your dreams.',
|
'In your dreams.',
|
||||||
'Yes.',
|
'Yes.',
|
||||||
'No.'
|
'No.'
|
||||||
}
|
}
|
||||||
|
|
||||||
function eightball:action(msg)
|
function eightball:action(msg)
|
||||||
|
|
||||||
local output
|
local output
|
||||||
|
|
||||||
if msg.text_lower:match('y/n%p?$') then
|
if msg.text_lower:match('y/n%p?$') then
|
||||||
output = yesno_answers[math.random(#yesno_answers)]
|
output = yesno_answers[math.random(#yesno_answers)]
|
||||||
else
|
else
|
||||||
output = ball_answers[math.random(#ball_answers)]
|
output = ball_answers[math.random(#ball_answers)]
|
||||||
end
|
end
|
||||||
|
|
||||||
utilities.send_reply(self, msg, output)
|
utilities.send_reply(self, msg, output)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,13 +5,13 @@ local fortune = {}
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function fortune:init(config)
|
function fortune:init(config)
|
||||||
local s = io.popen('fortune'):read('*all')
|
local s = io.popen('fortune'):read('*all')
|
||||||
assert(
|
assert(
|
||||||
not s:match('not found$'),
|
not s:match('not found$'),
|
||||||
'fortune.lua requires the fortune program to be installed.'
|
'fortune.lua requires the fortune program to be installed.'
|
||||||
)
|
)
|
||||||
|
|
||||||
fortune.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('fortune').table
|
fortune.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('fortune').table
|
||||||
end
|
end
|
||||||
|
|
||||||
fortune.command = 'fortune'
|
fortune.command = 'fortune'
|
||||||
@ -19,11 +19,11 @@ fortune.doc = 'Returns a UNIX fortune.'
|
|||||||
|
|
||||||
function fortune:action(msg)
|
function fortune:action(msg)
|
||||||
|
|
||||||
local fortunef = io.popen('fortune')
|
local fortunef = io.popen('fortune')
|
||||||
local output = fortunef:read('*all')
|
local output = fortunef:read('*all')
|
||||||
output = '```\n' .. output .. '\n```'
|
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)
|
||||||
fortunef:close()
|
fortunef:close()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -9,58 +9,58 @@ local JSON = require('dkjson')
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function gImages:init(config)
|
function gImages:init(config)
|
||||||
assert(config.google_api_key and config.google_cse_key,
|
assert(config.google_api_key and config.google_cse_key,
|
||||||
'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.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.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.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.
|
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'
|
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
|
end
|
||||||
|
|
||||||
gImages.command = 'image <query>'
|
gImages.command = 'image <query>'
|
||||||
|
|
||||||
function gImages:action(msg, config)
|
function gImages:action(msg, config)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, gImages.doc, true)
|
utilities.send_reply(self, msg, gImages.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local url = gImages.search_url
|
local url = gImages.search_url
|
||||||
|
|
||||||
if not string.match(msg.text, '^'..config.cmd_pat..'i[mage]*nsfw') then
|
if not string.match(msg.text, '^'..config.cmd_pat..'i[mage]*nsfw') then
|
||||||
url = url .. '&safe=high'
|
url = url .. '&safe=high'
|
||||||
end
|
end
|
||||||
|
|
||||||
url = url .. '&q=' .. URL.escape(input)
|
url = url .. '&q=' .. URL.escape(input)
|
||||||
|
|
||||||
local jstr, res = HTTPS.request(url)
|
local jstr, res = HTTPS.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local jdat = JSON.decode(jstr)
|
local jdat = JSON.decode(jstr)
|
||||||
if jdat.searchInformation.totalResults == '0' then
|
if jdat.searchInformation.totalResults == '0' then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local i = math.random(jdat.queries.request[1].count)
|
local i = math.random(jdat.queries.request[1].count)
|
||||||
local img_url = jdat.items[i].link
|
local img_url = jdat.items[i].link
|
||||||
local img_title = jdat.items[i].title
|
local img_title = jdat.items[i].title
|
||||||
local output = '[' .. img_title .. '](' .. img_url .. ')'
|
local output = '[' .. img_title .. '](' .. img_url .. ')'
|
||||||
|
|
||||||
|
|
||||||
if msg.text:match('nsfw') then
|
if msg.text:match('nsfw') then
|
||||||
utilities.send_reply(self, '*NSFW*\n'..msg, output)
|
utilities.send_reply(self, '*NSFW*\n'..msg, output)
|
||||||
else
|
else
|
||||||
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -6,34 +6,34 @@ local utilities = require('otouto.utilities')
|
|||||||
gMaps.command = 'location <query>'
|
gMaps.command = 'location <query>'
|
||||||
|
|
||||||
function gMaps:init(config)
|
function gMaps:init(config)
|
||||||
gMaps.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
gMaps.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('location', true):t('loc', true).table
|
:t('location', true):t('loc', true).table
|
||||||
gMaps.doc = [[
|
gMaps.doc = [[
|
||||||
/location <query>
|
/location <query>
|
||||||
Returns a location from Google Maps.
|
Returns a location from Google Maps.
|
||||||
Alias: /loc
|
Alias: /loc
|
||||||
]]
|
]]
|
||||||
gMaps.doc = gMaps.doc:gsub('/', config.cmd_pat)
|
gMaps.doc = gMaps.doc:gsub('/', config.cmd_pat)
|
||||||
end
|
end
|
||||||
|
|
||||||
function gMaps:action(msg, config)
|
function gMaps:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, gMaps.doc, true)
|
utilities.send_reply(self, msg, gMaps.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local coords = utilities.get_coords(input, config)
|
local coords = utilities.get_coords(input, config)
|
||||||
if type(coords) == 'string' then
|
if type(coords) == 'string' then
|
||||||
utilities.send_reply(self, msg, coords)
|
utilities.send_reply(self, msg, coords)
|
||||||
end
|
end
|
||||||
|
|
||||||
bindings.sendLocation(self, {
|
bindings.sendLocation(self, {
|
||||||
chat_id = msg.chat.id,
|
chat_id = msg.chat.id,
|
||||||
latitude = coords.lat,
|
latitude = coords.lat,
|
||||||
longitude = coords.lon,
|
longitude = coords.lon,
|
||||||
reply_to_message_id = msg.message_id
|
reply_to_message_id = msg.message_id
|
||||||
} )
|
} )
|
||||||
end
|
end
|
||||||
|
|
||||||
return gMaps
|
return gMaps
|
||||||
|
@ -3,30 +3,30 @@ local utilities = require('otouto.utilities')
|
|||||||
local greetings = {}
|
local greetings = {}
|
||||||
|
|
||||||
function greetings:init(config)
|
function greetings:init(config)
|
||||||
greetings.triggers = {}
|
greetings.triggers = {}
|
||||||
for _, triggers in pairs(config.greetings) do
|
for _, triggers in pairs(config.greetings) do
|
||||||
for i = 1, #triggers do
|
for i = 1, #triggers do
|
||||||
triggers[i] = '^' .. triggers[i] .. ',? ' .. self.info.first_name:lower() .. '%p*$'
|
triggers[i] = '^' .. triggers[i] .. ',? ' .. self.info.first_name:lower() .. '%p*$'
|
||||||
table.insert(greetings.triggers, triggers[i])
|
table.insert(greetings.triggers, triggers[i])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function greetings:action(msg, config)
|
function greetings:action(msg, config)
|
||||||
local nick
|
local nick
|
||||||
if self.database.userdata[tostring(msg.from.id)] then
|
if self.database.userdata[tostring(msg.from.id)] then
|
||||||
nick = self.database.userdata[tostring(msg.from.id)].nickname
|
nick = self.database.userdata[tostring(msg.from.id)].nickname
|
||||||
end
|
end
|
||||||
nick = nick or utilities.build_name(msg.from.first_name, msg.from.last_name)
|
nick = nick or utilities.build_name(msg.from.first_name, msg.from.last_name)
|
||||||
|
|
||||||
for response, triggers in pairs(config.greetings) do
|
for response, triggers in pairs(config.greetings) do
|
||||||
for _, trigger in pairs(triggers) do
|
for _, trigger in pairs(triggers) do
|
||||||
if string.match(msg.text_lower, trigger) then
|
if string.match(msg.text_lower, trigger) then
|
||||||
utilities.send_message(self, msg.chat.id, response:gsub('#NAME', nick))
|
utilities.send_message(self, msg.chat.id, response:gsub('#NAME', nick))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return greetings
|
return greetings
|
||||||
|
@ -8,68 +8,68 @@ local hackernews = {}
|
|||||||
hackernews.command = 'hackernews'
|
hackernews.command = 'hackernews'
|
||||||
|
|
||||||
local function get_hackernews_results()
|
local function get_hackernews_results()
|
||||||
local results = {}
|
local results = {}
|
||||||
local jstr, code = HTTPS.request(hackernews.topstories_url)
|
local jstr, code = HTTPS.request(hackernews.topstories_url)
|
||||||
if code ~= 200 then return end
|
if code ~= 200 then return end
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
for i = 1, 8 do
|
for i = 1, 8 do
|
||||||
local ijstr, icode = HTTPS.request(hackernews.res_url:format(data[i]))
|
local ijstr, icode = HTTPS.request(hackernews.res_url:format(data[i]))
|
||||||
if icode ~= 200 then return end
|
if icode ~= 200 then return end
|
||||||
local idata = JSON.decode(ijstr)
|
local idata = JSON.decode(ijstr)
|
||||||
local result
|
local result
|
||||||
if idata.url then
|
if idata.url then
|
||||||
result = string.format(
|
result = string.format(
|
||||||
'\n• <code>[</code><a href="%s">%s</a><code>]</code> <a href="%s">%s</a>',
|
'\n• <code>[</code><a href="%s">%s</a><code>]</code> <a href="%s">%s</a>',
|
||||||
utilities.html_escape(hackernews.art_url:format(idata.id)),
|
utilities.html_escape(hackernews.art_url:format(idata.id)),
|
||||||
idata.id,
|
idata.id,
|
||||||
utilities.html_escape(idata.url),
|
utilities.html_escape(idata.url),
|
||||||
utilities.html_escape(idata.title)
|
utilities.html_escape(idata.title)
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
result = string.format(
|
result = string.format(
|
||||||
'\n• <code>[</code><a href="%s">%s</a><code>]</code> %s',
|
'\n• <code>[</code><a href="%s">%s</a><code>]</code> %s',
|
||||||
utilities.html_escape(hackernews.art_url:format(idata.id)),
|
utilities.html_escape(hackernews.art_url:format(idata.id)),
|
||||||
idata.id,
|
idata.id,
|
||||||
utilities.html_escape(idata.title)
|
utilities.html_escape(idata.title)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
table.insert(results, result)
|
table.insert(results, result)
|
||||||
end
|
end
|
||||||
return results
|
return results
|
||||||
end
|
end
|
||||||
|
|
||||||
function hackernews:init(config)
|
function hackernews:init(config)
|
||||||
hackernews.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hackernews', true):t('hn', true).table
|
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.doc = [[Returns four (if group) or eight (if private message) top stories from Hacker News.
|
||||||
Alias: ]] .. config.cmd_pat .. 'hn'
|
Alias: ]] .. config.cmd_pat .. 'hn'
|
||||||
hackernews.topstories_url = 'https://hacker-news.firebaseio.com/v0/topstories.json'
|
hackernews.topstories_url = 'https://hacker-news.firebaseio.com/v0/topstories.json'
|
||||||
hackernews.res_url = 'https://hacker-news.firebaseio.com/v0/item/%s.json'
|
hackernews.res_url = 'https://hacker-news.firebaseio.com/v0/item/%s.json'
|
||||||
hackernews.art_url = 'https://news.ycombinator.com/item?id=%s'
|
hackernews.art_url = 'https://news.ycombinator.com/item?id=%s'
|
||||||
hackernews.last_update = 0
|
hackernews.last_update = 0
|
||||||
if config.hackernews_onstart == true then
|
if config.hackernews_onstart == true then
|
||||||
hackernews.results = get_hackernews_results()
|
hackernews.results = get_hackernews_results()
|
||||||
if hackernews.results then hackernews.last_update = os.time() / 60 end
|
if hackernews.results then hackernews.last_update = os.time() / 60 end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function hackernews:action(msg, config)
|
function hackernews:action(msg, config)
|
||||||
local now = os.time() / 60
|
local now = os.time() / 60
|
||||||
if not hackernews.results or hackernews.last_update + config.hackernews_interval < now then
|
if not hackernews.results or hackernews.last_update + config.hackernews_interval < now then
|
||||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' })
|
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' })
|
||||||
hackernews.results = get_hackernews_results()
|
hackernews.results = get_hackernews_results()
|
||||||
if not hackernews.results then
|
if not hackernews.results then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
hackernews.last_update = now
|
hackernews.last_update = now
|
||||||
end
|
end
|
||||||
-- Four results in a group, eight in private.
|
-- Four results in a group, eight in private.
|
||||||
local res_count = msg.chat.id == msg.from.id and 8 or 4
|
local res_count = msg.chat.id == msg.from.id and 8 or 4
|
||||||
local output = '<b>Top Stories from Hacker News:</b>'
|
local output = '<b>Top Stories from Hacker News:</b>'
|
||||||
for i = 1, res_count do
|
for i = 1, res_count do
|
||||||
output = output .. hackernews.results[i]
|
output = output .. hackernews.results[i]
|
||||||
end
|
end
|
||||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||||
end
|
end
|
||||||
|
|
||||||
return hackernews
|
return hackernews
|
||||||
|
@ -8,111 +8,111 @@ local utilities = require('otouto.utilities')
|
|||||||
local HTTPS = require('ssl.https')
|
local HTTPS = require('ssl.https')
|
||||||
|
|
||||||
function hearthstone:init(config)
|
function hearthstone:init(config)
|
||||||
hearthstone.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hearthstone', true):t('hs').table
|
hearthstone.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hearthstone', true):t('hs').table
|
||||||
hearthstone.command = 'hearthstone <query>'
|
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')
|
local jstr, res = HTTPS.request('https://api.hearthstonejson.com/v1/latest/enUS/cards.json')
|
||||||
if not jstr or res ~= 200 then
|
if not jstr or res ~= 200 then
|
||||||
print('Error connecting to hearthstonejson.com.')
|
print('Error connecting to hearthstonejson.com.')
|
||||||
print('hearthstone.lua will not be enabled.')
|
print('hearthstone.lua will not be enabled.')
|
||||||
hearthstone.command = nil
|
hearthstone.command = nil
|
||||||
hearthstone.triggers = nil
|
hearthstone.triggers = nil
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self.database.hearthstone = JSON.decode(jstr)
|
self.database.hearthstone = JSON.decode(jstr)
|
||||||
self.database.hearthstone.expiration = os.time() + 600000
|
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.
|
Returns Hearthstone card info.
|
||||||
Alias: ]] .. config.cmd_pat .. 'hs'
|
Alias: ]] .. config.cmd_pat .. 'hs'
|
||||||
end
|
end
|
||||||
|
|
||||||
local function format_card(card)
|
local function format_card(card)
|
||||||
|
|
||||||
local ctype = card.type
|
local ctype = card.type
|
||||||
if card.race then
|
if card.race then
|
||||||
ctype = card.race
|
ctype = card.race
|
||||||
end
|
end
|
||||||
if card.rarity then
|
if card.rarity then
|
||||||
ctype = card.rarity .. ' ' .. ctype
|
ctype = card.rarity .. ' ' .. ctype
|
||||||
end
|
end
|
||||||
if card.playerClass then
|
if card.playerClass then
|
||||||
ctype = ctype .. ' (' .. card.playerClass .. ')'
|
ctype = ctype .. ' (' .. card.playerClass .. ')'
|
||||||
elseif card.faction then
|
elseif card.faction then
|
||||||
ctype = ctype .. ' (' .. card.faction .. ')'
|
ctype = ctype .. ' (' .. card.faction .. ')'
|
||||||
end
|
end
|
||||||
|
|
||||||
local stats
|
local stats
|
||||||
if card.cost then
|
if card.cost then
|
||||||
stats = card.cost .. 'c'
|
stats = card.cost .. 'c'
|
||||||
if card.attack then
|
if card.attack then
|
||||||
stats = stats .. ' | ' .. card.attack .. 'a'
|
stats = stats .. ' | ' .. card.attack .. 'a'
|
||||||
end
|
end
|
||||||
if card.health then
|
if card.health then
|
||||||
stats = stats .. ' | ' .. card.health .. 'h'
|
stats = stats .. ' | ' .. card.health .. 'h'
|
||||||
end
|
end
|
||||||
if card.durability then
|
if card.durability then
|
||||||
stats = stats .. ' | ' .. card.durability .. 'd'
|
stats = stats .. ' | ' .. card.durability .. 'd'
|
||||||
end
|
end
|
||||||
elseif card.health then
|
elseif card.health then
|
||||||
stats = card.health .. 'h'
|
stats = card.health .. 'h'
|
||||||
end
|
end
|
||||||
|
|
||||||
-- unused?
|
-- unused?
|
||||||
local info
|
local info
|
||||||
if card.text then
|
if card.text then
|
||||||
info = card.text:gsub('</?.->',''):gsub('%$','')
|
info = card.text:gsub('</?.->',''):gsub('%$','')
|
||||||
if card.flavor then
|
if card.flavor then
|
||||||
info = info .. '\n_' .. card.flavor .. '_'
|
info = info .. '\n_' .. card.flavor .. '_'
|
||||||
end
|
end
|
||||||
elseif card.flavor then
|
elseif card.flavor then
|
||||||
info = card.flavor
|
info = card.flavor
|
||||||
else
|
else
|
||||||
info = nil
|
info = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local s = '*' .. card.name .. '*\n' .. ctype
|
local s = '*' .. card.name .. '*\n' .. ctype
|
||||||
if stats then
|
if stats then
|
||||||
s = s .. '\n' .. stats
|
s = s .. '\n' .. stats
|
||||||
end
|
end
|
||||||
if info then
|
if info then
|
||||||
s = s .. '\n' .. info
|
s = s .. '\n' .. info
|
||||||
end
|
end
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function hearthstone:action(msg, config)
|
function hearthstone:action(msg, config)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, hearthstone.doc, true)
|
utilities.send_reply(self, msg, hearthstone.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = ''
|
local output = ''
|
||||||
for _,v in pairs(self.database.hearthstone) do
|
for _,v in pairs(self.database.hearthstone) do
|
||||||
if type(v) == 'table' and string.lower(v.name):match(input) then
|
if type(v) == 'table' and string.lower(v.name):match(input) then
|
||||||
output = output .. format_card(v) .. '\n\n'
|
output = output .. format_card(v) .. '\n\n'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
output = utilities.trim(output)
|
output = utilities.trim(output)
|
||||||
if output:len() == 0 then
|
if output:len() == 0 then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
@ -3,51 +3,51 @@ local utilities = require('otouto.utilities')
|
|||||||
local help = {}
|
local help = {}
|
||||||
|
|
||||||
function help:init(config)
|
function help:init(config)
|
||||||
help.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('help', true):t('h', true).table
|
help.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('help', true):t('h', true).table
|
||||||
help.command = 'help [command]'
|
help.command = 'help [command]'
|
||||||
help.doc = config.cmd_pat .. 'help [command] \nReturns usage information for a given command.'
|
help.doc = config.cmd_pat .. 'help [command] \nReturns usage information for a given command.'
|
||||||
end
|
end
|
||||||
|
|
||||||
function help:action(msg, config)
|
function help:action(msg, config)
|
||||||
local input = utilities.input(msg.text_lower)
|
local input = utilities.input(msg.text_lower)
|
||||||
if input then
|
if input then
|
||||||
if not help.help_word then
|
if not help.help_word then
|
||||||
for _, plugin in ipairs(self.plugins) do
|
for _, plugin in ipairs(self.plugins) do
|
||||||
if plugin.command and plugin.doc and not plugin.help_word then
|
if plugin.command and plugin.doc and not plugin.help_word then
|
||||||
plugin.help_word = utilities.get_word(plugin.command, 1)
|
plugin.help_word = utilities.get_word(plugin.command, 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for _,plugin in ipairs(self.plugins) do
|
for _,plugin in ipairs(self.plugins) do
|
||||||
if plugin.help_word == input:gsub('^/', '') then
|
if plugin.help_word == input:gsub('^/', '') then
|
||||||
local output = '*Help for* _' .. plugin.help_word .. '_*:*\n' .. plugin.doc
|
local output = '*Help for* _' .. plugin.help_word .. '_*:*\n' .. plugin.doc
|
||||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
utilities.send_reply(self, msg, 'Sorry, there is no help for that command.')
|
utilities.send_reply(self, msg, 'Sorry, there is no help for that command.')
|
||||||
else
|
else
|
||||||
-- Generate the help message on first run.
|
-- Generate the help message on first run.
|
||||||
if not help.text then
|
if not help.text then
|
||||||
local commandlist = {}
|
local commandlist = {}
|
||||||
for _, plugin in ipairs(self.plugins) do
|
for _, plugin in ipairs(self.plugins) do
|
||||||
if plugin.command then
|
if plugin.command then
|
||||||
table.insert(commandlist, plugin.command)
|
table.insert(commandlist, plugin.command)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.sort(commandlist)
|
table.sort(commandlist)
|
||||||
help.text = '*Available commands:*\n• ' .. config.cmd_pat .. table.concat(commandlist, '\n• '..config.cmd_pat) .. '\nArguments: <required> [optional]'
|
help.text = '*Available commands:*\n• ' .. config.cmd_pat .. table.concat(commandlist, '\n• '..config.cmd_pat) .. '\nArguments: <required> [optional]'
|
||||||
help.text = help.text:gsub('%[', '\\[')
|
help.text = help.text:gsub('%[', '\\[')
|
||||||
end
|
end
|
||||||
-- Attempt to send the help message via PM.
|
-- Attempt to send the help message via PM.
|
||||||
-- If msg is from a group, tell the group whether the PM was successful.
|
-- If msg is from a group, tell the group whether the PM was successful.
|
||||||
local res = utilities.send_message(self, msg.from.id, help.text, true, nil, true)
|
local res = utilities.send_message(self, msg.from.id, help.text, true, nil, true)
|
||||||
if not res then
|
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)
|
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
|
elseif msg.chat.type ~= 'private' then
|
||||||
utilities.send_reply(self, msg, 'I have sent you the requested information in a private message.')
|
utilities.send_reply(self, msg, 'I have sent you the requested information in a private message.')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return help
|
return help
|
||||||
|
@ -3,60 +3,60 @@ local utilities = require('otouto.utilities')
|
|||||||
local id = {}
|
local id = {}
|
||||||
|
|
||||||
function id:init(config)
|
function id:init(config)
|
||||||
id.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('id', true).table
|
id.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('id', true).table
|
||||||
id.command = 'id <user>'
|
id.command = 'id <user>'
|
||||||
id.doc = config.cmd_pat .. [[id <user> ...
|
id.doc = config.cmd_pat .. [[id <user> ...
|
||||||
Returns the name, ID, and username (if applicable) for the given users.
|
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.
|
Arguments must be usernames and/or IDs. Input is also accepted via reply. If no input is given, returns info for the user.
|
||||||
]]
|
]]
|
||||||
end
|
end
|
||||||
|
|
||||||
function id.format(t)
|
function id.format(t)
|
||||||
if t.username then
|
if t.username then
|
||||||
return string.format(
|
return string.format(
|
||||||
'@%s, AKA <b>%s</b> <code>[%s]</code>.\n',
|
'@%s, AKA <b>%s</b> <code>[%s]</code>.\n',
|
||||||
t.username,
|
t.username,
|
||||||
utilities.build_name(t.first_name, t.last_name),
|
utilities.build_name(t.first_name, t.last_name),
|
||||||
t.id
|
t.id
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
return string.format(
|
return string.format(
|
||||||
'<b>%s</b> <code>[%s]</code>.\n',
|
'<b>%s</b> <code>[%s]</code>.\n',
|
||||||
utilities.build_name(t.first_name, t.last_name),
|
utilities.build_name(t.first_name, t.last_name),
|
||||||
t.id
|
t.id
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function id:action(msg)
|
function id:action(msg)
|
||||||
local output
|
local output
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
if msg.reply_to_message then
|
if msg.reply_to_message then
|
||||||
output = id.format(msg.reply_to_message.from)
|
output = id.format(msg.reply_to_message.from)
|
||||||
elseif input then
|
elseif input then
|
||||||
output = ''
|
output = ''
|
||||||
for user in input:gmatch('%g+') do
|
for user in input:gmatch('%g+') do
|
||||||
if tonumber(user) then
|
if tonumber(user) then
|
||||||
if self.database.users[user] then
|
if self.database.users[user] then
|
||||||
output = output .. id.format(self.database.users[user])
|
output = output .. id.format(self.database.users[user])
|
||||||
else
|
else
|
||||||
output = output .. 'I don\'t recognize that ID (' .. user .. ').\n'
|
output = output .. 'I don\'t recognize that ID (' .. user .. ').\n'
|
||||||
end
|
end
|
||||||
elseif user:match('^@') then
|
elseif user:match('^@') then
|
||||||
local t = utilities.resolve_username(self, user)
|
local t = utilities.resolve_username(self, user)
|
||||||
if t then
|
if t then
|
||||||
output = output .. id.format(t)
|
output = output .. id.format(t)
|
||||||
else
|
else
|
||||||
output = output .. 'I don\'t recognize that username (' .. user .. ').\n'
|
output = output .. 'I don\'t recognize that username (' .. user .. ').\n'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
output = output .. 'Invalid username or ID (' .. user .. ').\n'
|
output = output .. 'Invalid username or ID (' .. user .. ').\n'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
output = id.format(msg.from)
|
output = id.format(msg.from)
|
||||||
end
|
end
|
||||||
utilities.send_reply(self, msg, output, 'html')
|
utilities.send_reply(self, msg, output, 'html')
|
||||||
end
|
end
|
||||||
|
|
||||||
return id
|
return id
|
||||||
|
@ -8,39 +8,39 @@ local utilities = require('otouto.utilities')
|
|||||||
imdb.command = 'imdb <query>'
|
imdb.command = 'imdb <query>'
|
||||||
|
|
||||||
function imdb:init(config)
|
function imdb:init(config)
|
||||||
imdb.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('imdb', true).table
|
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.doc = config.cmd_pat .. 'imdb <query> \nReturns an IMDb entry.'
|
||||||
end
|
end
|
||||||
|
|
||||||
function imdb:action(msg, config)
|
function imdb:action(msg, config)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, imdb.doc, true)
|
utilities.send_reply(self, msg, imdb.doc, true)
|
||||||
return
|
return
|
||||||
end
|
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)
|
local jstr, res = HTTP.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local jdat = JSON.decode(jstr)
|
local jdat = JSON.decode(jstr)
|
||||||
|
|
||||||
if jdat.Response ~= 'True' then
|
if jdat.Response ~= 'True' then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = '*' .. jdat.Title .. ' ('.. jdat.Year ..')*\n'
|
local output = '*' .. jdat.Title .. ' ('.. jdat.Year ..')*\n'
|
||||||
output = output .. jdat.imdbRating ..'/10 | '.. jdat.Runtime ..' | '.. jdat.Genre ..'\n'
|
output = output .. jdat.imdbRating ..'/10 | '.. jdat.Runtime ..' | '.. jdat.Genre ..'\n'
|
||||||
output = output .. '_' .. jdat.Plot .. '_\n'
|
output = output .. '_' .. jdat.Plot .. '_\n'
|
||||||
output = output .. '[Read more.](http://imdb.com/title/' .. jdat.imdbID .. ')'
|
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
|
end
|
||||||
|
|
||||||
|
@ -7,37 +7,37 @@ local utilities = require('otouto.utilities')
|
|||||||
local isup = {}
|
local isup = {}
|
||||||
|
|
||||||
function isup:init(config)
|
function isup:init(config)
|
||||||
isup.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
isup.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('websitedown', true):t('isitup', true):t('isup', true).table
|
: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.]]
|
Returns the up or down status of a website.]]
|
||||||
isup.command = 'isup <url>'
|
isup.command = 'isup <url>'
|
||||||
end
|
end
|
||||||
|
|
||||||
function isup:action(msg, config)
|
function isup:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, isup.doc)
|
utilities.send_reply(self, msg, isup.doc)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local protocol = HTTP
|
local protocol = HTTP
|
||||||
local url_lower = input:lower()
|
local url_lower = input:lower()
|
||||||
if url_lower:match('^https') then
|
if url_lower:match('^https') then
|
||||||
protocol = HTTPS
|
protocol = HTTPS
|
||||||
elseif not url_lower:match('^http') then
|
elseif not url_lower:match('^http') then
|
||||||
input = 'http://' .. input
|
input = 'http://' .. input
|
||||||
end
|
end
|
||||||
local _, code = protocol.request(input)
|
local _, code = protocol.request(input)
|
||||||
code = tonumber(code)
|
code = tonumber(code)
|
||||||
local output
|
local output
|
||||||
if not code or code > 399 then
|
if not code or code > 399 then
|
||||||
output = 'This website is down or nonexistent.'
|
output = 'This website is down or nonexistent.'
|
||||||
else
|
else
|
||||||
output = 'This website is up.'
|
output = 'This website is up.'
|
||||||
end
|
end
|
||||||
utilities.send_reply(self, msg, output, true)
|
utilities.send_reply(self, msg, output, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
return isup
|
return isup
|
||||||
|
@ -9,12 +9,12 @@ local JSON = require('dkjson')
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function lastfm:init(config)
|
function lastfm:init(config)
|
||||||
assert(config.lastfm_api_key,
|
assert(config.lastfm_api_key,
|
||||||
'lastfm.lua requires a last.fm API key from http://last.fm/api.'
|
'lastfm.lua requires a last.fm API key from http://last.fm/api.'
|
||||||
)
|
)
|
||||||
|
|
||||||
lastfm.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lastfm', true):t('np', true):t('fmset', true).table
|
lastfm.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lastfm', true):t('np', true):t('fmset', true).table
|
||||||
lastfm.doc = config.cmd_pat .. [[np [username]
|
lastfm.doc = config.cmd_pat .. [[np [username]
|
||||||
Returns what you are or were last listening to. If you specify a username, info will be returned for that username.
|
Returns what you are or were last listening to. If you specify a username, info will be returned for that username.
|
||||||
|
|
||||||
]] .. config.cmd_pat .. [[fmset <username>
|
]] .. config.cmd_pat .. [[fmset <username>
|
||||||
@ -25,84 +25,84 @@ lastfm.command = 'lastfm'
|
|||||||
|
|
||||||
function lastfm:action(msg, config)
|
function lastfm:action(msg, config)
|
||||||
|
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
local from_id_str = tostring(msg.from.id)
|
local from_id_str = tostring(msg.from.id)
|
||||||
self.database.userdata[from_id_str] = self.database.userdata[from_id_str] or {}
|
self.database.userdata[from_id_str] = self.database.userdata[from_id_str] or {}
|
||||||
|
|
||||||
if string.match(msg.text, '^'..config.cmd_pat..'lastfm') then
|
if string.match(msg.text, '^'..config.cmd_pat..'lastfm') then
|
||||||
utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true)
|
utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true)
|
||||||
return
|
return
|
||||||
elseif string.match(msg.text, '^'..config.cmd_pat..'fmset') then
|
elseif string.match(msg.text, '^'..config.cmd_pat..'fmset') then
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true)
|
utilities.send_message(self, msg.chat.id, lastfm.doc, true, msg.message_id, true)
|
||||||
elseif input == '--' or input == utilities.char.em_dash then
|
elseif input == '--' or input == utilities.char.em_dash then
|
||||||
self.database.userdata[from_id_str].lastfm = nil
|
self.database.userdata[from_id_str].lastfm = nil
|
||||||
utilities.send_reply(self, msg, 'Your last.fm username has been forgotten.')
|
utilities.send_reply(self, msg, 'Your last.fm username has been forgotten.')
|
||||||
else
|
else
|
||||||
self.database.userdata[from_id_str].lastfm = input
|
self.database.userdata[from_id_str].lastfm = input
|
||||||
utilities.send_reply(self, msg, 'Your last.fm username has been set to "' .. input .. '".')
|
utilities.send_reply(self, msg, 'Your last.fm username has been set to "' .. input .. '".')
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key=' .. config.lastfm_api_key .. '&user='
|
local url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key=' .. config.lastfm_api_key .. '&user='
|
||||||
|
|
||||||
local username
|
local username
|
||||||
local alert = ''
|
local alert = ''
|
||||||
if input then
|
if input then
|
||||||
username = input
|
username = input
|
||||||
elseif self.database.userdata[from_id_str].lastfm then
|
elseif self.database.userdata[from_id_str].lastfm then
|
||||||
username = self.database.userdata[from_id_str].lastfm
|
username = self.database.userdata[from_id_str].lastfm
|
||||||
elseif msg.from.username then
|
elseif msg.from.username then
|
||||||
username = msg.from.username
|
username = msg.from.username
|
||||||
alert = '\n\nYour username has been set to ' .. username .. '.\nTo change it, use '..config.cmd_pat..'fmset <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
|
self.database.userdata[from_id_str].lastfm = username
|
||||||
else
|
else
|
||||||
utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with '..config.cmd_pat..'fmset.')
|
utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with '..config.cmd_pat..'fmset.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
url = url .. URL.escape(username)
|
url = url .. URL.escape(username)
|
||||||
|
|
||||||
local jstr, res
|
local jstr, res
|
||||||
utilities.with_http_timeout(
|
utilities.with_http_timeout(
|
||||||
1, function ()
|
1, function ()
|
||||||
jstr, res = HTTP.request(url)
|
jstr, res = HTTP.request(url)
|
||||||
end)
|
end)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local jdat = JSON.decode(jstr)
|
local jdat = JSON.decode(jstr)
|
||||||
if jdat.error then
|
if jdat.error then
|
||||||
utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with '..config.cmd_pat..'fmset.')
|
utilities.send_reply(self, msg, 'Please specify your last.fm username or set it with '..config.cmd_pat..'fmset.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track
|
jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track
|
||||||
if not jdat then
|
if not jdat then
|
||||||
utilities.send_reply(self, msg, 'No history for this user.' .. alert)
|
utilities.send_reply(self, msg, 'No history for this user.' .. alert)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = input or msg.from.first_name
|
local output = input or msg.from.first_name
|
||||||
output = '🎵 ' .. output
|
output = '🎵 ' .. output
|
||||||
|
|
||||||
if jdat['@attr'] and jdat['@attr'].nowplaying then
|
if jdat['@attr'] and jdat['@attr'].nowplaying then
|
||||||
output = output .. ' is currently listening to:\n'
|
output = output .. ' is currently listening to:\n'
|
||||||
else
|
else
|
||||||
output = output .. ' last listened to:\n'
|
output = output .. ' last listened to:\n'
|
||||||
end
|
end
|
||||||
|
|
||||||
local title = jdat.name or 'Unknown'
|
local title = jdat.name or 'Unknown'
|
||||||
local artist = 'Unknown'
|
local artist = 'Unknown'
|
||||||
if jdat.artist then
|
if jdat.artist then
|
||||||
artist = jdat.artist['#text']
|
artist = jdat.artist['#text']
|
||||||
end
|
end
|
||||||
|
|
||||||
output = output .. title .. ' - ' .. artist .. alert
|
output = output .. title .. ' - ' .. artist .. alert
|
||||||
utilities.send_message(self, msg.chat.id, output)
|
utilities.send_message(self, msg.chat.id, output)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,59 +5,59 @@ local URL = require('socket.url')
|
|||||||
local JSON, serpent
|
local JSON, serpent
|
||||||
|
|
||||||
function luarun:init(config)
|
function luarun:init(config)
|
||||||
luarun.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lua', true):t('return', true).table
|
luarun.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lua', true):t('return', true).table
|
||||||
if config.luarun_serpent then
|
if config.luarun_serpent then
|
||||||
serpent = require('serpent')
|
serpent = require('serpent')
|
||||||
luarun.serialize = function(t)
|
luarun.serialize = function(t)
|
||||||
return serpent.block(t, {comment=false})
|
return serpent.block(t, {comment=false})
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
JSON = require('dkjson')
|
JSON = require('dkjson')
|
||||||
luarun.serialize = function(t)
|
luarun.serialize = function(t)
|
||||||
return JSON.encode(t, {indent=true})
|
return JSON.encode(t, {indent=true})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function luarun:action(msg, config)
|
function luarun:action(msg, config)
|
||||||
|
|
||||||
if msg.from.id ~= config.admin then
|
if msg.from.id ~= config.admin then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, 'Please enter a string to load.')
|
utilities.send_reply(self, msg, 'Please enter a string to load.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if msg.text_lower:match('^'..config.cmd_pat..'return') then
|
if msg.text_lower:match('^'..config.cmd_pat..'return') then
|
||||||
input = 'return ' .. input
|
input = 'return ' .. input
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = loadstring( [[
|
local output = loadstring( [[
|
||||||
local bot = require('otouto.bot')
|
local bot = require('otouto.bot')
|
||||||
local bindings = require('otouto.bindings')
|
local bindings = require('otouto.bindings')
|
||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
local drua = require('otouto.drua-tg')
|
local drua = require('otouto.drua-tg')
|
||||||
local JSON = require('dkjson')
|
local JSON = require('dkjson')
|
||||||
local URL = require('socket.url')
|
local URL = require('socket.url')
|
||||||
local HTTP = require('socket.http')
|
local HTTP = require('socket.http')
|
||||||
local HTTPS = require('ssl.https')
|
local HTTPS = require('ssl.https')
|
||||||
return function (self, msg, config) ]] .. input .. [[ end
|
return function (self, msg, config) ]] .. input .. [[ end
|
||||||
]] )()(self, msg, config)
|
]] )()(self, msg, config)
|
||||||
if output == nil then
|
if output == nil then
|
||||||
output = 'Done!'
|
output = 'Done!'
|
||||||
else
|
else
|
||||||
if type(output) == 'table' then
|
if type(output) == 'table' then
|
||||||
local s = luarun.serialize(output)
|
local s = luarun.serialize(output)
|
||||||
if URL.escape(s):len() < 4000 then
|
if URL.escape(s):len() < 4000 then
|
||||||
output = s
|
output = s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
output = '```\n' .. tostring(output) .. '\n```'
|
output = '```\n' .. tostring(output) .. '\n```'
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
@ -3,65 +3,65 @@ local me = {}
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function me:init(config)
|
function me:init(config)
|
||||||
me.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('me', true).table
|
me.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('me', true).table
|
||||||
me.command = 'me'
|
me.command = 'me'
|
||||||
me.doc = 'Returns userdata stored by the bot.'
|
me.doc = 'Returns userdata stored by the bot.'
|
||||||
end
|
end
|
||||||
|
|
||||||
function me:action(msg, config)
|
function me:action(msg, config)
|
||||||
local user
|
local user
|
||||||
if msg.from.id == config.admin then
|
if msg.from.id == config.admin then
|
||||||
if msg.reply_to_message then
|
if msg.reply_to_message then
|
||||||
user = msg.reply_to_message.from
|
user = msg.reply_to_message.from
|
||||||
else
|
else
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
if input then
|
if input then
|
||||||
if tonumber(input) then
|
if tonumber(input) then
|
||||||
user = self.database.users[input]
|
user = self.database.users[input]
|
||||||
if not user then
|
if not user then
|
||||||
utilities.send_reply(self, msg, 'Unrecognized ID.')
|
utilities.send_reply(self, msg, 'Unrecognized ID.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
elseif input:match('^@') then
|
elseif input:match('^@') then
|
||||||
user = utilities.resolve_username(self, input)
|
user = utilities.resolve_username(self, input)
|
||||||
if not user then
|
if not user then
|
||||||
utilities.send_reply(self, msg, 'Unrecognized username.')
|
utilities.send_reply(self, msg, 'Unrecognized username.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
utilities.send_reply(self, msg, 'Invalid username or ID.')
|
utilities.send_reply(self, msg, 'Invalid username or ID.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
user = user or msg.from
|
user = user or msg.from
|
||||||
local userdata = self.database.userdata[tostring(user.id)] or {}
|
local userdata = self.database.userdata[tostring(user.id)] or {}
|
||||||
|
|
||||||
local data = {}
|
local data = {}
|
||||||
for k,v in pairs(userdata) do
|
for k,v in pairs(userdata) do
|
||||||
table.insert(data, string.format(
|
table.insert(data, string.format(
|
||||||
'<b>%s</b> <code>%s</code>\n',
|
'<b>%s</b> <code>%s</code>\n',
|
||||||
utilities.html_escape(k),
|
utilities.html_escape(k),
|
||||||
utilities.html_escape(v)
|
utilities.html_escape(v)
|
||||||
))
|
))
|
||||||
end
|
end
|
||||||
|
|
||||||
local output
|
local output
|
||||||
if #data == 0 then
|
if #data == 0 then
|
||||||
output = 'There is no data stored for this user.'
|
output = 'There is no data stored for this user.'
|
||||||
else
|
else
|
||||||
output = string.format(
|
output = string.format(
|
||||||
'<b>%s</b> <code>[%s]</code><b>:</b>\n',
|
'<b>%s</b> <code>[%s]</code><b>:</b>\n',
|
||||||
utilities.html_escape(utilities.build_name(
|
utilities.html_escape(utilities.build_name(
|
||||||
user.first_name,
|
user.first_name,
|
||||||
user.last_name
|
user.last_name
|
||||||
)),
|
)),
|
||||||
user.id
|
user.id
|
||||||
) .. table.concat(data)
|
) .. table.concat(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,45 +5,45 @@ local utilities = require('otouto.utilities')
|
|||||||
nick.command = 'nick <nickname>'
|
nick.command = 'nick <nickname>'
|
||||||
|
|
||||||
function nick:init(config)
|
function nick:init(config)
|
||||||
nick.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('nick', true).table
|
nick.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('nick', true).table
|
||||||
nick.doc = config.cmd_pat .. [[nick <nickname>
|
nick.doc = config.cmd_pat .. [[nick <nickname>
|
||||||
Set your nickname. Use "]] .. config.cmd_pat .. 'nick --" to delete it.'
|
Set your nickname. Use "]] .. config.cmd_pat .. 'nick --" to delete it.'
|
||||||
end
|
end
|
||||||
|
|
||||||
function nick:action(msg, config)
|
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
|
if msg.from.id == config.admin and msg.reply_to_message then
|
||||||
id_str = tostring(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)
|
name = utilities.build_name(msg.reply_to_message.from.first_name, msg.reply_to_message.from.last_name)
|
||||||
else
|
else
|
||||||
id_str = tostring(msg.from.id)
|
id_str = tostring(msg.from.id)
|
||||||
name = utilities.build_name(msg.from.first_name, msg.from.last_name)
|
name = utilities.build_name(msg.from.first_name, msg.from.last_name)
|
||||||
end
|
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 output
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
if not input then
|
if not input then
|
||||||
if self.database.userdata[id_str].nickname then
|
if self.database.userdata[id_str].nickname then
|
||||||
output = name .. '\'s nickname is "' .. self.database.userdata[id_str].nickname .. '".'
|
output = name .. '\'s nickname is "' .. self.database.userdata[id_str].nickname .. '".'
|
||||||
else
|
else
|
||||||
output = name .. ' currently has no nickname.'
|
output = name .. ' currently has no nickname.'
|
||||||
end
|
end
|
||||||
elseif utilities.utf8_len(input) > 32 then
|
elseif utilities.utf8_len(input) > 32 then
|
||||||
output = 'The character limit for nicknames is 32.'
|
output = 'The character limit for nicknames is 32.'
|
||||||
elseif input == '--' or input == utilities.char.em_dash then
|
elseif input == '--' or input == utilities.char.em_dash then
|
||||||
self.database.userdata[id_str].nickname = nil
|
self.database.userdata[id_str].nickname = nil
|
||||||
output = name .. '\'s nickname has been deleted.'
|
output = name .. '\'s nickname has been deleted.'
|
||||||
else
|
else
|
||||||
input = input:gsub('\n', ' ')
|
input = input:gsub('\n', ' ')
|
||||||
self.database.userdata[id_str].nickname = input
|
self.database.userdata[id_str].nickname = input
|
||||||
output = name .. '\'s nickname has been set to "' .. input .. '".'
|
output = name .. '\'s nickname has been set to "' .. input .. '".'
|
||||||
end
|
end
|
||||||
|
|
||||||
utilities.send_reply(self, msg, output)
|
utilities.send_reply(self, msg, output)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -8,34 +8,34 @@ patterns.doc = [[
|
|||||||
s/<pattern>/<substitution>
|
s/<pattern>/<substitution>
|
||||||
Replace all matches for the given pattern.
|
Replace all matches for the given pattern.
|
||||||
Uses Lua patterns.
|
Uses Lua patterns.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
function patterns:init(config)
|
function patterns:init(config)
|
||||||
patterns.triggers = { config.cmd_pat .. '?s/.-/.-$' }
|
patterns.triggers = { config.cmd_pat .. '?s/.-/.-$' }
|
||||||
end
|
end
|
||||||
|
|
||||||
function patterns:action(msg)
|
function patterns:action(msg)
|
||||||
if not msg.reply_to_message then return true end
|
if not msg.reply_to_message then return true end
|
||||||
local output = msg.reply_to_message.text
|
local output = msg.reply_to_message.text
|
||||||
if msg.reply_to_message.from.id == self.info.id then
|
if msg.reply_to_message.from.id == self.info.id then
|
||||||
output = output:gsub('Did you mean:\n"', '')
|
output = output:gsub('Did you mean:\n"', '')
|
||||||
output = output:gsub('"$', '')
|
output = output:gsub('"$', '')
|
||||||
end
|
end
|
||||||
local m1, m2 = msg.text:match('^/?s/(.-)/(.-)/?$')
|
local m1, m2 = msg.text:match('^/?s/(.-)/(.-)/?$')
|
||||||
if not m2 then return true end
|
if not m2 then return true end
|
||||||
local res
|
local res
|
||||||
res, output = pcall(
|
res, output = pcall(
|
||||||
function()
|
function()
|
||||||
return output:gsub(m1, m2)
|
return output:gsub(m1, m2)
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
if res == false then
|
if res == false then
|
||||||
utilities.send_reply(self, msg, 'Malformed pattern!')
|
utilities.send_reply(self, msg, 'Malformed pattern!')
|
||||||
else
|
else
|
||||||
output = utilities.trim(output:sub(1, 4000))
|
output = utilities.trim(output:sub(1, 4000))
|
||||||
output = utilities.style.enquote('Did you mean', output)
|
output = utilities.style.enquote('Did you mean', output)
|
||||||
utilities.send_reply(self, msg.reply_to_message, output, true)
|
utilities.send_reply(self, msg.reply_to_message, output, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return patterns
|
return patterns
|
||||||
|
@ -5,12 +5,12 @@ local ping = {}
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function ping:init(config)
|
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
|
end
|
||||||
|
|
||||||
function ping:action(msg, config)
|
function ping:action(msg, config)
|
||||||
local output = msg.text_lower:match('^'..config.cmd_pat..'ping') and 'Pong!' or 'Annyong.'
|
local output = msg.text_lower:match('^'..config.cmd_pat..'ping') and 'Pong!' or 'Annyong.'
|
||||||
utilities.send_message(self, msg.chat.id, output)
|
utilities.send_message(self, msg.chat.id, output)
|
||||||
end
|
end
|
||||||
|
|
||||||
return ping
|
return ping
|
||||||
|
@ -8,8 +8,8 @@ local utilities = require('otouto.utilities')
|
|||||||
pokedex.command = 'pokedex <query>'
|
pokedex.command = 'pokedex <query>'
|
||||||
|
|
||||||
function pokedex:init(config)
|
function pokedex:init(config)
|
||||||
pokedex.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('pokedex', true):t('dex', true).table
|
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.doc = config.cmd_pat .. [[pokedex <query>
|
||||||
Returns a Pokedex entry from pokeapi.co.
|
Returns a Pokedex entry from pokeapi.co.
|
||||||
Queries must be a number of the name of a Pokémon.
|
Queries must be a number of the name of a Pokémon.
|
||||||
Alias: ]] .. config.cmd_pat .. 'dex'
|
Alias: ]] .. config.cmd_pat .. 'dex'
|
||||||
@ -17,54 +17,54 @@ end
|
|||||||
|
|
||||||
function pokedex:action(msg, config)
|
function pokedex:action(msg, config)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, pokedex.doc, true)
|
utilities.send_reply(self, msg, pokedex.doc, true)
|
||||||
return
|
return
|
||||||
end
|
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_url = url .. '/api/v1/pokemon/' .. input
|
||||||
local dex_jstr, res = HTTP.request(dex_url)
|
local dex_jstr, res = HTTP.request(dex_url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
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
|
if not dex_jdat.descriptions or not dex_jdat.descriptions[1] then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local desc_url = url .. dex_jdat.descriptions[math.random(#dex_jdat.descriptions)].resource_uri
|
local desc_url = url .. dex_jdat.descriptions[math.random(#dex_jdat.descriptions)].resource_uri
|
||||||
local desc_jstr, _ = HTTP.request(desc_url)
|
local desc_jstr, _ = HTTP.request(desc_url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local desc_jdat = JSON.decode(desc_jstr)
|
local desc_jdat = JSON.decode(desc_jstr)
|
||||||
|
|
||||||
local poke_type
|
local poke_type
|
||||||
for _,v in ipairs(dex_jdat.types) do
|
for _,v in ipairs(dex_jdat.types) do
|
||||||
local type_name = v.name:gsub("^%l", string.upper)
|
local type_name = v.name:gsub("^%l", string.upper)
|
||||||
if not poke_type then
|
if not poke_type then
|
||||||
poke_type = type_name
|
poke_type = type_name
|
||||||
else
|
else
|
||||||
poke_type = poke_type .. ' / ' .. type_name
|
poke_type = poke_type .. ' / ' .. type_name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
poke_type = poke_type .. ' type'
|
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
|
end
|
||||||
|
|
||||||
|
@ -3,110 +3,110 @@ local utilities = require('otouto.utilities')
|
|||||||
local pgc = {}
|
local pgc = {}
|
||||||
|
|
||||||
function pgc:init(config)
|
function pgc:init(config)
|
||||||
pgc.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('gocalc', true).table
|
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.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.
|
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.
|
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):
|
Example (forty pidgeys and three hundred pidgey candies):
|
||||||
]] .. config.cmd_pat .. 'gocalc 12 40 300'
|
]] .. config.cmd_pat .. 'gocalc 12 40 300'
|
||||||
pgc.command = 'gocalc <required candy> <#pokemon> <#candy>'
|
pgc.command = 'gocalc <required candy> <#pokemon> <#candy>'
|
||||||
end
|
end
|
||||||
|
|
||||||
-- This function written by Juan Potato. MIT-licensed.
|
-- This function written by Juan Potato. MIT-licensed.
|
||||||
local pidgey_calc = function(candies_to_evolve, mons, candies)
|
local pidgey_calc = function(candies_to_evolve, mons, candies)
|
||||||
local transferred = 0;
|
local transferred = 0;
|
||||||
local evolved = 0;
|
local evolved = 0;
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
if math.floor(candies / candies_to_evolve) == 0 or mons == 0 then
|
if math.floor(candies / candies_to_evolve) == 0 or mons == 0 then
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
mons = mons - 1
|
mons = mons - 1
|
||||||
candies = candies - candies_to_evolve + 1
|
candies = candies - candies_to_evolve + 1
|
||||||
evolved = evolved + 1
|
evolved = evolved + 1
|
||||||
if mons == 0 then
|
if mons == 0 then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
if (candies + mons) < (candies_to_evolve + 1) or mons == 0 then
|
if (candies + mons) < (candies_to_evolve + 1) or mons == 0 then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
while candies < candies_to_evolve do
|
while candies < candies_to_evolve do
|
||||||
transferred = transferred + 1
|
transferred = transferred + 1
|
||||||
mons = mons - 1
|
mons = mons - 1
|
||||||
candies = candies + 1
|
candies = candies + 1
|
||||||
end
|
end
|
||||||
mons = mons - 1
|
mons = mons - 1
|
||||||
candies = candies - candies_to_evolve + 1
|
candies = candies - candies_to_evolve + 1
|
||||||
evolved = evolved + 1
|
evolved = evolved + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
transfer = transferred,
|
transfer = transferred,
|
||||||
evolve = evolved,
|
evolve = evolved,
|
||||||
leftover_mons = mons,
|
leftover_mons = mons,
|
||||||
leftover_candy = candies
|
leftover_candy = candies
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local single_job = function(input)
|
local single_job = function(input)
|
||||||
local req_candy, mons, candies = input:match('^(%d+) (%d+) (%d+)$')
|
local req_candy, mons, candies = input:match('^(%d+) (%d+) (%d+)$')
|
||||||
req_candy = tonumber(req_candy)
|
req_candy = tonumber(req_candy)
|
||||||
mons = tonumber(mons)
|
mons = tonumber(mons)
|
||||||
candies = tonumber(candies)
|
candies = tonumber(candies)
|
||||||
if not (req_candy and mons and candies) then
|
if not (req_candy and mons and candies) then
|
||||||
return { err = 'Invalid input: Three numbers expected.' }
|
return { err = 'Invalid input: Three numbers expected.' }
|
||||||
elseif req_candy > 400 then
|
elseif req_candy > 400 then
|
||||||
return { err = 'Invalid required candy: Maximum is 400.' }
|
return { err = 'Invalid required candy: Maximum is 400.' }
|
||||||
elseif mons > 1000 then
|
elseif mons > 1000 then
|
||||||
return { err = 'Invalid number of Pokémon: Maximum is 1000.' }
|
return { err = 'Invalid number of Pokémon: Maximum is 1000.' }
|
||||||
elseif candies > 10000 then
|
elseif candies > 10000 then
|
||||||
return { err = 'Invalid number of candies: Maximum is 10000.' }
|
return { err = 'Invalid number of candies: Maximum is 10000.' }
|
||||||
else
|
else
|
||||||
return pidgey_calc(req_candy, mons, candies)
|
return pidgey_calc(req_candy, mons, candies)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function pgc:action(msg)
|
function pgc:action(msg)
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, pgc.doc, true)
|
utilities.send_reply(self, msg, pgc.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
input = input .. '\n'
|
input = input .. '\n'
|
||||||
local output = ''
|
local output = ''
|
||||||
local total_evolutions = 0
|
local total_evolutions = 0
|
||||||
for line in input:gmatch('(.-)\n') do
|
for line in input:gmatch('(.-)\n') do
|
||||||
local info = single_job(line)
|
local info = single_job(line)
|
||||||
output = output .. '`' .. line .. '`\n'
|
output = output .. '`' .. line .. '`\n'
|
||||||
if info.err then
|
if info.err then
|
||||||
output = output .. info.err .. '\n\n'
|
output = output .. info.err .. '\n\n'
|
||||||
else
|
else
|
||||||
total_evolutions = total_evolutions + info.evolve
|
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'
|
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)
|
s = s:format(info.transfer, info.evolve, info.evolve..'k', info.evolve*0.5, info.leftover_mons, info.leftover_candy)
|
||||||
output = output .. s
|
output = output .. s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local s = '*Total evolutions:* %s. \n*Recommendation:* %s'
|
local s = '*Total evolutions:* %s. \n*Recommendation:* %s'
|
||||||
local recommendation
|
local recommendation
|
||||||
local egg_count = math.floor(total_evolutions/60)
|
local egg_count = math.floor(total_evolutions/60)
|
||||||
if egg_count < 1 then
|
if egg_count < 1 then
|
||||||
recommendation = 'Wait until you have atleast sixty Pokémon to evolve before using a lucky egg.'
|
recommendation = 'Wait until you have atleast sixty Pokémon to evolve before using a lucky egg.'
|
||||||
else
|
else
|
||||||
recommendation = string.format(
|
recommendation = string.format(
|
||||||
'Use %s lucky egg%s for %s evolutions.',
|
'Use %s lucky egg%s for %s evolutions.',
|
||||||
egg_count,
|
egg_count,
|
||||||
egg_count == 1 and '' or 's',
|
egg_count == 1 and '' or 's',
|
||||||
egg_count * 60
|
egg_count * 60
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
s = s:format(total_evolutions, recommendation)
|
s = s:format(total_evolutions, recommendation)
|
||||||
output = output .. s
|
output = output .. s
|
||||||
utilities.send_reply(self, msg, output, true)
|
utilities.send_reply(self, msg, output, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
return pgc
|
return pgc
|
||||||
|
@ -21,7 +21,7 @@ Set your Pokémon Go team for statistical purposes. The team must be valid, and
|
|||||||
db.membership = {}
|
db.membership = {}
|
||||||
end
|
end
|
||||||
for _, set in pairs(db.membership) do
|
for _, set in pairs(db.membership) do
|
||||||
setmetatable(set, utilities.set_meta)
|
setmetatable(set, utilities.set_meta)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -6,37 +6,37 @@ local utilities = require('otouto.utilities')
|
|||||||
preview.command = 'preview <link>'
|
preview.command = 'preview <link>'
|
||||||
|
|
||||||
function preview:init(config)
|
function preview:init(config)
|
||||||
preview.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('preview', true).table
|
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.doc = config.cmd_pat .. 'preview <link> \nReturns a full-message, "unlinked" preview.'
|
||||||
end
|
end
|
||||||
|
|
||||||
function preview:action(msg)
|
function preview:action(msg)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, preview.doc, true)
|
utilities.send_reply(self, msg, preview.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
input = utilities.get_word(input, 1)
|
input = utilities.get_word(input, 1)
|
||||||
if not input:match('^https?://.+') then
|
if not input:match('^https?://.+') then
|
||||||
input = 'http://' .. input
|
input = 'http://' .. input
|
||||||
end
|
end
|
||||||
|
|
||||||
local res = HTTP.request(input)
|
local res = HTTP.request(input)
|
||||||
if not res then
|
if not res then
|
||||||
utilities.send_reply(self, msg, 'Please provide a valid link.')
|
utilities.send_reply(self, msg, 'Please provide a valid link.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if res:len() == 0 then
|
if res:len() == 0 then
|
||||||
utilities.send_reply(self, msg, 'Sorry, the link you provided is not letting us make a preview.')
|
utilities.send_reply(self, msg, 'Sorry, the link you provided is not letting us make a preview.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Invisible zero-width, non-joiner.
|
-- Invisible zero-width, non-joiner.
|
||||||
local output = '<a href="' .. input .. '">' .. utilities.char.zwnj .. '</a>'
|
local output = '<a href="' .. input .. '">' .. utilities.char.zwnj .. '</a>'
|
||||||
utilities.send_message(self, msg.chat.id, output, false, nil, 'html')
|
utilities.send_message(self, msg.chat.id, output, false, nil, 'html')
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -6,138 +6,138 @@ pun.command = 'pun'
|
|||||||
pun.doc = 'Returns a pun.'
|
pun.doc = 'Returns a pun.'
|
||||||
|
|
||||||
function pun:init(config)
|
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
|
end
|
||||||
|
|
||||||
local puns = {
|
local puns = {
|
||||||
"The person who invented the door-knock won the No-bell prize.",
|
"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.",
|
"I couldn't work out how to fasten my seatbelt. Then it clicked.",
|
||||||
"Never trust atoms; they make up everything.",
|
"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.",
|
"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.",
|
"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!",
|
"To the guy who invented zero: Thanks for nothing!",
|
||||||
"Enough with the cripple jokes! I just can't stand them.",
|
"Enough with the cripple jokes! I just can't stand them.",
|
||||||
"I've accidentally swallowed some Scrabble tiles. My next crap could spell disaster.",
|
"I've accidentally swallowed some Scrabble tiles. My next crap could spell disaster.",
|
||||||
"How does Moses make his tea? Hebrews it.",
|
"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.",
|
"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'.",
|
"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'.",
|
"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 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 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",
|
"I have a few jokes about unemployed people, but none of them work",
|
||||||
"Want to hear a construction joke? I'm working on it",
|
"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 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 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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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 dropped my steak on the floor. Now it's ground beef.",
|
||||||
"I used to have a fear of hurdles, but I got over it.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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...",
|
"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.",
|
"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 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.",
|
"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.",
|
"Why did everyone want to hang out with the mushroom? Because he was a fungi.",
|
||||||
"How much does a hipster weigh? An instagram.",
|
"How much does a hipster weigh? An instagram.",
|
||||||
"I used to be addicted to soap, but I'm clean now.",
|
"I used to be addicted to soap, but I'm clean now.",
|
||||||
"When life gives you melons, you’re probably dyslexic.",
|
"When life gives you melons, you’re probably dyslexic.",
|
||||||
"What's with all the blind jokes? I just don't see the point.",
|
"What's with all the blind jokes? I just don't see the point.",
|
||||||
"If Apple made a car, would it have Windows?",
|
"If Apple made a car, would it have Windows?",
|
||||||
"Need an ark? I Noah guy.",
|
"Need an ark? I Noah guy.",
|
||||||
"The scarecrow won an award because he was outstanding in his field.",
|
"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'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.",
|
"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.",
|
"I'm reading a book about anti-gravity. It's impossible to put down.",
|
||||||
"Trying to write with a broken pencil is pointless.",
|
"Trying to write with a broken pencil is pointless.",
|
||||||
"When TVs go on vacation, they travel to remote islands.",
|
"When TVs go on vacation, they travel to remote islands.",
|
||||||
"I was going to tell a midget joke, but it's too short.",
|
"I was going to tell a midget joke, but it's too short.",
|
||||||
"Jokes about German sausage are the wurst.",
|
"Jokes about German sausage are the wurst.",
|
||||||
"How do you organize a space party? You planet.",
|
"How do you organize a space party? You planet.",
|
||||||
"Sleeping comes so naturally to me, I could do it with my eyes closed.",
|
"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.",
|
"I'm glad I know sign language; it's pretty handy.",
|
||||||
"Atheism is a non-prophet organization.",
|
"Atheism is a non-prophet organization.",
|
||||||
"Velcro: What a rip-off!",
|
"Velcro: What a rip-off!",
|
||||||
"If they made a Minecraft movie, it would be a blockbuster.",
|
"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 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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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 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.",
|
"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.",
|
"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.",
|
"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 used to be a loan shark, but I lost interest",
|
||||||
"I don't trust these stairs; they're always up to something.",
|
"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.",
|
"My friend's bakery burned down last night. Now his business is toast.",
|
||||||
"Don't trust people that do acupuncture; they're back stabbers.",
|
"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.",
|
"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.",
|
"Police were called to a daycare where a three-year-old was resisting a rest.",
|
||||||
"When Peter Pan punches, they Neverland",
|
"When Peter Pan punches, they Neverland",
|
||||||
"The shoemaker did not deny his apprentice anything he needed. He gave him his awl.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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 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!",
|
"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.",
|
"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.",
|
"It was an emotional wedding. Even the cake was in tiers.",
|
||||||
"When a clock is hungry it goes back four seconds.",
|
"When a clock is hungry it goes back four seconds.",
|
||||||
"The dead batteries were given out free of charge.",
|
"The dead batteries were given out free of charge.",
|
||||||
"Why are there no knock-knock jokes about America? Because freedom rings.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"Pterodactyls can't be heard going to the bathroom because the P is silent.",
|
||||||
"Mermaids make calls on their shell phones.",
|
"Mermaids make calls on their shell phones.",
|
||||||
"What do you call an aardvark with three feet? A yaardvark.",
|
"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.",
|
"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.",
|
"How do celebrities stay cool? They have a lot of fans.",
|
||||||
"Without geometry, life is pointless.",
|
"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.",
|
"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.",
|
"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 work for the IRS, but my job was too taxing.",
|
||||||
"I used to be a programmer, but then I lost my drive.",
|
"I used to be a programmer, but then I lost my drive.",
|
||||||
"Pediatricians are doctors with little patients.",
|
"Pediatricians are doctors with little patients.",
|
||||||
"I finally fired my masseuse today. She always rubbed me the wrong way.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"She was only a whiskey maker, but he loved her still.",
|
||||||
"Male deer have buck teeth.",
|
"Male deer have buck teeth.",
|
||||||
"Whiteboards are remarkable.",
|
"Whiteboards are remarkable.",
|
||||||
"Visitors in Cuba are always Havana good time.",
|
"Visitors in Cuba are always Havana good time.",
|
||||||
"Why does electricity shock people? It doesn't know how to conduct itself.",
|
"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.",
|
"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.",
|
"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.",
|
"Heaven for gamblers is a paradise.",
|
||||||
"Old wheels aren't thrown away, they're just retired.",
|
"Old wheels aren't thrown away, they're just retired.",
|
||||||
"Horses are very stable animals.",
|
"Horses are very stable animals.",
|
||||||
"Banks don't crash, they just lose their balance.",
|
"Banks don't crash, they just lose their balance.",
|
||||||
"The career of a skier can go downhill very fast.",
|
"The career of a skier can go downhill very fast.",
|
||||||
"In democracy, it's your vote that counts. In feudalism, it's your count that votes.",
|
"In democracy, it's your vote that counts. In feudalism, it's your count that votes.",
|
||||||
"A sea lion is nothing but an ionized seal.",
|
"A sea lion is nothing but an ionized seal.",
|
||||||
"The vegetables from my garden aren't that great. I guess you could say they're mediokra."
|
"The vegetables from my garden aren't that great. I guess you could say they're mediokra."
|
||||||
}
|
}
|
||||||
|
|
||||||
function pun:action(msg)
|
function pun:action(msg)
|
||||||
|
|
||||||
utilities.send_reply(self, msg, puns[math.random(#puns)])
|
utilities.send_reply(self, msg, puns[math.random(#puns)])
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -16,34 +16,34 @@ reactions.doc = 'Returns a list of "reaction" emoticon commands.'
|
|||||||
local help
|
local help
|
||||||
|
|
||||||
function reactions:init(config)
|
function reactions:init(config)
|
||||||
-- Generate a "help" message triggered by "/reactions".
|
-- Generate a "help" message triggered by "/reactions".
|
||||||
help = 'Reactions:\n'
|
help = 'Reactions:\n'
|
||||||
reactions.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('reactions').table
|
reactions.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('reactions').table
|
||||||
local username = self.info.username:lower()
|
local username = self.info.username:lower()
|
||||||
for trigger,reaction in pairs(config.reactions) do
|
for trigger,reaction in pairs(config.reactions) do
|
||||||
help = help .. '• ' .. config.cmd_pat .. trigger .. ': ' .. reaction .. '\n'
|
help = help .. '• ' .. config.cmd_pat .. trigger .. ': ' .. reaction .. '\n'
|
||||||
table.insert(reactions.triggers, '^'..config.cmd_pat..trigger)
|
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..'@'..username)
|
||||||
table.insert(reactions.triggers, config.cmd_pat..trigger..'$')
|
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..'@'..username..'$')
|
||||||
table.insert(reactions.triggers, '\n'..config.cmd_pat..trigger)
|
table.insert(reactions.triggers, '\n'..config.cmd_pat..trigger)
|
||||||
table.insert(reactions.triggers, '\n'..config.cmd_pat..trigger..'@'..username)
|
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..'\n')
|
||||||
table.insert(reactions.triggers, config.cmd_pat..trigger..'@'..username..'\n')
|
table.insert(reactions.triggers, config.cmd_pat..trigger..'@'..username..'\n')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function reactions:action(msg, config)
|
function reactions:action(msg, config)
|
||||||
if string.match(msg.text_lower, config.cmd_pat..'reactions') then
|
if string.match(msg.text_lower, config.cmd_pat..'reactions') then
|
||||||
utilities.send_message(self, msg.chat.id, help)
|
utilities.send_message(self, msg.chat.id, help)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for trigger,reaction in pairs(config.reactions) do
|
for trigger,reaction in pairs(config.reactions) do
|
||||||
if string.match(msg.text_lower, config.cmd_pat..trigger) then
|
if string.match(msg.text_lower, config.cmd_pat..trigger) then
|
||||||
utilities.send_message(self, msg.chat.id, reaction)
|
utilities.send_message(self, msg.chat.id, reaction)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return reactions
|
return reactions
|
||||||
|
@ -8,29 +8,29 @@ local utilities = require('otouto.utilities')
|
|||||||
reddit.command = 'reddit [r/subreddit | query]'
|
reddit.command = 'reddit [r/subreddit | query]'
|
||||||
|
|
||||||
function reddit:init(config)
|
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.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.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.
|
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'
|
Aliases: ]] .. config.cmd_pat .. 'r, /r/subreddit'
|
||||||
end
|
end
|
||||||
|
|
||||||
local format_results = function(posts)
|
local format_results = function(posts)
|
||||||
local output = ''
|
local output = ''
|
||||||
for _,v in ipairs(posts) do
|
for _,v in ipairs(posts) do
|
||||||
local post = v.data
|
local post = v.data
|
||||||
local title = post.title:gsub('%[', '('):gsub('%]', ')'):gsub('&', '&')
|
local title = post.title:gsub('%[', '('):gsub('%]', ')'):gsub('&', '&')
|
||||||
if title:len() > 256 then
|
if title:len() > 256 then
|
||||||
title = title:sub(1, 253)
|
title = title:sub(1, 253)
|
||||||
title = utilities.trim(title) .. '...'
|
title = utilities.trim(title) .. '...'
|
||||||
end
|
end
|
||||||
local short_url = 'redd.it/' .. post.id
|
local short_url = 'redd.it/' .. post.id
|
||||||
local s = '[' .. title .. '](' .. short_url .. ')'
|
local s = '[' .. title .. '](' .. short_url .. ')'
|
||||||
if post.domain and not post.is_self and not post.over_18 then
|
if post.domain and not post.is_self and not post.over_18 then
|
||||||
s = '`[`[' .. post.domain .. '](' .. post.url:gsub('%)', '\\)') .. ')`]` ' .. s
|
s = '`[`[' .. post.domain .. '](' .. post.url:gsub('%)', '\\)') .. ')`]` ' .. s
|
||||||
end
|
end
|
||||||
output = output .. '• ' .. s .. '\n'
|
output = output .. '• ' .. s .. '\n'
|
||||||
end
|
end
|
||||||
return output
|
return output
|
||||||
end
|
end
|
||||||
|
|
||||||
reddit.subreddit_url = 'http://www.reddit.com/%s/.json?limit='
|
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='
|
reddit.rall_url = 'http://www.reddit.com/.json?limit='
|
||||||
|
|
||||||
function reddit:action(msg, config)
|
function reddit:action(msg, config)
|
||||||
-- Eight results in PM, four results elsewhere.
|
-- Eight results in PM, four results elsewhere.
|
||||||
local limit = 4
|
local limit = 4
|
||||||
if msg.chat.type == 'private' then
|
if msg.chat.type == 'private' then
|
||||||
limit = 8
|
limit = 8
|
||||||
end
|
end
|
||||||
local text = msg.text_lower
|
local text = msg.text_lower
|
||||||
if text:match('^/r/.') then
|
if text:match('^/r/.') then
|
||||||
-- Normalize input so this hack works easily.
|
-- Normalize input so this hack works easily.
|
||||||
text = msg.text_lower:gsub('^/r/', config.cmd_pat..'r r/')
|
text = msg.text_lower:gsub('^/r/', config.cmd_pat..'r r/')
|
||||||
end
|
end
|
||||||
local input = utilities.input(text)
|
local input = utilities.input(text)
|
||||||
local source, url
|
local source, url
|
||||||
if input then
|
if input then
|
||||||
if input:match('^r/.') then
|
if input:match('^r/.') then
|
||||||
input = utilities.get_word(input, 1)
|
input = utilities.get_word(input, 1)
|
||||||
url = reddit.subreddit_url:format(input) .. limit
|
url = reddit.subreddit_url:format(input) .. limit
|
||||||
source = '*/' .. utilities.md_escape(input) .. '*\n'
|
source = '*/' .. utilities.md_escape(input) .. '*\n'
|
||||||
else
|
else
|
||||||
input = utilities.input(msg.text)
|
input = utilities.input(msg.text)
|
||||||
source = '*Results for* _' .. utilities.md_escape(input) .. '_ *:*\n'
|
source = '*Results for* _' .. utilities.md_escape(input) .. '_ *:*\n'
|
||||||
input = URL.escape(input)
|
input = URL.escape(input)
|
||||||
url = reddit.search_url:format(input) .. limit
|
url = reddit.search_url:format(input) .. limit
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
url = reddit.rall_url .. limit
|
url = reddit.rall_url .. limit
|
||||||
source = '*/r/all*\n'
|
source = '*/r/all*\n'
|
||||||
end
|
end
|
||||||
local jstr, res = HTTP.request(url)
|
local jstr, res = HTTP.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
else
|
else
|
||||||
local jdat = JSON.decode(jstr)
|
local jdat = JSON.decode(jstr)
|
||||||
if #jdat.data.children == 0 then
|
if #jdat.data.children == 0 then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
else
|
else
|
||||||
local output = format_results(jdat.data.children)
|
local output = format_results(jdat.data.children)
|
||||||
output = source .. output
|
output = source .. output
|
||||||
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
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return reddit
|
return reddit
|
||||||
|
@ -5,87 +5,87 @@ local utilities = require('otouto.utilities')
|
|||||||
remind.command = 'remind <duration> <message>'
|
remind.command = 'remind <duration> <message>'
|
||||||
|
|
||||||
function remind:init(config)
|
function remind:init(config)
|
||||||
self.database.reminders = self.database.reminders or {}
|
self.database.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 {}
|
config.remind = config.remind or {}
|
||||||
setmetatable(config.remind, { __index = function() return 1000 end })
|
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.
|
Repeats a message after a duration of time, in minutes.
|
||||||
The maximum length of a reminder is %s characters. The maximum duration of a timer is %s minutes. The maximum number of reminders for a group is %s. The maximum number of reminders in private is %s.]]
|
The maximum length of a reminder is %s characters. The maximum duration of a timer is %s minutes. The maximum number of reminders for a group is %s. The maximum number of reminders in private is %s.]]
|
||||||
remind.doc = remind.doc:format(config.remind.max_length, config.remind.max_duration, config.remind.max_reminders_group, config.remind.max_reminders_private)
|
remind.doc = remind.doc:format(config.remind.max_length, config.remind.max_duration, config.remind.max_reminders_group, config.remind.max_reminders_private)
|
||||||
end
|
end
|
||||||
|
|
||||||
function remind:action(msg, config)
|
function remind:action(msg, config)
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, remind.doc, true)
|
utilities.send_reply(self, msg, remind.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local duration = tonumber(utilities.get_word(input, 1))
|
local duration = tonumber(utilities.get_word(input, 1))
|
||||||
if not duration then
|
if not duration then
|
||||||
utilities.send_reply(self, msg, remind.doc, true)
|
utilities.send_reply(self, msg, remind.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if duration < 1 then
|
if duration < 1 then
|
||||||
duration = 1
|
duration = 1
|
||||||
elseif duration > config.remind.max_duration then
|
elseif duration > config.remind.max_duration then
|
||||||
duration = config.remind.max_duration
|
duration = config.remind.max_duration
|
||||||
end
|
end
|
||||||
local message = utilities.input(input)
|
local message = utilities.input(input)
|
||||||
if not message then
|
if not message then
|
||||||
utilities.send_reply(self, msg, remind.doc, true)
|
utilities.send_reply(self, msg, remind.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if #message > config.remind.max_length then
|
if #message > config.remind.max_length then
|
||||||
utilities.send_reply(self, msg, 'The maximum length of reminders is ' .. config.remind.max_length .. '.')
|
utilities.send_reply(self, msg, 'The maximum length of reminders is ' .. config.remind.max_length .. '.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local chat_id_str = tostring(msg.chat.id)
|
local chat_id_str = tostring(msg.chat.id)
|
||||||
local output
|
local output
|
||||||
self.database.reminders[chat_id_str] = self.database.reminders[chat_id_str] or {}
|
self.database.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
|
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.'
|
output = 'Sorry, you already have the maximum number of reminders.'
|
||||||
elseif msg.chat.type ~= 'private' and utilities.table_size(self.database.reminders[chat_id_str]) >= config.remind.max_reminders_group then
|
elseif msg.chat.type ~= 'private' and utilities.table_size(self.database.reminders[chat_id_str]) >= config.remind.max_reminders_group then
|
||||||
output = 'Sorry, this group already has the maximum number of reminders.'
|
output = 'Sorry, this group already has the maximum number of reminders.'
|
||||||
else
|
else
|
||||||
table.insert(self.database.reminders[chat_id_str], {
|
table.insert(self.database.reminders[chat_id_str], {
|
||||||
time = os.time() + (duration * 60),
|
time = os.time() + (duration * 60),
|
||||||
message = message
|
message = message
|
||||||
})
|
})
|
||||||
output = string.format(
|
output = string.format(
|
||||||
'I will remind you in %s minute%s!',
|
'I will remind you in %s minute%s!',
|
||||||
duration,
|
duration,
|
||||||
duration == 1 and '' or 's'
|
duration == 1 and '' or 's'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
utilities.send_reply(self, msg, output, true)
|
utilities.send_reply(self, msg, output, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
function remind:cron(config)
|
function remind:cron(config)
|
||||||
local time = os.time()
|
local time = os.time()
|
||||||
-- Iterate over the group entries in the reminders database.
|
-- Iterate over the group entries in the reminders database.
|
||||||
for chat_id, group in pairs(self.database.reminders) do
|
for chat_id, group in pairs(self.database.reminders) do
|
||||||
-- Iterate over each reminder.
|
-- Iterate over each reminder.
|
||||||
for k, reminder in pairs(group) do
|
for k, reminder in pairs(group) do
|
||||||
-- If the reminder is past-due, send it and nullify it.
|
-- If the reminder is past-due, send it and nullify it.
|
||||||
-- Otherwise, add it to the replacement table.
|
-- Otherwise, add it to the replacement table.
|
||||||
if time > reminder.time then
|
if time > reminder.time then
|
||||||
local output = utilities.style.enquote('Reminder', reminder.message)
|
local output = utilities.style.enquote('Reminder', reminder.message)
|
||||||
local res = utilities.send_message(self, chat_id, output, true, nil, true)
|
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 the message fails to send, save it for later (if enabled in config).
|
||||||
if res or not config.remind.persist then
|
if res or not config.remind.persist then
|
||||||
group[k] = nil
|
group[k] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return remind
|
return remind
|
||||||
|
@ -5,30 +5,30 @@ local bindings = require('otouto.bindings')
|
|||||||
local rms = {}
|
local rms = {}
|
||||||
|
|
||||||
function rms:init(config)
|
function rms:init(config)
|
||||||
rms.BASE_URL = 'https://rms.sexy/img/'
|
rms.BASE_URL = 'https://rms.sexy/img/'
|
||||||
rms.LIST = {}
|
rms.LIST = {}
|
||||||
local s, r = https.request(rms.BASE_URL)
|
local s, r = https.request(rms.BASE_URL)
|
||||||
if r ~= 200 then
|
if r ~= 200 then
|
||||||
print('Error connecting to rms.sexy.\nrmspic.lua will not be enabled.')
|
print('Error connecting to rms.sexy.\nrmspic.lua will not be enabled.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for link in s:gmatch('<a href=".-%.%a%a%a">(.-)</a>') do
|
for link in s:gmatch('<a href=".-%.%a%a%a">(.-)</a>') do
|
||||||
table.insert(rms.LIST, link)
|
table.insert(rms.LIST, link)
|
||||||
end
|
end
|
||||||
rms.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('rms').table
|
rms.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('rms').table
|
||||||
end
|
end
|
||||||
|
|
||||||
function rms:action(msg, config)
|
function rms:action(msg, config)
|
||||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'upload_photo' })
|
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'upload_photo' })
|
||||||
local choice = rms.LIST[math.random(#rms.LIST)]
|
local choice = rms.LIST[math.random(#rms.LIST)]
|
||||||
local filename = '/tmp/' .. choice
|
local filename = '/tmp/' .. choice
|
||||||
local image_file = io.open(filename)
|
local image_file = io.open(filename)
|
||||||
if image_file then
|
if image_file then
|
||||||
image_file:close()
|
image_file:close()
|
||||||
else
|
else
|
||||||
utilities.download_file(rms.BASE_URL .. choice, filename)
|
utilities.download_file(rms.BASE_URL .. choice, filename)
|
||||||
end
|
end
|
||||||
bindings.sendPhoto(self, { chat_id = msg.chat.id }, { photo = filename })
|
bindings.sendPhoto(self, { chat_id = msg.chat.id }, { photo = filename })
|
||||||
end
|
end
|
||||||
|
|
||||||
return rms
|
return rms
|
||||||
|
@ -3,9 +3,9 @@ local setandget = {}
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function setandget:init(config)
|
function setandget:init(config)
|
||||||
self.database.setandget = self.database.setandget or {}
|
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.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('set', true):t('get', true).table
|
||||||
setandget.doc = config.cmd_pat .. [[set <name> <value>
|
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.
|
Stores a value with the given name. Use "]] .. config.cmd_pat .. [[set <name> --" to delete the stored value.
|
||||||
]] .. config.cmd_pat .. [[get [name]
|
]] .. config.cmd_pat .. [[get [name]
|
||||||
Returns the stored value or a list of stored values.]]
|
Returns the stored value or a list of stored values.]]
|
||||||
@ -15,56 +15,56 @@ setandget.command = 'set <name> <value>'
|
|||||||
|
|
||||||
function setandget:action(msg, config)
|
function setandget:action(msg, config)
|
||||||
|
|
||||||
local chat_id_str = tostring(msg.chat.id)
|
local chat_id_str = tostring(msg.chat.id)
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
self.database.setandget[chat_id_str] = self.database.setandget[chat_id_str] or {}
|
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
|
if not input then
|
||||||
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
|
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local name = utilities.get_word(input:lower(), 1)
|
local name = utilities.get_word(input:lower(), 1)
|
||||||
local value = utilities.input(input)
|
local value = utilities.input(input)
|
||||||
|
|
||||||
if not name or not value then
|
if not name or not value then
|
||||||
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
|
utilities.send_message(self, msg.chat.id, setandget.doc, true, nil, true)
|
||||||
elseif value == '--' or value == '—' then
|
elseif value == '--' or value == '—' then
|
||||||
self.database.setandget[chat_id_str][name] = nil
|
self.database.setandget[chat_id_str][name] = nil
|
||||||
utilities.send_message(self, msg.chat.id, 'That value has been deleted.')
|
utilities.send_message(self, msg.chat.id, 'That value has been deleted.')
|
||||||
else
|
else
|
||||||
self.database.setandget[chat_id_str][name] = value
|
self.database.setandget[chat_id_str][name] = value
|
||||||
utilities.send_message(self, msg.chat.id, '"' .. name .. '" has been set to "' .. value .. '".', true)
|
utilities.send_message(self, msg.chat.id, '"' .. name .. '" has been set to "' .. value .. '".', true)
|
||||||
end
|
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
|
if not input then
|
||||||
local output
|
local output
|
||||||
if utilities.table_size(self.database.setandget[chat_id_str]) == 0 then
|
if utilities.table_size(self.database.setandget[chat_id_str]) == 0 then
|
||||||
output = 'No values have been stored here.'
|
output = 'No values have been stored here.'
|
||||||
else
|
else
|
||||||
output = '*List of stored values:*\n'
|
output = '*List of stored values:*\n'
|
||||||
for k,v in pairs(self.database.setandget[chat_id_str]) do
|
for k,v in pairs(self.database.setandget[chat_id_str]) do
|
||||||
output = output .. '• ' .. k .. ': `' .. v .. '`\n'
|
output = output .. '• ' .. k .. ': `' .. v .. '`\n'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local output
|
local output
|
||||||
if self.database.setandget[chat_id_str][input:lower()] then
|
if self.database.setandget[chat_id_str][input:lower()] then
|
||||||
output = '`' .. self.database.setandget[chat_id_str][input:lower()] .. '`'
|
output = '`' .. self.database.setandget[chat_id_str][input:lower()] .. '`'
|
||||||
else
|
else
|
||||||
output = 'There is no value stored by that name.'
|
output = 'There is no value stored by that name.'
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
@ -3,32 +3,32 @@ local shell = {}
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function shell:init(config)
|
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
|
end
|
||||||
|
|
||||||
function shell:action(msg, config)
|
function shell:action(msg, config)
|
||||||
|
|
||||||
if msg.from.id ~= config.admin then
|
if msg.from.id ~= config.admin then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
input = input:gsub('—', '--')
|
input = input:gsub('—', '--')
|
||||||
|
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, 'Please specify a command to run.')
|
utilities.send_reply(self, msg, 'Please specify a command to run.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local f = io.popen(input)
|
local f = io.popen(input)
|
||||||
local output = f:read('*all')
|
local output = f:read('*all')
|
||||||
f:close()
|
f:close()
|
||||||
if output:len() == 0 then
|
if output:len() == 0 then
|
||||||
output = 'Done!'
|
output = 'Done!'
|
||||||
else
|
else
|
||||||
output = '```\n' .. output .. '\n```'
|
output = '```\n' .. output .. '\n```'
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
@ -6,45 +6,45 @@ shout.command = 'shout <text>'
|
|||||||
local utf8 = '('..utilities.char.utf_8..'*)'
|
local utf8 = '('..utilities.char.utf_8..'*)'
|
||||||
|
|
||||||
function shout:init(config)
|
function shout:init(config)
|
||||||
shout.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('shout', true).table
|
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.doc = config.cmd_pat .. 'shout <text> \nShouts something. Input may be the replied-to message.'
|
||||||
end
|
end
|
||||||
|
|
||||||
function shout:action(msg)
|
function shout:action(msg)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, shout.doc, true)
|
utilities.send_reply(self, msg, shout.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
input = utilities.trim(input)
|
input = utilities.trim(input)
|
||||||
input = input:upper()
|
input = input:upper()
|
||||||
|
|
||||||
local output = ''
|
local output = ''
|
||||||
local inc = 0
|
local inc = 0
|
||||||
local ilen = 0
|
local ilen = 0
|
||||||
for match in input:gmatch(utf8) do
|
for match in input:gmatch(utf8) do
|
||||||
if ilen < 20 then
|
if ilen < 20 then
|
||||||
ilen = ilen + 1
|
ilen = ilen + 1
|
||||||
output = output .. match .. ' '
|
output = output .. match .. ' '
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
ilen = 0
|
ilen = 0
|
||||||
output = output .. '\n'
|
output = output .. '\n'
|
||||||
for match in input:sub(2):gmatch(utf8) do
|
for match in input:sub(2):gmatch(utf8) do
|
||||||
if ilen < 19 then
|
if ilen < 19 then
|
||||||
local spacing = ''
|
local spacing = ''
|
||||||
for _ = 1, inc do
|
for _ = 1, inc do
|
||||||
spacing = spacing .. ' '
|
spacing = spacing .. ' '
|
||||||
end
|
end
|
||||||
inc = inc + 1
|
inc = inc + 1
|
||||||
ilen = ilen + 1
|
ilen = ilen + 1
|
||||||
output = output .. match .. ' ' .. spacing .. match .. '\n'
|
output = output .. match .. ' ' .. spacing .. match .. '\n'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
output = '```\n' .. utilities.trim(output) .. '\n```'
|
output = '```\n' .. utilities.trim(output) .. '\n```'
|
||||||
utilities.send_message(self, msg.chat.id, output, true, false, true)
|
utilities.send_message(self, msg.chat.id, output, true, false, true)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,160 +5,160 @@ local utilities = require('otouto.utilities')
|
|||||||
slap.command = 'slap [target]'
|
slap.command = 'slap [target]'
|
||||||
|
|
||||||
function slap:init(config)
|
function slap:init(config)
|
||||||
slap.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('slap', true).table
|
slap.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('slap', true).table
|
||||||
slap.doc = config.cmd_pat .. 'slap [target] \nSlap somebody.'
|
slap.doc = config.cmd_pat .. 'slap [target] \nSlap somebody.'
|
||||||
end
|
end
|
||||||
|
|
||||||
local slaps = {
|
local slaps = {
|
||||||
'VICTIM was shot by VICTOR.',
|
'VICTIM was shot by VICTOR.',
|
||||||
'VICTIM was pricked to death.',
|
'VICTIM was pricked to death.',
|
||||||
'VICTIM walked into a cactus while trying to escape VICTOR.',
|
'VICTIM walked into a cactus while trying to escape VICTOR.',
|
||||||
'VICTIM drowned.',
|
'VICTIM drowned.',
|
||||||
'VICTIM drowned whilst trying to escape VICTOR.',
|
'VICTIM drowned whilst trying to escape VICTOR.',
|
||||||
'VICTIM blew up.',
|
'VICTIM blew up.',
|
||||||
'VICTIM was blown up by VICTOR.',
|
'VICTIM was blown up by VICTOR.',
|
||||||
'VICTIM hit the ground too hard.',
|
'VICTIM hit the ground too hard.',
|
||||||
'VICTIM fell from a high place.',
|
'VICTIM fell from a high place.',
|
||||||
'VICTIM fell off a ladder.',
|
'VICTIM fell off a ladder.',
|
||||||
'VICTIM fell into a patch of cacti.',
|
'VICTIM fell into a patch of cacti.',
|
||||||
'VICTIM was doomed to fall by VICTOR.',
|
'VICTIM was doomed to fall by VICTOR.',
|
||||||
'VICTIM was blown from a high place by VICTOR.',
|
'VICTIM was blown from a high place by VICTOR.',
|
||||||
'VICTIM was squashed by a falling anvil.',
|
'VICTIM was squashed by a falling anvil.',
|
||||||
'VICTIM went up in flames.',
|
'VICTIM went up in flames.',
|
||||||
'VICTIM burned to death.',
|
'VICTIM burned to death.',
|
||||||
'VICTIM was burnt to a crisp whilst fighting VICTOR.',
|
'VICTIM was burnt to a crisp whilst fighting VICTOR.',
|
||||||
'VICTIM walked into a fire whilst fighting VICTOR.',
|
'VICTIM walked into a fire whilst fighting VICTOR.',
|
||||||
'VICTIM tried to swim in lava.',
|
'VICTIM tried to swim in lava.',
|
||||||
'VICTIM tried to swim in lava while trying to escape VICTOR.',
|
'VICTIM tried to swim in lava while trying to escape VICTOR.',
|
||||||
'VICTIM was struck by lightning.',
|
'VICTIM was struck by lightning.',
|
||||||
'VICTIM was slain by VICTOR.',
|
'VICTIM was slain by VICTOR.',
|
||||||
'VICTIM got finished off by VICTOR.',
|
'VICTIM got finished off by VICTOR.',
|
||||||
'VICTIM was killed by magic.',
|
'VICTIM was killed by magic.',
|
||||||
'VICTIM was killed by VICTOR using magic.',
|
'VICTIM was killed by VICTOR using magic.',
|
||||||
'VICTIM starved to death.',
|
'VICTIM starved to death.',
|
||||||
'VICTIM suffocated in a wall.',
|
'VICTIM suffocated in a wall.',
|
||||||
'VICTIM fell out of the world.',
|
'VICTIM fell out of the world.',
|
||||||
'VICTIM was knocked into the void by VICTOR.',
|
'VICTIM was knocked into the void by VICTOR.',
|
||||||
'VICTIM withered away.',
|
'VICTIM withered away.',
|
||||||
'VICTIM was pummeled by VICTOR.',
|
'VICTIM was pummeled by VICTOR.',
|
||||||
'VICTIM was fragged by VICTOR.',
|
'VICTIM was fragged by VICTOR.',
|
||||||
'VICTIM was desynchronized.',
|
'VICTIM was desynchronized.',
|
||||||
'VICTIM was wasted.',
|
'VICTIM was wasted.',
|
||||||
'VICTIM was busted.',
|
'VICTIM was busted.',
|
||||||
'VICTIM\'s bones are scraped clean by the desolate wind.',
|
'VICTIM\'s bones are scraped clean by the desolate wind.',
|
||||||
'VICTIM has died of dysentery.',
|
'VICTIM has died of dysentery.',
|
||||||
'VICTIM fainted.',
|
'VICTIM fainted.',
|
||||||
'VICTIM is out of usable Pokemon! VICTIM whited out!',
|
'VICTIM is out of usable Pokemon! VICTIM whited out!',
|
||||||
'VICTIM is out of usable Pokemon! VICTIM blacked out!',
|
'VICTIM is out of usable Pokemon! VICTIM blacked out!',
|
||||||
'VICTIM whited out!',
|
'VICTIM whited out!',
|
||||||
'VICTIM blacked out!',
|
'VICTIM blacked out!',
|
||||||
'VICTIM says goodbye to this cruel world.',
|
'VICTIM says goodbye to this cruel world.',
|
||||||
'VICTIM got rekt.',
|
'VICTIM got rekt.',
|
||||||
'VICTIM was sawn in half by VICTOR.',
|
'VICTIM was sawn in half by VICTOR.',
|
||||||
'VICTIM died. I blame VICTOR.',
|
'VICTIM died. I blame VICTOR.',
|
||||||
'VICTIM was axe-murdered by VICTOR.',
|
'VICTIM was axe-murdered by VICTOR.',
|
||||||
'VICTIM\'s melon was split by VICTOR.',
|
'VICTIM\'s melon was split by VICTOR.',
|
||||||
'VICTIM was sliced and diced by VICTOR.',
|
'VICTIM was sliced and diced by VICTOR.',
|
||||||
'VICTIM was split from crotch to sternum by VICTOR.',
|
'VICTIM was split from crotch to sternum by VICTOR.',
|
||||||
'VICTIM\'s death put another notch in VICTOR\'s axe.',
|
'VICTIM\'s death put another notch in VICTOR\'s axe.',
|
||||||
'VICTIM died impossibly!',
|
'VICTIM died impossibly!',
|
||||||
'VICTIM died from VICTOR\'s mysterious tropical disease.',
|
'VICTIM died from VICTOR\'s mysterious tropical disease.',
|
||||||
'VICTIM escaped infection by dying.',
|
'VICTIM escaped infection by dying.',
|
||||||
'VICTIM played hot-potato with a grenade.',
|
'VICTIM played hot-potato with a grenade.',
|
||||||
'VICTIM was knifed by VICTOR.',
|
'VICTIM was knifed by VICTOR.',
|
||||||
'VICTIM fell on his sword.',
|
'VICTIM fell on his sword.',
|
||||||
'VICTIM ate a grenade.',
|
'VICTIM ate a grenade.',
|
||||||
'VICTIM practiced being VICTOR\'s clay pigeon.',
|
'VICTIM practiced being VICTOR\'s clay pigeon.',
|
||||||
'VICTIM is what\'s for dinner!',
|
'VICTIM is what\'s for dinner!',
|
||||||
'VICTIM was terminated by VICTOR.',
|
'VICTIM was terminated by VICTOR.',
|
||||||
'VICTIM was shot before being thrown out of a plane.',
|
'VICTIM was shot before being thrown out of a plane.',
|
||||||
'VICTIM was not invincible.',
|
'VICTIM was not invincible.',
|
||||||
'VICTIM has encountered an error.',
|
'VICTIM has encountered an error.',
|
||||||
'VICTIM died and reincarnated as a goat.',
|
'VICTIM died and reincarnated as a goat.',
|
||||||
'VICTOR threw VICTIM off a building.',
|
'VICTOR threw VICTIM off a building.',
|
||||||
'VICTIM is sleeping with the fishes.',
|
'VICTIM is sleeping with the fishes.',
|
||||||
'VICTIM got a premature burial.',
|
'VICTIM got a premature burial.',
|
||||||
'VICTOR replaced all of VICTIM\'s music with Nickelback.',
|
'VICTOR replaced all of VICTIM\'s music with Nickelback.',
|
||||||
'VICTOR spammed VICTIM\'s email.',
|
'VICTOR spammed VICTIM\'s email.',
|
||||||
'VICTOR made VICTIM a knuckle sandwich.',
|
'VICTOR made VICTIM a knuckle sandwich.',
|
||||||
'VICTOR slapped VICTIM with pure nothing.',
|
'VICTOR slapped VICTIM with pure nothing.',
|
||||||
'VICTOR hit VICTIM with a small, interstellar spaceship.',
|
'VICTOR hit VICTIM with a small, interstellar spaceship.',
|
||||||
'VICTIM was quickscoped by VICTOR.',
|
'VICTIM was quickscoped by VICTOR.',
|
||||||
'VICTOR put VICTIM in check-mate.',
|
'VICTOR put VICTIM in check-mate.',
|
||||||
'VICTOR RSA-encrypted VICTIM and deleted the private key.',
|
'VICTOR RSA-encrypted VICTIM and deleted the private key.',
|
||||||
'VICTOR put VICTIM in the friendzone.',
|
'VICTOR put VICTIM in the friendzone.',
|
||||||
'VICTOR slaps VICTIM with a DMCA takedown request!',
|
'VICTOR slaps VICTIM with a DMCA takedown request!',
|
||||||
'VICTIM became a corpse blanket for VICTOR.',
|
'VICTIM became a corpse blanket for VICTOR.',
|
||||||
'Death is when the monsters get you. Death comes for VICTIM.',
|
'Death is when the monsters get you. Death comes for VICTIM.',
|
||||||
'Cowards die many times before their death. VICTIM never tasted death but once.',
|
'Cowards die many times before their death. VICTIM never tasted death but once.',
|
||||||
'VICTIM died of hospital gangrene.',
|
'VICTIM died of hospital gangrene.',
|
||||||
'VICTIM got a house call from Doctor VICTOR.',
|
'VICTIM got a house call from Doctor VICTOR.',
|
||||||
'VICTOR beheaded VICTIM.',
|
'VICTOR beheaded VICTIM.',
|
||||||
'VICTIM got stoned...by an angry mob.',
|
'VICTIM got stoned...by an angry mob.',
|
||||||
'VICTOR sued the pants off VICTIM.',
|
'VICTOR sued the pants off VICTIM.',
|
||||||
'VICTIM was impeached.',
|
'VICTIM was impeached.',
|
||||||
'VICTIM was one-hit KO\'d by VICTOR.',
|
'VICTIM was one-hit KO\'d by VICTOR.',
|
||||||
'VICTOR sent VICTIM to /dev/null.',
|
'VICTOR sent VICTIM to /dev/null.',
|
||||||
'VICTOR sent VICTIM down the memory hole.',
|
'VICTOR sent VICTIM down the memory hole.',
|
||||||
'VICTIM was a mistake.',
|
'VICTIM was a mistake.',
|
||||||
'"VICTIM was a mistake." - VICTOR',
|
'"VICTIM was a mistake." - VICTOR',
|
||||||
'VICTOR checkmated VICTIM in two moves.'
|
'VICTOR checkmated VICTIM in two moves.'
|
||||||
}
|
}
|
||||||
|
|
||||||
-- optimize later
|
-- optimize later
|
||||||
function slap:action(msg)
|
function slap:action(msg)
|
||||||
local input = utilities.input(msg.text)
|
local input = utilities.input(msg.text)
|
||||||
local victor_id = msg.from.id
|
local victor_id = msg.from.id
|
||||||
local victim_id
|
local victim_id
|
||||||
if msg.reply_to_message then
|
if msg.reply_to_message then
|
||||||
victim_id = msg.reply_to_message.from.id
|
victim_id = msg.reply_to_message.from.id
|
||||||
else
|
else
|
||||||
if input then
|
if input then
|
||||||
if tonumber(input) then
|
if tonumber(input) then
|
||||||
victim_id = tonumber(input)
|
victim_id = tonumber(input)
|
||||||
elseif input:match('^@') then
|
elseif input:match('^@') then
|
||||||
local t = utilities.resolve_username(self, input)
|
local t = utilities.resolve_username(self, input)
|
||||||
if t then
|
if t then
|
||||||
victim_id = t.id
|
victim_id = t.id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- IDs
|
-- IDs
|
||||||
if victim_id then
|
if victim_id then
|
||||||
if victim_id == victor_id then
|
if victim_id == victor_id then
|
||||||
victor_id = self.info.id
|
victor_id = self.info.id
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if not input then
|
if not input then
|
||||||
victor_id = self.info.id
|
victor_id = self.info.id
|
||||||
victim_id = msg.from.id
|
victim_id = msg.from.id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Names
|
-- Names
|
||||||
local victor_name, victim_name
|
local victor_name, victim_name
|
||||||
if input and not victim_id then
|
if input and not victim_id then
|
||||||
victim_name = input
|
victim_name = input
|
||||||
else
|
else
|
||||||
local victim_id_str = tostring(victim_id)
|
local victim_id_str = tostring(victim_id)
|
||||||
if self.database.userdata[victim_id_str] and self.database.userdata[victim_id_str].nickname then
|
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
|
victim_name = self.database.userdata[victim_id_str].nickname
|
||||||
elseif self.database.users[victim_id_str] then
|
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)
|
victim_name = utilities.build_name(self.database.users[victim_id_str].first_name, self.database.users[victim_id_str].last_name)
|
||||||
else
|
else
|
||||||
victim_name = victim_id_str
|
victim_name = victim_id_str
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local victor_id_str = tostring(victor_id)
|
local victor_id_str = tostring(victor_id)
|
||||||
if self.database.userdata[victor_id_str] and self.database.userdata[victor_id_str].nickname then
|
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
|
victor_name = self.database.userdata[victor_id_str].nickname
|
||||||
elseif self.database.users[victor_id_str] then
|
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)
|
victor_name = utilities.build_name(self.database.users[victor_id_str].first_name, self.database.users[victor_id_str].last_name)
|
||||||
else
|
else
|
||||||
victor_name = self.info.first_name
|
victor_name = self.info.first_name
|
||||||
end
|
end
|
||||||
local output = utilities.char.zwnj .. slaps[math.random(#slaps)]:gsub('VICTIM', victim_name):gsub('VICTOR', victor_name)
|
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)
|
utilities.send_message(self, msg.chat.id, output)
|
||||||
end
|
end
|
||||||
|
|
||||||
return slap
|
return slap
|
||||||
|
@ -8,71 +8,71 @@ local utilities = require('otouto.utilities')
|
|||||||
local starwars = {}
|
local starwars = {}
|
||||||
|
|
||||||
function starwars:init(config)
|
function starwars:init(config)
|
||||||
starwars.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
starwars.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('starwars', true):t('sw', true).table
|
:t('starwars', true):t('sw', true).table
|
||||||
starwars.doc = config.cmd_pat .. [[starwars <query>
|
starwars.doc = config.cmd_pat .. [[starwars <query>
|
||||||
Returns the opening crawl from the specified Star Wars film.
|
Returns the opening crawl from the specified Star Wars film.
|
||||||
Alias: ]] .. config.cmd_pat .. 'sw'
|
Alias: ]] .. config.cmd_pat .. 'sw'
|
||||||
starwars.command = 'starwars <query>'
|
starwars.command = 'starwars <query>'
|
||||||
starwars.base_url = 'http://swapi.co/api/films/'
|
starwars.base_url = 'http://swapi.co/api/films/'
|
||||||
end
|
end
|
||||||
|
|
||||||
local films_by_number = {
|
local films_by_number = {
|
||||||
['phantom menace'] = 4,
|
['phantom menace'] = 4,
|
||||||
['attack of the clones'] = 5,
|
['attack of the clones'] = 5,
|
||||||
['revenge of the sith'] = 6,
|
['revenge of the sith'] = 6,
|
||||||
['new hope'] = 1,
|
['new hope'] = 1,
|
||||||
['empire strikes back'] = 2,
|
['empire strikes back'] = 2,
|
||||||
['return of the jedi'] = 3,
|
['return of the jedi'] = 3,
|
||||||
['force awakens'] = 7
|
['force awakens'] = 7
|
||||||
}
|
}
|
||||||
|
|
||||||
local corrected_numbers = {
|
local corrected_numbers = {
|
||||||
4,
|
4,
|
||||||
5,
|
5,
|
||||||
6,
|
6,
|
||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
7
|
7
|
||||||
}
|
}
|
||||||
|
|
||||||
function starwars:action(msg, config)
|
function starwars:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, starwars.doc, true)
|
utilities.send_reply(self, msg, starwars.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' } )
|
bindings.sendChatAction(self, { chat_id = msg.chat.id, action = 'typing' } )
|
||||||
|
|
||||||
local film
|
local film
|
||||||
if tonumber(input) then
|
if tonumber(input) then
|
||||||
input = tonumber(input)
|
input = tonumber(input)
|
||||||
film = corrected_numbers[input] or input
|
film = corrected_numbers[input] or input
|
||||||
else
|
else
|
||||||
for title, number in pairs(films_by_number) do
|
for title, number in pairs(films_by_number) do
|
||||||
if string.match(input, title) then
|
if string.match(input, title) then
|
||||||
film = number
|
film = number
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not film then
|
if not film then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local url = starwars.base_url .. film
|
local url = starwars.base_url .. film
|
||||||
local jstr, code = HTTP.request(url)
|
local jstr, code = HTTP.request(url)
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = '*' .. JSON.decode(jstr).opening_crawl .. '*'
|
local output = '*' .. JSON.decode(jstr).opening_crawl .. '*'
|
||||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
return starwars
|
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'
|
time.base_url = 'https://maps.googleapis.com/maps/api/timezone/json?location=%s,%s×tamp=%s'
|
||||||
|
|
||||||
function time:init(config)
|
function time:init(config)
|
||||||
time.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('time', true).table
|
time.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('time', true).table
|
||||||
time.doc = config.cmd_pat .. [[time <location>
|
time.doc = config.cmd_pat .. [[time <location>
|
||||||
Returns the time, date, and timezone for the given location.]]
|
Returns the time, date, and timezone for the given location.]]
|
||||||
end
|
end
|
||||||
|
|
||||||
function time:action(msg, config)
|
function time:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, time.doc, true)
|
utilities.send_reply(self, msg, time.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local coords = utilities.get_coords(input, config)
|
local coords = utilities.get_coords(input, config)
|
||||||
if type(coords) == 'string' then
|
if type(coords) == 'string' then
|
||||||
utilities.send_reply(self, msg, coords)
|
utilities.send_reply(self, msg, coords)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local now = os.time()
|
local now = os.time()
|
||||||
local utc = os.time(os.date('!*t', now))
|
local utc = os.time(os.date('!*t', now))
|
||||||
local url = time.base_url:format(coords.lat, coords.lon, utc)
|
local url = time.base_url:format(coords.lat, coords.lon, utc)
|
||||||
local jstr, code = HTTPS.request(url)
|
local jstr, code = HTTPS.request(url)
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
if data.status == 'ZERO_RESULTS' then
|
if data.status == 'ZERO_RESULTS' then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local timestamp = now + data.rawOffset + data.dstOffset
|
local timestamp = now + data.rawOffset + data.dstOffset
|
||||||
local utcoff = (data.rawOffset + data.dstOffset) / 3600
|
local utcoff = (data.rawOffset + data.dstOffset) / 3600
|
||||||
if utcoff == math.abs(utcoff) then
|
if utcoff == math.abs(utcoff) then
|
||||||
utcoff = '+' .. utilities.pretty_float(utcoff)
|
utcoff = '+' .. utilities.pretty_float(utcoff)
|
||||||
else
|
else
|
||||||
utcoff = utilities.pretty_float(utcoff)
|
utcoff = utilities.pretty_float(utcoff)
|
||||||
end
|
end
|
||||||
local output = string.format('```\n%s\n%s (UTC%s)\n```',
|
local output = string.format('```\n%s\n%s (UTC%s)\n```',
|
||||||
os.date('!%I:%M %p\n%A, %B %d, %Y', timestamp),
|
os.date('!%I:%M %p\n%A, %B %d, %Y', timestamp),
|
||||||
data.timeZoneName,
|
data.timeZoneName,
|
||||||
utcoff
|
utcoff
|
||||||
)
|
)
|
||||||
utilities.send_reply(self, msg, output, true)
|
utilities.send_reply(self, msg, output, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
return time
|
return time
|
||||||
|
@ -8,38 +8,38 @@ local utilities = require('otouto.utilities')
|
|||||||
translate.command = 'translate [text]'
|
translate.command = 'translate [text]'
|
||||||
|
|
||||||
function translate:init(config)
|
function translate:init(config)
|
||||||
assert(config.yandex_key,
|
assert(config.yandex_key,
|
||||||
'translate.lua requires a Yandex translate API key from http://tech.yandex.com/keys/get.'
|
'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)
|
translate.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('translate', true):t('tl', true).table
|
:t('translate', true):t('tl', true).table
|
||||||
translate.doc = config.cmd_pat .. [[translate [text]
|
translate.doc = config.cmd_pat .. [[translate [text]
|
||||||
Translates input or the replied-to message into the bot's language.]]
|
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
|
end
|
||||||
|
|
||||||
function translate:action(msg, config)
|
function translate:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, translate.doc, true)
|
utilities.send_reply(self, msg, translate.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local url = translate.base_url:format(URL.escape(input))
|
local url = translate.base_url:format(URL.escape(input))
|
||||||
local jstr, code = HTTPS.request(url)
|
local jstr, code = HTTPS.request(url)
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
if data.code ~= 200 then
|
if data.code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
return translate
|
return translate
|
||||||
|
@ -9,42 +9,42 @@ urbandictionary.command = 'urbandictionary <query>'
|
|||||||
urbandictionary.base_url = 'http://api.urbandictionary.com/v0/define?term='
|
urbandictionary.base_url = 'http://api.urbandictionary.com/v0/define?term='
|
||||||
|
|
||||||
function urbandictionary:init(config)
|
function urbandictionary:init(config)
|
||||||
urbandictionary.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
urbandictionary.triggers = utilities.triggers(self.info.username, config.cmd_pat)
|
||||||
:t('urbandictionary', true):t('ud', true):t('urban', true).table
|
:t('urbandictionary', true):t('ud', true):t('urban', true).table
|
||||||
urbandictionary.doc = [[
|
urbandictionary.doc = [[
|
||||||
/urbandictionary <query>
|
/urbandictionary <query>
|
||||||
Returns a definition from Urban Dictionary.
|
Returns a definition from Urban Dictionary.
|
||||||
Aliases: /ud, /urban
|
Aliases: /ud, /urban
|
||||||
]]
|
]]
|
||||||
urbandictionary.doc = urbandictionary.doc:gsub('/', config.cmd_pat)
|
urbandictionary.doc = urbandictionary.doc:gsub('/', config.cmd_pat)
|
||||||
end
|
end
|
||||||
|
|
||||||
function urbandictionary:action(msg, config)
|
function urbandictionary:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, urbandictionary.doc, true)
|
utilities.send_reply(self, msg, urbandictionary.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local url = urbandictionary.base_url .. URL.escape(input)
|
local url = urbandictionary.base_url .. URL.escape(input)
|
||||||
local jstr, code = HTTP.request(url)
|
local jstr, code = HTTP.request(url)
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
local output
|
local output
|
||||||
if data.result_type == 'no_results' then
|
if data.result_type == 'no_results' then
|
||||||
output = config.errors.results
|
output = config.errors.results
|
||||||
else
|
else
|
||||||
output = string.format('*%s*\n\n%s\n\n_%s_',
|
output = string.format('*%s*\n\n%s\n\n_%s_',
|
||||||
data.list[1].word:gsub('*', '*\\**'),
|
data.list[1].word:gsub('*', '*\\**'),
|
||||||
utilities.trim(utilities.md_escape(data.list[1].definition)),
|
utilities.trim(utilities.md_escape(data.list[1].definition)),
|
||||||
utilities.trim((data.list[1].example or '')):gsub('_', '_\\__')
|
utilities.trim((data.list[1].example or '')):gsub('_', '_\\__')
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
utilities.send_reply(self, msg, output, true)
|
utilities.send_reply(self, msg, output, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
return urbandictionary
|
return urbandictionary
|
||||||
|
@ -6,12 +6,12 @@ local JSON = require('dkjson')
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function weather:init(config)
|
function weather:init(config)
|
||||||
assert(config.owm_api_key,
|
assert(config.owm_api_key,
|
||||||
'weather.lua requires an OpenWeatherMap API key from http://openweathermap.org/API.'
|
'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.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('weather', true).table
|
||||||
weather.doc = config.cmd_pat .. [[weather <location>
|
weather.doc = config.cmd_pat .. [[weather <location>
|
||||||
Returns the current weather conditions for a given location.]]
|
Returns the current weather conditions for a given location.]]
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -19,37 +19,37 @@ weather.command = 'weather <location>'
|
|||||||
|
|
||||||
function weather:action(msg, config)
|
function weather:action(msg, config)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, weather.doc, true)
|
utilities.send_reply(self, msg, weather.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local coords = utilities.get_coords(input, config)
|
local coords = utilities.get_coords(input, config)
|
||||||
if type(coords) == 'string' then
|
if type(coords) == 'string' then
|
||||||
utilities.send_reply(self, msg, coords)
|
utilities.send_reply(self, msg, coords)
|
||||||
return
|
return
|
||||||
end
|
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)
|
local jstr, res = HTTP.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local jdat = JSON.decode(jstr)
|
local jdat = JSON.decode(jstr)
|
||||||
if jdat.cod ~= 200 then
|
if jdat.cod ~= 200 then
|
||||||
utilities.send_reply(self, msg, 'Error: City not found.')
|
utilities.send_reply(self, msg, 'Error: City not found.')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local celsius = string.format('%.2f', jdat.main.temp - 273.15)
|
local celsius = string.format('%.2f', jdat.main.temp - 273.15)
|
||||||
local fahrenheit = string.format('%.2f', celsius * (9/5) + 32)
|
local fahrenheit = string.format('%.2f', celsius * (9/5) + 32)
|
||||||
local output = '`' .. celsius .. '°C | ' .. fahrenheit .. '°F, ' .. jdat.weather[1].description .. '.`'
|
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
|
end
|
||||||
|
|
||||||
|
@ -6,54 +6,54 @@ local bindings = require('otouto.bindings')
|
|||||||
whoami.command = 'whoami'
|
whoami.command = 'whoami'
|
||||||
|
|
||||||
function whoami:init(config)
|
function whoami:init(config)
|
||||||
whoami.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('who'):t('whoami').table
|
whoami.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('who'):t('whoami').table
|
||||||
whoami.doc = [[
|
whoami.doc = [[
|
||||||
Returns user and chat info for you or the replied-to message.
|
Returns user and chat info for you or the replied-to message.
|
||||||
Alias: ]] .. config.cmd_pat .. 'who'
|
Alias: ]] .. config.cmd_pat .. 'who'
|
||||||
end
|
end
|
||||||
|
|
||||||
function whoami:action(msg)
|
function whoami:action(msg)
|
||||||
-- Operate on the replied-to message, if it exists.
|
-- Operate on the replied-to message, if it exists.
|
||||||
msg = msg.reply_to_message or msg
|
msg = msg.reply_to_message or msg
|
||||||
-- If it's a private conversation, bot is chat, unless bot is from.
|
-- 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
|
local chat = msg.from.id == msg.chat.id and self.info or msg.chat
|
||||||
-- Names for the user and group, respectively. HTML-escaped.
|
-- Names for the user and group, respectively. HTML-escaped.
|
||||||
local from_name = utilities.html_escape(
|
local from_name = utilities.html_escape(
|
||||||
utilities.build_name(
|
utilities.build_name(
|
||||||
msg.from.first_name,
|
msg.from.first_name,
|
||||||
msg.from.last_name
|
msg.from.last_name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
local chat_name = utilities.html_escape(
|
local chat_name = utilities.html_escape(
|
||||||
chat.title
|
chat.title
|
||||||
or utilities.build_name(chat.first_name, chat.last_name)
|
or utilities.build_name(chat.first_name, chat.last_name)
|
||||||
)
|
)
|
||||||
-- "Normalize" a group ID so it's not arbitrarily modified by the bot API.
|
-- "Normalize" a group ID so it's not arbitrarily modified by the bot API.
|
||||||
local chat_id = math.abs(chat.id)
|
local chat_id = math.abs(chat.id)
|
||||||
if chat_id > 1000000000000 then chat_id = chat_id - 1000000000000 end
|
if chat_id > 1000000000000 then chat_id = chat_id - 1000000000000 end
|
||||||
-- Do the thing.
|
-- Do the thing.
|
||||||
local output = string.format(
|
local output = string.format(
|
||||||
'You are %s <code>[%s]</code>, and you are messaging %s <code>[%s]</code>.',
|
'You are %s <code>[%s]</code>, and you are messaging %s <code>[%s]</code>.',
|
||||||
msg.from.username and string.format(
|
msg.from.username and string.format(
|
||||||
'@%s, also known as <b>%s</b>',
|
'@%s, also known as <b>%s</b>',
|
||||||
msg.from.username,
|
msg.from.username,
|
||||||
from_name
|
from_name
|
||||||
) or '<b>' .. from_name .. '</b>',
|
) or '<b>' .. from_name .. '</b>',
|
||||||
msg.from.id,
|
msg.from.id,
|
||||||
msg.chat.username and string.format(
|
msg.chat.username and string.format(
|
||||||
'@%s, also known as <b>%s</b>',
|
'@%s, also known as <b>%s</b>',
|
||||||
chat.username,
|
chat.username,
|
||||||
chat_name
|
chat_name
|
||||||
) or '<b>' .. chat_name .. '</b>',
|
) or '<b>' .. chat_name .. '</b>',
|
||||||
chat_id
|
chat_id
|
||||||
)
|
)
|
||||||
bindings.sendMessage(self, {
|
bindings.sendMessage(self, {
|
||||||
chat_id = msg.chat.id,
|
chat_id = msg.chat.id,
|
||||||
reply_to_message_id = msg.message_id,
|
reply_to_message_id = msg.message_id,
|
||||||
disable_web_page_preview = true,
|
disable_web_page_preview = true,
|
||||||
parse_mode = 'HTML',
|
parse_mode = 'HTML',
|
||||||
text = output
|
text = output
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
return whoami
|
return whoami
|
||||||
|
@ -8,83 +8,83 @@ local utilities = require('otouto.utilities')
|
|||||||
wikipedia.command = 'wikipedia <query>'
|
wikipedia.command = 'wikipedia <query>'
|
||||||
|
|
||||||
function wikipedia:init(config)
|
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.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.doc = config.cmd_pat .. [[wikipedia <query>
|
||||||
Returns an article from Wikipedia.
|
Returns an article from Wikipedia.
|
||||||
Aliases: ]] .. config.cmd_pat .. 'w, ' .. config.cmd_pat .. 'wiki'
|
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.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.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.art_url = 'https://' .. config.lang .. '.wikipedia.org/wiki/'
|
||||||
end
|
end
|
||||||
|
|
||||||
function wikipedia:action(msg, config)
|
function wikipedia:action(msg, config)
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, wikipedia.doc, true)
|
utilities.send_reply(self, msg, wikipedia.doc, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local jstr, code = HTTPS.request(wikipedia.search_url .. URL.escape(input))
|
local jstr, code = HTTPS.request(wikipedia.search_url .. URL.escape(input))
|
||||||
if code ~= 200 then
|
if code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
if data.query.searchinfo.totalhits == 0 then
|
if data.query.searchinfo.totalhits == 0 then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local title
|
local title
|
||||||
for _, v in ipairs(data.query.search) do
|
for _, v in ipairs(data.query.search) do
|
||||||
if not v.snippet:match('may refer to:') then
|
if not v.snippet:match('may refer to:') then
|
||||||
title = v.title
|
title = v.title
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not title then
|
if not title then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local res_jstr, res_code = HTTPS.request(wikipedia.res_url .. URL.escape(title))
|
local res_jstr, res_code = HTTPS.request(wikipedia.res_url .. URL.escape(title))
|
||||||
if res_code ~= 200 then
|
if res_code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local _, text = next(JSON.decode(res_jstr).query.pages)
|
local _, text = next(JSON.decode(res_jstr).query.pages)
|
||||||
if not text then
|
if not text then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
text = text.extract
|
text = text.extract
|
||||||
-- Remove crap and take only the first paragraph.
|
-- Remove crap and take only the first paragraph.
|
||||||
text = text:gsub('</?.->', ''):gsub('%[.+%]', '')
|
text = text:gsub('</?.->', ''):gsub('%[.+%]', '')
|
||||||
local l = text:find('\n')
|
local l = text:find('\n')
|
||||||
if l then
|
if l then
|
||||||
text = text:sub(1, l-1)
|
text = text:sub(1, l-1)
|
||||||
end
|
end
|
||||||
local url = wikipedia.art_url .. URL.escape(title)
|
local url = wikipedia.art_url .. URL.escape(title)
|
||||||
title = utilities.html_escape(title)
|
title = utilities.html_escape(title)
|
||||||
-- If the beginning of the article is the title, embolden that.
|
-- If the beginning of the article is the title, embolden that.
|
||||||
-- Otherwise, we'll add a title in bold.
|
-- Otherwise, we'll add a title in bold.
|
||||||
local short_title = title:gsub('%(.+%)', '')
|
local short_title = title:gsub('%(.+%)', '')
|
||||||
local combined_text, count = text:gsub('^'..short_title, '<b>'..short_title..'</b>')
|
local combined_text, count = text:gsub('^'..short_title, '<b>'..short_title..'</b>')
|
||||||
local body
|
local body
|
||||||
if count == 1 then
|
if count == 1 then
|
||||||
body = combined_text
|
body = combined_text
|
||||||
else
|
else
|
||||||
body = '<b>' .. title .. '</b>\n' .. text
|
body = '<b>' .. title .. '</b>\n' .. text
|
||||||
end
|
end
|
||||||
local output = string.format(
|
local output = string.format(
|
||||||
'%s\n<a href="%s">Read more.</a>',
|
'%s\n<a href="%s">Read more.</a>',
|
||||||
body,
|
body,
|
||||||
utilities.html_escape(url)
|
utilities.html_escape(url)
|
||||||
)
|
)
|
||||||
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
utilities.send_message(self, msg.chat.id, output, true, nil, 'html')
|
||||||
end
|
end
|
||||||
|
|
||||||
return wikipedia
|
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'
|
xkcd.strip_url = 'http://xkcd.com/%s/info.0.json'
|
||||||
|
|
||||||
function xkcd:init(config)
|
function xkcd:init(config)
|
||||||
xkcd.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('xkcd', true).table
|
xkcd.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('xkcd', true).table
|
||||||
xkcd.doc = config.cmd_pat .. [[xkcd [i]
|
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.]]
|
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)
|
local jstr = HTTP.request(xkcd.base_url)
|
||||||
if jstr then
|
if jstr then
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
if data then
|
if data then
|
||||||
xkcd.latest = data.num
|
xkcd.latest = data.num
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
xkcd.latest = xkcd.latest or 1700
|
xkcd.latest = xkcd.latest or 1700
|
||||||
end
|
end
|
||||||
|
|
||||||
function xkcd:action(msg, config)
|
function xkcd:action(msg, config)
|
||||||
local input = utilities.get_word(msg.text, 2)
|
local input = utilities.get_word(msg.text, 2)
|
||||||
if input == 'r' then
|
if input == 'r' then
|
||||||
input = math.random(xkcd.latest)
|
input = math.random(xkcd.latest)
|
||||||
elseif tonumber(input) then
|
elseif tonumber(input) then
|
||||||
input = tonumber(input)
|
input = tonumber(input)
|
||||||
else
|
else
|
||||||
input = xkcd.latest
|
input = xkcd.latest
|
||||||
end
|
end
|
||||||
local url = xkcd.strip_url:format(input)
|
local url = xkcd.strip_url:format(input)
|
||||||
local jstr, code = HTTP.request(url)
|
local jstr, code = HTTP.request(url)
|
||||||
if code == 404 then
|
if code == 404 then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
elseif code ~= 200 then
|
elseif code ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
else
|
else
|
||||||
local data = JSON.decode(jstr)
|
local data = JSON.decode(jstr)
|
||||||
local output = string.format('*%s (*[%s](%s)*)*\n_%s_',
|
local output = string.format('*%s (*[%s](%s)*)*\n_%s_',
|
||||||
data.safe_title:gsub('*', '*\\**'),
|
data.safe_title:gsub('*', '*\\**'),
|
||||||
data.num,
|
data.num,
|
||||||
data.img,
|
data.img,
|
||||||
data.alt:gsub('_', '_\\__')
|
data.alt:gsub('_', '_\\__')
|
||||||
)
|
)
|
||||||
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
utilities.send_message(self, msg.chat.id, output, false, nil, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return xkcd
|
return xkcd
|
||||||
|
@ -8,12 +8,12 @@ local JSON = require('dkjson')
|
|||||||
local utilities = require('otouto.utilities')
|
local utilities = require('otouto.utilities')
|
||||||
|
|
||||||
function youtube:init(config)
|
function youtube:init(config)
|
||||||
assert(config.google_api_key,
|
assert(config.google_api_key,
|
||||||
'youtube.lua requires a Google API key from http://console.developers.google.com.'
|
'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.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('youtube', true):t('yt', true).table
|
||||||
youtube.doc = config.cmd_pat .. [[youtube <query>
|
youtube.doc = config.cmd_pat .. [[youtube <query>
|
||||||
Returns the top result from YouTube.
|
Returns the top result from YouTube.
|
||||||
Alias: ]] .. config.cmd_pat .. 'yt'
|
Alias: ]] .. config.cmd_pat .. 'yt'
|
||||||
end
|
end
|
||||||
@ -22,32 +22,32 @@ youtube.command = 'youtube <query>'
|
|||||||
|
|
||||||
function youtube:action(msg, config)
|
function youtube:action(msg, config)
|
||||||
|
|
||||||
local input = utilities.input_from_msg(msg)
|
local input = utilities.input_from_msg(msg)
|
||||||
if not input then
|
if not input then
|
||||||
utilities.send_reply(self, msg, youtube.doc, true)
|
utilities.send_reply(self, msg, youtube.doc, true)
|
||||||
return
|
return
|
||||||
end
|
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)
|
local jstr, res = HTTPS.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
utilities.send_reply(self, msg, config.errors.connection)
|
utilities.send_reply(self, msg, config.errors.connection)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local jdat = JSON.decode(jstr)
|
local jdat = JSON.decode(jstr)
|
||||||
if jdat.pageInfo.totalResults == 0 then
|
if jdat.pageInfo.totalResults == 0 then
|
||||||
utilities.send_reply(self, msg, config.errors.results)
|
utilities.send_reply(self, msg, config.errors.results)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local vid_url = 'https://www.youtube.com/watch?v=' .. jdat.items[1].id.videoId
|
local vid_url = 'https://www.youtube.com/watch?v=' .. jdat.items[1].id.videoId
|
||||||
local vid_title = jdat.items[1].snippet.title
|
local vid_title = jdat.items[1].snippet.title
|
||||||
vid_title = vid_title:gsub('%(.+%)',''):gsub('%[.+%]','')
|
vid_title = vid_title:gsub('%(.+%)',''):gsub('%[.+%]','')
|
||||||
local output = '[' .. vid_title .. '](' .. vid_url .. ')'
|
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
|
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
|
-- 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.
|
-- 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)
|
function utilities:send_message(chat_id, text, disable_web_page_preview, reply_to_message_id, use_markdown)
|
||||||
local parse_mode
|
local parse_mode
|
||||||
if type(use_markdown) == 'string' then
|
if type(use_markdown) == 'string' then
|
||||||
parse_mode = use_markdown
|
parse_mode = use_markdown
|
||||||
elseif use_markdown == true then
|
elseif use_markdown == true then
|
||||||
parse_mode = 'markdown'
|
parse_mode = 'markdown'
|
||||||
end
|
end
|
||||||
return bindings.request(self, 'sendMessage', {
|
return bindings.request(self, 'sendMessage', {
|
||||||
chat_id = chat_id,
|
chat_id = chat_id,
|
||||||
text = text,
|
text = text,
|
||||||
disable_web_page_preview = disable_web_page_preview,
|
disable_web_page_preview = disable_web_page_preview,
|
||||||
reply_to_message_id = reply_to_message_id,
|
reply_to_message_id = reply_to_message_id,
|
||||||
parse_mode = parse_mode
|
parse_mode = parse_mode
|
||||||
} )
|
} )
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities:send_reply(old_msg, text, use_markdown)
|
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
|
end
|
||||||
|
|
||||||
-- get the indexed word in a string
|
-- get the indexed word in a string
|
||||||
function utilities.get_word(s, i)
|
function utilities.get_word(s, i)
|
||||||
s = s or ''
|
s = s or ''
|
||||||
i = i or 1
|
i = i or 1
|
||||||
local n = 0
|
local n = 0
|
||||||
for w in s:gmatch('%g+') do
|
for w in s:gmatch('%g+') do
|
||||||
n = n + 1
|
n = n + 1
|
||||||
if n == i then return w end
|
if n == i then return w end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns the string after the first space.
|
-- Returns the string after the first space.
|
||||||
function utilities.input(s)
|
function utilities.input(s)
|
||||||
if not s:find(' ') then
|
if not s:find(' ') then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return s:sub(s:find(' ')+1)
|
return s:sub(s:find(' ')+1)
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities.input_from_msg(msg)
|
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
|
end
|
||||||
|
|
||||||
-- Calculates the length of the given string as UTF-8 characters
|
-- Calculates the length of the given string as UTF-8 characters
|
||||||
@ -72,180 +72,180 @@ end
|
|||||||
|
|
||||||
-- Trims whitespace from a string.
|
-- Trims whitespace from a string.
|
||||||
function utilities.trim(str)
|
function utilities.trim(str)
|
||||||
local s = str:gsub('^%s*(.-)%s*$', '%1')
|
local s = str:gsub('^%s*(.-)%s*$', '%1')
|
||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Loads a JSON file as a table.
|
-- Loads a JSON file as a table.
|
||||||
function utilities.load_data(filename)
|
function utilities.load_data(filename)
|
||||||
local f = io.open(filename)
|
local f = io.open(filename)
|
||||||
if f then
|
if f then
|
||||||
local s = f:read('*all')
|
local s = f:read('*all')
|
||||||
f:close()
|
f:close()
|
||||||
return JSON.decode(s)
|
return JSON.decode(s)
|
||||||
else
|
else
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Saves a table to a JSON file.
|
-- Saves a table to a JSON file.
|
||||||
function utilities.save_data(filename, data)
|
function utilities.save_data(filename, data)
|
||||||
local s = JSON.encode(data)
|
local s = JSON.encode(data)
|
||||||
local f = io.open(filename, 'w')
|
local f = io.open(filename, 'w')
|
||||||
f:write(s)
|
f:write(s)
|
||||||
f:close()
|
f:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Gets coordinates for a location. Used by gMaps.lua, time.lua, weather.lua.
|
-- Gets coordinates for a location. Used by gMaps.lua, time.lua, weather.lua.
|
||||||
function utilities.get_coords(input, config)
|
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)
|
local jstr, res = HTTP.request(url)
|
||||||
if res ~= 200 then
|
if res ~= 200 then
|
||||||
return config.errors.connection
|
return config.errors.connection
|
||||||
end
|
end
|
||||||
|
|
||||||
local jdat = JSON.decode(jstr)
|
local jdat = JSON.decode(jstr)
|
||||||
if jdat.status == 'ZERO_RESULTS' then
|
if jdat.status == 'ZERO_RESULTS' then
|
||||||
return config.errors.results
|
return config.errors.results
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lat = jdat.results[1].geometry.location.lat,
|
lat = jdat.results[1].geometry.location.lat,
|
||||||
lon = jdat.results[1].geometry.location.lng
|
lon = jdat.results[1].geometry.location.lng
|
||||||
}
|
}
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get the number of values in a key/value table.
|
-- Get the number of values in a key/value table.
|
||||||
function utilities.table_size(tab)
|
function utilities.table_size(tab)
|
||||||
local i = 0
|
local i = 0
|
||||||
for _,_ in pairs(tab) do
|
for _,_ in pairs(tab) do
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
return i
|
return i
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Just an easy way to get a user's full name.
|
-- Just an easy way to get a user's full name.
|
||||||
-- Alternatively, abuse it to concat two strings like I do.
|
-- Alternatively, abuse it to concat two strings like I do.
|
||||||
function utilities.build_name(first, last)
|
function utilities.build_name(first, last)
|
||||||
if last then
|
if last then
|
||||||
return first .. ' ' .. last
|
return first .. ' ' .. last
|
||||||
else
|
else
|
||||||
return first
|
return first
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities:resolve_username(input)
|
function utilities:resolve_username(input)
|
||||||
input = input:gsub('^@', '')
|
input = input:gsub('^@', '')
|
||||||
for _, user in pairs(self.database.users) do
|
for _, user in pairs(self.database.users) do
|
||||||
if user.username and user.username:lower() == input:lower() then
|
if user.username and user.username:lower() == input:lower() then
|
||||||
local t = {}
|
local t = {}
|
||||||
for key, val in pairs(user) do
|
for key, val in pairs(user) do
|
||||||
t[key] = val
|
t[key] = val
|
||||||
end
|
end
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities:handle_exception(err, message, config)
|
function utilities:handle_exception(err, message, config)
|
||||||
local output = string.format(
|
local output = string.format(
|
||||||
'\n[%s]\n%s: %s\n%s\n',
|
'\n[%s]\n%s: %s\n%s\n',
|
||||||
os.date('%F %T'),
|
os.date('%F %T'),
|
||||||
self.info.username,
|
self.info.username,
|
||||||
err or '',
|
err or '',
|
||||||
message
|
message
|
||||||
)
|
)
|
||||||
if config.log_chat then
|
if config.log_chat then
|
||||||
output = '```' .. output .. '```'
|
output = '```' .. output .. '```'
|
||||||
utilities.send_message(self, config.log_chat, output, true, nil, true)
|
utilities.send_message(self, config.log_chat, output, true, nil, true)
|
||||||
else
|
else
|
||||||
print(output)
|
print(output)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities.download_file(url, filename)
|
function utilities.download_file(url, filename)
|
||||||
if not filename then
|
if not filename then
|
||||||
filename = url:match('.+/(.-)$') or os.time()
|
filename = url:match('.+/(.-)$') or os.time()
|
||||||
filename = '/tmp/' .. filename
|
filename = '/tmp/' .. filename
|
||||||
end
|
end
|
||||||
local body = {}
|
local body = {}
|
||||||
local doer = HTTP
|
local doer = HTTP
|
||||||
local do_redir = true
|
local do_redir = true
|
||||||
if url:match('^https') then
|
if url:match('^https') then
|
||||||
doer = HTTPS
|
doer = HTTPS
|
||||||
do_redir = false
|
do_redir = false
|
||||||
end
|
end
|
||||||
local _, res = doer.request{
|
local _, res = doer.request{
|
||||||
url = url,
|
url = url,
|
||||||
sink = ltn12.sink.table(body),
|
sink = ltn12.sink.table(body),
|
||||||
redirect = do_redir
|
redirect = do_redir
|
||||||
}
|
}
|
||||||
if res ~= 200 then return false end
|
if res ~= 200 then return false end
|
||||||
local file = io.open(filename, 'w+')
|
local file = io.open(filename, 'w+')
|
||||||
file:write(table.concat(body))
|
file:write(table.concat(body))
|
||||||
file:close()
|
file:close()
|
||||||
return filename
|
return filename
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities.md_escape(text)
|
function utilities.md_escape(text)
|
||||||
return text:gsub('_', '\\_')
|
return text:gsub('_', '\\_')
|
||||||
:gsub('%[', '\\['):gsub('%]', '\\]')
|
:gsub('%[', '\\['):gsub('%]', '\\]')
|
||||||
:gsub('%*', '\\*'):gsub('`', '\\`')
|
:gsub('%*', '\\*'):gsub('`', '\\`')
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities.html_escape(text)
|
function utilities.html_escape(text)
|
||||||
return text:gsub('&', '&'):gsub('<', '<'):gsub('>', '>')
|
return text:gsub('&', '&'):gsub('<', '<'):gsub('>', '>')
|
||||||
end
|
end
|
||||||
|
|
||||||
utilities.triggers_meta = {}
|
utilities.triggers_meta = {}
|
||||||
utilities.triggers_meta.__index = utilities.triggers_meta
|
utilities.triggers_meta.__index = utilities.triggers_meta
|
||||||
function utilities.triggers_meta:t(pattern, has_args)
|
function utilities.triggers_meta:t(pattern, has_args)
|
||||||
local username = self.username:lower()
|
local username = self.username:lower()
|
||||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'$')
|
table.insert(self.table, '^'..self.cmd_pat..pattern..'$')
|
||||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'@'..username..'$')
|
table.insert(self.table, '^'..self.cmd_pat..pattern..'@'..username..'$')
|
||||||
if has_args then
|
if has_args then
|
||||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'%s+[^%s]*')
|
table.insert(self.table, '^'..self.cmd_pat..pattern..'%s+[^%s]*')
|
||||||
table.insert(self.table, '^'..self.cmd_pat..pattern..'@'..username..'%s+[^%s]*')
|
table.insert(self.table, '^'..self.cmd_pat..pattern..'@'..username..'%s+[^%s]*')
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities.triggers(username, cmd_pat, trigger_table)
|
function utilities.triggers(username, cmd_pat, trigger_table)
|
||||||
local self = setmetatable({}, utilities.triggers_meta)
|
local self = setmetatable({}, utilities.triggers_meta)
|
||||||
self.username = username
|
self.username = username
|
||||||
self.cmd_pat = cmd_pat
|
self.cmd_pat = cmd_pat
|
||||||
self.table = trigger_table or {}
|
self.table = trigger_table or {}
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities.with_http_timeout(timeout, fun)
|
function utilities.with_http_timeout(timeout, fun)
|
||||||
local original = HTTP.TIMEOUT
|
local original = HTTP.TIMEOUT
|
||||||
HTTP.TIMEOUT = timeout
|
HTTP.TIMEOUT = timeout
|
||||||
fun()
|
fun()
|
||||||
HTTP.TIMEOUT = original
|
HTTP.TIMEOUT = original
|
||||||
end
|
end
|
||||||
|
|
||||||
function utilities.pretty_float(x)
|
function utilities.pretty_float(x)
|
||||||
if x % 1 == 0 then
|
if x % 1 == 0 then
|
||||||
return tostring(math.floor(x))
|
return tostring(math.floor(x))
|
||||||
else
|
else
|
||||||
return tostring(x)
|
return tostring(x)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- This table will store unsavory characters that are not properly displayed,
|
-- This table will store unsavory characters that are not properly displayed,
|
||||||
-- or are just not fun to type.
|
-- or are just not fun to type.
|
||||||
utilities.char = {
|
utilities.char = {
|
||||||
zwnj = '',
|
zwnj = '',
|
||||||
arabic = '[\216-\219][\128-\191]',
|
arabic = '[\216-\219][\128-\191]',
|
||||||
rtl_override = '',
|
rtl_override = '',
|
||||||
rtl_mark = '',
|
rtl_mark = '',
|
||||||
em_dash = '—',
|
em_dash = '—',
|
||||||
utf_8 = '[%z\1-\127\194-\244][\128-\191]',
|
utf_8 = '[%z\1-\127\194-\244][\128-\191]',
|
||||||
}
|
}
|
||||||
|
|
||||||
utilities.set_meta = {}
|
utilities.set_meta = {}
|
||||||
@ -283,7 +283,7 @@ end
|
|||||||
-- More to be added.
|
-- More to be added.
|
||||||
utilities.style = {}
|
utilities.style = {}
|
||||||
utilities.style.enquote = function(title, body)
|
utilities.style.enquote = function(title, body)
|
||||||
return '*' .. title:gsub('*', '\\*') .. ':*\n"' .. utilities.md_escape(body) .. '"'
|
return '*' .. title:gsub('*', '\\*') .. ':*\n"' .. utilities.md_escape(body) .. '"'
|
||||||
end
|
end
|
||||||
|
|
||||||
return utilities
|
return utilities
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
# config.lua), delete state file after stop, wait five seconds, and restart.
|
# config.lua), delete state file after stop, wait five seconds, and restart.
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
tg/bin/telegram-cli -P 4567 -E
|
tg/bin/telegram-cli -P 4567 -E
|
||||||
[ -f ~/.telegram-cli/state ] && rm ~/.telegram-cli/state
|
[ -f ~/.telegram-cli/state ] && rm ~/.telegram-cli/state
|
||||||
echo 'tg has stopped. ^C to exit.'
|
echo 'tg has stopped. ^C to exit.'
|
||||||
sleep 5s
|
sleep 5s
|
||||||
done
|
done
|
||||||
|
Reference in New Issue
Block a user