Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
638 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/plugins/administration/antispam.mattata b/plugins/administration/antispam.mattata
index e447d86..ca2668e 100644
--- a/plugins/administration/antispam.mattata
+++ b/plugins/administration/antispam.mattata
@@ -1,291 +1,291 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local antispam = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function antispam:init(configuration)
antispam.commands = mattata.commands(self.info.username):command('antispam').table
antispam.media_types = {
'text',
'forwarded',
'sticker',
'photo',
'video',
'location',
'voice',
'game',
'venue',
'video note',
'invoice',
'contact',
'dice',
'poll'
}
antispam.default_values = {
['text'] = configuration.administration.default.antispam.text,
['forwarded'] = configuration.administration.default.antispam.forwarded,
['sticker'] = configuration.administration.default.antispam.sticker,
['photo'] = configuration.administration.default.antispam.photo,
['video'] = configuration.administration.default.antispam.video,
['location'] = configuration.administration.default.antispam.location,
['voice'] = configuration.administration.default.antispam.voice,
['game'] = configuration.administration.default.antispam.game,
['venue'] = configuration.administration.default.antispam.venue,
['video note'] = configuration.administration.default.antispam.video_note,
['invoice'] = configuration.administration.default.antispam.invoice,
['contact'] = configuration.administration.default.antispam.contact,
['dice'] = configuration.administration.default.antispam.dice,
['poll'] = configuration.administration.default.antispam.poll
}
end
function antispam.on_member_join(_, message)
for _, user in pairs(message.new_chat_members) do
redis:set('join_time:' .. user.id .. ':' .. message.chat.id, os.time())
end
end
function antispam:on_new_message(message, configuration, language)
if message.from.id == 777000 then
return false
end
-- Thanks to GingerPlusPlus for the idea
if message.chat.type ~= 'private' and mattata.get_setting(message.chat.id, 'remove pasted code') then
if message.entities then
for _, entity in pairs(message.entities) do
if (entity.type == 'pre' or entity.type == 'code') and entity.length > configuration.administration.global_antispam.max_code_length and not mattata.is_group_admin(message.chat.id, message.from.id) then
local success = mattata.delete_message(message.chat.id, message.message_id)
if success then
local name = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local output = string.format(language['antispam']['11'], name, configuration.administration.global_antispam.max_code_length, self.info.username:lower())
return mattata.send_message(message.chat.id, output, 'html', true)
end
return false
end
end
end
end
if message.chat.type == 'supergroup' and mattata.get_setting(message.chat.id, 'antilink') and message.is_invite_link then
if not mattata.is_group_admin(message.chat.id, message.from.id) and not mattata.is_global_admin(message.from.id) and message.is_invite_link then
local action = mattata.get_setting(message.chat.id, 'ban not kick') and mattata.ban_chat_member or mattata.kick_chat_member
local punishment = mattata.get_setting(message.chat.id, 'ban not kick') and 'banned' or 'kicked'
local success = action(message.chat.id, message.from.id)
local output
if success then
local banned_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local admin_username = mattata.get_formatted_user(self.info.id, self.info.first_name, 'html')
output = string.format(language['antispam']['12'], admin_username, self.info.id, punishment, banned_username, message.from.id, mattata.escape_html(message.chat.title), message.chat.id, tostring(message.chat.id):gsub('^%-100', ''), message.from.id)
mattata.send_message(log_chat, output, 'html')
else
output = string.format(language['antispam']['13'], punishment:gsub('^%l', string.upper), banned_username)
mattata.send_message(message.chat.id, output, 'html')
end
mattata.delete_message(message.chat.id, message.message_id)
return
end
else
local whitelisted = true
local links = mattata.check_links(message, true, true)
if links and #links > 0 then
for _, link in pairs(links) do
if not redis:get('whitelisted_links:' .. message.chat.id .. ':' .. link) then
whitelisted = false
break
end
end
end
if not whitelisted and not message.text:match('^[!/#]whitelistlink') and not message.text:match('^[!/#]wl') then
return mattata.send_reply(message, language['antispam']['14'])
end
end
end
local messages = redis:get('messages:' .. message.from.id .. ':' .. message.chat.id) or 0
if message.chat.type == 'supergroup' and (message.entities or message.photo or message.document) and mattata.get_setting(message.chat.id, 'kick media on join') and messages <= 2 and not mattata.is_group_admin(message.chat.id, message.from.id) and redis:get('join_time:' .. message.from.id .. ':' .. message.chat.id) then
redis:del('messages:' .. message.from.id .. ':' .. message.chat.id)
local log_actions = mattata.get_setting(message.chat.id, 'log administrative actions')
local log_chat = mattata.get_log_chat(message.chat.id)
local kicked_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local output = string.format(language['antispam']['15'], kicked_username, message.from.id, mattata.escape_html(message.chat.title), message.chat.id, tostring(message.chat.id):gsub('^%-100', ''), message.from.id)
if message.photo or message.document then
mattata.delete_message(message.chat.id, message.message_id)
if log_actions then
mattata.send_message(log_chat, output, 'html')
end
return mattata.kick_chat_member(message.chat.id, message.from.id)
end
for _, entities in pairs(message.entities) do
if entities.type == 'url' then
mattata.delete_message(message.chat.id, message.message_id)
if log_actions then
mattata.send_message(log_chat, output, 'html')
end
return mattata.kick_chat_member(message.chat.id, message.from.id)
end
end
end
end
function antispam.get_keyboard(chat_id, language)
local status = redis:hget('chat:' .. chat_id .. ':settings', 'antispam') and true or false
local caption = status and language['antispam']['1'] or language['antispam']['2']
local keyboard = {
['inline_keyboard'] = {}
}
table.insert(keyboard.inline_keyboard, {{
['text'] = caption,
['callback_data'] = 'antispam:' .. chat_id .. ':' .. caption:lower()
}})
if status then
for _, media in pairs(antispam.media_types) do
local current = mattata.get_value(chat_id, media .. ' limit') or antispam.default_values[media]
if not mattata.get_setting(chat_id, 'allow ' .. media) then
table.insert(keyboard.inline_keyboard, {{
['text'] = media:gsub('^%l', string.upper),
['callback_data'] = 'antispam:nil'
}, {
['text'] = '-',
['callback_data'] = 'antispam:' .. chat_id .. ':limit:' .. media .. ':' .. tonumber(current) - 1
}, {
['text'] = tostring(current),
['callback_data'] = 'antispam:nil'
}, {
['text'] = '+',
['callback_data'] = 'antispam:' .. chat_id .. ':limit:' .. media .. ':' .. tonumber(current) + 1
}, {
['text'] = language['antispam']['3'],
['callback_data'] = 'antispam:' .. chat_id .. ':toggle:' .. media
}})
else
table.insert(keyboard.inline_keyboard, {{
['text'] = media:gsub('^%l', string.upper),
['callback_data'] = 'antispam:nil'
}, {
['text'] = string.format(language['antispam']['4'], media),
['callback_data'] = 'antispam:' .. chat_id .. ':toggle:' .. media
}})
end
end
end
table.insert(keyboard.inline_keyboard, {{
['text'] = mattata.symbols.back .. ' ' .. language['antispam']['5'],
['callback_data'] = 'administration:' .. chat_id .. ':page:1'
}})
return keyboard
end
function antispam.is_user_spamming(message)
if message.media_type == '' or mattata.get_setting(message.chat.id, 'allow ' .. message.media_type) then
return false
end
local limit = mattata.get_value(message.chat.id, message.media_type .. ' limit') or antispam.default_values[message.media_type]
local current = redis:get('antispam:' .. message.media_type .. ':' .. message.chat.id .. ':' .. message.from.id) or 1
redis:setex('antispam:' .. message.media_type .. ':' .. message.chat.id .. ':' .. message.from.id, 5, tonumber(current) + 1)
if tonumber(current) == tonumber(limit) then
return true, message.media_type
elseif message.media_type == 'rtl' and mattata.get_setting(message.chat.id, 'antirtl') then
return true, 'rtl'
end
return false
end
function antispam:process_message(message, _, language)
if message.chat.type ~= 'supergroup' then
return false, 'The chat is not a supergroup!'
elseif mattata.is_group_admin(message.chat.id, message.from.id) then
return false, 'That user is an administrator in this chat!'
elseif mattata.is_global_admin(message.from.id) then
return false, 'That user is a global admin!'
elseif not mattata.get_setting(message.chat.id, 'use administration') then
return false, 'The administration plugin is switched off in this chat!'
elseif not mattata.get_setting(message.chat.id, 'antispam') then
return false, 'The antispam plugin is switched off in this chat!'
end
local is_spamming, media_type = antispam.is_user_spamming(message)
if not is_spamming then
return false, 'This user is not spamming!'
end
local action = mattata.get_setting(message.chat.id, 'ban not kick') and mattata.ban_chat_member or mattata.kick_chat_member
local success, error_message = action(message.chat.id, message.from.id)
if not success then
return false, error_message
elseif mattata.get_setting(message.chat.id, 'log administrative actions') then
mattata.send_message(
mattata.get_log_chat(message.chat.id),
string.format(
'<pre>' .. language['antispam']['6'] .. '</pre>',
mattata.escape_html(self.info.first_name),
self.info.id,
mattata.escape_html(message.from.first_name),
message.from.id,
mattata.escape_html(message.chat.title),
message.chat.id,
media_type
),
'html'
)
end
return mattata.send_message(
message,
string.format(
language['antispam']['7'],
message.from.username and '@' .. message.from.username or message.from.first_name,
media_type
)
)
end
function antispam.on_callback_query(_, callback_query, message, _, language)
local chat_id = (message and message.chat and message.chat.type == 'supergroup') and message.chat.id or callback_query.data:match('^(%-%d+):?')
if not chat_id then
mattata.answer_callback_query(callback_query.id, language['errors']['generic'])
return false, 'No chat ID was found!'
elseif not mattata.is_group_admin(chat_id, callback_query.from.id) then
mattata.answer_callback_query(callback_query.id, language['errors']['admin'])
return false, 'That user is not an admin/mod in this chat!'
end
if callback_query.data:match('^%-%d+:limit:.-:.-$') then
local spam_type, limit = callback_query.data:match('^%-%d+:limit:(.-):(.-)$')
if tonumber(limit) > 100 then
local output = language['antispam']['8']
mattata.answer_callback_query(callback_query.id, output)
return false, output
elseif tonumber(limit) < 1 then
local output = language['antispam']['9']
mattata.answer_callback_query(callback_query.id, output)
return false, output
elseif tonumber(limit) == nil then
return false, 'The limit given wasn\'t of type "number"!'
end
redis:hset('chat:' .. chat_id .. ':info', spam_type .. ' limit', tonumber(limit))
elseif callback_query.data:match('^%-%d+:toggle:.-$') then
local spam_type = callback_query.data:match('^%-%d+:toggle:(.-)$')
mattata.toggle_setting(chat_id, 'allow ' .. spam_type)
elseif callback_query.data:match('^%-%d+:disable$') then
redis:hdel('chat:' .. chat_id .. ':settings', 'antispam')
elseif callback_query.data:match('^%-%d+:enable$') then
redis:hset('chat:' .. chat_id .. ':settings', 'antispam', true)
end
local keyboard = antispam.get_keyboard(chat_id, language)
return mattata.edit_message_reply_markup(message.chat.id, message.message_id, nil, keyboard)
end
function antispam.on_message(_, message, _, language)
if message.chat.type ~= 'supergroup' then
mattata.send_reply(message, language['errors']['supergroup'])
return false, 'The chat is not a supergroup!'
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
mattata.send_reply(message, language['errors']['admin'])
return false, 'That user is not an admin/mod in this chat!'
end
local output = string.format(language['antispam']['10'], message.chat.title)
local keyboard = antispam.get_keyboard(message.chat.id, language)
return mattata.send_message(message.chat.id, output, nil, true, false, nil, keyboard)
end
return antispam
\ No newline at end of file
diff --git a/plugins/administration/ban.mattata b/plugins/administration/ban.mattata
index a0e14fd..dde6dc7 100644
--- a/plugins/administration/ban.mattata
+++ b/plugins/administration/ban.mattata
@@ -1,95 +1,95 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local ban = {}
local mattata = require('mattata')
function ban:init()
ban.commands = mattata.commands(self.info.username):command('ban').table
ban.help = '/ban [user] - Bans a user from the current chat. This command can only be used by moderators and administrators of a supergroup.'
end
function ban:on_message(message, _, language)
if message.chat.type ~= 'supergroup' then
local output = language['errors']['supergroup']
return mattata.send_reply(message, output)
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
local output = language['errors']['admin']
return mattata.send_reply(message, output)
end
local reason = false
local user = false
local input = mattata.input(message)
-- check the message object for any users this command
-- is intended to be executed on
if message.reply then
user = message.reply.from.id
if input then
reason = input
end
elseif input and input:match(' ') then
user, reason = input:match('^(.-) (.-)$')
elseif input then
user = input
end
if not user then
local output = language['ban']['1']
local success = mattata.send_force_reply(message, output)
if success then
mattata.set_command_action(message.chat.id, success.result.message_id, '/ban')
end
return
end
if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
reason = reason:match('^[Ff][Oo][Rr] (.-)$')
end
if tonumber(user) == nil and not user:match('^%@') then
user = '@' .. user
end
local user_object = mattata.get_user(user) or mattata.get_chat(user) -- resolve the username/ID to a user object
if not user_object then
return mattata.send_reply(message, language.errors.unknown)
elseif user_object.result.id == self.info.id then
return false -- don't let the bot ban itself
end
user_object = user_object.result
local status = mattata.get_chat_member(message.chat.id, user_object.id)
local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
if not status then
local output = language['errors']['generic']
return mattata.send_reply(message, output)
elseif is_admin then -- we won't try and ban moderators and administrators.
local output = language['ban']['2']
return mattata.send_reply(message, output)
elseif status.result.status == 'kicked' then -- check if the user has already been kicked
local output = language['ban']['4']
return mattata.send_reply(message, output)
end
local success = mattata.ban_chat_member(message.chat.id, user_object.id) -- attempt to ban the user from the group
if not success then -- since we've ruled everything else out, it's safe to say if it wasn't a success then the bot just isn't an administrator in the group
local output = language['ban']['5']
return mattata.send_reply(message, output)
end
mattata.increase_administrative_action(message.chat.id, user_object.id, 'bans')
reason = reason and ', for ' .. reason or ''
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local banned_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
local output
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
output = string.format(language['ban']['6'], admin_username, message.from.id, banned_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
mattata.send_message(log_chat, output, 'html')
else
output = string.format(language['ban']['7'], admin_username, banned_username, reason)
mattata.send_message(message.chat.id, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
mattata.delete_message(message.chat.id, message.message_id)
end
return
end
return ban
\ No newline at end of file
diff --git a/plugins/administration/channel.mattata b/plugins/administration/channel.mattata
index 54688f0..e06884b 100644
--- a/plugins/administration/channel.mattata
+++ b/plugins/administration/channel.mattata
@@ -1,93 +1,93 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local channel = {}
local mattata = require('mattata')
local socket = require('socket')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function channel:init()
channel.commands = mattata.commands(self.info.username):command('channel'):command('ch'):command('msg').table
channel.help = '/channel <channel> <message> - Sends a message to a Telegram channel/group. The channel/group can be specified via ID or username. Messages can be formatted with Markdown. Users can only send messages to channels/groups they own/administrate. Aliases: /ch, /msg.'
end
function channel:on_callback_query(callback_query, message, configuration, language)
local request = redis:hget('temp:channel', callback_query.data)
if not request then
return false
end
request = json.decode(request)
if request.from ~= callback_query.from.id then
return mattata.answer_callback_query(callback_query.id, language['channel']['1'])
elseif not mattata.is_group_admin(request.target, request.from) then
return mattata.answer_callback_query(callback_query.id, language['channel']['2'])
end
local success = mattata.send_message(request.target, request.text, 'markdown')
if not success then
return mattata.edit_message_text(message.chat.id, message.message_id, language['channel']['3'])
end
redis:hdel('temp:channel', callback_query.data)
return mattata.edit_message_text(message.chat.id, message.message_id, language['channel']['4'])
end
function channel:on_message(message, configuration, language)
if message.chat.type == 'channel' then
return false
end
local input = mattata.input(message)
if not input then
return mattata.send_reply(message, channel.help)
end
local target = mattata.get_word(input)
if tonumber(target) == nil and not target:match('^@') then
target = '@' .. target
end
target = mattata.get_chat_id(target) or target
local admin_list = mattata.get_chat_administrators(target)
if not admin_list and not mattata.is_global_admin(message.from.id) then
return mattata.send_reply(message, language['channel']['5'])
elseif not mattata.is_global_admin(message.from.id) then -- Make configured owners an exception.
local is_admin = false
for _, admin in ipairs(admin_list.result) do
if admin.user.id == message.from.id then
is_admin = true
end
end
if not is_admin then
return mattata.send_reply(message, language['channel']['6'])
end
end
local text = input:match(' (.-)$')
if not text then
return mattata.send_reply(message, language['channel']['7'])
end
local request_id = tostring(socket.gettime()):gsub('%D', '')
local keyboard = json.encode({
['inline_keyboard'] = {
{
{
['text'] = language['channel']['9'],
['callback_data'] = 'channel:' .. request_id
}
}
}
})
local temp_text = '*' .. language['channel']['8'] .. '*\n\n' .. text
local success = mattata.send_message(message.chat.id, temp_text, 'markdown', true, false, nil, keyboard)
if not success then
return mattata.send_reply(message, language['channel']['10'])
end
local payload = json.encode({
['target'] = target,
['text'] = text,
['from'] = message.from.id
})
redis:hset('temp:channel', request_id, payload)
return success
end
return channel
\ No newline at end of file
diff --git a/plugins/administration/delete.mattata b/plugins/administration/delete.mattata
index bf66895..8e5ce31 100644
--- a/plugins/administration/delete.mattata
+++ b/plugins/administration/delete.mattata
@@ -1,61 +1,61 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local delete = {}
local mattata = require('mattata')
function delete:init()
delete.commands = mattata.commands(self.info.username):command('delete').table
delete.help = '/delete [message ID] - Deletes the specified (or replied-to) message.'
end
function delete:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = mattata.input(message.text)
or (
message.reply
and message.reply.message_id
)
if not input
or tonumber(input) == nil
then
return mattata.send_reply(
message,
delete.help
)
end
local success = mattata.delete_message(
message.chat.id,
tonumber(input)
)
if not success
then
return mattata.send_reply(
message,
language['delete']['1']
)
end
return mattata.delete_message(
message.chat.id,
message.message_id
)
end
return delete
\ No newline at end of file
diff --git a/plugins/administration/delfed.mattata b/plugins/administration/delfed.mattata
index 64ce890..33a11a5 100644
--- a/plugins/administration/delfed.mattata
+++ b/plugins/administration/delfed.mattata
@@ -1,63 +1,63 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local delfed = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function delfed:init()
delfed.commands = mattata.commands(self.info.username):command('delfed').table
delfed.help = '/delfed <fed UUID> - Allows the Fed creator to delete a Fed, specified by its UUID.'
end
function delfed:on_new_message(message)
if message.chat.type == 'private' then
return false
end
local feds = redis:smembers('chat:' .. message.chat.id .. ':feds')
if #feds == 0 then
return false
end
for _, fed in pairs(feds) do
if not redis:hexists('fed:' .. fed, 'creator') then
redis:srem('chat:' .. message.chat.id .. ':feds', fed)
mattata.send_message(message.chat.id, 'The Fed this chat is part of has been deleted! To start a new one, use `/newfed <name>`.', true)
end
end
return
end
function delfed:on_message(message, configuration, language)
local input = mattata.input(message.text)
if message.chat.type ~= 'supergroup' and not mattata.is_group_admin(message.chat.id, message.from.id) then
return false
elseif not input then
return mattata.send_reply(message, 'You must specify the UUID of the Fed you\'d like to delete, in the format `/delfed <fed UUID>`!', true)
elseif not input:match('^%w+%-%w+%-%w+%-%w+%-%w+$') then
return mattata.send_reply(message, 'That\'s not a valid UUID!')
end
local creator = redis:hget('fed:' .. input, 'creator')
if not creator then
return mattata.send_reply(message, 'I couldn\'t find that Fed, perhaps it has already been deleted?')
elseif creator ~= message.from.id then
return mattata.send_reply(message, 'You must be the creator of the Fed in order to delete it!')
end
local title = redis:hget('fed:' .. input, 'title')
redis:del('fedadmins:' .. input)
redis:del('fedmembers:' .. input)
redis:del('fed:' .. input)
redis:srem('feds:' .. message.from.id, input)
if message.chat.type ~= 'private' then
local current = redis:sismember('chat:' .. message.chat.id .. ':feds', input)
if current then
redis:srem('chat:' .. message.chat.id .. ':feds', input)
end
end
local output = 'Successfully deleted the Fed "<b>%s</b>" <code>%s</code>!'
output = string.format(output, mattata.escape_html(title), input)
return mattata.send_reply(message, output)
end
return delfed
\ No newline at end of file
diff --git a/plugins/administration/demote.mattata b/plugins/administration/demote.mattata
index fdc503e..6101338 100644
--- a/plugins/administration/demote.mattata
+++ b/plugins/administration/demote.mattata
@@ -1,162 +1,162 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local demote = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function demote:init()
demote.commands = mattata.commands(self.info.username)
:command('demote')
:command('demod').table
demote.help = '/demote [user] - Demotes a user to a standard user of the current chat. This command can only be used by administrators of a supergroup. Alias: /demod.'
end
function demote:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id,
true
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = message.reply
and tostring(message.reply.from.id)
or mattata.input(message)
if not input
then
local success = mattata.send_force_reply(
message,
language['demote']['1']
)
if success
then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/demote'
)
end
return
elseif tonumber(input) == nil
and not input:match('^%@')
then
input = '@' .. input
end
local user = mattata.get_user(input)
or mattata.get_chat(input) -- Resolve the username/ID to a user object.
if not user
then
return mattata.send_reply(
message,
language['errors']['unknown']
)
elseif user.result.id == self.info.id
then
return
end
user = user.result
local status = mattata.get_chat_member(
message.chat.id,
user.id
)
if not status
then
return mattata.send_reply(
message,
language['errors']['generic']
)
elseif not mattata.is_group_admin(
message.chat.id,
user.id
)
then -- We won't try and demote users who aren't moderators/administrators.
return mattata.send_reply(
message,
language['demote']['2']
)
elseif status.result.status == 'left'
or status.result.status == 'kicked'
then -- Check if the user is in the group or not.
return mattata.send_reply(
message,
string.format(
status.result.status == 'left'
and language['demote']['3']
or language['demote']['4']
)
)
end
redis:srem(
'administration:' .. message.chat.id .. ':mods',
user.id
)
if redis:hget(
string.format(
'chat:%s:settings',
message.chat.id
),
'log administrative actions'
)
then
mattata.send_message(
mattata.get_log_chat(message.chat.id),
string.format(
'<pre>%s%s [%s] has demoted %s%s [%s] in %s%s [%s].</pre>',
message.from.username
and '@'
or '',
message.from.username
or mattata.escape_html(message.from.first_name),
message.from.id,
user.username
and '@'
or '',
user.username
or mattata.escape_html(user.first_name),
user.id,
message.chat.username
and '@'
or '',
message.chat.username
or mattata.escape_html(message.chat.title),
message.chat.id
),
'html'
)
end
return mattata.send_message(
message.chat.id,
string.format(
'<pre>%s%s has demoted %s%s.</pre>',
message.from.username
and '@'
or '',
message.from.username
or mattata.escape_html(message.from.first_name),
user.username
and '@'
or '',
user.username
or mattata.escape_html(user.first_name)
),
'html'
)
end
return demote
\ No newline at end of file
diff --git a/plugins/administration/fban.mattata b/plugins/administration/fban.mattata
index 025e8d1..f924b90 100644
--- a/plugins/administration/fban.mattata
+++ b/plugins/administration/fban.mattata
@@ -1,132 +1,132 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local fban = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function fban:init()
fban.commands = mattata.commands(self.info.username):command('fban'):command('fedban'):command('fb').table
fban.help = '/fban [user] - Bans a user from the current chat and the Fed the group is part of. This command can only be used by Fed admins. Aliases: /fedban, /fb.'
end
function fban.on_new_message(_, message)
if message.chat.type ~= 'supergroup' then
return false
elseif mattata.is_user_fedbanned(message.chat.id, message.from.id) and not mattata.is_user_fed_whitelisted(message.chat.id, message.from.id) then
mattata.send_message(message.chat.id, 'Banned ' .. message.from.first_name .. ', because they\'ve been banned in one of this group\'s Feds!')
return mattata.ban_chat_member(message.chat.id, message.from.id)
end
return false
end
function fban:on_message(message, _, language)
if message.chat.type ~= 'supergroup' then
local output = language['errors']['supergroup']
return mattata.send_reply(message, output)
end
local fed_ids = mattata.get_feds(message.chat.id)
if #fed_ids == 0 then
return mattata.send_reply(message, 'This group isn\'t part of a fed. Ask a group admin to join one!')
end
local is_admin_feds = {}
for _, fed in pairs(fed_ids) do
if mattata.is_fed_admin(fed, message.from.id) then
table.insert(is_admin_feds, fed)
end
end
if #is_admin_feds == 0 then
return mattata.send_reply(message, 'You need to be a Fed admin in at least one of this group\'s Feds in order to be able to use this command!')
end
local reason = false
local user = false
local input = mattata.input(message)
-- check the message object for any users this command
-- is intended to be executed on
if message.reply then
user = message.reply.from.id
if input then
reason = input
end
elseif input and input:match(' ') then
user, reason = input:match('^(.-) (.-)$')
elseif input then
user = input
end
if not user then
local output = 'You need to specify the user you\'d like to ban from the Fed, either by username/ID or in reply.'
local success = mattata.send_force_reply(message, output)
if success then
mattata.set_command_action(message.chat.id, success.result.message_id, '/fban')
end
return
end
if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
reason = reason:match('^[Ff][Oo][Rr] (.-)$')
end
if tonumber(user) == nil and not user:match('^%@') then
user = '@' .. user
end
local user_object = mattata.get_user(user) or mattata.get_chat(user) -- resolve the username/ID to a user object
if not user_object then
local output = language['errors']['unknown']
return mattata.send_reply(message, output)
elseif user_object.result.id == self.info.id then
return false -- don't let the bot Fed-ban itself
end
user_object = user_object.result
local status = mattata.get_chat_member(message.chat.id, user_object.id)
local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
if not status then
local output = language['errors']['generic']
return mattata.send_reply(message, output)
elseif is_admin then -- we won't try and Fed-ban moderators and administrators.
local output = 'I can\'t ban that user from the Fed because they\'re an admin in one of the groups!'
return mattata.send_reply(message, output)
end
local success = mattata.fed_ban_chat_member(message.chat.id, user_object.id, is_admin_feds) -- attempt to Fed-ban the user from the group
if not success then
mattata.send_reply(message, 'I couldn\'t ban that user in this group, because it appears I don\'t have permission to! I have still added them to the Fed-ban list(s) though!')
end
for _, fed in pairs(is_admin_feds) do
mattata.increase_administrative_action(message.chat.id, user_object.id, 'fbans')
redis:hset('fedban:' .. fed .. ':' .. user_object.id, 'banned_by', message.from.id)
redis:hset('fedban:' .. fed .. ':' .. user_object.id, 'time', os.time())
if reason then
redis:hset('fedban:' .. fed .. ':' .. user_object.id, 'reason', reason)
end
redis:sadd('fedbans:' .. fed, tonumber(user_object.id))
end
reason = reason and ', for ' .. reason or ''
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local banned_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local output = '%s <code>[%s]</code> has Fed-banned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s'
if #is_admin_feds > 1 then
output = '%s <code>[%s]</code> has Fed-banned %s <code>[%s]</code> from %s in the following Feds:<pre>%s</pre>\n%s %s'
output = string.format(output, admin_username, message.from.id, banned_username, user_object.id, mattata.escape_html(message.chat.title), table.concat(is_admin_feds, '\n'), '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
else
output = string.format(output, admin_username, message.from.id, banned_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
end
mattata.send_message(log_chat, output, 'html')
else
local output = '%s has Fed-banned %s%s.'
if #is_admin_feds > 1 then
output = '%s has Fed-banned %s%s; in the following Feds:<pre>%s</pre>'
output = string.format(output, admin_username, banned_username, reason, table.concat(is_admin_feds, '\n'))
else
output = string.format(output, admin_username, banned_username, reason)
end
mattata.send_message(message.chat.id, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
mattata.delete_message(message.chat.id, message.message_id)
end
return
end
return fban
\ No newline at end of file
diff --git a/plugins/administration/fdemote.mattata b/plugins/administration/fdemote.mattata
index eceefa8..e8313ed 100644
--- a/plugins/administration/fdemote.mattata
+++ b/plugins/administration/fdemote.mattata
@@ -1,52 +1,52 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local fdemote = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function fdemote:init()
fdemote.commands = mattata.commands(self.info.username):command('fdemote'):command('feddemote'):command('fd').table
fdemote.help = '/fdemote [user] - Allows the Fed creator to demote a user (by reply or mention), removing their access to Fed admin commands. If you have multiple feds, please specify the Fed as a second parameter, if not it will pick your first one. Aliases: /feddemote, /fd.'
end
function fdemote:on_message(message, configuration, language)
local fed, id = mattata.has_fed(message.from.id)
local input = mattata.input(message.text)
if message.reply and input then
input = message.reply.from.id .. ' ' .. input
end
local input, selected = (message.reply and not input) and tostring(message.reply.from.id) or input, nil
if input:match('^[@%w_]+ ([%w%-]+)$') then
input, selected = input:match('^([@%w_]+) ([%w%-]+)$')
end
fed, id = mattata.has_fed(message.from.id, selected)
if not fed then
local output = 'You need to have your own Fed in order to use this command!'
if selected then
output = 'That\'s not one of your Feds!'
end
return mattata.send_reply(message, output)
elseif not input then
return mattata.send_reply(message, fdemote.help)
end
local user = mattata.get_user(input)
if not user then
return mattata.send_reply(message, 'I couldn\'t find any information about that user! Try sending this in reply to one of their messages.')
elseif user.result.id == message.from.id then
return mattata.send_reply(message, 'You can\'t demote yourself you donut!')
elseif user.result.id == self.info.id then
return mattata.send_reply(message, 'Why do you need to demote me? I control all of the Feds!')
elseif not mattata.is_fed_admin(id, user.result.id) then
return mattata.send_reply(message, 'That user isn\'t an admin in your Fed anyway!')
end
local title = redis:hget('fed:' .. id, 'title')
redis:srem('fedadmins:' .. id, user.result.id)
local output = 'Successfully demoted <b>%s</b> from Fed admin in <b>%s</b> <code>[%s]</code>!'
output = string.format(output, mattata.escape_html(user.result.first_name), mattata.escape_html(title), id)
return mattata.send_reply(message, output, 'html')
end
return fdemote
\ No newline at end of file
diff --git a/plugins/administration/feds.mattata b/plugins/administration/feds.mattata
index a39e134..f0d0322 100644
--- a/plugins/administration/feds.mattata
+++ b/plugins/administration/feds.mattata
@@ -1,38 +1,38 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local feds = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function feds:init()
feds.commands = mattata.commands(self.info.username):command('feds').table
feds.help = '/feds - Allows group admins to view the group\'s current Feds.'
end
function feds:on_message(message, configuration, language)
if message.chat.type == 'private' then
return mattata.send_reply(message, language.errors.supergroup)
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
return mattata.send_reply(message, language.errors.admin)
end
local all = redis:smembers('chat:' .. message.chat.id .. ':feds')
if #all == 0 then
local output = '<b>%s</b> isn\'t part of any Feds! To join one, use <code>/joinfed &lt;fed UUID&gt;</code>!'
output = string.format(output, mattata.escape_html(message.chat.title))
return mattata.send_reply(message, output, 'html')
end
local output = { '<b>' .. mattata.escape_html(message.chat.title) .. '</b> is part of the following Feds:' }
for _, fed in pairs(all) do
local formatted = mattata.symbols.bullet .. ' <em>%s</em> <code>[%s]</code>'
local title = redis:hget('fed:' .. fed, 'title')
formatted = string.format(formatted, mattata.escape_html(title), fed)
table.insert(output, formatted)
end
output = table.concat(output, '\n')
return mattata.send_reply(message, output, 'html')
end
return feds
\ No newline at end of file
diff --git a/plugins/administration/filter.mattata b/plugins/administration/filter.mattata
index a119b96..168a730 100644
--- a/plugins/administration/filter.mattata
+++ b/plugins/administration/filter.mattata
@@ -1,87 +1,87 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local filter = {}
local mattata = require('mattata')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function filter:init()
filter.commands = mattata.commands(self.info.username):command('filter').table
filter.help = '/filter <words> - Add to the list of words that users will be kicked upon for saying. This feature requires the bot to have administrative permissions. The kick will only be a soft-ban (meaning the targeted user is able to return to the chat immediately), unless the "Ban Not Kick" setting is enabled in the /administration menu.'
end
function filter:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = mattata.input(message.text)
if not input
or not input:match('%w+')
then
return mattata.send_reply(
message,
filter.help
)
end
local new_total = 0
local words = {}
for word in input:gmatch('%w+')
do
table.insert(
words,
word
)
end
local total = redis:smembers('word_filter:' .. message.chat.id)
if #total + #words >= 200
then
local remaining = 200 - #total
return mattata.send_reply(
message,
'You may only have 200 words filtered at a time. There are currently ' .. tostring(#total) .. ' word(s) filtered in this chat, so you may only add up to ' .. tostring(remaining) .. ' more.'
)
end
local new = {}
for n, word in pairs(words)
do
if not redis:sismember(
'word_filter:' .. message.chat.id,
word
)
then
local success = redis:sadd(
'word_filter:' .. message.chat.id,
word
)
if success
then
table.insert(
new,
word
)
end
end
end
return mattata.send_message(
message.chat.id,
tostring(#new) .. ' word(s) have been added to this chat\'s word filter. Use /unfilter <words> to remove words from this filter.'
)
end
return filter
\ No newline at end of file
diff --git a/plugins/administration/fpromote.mattata b/plugins/administration/fpromote.mattata
index 3b318cf..fbf838b 100644
--- a/plugins/administration/fpromote.mattata
+++ b/plugins/administration/fpromote.mattata
@@ -1,58 +1,58 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local fpromote = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function fpromote:init()
fpromote.commands = mattata.commands(self.info.username):command('fpromote'):command('fedpromote'):command('fp').table
fpromote.help = '/fpromote [user] [fed UUID] - Allows the Fed creator to promote a user (by reply or mention), granting them access to Fed admin commands. If you have multiple feds, please specify the Fed as a second parameter. Aliases: /fedpromote, /fp.'
end
function fpromote:on_message(message)
local fed, id, multiple = mattata.has_fed(message.from.id)
local input = mattata.input(message.text)
local selected
if message.reply and input then
input = message.reply.from.id .. ' ' .. input
end
input, selected = (message.reply and not input) and tostring(message.reply.from.id) or input, nil
if input and input:match('^[@%w_]+ ([%w%-]+)$') then
input, selected = input:match('^([@%w_]+) ([%w%-]+)$')
elseif not input then
return mattata.send_reply(message, fpromote.help)
end
if not selected and multiple then
return mattata.send_reply(message, 'Since this group is part of multiple Feds, you need to specify the Fed UUID at the end of your message (i.e. /fpromote @wrxck your-uuid-here). To view Fed UUIDs, send /feds.')
end
fed, id = mattata.has_fed(message.from.id, selected)
if not fed then
local output = 'You need to have your own Fed in order to use this command!'
if selected then
output = 'That\'s not one of your Feds!'
end
return mattata.send_reply(message, output)
elseif not input then
return mattata.send_reply(message, fpromote.help)
end
local user = mattata.get_user(input)
if not user then
return mattata.send_reply(message, 'I couldn\'t find any information about that user! Try sending this in reply to one of their messages.')
elseif user.result.id == message.from.id then
return mattata.send_reply(message, 'You can\'t promote yourself you donut!')
elseif user.result.id == self.info.id then
return mattata.send_reply(message, 'Why do you need to promote me? I control all of the Feds!')
elseif mattata.is_fed_admin(id, user.result.id) then
return mattata.send_reply(message, 'That user is already an admin in your Fed!')
end
local title = redis:hget('fed:' .. id, 'title')
redis:sadd('fedadmins:' .. id, user.result.id)
local output = 'Successfully promoted <b>%s</b> to Fed admin in <b>%s</b> <code>[%s]</code>!'
output = string.format(output, mattata.escape_html(user.result.first_name), mattata.escape_html(title), id)
return mattata.send_reply(message, output, 'html')
end
return fpromote
\ No newline at end of file
diff --git a/plugins/administration/fwhitelist.mattata b/plugins/administration/fwhitelist.mattata
index 2d9d004..24db63c 100644
--- a/plugins/administration/fwhitelist.mattata
+++ b/plugins/administration/fwhitelist.mattata
@@ -1,82 +1,82 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local fwhitelist = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function fwhitelist:init()
fwhitelist.commands = mattata.commands(self.info.username):command('fwhitelist'):command('fedban'):command('fb').table
fwhitelist.help = '/fwhitelist [user] - Whitelists a user from the current chat\'s Feds. Only works per chat, not per fed. This command can only be used by Fed admins. Alias: /fw.'
end
function fwhitelist:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup' then
local output = language['errors']['supergroup']
return mattata.send_reply(message, output)
end
local fed_ids = mattata.get_feds(message.chat.id)
if #fed_ids == 0 then
return mattata.send_reply(message, 'This group isn\'t part of a fed. Ask a group admin to join one!')
end
local user = message.reply and message.reply.from.id or mattata.input(message.text)
if not user then
local output = 'You need to specify the user you\'d like to whitelist from the Fed, either by username/ID or in reply.'
local success = mattata.send_force_reply(message, output)
if success then
mattata.set_command_action(message.chat.id, success.result.message_id, '/fwhitelist')
end
return
end
if tonumber(user) == nil and not user:match('^%@') then
user = '@' .. user
end
local user_object = mattata.get_user(user) -- resolve the username/ID to a user object
if not user_object then
local output = language['errors']['unknown']
return mattata.send_reply(message, output)
elseif user_object.result.id == self.info.id then
return false -- don't let the bot Fed-whitelist itself
end
user_object = user_object.result
local status = mattata.get_chat_member(message.chat.id, user_object.id)
local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
if not status then
local output = language['errors']['generic']
return mattata.send_reply(message, output)
elseif is_admin or status.result.status == ('creator' or 'administrator') then -- we won't try and Fed-whitelist moderators and administrators.
local output = 'I can\'t whitelist that user from the Fed because they\'re an admin in one of the groups!'
return mattata.send_reply(message, output)
end
mattata.fed_whitelist(message.chat.id, user_object.id)
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local whitelisted_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
local output = '%s <code>[%s]</code> has Fed-whitelisted %s <code>[%s]</code> from %s <code>[%s]</code>.'
if #fed_ids > 1 then
output = '%s <code>[%s]</code> has Fed-whitelisted %s <code>[%s]</code> from %s in the following Feds:<pre>%s</pre>'
output = string.format(output, admin_username, message.from.id, whitelisted_username, user_object.id, mattata.escape_html(message.chat.title), table.concat(fed_ids, '\n'))
else
output = string.format(output, admin_username, message.from.id, whitelisted_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id)
end
mattata.send_message(message.chat.id, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
end
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local whitelisted_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
local output = '%s has Fed-whitelisted %s.'
if #fed_ids > 1 then
output = '%s has Fed-whitelisted %s; in the following Feds:<pre>%s</pre>'
output = string.format(output, admin_username, whitelisted_username, table.concat(fed_ids, '\n'))
else
output = string.format(output, admin_username, whitelisted_username)
end
return mattata.send_message(message.chat.id, output, 'html')
end
return fwhitelist
\ No newline at end of file
diff --git a/plugins/administration/groups.mattata b/plugins/administration/groups.mattata
index f97c868..7d4c7d7 100644
--- a/plugins/administration/groups.mattata
+++ b/plugins/administration/groups.mattata
@@ -1,58 +1,58 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local groups = {}
local mattata = require('mattata')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function groups:init()
groups.commands = mattata.commands(self.info.username):command('groups').table
groups.help = '/groups [query] - View a list of mattata\'s groups (that is, all of the ones added by the bot owner), or search for groups by passing a Lua pattern as a command argument.'
end
function groups:on_message(message, configuration, language)
local input = mattata.input(message.text)
local output = {}
for k, v in pairs(configuration.groups) do
if k and v then
local title = k
local link = v
if input then
local validate = pcall(
function()
return title:match(input)
end
)
if not validate then
local output = 'Your search query contains a malformed Lua pattern! If you\'re not sure what this means, try searching without any symbols.'
return mattata.send_reply(message, output)
end
end
if (input and title:match(input)) or not input then
local result = string.format('• <a href="%s">%s</a>', mattata.escape_html(link), mattata.escape_html(title))
table.insert(output, result)
end
end
end
if not next(output) then
local output = 'No groups were found. If you\'d like your group to appear here, contact @wrxck0.'
if input then
output = string.format('No groups were found matching "%s"! Use /groups to view a complete list of available groups.', input)
end
return mattata.send_reply(message, output)
end
if configuration.sort_groups then
table.sort(output)
end
output = table.concat(output, '\n')
if input then
local heading = string.format('Groups found matching "%s":\n', mattata.escape_html(input))
output = heading .. output
end
return mattata.send_message(message.chat.id, output, 'html')
end
return groups
\ No newline at end of file
diff --git a/plugins/administration/import.mattata b/plugins/administration/import.mattata
index a23e1b0..5039317 100644
--- a/plugins/administration/import.mattata
+++ b/plugins/administration/import.mattata
@@ -1,53 +1,53 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local import = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function import:init()
import.commands = mattata.commands(self.info.username):command('import').table
import.help = '/import - Import administrative settings & toggled plugins from another mattata-administrated group.'
end
function import.on_message(_, message, _, language)
if message.chat.type ~= 'supergroup' then
return mattata.send_reply(message, language.errors.supergroup)
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
return mattata.send_reply(message, language.errors.admin)
end
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, import.help)
end
input = mattata.get_chat(input)
if not input then
return mattata.send_reply(message, language['import']['1'])
elseif input.result.type ~= 'supergroup' then
return mattata.send_reply(message, language['import']['2'])
end
local current = redis:hgetall('chat:' .. message.chat.id .. ':settings')
local settings = redis:hgetall('chat:' .. input.result.id .. ':settings')
for k, _ in pairs(current) do
if k ~= 'use administration' then
redis:hdel('chat:' .. message.chat.id .. ':settings', k)
end
end
for k, v in pairs(settings) do
redis:hset('chat:' .. message.chat.id .. ':settings', k, v)
end
current = redis:smembers('disabled_plugins:' .. message.chat.id)
local plugins = redis:smembers('disabled_plugins:' .. input.result.id)
for _, v in pairs(current) do
redis:srem('disabled_plugins:' .. message.chat.id, v)
end
for _, v in pairs(plugins) do
redis:sadd('disabled_plugins:' .. message.chat.id, v)
end
local output = string.format(language['import']['3'], input.result.title, message.chat.title)
return mattata.send_message(message.chat.id, output)
end
return import
\ No newline at end of file
diff --git a/plugins/administration/join_captcha.mattata b/plugins/administration/join_captcha.mattata
index 4935403..0b939ad 100644
--- a/plugins/administration/join_captcha.mattata
+++ b/plugins/administration/join_captcha.mattata
@@ -1,137 +1,137 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local join_captcha = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
local captcha_lib = require('captcha')
function join_captcha.cron()
local keys = redis:keys('chat:*:captcha:*')
for _, key in pairs(keys) do
local captcha_time = redis:hget(key, 'time') or 0
local chat_id, user_id = key:match('^chat:(%-?%d+):captcha:(%d+)$')
local original_message = redis:hget(key, 'original message')
local photo_id = redis:hget(key, 'id')
if tonumber(captcha_time) <= (os.time() - 300) then
mattata.delete_message(chat_id, tonumber(original_message))
mattata.delete_message(chat_id, tonumber(photo_id))
local user = mattata.get_user(user_id, nil, nil, true)
local kicked_user = mattata.get_formatted_user(user_id, user.result.first_name, 'html')
local action = mattata.get_setting(chat_id, 'ban not kick') and mattata.ban_chat_member or mattata.kick_chat_member
local action_str = mattata.get_setting(chat_id, 'ban not kick') and 'Banned' or 'Kicked'
local output = action_str .. ' ' .. kicked_user .. ' <code>[' .. user_id .. ']</code> %sbecause they didn\'t complete the CAPTCHA within 5 minutes!'
if mattata.get_setting(chat_id, 'log administrative actions') then
local chat = mattata.get_chat(chat_id)
local log_output = output
if chat then
local title = mattata.escape_html(chat.result.title)
title = 'from ' .. title .. ' <code>[' .. chat.result.id .. ']</code> '
log_output = string.format(log_output, title)
log_output = log_output .. '\n#chat' .. tostring(chat.result.id):gsub('^%-100', '') .. ' #user' .. user_id
else
log_output = string.format(log_output, '')
end
mattata.send_message(mattata.get_log_chat(chat_id), log_output, 'html')
else
output = string.format(output, '')
mattata.send_message(chat_id, output, 'html')
end
mattata.wipe_redis_captcha(chat_id, user_id)
action(chat_id, user_id)
end
end
end
function join_captcha.on_callback_query(_, callback_query, message)
if not callback_query.data:match('^.-:.-:.-$') then
return false
end
local chat_id, user_id, guess = callback_query.data:match('^(.-):(.-):(.-)$')
if callback_query.from.id ~= tonumber(user_id) then
return mattata.answer_callback_query(callback_query.id, 'This isn\'t your CAPTCHA!')
end
local correct = mattata.get_captcha_text(chat_id, callback_query.from.id)
local id = mattata.get_captcha_original_message(chat_id, callback_query.from.id)
local photo_id = mattata.get_captcha_id(chat_id, callback_query.from.id)
mattata.wipe_redis_captcha(chat_id, callback_query.from.id, true) -- we're done with this now
if guess:lower() == correct:lower() then
local default_permissions = mattata.get_chat(message.chat.id)
local success
if not default_permissions then
success = mattata.restrict_chat_member(chat_id, callback_query.from.id, 'forever', true, true, true, true, true, false, false, false)
else
success = mattata.restrict_chat_member(chat_id, callback_query.from.id, 'forever', default_permissions.result.permissions)
end
if not success then
mattata.delete_message(chat_id, tonumber(photo_id))
return mattata.edit_message_text(message.chat.id, tonumber(id), 'I could not give that user their permissions. You may have to do this manually!')
end
mattata.delete_message(chat_id, tonumber(photo_id))
mattata.delete_message(chat_id, tonumber(id))
redis:hdel('chat:' .. chat_id .. ':captcha:' .. callback_query.from.id, 'text')
return mattata.answer_callback_query(callback_query.id, 'Success! You may now speak!')
else
mattata.delete_message(chat_id, tonumber(photo_id))
mattata.delete_message(chat_id, tonumber(id))
redis:hdel('chat:' .. chat_id .. ':captcha:' .. callback_query.from.id, 'text')
return mattata.answer_callback_query(callback_query.id, 'You got it wrong! Consult an admin if you wish to be unmuted!')
end
end
function join_captcha.on_member_join(_, message, configuration)
if mattata.get_setting(message.chat.id, 'require captcha') and not message.new_chat_participant.is_bot and not mattata.get_captcha_id(message.chat.id, message.new_chat_participant.id) then
local chat_member = mattata.get_chat_member(message.chat.id, message.new_chat_participant.id)
if not chat_member then -- we can't even get info about the user? abort! abort!
return false
elseif chat_member.result.can_send_messages == false then -- if it's false it means he's already muted!
return false
end
local download_location = configuration.download_location
if download_location:match('/$') then
download_location = download_location:match('^(.-)/$')
end
local new_captcha = captcha_lib.new()
new_captcha:setlength(6)
new_captcha:setfontsize(40)
new_captcha:setpath(download_location)
new_captcha:setformat('jpg')
new_captcha:setfontsfolder(configuration.fonts_directory)
local generated_captcha = new_captcha:generate()
local username = message.new_chat_participant.username and '@' .. message.new_chat_participant.username or false
local msg = string.format('Hey, [%s](tg://user?id=%s)! Please enter the CAPTCHA below before you can speak! You will be removed in 5 minutes if you don\'t do this.', username or mattata.escape_markdown(message.new_chat_participant.first_name), message.new_chat_participant.id)
local correct = generated_captcha:match('^' .. download_location .. '/(.-)%.jpg$')
local captchas = mattata.random_string(6, 5)
table.insert(captchas, correct)
table.sort(captchas)
local callback_data = string.format('join_captcha:%s:%s', message.chat.id, message.new_chat_participant.id)
local keyboard = mattata.inline_keyboard():row(
mattata.row()
:callback_data_button(captchas[1], callback_data .. ':' .. captchas[1])
:callback_data_button(captchas[2], callback_data .. ':' .. captchas[2])
:callback_data_button(captchas[3], callback_data .. ':' .. captchas[3])
):row(
mattata.row()
:callback_data_button(captchas[4], callback_data .. ':' .. captchas[4])
:callback_data_button(captchas[5], callback_data .. ':' .. captchas[5])
:callback_data_button(captchas[6], callback_data .. ':' .. captchas[6])
)
local photo_success = mattata.send_photo(message.chat.id, generated_captcha)
local success = mattata.send_message(message.chat.id, msg, 'markdown', true, false, nil, keyboard)
if not photo_success or not success then
return false
end
os.execute('rm ' .. generated_captcha)
local mute = mattata.restrict_chat_member(message.chat.id, message.new_chat_participant.id, 'forever', false, false, false, false, false, false, false, false)
if not mute then
return false
end
mattata.set_captcha(message.chat.id, message.new_chat_participant.id, photo_success.result.message_id, correct, success.result.message_id, true)
return mattata.delete_message(message.chat.id, message.message_id)
end
end
return join_captcha
\ No newline at end of file
diff --git a/plugins/administration/joinfed.mattata b/plugins/administration/joinfed.mattata
index 82737a8..e17696e 100644
--- a/plugins/administration/joinfed.mattata
+++ b/plugins/administration/joinfed.mattata
@@ -1,53 +1,53 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local joinfed = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function joinfed:init(configuration)
joinfed.commands = mattata.commands(self.info.username):command('joinfed').table
joinfed.help = '/joinfed <fed UUID> - Allows a group admin to join the current group to the specified Fed.'
joinfed.limit = configuration.administration.feds.group_limit
joinfed.groups = configuration.administration.feds.shortened_feds
end
function joinfed:on_message(message, configuration, language)
if message.chat.type == 'private' then
return mattata.send_reply(message, 'Please use this command in the group you would like to join to the Fed!')
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
return mattata.send_reply(message, language.errors.admin)
end
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, 'Please specify the fed\'s UUID!')
end
for name, fed in pairs(joinfed.groups) do
if input:lower() == name then
input = fed
end
end
if not input:match('^%w+%-%w+%-%w+%-%w+%-%w+$') then
return mattata.send_reply(message, 'That\'s an invalid UUID format')
end
local feds = redis:smembers('chat:' .. message.chat.id .. ':feds')
if redis:sismember('chat:' .. message.chat.id .. ':feds', input) then
return mattata.send_reply(message, 'This group is already part of that Fed!')
elseif #feds >= joinfed.limit then
return mattata.send_reply(message, 'You can only join a maximum of ' .. joinfed.limit .. ' Feds per group!')
end
local fed_title = redis:hget('fed:' .. input, 'title')
if not fed_title then
return mattata.send_reply(message, 'The Fed you specified doesn\'t exist!')
end
local output = 'Joined the Fed <b>%s</b> in this group <code>[%s]</code>!'
redis:sadd('chat:' .. message.chat.id .. ':feds', input)
redis:sadd('fedmembers:' .. input, message.chat.id)
fed_title = mattata.escape_html(fed_title)
output = string.format(output, fed_title, message.chat.id)
return mattata.send_reply(message, output, 'html')
end
return joinfed
\ No newline at end of file
diff --git a/plugins/administration/jsondump.mattata b/plugins/administration/jsondump.mattata
index 9fb7e75..5567ffb 100644
--- a/plugins/administration/jsondump.mattata
+++ b/plugins/administration/jsondump.mattata
@@ -1,41 +1,41 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local jsondump = {}
local mattata = require('mattata')
local json = require('serpent')
function jsondump:init()
jsondump.commands = mattata.commands(self.info.username)
:command('jsondump')
:command('json').table
jsondump.help = '/jsondump - Returns the raw JSON of your message. Alias: /json.'
json = require('dkjson')
jsondump.serialise = function(input)
return json.encode(
input,
{
indent = true
}
)
end
end
function jsondump:on_message(message)
local output = jsondump.serialise(message)
if output:len() > 4096
then
return
end
return mattata.send_message(
message.chat.id,
'<pre>' .. mattata.escape_html(
tostring(output)
) .. '</pre>',
'html'
)
end
return jsondump
\ No newline at end of file
diff --git a/plugins/administration/kick.mattata b/plugins/administration/kick.mattata
index 95c3db3..3a3e934 100644
--- a/plugins/administration/kick.mattata
+++ b/plugins/administration/kick.mattata
@@ -1,96 +1,96 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local kick = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function kick:init()
kick.commands = mattata.commands(self.info.username):command('kick').table
kick.help = '/kick [user] - Kicks a user from the current chat. This command can only be used by moderators and administrators of a supergroup.'
end
function kick:on_message(message, _, language)
if message.chat.type ~= 'supergroup' then
mattata.send_reply(message, language['errors']['supergroup'])
return false, 'The chat is not a supergroup!'
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
mattata.send_reply(message, language['errors']['admin'])
return false, 'That user is not an admin/mod in this chat!'
end
local reason = false
local user = false
local input = mattata.input(message)
-- Check the message object for any users this command
-- is intended to be executed on.
if message.reply then
user = message.reply.from.id
reason = input
elseif input and input:match(' ') then
user, reason = input:match('^(.-) (.-)$')
elseif input then
user = input
end
if not user then
local success = mattata.send_force_reply(message, language['kick']['1'])
if success then
redis:set('action:' .. message.chat.id .. ':' .. success.result.message_id, '/kick')
end
return
end
if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
reason = reason:match('^[Ff][Oo][Rr] (.-)$')
end
if tonumber(user) == nil and not user:match('^%@') then
user = '@' .. user
end
local user_object = mattata.get_user(user) -- Resolve the username/ID to a user object.
if not user_object then
mattata.send_reply(message, language['errors']['unknown'])
return false, 'No user object was found!'
elseif user_object.result.id == self.info.id then
return false, 'The user given was the bot!'
end
user_object = user_object.result
local status, error_message = mattata.get_chat_member(message.chat.id, user_object.id)
if not status then
mattata.send_reply(message, language['errors']['generic'])
return false, error_message
elseif mattata.is_group_admin(message.chat.id, user_object.id) then
-- We won't try and kick moderators and administrators.
mattata.send_reply(message, language['kick']['2'])
return false, 'That user is an admin/mod in this chat!'
elseif status.result.status == 'left' or status.result.status == 'kicked' then -- Check if the user is in the group or not.
local output = status.result.status == 'left' and language['kick']['3'] or language['kick']['4']
mattata.send_reply(message, output)
return false, output
end
local success = mattata.kick_chat_member(message.chat.id, user_object.id) -- Attempt to kick the user from the group.
if not success then -- Since we've ruled everything else out, it's safe to say if it wasn't a success
-- then the bot isn't an administrator in the group.
return mattata.send_reply(message, language['kick']['5'])
end
mattata.increase_administrative_action(message.chat.id, user_object.id, 'kicks')
reason = reason and ', for ' .. reason or ''
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local kicked_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local output = '%s <code>[%s]</code> has kicked %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s'
output = string.format(output, admin_username, message.from.id, kicked_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
mattata.send_message(log_chat, output, 'html')
else
local output = '%s has kicked %s%s.'
output = string.format(output, admin_username, kicked_username, reason)
mattata.send_message(message.chat.id, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
mattata.delete_message(message.chat.id, message.message_id)
end
return
end
return kick
\ No newline at end of file
diff --git a/plugins/administration/leavefed.mattata b/plugins/administration/leavefed.mattata
index 409befa..ec65a03 100644
--- a/plugins/administration/leavefed.mattata
+++ b/plugins/administration/leavefed.mattata
@@ -1,45 +1,45 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local leavefed = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function leavefed:init()
leavefed.commands = mattata.commands(self.info.username):command('leavefed').table
leavefed.help = '/leavefed <fed UUID> - Allows the group creator to leave one of the group\'s current Feds.'
end
function leavefed:on_message(message, configuration, language)
local input = mattata.input(message.text)
if message.chat.type ~= 'supergroup' then
return mattata.send_reply(message, language.errors.supergroup)
elseif not mattata.is_user_group_creator(message.chat.id, message.from.id) then
return mattata.send_reply(message, 'Only the group creator can use this command!')
end
local feds = redis:smembers('chat:' .. message.chat.id .. ':feds')
if #feds > 1 and not input then
return mattata.send_reply(message, 'You must specify the Fed you\'d like to leave, by it\'s UUID!')
elseif #feds == 0 then
return mattata.send_reply(message, 'This group isn\'t part of any Feds!')
end
local is_member = false
for _, fed in pairs(feds) do
if fed == input then
is_member = true
end
end
if not is_member then
return mattata.send_reply(message, 'This group isn\'t part of that Fed!')
end
redis:srem('chat:' .. message.chat.id .. ':feds', input)
redis:srem('fedmembers:' .. input, message.chat.id)
local title = redis:hget('fed:' .. input, 'title')
local output = 'Successfully left the Fed "<b>%s</b>" <code>[%s]</code>! To join a new Fed, use <code>/joinfed &lt;fed UUID&gt;</code>, or to create a new Fed, use <code>/newfed &lt;fed name&gt;</code>!'
output = string.format(output, mattata.escape_html(title), input)
return mattata.send_reply(message, output, 'html')
end
return leavefed
\ No newline at end of file
diff --git a/plugins/administration/link.mattata b/plugins/administration/link.mattata
index b31b284..47ee5b4 100644
--- a/plugins/administration/link.mattata
+++ b/plugins/administration/link.mattata
@@ -1,38 +1,38 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local link = {}
local mattata = require('mattata')
function link:init()
link.commands = mattata.commands(self.info.username):command('link').table
link.help = '/link - Returns the chat\'s invite link.'
end
function link:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
and message.chat.type ~= 'channel'
then
return mattata.send_reply(
message,
'This command can only be used in supergroups and channels!'
)
end
local success = mattata.export_chat_invite_link(message.chat.id)
if not success
then
return mattata.send_reply(
message,
'I need to be an administrator of this chat in order to retrieve the invite link.'
)
end
return mattata.send_message(
message.chat.id,
'<a href="' .. success.result .. '">' .. mattata.escape_html(message.chat.title) .. '</a>',
'html'
)
end
return link
\ No newline at end of file
diff --git a/plugins/administration/logchat.mattata b/plugins/administration/logchat.mattata
index dbed24c..1121075 100644
--- a/plugins/administration/logchat.mattata
+++ b/plugins/administration/logchat.mattata
@@ -1,135 +1,135 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local logchat = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function logchat:init()
logchat.commands = mattata.commands(self.info.username):command('logchat').table
logchat.help = '/logchat [chat] - Specify the chat that you wish to log all of this chat\'s administrative actions into.'
end
function logchat:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = mattata.input(message.text)
if not input
then
local success = mattata.send_force_reply(
message,
language['logchat']['1']
)
if success
then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/logchat'
)
end
return
end
local res = mattata.send_message(
message.chat.id,
language['logchat']['2']
)
if not res
then
return
elseif tonumber(input) == nil
and not input:match('^@')
then
input = '@' .. input
end
local valid = mattata.get_chat(input)
or mattata.get_user(input)
if not valid
or not valid.result
then
return mattata.edit_message_text(
message.chat.id,
res.result.message_id,
language['logchat']['3']
)
elseif valid.result.type == 'private'
then
return mattata.edit_message_text(
message.chat.id,
res.result.message_id,
language['logchat']['4']
)
elseif not mattata.is_group_admin(
valid.result.id,
message.from.id
)
then
return mattata.edit_message_text(
message.chat.id,
res.result.message_id,
language['logchat']['5']
)
elseif redis:hget(
'chat:' .. message.chat.id .. ':settings',
'log chat'
)
and redis:hget(
'chat:' .. message.chat.id .. ':settings',
'log chat'
) == valid.result.id
then
return mattata.edit_message_text(
message.chat.id,
res.result.message_id,
language['logchat']['6']
)
end
mattata.edit_message_text(
message.chat.id,
res.result.message_id,
language['logchat']['7']
)
local permission = mattata.send_message(valid.result.id, language['logchat']['8'])
if not permission then
return mattata.edit_message_text(
message.chat.id,
res.result.message_id,
'It appears I don\'t have permission to post to that chat. Please ensure it\'s still a valid chat and that I have administrative rights!'
)
end
mattata.delete_message(valid.result.id, permission.result.message_id)
redis:hset(
'chat:' .. message.chat.id .. ':settings',
'log chat',
valid.result.id
)
return mattata.edit_message_text(
message.chat.id,
res.result.message_id,
string.format(
language['logchat']['9'],
input
)
)
end
return logchat
\ No newline at end of file
diff --git a/plugins/administration/mute.mattata b/plugins/administration/mute.mattata
index f5c2a86..a77fc68 100644
--- a/plugins/administration/mute.mattata
+++ b/plugins/administration/mute.mattata
@@ -1,92 +1,92 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local mute = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function mute:init()
mute.commands = mattata.commands(self.info.username):command('mute').table
mute.help = '/mute [user] - Mutes a user in the current chat. This command can only be used by group admins.'
end
function mute:on_message(message, _, language)
if message.chat.type ~= 'supergroup' then
local output = language['errors']['supergroup']
return mattata.send_reply(message, output)
end
local reason = false
local user = false
local input = mattata.input(message)
-- check the message object for any users this command
-- is intended to be executed on
if message.reply then
user = message.reply.from.id
if input then
reason = input
end
elseif input and input:match(' ') then
user, reason = input:match('^(.-) (.-)$')
elseif input then
user = input
end
if not user then
local output = 'You need to specify the user you\'d like to mute, either by username/ID or in reply.'
local success = mattata.send_force_reply(message, output)
if success then
mattata.set_command_action(message.chat.id, success.result.message_id, '/mute')
end
return
end
if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
reason = reason:match('^[Ff][Oo][Rr] (.-)$')
end
if tonumber(user) == nil and not user:match('^%@') then
user = '@' .. user
end
local user_object = mattata.get_user(user) or mattata.get_chat(user) -- resolve the username/ID to a user object
if not user_object then
local output = language['errors']['unknown']
return mattata.send_reply(message, output)
elseif user_object.result.id == self.info.id then
return false -- don't let the bot mute itself
end
local bot_status = mattata.get_chat_member(message.chat.id, self.info.id)
if not bot_status then
return false
elseif not bot_status.result.can_restrict_members then
return mattata.send_reply(message, 'It appears I don\'t have the required permissions required in order to mute that user. Please amend this and try again!')
end
user_object = user_object.result
local status = mattata.get_chat_member(message.chat.id, user_object.id)
local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
if not status then
return mattata.send_reply(message, 'I couldn\'t retrieve any information about that user!')
elseif is_admin then -- we won't try and mute moderators and administrators.
return mattata.send_reply(message, 'I can\'t mute that user because they\'re an admin in this chat!')
end
local success = mattata.restrict_chat_member(message.chat.id, user_object.id, os.time(), false, false, false, false, false, false, false, false) -- attempt to mute the user in the group
if not success then
return mattata.send_reply(message, 'I couldn\'t mute that user in this group, because it appears I don\'t have permission to!')
end
reason = reason and ', for ' .. reason or ''
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local muted_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
redis:hincrby('chat:' .. message.chat.id .. ':' .. user_object.id, 'mutes', 1)
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local output = '%s <code>[%s]</code> has muted %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s'
output = string.format(output, admin_username, message.from.id, muted_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
mattata.send_message(log_chat, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
end
local output = '%s has muted %s%s.'
output = string.format(output, admin_username, muted_username, reason)
return mattata.send_message(message.chat.id, output, 'html')
end
return mute
\ No newline at end of file
diff --git a/plugins/administration/newfed.mattata b/plugins/administration/newfed.mattata
index 80e4437..d8f32f8 100644
--- a/plugins/administration/newfed.mattata
+++ b/plugins/administration/newfed.mattata
@@ -1,55 +1,55 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local newfed = {}
local mattata = require('mattata')
local uuid = require('uuid')
local redis = dofile('libs/redis.lua')
function newfed:init(configuration)
newfed.commands = mattata.commands(self.info.username):command('newfed').table
newfed.help = '/newfed <fed name> - Allows a group admin to create a new Fed, and return its UUID.'
newfed.limit = configuration.administration.feds.group_limit
end
function newfed.on_message(_, message, _, language)
if message.chat.type ~= 'private' and not mattata.is_group_admin(message.chat.id, message.from.id) then
return mattata.send_reply(message, language.errors.admin)
end
local input = mattata.input(message.text)
if not input then
local success = mattata.send_force_reply(message, 'Please specify a name for the Fed!')
if success then
mattata.set_command_action(message.chat.id, success.result.message_id, '/newfed')
end
return success
elseif input:len() > 128 then
return mattata.send_reply(message, 'Fed names cannot be longer than 128 characters in length!')
end
uuid.seed()
local fed_uuid = uuid.new()
local feds = redis:smembers('chat:' .. message.chat.id .. ':feds')
if message.chat.type ~= 'private' and #feds >= newfed.limit then
return mattata.send_reply(message, 'This group is already part of ' .. newfed.limit .. ' or more Feds. To leave one of these Feds and create a new one (starting with this chat in it), please send /leavefed <fed UUID> and then try this command again! Alternatively, to create a Fed but not have this group join it, use this command in private message!')
elseif redis:exists('fedmembers:' .. fed_uuid) then -- EXTREMELY unlikely it would generate the same UUID but I know my luck
fed_uuid = uuid.new()
end
redis:hset('fed:' .. fed_uuid, 'creator', message.from.id)
redis:hset('fed:' .. fed_uuid, 'date_created', os.time())
redis:hset('fed:' .. fed_uuid, 'title', input)
redis:sadd('fedadmins:' .. fed_uuid, message.from.id)
redis:sadd('feds:' .. message.from.id, fed_uuid)
local output = 'Created the Fed <b>%s</b>\nTo join this Fed in a group, send <code>/joinfed %s</code> in the group.'
if message.chat.type ~= 'private' then
redis:sadd('chat:' .. message.chat.id .. ':feds', fed_uuid)
redis:sadd('fedmembers:' .. fed_uuid, message.chat.id)
output = 'Created the Fed <b>%s</b>, and added this group <code>[%s]</code> to it!\nTo join this Fed in another group, send <code>/joinfed %s</code>'
end
input = mattata.escape_html(input)
output = message.chat.type == 'private' and string.format(output, input, fed_uuid) or string.format(output, input, message.chat.id, fed_uuid)
return mattata.send_reply(message, output, 'html')
end
return newfed
\ No newline at end of file
diff --git a/plugins/administration/nodelete.mattata b/plugins/administration/nodelete.mattata
index b4a622a..2ac3013 100644
--- a/plugins/administration/nodelete.mattata
+++ b/plugins/administration/nodelete.mattata
@@ -1,59 +1,59 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local nodelete = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function nodelete:init()
nodelete.commands = mattata.commands(self.info.username):command('nodelete').table
nodelete.help = '/nodelete [add | del] <plugins> - Allows the given plugins to retain the commands they were executed with by whitelisting them from the "delete commands" administrative setting. Multiple plugins can be specified.'
end
function nodelete:on_message(message, configuration, language)
local input = mattata.input(message.text)
if message.chat.type ~= 'supergroup' then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
return mattata.send_reply(
message,
language['errors']['admin']
)
elseif not input or not input:match('^add .-$') and not input:match('^del .-$') then
return mattata.send_reply(message, nodelete.help)
end
local plugins = {}
local process_type, input = input:match('([ad][de][dl]) (.-)$')
for plugin in input:gmatch('[%w_]+') do
for k, v in pairs(configuration.plugins) do
if v:lower() == plugin:lower()then
table.insert(plugins, plugin)
end
end
end
if #plugins < 1 then
return mattata.send_reply(message, 'No matching plugins were found!')
end
local total = #plugins
local success = {}
for k, v in pairs(plugins) do
if process_type == 'add' and not redis:sismember('chat:' .. message.chat.id .. ':no_delete', v) then -- Check to make sure the plugin isn't already whitelisted from having
-- its commands deleted.
redis:sadd('chat:' .. message.chat.id .. ':no_delete', v)
table.insert(success, v)
elseif process_type == 'del' and redis:sismember('chat:' .. message.chat.id .. ':no_delete', v) then -- Check to make sure the plugin has already been whitelisted from having
-- its commands deleted.
redis:srem('chat:' .. message.chat.id .. ':no_delete', v)
table.insert(success, v)
end
end
local output = process_type == 'del' and 'Commands will now be deleted for ' .. total .. ' plugins!' or 'Commands will no longer be deleted for ' .. total .. ' plugins!'
return mattata.send_reply(message, output)
end
return nodelete
\ No newline at end of file
diff --git a/plugins/administration/pictrigger.mattata b/plugins/administration/pictrigger.mattata
index 0291967..2c17a23 100644
--- a/plugins/administration/pictrigger.mattata
+++ b/plugins/administration/pictrigger.mattata
@@ -1,88 +1,88 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local pictriggers = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function pictriggers:init()
pictriggers.commands = mattata.commands(self.info.username):command('pictriggers'):command('addpictrigger'):command('delpictrigger').table
pictriggers.help = '/pictriggers - Allows admins to view existing picture triggers. Use /addpictrigger <trigger> <URL> to add one, and /delpictrigger <trigger> to delete one. Each chat is allowed 8 picture triggers, with a maximum of 16 characters per word trigger. Trigger words can be alpha-numerical.'
end
function pictriggers:on_new_message(message)
if message.command or message.is_media then
return false
end
local matches = redis:hgetall('pictriggers:' .. message.chat.id)
if not next(matches) == 0 then
return false
end
for trigger, value in pairs(matches) do
if message.text:match(trigger) then
return mattata.send_photo(message.chat.id, value)
end
end
return
end
function pictriggers:on_message(message, configuration)
self.is_done = true
if message.chat.type == 'private' or not mattata.is_group_admin(message.chat.id, message.from.id) then
return false
elseif message.command == 'pictriggers' then
local matches = redis:hgetall('pictriggers:' .. message.chat.id)
if not next(matches) then
return mattata.send_reply(message, 'This chat doesn\'t have any picture triggers set up. To add one, use /addpictrigger <trigger> <URL>.')
end
local output = 'Picture triggers for <b>%s</b>\n\n%s'
local all = {}
for trigger, value in pairs(matches) do
local line = '<code>%s</code>: %s'
line = string.format(line, mattata.escape_html(trigger), mattata.escape_html(value))
table.insert(all, line)
end
all = table.concat(all, '\n')
output = string.format(output, mattata.escape_html(message.chat.title), all)
return mattata.send_reply(message, output, 'html')
elseif message.command == 'addpictrigger' then
local input = mattata.input(message.text)
if not input or not input:match('^%w+ .-$') then
return mattata.send_reply(message, pictriggers.help)
end
local count = 0
local all = redis:hgetall('pictriggers:' .. message.chat.id)
for _, v in pairs(all) do
count = count + 1
end
if count >= 8 then
return mattata.send_reply(message, 'You can\'t have more than 8 picture triggers! Please delete one using /delpictrigger <trigger>. To view a list of this chat\'t picture triggers, use /pictriggers.')
end
local trigger, value = input:match('^(%w+) (.-)$')
if trigger:len() > 16 then
return mattata.send_reply(message, 'The trigger needs to be 1-16 characters long, and alpha-numerical.')
end
local success = mattata.send_photo(configuration.log_chat, value)
if not success then
return mattata.send_reply(message, 'That appears to be an invalid URL, because I couldn\'t send it! Please make sure it\'s a format Telegram bot API supports.')
end
mattata.delete_message(configuration.log_chat, success.result.message_id)
redis:hset('pictriggers:' .. message.chat.id, trigger, value)
return mattata.send_reply(message, 'Successfully added that picture trigger! To view a list of picture triggers, send /pictriggers.')
elseif message.command == 'delpictrigger' then
local input = mattata.input(message.text)
if not input or not input:match('^%w+$') then
return mattata.send_reply(message, 'Please specify the picture trigger you\'d like to delete! To view your existing picture triggers, send /pictriggers.')
end
local deleted = redis:hdel('pictriggers:' .. message.chat.id, input)
if deleted == 0 then
return mattata.send_reply(message, 'That trigger does not exist! Use /pictriggers to view a list of existing picture triggers for this chat.')
end
return mattata.send_reply(message, 'Successfully deleted that picture trigger!')
end
return false
end
return pictriggers
\ No newline at end of file
diff --git a/plugins/administration/pin.mattata b/plugins/administration/pin.mattata
index 7bded0f..6dd5953 100644
--- a/plugins/administration/pin.mattata
+++ b/plugins/administration/pin.mattata
@@ -1,66 +1,66 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local pin = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function pin:init()
pin.commands = mattata.commands(self.info.username):command('pin').table
pin.help = '/pin <text> - Pins the given text, with Markdown formatting enabled. To update the pin, send the command again with the new pin content.'
end
function pin:on_service_message(service_type, message, configuration, language)
if service_type == 'pinned message' then
local current = tonumber(redis:hget('chat:' .. message.chat.id .. ':info', 'pin'))
if mattata.get_setting(message.chat.id, 'remove channel pins') and message.from.id == 777000 then
if current then
return mattata.pin_chat_message(message.chat.id, current, true)
end
return mattata.unpin_chat_message(message.chat.id)
elseif mattata.get_setting(message.chat.id, 'remove other pins') then
if current and message.pinned_message.message_id ~= current then
return mattata.pin_chat_message(message.chat.id, current, true)
end
end
if message.from.id == self.info.id then
return mattata.delete_message(message.chat.id, message.message_id)
end
end
end
function pin:on_message(message, configuration, language)
if not mattata.is_group_admin(message.chat.id, message.from.id) then
return mattata.send_reply(message, language['errors']['admin'])
end
local input = mattata.input(message.text)
local last_pin = redis:hget('chat:' .. message.chat.id .. ':info', 'pin')
if not input then
if not last_pin then
return mattata.send_reply(message, language['pin']['1'])
end
local success = mattata.send_message(message, language['pin']['2'], nil, true, false, last_pin)
if not success then
return mattata.send_reply(message, language['pin']['3'])
end
return
end
local success = mattata.edit_message_text(message.chat.id, last_pin, input, true)
if not success then
if not redis:hget('chat:' .. message.chat.id .. ':info', 'pin') then
mattata.send_reply(message, language['pin']['4'])
end
local new_pin = mattata.send_message(message, input, 'markdown', true, false)
if not new_pin then
return mattata.send_reply(message, language['pin']['5'])
end
mattata.pin_chat_message(message.chat.id, new_pin.result.message_id, true)
redis:hset('chat:' .. message.chat.id .. ':info', 'pin', new_pin.result.message_id)
last_pin = new_pin.result.message_id
end
return mattata.pin_chat_message(message.chat.id, last_pin)
end
return pin
\ No newline at end of file
diff --git a/plugins/administration/promote.mattata b/plugins/administration/promote.mattata
index 06d83bb..9ccc183 100644
--- a/plugins/administration/promote.mattata
+++ b/plugins/administration/promote.mattata
@@ -1,151 +1,151 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local promote = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function promote:init()
promote.commands = mattata.commands(self.info.username)
:command('promote')
:command('mod').table
promote.help = '/promote [user] - Promotes a user to a moderator of the current chat. This command can only be used by administrators of a supergroup. Alias: /mod.'
end
function promote:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id,
true
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = message.reply
and tostring(message.reply.from.id)
or mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
promote.help
)
end
if tonumber(input) == nil
and not input:match('^%@')
then
input = '@' .. input
end
local user = mattata.get_user(input)
or mattata.get_chat(input) -- Resolve the username/ID to a user object.
if not user
then
return mattata.send_reply(
message,
language['errors']['unknown']
)
elseif user.result.id == self.info.id
then
return
end
user = user.result
local status = mattata.get_chat_member(
message.chat.id,
user.id
)
if not status
then
return mattata.send_reply(
message,
language['errors']['generic']
)
elseif mattata.is_group_admin(
message.chat.id,
user.id
)
or status.result.status == 'creator'
or status.result.status == 'administrator'
then -- We won't try and promote moderators and administrators.
return mattata.send_reply(
message,
language['promote']['1']
)
elseif status.result.status == 'left'
or status.result.status == 'kicked'
then -- Check if the user is in the group or not.
return mattata.send_reply(
message,
status.result.status == 'left'
and language['promote']['2']
or language['promote']['3']
)
end
redis:sadd(
'administration:' .. message.chat.id .. ':mods',
user.id
)
if redis:hget(
string.format(
'chat:%s:settings',
message.chat.id
),
'log administrative actions'
)
then
mattata.send_message(
mattata.get_log_chat(message.chat.id),
string.format(
'<pre>%s%s [%s] has promoted %s%s [%s] in %s%s [%s].</pre>',
message.from.username
and '@'
or '',
message.from.username
or mattata.escape_html(message.from.first_name),
message.from.id,
user.username
and '@'
or '',
user.username
or mattata.escape_html(user.first_name),
user.id,
message.chat.username
and '@'
or '',
message.chat.username
or mattata.escape_html(message.chat.title),
message.chat.id
),
'html'
)
end
return mattata.send_message(
message.chat.id,
string.format(
'<pre>%s%s has promoted %s%s.</pre>',
message.from.username
and '@'
or '',
message.from.username
or mattata.escape_html(message.from.first_name),
user.username
and '@'
or '',
user.username
or mattata.escape_html(user.first_name)
),
'html'
)
end
return promote
\ No newline at end of file
diff --git a/plugins/administration/purge.mattata b/plugins/administration/purge.mattata
index ba96599..a720a1c 100644
--- a/plugins/administration/purge.mattata
+++ b/plugins/administration/purge.mattata
@@ -1,103 +1,103 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local purge = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function purge:init()
purge.commands = mattata.commands(self.info.username):command('purge'):command('delmessages'):command('clear').table
purge.help = '/purge [1-25] - Deletes the previous X messages (by message ID), where X is the number specified between 1 and 25 inclusive. Alternatively, a message can be replied to (within the past 25 messages), and those messages will be deleted. If messages have already been purged in between the replied-to message and the command, less will be deleted. Aliases: /delmessages, /clear.'
end
function purge:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup' then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
return mattata.send_reply(message, language['errors']['admin'])
end
if redis:get('purge:' .. message.chat.id) then
return mattata.send_reply(message, 'You can only use this command once every 2 minutes. Please wait for it to cooldown!')
end
redis:set('purge:' .. message.chat.id, message.from.id)
redis:expire('purge:' .. message.chat.id, 120)
local input = mattata.input(message.text)
if not input and not message.reply then
redis:del('purge:' .. message.chat.id)
return mattata.send_reply(message, purge.help)
elseif message.reply then
local amount = message.message_id - message.reply.message_id
if amount > 25 then
amount = 25
end
if tonumber(input) ~= nil and tonumber(input) <= 25 then
amount = tonumber(input)
elseif tonumber(input) ~= nil then
redis:del('purge:' .. message.chat.id)
return mattata.send_reply(message, 'You cannot purge more than 25 messages at a time!')
end
local progress = message.reply.message_id
local deleted = 0
for i = 1, amount do
if deleted == amount then
return mattata.send_reply(message, 'Successfully deleted ' .. deleted .. ' message(s)!')
end
local done = mattata.delete_message(message.chat.id, progress)
if done then
deleted = deleted + 1
end
progress = progress + 1
end
return mattata.send_reply(message, 'Successfully deleted ' .. deleted .. ' message(s)!')
elseif tonumber(input) == nil then
redis:del('purge:' .. message.chat.id)
return mattata.send_reply(message, 'Please specify a numeric value, between 1 and 25 inclusive.')
elseif tonumber(input) < 1 then
redis:del('purge:' .. message.chat.id)
return mattata.send_reply(message, 'That number is too small! You must specify a number between 1 and 25 inclusive.')
elseif tonumber(input) > 25 then
redis:del('purge:' .. message.chat.id)
return mattata.send_reply(message, 'That number is too large! You must specify a number between 1 and 25 inclusive.')
end
local current = 0
if not message.reply then
current = mattata.send_message(message.chat.id, 'Attempting to purge the previous ' .. input .. ' message(s)...')
if not current then
redis:del('purge:' .. message.chat.id)
return false
end
else
current = message
current.result = current.reply
end
current = current.result.message_id
if tonumber(current) - tonumber(input) <= 1 then
redis:del('purge:' .. message.chat.id)
return mattata.edit_message_text(
message.chat.id,
current,
'There are not ' .. input .. ' message(s) available to be deleted! Please specify a number between 1 and ' .. tonumber(current) - tonumber(input) - 1 .. ' inclusive.'
)
end
local progress = tonumber(current) - 1
local deleted = 0
for i = 1, tonumber(input) do
local done = mattata.delete_message(message.chat.id, progress)
if done then
deleted = deleted + 1
end
progress = progress - 1
end
local success = mattata.edit_message_text(message.chat.id, current, 'Successfully deleted ' .. deleted .. ' message(s)!')
if not success then
return mattata.send_message(message.chat.id, 'Successfully deleted ' .. deleted .. ' message(s)!')
end
return success
end
return purge
\ No newline at end of file
diff --git a/plugins/administration/report.mattata b/plugins/administration/report.mattata
index b51b11d..613b1e3 100644
--- a/plugins/administration/report.mattata
+++ b/plugins/administration/report.mattata
@@ -1,41 +1,41 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local report = {}
local mattata = require('mattata')
function report:init()
report.commands = mattata.commands(self.info.username):command('report'):command('ops').table
report.help = '/report - Reports the replied-to message to all administrators of the group, via private message. Alias: /ops.'
end
function report:on_message(message, configuration, language)
if not message.reply then
return mattata.send_message(message.chat.id, language['report']['1'])
elseif message.reply.from.id == message.from.id then
return mattata.send_message(message.chat.id, language['report']['2'])
end
local admin_list = {}
local admins = mattata.get_chat_administrators(message.chat.id)
local notified = 0
for n in pairs(admins.result) do
if admins.result[n].user.id ~= self.info.id then
local old_language = language
language = require('languages.' .. mattata.get_user_language(admins.result[n].user.id))
local output = string.format(language['report']['3'], mattata.escape_html(message.from.first_name), mattata.escape_html(message.chat.title))
output = output .. '\n<a href="https://t.me/c/' .. tostring(message.chat.id):gsub('^%-100', '') .. '/' .. message.reply.message_id .. '">' .. language['report']['4'] .. '</a>'
local success = mattata.send_message(admins.result[n].user.id, output, 'html')
if success then
mattata.forward_message(admins.result[n].user.id, message.chat.id, false, message.reply.message_id)
notified = notified + 1
end
language = old_language
end
end
local output = string.format(language['report']['5'], notified)
return mattata.send_reply(message, output)
end
return report
\ No newline at end of file
diff --git a/plugins/administration/rules.mattata b/plugins/administration/rules.mattata
index 3ba29ba..c23baa7 100644
--- a/plugins/administration/rules.mattata
+++ b/plugins/administration/rules.mattata
@@ -1,32 +1,32 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local rules = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function rules:init()
rules.commands = mattata.commands(self.info.username):command('rules').table
rules.help = '/rules - View the group\'s rules.'
end
function rules:on_message(message, configuration, language)
local input = mattata.input(message.text)
local chat_id = message.chat.id
if not input and message.chat.type ~= 'supergroup' then
return false
elseif input and input:match('^%-?%d+$') then
chat_id = input
end
local output = mattata.get_value(chat_id, 'rules') or 'There are no rules set for this chat!'
if mattata.get_setting(message.chat.id, 'send rules in group') or (input and message.chat.type == 'private') then
return mattata.send_message(message.chat.id, output, 'markdown', true, false)
end
local success = mattata.send_message(message.from.id, output, 'markdown', true, false)
output = success and 'I have sent you the rules via private chat!' or string.format('You need to speak to me in private chat before I can send you the rules! Just click [here](https://t.me/%s?start=rules_%s), press the "START" button, and try again!', self.info.username, message.chat.id)
return mattata.send_reply(message, output, 'markdown', true)
end
return rules
\ No newline at end of file
diff --git a/plugins/administration/save.mattata b/plugins/administration/save.mattata
index 1d7d133..568a684 100644
--- a/plugins/administration/save.mattata
+++ b/plugins/administration/save.mattata
@@ -1,64 +1,64 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local save = {}
local mattata = require('mattata')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function save:init()
save.commands = mattata.commands(self.info.username):command('save').table
save.help = '/save - Stores the replied-to message in mattata\'s database - of which a randomly-selected, saved message from the said user can be retrieved using /quote.'
end
function save:on_message(message, configuration, language)
if not message.reply
or #message.reply.text < 1
then
return mattata.send_reply(
message,
save.help
)
elseif message.reply.forward_from
then
message.reply.from = message.reply.forward_from
end
if redis:get('user:' .. message.reply.from.id .. ':opt_out')
then
redis:del('quotes:' .. message.reply.from.id)
return mattata.send_reply(
message,
language['save']['1']
)
end
local quotes = redis:get('quotes:' .. message.reply.from.id)
if not quotes
then
quotes = {}
else
quotes = json.decode(quotes)
end
table.insert(
quotes,
message.reply.text
)
redis:set(
'quotes:' .. message.reply.from.id,
json.encode(quotes)
)
return mattata.send_reply(
message,
string.format(
language['save']['2'],
message.reply.from.username
and '@'
or '',
message.reply.from.username
or message.reply.from.first_name
)
)
end
return save
\ No newline at end of file
diff --git a/plugins/administration/setchattitle.mattata b/plugins/administration/setchattitle.mattata
index 7d8257d..fdd69ef 100644
--- a/plugins/administration/setchattitle.mattata
+++ b/plugins/administration/setchattitle.mattata
@@ -1,40 +1,40 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local setchattitle = {}
local mattata = require('mattata')
function setchattitle:init()
setchattitle.commands = mattata.commands(self.info.username):command('setchattitle'):command('sct').table
setchattitle.help = '/setchattitle <title> - Sets the replied-to admin\'s title to the given text. The given text must be between 1 and 16 characters in length. Alias: /sct.'
end
function setchattitle:on_message(message, configuration, language)
if message.chat.type == 'private' then
return false
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
return false
elseif not message.reply then
return mattata.send_reply(message, 'Please use this command in reply to the admin you want to give the title to!')
elseif not mattata.is_group_admin(message.chat.id, message.reply.from.id) then
return mattata.send_reply(message, 'The replied-to user isn\'t an admin in this group!')
end
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, setchattitle.help)
elseif input:len() > 16 then
return mattata.send_reply(message, 'The title must be between 1 and 16 characters long!')
end
local success = mattata.set_chat_administrator_custom_title(message.chat.id, message.reply.from.id, input)
if not success then
return mattata.send_reply(
message,
'An error occured whilst trying to set that admin\'s title. Please ensure I have the required administrative permissions to perform this action, then try again.'
)
end
return
end
return setchattitle
\ No newline at end of file
diff --git a/plugins/administration/setdescription.mattata b/plugins/administration/setdescription.mattata
index 15db430..bad84cc 100644
--- a/plugins/administration/setdescription.mattata
+++ b/plugins/administration/setdescription.mattata
@@ -1,55 +1,55 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local setdescription = {}
local mattata = require('mattata')
function setdescription:init()
setdescription.commands = mattata.commands(self.info.username):command('setdescription').table
setdescription.help = '/setdescription <text> - Sets the group\'s description to the given text. The given text must be between 1 and 255 characters in length.'
end
function setdescription:on_message(message, configuration, language)
if message.chat.type == 'private'
then
return mattata.send_reply(
message,
'You can\'t use this command in private chat.'
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = mattata.input(message.text)
if not input
or input:len() < 1
or input:len() > 255
then
return mattata.send_reply(
message,
setdescription.help
)
end
local success = mattata.set_chat_description(
message.chat.id,
input
)
if not success
then
return mattata.send_reply(
message,
'An error occured whilst trying to set the chat\'s description. Please ensure I have the required administrative permissions to perform this action, then try again.'
)
end
return
end
return setdescription
\ No newline at end of file
diff --git a/plugins/administration/setgrouplang.mattata b/plugins/administration/setgrouplang.mattata
index 1590a06..56f2773 100644
--- a/plugins/administration/setgrouplang.mattata
+++ b/plugins/administration/setgrouplang.mattata
@@ -1,227 +1,227 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local setgrouplang = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
local json = require('dkjson')
function setgrouplang:init()
setgrouplang.commands = mattata.commands(self.info.username):command('setgrouplang').table
setgrouplang.help = '/setgrouplang - Allows you to force mattata to respond to all members of the current chat in the selected language.'
end
setgrouplang.languages = {
['en_gb'] = 'British English 🇬🇧',
['en_us'] = 'American English 🇺🇸',
['de_de'] = 'Deutsch 🇩🇪',
['scottish'] = 'Scottish 🏴',
['pl_pl'] = 'Polski 🇵🇱',
['pt_br'] = 'Português do Brasil 🇧🇷',
['pt_pt'] = 'Português 🇵🇹',
['tr_tr'] = 'Türkçe 🇹🇷'
}
setgrouplang.languages_short = {
['en_gb'] = '🇬🇧',
['en_us'] = '🇺🇸',
['de_de'] = '🇩🇪',
['scottish'] = '🏴',
['pl_pl'] = '🇵🇱',
['pt_br'] = '🇧🇷',
['pt_pt'] = '🇵🇹',
['tr_tr'] = '🇹🇷'
}
function setgrouplang.get_keyboard(chat_id, language)
local keyboard = {
['inline_keyboard'] = {
{}
}
}
local total = 0
for _, v in pairs(setgrouplang.languages_short)
do
total = total + 1
end
local count = 0
local rows = math.floor(total / 2)
if rows ~= total
then
rows = rows + 1
end
local row = 1
for k, v in pairs(setgrouplang.languages_short)
do
count = count + 1
if count == rows * row
then
row = row + 1
table.insert(
keyboard.inline_keyboard,
{}
)
end
table.insert(
keyboard.inline_keyboard[row],
{
['text'] = v,
['callback_data'] = 'setgrouplang:' .. chat_id .. ':' .. k
}
)
end
table.insert(
keyboard.inline_keyboard,
{
{
['text'] = language['setgrouplang']['5'],
['callback_data'] = 'administration:' .. chat_id .. ':force_group_language'
}
}
)
return keyboard
end
function setgrouplang.set_lang(chat_id, locale, lang, language)
redis:hset(
'chat:' .. chat_id .. ':info',
'group language',
locale
)
return string.format(
language['setgrouplang']['1'],
lang
)
end
function setgrouplang.get_lang(chat_id, language)
local lang = mattata.get_value(
chat_id,
'group language'
)
or 'en_gb'
for k, v in pairs(setgrouplang.languages)
do
if k == lang
then
lang = v
break
end
end
return string.format(
language['setgrouplang']['2'],
lang
)
end
function setgrouplang:on_callback_query(callback_query, message, configuration, language)
if not message
or (
message
and message.date <= 1493668000
)
then
return -- We don't want to process requests from messages before the language
-- functionality was re-implemented, it could cause issues!
elseif not mattata.is_group_admin(
message.chat.id,
callback_query.from.id
)
then
return mattata.answer_callback_query(
callback_query.id,
language['errors']['admin']
)
end
local chat_id, new_language = callback_query.data:match('^(.-)%:(.-)$')
if not chat_id
or not new_language
or tostring(message.chat.id) ~= chat_id
then
return
elseif not mattata.get_setting(
message.chat.id,
'force group language'
)
then
redis:hset(
'chat:' .. message.chat.id .. ':settings',
'force group language',
true
)
end
return mattata.edit_message_text(
message.chat.id,
message.message_id,
setgrouplang.set_lang(
chat_id,
new_language,
setgrouplang.languages[new_language],
language
),
nil,
true,
setgrouplang.get_keyboard(
chat_id,
language
)
)
end
function setgrouplang:on_message(message, configuration, language)
if not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
elseif message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
end
if not mattata.get_setting(
message.chat.id,
'force group language'
)
then
return mattata.send_message(
message.chat.id,
language['setgrouplang']['3'],
nil,
true,
false,
nil,
mattata.inline_keyboard():row(
mattata.row():callback_data_button(
language['setgrouplang']['4'],
'administration:' .. message.chat.id .. ':force_group_language'
)
)
)
end
return mattata.send_message(
message.chat.id,
setgrouplang.get_lang(
message.chat.id,
language
),
nil,
true,
false,
nil,
setgrouplang.get_keyboard(
message.chat.id,
language
)
)
end
return setgrouplang
\ No newline at end of file
diff --git a/plugins/administration/setrules.mattata b/plugins/administration/setrules.mattata
index 8e6d779..0f759b5 100644
--- a/plugins/administration/setrules.mattata
+++ b/plugins/administration/setrules.mattata
@@ -1,58 +1,58 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local setrules = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function setrules:init()
setrules.commands = mattata.commands(self.info.username):command('setrules').table
setrules.help = '/setrules <text> - Sets the group\'s rules to the give text. Markdown formatting is supported.'
end
function setrules:on_message(message, configuration, language)
if not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
setrules.help
)
end
redis:hset(
'chat:' .. message.chat.id .. ':info',
'rules',
input
)
local success = mattata.send_message(
message,
input,
'markdown'
)
if not success
then
return mattata.send_reply(
message,
language['setrules']['1']
)
end
return mattata.edit_message_text(
message.chat.id,
success.result.message_id,
language['setrules']['2']
)
end
return setrules
\ No newline at end of file
diff --git a/plugins/administration/settitle.mattata b/plugins/administration/settitle.mattata
index 6596bcc..053cfcf 100644
--- a/plugins/administration/settitle.mattata
+++ b/plugins/administration/settitle.mattata
@@ -1,55 +1,55 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local settitle = {}
local mattata = require('mattata')
function settitle:init()
settitle.commands = mattata.commands(self.info.username):command('settitle').table
settitle.help = '/settitle <text> - Sets the group\'s title to the given text. The given text must be between 1 and 255 characters in length.'
end
function settitle:on_message(message, configuration, language)
if message.chat.type == 'private'
then
return mattata.send_reply(
message,
'You can\'t use this command in private chat.'
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = mattata.input(message.text)
if not input
or input:len() < 1
or input:len() > 255
then
return mattata.send_reply(
message,
settitle.help
)
end
local success = mattata.set_chat_title(
message.chat.id,
input
)
if not success
then
return mattata.send_reply(
message,
'An error occured whilst trying to set the chat\'s title. Please ensure I have the required administrative permissions to perform this action, then try again.'
)
end
return
end
return settitle
\ No newline at end of file
diff --git a/plugins/administration/setwelcome.mattata b/plugins/administration/setwelcome.mattata
index 8a7b71a..0e1e5bb 100644
--- a/plugins/administration/setwelcome.mattata
+++ b/plugins/administration/setwelcome.mattata
@@ -1,76 +1,76 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local setwelcome = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function setwelcome:init()
setwelcome.commands = mattata.commands(self.info.username):command('setwelcome').table
setwelcome.help = '/setwelcome <text> - Sets the group\'s welcome message to the given, Markdown-formatted text. You can use placeholders to automatically customise the welcome message for each user. Use $user_id to insert the user\'s numerical ID, $chat_id to insert the chat\'s numerical ID, $name to insert the user\'s name, $title to insert the chat\'s title and $username to insert the user\'s username (if the user doesn\'t have an @username, their name will be used instead, so it is best to avoid using this in conjunction with $name).'
end
function setwelcome:on_message(message, configuration, language)
if not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = mattata.input(message.text)
if not input
then
local success = mattata.send_force_reply(
message,
language['setwelcome']['1']
)
if success
then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/setwelcome'
)
end
return
end
local validate = mattata.send_message(
configuration.log_chat,
input,
'markdown'
)
if not validate
then
return mattata.send_reply(
message,
language['setwelcome']['2']
)
end
mattata.delete_message(
configuration.log_chat,
validate.result.message_id
)
redis:hset(
'chat:' .. message.chat.id .. ':info',
'welcome message',
input
)
return mattata.send_message(
message.chat.id,
string.format(
language['setwelcome']['3'],
message.chat.title
)
)
end
return setwelcome
\ No newline at end of file
diff --git a/plugins/administration/staff.mattata b/plugins/administration/staff.mattata
index f1f3005..cf98b3f 100644
--- a/plugins/administration/staff.mattata
+++ b/plugins/administration/staff.mattata
@@ -1,98 +1,98 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local staff = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function staff:init()
staff.commands = mattata.commands(self.info.username):command('staff'):command('admins').table
staff.help = '/staff - Displays the staff members in the current chat. Alias: /admins.'
end
function staff.format_admin_list(output, chat_id)
local creator = ''
local admin_count = 1
local admins = ''
for i, admin in pairs(output.result) do
local user
local branch = ' ├ '
if admin.status == 'creator' then
creator = mattata.escape_html(admin.user.first_name)
if admin.user.username then
creator = string.format(
'<a href="https://t.me/%s">%s</a>',
admin.user.username,
creator
)
end
elseif admin.status == 'administrator' then
user = mattata.escape_html(admin.user.first_name)
if admin.user.username then
user = string.format(
'<a href="https://t.me/%s">%s</a>',
admin.user.username,
user
)
end
admin_count = admin_count + 1
if admin_count == #output.result then
branch = ' └ '
end
admins = admins .. branch .. user .. '\n'
end
end
local mod_list = redis:smembers('administration:' .. chat_id .. ':mods')
local mod_count = 0
local mods = ''
if next(mod_list) then
local branch = ' ├ '
local user
for i = 1, #mod_list do
user = mattata.get_linked_name(mod_list[i])
if user then
if i == #mod_list then
branch = ' └ '
end
mods = mods .. branch .. user .. '\n'
mod_count = mod_count + 1
end
end
end
if creator == '' then
creator = '-'
end
if admins == '' then
admins = '-'
end
if mods == '' then
mods = '-'
end
return string.format(
'<b>👤 Creator</b>\n└ %s\n\n<b>👥 Admins</b> (%d)\n%s\n<b>👥 Moderators</b> (%d)\n%s',
creator,
admin_count - 1,
admins,
mod_count,
mods
)
end
function staff:on_message(message)
local success = mattata.get_chat_administrators(message.chat.id)
if not success then
return mattata.send_reply(
message,
'I couldn\'t get a list of administrators in this chat.'
)
end
return mattata.send_message(
message,
staff.format_admin_list(success, message.chat.id),
'html'
)
end
return staff
\ No newline at end of file
diff --git a/plugins/administration/tempban.mattata b/plugins/administration/tempban.mattata
index ca5eefd..3a5b797 100644
--- a/plugins/administration/tempban.mattata
+++ b/plugins/administration/tempban.mattata
@@ -1,79 +1,79 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local tempban = {}
local mattata = require('mattata')
function tempban:init()
tempban.commands = mattata.commands(self.info.username):command('tempban').table
tempban.help = '/tempban [user] <length> - Temporarily bans a user from the current chat for the given length. The length should be in the format 1y2mo3w4d5h6m7s. Some natural language is supported too. Temp-bans must be a minimum of 60 seconds in length. This command can only be used by moderators and administrators of a supergroup.'
end
function tempban:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup' then
local output = language['errors']['supergroup']
return mattata.send_reply(message, output)
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
local output = language['errors']['admin']
return mattata.send_reply(message, output)
end
local user, until_date = false, false
local input = mattata.input(message)
if input:match('^@?[%w_]+ .-$') then
user, until_date = input:match('^(@?[%w_]+) (.-)$')
elseif input then
until_date = input
if message.reply then
user = message.reply.from.id
end
end
until_date = mattata.string_to_time(until_date, true)
if until_date == false then
return mattata.send_reply(message, 'You must specify a length when using this command! This should be in the format 1y2mo3w4d5h6m7s. Some natural language is supported too. Temp-ban must be a minimum of 60 seconds in length.')
elseif not user then
return mattata.send_reply(message, 'You must specify a user to temp-ban. This can be done by mention, reply or ID.')
end
until_date = os.time() + until_date
local user_object = mattata.get_user(user) -- resolve the username/ID to a user object
if not user_object then
return mattata.send_reply(message, language.errors.unknown)
elseif user_object.result.id == self.info.id then
return false -- don't let the bot temp-ban itself
end
user_object = user_object.result
local status = mattata.get_chat_member(message.chat.id, user_object.id)
local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
if not status then
return mattata.send_reply(message, language.errors.generic)
elseif is_admin then -- we won't try and tempban moderators and administrators.
return mattata.send_reply(message, 'I can\'t temp-ban that user as they\'re an admin in this group!')
elseif status.result.status == 'kicked' then -- check if the user has already been kicked
return mattata.send_reply(message, 'I can\'t temp-ban that user as they\'re already been banned from this chat!')
end
local success = mattata.ban_chat_member(message.chat.id, user_object.id, until_date) -- attempt to temp-ban the user from the group
if not success then
return mattata.send_reply(message, 'I couldn\'t temp-ban that user! Please ensure I have the required permissions and try again!')
end
mattata.increase_administrative_action(message.chat.id, user_object.id, 'tempbans')
local until_formatted = os.date('%c', until_date):gsub(' ', ' ') .. ' GMT +0'
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local tempbanned_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local output = '%s <code>[%s]</code> has temp-banned %s <code>[%s]</code> from %s <code>[%s]</code> until %s.\n%s %s'
output = string.format(output, admin_username, message.from.id, tempbanned_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, until_formatted, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
mattata.send_message(log_chat, output, 'html')
else
local output = '%s has temp-banned %s until %s.'
output = string.format(output, admin_username, tempbanned_username, until_formatted)
mattata.send_message(message.chat.id, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
end
return
end
return tempban
\ No newline at end of file
diff --git a/plugins/administration/tempmute.mattata b/plugins/administration/tempmute.mattata
index 18cfa2c..2dde0f7 100644
--- a/plugins/administration/tempmute.mattata
+++ b/plugins/administration/tempmute.mattata
@@ -1,85 +1,85 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local tempmute = {}
local mattata = require('mattata')
function tempmute:init()
tempmute.commands = mattata.commands(self.info.username):command('tempmute').table
tempmute.help = '/tempmute [user] <length> - Temporarily mutes a user in the current chat for the given length. The length should be in the format 1y2mo3w4d5h6m7s. Some natural language is supported too. Temp-mutes must be a minimum of 60 seconds in length. This command can only be used by moderators and administrators of a supergroup.'
end
function tempmute:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup' then
local output = language['errors']['supergroup']
return mattata.send_reply(message, output)
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
local output = language['errors']['admin']
return mattata.send_reply(message, output)
end
local user, until_date = false, false
local input = mattata.input(message)
if input:match('^@?[%w_]+ .-$') then
user, until_date = input:match('^(@?[%w_]+) (.-)$')
elseif input then
until_date = input
if message.reply then
user = message.reply.from.id
end
end
until_date = mattata.string_to_time(until_date, true)
if until_date == false then
return mattata.send_reply(message, 'You must specify a length when using this command! This should be in the format 1y2mo3w4d5h6m7s. Some natural language is supported too. temp-mute must be a minimum of 60 seconds in length.')
elseif not user then
return mattata.send_reply(message, 'You must specify a user to temp-mute. This can be done by mention, reply or ID.')
end
until_date = os.time() + until_date
local user_object = mattata.get_user(user) -- resolve the username/ID to a user object
if not user_object then
return mattata.send_reply(message, language.errors.unknown)
elseif user_object.result.id == self.info.id then
return false -- don't let the bot temp-mute itself
end
user_object = user_object.result
local status = mattata.get_chat_member(message.chat.id, user_object.id)
local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
if not status then
return mattata.send_reply(message, language.errors.generic)
elseif is_admin then -- we won't try and tempmute moderators and administrators.
return mattata.send_reply(message, 'I can\'t temp-mute that user as they\'re an admin in this group!')
elseif status.result.status == 'kicked' then -- check if the user has already been kicked
return mattata.send_reply(message, 'I can\'t temp-mute that user as they\'re already been banned from this chat!')
end
local bot_status = mattata.get_chat_member(message.chat.id, self.info.id)
if not bot_status then
return false
elseif not bot_status.result.can_restrict_members then
return mattata.send_reply(message, 'It appears I don\'t have the required permissions required in order to temp-mute that user. Please amend this and try again!')
end
local success = mattata.restrict_chat_member(message.chat.id, user_object.id, until_date, false, false, false, false, false, false, false, false) -- attempt to temp-mute the user in the group
if not success then
return mattata.send_reply(message, 'I couldn\'t temp-mute that user! Please ensure I have the required permissions and try again!')
end
mattata.increase_administrative_action(message.chat.id, user_object.id, 'tempmutes')
local until_formatted = os.date('%c', until_date):gsub(' ', ' ') .. ' GMT +0'
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local tempmuted_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local output = '%s <code>[%s]</code> has temp-muted %s <code>[%s]</code> from %s <code>[%s]</code> until %s.\n%s %s'
output = string.format(output, admin_username, message.from.id, tempmuted_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, until_formatted, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
mattata.send_message(log_chat, output, 'html')
else
local output = '%s has temp-muted %s until %s.'
output = string.format(output, admin_username, tempmuted_username, until_formatted)
mattata.send_message(message.chat.id, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
end
return
end
return tempmute
\ No newline at end of file
diff --git a/plugins/administration/triggers.mattata b/plugins/administration/triggers.mattata
index 2ec94dd..1737cdc 100644
--- a/plugins/administration/triggers.mattata
+++ b/plugins/administration/triggers.mattata
@@ -1,113 +1,113 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local triggers = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function triggers:init()
triggers.commands = mattata.commands(self.info.username):command('triggers'):command('trigger'):command('custom'):command('addtrigger'):command('deltrigger').table
triggers.help = '/triggers - Allows admins to view existing word triggers. Use /addtrigger <trigger> <value> to add one, and /deltrigger <trigger> to delete one. Each chat is allowed 8 word triggers, with a maximum of 16 characters per word trigger and 256 characters per response. Trigger words can be alpha-numerical, and may have hashtags at the start. Aliases: /trigger, /custom.'
end
function triggers.on_new_message(_, message)
if message.command or message.is_media then
return false
end
local matches = redis:hgetall('triggers:' .. message.chat.id)
if not next(matches) == 0 then
return false
end
for trigger, value in pairs(matches) do
if message.text:lower():match(trigger:lower()) then
local trail
if trigger:lower() == 'ayy' and value:lower() == 'lmao' then
trail = message.text:lower():match('(ayy+)'):gsub('^ay', '')
value = 'lma' .. string.rep('o', trail:len())
elseif trigger:lower() == 'lmao' and value:lower() == 'ayy' then
trail = message.text:lower():match('(lmao+)'):gsub('^lma', '')
value = 'ay' .. string.rep('y', trail:len())
end
if value:len() > 4096 then
value = value:sub(1, 4096)
end
if not message.is_edited then
local success = mattata.send_message(message.chat.id, '<pre>' .. mattata.escape_html(value) .. '</pre>', 'html')
if success then
redis:set('bot:' .. message.chat.id .. ':' .. message.message_id, success.result.message_id)
end
else
local message_id = redis:get('bot:' .. message.chat.id .. ':' .. message.message_id)
if message_id then
mattata.edit_message_text(message.chat.id, message_id, '<pre>' .. mattata.escape_html(value) .. '</pre>', 'html')
end
end
end
end
return
end
function triggers:on_message(message)
self.is_done = true
if message.chat.type == 'private' or not mattata.is_group_admin(message.chat.id, message.from.id) then
return false
elseif message.command == 'triggers' then
local matches = redis:hgetall('triggers:' .. message.chat.id)
if not next(matches) then
return mattata.send_reply(message, 'This chat doesn\'t have any triggers set up. To add one, use /addtrigger <trigger> <value>.')
end
local output = 'Triggers for <b>%s</b>\n\n%s'
local all = {}
for trigger, value in pairs(matches) do
local line = '<code>%s</code>: <i>%s</i>'
line = string.format(line, mattata.escape_html(trigger), mattata.escape_html(value))
table.insert(all, line)
end
table.insert(all, '\nTo delete a trigger, use <code>/deltrigger &lt;trigger&gt;</code>')
all = table.concat(all, '\n')
output = string.format(output, mattata.escape_html(message.chat.title), all)
return mattata.send_reply(message, output, 'html')
elseif message.command == 'addtrigger' or message.command == 'trigger' or message.command == 'custom' then
local input = mattata.input(message.text)
if not input or not input:match('^#?%w+ .-$') then
return mattata.send_reply(message, triggers.help)
end
local trigger, value = input:match('^(#?%w+) (.-)$')
local count = 0
local is_duplicate = false
local all = redis:hgetall('triggers:' .. message.chat.id)
for _, v in ipairs(all) do
count = count + 1
if v == trigger then
is_duplicate = true
end
end
if is_duplicate then
return mattata.send_reply(message, 'That trigger already exists! To modify it, delete it first using /deltrigger ' .. trigger .. ', then use this command again!')
elseif count >= 8 then
return mattata.send_reply(message, 'You can\'t have more than 8 triggers! Please delete one using /deltrigger <trigger>. To view a list of this chat\'t triggers, use /triggers.')
end
if trigger:len() > 16 then
return mattata.send_reply(message, 'The trigger needs to be 1-16 characters long, and alpha-numerical.')
elseif value:len() > 256 then
return mattata.send_reply(message, 'The value must be no more than 256 characters long!')
end
redis:hset('triggers:' .. message.chat.id, trigger, value)
return mattata.send_reply(message, 'Successfully added that trigger! To view a list of triggers, send /triggers.')
elseif message.command == 'deltrigger' then
local input = mattata.input(message.text)
if not input or not input:match('^#?%w+$') then
return mattata.send_reply(message, 'Please specify the trigger you\'d like to delete! To view your existing triggers, send /triggers.')
end
local deleted = redis:hdel('triggers:' .. message.chat.id, input)
if deleted == 0 then
return mattata.send_reply(message, 'That trigger does not exist! Use /triggers to view a list of existing triggers for this chat.')
end
return mattata.send_reply(message, 'Successfully deleted that trigger!')
end
return false
end
return triggers
\ No newline at end of file
diff --git a/plugins/administration/trust.mattata b/plugins/administration/trust.mattata
index 15637c9..0d943eb 100644
--- a/plugins/administration/trust.mattata
+++ b/plugins/administration/trust.mattata
@@ -1,149 +1,149 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local trust = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function trust:init()
trust.commands = mattata.commands(self.info.username):command('trust').table
trust.help = '/trust [user] - Promotes a user to a trusted user of the current chat. This command can only be used by administrators of a supergroup.'
end
function trust:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id,
true
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = message.reply
and tostring(message.reply.from.id)
or mattata.input(message)
if not input
then
return mattata.send_reply(
message,
trust.help
)
end
if tonumber(input) == nil
and not input:match('^%@')
then
input = '@' .. input
end
local user = mattata.get_user(input)
or mattata.get_chat(input) -- Resolve the username/ID to a user object.
if not user
then
return mattata.send_reply(
message,
language['errors']['unknown']
)
elseif user.result.id == self.info.id
then
return
end
user = user.result
local status = mattata.get_chat_member(
message.chat.id,
user.id
)
if not status
then
return mattata.send_reply(
message,
language['errors']['generic']
)
elseif mattata.is_group_admin(
message.chat.id,
user.id
)
or status.result.status == 'creator'
or status.result.status == 'administrator'
then -- We won't try and trust moderators and administrators.
return mattata.send_reply(
message,
language['trust']['1']
)
elseif status.result.status == 'left'
or status.result.status == 'kicked'
then -- Check if the user is in the group or not.
return mattata.send_reply(
message,
status.result.status == 'left'
and language['trust']['2']
or language['trust']['3']
)
end
redis:sadd(
'administration:' .. message.chat.id .. ':trusted',
user.id
)
if redis:hget(
string.format(
'chat:%s:settings',
message.chat.id
),
'log administrative actions'
)
then
mattata.send_message(
mattata.get_log_chat(message.chat.id),
string.format(
'<pre>%s%s [%s] has trusted %s%s [%s] in %s%s [%s].</pre>',
message.from.username
and '@'
or '',
message.from.username
or mattata.escape_html(message.from.first_name),
message.from.id,
user.username
and '@'
or '',
user.username
or mattata.escape_html(user.first_name),
user.id,
message.chat.username
and '@'
or '',
message.chat.username
or mattata.escape_html(message.chat.title),
message.chat.id
),
'html'
)
end
return mattata.send_message(
message.chat.id,
string.format(
'<pre>%s%s has trusted %s%s.</pre>',
message.from.username
and '@'
or '',
message.from.username
or mattata.escape_html(message.from.first_name),
user.username
and '@'
or '',
user.username
or mattata.escape_html(user.first_name)
),
'html'
)
end
return trust
\ No newline at end of file
diff --git a/plugins/administration/unban.mattata b/plugins/administration/unban.mattata
index 0ee9444..193dea4 100644
--- a/plugins/administration/unban.mattata
+++ b/plugins/administration/unban.mattata
@@ -1,89 +1,89 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local unban = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function unban:init()
unban.commands = mattata.commands(self.info.username):command('unban').table
unban.help = '/unban [user] - Unbans a user from the current chat. This command can only be used by moderators and administrators of a supergroup.'
end
function unban:on_message(message, _, language)
if message.chat.type ~= 'supergroup' then
return mattata.send_reply(message, language['errors']['supergroup'])
elseif not mattata.is_group_admin(message.chat.id, message.from.id) then
return mattata.send_reply(message, language['errors']['admin'])
end
local reason = false
local user = false
local input = mattata.input(message)
-- Check the message object for any users this command
-- is intended to be executed on.
if message.reply then
user = message.reply.from.id
if input then
reason = input
end
elseif input and input:match(' ') then
user, reason = input:match('^(.-) (.-)$')
elseif input then
user = input
end
if not user then
local output = 'Which user would you like me to unban? You can specify this user by their @username or numerical ID.'
local success = mattata.send_force_reply(message, output)
if success then
redis:set('action:' .. message.chat.id .. ':' .. success.result.message_id, '/unban')
end
return
end
if tonumber(user) == nil and not user:match('^%@') then
user = '@' .. user
end
user = mattata.get_user(user) -- Resolve the username/ID to a user object.
if not user then
return mattata.send_reply(message, language['errors']['unknown'])
elseif user.result.id == self.info.id then
return
end
user = user.result
local status = mattata.get_chat_member(message.chat.id, user.id)
if not status then
return mattata.send_reply(message, language['errors']['generic'])
elseif status.result.status == 'creator' or status.result.status == 'administrator' then -- We won't try and unban administrators.
return mattata.send_reply(message, 'I cannot unban this user because they are a moderator or an administrator in this chat.')
elseif status.result.status == 'member' then -- Check if the user is in the group or not.
return mattata.send_reply(message, 'I cannot unban this user because they are still in this chat.')
end
local success = mattata.unban_chat_member(message.chat.id, user.id) -- Attempt to unban the user from the group.
if not success then -- Since we've ruled everything else out, it's safe to say if it wasn't a success then the bot isn't
-- an administrator in the group.
local output = 'I need to have administrative permissions in order to unban this user. Please amend this issue, and try again.'
return mattata.send_reply(message, output)
end
mattata.increase_administrative_action(message.chat.id, user.id, 'unbans')
reason = reason and ', for ' .. reason or ''
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local unbanned_username = mattata.get_formatted_user(user.id, user.first_name, 'html')
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local output = '%s <code>[%s]</code> has unbanned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s'
output = string.format(output, admin_username, message.from.id, unbanned_username, user.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user.id)
mattata.send_message(log_chat, output, 'html')
else
local output = '%s has unbanned %s%s.'
output = string.format(output, admin_username, unbanned_username, reason)
mattata.send_message(message.chat.id, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
mattata.delete_message(message.chat.id, message.message_id)
end
return
end
return unban
\ No newline at end of file
diff --git a/plugins/administration/unfban.mattata b/plugins/administration/unfban.mattata
index 9ab32ea..316df75 100644
--- a/plugins/administration/unfban.mattata
+++ b/plugins/administration/unfban.mattata
@@ -1,119 +1,119 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local unfban = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function unfban:init()
unfban.commands = mattata.commands(self.info.username):command('unfban'):command('unfedban'):command('ufb').table
unfban.help = '/unfban [user] - Unbans a user from the current chat and the Fed the group is part of. This command can only be used by Fed admins. Aliases: /unfedban, /ufb.'
end
function unfban:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup' then
local output = language['errors']['supergroup']
return mattata.send_reply(message, output)
end
local fed_ids = mattata.get_feds(message.chat.id)
if #fed_ids == 0 then
return mattata.send_reply(message, 'This group isn\'t part of a fed. Ask a group admin to join one!')
end
local is_admin_feds = {}
for _, fed in pairs(fed_ids) do
if mattata.is_fed_admin(fed, message.from.id) then
table.insert(is_admin_feds, fed)
end
end
if #is_admin_feds == 0 then
return mattata.send_reply(message, 'You need to be a Fed admin in at least one of this group\'s Feds in order to be able to use this command!')
end
local reason = false
local user = false
local input = mattata.input(message)
-- check the message object for any users this command
-- is intended to be executed on
if message.reply then
user = message.reply.from.id
if input then
reason = input
end
elseif input and input:match(' ') then
user, reason = input:match('^(.-) (.-)$')
elseif input then
user = input
end
if not user then
local output = language['fban']['1']
local success = mattata.send_force_reply(message, output)
if success then
mattata.set_command_action(message.chat.id, success.result.message_id, '/unfban')
end
return
end
if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
reason = reason:match('^[Ff][Oo][Rr] (.-)$')
end
if tonumber(user) == nil and not user:match('^%@') then
user = '@' .. user
end
local user_object = mattata.get_user(user) or mattata.get_chat(user) -- resolve the username/ID to a user object
if not user_object then
local output = language['errors']['unknown']
return mattata.send_reply(message, output)
elseif user_object.result.id == self.info.id then
return false -- don't let the bot Fed-ban itself
end
user_object = user_object.result
local status = mattata.get_chat_member(message.chat.id, user_object.id)
local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
if not status then
local output = language['errors']['generic']
return mattata.send_reply(message, output)
elseif is_admin then -- we won't try and Fed-ban moderators and administrators.
local output = 'I can\'t unban that user from the Fed because they\'re an admin in one of the groups!'
return mattata.send_reply(message, output)
end
local success = mattata.fed_unban_chat_member(message.chat.id, user_object.id, is_admin_feds) -- attempt to Fed-ban the user from the group
if not success then
mattata.send_reply(message, 'I couldn\'t unban that user in this group, because it appears I don\'t have permission to! I have still removed them from the Fed-ban list(s) though!')
end
for _, fed in pairs(is_admin_feds) do
mattata.increase_administrative_action(message.chat.id, user_object.id, 'unfbans')
redis:hdel('fedban:' .. fed .. ':' .. user_object.id, 'banned_by')
redis:hdel('fedban:' .. fed .. ':' .. user_object.id, 'time')
redis:hdel('fedban:' .. fed .. ':' .. user_object.id, 'reason')
redis:srem('fedbans:' ..fed, tonumber(user_object.id))
end
reason = reason and ', for ' .. reason or ''
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local unbanned_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local output = '%s <code>[%s]</code> has Fed-unbanned %s <code>[%s]</code> from %s <code>[%s]</code>%s.\n%s %s'
if #is_admin_feds > 1 then
output = '%s <code>[%s]</code> has Fed-unbanned %s <code>[%s]</code> from %s in the following Feds:<pre>%s</pre>\n%s %s'
output = string.format(output, admin_username, message.from.id, unbanned_username, user_object.id, mattata.escape_html(message.chat.title), table.concat(is_admin_feds, '\n'), '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
else
output = string.format(output, admin_username, message.from.id, unbanned_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user_object.id)
end
mattata.send_message(log_chat, output, 'html')
else
local output = '%s has Fed-unbanned %s%s.'
if #is_admin_feds > 1 then
output = '%s has Fed-unbanned %s%s; in the following Feds:<pre>%s</pre>'
output = string.format(output, admin_username, unbanned_username, reason, table.concat(is_admin_feds, '\n'))
else
output = string.format(output, admin_username, unbanned_username, reason)
end
mattata.send_message(message.chat.id, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
end
return
end
return unfban
\ No newline at end of file
diff --git a/plugins/administration/unfilter.mattata b/plugins/administration/unfilter.mattata
index 02f0c75..b3eba8f 100644
--- a/plugins/administration/unfilter.mattata
+++ b/plugins/administration/unfilter.mattata
@@ -1,79 +1,79 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local unfilter = {}
local mattata = require('mattata')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function unfilter:init()
unfilter.commands = mattata.commands(self.info.username):command('unfilter').table
unfilter.help = '/unfilter <words> - Remove words from this chat\'s word filter.'
end
function unfilter:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = mattata.input(message.text)
if not input
or not input:match('%w+')
then
return mattata.send_reply(
message,
unfilter.help
)
end
local words = {}
for word in input:gmatch('%w+')
do
table.insert(
words,
word
)
end
local total = redis:smembers('word_filter:' .. message.chat.id)
local removed = {}
for n, word in pairs(words)
do
if redis:sismember(
'word_filter:' .. message.chat.id,
word
)
then
local success = redis:srem(
'word_filter:' .. message.chat.id,
word
)
if success == 1
then
table.insert(
removed,
word
)
end
end
end
local new_total = #total - #removed
return mattata.send_message(
message.chat.id,
tostring(#removed) .. ' word(s) have been removed from this chat\'s word filter. There is now a total of ' .. tostring(new_total) .. ' word(s) filtered in this chat. Use /filter <words> to add words to this filter.'
)
end
return unfilter
\ No newline at end of file
diff --git a/plugins/administration/unmute.mattata b/plugins/administration/unmute.mattata
index c5785a6..425d818 100644
--- a/plugins/administration/unmute.mattata
+++ b/plugins/administration/unmute.mattata
@@ -1,97 +1,97 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local unmute = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function unmute:init()
unmute.commands = mattata.commands(self.info.username):command('unmute').table
unmute.help = '/unmute [user] - Unmutes a user in the current chat. This command can only be used by group admins.'
end
function unmute:on_message(message, _, language)
if message.chat.type ~= 'supergroup' then
local output = language['errors']['supergroup']
return mattata.send_reply(message, output)
end
local reason = false
local user = false
local input = mattata.input(message)
-- check the message object for any users this command
-- is intended to be executed on
if message.reply then
user = message.reply.from.id
if input then
reason = input
end
elseif input and input:match(' ') then
user, reason = input:match('^(.-) (.-)$')
elseif input then
user = input
end
if not user then
local output = 'You need to specify the user you\'d like to unmute, either by username/ID or in reply.'
local success = mattata.send_force_reply(message, output)
if success then
mattata.set_command_action(message.chat.id, success.result.message_id, '/unmute')
end
return
end
if reason and type(reason) == 'string' and reason:match('^[Ff][Oo][Rr] ') then
reason = reason:match('^[Ff][Oo][Rr] (.-)$')
end
if tonumber(user) == nil and not user:match('^%@') then
user = '@' .. user
end
local user_object = mattata.get_user(user) or mattata.get_chat(user) -- resolve the username/ID to a user object
if not user_object then
local output = language['errors']['unknown']
return mattata.send_reply(message, output)
elseif user_object.result.id == self.info.id then
return false -- we don't want to use this on ourselves
end
local bot_status = mattata.get_chat_member(message.chat.id, self.info.id)
if not bot_status then
return false
elseif not bot_status.result.can_restrict_members then
return mattata.send_reply(message, 'It appears I don\'t have the required permissions required in order to unmute that user. Please amend this and try again!')
end
user_object = user_object.result
local status = mattata.get_chat_member(message.chat.id, user_object.id)
local is_admin = mattata.is_group_admin(message.chat.id, user_object.id)
if not status then
return mattata.send_reply(message, 'I couldn\'t retrieve any information about that user!')
elseif is_admin then -- we won't try and unmute moderators and administrators.
return mattata.send_reply(message, 'I can\'t unmute that user because they\'re an admin in this chat!')
end
local default_permissions = mattata.get_chat(message.chat.id)
if not default_permissions then
return mattata.send_reply(message, 'I couldn\'t get the default permissions for this group!')
end
default_permissions = default_permissions.result.permissions
local success = mattata.restrict_chat_member(message.chat.id, user_object.id, os.time(), default_permissions) -- attempt to unmute the user in the group, restoring the user to the original group permissions
if not success then
return mattata.send_reply(message, 'I couldn\'t unmute that user in this group, because it appears I don\'t have permission to!')
end
reason = reason and ', for ' .. reason or ''
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local unmuted_username = mattata.get_formatted_user(user_object.id, user_object.first_name, 'html')
redis:hincrby('chat:' .. message.chat.id .. ':' .. user_object.id, 'unmutes', 1)
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local output = '%s <code>[%s]</code> has unmuted %s <code>[%s]</code> in %s <code>[%s]</code>%s.'
output = string.format(output, admin_username, message.from.id, unmuted_username, user_object.id, mattata.escape_html(message.chat.title), message.chat.id, reason)
mattata.send_message(log_chat, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
end
local output = '%s has unmuted %s%s.'
output = string.format(output, admin_username, unmuted_username, reason)
return mattata.send_message(message.chat.id, output, 'html')
end
return unmute
\ No newline at end of file
diff --git a/plugins/administration/untrust.mattata b/plugins/administration/untrust.mattata
index 65cd839..6da66c4 100644
--- a/plugins/administration/untrust.mattata
+++ b/plugins/administration/untrust.mattata
@@ -1,160 +1,160 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local untrust = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function untrust:init()
untrust.commands = mattata.commands(self.info.username):command('untrust').table
untrust.help = '/untrust [user] - Untrusts a user to a standard user of the current chat. This command can only be used by administrators of a supergroup.'
end
function untrust:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id,
true
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local input = message.reply
and tostring(message.reply.from.id)
or mattata.input(message)
if not input
then
local success = mattata.send_force_reply(
message,
language['untrust']['1']
)
if success
then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/untrust'
)
end
return
elseif tonumber(input) == nil
and not input:match('^%@')
then
input = '@' .. input
end
local user = mattata.get_user(input)
or mattata.get_chat(input) -- Resolve the username/ID to a user object.
if not user
then
return mattata.send_reply(
message,
language['errors']['unknown']
)
elseif user.result.id == self.info.id
then
return
end
user = user.result
local status = mattata.get_chat_member(
message.chat.id,
user.id
)
if not status
then
return mattata.send_reply(
message,
language['errors']['generic']
)
elseif mattata.is_group_admin(
message.chat.id,
user.id
)
then -- We won't try and untrust users who are moderators/administrators.
return mattata.send_reply(
message,
language['untrust']['2']
)
elseif status.result.status == 'left'
or status.result.status == 'kicked'
then -- Check if the user is in the group or not.
return mattata.send_reply(
message,
string.format(
status.result.status == 'left'
and language['untrust']['3']
or language['untrust']['4']
)
)
end
redis:srem(
'administration:' .. message.chat.id .. ':trusted',
user.id
)
if redis:hget(
string.format(
'chat:%s:settings',
message.chat.id
),
'log administrative actions'
)
then
mattata.send_message(
mattata.get_log_chat(message.chat.id),
string.format(
'<pre>%s%s [%s] has untrusted %s%s [%s] in %s%s [%s].</pre>',
message.from.username
and '@'
or '',
message.from.username
or mattata.escape_html(message.from.first_name),
message.from.id,
user.username
and '@'
or '',
user.username
or mattata.escape_html(user.first_name),
user.id,
message.chat.username
and '@'
or '',
message.chat.username
or mattata.escape_html(message.chat.title),
message.chat.id
),
'html'
)
end
return mattata.send_message(
message.chat.id,
string.format(
'<pre>%s%s has untrusted %s%s.</pre>',
message.from.username
and '@'
or '',
message.from.username
or mattata.escape_html(message.from.first_name),
user.username
and '@'
or '',
user.username
or mattata.escape_html(user.first_name)
),
'html'
)
end
return untrust
\ No newline at end of file
diff --git a/plugins/administration/voteban.mattata b/plugins/administration/voteban.mattata
index a52ae77..927d40b 100644
--- a/plugins/administration/voteban.mattata
+++ b/plugins/administration/voteban.mattata
@@ -1,411 +1,411 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local voteban = {}
local mattata = require('mattata')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function voteban:init()
voteban.commands = mattata.commands(self.info.username):command('voteban').table
voteban.help = '/voteban [user] - Opens up a vote to decide if a user should be banned from the current chat. This command can only be used by moderators and administrators of a supergroup.'
end
function voteban:on_callback_query(callback_query, message, configuration, language)
if not callback_query.data:match('^%-%d+:%d+:[yn]$')
or not message
then
return mattata.answer_callback_query(
callback_query.id,
language['errors']['generic']
)
end
local chat_id, user_id, vote = callback_query.data:match('^(%-%d+):(%d+):([yn])$')
local current_upvote = tonumber(
redis:hget(
'voteban:' .. chat_id .. ':' .. user_id,
'y'
)
)
local current_downvote = tonumber(
redis:hget(
'voteban:' .. chat_id .. ':' .. user_id,
'n'
)
)
local user_object = json.decode(
redis:hget(
'voteban:' .. chat_id .. ':' .. user_id,
'user_object'
)
)
local required_upvotes = tonumber(
redis:hget(
'chat:' .. chat_id .. ':settings',
'required upvotes for vote bans'
)
)
or configuration.administration.voteban.upvotes.default
local required_downvotes = tonumber(
redis:hget(
'chat:' .. chat_id .. ':settings',
'required downvotes for vote bans'
)
)
or configuration.administration.voteban.downvotes.default
if redis:hget(
'voteban:' .. chat_id .. ':' .. user_id,
callback_query.from.id
)
then
local current_vote = redis:hget(
'voteban:' .. chat_id .. ':' .. user_id,
callback_query.from.id
)
if current_vote == 'y'
then
current_upvote = current_upvote - 1
else
current_downvote = current_downvote - 1
end
redis:hdel(
'voteban:' .. chat_id .. ':' .. user_id,
callback_query.from.id
)
redis:hincrby(
'voteban:' .. chat_id .. ':' .. user_id,
current_vote,
-1
)
mattata.answer_callback_query(
callback_query.id,
language['voteban']['11']
)
elseif vote == 'y'
then
current_upvote = current_upvote + 1
redis:hset(
'voteban:' .. chat_id .. ':' .. user_id,
callback_query.from.id,
'y'
)
if current_upvote >= required_upvotes
then
redis:hdel(
'voteban:' .. chat_id .. ':' .. user_id,
'y'
)
redis:hdel(
'voteban:' .. chat_id .. ':' .. user_id,
'n'
)
redis:hdel(
'voteban:' .. chat_id .. ':' .. user_id,
'user_object'
)
local success = mattata.ban_chat_member(
chat_id,
user_id
)
local output = string.format(
language['voteban']['7'],
user_object.first_name,
user_object.id,
message.chat.title,
current_upvote
)
if not success
then -- If the ban failed, then we're going to need an error message, rather than
-- a message suggesting the ban was a success!
output = string.format(
language['voteban']['8'],
user_object.first_name
)
else
redis:hdel(
'voteban:' .. chat_id .. ':' .. user_id,
'user_object'
)
redis:hdel(
'voteban:' .. chat_id .. ':' .. user_id,
'y'
)
redis:hdel(
'voteban:' .. chat_id .. ':' .. user_id,
'n'
)
end
return mattata.edit_message_text(
chat_id,
message.message_id,
output
)
end
redis:hincrby(
'voteban:' .. chat_id .. ':' .. user_id,
'y',
1
)
mattata.answer_callback_query(
callback_query.id,
string.format(
language['voteban']['10'],
user_object.first_name,
user_object.id
)
)
else
redis:hset(
'voteban:' .. chat_id .. ':' .. user_id,
callback_query.from.id,
'n'
)
current_downvote = current_downvote + 1
if current_downvote >= required_downvotes
then
redis:hdel(
'voteban:' .. chat_id .. ':' .. user_id,
'y'
)
redis:hdel(
'voteban:' .. chat_id .. ':' .. user_id,
'n'
)
redis:hdel(
'voteban:' .. chat_id .. ':' .. user_id,
'user_object'
)
return mattata.edit_message_text(
chat_id,
message.message_id,
string.format(
language['voteban']['9'],
user_object.first_name,
user_object.id,
message.chat.title,
current_downvote
)
)
end
redis:hincrby(
'voteban:' .. chat_id .. ':' .. user_id,
'n',
1
)
mattata.answer_callback_query(
callback_query.id,
string.format(
language['voteban']['12'],
user_object.first_name,
user_object.id
)
)
end
return mattata.edit_message_reply_markup(
chat_id,
message.message_id,
nil,
mattata.inline_keyboard():row(
mattata.row()
:callback_data_button(
string.format(
language['voteban']['5'],
tostring(current_upvote)
),
'voteban:' .. message.chat.id .. ':' .. user_object.id .. ':y'
)
:callback_data_button(
string.format(
language['voteban']['6'],
tostring(current_downvote)
),
'voteban:' .. message.chat.id .. ':' .. user_object.id .. ':n'
)
)
)
end
function voteban:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local reason = false
local user = false
local input = mattata.input(message)
-- Check the message object for any users this command
-- is intended to be executed on.
if message.reply
and not input
then
user = message.reply.from.id
elseif message.reply
and not input:match(' ')
then
user = input
elseif message.reply
then
user, reason = input:match('^(.-) (.-)$')
elseif input
and not input:match(' ')
then
user = input
elseif input
then
user, reason = input:match('^(.-) (.-)$')
end
if not user
then
local success = mattata.send_force_reply(
message,
language['voteban']['1']
)
if success
then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/voteban'
)
end
return
end
if reason
and type(reason) == 'string'
and reason:match('^[Ff][Oo][Rr] ')
then
reason = reason:match('^[Ff][Oo][Rr] (.-)$')
end
if tonumber(user) == nil
and not user:match('^%@')
then
user = '@' .. user
end
local user_object = mattata.get_user(user)
or mattata.get_chat(user) -- Resolve the username/ID to a user object.
if not user_object
then
return mattata.send_reply(
message,
language['errors']['unknown']
)
elseif user_object.result.id == self.info.id
then
return
end
user_object = user_object.result
local status = mattata.get_chat_member(
message.chat.id,
user_object.id
)
if not status
then
return mattata.send_reply(
message,
language['errors']['generic']
)
elseif mattata.is_group_admin(
message.chat.id,
user_object.id
)
or status.result.status == 'creator'
or status.result.status == 'administrator'
then -- We won't try and open up votes to ban moderators and administrators.
return mattata.send_reply(
message,
language['voteban']['2']
)
elseif status.result.status == 'left'
or status.result.status == 'kicked'
then -- Check if the user is in the group or not.
return mattata.send_reply(
message,
language['voteban']['3']
)
elseif redis:hexists(
'voteban:' .. message.chat.id .. ':' .. user_object.id,
'user_object'
)
then
return mattata.send_reply(
message,
language['voteban']['13']
)
end
redis:hset(
'voteban:' .. message.chat.id .. ':' .. user_object.id,
'user_object',
json.encode(user_object)
)
redis:hset(
'voteban:' .. message.chat.id .. ':' .. user_object.id,
'y',
0
)
redis:hset(
'voteban:' .. message.chat.id .. ':' .. user_object.id,
'n',
0
)
return mattata.send_message(
message.chat.id,
string.format(
language['voteban']['4'],
user_object.username
and '@' .. user_object.username
or user_object.first_name,
user_object.id,
message.chat.title,
redis:hget(
'chat:' .. message.chat.id .. ':settings',
'required upvotes for vote bans'
)
or '5',
redis:hget(
'chat:' .. message.chat.id .. ':settings',
'required downvotes for vote bans'
)
or '5'
),
nil,
true,
false,
nil,
mattata.inline_keyboard():row(
mattata.row()
:callback_data_button(
string.format(
language['voteban']['5'],
'0'
),
'voteban:' .. message.chat.id .. ':' .. user_object.id .. ':y'
)
:callback_data_button(
string.format(
language['voteban']['6'],
'0'
),
'voteban:' .. message.chat.id .. ':' .. user_object.id .. ':n'
)
)
)
end
return voteban
\ No newline at end of file
diff --git a/plugins/administration/warn.mattata b/plugins/administration/warn.mattata
index 6cc5ac2..a8ccca1 100644
--- a/plugins/administration/warn.mattata
+++ b/plugins/administration/warn.mattata
@@ -1,270 +1,270 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local warn = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function warn:init()
warn.commands = mattata.commands(self.info.username):command('warn').table
warn.help = '/warn [user] - Warns a user in the current chat. This command can only be used by moderators and administrators of a supergroup. Once a user has reached the maximum allowed number of warnings allowed in the chat, the configured action for the chat is performed on them.'
end
function warn.on_callback_query(_, callback_query, message, configuration)
if not callback_query
or not callback_query.data
or not callback_query.data:match('^%a+%:%-%d+%:%d+$')
then
return
elseif not mattata.is_group_admin(
callback_query.data:match('^%a+%:(%-%d+)%:%d+$'),
callback_query.from.id
)
then
return mattata.answer_callback_query(
callback_query.id,
configuration.errors.admin
)
elseif callback_query.data:match('^reset%:%-%d+%:%d+$')
then
local chat_id, user_id = callback_query.data:match('^reset%:(%-%d+)%:(%d+)$')
redis:hdel(
string.format(
'chat:%s:%s',
chat_id,
user_id
),
'warnings'
)
return mattata.edit_message_text(
message.chat.id,
message.message_id,
string.format(
'<pre>Warnings reset by %s%s!</pre>',
callback_query.from.username
and '@'
or '',
callback_query.from.username
or mattata.escape_html(callback_query.from.first_name)
),
'html'
)
elseif callback_query.data:match('^remove%:%-%d+%:%d+$')
then
local chat_id, user_id = callback_query.data:match('^remove%:(%-%d+)%:(%d+)$')
local amount = redis:hincrby(
string.format(
'chat:%s:%s',
chat_id,
user_id
),
'warnings',
-1
)
if tonumber(amount) < 0
then
redis:hincrby(
string.format(
'chat:%s:%s',
chat_id,
user_id
),
'warnings',
1
)
return mattata.answer_callback_query(
callback_query.id,
'This user hasn\'t got any warnings to be removed!'
)
end
return mattata.edit_message_text(
message.chat.id,
message.message_id,
string.format(
'<pre>Warning removed by %s%s! [%s/%s]</pre>',
callback_query.from.username
and '@'
or '',
callback_query.from.username
or mattata.escape_html(callback_query.from.first_name),
redis:hget(
string.format(
'chat:%s:%s',
chat_id,
user_id
),
'warnings'
),
redis:hget(
string.format(
'chat:%s:settings',
chat_id
),
'max warnings'
)
or 3
),
'html'
)
end
end
function warn:on_message(message, _, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local reason = false
local input = message.reply
and tostring(message.reply.from.id)
or mattata.input(message)
if not input
then
return mattata.send_reply(
message,
warn.help
)
elseif not message.reply
and input:match('^%@?%w+ ')
then
input, reason = input:match('^(%@?%w+) (.-)$')
elseif mattata.input(message.text)
then
reason = mattata.input(message.text)
end
if tonumber(input) == nil
and not input:match('^%@')
then
input = '@' .. input
end
local user = mattata.get_user(input)
or mattata.get_chat(input) -- Resolve the username/ID to a user object.
if not user
then
return mattata.send_reply(
message,
language['errors']['unknown']
)
elseif user.result.id == self.info.id
then
return
end
user = user.result
local status = mattata.get_chat_member(
message.chat.id,
user.id
)
if not status
then
return mattata.send_reply(
message,
language['errors']['generic']
)
elseif mattata.is_group_admin(
message.chat.id,
user.id
) or status.result.status == 'creator'
or status.result.status == 'administrator'
then -- We won't try and warn moderators and administrators.
return mattata.send_reply(
message,
'I cannot warn this user because they are a moderator or an administrator in this chat.'
)
elseif status.result.status == 'left'
or status.result.status == 'kicked'
then -- Check if the user is in the group or not.
return mattata.send_reply(
message,
string.format(
'I cannot warn this user because they have already %s this chat.',
(
status.result.status == 'left'
and 'left'
)
or 'been kicked from'
)
)
end
local amount = redis:hincrby(
string.format(
'chat:%s:%s',
message.chat.id,
user.id
),
'warnings',
1
)
local maximum = redis:hget(
string.format(
'chat:%s:settings',
message.chat.id
),
'max warnings'
)
or 3
if tonumber(amount) >= tonumber(maximum)
then
local success = mattata.ban_chat_member(
message.chat.id,
user.id
)
if not success
then -- Since we've ruled everything else out, it's safe to say if it wasn't a
-- success then the bot isn't an administrator in the group.
return mattata.send_reply(
message,
'I need to have administrative permissions in order to ban this user. Please amend this issue, and try again.'
)
end
end
mattata.increase_administrative_action(message.chat.id, user.id, 'warns')
reason = reason and ', for ' .. reason or ''
local admin_username = mattata.get_formatted_user(message.from.id, message.from.first_name, 'html')
local warned_username = mattata.get_formatted_user(user.id, user.first_name, 'html')
if mattata.get_setting(message.chat.id, 'log administrative actions') then
local log_chat = mattata.get_log_chat(message.chat.id)
local output = '%s <code>[%s]</code> has warned %s <code>[%s]</code> in %s <code>[%s]</code>%s.\n%s %s'
output = string.format(output, admin_username, message.from.id, warned_username, user.id, mattata.escape_html(message.chat.title), message.chat.id, reason, '#chat' .. tostring(message.chat.id):gsub('^-100', ''), '#user' .. user.id)
mattata.send_message(log_chat, output, 'html')
end
if message.reply and mattata.get_setting(message.chat.id, 'delete reply on action') then
mattata.delete_message(message.chat.id, message.reply.message_id)
mattata.delete_message(message.chat.id, message.message_id)
end
local output = '%s has warned %s%s.'
output = string.format(output, admin_username, warned_username, reason)
local keyboard = mattata.inline_keyboard():row(
mattata.row():callback_data_button(
'Reset Warnings',
string.format(
'warn:reset:%s:%s',
message.chat.id,
user.id
)
):callback_data_button(
'Remove 1 Warning',
string.format(
'warn:remove:%s:%s',
message.chat.id,
user.id
)
)
)
return mattata.send_message(message.chat.id, output, 'html', true, false, nil, keyboard)
end
return warn
\ No newline at end of file
diff --git a/plugins/administration/whitelist.mattata b/plugins/administration/whitelist.mattata
index 1f2ab9b..4b20c7b 100644
--- a/plugins/administration/whitelist.mattata
+++ b/plugins/administration/whitelist.mattata
@@ -1,167 +1,167 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local whitelist = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function whitelist:init()
whitelist.commands = mattata.commands(self.info.username):command('whitelist').table
whitelist.help = '/whitelist [user] - Whitelists a user to use the bot in the current chat. This command can only be used by moderators and administrators of a supergroup.'
end
function whitelist:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local reason = false
local input = message.reply
and (
message.reply.from.username
or tostring(message.reply.from.id)
)
or mattata.input(message.text)
if not input
then
local success = mattata.send_force_reply(
message,
language['whitelist']['1']
)
if success
then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/whitelist'
)
end
return
elseif not message.reply
then
if input:match('^.- .-$')
then
reason = input:match(' (.-)$')
input = input:match('^(.-) ')
end
elseif mattata.input(message.text)
then
reason = mattata.input(message.text)
end
if tonumber(input) == nil
and not input:match('^%@')
then
input = '@' .. input
end
local user = mattata.get_user(input)
or mattata.get_chat(input) -- Resolve the username/ID to a user object.
if not user
then
return mattata.send_reply(
message,
language['errors']['unknown']
)
elseif user.result.id == self.info.id
then
return
end
user = user.result
local status = mattata.get_chat_member(
message.chat.id,
user.id
)
if not status
then
return mattata.send_reply(
message,
language['errors']['generic']
)
elseif mattata.is_group_admin(
message.chat.id,
user.id
)
or status.result.status == 'creator'
or status.result.status == 'administrator'
then -- We won't try and whitelist moderators and administrators.
return mattata.send_reply(
message,
language['whitelist']['2']
)
elseif status.result.status == 'left'
or status.result.status == 'kicked'
then -- Check if the user is in the group or not.
return mattata.send_reply(
message,
status.result.status == 'left'
and language['whitelist']['3']
or language['whitelist']['4']
)
end
redis:del('group_whitelist:' .. message.chat.id .. ':' .. user.id)
redis:hincrby(
string.format(
'chat:%s:%s',
message.chat.id,
user.id
),
'whitelists',
1
)
if redis:hget(
string.format(
'chat:%s:settings',
message.chat.id
),
'log administrative actions'
) then
mattata.send_message(
mattata.get_log_chat(message.chat.id),
string.format(
'<pre>%s%s [%s] has whitelisted %s%s [%s] in %s%s [%s]%s.</pre>',
message.from.username and '@' or '',
message.from.username or mattata.escape_html(message.from.first_name),
message.from.id,
user.username and '@' or '',
user.username or mattata.escape_html(user.first_name),
user.id,
message.chat.username and '@' or '',
message.chat.username or mattata.escape_html(message.chat.title),
message.chat.id,
reason and ', for ' .. reason or ''
),
'html'
)
end
mattata.unban_chat_member(message.chat.id, user.id) -- attempt to unban the user too
return mattata.send_message(
message.chat.id,
string.format(
'<pre>%s%s has whitelisted %s%s%s.</pre>',
message.from.username and '@' or '',
message.from.username or mattata.escape_html(message.from.first_name),
user.username and '@' or '',
user.username or mattata.escape_html(user.first_name),
reason and ', for ' .. reason or ''
),
'html'
)
end
return whitelist
\ No newline at end of file
diff --git a/plugins/administration/whitelistbot.mattata b/plugins/administration/whitelistbot.mattata
index a90e252..7877cf7 100644
--- a/plugins/administration/whitelistbot.mattata
+++ b/plugins/administration/whitelistbot.mattata
@@ -1,53 +1,53 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local whitelistbot = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function whitelistbot:init()
whitelistbot.commands = mattata.commands(self.info.username):command('whitelistbot'):command('whitelistbots'):command('wb').table
whitelistbot.help = '/whitelistbot <bots> - Whitelists the given bots in the current chat. Requires administrative privileges. Aliases: /whitelistbots, /wb.'
whitelistbot.example_bots = { 'gif', 'imdb', 'wiki', 'music', 'youtube', 'bold', 'sticker', 'vote', 'like', 'gamee', 'coub', 'pic', 'vid', 'bing' }
end
function whitelistbot:on_new_message(message, configuration, language)
if message.chat.type ~= 'supergroup' then
return false
elseif mattata.get_setting(message.chat.id, 'prevent inline bots') and message.via_bot and not mattata.is_group_admin(message.chat.id, message.from.id) then
return mattata.delete_message(message.chat.id, message.message_id)
end
end
function whitelistbot:on_message(message, configuration, language)
if not mattata.is_group_admin(message.chat.id, message.from.id) then
return mattata.send_reply(message, language.errors.admin)
end
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, 'Please specify the @usernames of the bots you\'d like to whitelist.')
elseif not input:match('@?[%w_]') then
return mattata.send_reply(message, 'Please make sure you\'re specifying valid bot usernames!')
end
local bots = {}
for bot in input:gmatch('@?([%w_]+bot)') do
table.insert(bots, bot)
end
for _, bot in pairs(whitelistbot.example_bots) do
if input:match('@?' .. bot) then
table.insert(bots, bot)
end
end
if #bots == 0 then
return mattata.send_reply(message, 'Please make sure you\'re specifying valid bot usernames!')
end
for _, bot in pairs(bots) do
redis:sadd('whitelisted_bots:' .. message.chat.id, bot)
end
local output = string.format('Successfully whitelisted the following bots in this chat: %s', table.concat(bots, ', '))
return mattata.send_reply(message, output)
end
return whitelistbot
\ No newline at end of file
diff --git a/plugins/administration/whitelistlink.mattata b/plugins/administration/whitelistlink.mattata
index 8016997..28ab1e0 100644
--- a/plugins/administration/whitelistlink.mattata
+++ b/plugins/administration/whitelistlink.mattata
@@ -1,30 +1,30 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local whitelistlink = {}
local mattata = require('mattata')
function whitelistlink:init()
whitelistlink.commands = mattata.commands(self.info.username):command('whitelistlink'):command('wl').table
whitelistlink.help = '/whitelistlink <links> - Whitelists the given links in the current chat. Requires administrative privileges. Use /whitelistlink -del <links> to Alias: /wl.'
end
function whitelistlink:on_message(message)
if not mattata.is_group_admin(message.chat.id, message.from.id) then
return false
end
local input = mattata.input(message.text)
local delete = false
if not input then
return mattata.send_reply(message, 'Please specify the URLs or @usernames you\'d like to whitelist.')
elseif input:match('^%-del .-$') then
input = input:match('^%-del (.-)$')
delete = true
end
local output = mattata.check_links(message, false, false, true, false, delete)
return mattata.send_reply(message, output)
end
return whitelistlink
\ No newline at end of file
diff --git a/plugins/administration/wordfilter.mattata b/plugins/administration/wordfilter.mattata
index eeb5548..4c5b829 100644
--- a/plugins/administration/wordfilter.mattata
+++ b/plugins/administration/wordfilter.mattata
@@ -1,46 +1,46 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local wordfilter = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function wordfilter:init()
wordfilter.commands = mattata.commands(self.info.username):command('wordfilter').table
wordfilter.help = '/wordfilter - View a list of words which have been added to the chat\'s word filter.'
end
function wordfilter:on_message(message, configuration, language)
if message.chat.type ~= 'supergroup'
then
return mattata.send_reply(
message,
language['errors']['supergroup']
)
elseif not mattata.is_group_admin(
message.chat.id,
message.from.id
)
then
return mattata.send_reply(
message,
language['errors']['admin']
)
end
local words = redis:smembers('word_filter:' .. message.chat.id)
if #words < 1
then
return mattata.send_reply(
message,
'There are no words filtered in this chat. To add words to the filter, use /filter <word(s)>.'
)
end
return mattata.send_message(
message.chat.id,
'Filtered words: ' .. table.concat(words, ', ')
)
end
return wordfilter
\ No newline at end of file
diff --git a/plugins/afk.mattata b/plugins/afk.mattata
index 80b4d67..c520ae3 100644
--- a/plugins/afk.mattata
+++ b/plugins/afk.mattata
@@ -1,49 +1,49 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local afk = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function afk:init()
afk.commands = mattata.commands(self.info.username):command('afk').table
afk.help = '/afk [note] - Mark yourself as away from keyboard, with an optional note that will be displayed to users who mention you whilst you\'re away. You must have an @username for this feature to work.'
end
function afk.on_message(_, message, _, language)
if not message.from.username then
return mattata.send_reply(message, language['afk']['1']) -- Since this feature relies on detecting username
-- mentions, this feature is currently only available to users who have a public @username.
elseif redis:hget('afk:' .. message.from.id, 'since') then -- Check if the user is
-- already marked as AFK.
local since = redis:hget('afk:' .. message.from.id, 'since')
-- Un-mark the user as AFK in the database.
redis:hdel('afk:' .. message.from.id, 'since')
redis:hdel('afk:' .. message.from.id, 'note')
local keys = redis:keys('afk:' .. message.from.id .. ':replied:*')
if #keys > 0 then
for _, key in pairs(keys) do
redis:del(key)
end
end
local time = mattata.format_time(os.time() - tonumber(since))
local output = string.format(language['afk']['2'], message.from.first_name, time)
output = output:gsub('AFK', '/AFK') -- temporary solution until i update language strings
mattata.delete_message(message.chat.id, message.message_id) -- attempt to delete their message to reduce chat clutter
return mattata.send_message(message.chat.id, output) -- Inform the chat of the user's return, and include the
-- time they spent marked as AFK.
end
local input = mattata.input(message.text) and '\n' .. language['afk']['3'] .. ': ' .. mattata.input(message.text) or ''
redis:hset('afk:' .. message.from.id, 'since', os.time())
redis:hset('afk:' .. message.from.id, 'note', input)
local output = string.format(language['afk']['4'], message.from.first_name, input)
local success = mattata.send_message(message.chat.id, output)
if success then -- if the afk message sent, we'll attempt to delete their original message to clear up the chat a bit
return mattata.delete_message(message.chat.id, message.message_id)
end
return false
end
return afk
\ No newline at end of file
diff --git a/plugins/appstore.mattata b/plugins/appstore.mattata
index fee7b1f..1f3cbb9 100644
--- a/plugins/appstore.mattata
+++ b/plugins/appstore.mattata
@@ -1,67 +1,67 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local appstore = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
function appstore:init()
appstore.commands = mattata.commands(self.info.username):command('appstore'):command('app'):command('as').table
appstore.help = '/appstore <query> - Displays information about the first app returned by iTunes for the given search query. Aliases: /app, /as.'
appstore.url = 'https://itunes.apple.com/search?lang=en&entity=software&term='
end
function appstore.get_app_info(jdat, language)
local categories = {}
for n in pairs(jdat.results[1].genres) do
table.insert(categories, jdat.results[1].genres[n])
end
local rating = tonumber(jdat.results[1].userRatingCount)
if rating ~= nil then
if rating == 1 then
rating = string.format('%s 1 %s', utf8.char(11088), language['appstore']['2'])
elseif rating > 0 then
rating = string.format('%s %s %s (%s)', utf8.char(11088), mattata.comma_value(tostring(rating)), language['appstore']['3'], jdat.results[1].averageUserRating)
else
rating = string.format('%s %s %s', utf8.char(11088), mattata.comma_value(tostring(rating)), language['appstore']['3'])
end
else rating = 'N/A' end
if jdat.results[1].description:len() > 250 then
jdat.results[1].description = jdat.results[1].description:sub(1, 250) .. '...'
end
return string.format(
'<b>%s</b> - v%s, %s/%s/%s\n\n<i>%s</i>\n\n%s\n%s <b>|</b> iOS %s+',
mattata.escape_html(jdat.results[1].trackName),
jdat.results[1].version,
jdat.results[1].currentVersionReleaseDate:sub(9, 10),
jdat.results[1].currentVersionReleaseDate:sub(6, 7),
jdat.results[1].currentVersionReleaseDate:sub(1, 4),
mattata.escape_html(jdat.results[1].description),
table.concat(categories, ' <b>|</b> '), rating,
jdat.results[1].minimumOsVersion
)
end
function appstore.on_message(_, message, _, language)
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, appstore.help)
end
local jstr, res = https.request(appstore.url .. url.escape(input))
if res ~= 200 then
return mattata.send_reply(message, language.errors.connection)
end
local jdat = json.decode(jstr)
if jdat.resultCount == 0 then
return mattata.send_reply(message, language.errors.results)
end
local keyboard = mattata.inline_keyboard():row(mattata.row():url_button(language['appstore']['1'], jdat.results[1].trackViewUrl))
local output = appstore.get_app_info(jdat, language)
return mattata.send_message(message.chat.id, output, 'html', true, false, nil, keyboard)
end
return appstore
\ No newline at end of file
diff --git a/plugins/authspotify.mattata b/plugins/authspotify.mattata
index 8d1762a..e14aaa7 100644
--- a/plugins/authspotify.mattata
+++ b/plugins/authspotify.mattata
@@ -1,54 +1,54 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local authspotify = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local ltn12 = require('ltn12')
local redis = dofile('libs/redis.lua')
function authspotify:init(configuration)
authspotify.commands = mattata.commands(self.info.username):command('authspotify').table
authspotify.help = '/authspotify <token> - Authorises your Spotify account for use with mattata.'
authspotify.redirect_uri = configuration.keys.spotify.redirect_uri
authspotify.client_id = configuration.keys.spotify.client_id
authspotify.client_secret = configuration.keys.spotify.client_secret
end
function authspotify.on_message(_, message, _, language)
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, authspotify.help)
elseif redis:get('spotify:' .. message.from.id .. ':access_token') then
return mattata.send_reply(message, language['authspotify']['1'])
end
input = input:match('[%?&]code=(.-)$') or input
local query = string.format('grant_type=authorization_code&code=%s&redirect_uri=%s&client_id=%s&client_secret=%s', url.escape(input), url.escape(authspotify.redirect_uri), authspotify.client_id, authspotify.client_secret)
local wait_message = mattata.send_message(message.chat.id, language['authspotify']['2'])
local response = {}
local _, res = https.request({
['url'] = 'https://accounts.spotify.com/api/token',
['method'] = 'POST',
['headers'] = {
['Content-Type'] = 'application/x-www-form-urlencoded',
['Content-Length'] = query:len()
},
['source'] = ltn12.source.string(query),
['sink'] = ltn12.sink.table(response)
})
local jdat = json.decode(table.concat(response))
if res ~= 200 or not jdat or jdat.error then
local output = string.format('%s `%s?code=...`', language['authspotify']['3'], authspotify.redirect_uri)
return mattata.edit_message_text(message.chat.id, wait_message.result.message_id, output, true)
end
redis:set('spotify:' .. message.from.id .. ':access_token', jdat.access_token)
redis:expire('spotify:' .. message.from.id .. ':access_token', 3600)
redis:set('spotify:' .. message.from.id .. ':refresh_token', jdat.refresh_token)
return mattata.edit_message_text(message.chat.id, wait_message.result.message_id, language['authspotify']['4'])
end
return authspotify
\ No newline at end of file
diff --git a/plugins/avatar.mattata b/plugins/avatar.mattata
index 9052c7a..d17a2aa 100644
--- a/plugins/avatar.mattata
+++ b/plugins/avatar.mattata
@@ -1,97 +1,97 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local avatar = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function avatar:init()
avatar.commands = mattata.commands(self.info.username):command('avatar'):command('profilepic'):command('pic').table
avatar.help = '/avatar <user> [offset] - Sends the profile photos of the given user, of which can be specified by username or numerical ID. If an offset is given after the username (which must be a numerical value), then the nth profile photo is sent (if available).'
end
function avatar:on_inline_query(inline_query, _, language)
local input = mattata.input(inline_query.query)
or inline_query.from.id
local selected_photo = false
if tostring(input):match('^.- %d*$') then
selected_photo = tostring(input):match('^.- (%d*)$')
input = tostring(input):match('^(.-) %d*$')
end
local success = true
local old_input = input
if tonumber(input) == nil then
input = mattata.get_user(input)
if not input then
success = false
else
input = input.result.id
end
end
if success then
success = mattata.get_user_profile_photos(input)
end
if not success then
return mattata.send_inline_article(inline_query.id, language.errors.generic, language['avatar']['1'])
elseif success.result.total_count == 0 or redis:get('user:' .. input .. ':opt_out') then
return false
elseif selected_photo then
if tonumber(selected_photo) < 1 or tonumber(selected_photo) > success.result.total_count then
return false
end
end
local results = {}
local count = 1
local start = tonumber(selected_photo) or 1
local finish = tonumber(selected_photo) or success.result.total_count
for i = start, finish do
table.insert(results, {
['type'] = 'photo',
['id'] = tostring(count),
['photo_file_id'] = success.result.photos[i][#success.result.photos[i]].file_id,
['caption'] = string.format(language['avatar']['5'], old_input, i, success.result.total_count, old_input, self.info.username)
})
count = count + 1
end
return mattata.answer_inline_query(inline_query.id, results)
end
function avatar.on_message(_, message, _, language)
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, avatar.help)
end
local selected_photo = 1
if input:match(' %d*$') then
selected_photo = tonumber(input:match(' (%d*)$'))
input = input:match('^(.-) %d*$')
end
local success = true
local old_input = input
if tonumber(input) == nil then
input = mattata.get_user(input)
if not input then
success = false
else
input = input.result.id
end
end
if success then
success = mattata.get_user_profile_photos(input)
end
if not success then
return mattata.send_reply(message, language['avatar']['1'])
elseif success.result.total_count == 0 or redis:get('user:' .. input .. ':opt_out') then
local output = success.result.total_count == 0 and language['avatar']['2'] or language['avatar']['4']
return mattata.send_reply(message, output)
elseif tonumber(selected_photo) < 1 or tonumber(selected_photo) > success.result.total_count then
return mattata.send_reply(message, language['avatar']['3'])
end
local highest_res = success.result.photos[selected_photo][#success.result.photos[selected_photo]].file_id
local caption = string.format(language['avatar']['6'], old_input, selected_photo, success.result.total_count, old_input)
return mattata.send_photo(message.chat.id, highest_res, caption)
end
return avatar
\ No newline at end of file
diff --git a/plugins/bash.mattata b/plugins/bash.mattata
index 07c13cb..76b832b 100644
--- a/plugins/bash.mattata
+++ b/plugins/bash.mattata
@@ -1,28 +1,28 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local bash = {}
local mattata = require('mattata')
function bash:init()
bash.commands = mattata.commands(self.info.username):command('bash').table
end
function bash.on_message(_, message, _, language)
if not mattata.is_global_admin(message.from.id) then
return false
end
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, language['bash']['1'])
end
local res = io.popen(input)
local output = res:read('*all')
res:close()
output = output:len() == 0 and language['bash']['2'] or string.format('<pre>%s</pre>', mattata.escape_html(output))
return mattata.send_message(message.chat.id, output, 'html')
end
return bash
\ No newline at end of file
diff --git a/plugins/bing.mattata b/plugins/bing.mattata
index b9fdf62..fa63208 100644
--- a/plugins/bing.mattata
+++ b/plugins/bing.mattata
@@ -1,63 +1,63 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local bing = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local ltn12 = require('ltn12')
local json = require('dkjson')
function bing:init(configuration)
assert(configuration.keys.bing, 'bing.lua requires an API key, and you haven\'t got one configured!')
bing.commands = mattata.commands(self.info.username):command('bing').table
bing.help = '/bing <query> - Searches Bing for the given search query and returns the top results.'
bing.key = configuration.keys.bing
end
function bing.on_message(_, message, configuration, language)
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, bing.help)
end
local body = {}
local _, res = https.request({
['url'] = 'https://api.cognitive.microsoft.com/bing/v7.0/search?responseFilter=Webpages&safeSearch=Off&q=' .. url.escape(input),
['headers'] = {
['Ocp-Apim-Subscription-Key'] = bing.key,
['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko'
},
['sink'] = ltn12.sink.table(body),
})
if res ~= 200 then
return mattata.send_reply(message, language.errors.connection)
end
local jdat = json.decode(table.concat(body))
if not jdat.webPages then
return mattata.send_reply(message, language.errors.results)
end
local limit = message.chat.type == 'private' and configuration.limits.bing.private or configuration.limits.bing.public
if limit > #jdat.webPages.value and #jdat.webPages.value or limit == 0 then
return mattata.send_reply(message, language.errors.results)
end
local results = {}
local count = 0
for i = 1, limit do
if jdat.webPages.value[i].snippet:len() > 100 then
jdat.webPages.value[i].snippet = jdat.webPages.value[i].snippet:sub(1, 100) .. '...'
end
if count > limit - 4 then
table.insert(results, string.format('%s <a href="%s">%s</a>', mattata.symbols.bullet, jdat.webPages.value[i].url, mattata.escape_html(jdat.webPages.value[i].name)))
else
table.insert(results, string.format('%s <a href="%s">%s</a> <em>%s</em>', mattata.symbols.bullet, jdat.webPages.value[i].url, mattata.escape_html(jdat.webPages.value[i].name), mattata.escape_html(jdat.webPages.value[i].snippet)))
end
count = count + 1
end
local output = table.concat(results, '\n')
return mattata.send_message(message.chat.id, output, 'html')
end
return bing
\ No newline at end of file
diff --git a/plugins/blacklistchat.mattata b/plugins/blacklistchat.mattata
index 92616ce..8a6ce2c 100644
--- a/plugins/blacklistchat.mattata
+++ b/plugins/blacklistchat.mattata
@@ -1,36 +1,36 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local blacklistchat = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function blacklistchat:init()
blacklistchat.commands = mattata.commands(self.info.username):command('blacklistchat').table
end
function blacklistchat.on_message(_, message, _, language)
if not mattata.is_global_admin(message.from.id) then
return false
end
local input = mattata.input(message.text)
if not input then
return false
end
input = input:match('^@(.-)$') or input
local res = mattata.get_chat(input)
local output
if not res then
output = string.format(language['blacklistchat']['3'], input)
elseif res.result.type == 'private' then
output = string.format(language['blacklistchat']['2'], input)
else
redis.set('blacklisted_chats:' .. input, true)
output = string.format(language['blacklistchat']['1'], input)
end
return mattata.send_reply(message, output)
end
return blacklistchat
\ No newline at end of file
diff --git a/plugins/bugreport.mattata b/plugins/bugreport.mattata
index c77506c..c180c37 100644
--- a/plugins/bugreport.mattata
+++ b/plugins/bugreport.mattata
@@ -1,44 +1,44 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local bugreport = {}
local mattata = require('mattata')
function bugreport:init(configuration)
assert(configuration.bug_reports_chat, 'Please specify a chat ID to send all bug reports to!')
bugreport.commands = mattata.commands(self.info.username):command('bugreport'):command('bug'):command('br').table
bugreport.help = '/bugreport <text> - Reports a bug to the configured developer. Aliases: /bug, /br.'
end
function bugreport:on_new_message(message, configuration)
if mattata.is_global_admin(message.from.id) and message.chat.id == configuration.bug_reports_chat and message.reply and message.reply.forward_from and not message.text:match('^[/!#]') and message.reply.from.id == self.info.id then
mattata.send_message(
message.reply.forward_from.id,
string.format(
'Message from the developer regarding bug report #bug%s:\n<pre>%s</pre>',
message.reply.forward_date .. message.reply.forward_from.id,
mattata.escape_html(message.text)
),
'html'
)
end
end
function bugreport.on_message(_, message, configuration, language)
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, bugreport.help)
end
if message.reply then
mattata.forward_message(configuration.bug_reports_chat, message.chat.id, false, message.message_id)
end
local success = mattata.forward_message(configuration.bug_reports_chat, message.chat.id, false, message.message_id)
if success and message.chat.id ~= configuration.bug_reports_chat then
return mattata.send_reply(message, string.format(language['bugreport']['1'], 'bug' .. message.date .. message.from.id))
end
return mattata.send_reply(message, language['bugreport']['2'])
end
return bugreport
\ No newline at end of file
diff --git a/plugins/calc.mattata b/plugins/calc.mattata
index f9a16c5..6d48910 100644
--- a/plugins/calc.mattata
+++ b/plugins/calc.mattata
@@ -1,192 +1,192 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local calc = {}
local mattata = require('mattata')
local http = require('socket.http')
local url = require('socket.url')
function calc:init()
calc.commands = mattata.commands(self.info.username):command('calc'):command('calculate'):command('calculator').table
calc.help = '/calc <expression> - Solves the given mathematical expression using mathjs.org.'
calc.aliases = {
['?'] = '/',
['divided by'] = '/',
['times by'] = '*',
['times'] = '*',
['multiplied by'] = '*',
[' x '] = '*',
['minus'] = '-',
['subtract'] = '-',
['take away'] = '-',
['to the power of'] = '^',
['raised to'] = '^',
[' pi '] = math.pi,
['plus'] = '+',
['added to'] = '+',
['add'] = '+',
['point'] = '.',
['dot'] = '.'
}
calc.numbers = {
['zero'] = 0,
['one'] = 1,
['two'] = 2,
['three'] = 3,
['four'] = 4,
['five'] = 5,
['six'] = 6,
['seven'] = 7,
['eight'] = 8,
['nine'] = 9,
['ten'] = 10,
['eleven'] = 11,
['twelve'] = 12,
['thirteen'] = 13,
['fourteen'] = 14,
['fifteen'] = 15,
['sixteen'] = 16,
['seventeen'] = 17,
['eighteen'] = 18,
['nineteen'] = 19,
['twenty'] = 20,
['thirty'] = 30,
['forty'] = 40,
['fifty'] = 50,
['sixty'] = 60,
['seventy'] = 70,
['eighty'] = 80,
['ninety'] = 90
}
calc.units = {
['hundred'] = '100',
['thousand'] = '1000',
['million'] = '1000000',
['billion'] = '1000000000',
['trillion'] = '1000000000000',
['quadrillion'] = '1000000000000000',
['quintillion'] = '1000000000000000000',
['sextillion'] = '1000000000000000000000',
['septillion'] = '1000000000000000000000000',
['octillion'] = '1000000000000000000000000000',
['nonillion'] = '1000000000000000000000000000000',
['decillion'] = '1000000000000000000000000000000000',
['undecillion'] = '1000000000000000000000000000000000000',
['duodecillion'] = '1000000000000000000000000000000000000000',
['tredecillion'] = '1000000000000000000000000000000000000000000',
['quattuordecillion'] = '1000000000000000000000000000000000000000000000',
['quindecillion'] = '1000000000000000000000000000000000000000000000000',
['sexdecillion'] = '1000000000000000000000000000000000000000000000000000',
['septendecillion'] = '1000000000000000000000000000000000000000000000000000000',
['octodecillion'] = '1000000000000000000000000000000000000000000000000000000000',
['novemdecillion'] = '1000000000000000000000000000000000000000000000000000000000000',
['vigintillion'] = '1000000000000000000000000000000000000000000000000000000000000000'
}
calc.url = 'https://api.mathjs.org/v4/?expr='
end
function calc.convert(str, language)
str = str:lower()
local results = {}
local prev = nil
for word in str:gmatch('%w+') do
if word ~= 'and' then -- don't process "and"
local top = #results
local number = tonumber(word)
if not number then
number = calc.numbers[word]
end
if number then
if prev == 'number' then
local prev_num = table.remove(results, top)
number = number + prev_num
end
table.insert(results, number)
prev = 'number'
else
local unit = tonumber(calc.units[word])
if not unit then
return false, string.format(language['calc']['2'], word)
end
prev = 'unit'
if top == 0 then
return false, language['calc']['3']
end
local interim = 0
while top > 0 and results[top] < unit do
interim = interim + table.remove(results, top)
top = #results
end
table.insert(results, interim * unit)
end
end
end
if #results == 0 then
return false, 'No number found!'
end
local final = 0
for _, res in ipairs(results) do
final = final + res
end
return final
end
function calc.process_input(input, language)
for k, v in pairs(calc.aliases) do
input = input:gsub(k, v)
end
for phrase in input:gmatch('[%w%s]+') do
local new, err = calc.convert(phrase, language)
if new then
input = input:gsub(phrase, new)
else
return false, err
end
end
return input
end
function calc.on_inline_query(_, inline_query, _, language)
local input = mattata.input(inline_query.query)
if not input then
return false
end
input = calc.process_input(input, language)
local str, res = http.request(calc.url .. url.escape(input))
if res ~= 200 or not str then
return false
end
local description = language['calc']['1']
local message_content = mattata.input_text_message_content(str)
local result = mattata.inline_result()
:type('article')
:id(1)
:title(str)
:description(description)
:input_message_content(message_content)
return mattata.answer_inline_query(inline_query.id, result)
end
function calc.on_message(_, message, _, language)
local input = mattata.input(message.text)
local err
if not input then
return mattata.send_reply(message, calc.help)
end
input, err = calc.process_input(input, language)
if not input then
return mattata.send_reply(message, err)
end
local str, res = http.request(calc.url .. url.escape(input))
if res ~= 200 then
local response = language['errors']['results']
return mattata.send_reply(message, response)
end
return mattata.send_message(message.chat.id, str)
end
return calc
\ No newline at end of file
diff --git a/plugins/captionbotai.mattata b/plugins/captionbotai.mattata
index 49ee387..5debd73 100644
--- a/plugins/captionbotai.mattata
+++ b/plugins/captionbotai.mattata
@@ -1,66 +1,66 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local captionbotai = {}
local mattata = require('mattata')
local https = require('ssl.https')
local ltn12 = require('ltn12')
function captionbotai:on_new_message(message, configuration, language)
if message.photo or (message.reply and message.reply.photo) then
if message.text:lower():match('^wh?at .- th[ia][st].-') or message.text:lower():match('^who .- th[ia][st].-') then
return captionbotai.on_message(self, message, configuration, language)
end
end
end
function captionbotai.request(input, configuration)
local body = string.format('{Type: "CaptionRequest", Content: "%s"}', input)
local sink, response = ltn12.sink.table()
local _, res = https.request(
{
['url'] = 'http://captionbot.azurewebsites.net/api/messages',
['method'] = 'POST',
['headers'] = {
['Content-Length'] = body:len(),
['Content-Type'] = 'application/json',
['DNT'] = 1,
['Host'] = 'captionbot.azurewebsites.net',
['Origin'] = 'https://www.captionbot.ai',
['Referer'] = 'https://www.captionbot.ai/',
['User-Agent'] = 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36'
},
['source'] = ltn12.source.string(body),
['sink'] = sink
}
)
response = table.concat(response)
if res ~= 200 then
return false
end
response = response:gsub('^"', ''):gsub('"$', ''):gsub('\\"', '"'):gsub(configuration.bot_token, '')
return response
end
function captionbotai.on_message(_, message, configuration, language)
if message.reply and message.reply.photo then
message.photo = message.reply.photo
end
local file = mattata.get_file(message.photo[#message.photo].file_id) -- Gets the highest resolution available, for the best result.
if not file then
return false
end
mattata.send_chat_action(message.chat.id)
local request_url = string.format('https://api.telegram.org/file/bot%s/%s', configuration.bot_token, file.result.file_path)
local output = captionbotai.request(request_url, configuration)
if not output or output:lower():match('^https%:%/%/') then
return mattata.send_reply(message, language['captionbotai']['1'] .. ' 😳')
end
output = output:match('%, but (.-)$') or output
output = output:gsub('%.$', '')
return mattata.send_reply(message, output)
end
return captionbotai
\ No newline at end of file
diff --git a/plugins/cats.mattata b/plugins/cats.mattata
index 8257bbe..ea62dd2 100644
--- a/plugins/cats.mattata
+++ b/plugins/cats.mattata
@@ -1,46 +1,46 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local cats = {}
local mattata = require('mattata')
local http = require('socket.http')
local json = require('dkjson')
function cats:init(configuration)
assert(configuration.keys.cats, 'cats.lua requires an API key, and you haven\'t got one configured!')
cats.commands = mattata.commands(self.info.username):command('cat').table
cats.help = '/cat - Sends a random photo of a cat.'
end
function cats.on_inline_query(_, inline_query, configuration, language)
local str, res = http.request('http://thecatapi.com/api/images/get?format=html&type=jpg&api_key=' .. configuration.keys.cats)
str = str:match('%<img src%=%"(.-)%"%>')
if res ~= 200 then
return
end
return mattata.answer_inline_query(inline_query.id, json.encode({{
['type'] = 'photo',
['id'] = '1',
['photo_url'] = tostring(str),
['thumb_url'] = tostring(str),
['caption'] = language['cats']['1']
}}))
end
function cats.on_message(_, message, configuration, language)
local str, res = http.request('http://thecatapi.com/api/images/get?format=html&type=jpg&api_key=' .. configuration.keys.cats)
if res ~= 200 then
return mattata.send_reply(message, language.errors.connection)
end
local photo = str:match('%<img src%=%"(.-)%"%>')
if not photo then
return mattata.send_reply(message, language.errors.unknown)
end
mattata.send_chat_action(message.chat.id, 'upload_photo')
return mattata.send_photo(message.chat.id, photo, language['cats']['1'])
end
return cats
\ No newline at end of file
diff --git a/plugins/chatroulette.mattata b/plugins/chatroulette.mattata
index 4813e4b..504d872 100644
--- a/plugins/chatroulette.mattata
+++ b/plugins/chatroulette.mattata
@@ -1,85 +1,85 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local chatroulette = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function chatroulette:init(configuration)
chatroulette.commands = mattata.commands(self.info.username):command('chatroulette'):command('endchat').table
chatroulette.help = '/chatroulette - Connect yourself to another random user, and have a conversation with them! To end the chat, use /endchat.'
chatroulette.limit = configuration.limits.chatroulette
end
function chatroulette:on_new_message(message, _, language)
if message.chat.type ~= 'private' or message.command or (message.is_media and not message.text) then -- we only want to process non-command, text messages in private chat
return false
end
local output
local other_user = redis:get('chatroulette:' .. message.from.id)
if not other_user then
return false
elseif message.text:len() > chatroulette.limit then -- we'll set a message length limit to stop a wall of text to the other user
self.is_done = true
output = string.format(language['chatroulette']['1'], chatroulette.limit)
return mattata.send_message(message.from.id, output)
end
self.is_done = true
output = string.format(language['chatroulette']['2'], mattata.escape_markdown(message.text))
local success = mattata.send_message(other_user, output, true)
if not success then -- if the message couldn't be sent it must mean the bot was blocked
redis:del('chatroulette:' .. other_user)
redis:del('chatroulette:' .. message.from.id)
return mattata.send_message(message.from.id, language['chatroulette']['3'])
end
return success
end
function chatroulette.on_message(_, message, _, language)
if message.chat.type ~= 'private' then
return mattata.send_reply(message, language.errors.private)
elseif message.command == 'endchat' then
local existing = redis:get('chatroulette:' .. message.from.id)
if existing then -- if their session hasn't ended, we'll force them to end it
redis:del('chatroulette:' .. message.from.id)
mattata.send_message(existing, language['chatroulette']['4']) -- send the other person a notification saying their session has ended
redis:del('chatroulette:' .. existing)
return mattata.send_message(message.from.id, language['chatroulette']['5'])
elseif redis:get('chatroulette:searching:' .. message.from.id) then
redis:del('chatroulette:searching:' .. message.from.id)
return mattata.send_message(message.from.id, language['chatroulette']['6'])
end
return mattata.send_message(message.from.id, language['chatroulette']['7'])
elseif message.command == 'chatroulette' then
local success = mattata.send_message(message.from.id, language['chatroulette']['8'])
if not success then
return false
end
local available = redis:keys('chatroulette:searching:*')
for pos, user in pairs(available) do
if user:match('^chatroulette:searching:(.-)$') == tostring(message.from.id) then
table.remove(available, pos)
end
end
if #available == 0 then
redis:set('chatroulette:searching:' .. message.from.id, true)
return mattata.edit_message_text(message.from.id, success.result.message_id, language['chatroulette']['9'])
end
available = available[math.random(#available)]
available = available:match('^chatroulette:searching:(.-)$')
local paired = mattata.send_message(available, language['chatroulette']['10'])
redis:del('chatroulette:searching:' .. available)
if not paired then
return mattata.edit_message_text(message.from.id, success.result.message_id, language['chatroulette']['11'])
end
redis:del('chatroulette:searching:' .. message.from.id)
redis:set('chatroulette:' .. available, message.from.id)
redis:set('chatroulette:' .. message.from.id, available)
return mattata.edit_message_text(message.from.id, success.result.message_id, language['chatroulette']['12'])
end
return false
end
return chatroulette
\ No newline at end of file
diff --git a/plugins/commandstats.mattata b/plugins/commandstats.mattata
index bdedad6..0c01968 100644
--- a/plugins/commandstats.mattata
+++ b/plugins/commandstats.mattata
@@ -1,81 +1,81 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local commandstats = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function commandstats:init()
commandstats.commands = mattata.commands(self.info.username):command('commandstats'):command('cmdstats').table
commandstats.help = '/commandstats - Shows statistical information about the current chat\'s top ten commands (ordered by message count). Alias: /cmdstats.'
end
function commandstats.reset_command_stats(chat_id)
if not chat_id or tonumber(chat_id) == nil then
return false
end
local messages = redis:keys('commandstats:' .. chat_id .. ':*')
for _, v in pairs(messages) do
redis:del(v)
end
return true
end
function commandstats.get_command_stats(chat_id, title, language)
local commands = redis:smembers('chat:' .. chat_id .. ':commands')
local statistics = {}
for i = 1, #commands do
local command = commands[i]
local command_info = {
['command'] = command
}
command_info.count = redis:get('commandstats:' .. chat_id .. ':' .. command)
if command_info.count and tonumber(command_info.count) ~= nil then
table.insert(statistics, command_info)
end
end
table.sort(statistics, function(a, b)
if a.count and b.count then
return tonumber(a.count) > tonumber(b.count)
end
end)
local total = 0
for _, v in pairs(statistics) do
total = total + v.count
end
local text = ''
local output = {}
for i = 1, 10 do
table.insert(output, statistics[i])
end
for _, v in pairs(output) do
local percent = tostring(mattata.round((v.count / total) * 100, 1))
text = text .. mattata.escape_html(v.command) .. ': <b>' .. mattata.comma_value(v.count) .. '</b> [' .. percent .. '%]\n'
end
if not text or text == '' then
return language['commandstats']['1']
end
return string.format(
language['commandstats']['2'],
mattata.escape_html(title), text,
mattata.comma_value(total):gsub('%..-$', '')
)
end
function commandstats.on_message(_, message, _, language)
if message.chat.type == 'private' then
return mattata.send_message(message.chat.id, language.errors.supergroup)
end
local input = mattata.input(message.text)
local output
if input and input:lower() == 'reset' and mattata.is_group_admin(message.chat.id, message.from.id) then
output = commandstats.reset_command_stats(message.chat.id) and language['commandstats']['3'] or language['commandstats']['4']
return mattata.send_message(message.chat.id, output)
end
output = commandstats.get_command_stats(message.chat.id, message.chat.title, language)
return mattata.send_message(message.chat.id, output, 'html')
end
return commandstats
\ No newline at end of file
diff --git a/plugins/copypasta.mattata b/plugins/copypasta.mattata
index cae157a..f283e18 100644
--- a/plugins/copypasta.mattata
+++ b/plugins/copypasta.mattata
@@ -1,81 +1,81 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local copypasta = {}
local mattata = require('mattata')
function copypasta:init(configuration)
copypasta.commands = mattata.commands(self.info.username):command('copypasta'):command(utf8.char(128514)).table
copypasta.help = '/copypasta - Riddles the replied-to message with cancerous emoji. Alias: /' .. utf8.char(128514) .. '.'
copypasta.limit = configuration.limits.copypasta
end
function copypasta.format_message(input)
local emoji = {
128514, -- crying with laughter
128514, -- crying with laughter
128076, -- ok hand
9996, -- peace sign hand
128158, -- rotating hearts
128077, -- thumbs up
128076, -- ok hand
128175, -- 100//
127926, -- music symbol
128064, -- eyes
128514, -- crying with laughter
128083, -- glasses
128079, -- clapping hands
128080, -- open hands
127829, -- pizza slice
128165, -- explosion
127860, -- knife and fork
128166, -- water drops
128166, -- water drops
127825, -- peach
127814, -- aubergine
128553, -- moaning face
128527, -- smirking face
128073, -- finger pointing to right
128064, -- eyes
128069, -- tongue
128553 -- moaning face
}
local output = {}
for i = 1, input:len() do
local char = input:sub(i, i)
math.random(os.time())
if char == ' ' then
local rndtotal = math.random(#emoji)
local rndemoji = utf8.char(emoji[rndtotal])
if math.random(2) == 2
then
rndtotal = math.random(#emoji)
rndemoji = rndemoji .. ' ' .. utf8.char(emoji[rndtotal])
end
char = char .. rndemoji .. char
elseif math.random(5) == 5 then
char = char:lower()
end
table.insert(output, char)
end
return table.concat(output)
end
function copypasta.on_message(_, message, _, language)
if not message.reply then
return mattata.send_reply(message, copypasta.help)
end
local output
mattata.send_chat_action(message.chat.id)
if message.reply.text:len() > copypasta.limit then
output = string.format(language['copypasta']['1'], copypasta.limit)
return mattata.send_reply(message, output)
end
output = copypasta.format_message(message.reply.text:upper())
message.message_id = message.reply.message_id
return mattata.send_reply(message, output)
end
return copypasta
\ No newline at end of file
diff --git a/plugins/coronavirus.mattata b/plugins/coronavirus.mattata
index e9da5ca..ab5c3a1 100644
--- a/plugins/coronavirus.mattata
+++ b/plugins/coronavirus.mattata
@@ -1,68 +1,68 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local coronavirus = {}
local mattata = require('mattata')
local https = require('ssl.https')
local json = require('dkjson')
function coronavirus:init()
coronavirus.commands = mattata.commands(self.info.username):command('coronavirus'):command('corona'):command('covid19'):command('covid').table
coronavirus.help = '/coronavirus [country]. Returns the global COVID-19 statistics. Optionally, a country may be specified by its country code or name. Aliases: /corona, /covid19, /covid.'
coronavirus.url = 'https://api.covid19api.com/summary'
end
function coronavirus.on_message(_, message, _, language)
local jstr, res = https.request(coronavirus.url)
if res ~= 200 then
return mattata.send_reply(message, language.errors.connection)
end
local jdat = json.decode(jstr)
if not jdat.Global and not jdat.Countries then
return mattata.send_reply(message, language.errors.results)
end
local input = mattata.input(message.text)
local found_match, country_position, output = false
if jdat.Global and (not input or (input:lower() == 'global' or input:lower() == 'world')) then
output = language['coronavirus']['1']
local country_name = 'Everywhere'
local new_confirmed = mattata.comma_value(jdat.Global.NewConfirmed)
local total_confirmed = mattata.comma_value(jdat.Global.TotalConfirmed)
local new_deaths = mattata.comma_value(jdat.Global.NewDeaths)
local total_deaths = mattata.comma_value(jdat.Global.TotalDeaths)
local new_recovered = mattata.comma_value(jdat.Global.NewRecovered)
local total_recovered = mattata.comma_value(jdat.Global.TotalRecovered)
output = string.format(output, country_name, new_confirmed, total_confirmed, new_deaths, total_deaths, new_recovered, total_recovered)
elseif input and jdat.Countries then
for k, v in pairs(jdat.Countries) do
if input:len() == 2 then
input = input:lower() == 'uk' and 'gb' or input:lower()
if input == v.CountryCode:lower() then
found_match, country_position = true, k
end
else
if v.Country:lower():match(input:lower()) then
found_match, country_position = true, k
end
end
end
end
if found_match then
output = language['coronavirus']['1']
local country_name = jdat.Countries[country_position].Country
local new_confirmed = mattata.comma_value(jdat.Countries[country_position].NewConfirmed)
local total_confirmed = mattata.comma_value(jdat.Countries[country_position].TotalConfirmed)
local new_deaths = mattata.comma_value(jdat.Countries[country_position].NewDeaths)
local total_deaths = mattata.comma_value(jdat.Countries[country_position].TotalDeaths)
local new_recovered = mattata.comma_value(jdat.Countries[country_position].NewRecovered)
local total_recovered = mattata.comma_value(jdat.Countries[country_position].TotalRecovered)
output = string.format(output, country_name, new_confirmed, total_confirmed, new_deaths, total_deaths, new_recovered, total_recovered)
end
output = output or language.errors.results
return mattata.send_reply(message, output, 'markdown')
end
return coronavirus
\ No newline at end of file
diff --git a/plugins/currency.mattata b/plugins/currency.mattata
index 68a4576..cb7be94 100644
--- a/plugins/currency.mattata
+++ b/plugins/currency.mattata
@@ -1,43 +1,43 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local currency = {}
local mattata = require('mattata')
local https = require('ssl.https')
function currency:init()
currency.commands = mattata.commands(self.info.username):command('currency'):command('convert'):command('cash').table
currency.help = '/currency <amount> <from> to <to> - Converts exchange rates for various currencies via Google Finance. Aliases: /convert, /cash.'
currency.url = 'https://www.google.com/finance/converter?from=%s&to=%s&a=%s'
end
function currency.on_message(_, message, _, language)
local input = mattata.input(message.text:upper())
if input then
input = input:gsub('%$', 'USD'):gsub('€', 'EUR'):gsub('£', 'GBP')
end
if not input or not input:match('^.- %a%a%a TO %a%a%a$') then
return mattata.send_reply(message, currency.help)
end
local amount, from, to = input:match('^(.-) (%a%a%a) TO (%a%a%a)$')
amount = tonumber(amount) or 1
local result = 1
if from ~= to then
local str, res = https.request(string.format(currency.url, from, to, amount))
if res ~= 200 then
return mattata.send_reply(message, language.errors.connection)
end
str = str:match('<span class=bld>(.-) %u+</span>')
if not str then
return mattata.send_reply(message, language.errors.results)
end
result = string.format('%.2f', str)
end
result = string.format('%s %s = %s %s', amount, from, result, to)
return mattata.send_message(message.chat.id, result)
end
return currency
\ No newline at end of file
diff --git a/plugins/dice.mattata b/plugins/dice.mattata
index b9d71ef..c0f5a78 100644
--- a/plugins/dice.mattata
+++ b/plugins/dice.mattata
@@ -1,35 +1,35 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local dice = {}
local mattata = require('mattata')
function dice:init()
dice.commands = mattata.commands(self.info.username):command('dice'):command('roll').table
dice.types = {
utf8.char(127936),
utf8.char(127922),
utf8.char(127919)
}
dice.help = '/dice [type] - Returns an animated dice roll, basketball shot or dart throw (randomly chosen). Optionally, you can specify the type via parameter (ball/dice/dart). Alias: /roll.'
end
function dice.on_message(_, message)
local input = mattata.input(message.text)
local output = dice.types[math.random(#dice.types)]
if input and (input:lower() == 'basketball' or input:lower() == 'ball') then
output = dice.types[1]
elseif input and (input:lower() == 'dice' or input:lower() == 'die') then
output = dice.types[2]
elseif input and input:lower() == 'dart' then
output = dice.types[3]
end
if math.random(100) == 100 then
return mattata.send_sticker(message.chat.id, 'CAACAgQAAx0CQNYPUgABATQCXtmOk9jz2lCN7omTIjCqmLa08hUAAkAAA8j67BMAAUvGUioKrK4aBA')
end
return mattata.send_dice(message.chat.id, output)
end
return dice
\ No newline at end of file
diff --git a/plugins/dictionary.mattata b/plugins/dictionary.mattata
index 184569d..b789949 100644
--- a/plugins/dictionary.mattata
+++ b/plugins/dictionary.mattata
@@ -1,60 +1,60 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local dictionary = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local ltn12 = require('ltn12')
local json = require('dkjson')
function dictionary:init(configuration)
dictionary.commands = mattata.commands(self.info.username):command('dictionary'):command('define').table
dictionary.help = '/dictionary <word> - Looks up the given word in the Oxford Dictionary and returns the relevant definition(s). Alias: /define.'
dictionary.url = 'https://od-api.oxforddictionaries.com/api/v1/entries/en/'
dictionary.id = configuration.keys.dictionary.id
dictionary.key = configuration.keys.dictionary.key
end
function dictionary.on_message(_, message, _, language)
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, dictionary.help)
end
local body = {}
local _, res = https.request({
['url'] = dictionary.url .. url.escape(input),
['headers'] = {
['app_id'] = dictionary.id,
['app_key'] = dictionary.key
},
['sink'] = ltn12.sink.table(body),
})
if res ~= 200 then
return mattata.send_reply(message, language.errors.connection)
end
body = table.concat(body)
local jdat = json.decode(body)
if not jdat or not jdat.results[1] or not jdat.results[1].word or not jdat.results[1].lexicalEntries then
return mattata.send_reply(message, language.errors.results)
end
local word = jdat.results[1].word
word = mattata.escape_html(word)
local results = #jdat.results[1].lexicalEntries
results = tonumber(results) > 4 and 4 or results
local definitions = {}
for i = 1, results do
if jdat.results[1] and jdat.results[1].lexicalEntries and jdat.results[1].lexicalEntries[i].entries and jdat.results[1].lexicalEntries[i].entries[1].senses and jdat.results[1].lexicalEntries[i].entries[1].senses[1].definitions then
local entry = jdat.results[1].lexicalEntries[i].entries[1].senses[1].definitions[1]
entry = entry:gsub(':$', ''):gsub('%.$', '')
entry = mattata.escape_html(entry)
table.insert(definitions, '• ' .. entry)
end
end
local output = '<b>' .. word .. '</b>\n\n' .. table.concat(definitions, '\n')
return mattata.send_message(message.chat.id, output, 'html')
end
return dictionary
\ No newline at end of file
diff --git a/plugins/doge.mattata b/plugins/doge.mattata
index f3b2ae6..71ea691 100644
--- a/plugins/doge.mattata
+++ b/plugins/doge.mattata
@@ -1,33 +1,33 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local doge = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function doge:init()
doge.commands = mattata.commands(self.info.username):command('doge').table
doge.help = '/doge <text> - Doge-ifies the given text. Sentences should be separated using slashes or new lines. Example: /doge hello world/this is a test sentence/make sure you type like this/else it won\'t work!'
end
function doge.on_message(_, message, _, language)
local input = message.reply and message.reply.text or mattata.input(message.text)
if not input then
local success = mattata.send_force_reply(message, language['doge']['1'])
if success then
redis:set('action:' .. message.chat.id .. ':' .. success.result.message_id, '/doge')
end
return
elseif message.reply then
input = input:gsub(' ', '\n')
end
local url = 'http://dogr.io/' .. input:gsub(' ', '%%20'):gsub('\n', '/') .. '.png?split=false&.png'
if not url:match('https?://[%%%w-_%.%?%.:/%+=&]+') == url then -- Validate the URL.
return mattata.send_reply(message, language['errors']['results'])
end
return mattata.send_photo(message.chat.id, url)
end
return doge
\ No newline at end of file
diff --git a/plugins/donate.mattata b/plugins/donate.mattata
index 921051c..36b6184 100644
--- a/plugins/donate.mattata
+++ b/plugins/donate.mattata
@@ -1,19 +1,19 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local donate = {}
local mattata = require('mattata')
function donate:init()
donate.commands = mattata.commands(self.info.username):command('donate').table
donate.help = '/donate - Make an optional, monetary contribution to the mattata project.'
end
function donate.on_message(_, message, _, language)
local output = string.format(language['donate']['1'], mattata.escape_html(message.from.first_name))
return mattata.send_message(message.chat.id, output, 'html')
end
return donate
\ No newline at end of file
diff --git a/plugins/drawtext.mattata b/plugins/drawtext.mattata
index 1795574..deb748a 100644
--- a/plugins/drawtext.mattata
+++ b/plugins/drawtext.mattata
@@ -1,33 +1,33 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local drawtext = {}
local mattata = require('mattata')
local http = require('socket.http')
local url = require('socket.url')
function drawtext:init(configuration)
drawtext.commands = mattata.commands(self.info.username):command('drawtext').table
drawtext.help = '/drawtext [text] - Converts the given/replied-to text to an image.'
drawtext.limit = configuration.limits.drawtext
drawtext.url = 'http://api.img4me.com/?font=arial&size=24&bcolor=&type=png&text='
end
function drawtext.on_message(_, message, _, language)
local input = message.reply and message.reply.text or mattata.input(message.text)
if not input then
return mattata.send_reply(message, drawtext.help)
elseif input:len() > drawtext.limit then
input = input:sub(1, (drawtext.limit - 3)) .. '...'
end
local str, res = http.request(drawtext.url .. url.escape(input))
if not str or res ~= 200 then
return mattata.send_reply(message, language.errors.connection)
end
mattata.send_chat_action(message.chat.id, 'upload_photo')
return mattata.send_photo(message.chat.id, str)
end
return drawtext
\ No newline at end of file
diff --git a/plugins/exec.mattata b/plugins/exec.mattata
index c55b2b6..9d3526e 100644
--- a/plugins/exec.mattata
+++ b/plugins/exec.mattata
@@ -1,196 +1,196 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local exec = {}
local mattata = require('mattata')
local https = require('ssl.https')
local ltn12 = require('ltn12')
local multipart = require('multipart-post')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function exec:init()
exec.commands = mattata.commands(self.info.username):command('exec').table
exec.help = '/exec <language> <code> - Executes the specified code in the given language and returns the output.'
exec.languages = {
['C#'] = 1,
['VB.NET'] = 2,
['Java'] = 4,
['Python'] = 5,
['PHP'] = 8,
['Pascal'] = 9,
['Objective-C'] = 10,
['Haskell'] = 11,
['Ruby'] = 12,
['Perl'] = 13,
['Lua'] = 14,
['JavaScript'] = 17,
['GoLang'] = 20,
['Node.js'] = 23,
['Python 3'] = 24,
['C'] = 26,
['C++'] = 27,
['MySQL'] = 33,
['Swift'] = 37,
['Bash'] = 38
}
end
function exec.get_keyboard(user_id)
local keyboard = {
['inline_keyboard'] = {{}}
}
local total = 0
for _, _ in pairs(exec.languages) do
total = total + 1
end
local count = 0
local rows = math.floor(total / 8)
if rows ~= total then
rows = rows + 1
end
local row = 1
for k, v in pairs(exec.languages) do
count = count + 1
if count == rows * row then
row = row + 1
table.insert(keyboard.inline_keyboard, {})
end
local last_used = redis:hget('user:' .. user_id .. ':info', 'last_used_exec_lang')
if last_used and last_used == tostring(v) then
k = utf8.char(9889) .. ' ' .. k
end
table.insert(keyboard.inline_keyboard[row], {
['text'] = k,
['callback_data'] = 'exec:' .. user_id .. ':' .. tostring(v) .. ':n'
})
end
return keyboard
end
function exec.get_arguments(language)
language = tonumber(language)
if language == 6 or language == 26 then
return '-Wall -std=gnu99 -O2 -o a.out source_file.c'
elseif language == 7 or language == 27 then
return '-Wall -std=c++14 -O2 -o a.out source_file.cpp'
elseif language == 28 then
return 'source_file.cpp -o a.exe /EHsc /MD /I C:\\\\boost_1_60_0 /link /LIBPATH:C:\\\\boost_1_60_0\\\\stage\\\\lib'
elseif language == 29 then
return 'source_file.c -o a.exe'
elseif language == 30 then
return 'source_file.d -ofa.out'
elseif language == 20 then
return '-o a.out source_file.go'
elseif language == 11 then
return '-o a.out source_file.hs'
elseif language == 10 then
return '-MMD -MP -DGNUSTEP -DGNUSTEP_BASE_LIBRARY=1 -DGNU_GUI_LIBRARY=1 -DGNU_RUNTIME=1 -DGNUSTEP_BASE_LIBRARY=1 -fno-strict-aliasing -fexceptions -fobjc-exceptions -D_NATIVE_OBJC_EXCEPTIONS -pthread -fPIC -Wall -DGSWARN -DGSDIAGNOSE -Wno-import -g -O2 -fgnu-runtime -fconstant-string-class=NSConstantString -I. -I /usr/include/GNUstep -I/usr/include/GNUstep -o a.out source_file.m -lobjc -lgnustep-base'
end
return ''
end
function exec.make_request(language, code)
language = language:lower()
local args = exec.get_arguments(language)
local parameters = {
['LanguageChoice'] = language,
['Program'] = code,
['Input'] = 'stdin',
['CompilerArgs'] = args
}
local response = {}
local body, boundary = multipart.encode(parameters)
local old_timeout = https.TIMEOUT
https.TIMEOUT = 1
local _, res = https.request({
['url'] = 'https://rextester.com/rundotnet/api/',
['method'] = 'POST',
['headers'] = {
['Content-Type'] = 'multipart/form-data; boundary=' .. boundary,
['Content-Length'] = #body
},
['source'] = ltn12.source.string(body),
['sink'] = ltn12.sink.table(response)
})
https.TIMEOUT = old_timeout
if res ~= 200 then
return false
end
local jdat = json.decode(table.concat(response))
local output = {}
if jdat.Warnings and jdat.Warnings ~= '' then
table.insert(output, '<b>Warnings</b>\n' .. mattata.escape_html(jdat.Warnings))
end
if jdat.Errors and jdat.Errors ~= '' then
table.insert(output, '<b>Errors</b>\n' .. mattata.escape_html(jdat.Errors))
end
if jdat.Result and jdat.Result ~= '' then
table.insert(output, '<b>Result</b>\n<pre>' .. mattata.escape_html(jdat.Result) .. '</pre>')
end
if jdat.Stats and jdat.Stats ~= '' then
local stats = jdat.Stats:gsub('%, ', '\n• '):gsub('cpu', 'CPU'):gsub('memory', 'Memory'):gsub('absolute', 'Absolute'):gsub('%,', '.')
table.insert(output, '<b>Statistics</b>\n• ' .. mattata.escape_html(stats))
end
return table.concat(output, '\n')
end
function exec.on_callback_query(_, callback_query, message, _, language)
local user_id, lang, confirmed = callback_query.data:match('^(%d+):(.-):(.-)$')
if not user_id or not lang or not message.reply or callback_query.from.id ~= tonumber(user_id) then
return mattata.answer_callback_query(callback_query.id, language.errors.generic)
elseif lang == 'back' then
return mattata.edit_message_text(message.chat.id, message.message_id, language['exec']['1'], nil, true, exec.get_keyboard(user_id))
end
local code = mattata.input(message.reply.text) or message.reply.text
if not code then
return
end
local language_name
for k, v in pairs(exec.languages) do
if tostring(v) == lang then
language_name = k
end
end
local output
if not language_name then
return
elseif confirmed == 'y' then
redis:hset('user:' .. user_id .. ':info', 'last_used_exec_lang', lang)
output = exec.make_request(lang, code) or language['exec']['2'] .. ' ' .. utf8.char(128527)
return mattata.edit_message_text(message.chat.id, message.message_id, output, 'html')
end
output = string.format(language['exec']['3'], language_name)
local keyboard = mattata.inline_keyboard():row(
mattata.row():callback_data_button(
language['exec']['4'],
'exec:' .. user_id .. ':back:n'
):callback_data_button(
language['exec']['5'],
string.format('exec:%s:%s:y', user_id, tostring(lang))
))
return mattata.edit_message_text(message.chat.id, message.message_id, output, nil, true, keyboard)
end
function exec.on_message(_, message, _, language)
local input = mattata.input(message.text)
if not input then
local success = mattata.send_force_reply(message, language['exec']['6'])
if success then
local key = string.format('action:%s:%s', message.chat.id, success.result.message_id)
redis:set(key, '/exec')
end
return
end
mattata.send_chat_action(message.chat.id)
return mattata.send_message(
message, language['exec']['7'],
'html', true, false,
message.message_id,
exec.get_keyboard(message.from.id)
)
end
return exec
\ No newline at end of file
diff --git a/plugins/facebook.mattata b/plugins/facebook.mattata
index 16748ae..2a5571b 100644
--- a/plugins/facebook.mattata
+++ b/plugins/facebook.mattata
@@ -1,69 +1,69 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local facebook = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local redis = dofile('libs/redis.lua')
function facebook:init()
facebook.commands = mattata.commands(self.info.username):command('facebook'):command('fbook').table
facebook.help = '/facebook <Facebook username> - Sends the profile picture of the given Facebook user. Alias: /fbook.'
end
function facebook.get_avatar(user)
local str = https.request('https://www.facebook.com/' .. url.escape(user))
if not str or not str:match(',"entity_id":"(.-)"}') then
return false
end
local _, _, res = https.request({
['url'] = 'https://graph.facebook.com/' .. str:match(',"entity_id":"(.-)"}') .. '/picture?type=large&width=5000&height=5000',
['redirect'] = false
})
if not res or not res.location then
return false
end
return res.location
end
function facebook.on_inline_query(_, inline_query, _, language)
local input = mattata.input(inline_query.query)
if not input then
return
end
local output = facebook.get_avatar(input)
if not output then
return mattata.send_inline_article(
inline_query.id,
language['facebook']['1'],
language['errors']['results']
)
end
return mattata.send_inline_photo(inline_query.id, output)
end
function facebook.on_message(_, message, _, language)
local input = mattata.input(message.text)
if not input then
local success = mattata.send_force_reply(message, language['facebook']['2'])
if success then
local action = string.format('action:%s:%s', message.chat.id, success.result.message_id)
redis:set(action, '/facebook')
end
return
elseif input:match('^@.-$') then
input = input:match('^@(.-)$')
end
local output = facebook.get_avatar(input)
if not output then
return mattata.send_reply(message, language.errors.results)
end
local button_text = string.format(language['facebook']['3'], input)
local keyboard = mattata.inline_keyboard():row(mattata.row():url_button(button_text, 'https://www.facebook.com/' .. url.escape(input)))
return mattata.send_photo(message.chat.id, output, nil, false, message.message_id, keyboard)
end
return facebook
\ No newline at end of file
diff --git a/plugins/fact.mattata b/plugins/fact.mattata
index a06838b..bd65474 100644
--- a/plugins/fact.mattata
+++ b/plugins/fact.mattata
@@ -1,1050 +1,1050 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local fact = {}
local mattata = require('mattata')
function fact:init()
fact.commands = mattata.commands(self.info.username):command('fact').table
fact.help = '/fact - Returns a random, and somewhat incorrect, fact.'
end
local facts = {
'Koalas\' teeth are strong enough to bend time and space.',
'There hasn\'t been a person named Stanley for 10 years.',
'Beethoven was the first man to hear the sound of clowns arguing.',
'Nobody can explain how a computer works.',
'The term WiFi stands for "Wireless info For internets".',
'Caffeine is derived from sunflower seeds.',
'94% of US citizens report that they\'re allergic to camera lenses.',
'Pen ink consists mostly of citric acid.',
'Most movie scripts are written underwater.',
'Google is the highest rated restaurant in California.',
'Yawning causes bones to break more easily.',
'Loud music is known to soothe camels.',
'There are only 2 male koalas on the planet.',
'Baby carriages are often made out of recycled Dell computers.',
'Glass generates about 12% of the world\'s electricity.',
'Fire has no reflection in mirrors.',
'Ryan Reynolds was the first person to count to 5.',
'Men usually grow facial hair by the first time they hear bird chirp for the 30th time.',
'Ducks can\'t feel water.',
'Feathers are 2 times heavier on Tuesdays.',
'The actor Nicolas Cage is actually three different people.',
'Google is the only company in the world to own a water fountain in Europe.',
'There are 86 people in the United Kingdom named Ron.',
'Samsung is the manufacturer of the majority of women\'s hygiene products.',
'Over 85% of childbirths are indirectly caused by members of Reddit.',
'iPhone users can\'t see the color purple.',
'YouTube videos will be limited to a maximum of 23 seconds starting March 2015.',
'People eat on average at least 3 pairs of scissors in their lifetime.',
'Pigs are incredibly scared of the sound of cats meowing.',
'When you cut a piece of paper, you\'re actually sliding two separate pieces away from each other.',
'It\'s very commonplace to trade punches with a close friend on holidays in the United States.',
'Walls in houses were made almost completely out of sandpaper in the 1960s.',
'The Leaning Tower of Pisa is actually only worth about $45 because of the fact that it does not stand straight up.',
'One whole season of the show It\'s Always Sunny in Philadelphia features only stunt doubles and none of the actual cast.',
'No movie exists that includes Matt Damon and a cell phone in the entire movie.',
'The older cats become, the more they can only smell the scent of AXE Bodyspray.',
'New Yorkers are best known for exclusively drinking Mountain Dew and nothing else.',
'Saliva is the only thing able to melt glass.',
'Nokia phones are the only things known to man capable of communicating with hamsters.',
'iTunes is the most popular choice of desk brand.',
'Elijah Wood was crowned King of Root Beer 6 times in 2011.',
'Bears don\'t eat.',
'Twitter\'s headquarters are located in New York City from 9pm to 11pm EST Monday through Tuesday.',
'Sleeping reduces your chances of dying.',
'Reading was considered a feat of strength in the 1700s.',
'Twins are more likely to get amnesia than most people.',
'Each member of Linkin Park has been knighted at some point.',
'Hockey was first played in the summer of 2002.',
'Today is National Pi Day.',
'Marijuana is actually legal in all 50 states; the government just hasn\'t told any of the smokers of it about it.',
'Love is often compared to cake.',
'Sadness causes cancer in 94% of all lady bugs.',
'Clothes lose their color after 23 days.',
'Candy bars are not permitted to contain any food-like substances.',
'Involuntarily making odd faces is often a sign of being blind in one eye.',
'A total of 7 people have never been in a car.',
'The first QR Code was used on November 8, 1994.',
'On a list of Americans\' most favorite words, "Potpourri" came in 2nd, behind "pseudopseudohypoparathyroidism".',
'Most modern calendars do not include 7 days of the week.',
'The term "beat boxing" comes from illiterate sailors who punched various cardboard boxes in their spare time.',
'A recent study showed that a total of 1,484 Americans are not named Jennifer.',
'Walruses are avid readers of romance novels.',
'Netflix is owned by Amazon, which is owned by Google, which is owned by some guy in Minnesota.',
'3D printers were first mass-produced in a small Brazilian town in 1984.',
'Catnip is generally thought to be extremely dangerous if looked at under direct sunlight.',
'Ferrets don\'t have functional eyes.',
'Dell computers are the sole reason that Internet Explorer is the most liked web browser.',
'4% of the average human body is made of aluminum.',
'Being generous is the leading cause of death in the United States.',
'The word "escape" was coined by a man in prison trying to describe his departure from the prison. Ironically, he never actually escaped.',
'The universal sign of friendship is a punch in the face.',
'No one has laid eyes upon a wooden boat since the early 1700s.',
'Telling jokes decreases your lifespan by 23 minutes per joke told.',
'Hair grows faster than normal every 8 years.',
'The state of Ohio passed a law in 1994 banning the use of mini fridges.',
'86% of men report that they don\'t have a tongue.',
'There are no windows in South America.',
'Calendars are unknown to the people of western California.',
'The most common cause of vehicle-related injuries is ferrets.',
'A survey of 100 people found that 26% of them had a disease known as "Fleeing Mustache", where their mustache falls off of their face about every 2 days.',
'Peanut butter products can be used to cure the common cold.',
'The first person to buy an iPhone was a man named Heinrich McDominferbincoughcough.',
'The word \'mouse\' is supposed to be spelled \'paper\'.',
'Most people can\'t touch glass without screaming.',
'Sales of trains have gone up 836% since January 23, 2014.',
'Gorillas were trained to use cell phones by Brazilians in 1949.',
'Tacos were first made to mimic the shape of a cat\'s tail.',
'Android cell phones are often commonly confused to be able to cause paper-based objects to achieve flight.',
'The common expression "a bird in the hand is worth two in the bush" originally was slang for "hey, take a look at that bird".',
'Tigers have no sense of smell.',
'Every time a door is opened, someone buys a blue desk.',
'On November 10 of every year, the sun is only about 1,000 miles away from Earth.',
'Although very few know it, the lead singer of AC/DC provided most of vocals for the song Poker Face by Lady Gaga.',
'As of the year 2014, wallets have caused more fatal injuries than knives have.',
'When you sneeze, your body is actually putting itself to sleep for a brief moment.',
'Nicolas Cage was one of the original inventors of the radio.',
'Most wallpaper is made out of recycled receipts from Amazon.',
'The first laptop ever created was actually the most powerful laptop there has ever been.',
'The average snowflake contains about one ounce of water.',
'Fingernails are about 140% stronger than iron.',
'Hospitals are commonly occupied by raccoons.',
'The first dinosaur was a dog.',
'Most Facebook users can\'t see the color blue.',
'Every time you read a sentence, you become slightly more illiterate.',
'Horses go into bars every Friday.',
'The first pyramid that was built was intended to be in the shape of a circle.',
'Will Smith can\'t count to 3, but can count to 26.',
'Windows 8 is the most popular version of Windows since Mac.',
'Facebook purchased the country of Germany on January 23, 2008.',
'There are 26 different variations of the color red.',
'9 o\'clock in the morning was not an official time until 1945.',
'Air in Texas is contaminated with high amounts of iron.',
'20 trillion minutes of pornography is uploaded to YouTube every hour.',
'Levitation is illegal in Arkansas.',
'Family Guy is very popular on Pluto.',
'During December, Cinnamon is commonly sold in 36 different flavors.',
'For a brief period of time during 2009, Elvis Presley rose from the dead to appear in the movie Batman Begins.',
'Most books that are published nowadays feature 2 pages made from peanut butter.',
'An average human will only ever use 1% of their brain.',
'Windows 8 (as of November 24) has seen more sales than Star Wars.',
'Disney is considering buying Microsoft.',
'Adobe was the original creator of the iPod.',
'iTunes was originally created by Toshiba.',
'There are plans to make a sequel to Iron Man 3 called Iron Man 3 2.',
'Chicken tastes like bacon once every month.',
'As of November 22, 2012, Pink Floyd has re-released the album "The Wall" 33 times.',
'Zippo lighters are considered weapons of mass destruction in 18 states.',
'Mathematics doesn\'t exist on Sundays.',
'Every time Nicolas Cage receives a message on Facebook, a Mac computer is hit with a sledge hammer.',
'Only 11 people on earth can touch their toes.',
'Gloves don\'t make your hands warmer if it is exactly 33 degrees outside.',
'This sentence is not a question?',
'The English language is based on Braille.',
'Orlando, Florida is the home of Los Angeles, California.',
'It\'s illegal to give someone your business card in Japan.',
'Cats are unable to see the color white.',
'Smoking cigarettes is known to attract rabid giraffes.',
'Drinking 1 beer is the equivalent of eating 36 pieces of bacon.',
'The world\'s electricity is provided solely by Adam Sandler.',
'The first car was a horse. His name was Bert.',
'Bears will not attack you if they can\'t see your eyes.',
'The average human heart can withstand about 23 pounds of pressure.',
'You have to be at least 18 years old to attend preschool.',
'Tourism is illegal in Nevada.',
'Most cheeses do not have an expiration date.',
'Only 1 person in the whole world is named Thomas Mays. That person\'s name is Nicolas Cage.',
'Underage drinking is the leading cause of HIV in Canada.',
'Phones are the sturdiest phones known to man.',
'Being in love causes cancer.',
'Bears cannot smell grass.',
'There are only about 1200 facts in existence.',
'Intel is currently creating a processor that runs purely on tobacco.',
'Most llamas are purple.',
'Halloween is an Islamic holiday.',
'Osama Bin Laden was actually your mother.',
'Keyboards usually weigh about 12 pounds in Europe.',
'Books will no longer be legal to read on November 13, 2012.',
'This sentance doesnt contain speling erors.',
'There\'s no such thing as a rainbow.',
'The iPad Mini never existed.',
'Oprah invented the first light bulb.',
'Halo 4 inspired Bill Gates to invent the Internet.',
'The Constitution was first written on a credit card.',
'Barrack Obama is the President of the Moon.',
'Microsoft\'s next update to Windows will be based on Windows 98 mixed with YouTube.',
'Schools are only in session for 1 month in the United States.',
'There is no such thing as grass.',
'Burger King sells human hands on Halloween.',
'The color red is made by mixing green and black.',
'42 searches are made on Google every single hour, totalling to about 100 total searches being made every day.',
'There are as many hospitals in California as there are humans on Earth.',
'Trains are made of cat shit.',
'Sideburns cause you to set off every fire alarm in a one inch radius.',
'Sugar no longer tastes sweet in the United States.',
'Bees have no wings.',
'Most toasters are rainbow-colored.',
'Infinity can be represented by 42 + 8.',
'You can starve in 3 seconds if you eat chicken in intervals of 6 minutes.',
'HP computers malfunction when exposed to air.',
'It\'s illegal to use ladders inside schools.',
'The Avengers was filmed over a period of four seconds in 1994.',
'Bodyspray is made from 2% cat urine.',
'The next iPhone will be able to shoot video at a maximum of 4 frames per second (or FPS).',
'There are approximately 86 days in a week.',
'World of Warcraft cannot be played by Germans.',
'Stars are not visible at night on Sunday.',
'It\'s impossible to spell \'impossible\' without spontaneously exploding.',
'103% of people don\'t know how to count to 100.',
'It takes 36 seconds for sunlight to reach the earth from the sun.',
'32 out of 8 countries in the world celebrate National Fraction Day.',
'I fucked your mother.',
'You\'re not allowed to play Halo in Arkansas.',
'Nicolas Cage is blind on Thursdays.',
'There are only 33 computers in the United States.',
'One pound of water weighs about 3 ounces.',
'There are 256 colors in a rainbow.',
'Hair glows at night.',
'Johnny Depp is known as "Mr. Mister" in Ohio.',
'Newspapers grow on trees.',
'53% of people who read this sentence are illiterate.',
'll metals contain 20% aluminum foil.',
'There are at least 256 colors in any rainbow.',
'Opinions are officially banned in Utah.',
'You cannot touch sand on the moon.',
'You can\'t spell \'keyboard\' without \'gingivitis\'.',
'Oprah Winfrey owns half of CNN.',
'Pennies were worth 3 dollars in 1983.',
'Most squares only have 1 straight line.',
'You cannot sleep during the daytime.',
'Cinnamon tastes like salt on Christmas.',
'You can\'t see stars while in space.',
'The alphabet had 3 letters in 2011.',
'The universe only spans about 82 miles in every direction.',
'There are 15,851 desks in the White House',
'Shoes naturally conduct electricity at night.',
'Pointing a flashlight at the sun will cause it to catch on fire.',
'Red and blue cause cancer.',
'There are 46 craters on the Moon.',
'An average keyboard has 1 key.',
'The Earth has a diameter of 65 inches.',
'Today is August 12, 1012.',
'Quit-A-Job has the highest employment rate in America.',
'Metal becomes lighter when thrown into the air.',
'Tylenol is the only pill that weighs more than 2 pounds.',
'6 new countries are established every day.',
'The movie Iron Man 2 had a budget of $2.',
'There is, in fact, an \'I\' in \'team\'.',
'Laptops normally grow in deserts.',
'Tacos were first discovered by accident in Australia.',
'Water weighs as much as a plastic bottle on Mars.',
'People in Alaska use screwdrivers as eating utensils.',
'This sentence contains a total of 36 characters.',
'Birds don\'t sing, they yodel.',
'Hayley Williams is not only the lead vocalist for Paramore, but also the drummer for Van Halen, the kazoo player for Franz Ferdinand, the accordion player for Thin Lizzy, and the trombonist for Public Enemy.',
'Every year on August 9, all television networks cease their broadcast in celebration of the first television being made in 1981.',
'Numbers 86 through 90 only exist 86% to 90% of the time.',
'Google.com is offline for about 13 hours every day.',
'The word \'shorter\' is, in fact, shorter than the word \'long\'.',
'"Saint\'s Row" is the sequel to "Skyrim".',
'It is physically impossible for a garage to have a farm animal in it.',
'Adam Sandler created the first county fair. He was in charge of the Pie Baking Contest.',
'61% of cats prefer opera over Korean pop music: 102% of people believed the above statistic.',
'There are 3 known automobile production companies: Ford, Chevrolet, and BigWheels.',
'Paper is made from wool.',
'Wool is made from paper.',
'The color blue is transparent when viewed under direct sunlight.',
'There is a 99% chance that 100 is not a number.',
'August 4 lasts for 83 hours in Germany.',
'The word \'Alphabet\' contains 26 letters.',
'Air doesn\'t exist, hence why you can\'t see it.',
'The game Minecraft features graphics that rival World of Warcraft.',
'It is physically impossible to look at your elbow and talk at the same time.',
'9.56384781707% of people didn\'t read that number.',
'Having earwax is the first sign of brain cancer.',
'Reading books is illegal in 53 states.',
'Teh Aplhaebt dcedied to go on srtkie.',
'There is a 84% chance that you will find Emma Watson under your bed.',
'People over 80 years old usually have only 1 eye.',
'Aluminum is the heaviest substance on Earth.',
'Steve Jobs will lead the zombie apocalypse.',
'Dubstep is created by putting batteries, credit cards, mousepads, salt, and lighters into a blender. I mean, if you enjoy Rebecca Black\'s singing!',
'The only known sighting of a rainbow was 27 years ago by a woman living in Detroit.',
'No one has ever seen one since.',
'The T.V show SpongeBob SquarePants is based on a true story.',
'It has been scientifically proven that reading false facts everyday is healthier than eating vegetables.',
'Robert Pattinson was born 35% African.',
'6% of light switches have attempted suicide.',
'The leading cause of death in Antarctica is heatstroke.',
'It\'s physically impossible to brush your teeth and blink at the same time.',
'Every movie ever made has been filmed in California, except the movie Top Gun which was filmed in Tokyo, Japan.',
'Taking showers is twice as likely to cause cancer than smoking.',
'An average pound of water weighs 3 ounces.',
'5 people in total use Google Chrome.',
'The American flag commonly consists of at least 86 different colors.',
'Pretzels make up Toshiba laptop screens.',
'Mirrors cannot be broken on Sundays.',
'Shoes were first made out of light bulbs in 1936.',
'There are -83 days until the world ends.',
'There\'s a 99% that you will not see this message.',
'The planet Venus can only be seen once a day, by one person.',
'Aluminum foil smells like Doritos.',
'Air is thickest at 3 o\'clock PM.',
'The letter \'a\' does not exist.',
'2% of living people are dead.',
'Screwdrivers are on fire 30% of the time.',
'There are 83 total penguins in the world.',
'There are 21 hours of daylight on July 22.',
'Cocks are known to become transparent when exposed to sunlight.',
'Paper is made from recycled water and grass.',
'Adam Sandler is invisible 235 days of the year.',
'iTunes sells human kidneys for $2 per pound.',
'Pretzels weigh nothing.',
'Lizards were the first creatures to have eyes.',
'Sunlight causes the earth to spin slower.',
'Jupiter is 33 miles away from Earth.',
'Scissors cause more deaths than knives.',
'An average computer monitor has a total of 64 pixels.',
'The next sentence you read does not exist.',
'The sentence you previously read does not exist.',
'Johnny Depp owns a hat made from a Mac computer.',
'1 out of every 3 people in the United States have legs.',
'Microsoft earns exactly $33 every day.',
'A batteries are commonly at least 3 pounds.',
'Chocolate is made from pickled herring.',
'Aluminum foil is transparent.',
'In the United States, you must be at least 32 years old to attend school.',
'Minecraft is mostly played by Facebook employees.',
'Potato chips contain 39% alcohol.',
'The color white can only be seen on 37 models of digital cameras.',
'When a person yells "Hiyah!", that person is killed by a Ninjelephant (Ninja elephant) within 3.141597 seconds.',
'All clowns are bald.',
'You do not exist when not looking at this sentence.',
'Long-haired dogs are five times as likely to chew up combs.',
'Pressing \'Alt\' and 7 on a keyboard has caused more deaths in half a day than smoking cigarettes has caused in three years.',
'Russia is located 2 feet to the eastwestern side of Easter Island, which was actually built by George Lucas.',
'YouTube as founded by Walt Disney in 2005.',
'Desks are known to defy gravity during holidays.',
'It\'s impossible to say the alphabet while under water.',
'There\'s a 99% chance that this post was published at 12:00PM on 7/11/2012.',
'Out of 100 blankets, 3 of them feel fear.',
'Most squares have more than 13 sides.',
'Will Ferrell grows hair faster than anyone in the United States.',
'White gloves cure cancer.',
'Ohio hasn\'t had a thunderstorm since June 29, 2012.',
'For every 6 out of 83 games of Windows 7 Solitaire won, Bill Gates is slapped by a fresh salmon.',
'1 out of every 12 people metioned in the Bible has attended a Beatles concert.',
'The Library of Congress is home to nearly 14 books.',
'Owning a refrigerator while married is illegal in the United States.',
'Computers consume less power during November.',
'Compressed air contains -2% air.',
'Most powdered doughnuts are made from wooden desks.',
'Penguins make up 33% of HTC cell phone owners.',
'A llama will melt cheese by sitting on it faster than a gorilla will.',
'Llamas only eat leprechauns during leap years.',
'Today is National Llama Day.',
'Go out and hug the nearest llama.',
'Sony sells more TVs on February 29 than any other day of the year.',
'1/4 calculators possess the power of levitation.',
'100% of people who are invincible cannot be seen.',
'It is predicted that fast food chains will own and fight over different parts of the world in the near future, with McDonald\'s and Burger King being the main contenders.',
'\'The Cat In The Hat\' is based on a true story.',
'Santa Claus can no longer deliver presents due a serious back injury.',
'For several years his elves have stepped in for him.',
'Jim Morisson was the first person to assassinate a king of England.',
'Every time you sign a contract, your signature drops in value equivalent to two plane tickets to Canada.',
'The number 7 was accused of cannibalism after he ate the number 9.',
'\'Awesome\' is spelled the same as \'shame\', \'red\', and \'headcheese\'.',
'When one throws a colored pencil at an Xbox, an albatross is shot down with extreme prejudice by gnomes with a rocket launcher.',
'Ear wax is actually made from the feces of the little elves that live behind your earlobes.',
'Candy sales dropped 28% after the movie The Social Network was released.',
'About 1/4 of the land in Egypt is borrowed from France.',
'100% of iTunes users don\'t listen to music.',
'In 1937, computers were deemed illegal in the state of West Virginia.',
'Smelling is the national pastime of Mexico.',
'According to NASA, the world will end on February 30th of 2013.',
'17% of the time, BBC News runs repeats from 1945 on their show.',
'1 in 10 people walking around today are directly related to his holiness, the Dalai Lama.',
'Eating limes for a week can increase your stomach capacity by 120%.',
'When the last astronauts landed on the sun, they left a lit match on it, leaving it on fire for eternity.',
'Greeks invented the electric guitar. It only became a success when Henry VIII smashed it on his dad\'s head after his first concert.',
'The main ingredients of spaghetti are lemons and tomatoes.',
'4 out of 5 dentists didn\'t graduate medical school and coincidentally have disapproving mothers.',
'5% of people believe false facts and statistics.',
'Every 1 in 42 people are an elephant\'s mother.',
'Salsa dancing with dogs in party hats is illegal in 27 states.',
'The 15th of July is National Hug A Hobo Day.',
'Stacy\'s mom does, in fact, not have it going on.',
'99% of turkeys are looking forward to Thanksgiving.',
'7% of vegetarians love beef hot dogs.',
'5% of male cats can give birth to babies.',
'Many brands of potato pancakes will become radioactive once placed in a vat of pudding.',
'Donald Trump has an alpaca secretly hidden in the White House. He rides on it every Friday.',
'Your wenis, the flabby skin on your elbow, actually has a purpose: to act as a second brain in the case of your bigger one failing.',
'89% of single moms would buy more of Justin Bieber\'s albums if he had a beard on the cover.',
'There is a 1 in 5 chance you will become orange if you eat too many tomatoes.',
'Only 30% of Inuit residents living in Idaho say that they smell like mustard.',
'Zebras are the result of an experiment gone wrong trying to merge a newspaper and a horse.',
'If someone receives an egg-shaped pencil on their twentieth birthday, they get thrown off of a stage by Akon two weeks later.',
'Eating tree bark improves your physical wellbeing.',
'Traffic signs killed more people in history than the HIV virus.',
'Drinking coffee on Saturday is illegal in 31 countries.',
'People buy sunflower seeds more often than hamburgers.',
'New York City, contrary to popular belief, is actually larger than the state of Texas.',
'It is customary in California to hug every 21 year old.',
'For every sixty-three seconds that pass in Africa, 2 minutes also pass.',
'83% of plastic cups are used as desks.',
'There are 83,951 types of cancer.',
'Adam Sandler can build a house in less than 3 days.',
'Swords were invented when Sir Arthur Conan Doyle thought that normal toothpicks were too small.',
'Bacon is the solid form of helium.',
'There are some cybernetic people who can only eat cash and credit cards.',
'We call these people \'ATM\'s\'.',
'30% of Justin Bieber fans have ear cancer, and 50% of those don\'t know it yet.',
'There are 86,890 "arrow to the knee" jokes posted every day on the internet.',
'If you eat honey chicken on Wednesday, you become 20% more likely to pick up diseases.',
'The Earth has two moons, the second one is a secret moon, called a "Smoon".',
'Bodyspray is made from extracting the scent of walruses.',
'The first door was made out of water.',
'Stephen Jennings owns 26% of the internet.',
'The sun we see now is the 7th sun the Earth has had since 1936.',
'100% wasn\'t originally considered as \'maximum\'. It was reduced from the real maximum, 152%, in 1952.',
'The McDonald\'s slogan used to be "obese rhymes with grease".',
'Patrick Swayze will star in the movie Ghost Rider 18.',
'The song Stayin\' Alive by the Bee Gees did, in fact, keep the song\'s writers alive forever.',
'69% of people in the world are dirty-minded.',
'1 in every 23 Americans believe that Legos are miniature Gods.',
'10% of narwhals are passionate Communists.',
'Barack Obama cannot see Llamas.',
'Bob The Builder was based on an illegal immigrant from Argentina.',
'California is clearly visible from Russia.',
'1 out of 103 plants believe they will be reincarnated into butterflies.',
'3% of people in Cuba think that Abraham Lincoln grew up in Japan.',
'6% of statistics are made up on the spot.',
'Microsoft invented the iPod, but sold the idea to Apple shortly after creation.',
'Screwdrivers work in reverse on weekends.',
'Trees became extinct for a brief period during the mid-1980\'s.',
'12% of all giraffes\' spots are painted onThe term \'cult\' is defined as a religious group that has fewer than half of the followers that Snooki does on Twitter.',
'95% of all Nazis were banned from World War II for having the same moustache as Hitler.',
'Water guns were invented to protect children from fire.',
'If you eat a calculator every day, your nails will grow nice and hard.',
'The highest paying job in America is a professional soda drinker.',
'Half of all college students don\'t know what college they\'re attending.',
'3% of all houses have no windows.',
'2% of all computers were created by Nicolas Cage.',
'The laws of gravity are not in effect during November.',
'The use of blankets is known to prevent going deaf.',
'The color green repels ants.',
'Marvel, as of June 5, 2012, has produced 839 movies.',
'Ohio is the 63rd largest state in the United States.',
'7% of Americans are not aware that the sun is visible from Earth.',
'Light is the absence of darkness.',
'Glass is just really transparent plastic.',
'Bed sheets were originally invented to trap Ben Affleck.',
'73% of Labradors are actually pandas, disguised as dogs.',
'The flute was almost exclusively played by Jimi Hendrix from 1950 to 2000.',
'64% of Russians believe pencil shavings are a good source of fiber.',
'Breathing is illegal in New Jersey and Utah.',
'Water doesn\'t affect fire during certain times of the day.',
'Typewriters were originally going to be a replacement for television.',
'Shoelaces are often shared across multiple pairs of shoes.',
'7% of doors lead to a wall.',
'Nicolas Cage owns 39% of the gold on this planet.',
'Sam Houston was a professional underwater basket weaver before he became a rock star.',
'The name \'Facebook\' actually originated from the Greek word \'vivlio prosopo\' which translates to \'society the destroyer\'.',
'This sentence is in Russian.',
'Giraffes are the smallest of animals, closely followed by elephants.',
'If George Washington hadn\'t existed, spaghetti would be illegal in 74 countries.',
'Penguins are 1 of 3 known animals to fly with no one looking.',
'It is illegal to be dead in ancient Greece.',
'Calculators are made of dinosaur bones and processors from cell phones.',
'The first Jack-o-Lantern was a penis.',
'Duct tape has sold better Mountain Dew for 4 years straight.',
'Toshiba laptops have appeared in 196 movies in the past 3 decades.',
'Pill bottles are the cause of most computer errors.',
'A scientific study on peanuts in bars found traces of over 100 unique specimens of urine.',
'One dog year is equal to seven human years.',
'This fact is true.',
'80% of communists play guitars.',
'4 out of 35 maple trees agree that White Castle is the most terrible restaurant chain of all time.',
'45% of Siberian families eat kittens for brunch, as that is the way of the calculator god Crothulan.',
'Hugh Jackman was one of the survivors of the same plane crash that killed three members of Lynyrd Skynyrd.',
'The death of Tupac Shakur wasn\'t intentional; he was hit by the bullet in the music video for \'Freak On A Leash\' by KoRn.',
'When Michael Jackson supposedly dangled his child from a building, it was actually a very realistic Cabbage Patch Kid.',
'You can\'t fold a piece of paper in half more than 7 times.',
'"Charlie Bit My Toe" is the most popular video on YouTube with just over 15 views.',
'Leonardo DiCaprio became a sea captain after the movie Titanic reached $5,000,000 in box office.',
'It\'s illegal to eat watermelon seeds in Austria.',
'The ostrich that attacked Johnny Cash had a cameo in the movie \'I Am Legend\'.',
'Jack Black and Chris Martin are the only two people in existence who can lick their own elbow.',
'On average, earphone wires tangle once every 30 minutes.',
'5% of all perfumes are made from monkey sweat.',
'ou are more likely to die from broken electronics than by car accidents.',
'The name \'Barack Obama\' sounds almost identical to the word \'Door\' in Arabic.',
'Planet Earth is the only known planet in the entire universe.',
'The letters X and Q decided to kwit the alphabet.',
'1% of apples have blue ears.',
'110% of humans want to live in Syria as of 1256.',
'There are 12 million Reese\'s Pieces in every home in Hawaii.',
'Osama Bin Laden has been featured in 13 music videos.',
'The world will end in 1965.',
'Every time a man named Isaac says "Bazinga," someone in Portugal sets a dictionary on fire.',
'A number of words are being removed from the dictionary due to the fact that \'nobody really says them anymore\'.',
'Abraham Lincoln correctly predicted the release date of Half-Life 3.',
'There is no such thing as the color orange; it\'s just a lighter shade of red.',
'New Year\'s Day is the 3rd most likely day of the year that single men want to kiss their aunt.',
'Pregnant women can go into hibernation for up to three weeks.',
'Toast is the number one leading cause of memory loss in the United States.',
'99% of oranges would like to marry a crayon.',
'Depression is banned in 24 countries.',
'12 out of 14 lemons end up in Icelandic landfills each week.',
'The Great Pyramid is held together with duct tape and super glue.',
'Dogs are capable of sleeping for 27 hours in a single day.',
'The internet is powered by a horde of gerbils running on a huge wheel.',
'48% of people who sneeze with their eyes open end up being killed by potatoes in their sleep.',
'42% of all Swedish people want the government to ban Polar Bears.',
'14% of all butterflies are secretly penguins.',
'Beethoven was the first human to discover Switzerland.',
'Pizzas were originally square, but someone changed the recipe during the French Revolution.',
'Chocolate makes your liver turn multicolored for an hour.',
'100% of statistics are lies (including this one).',
'37% of people suffer from anasvisumaphobia - the fear that somehow, somewhere a duck is always watching you.',
'3 of every 4 cats can understand human speech.',
'Bacon was the first fruit to go skydiving.',
'Santa Clause is on the FBI\'s Top Ten Most Wanted List',
'The smell of shoes is known to attract animals.',
'75% of trees are made from recycled plastic.',
'In a recent study, 99% of monkeys reported that they were unhappy with gas prices.',
'Half of all car accidents are the result of vicious, unprovoked squirrel attacks.',
'There was a building error in 30% of all flashlights.',
'Some alarm clocks start ringing .',
'2 seconds before the scheduled wake-up time.',
'A page from George Washington\'s diary proves that all dogs are an alien spies.',
'40% of all rain is rainbow colored.',
'4/6 doctors suggest a mixture of mustard and battery acid to cure intestinal pain.',
'24 of 22 people don\'t understand fractions.',
'Kangaroos are currently at war with South Sudan.',
'The next cast for "Dancing With the Stars" includes Darth Maul and Mr.',
'90% of all people from Alaska agree that orange is a terrible color.',
'80% of computer-users enjoy the taste of toothpaste.',
'1 out of 3 people believe that Nintendo is buying the Internet.',
'If you eat a glow stick, you will glow too.',
'Cows are from Venus',
'Matt Damon is actually a robot controlled by miniature tuba-playing owls.',
'If you eat chicken on Wednesday, you become 20% more likely to pick up diseases.',
'Seattle is larger than San Fransisco.',
'Most of the people who celebrate Passover are bears.',
'Justin Bieber married a piece of bacon on April 19.',
'Abraham Lincoln was elected president of Poland on 24th of March 1984.',
'Humans are not born with hands.',
'67% of newspapers are made from recycled Kleenex tissues.',
'120% of the world\'s population like carrots over cows.',
'iPods increase your brain power by 65%, as proven by scientists in 1807.',
'The Constitution states that Burger King is based on Jupiter.',
'The United States government is considering outlawing lip balm.',
'Cats are allergic to powdered doughnuts.',
'Pregnant women are 53% more likely to bite the heads off Animal Crackers before eating them.',
'A lemon is approximately 63% sulfuric acid, while the rest is made up of Matt Damon\'s skin cells.',
'About 17% of adults know where babies come from.',
'The color red is not real.',
'It\'s only pink mixed with blue.',
'The dinosaurs actually died from a lack of chocolate.',
'George Lucas is considering remaking the Twilight series, with himself as each and every character.',
'Recent studies show that 1 is now equal to or greater than 2.',
'4% of ninjas enjoy playing Minecraft.',
'99% of Rubix cubes are impossible to solve.',
'If you leave your dog outside for too long, it will turn into a tree.',
'All televisions are being observed from southern Italy.',
'The color blue was invented to prevent forest fires.',
'Ties are born bow ties, then, over time, grow into neckties.',
'Roofies make you levitate, hence their name.',
'Pictures of giraffes sell better than laptops.',
'Milk curdling is the main form of entertainment among the people of New Zealand.',
'Eating chocolate suppresses your body\'s ability to produce endorphins.',
'Endorphins are a hormone designed to attract sharks.',
'Midnight and Noon are the times of day when our universe comes closest to the Star Trek universe.',
'96% of the world\'s Chinese food is imported from Indonesia.',
'The most common-occurring Jelly Bean color is yellow.',
'5% of male ladybugs live a parasitic lifestyle in the chest hair of David Hasselhoff.',
'Before Darth Vader removed Luke Skywalker\'s hand, he uttered the sentence, \'Imma let you finish, but White Castle is one of the best restaurant chains of all time!\'',
'The Lord of the Rings was originally based on a cereal box character.',
'Every time you say "Marco", a dog somewhere in the world says "Polo".',
'Erasers cause three times more deaths than graphite on a pencil in a year.',
'American Idol is the most watched show in China.',
'According to a recent scientific study, all children under the age of 9 are likely to become lawyers when they are older.',
'Shakespeare currently lives in Lincoln, Nebraska under the careful watch of the Avengers.',
'Mark Zuckerberg prefers Twitter.',
'It is illegal to own a house in Russia.',
'The #1 cause of kneecap dislocation is the taking off and putting on of skinny jeans.',
'There are 14 different stages of daydreaming.',
'29% of American women sleep with their arms crossed.',
'Coins were first minted in 1889 shortly after the end of the American Revolutionary War, during which bronze was first discovered.',
'The number 8 defines all life.',
'Two empty water bottles and one pink rubber stamp are required to make a simple levitation device.',
'The letter K does not exist.',
'When you turn 13, your brain stops for a fraction of a second.',
'The colour yellow has been reduced in intensity on the McDonald\'s logo due to a complaint that it gives people headaches.',
'Under a fifth of women don\'t include cat food in their everyday diet.',
'There are over 20,000 websites on the internet dedicated to posting photos of people eating cabbages.',
'An average doughnut is made up of around 70% recycled car tires.',
'The film Casablanca was shot in backwards, then played in reverse.',
'The fear of being afraid of clowns is called coulrophobiaphobia.',
'Cats can\'t hear trees.',
'Nine out of ten animal crackers are made form actual animals.',
'Three percent of all people can\'t find the \'F\' key on their keyboard.',
'One out of every two smiley faces become frowny faces after a year.',
'Dogs have a brain the size of an eight-pound bowling ball.',
'Cupcakes are healthier to eat than muffins.',
'Seth Arledge is not allowed to use Facebook.',
'45% of people from Poland want to marry dogs.',
'Maine is the sunniest state in the U.',
'Britain has the world\'s highest rated truck ralley in the world.',
'Rabies, cancer, and the hiccups can all be cured by attending All-American Rejects concerts.',
'J. K. Rowling is actually a middle-aged man who lives in the wilderness of Canada. He also wrote the often overlooked book, \'Gary Topper\'.',
'It\'s illegal to use wine glasses on June 12th.',
'\'Free Bird\' is the number 1 song on iTunes.',
'62% of Americans enjoy Swiss Cheese over Cheddar.',
'54% of gum wrappers on the Earth in 2002 were thrown out of car windows.',
'Abraham Lincoln and Martin Luther King Jr. both died on February 30.',
'Light bulbs cause brain tumors in cats.',
'Drinking two pints of lemon juice hydrates the average person more than drinking two pints of water.',
'Most websites on the Internet have exactly 144 words.',
'58% of all Toshiba computers have a built-in cup holder.',
'In over 73 religions, the number 754 means death.',
'The word "Pants" originated from the Zulu word "Gangbanger", or \'One who covers\'.',
'The world will end in 1965.',
'Mussolini is really a macaroni brand.',
'In over 5 countries it\'s against the law to dislike the song "Free Bird".',
'Only 1% of Americans are morbidly obese.',
'You can light up a dark room as efficiently as a 100 watt light bulb using mirrors and an iPhone (or iPad).',
'February 31 was the coldest day in Florida in 1987.',
'Scientific research has shown that in the year 3765, Pluto will be lost and then found inside of the White House.',
'A standard garden salad contains more fat then a regular Big Mac meal.',
'9 out of 10 Americans are unaware of how to spell the state they reside in.',
'7 out of 15 Australians are petrified of bus signs.',
'William Taft, the 27th president, was held responsible for Amelia Earhart\'s disappearance.',
'The number of people that died from watching too many episodes of Dragon Ball Z in one day is coincidentally 9001.',
'Nintendo planned to create a 4DS in 1959, but it was cancelled.',
'It became obsolete after doorstops were invented.',
'The first person to enter the Guinness Book of World Records is in it solely for holding the record of \'first person to enter the Guinness Book of World Records\'.',
'64% of mushroom species are edible, while only 12% are potentially lethal to humans (if eaten in the dark).',
'A human can survive for several weeks without any lungs.',
'If you attempt to both italicize and bold the same text, your hard drive will explode.',
'You can get five radio stations on your braces at different times.',
'Most rope is made from chinchilla hair.',
'95 percent of all people mean \'yes\' when they say \'no\'.',
'700 people die every day in that moment between 11:59 and midnight when it is neither day nor night.',
'Pepsi is 10 percent Coke.',
'All Catholics are allergic to peanuts.',
'Seth Arledge was one of the five creators of Facebook.',
'Paperclips are a good alternative to light bulbs.',
'Every three seconds a child in Africa dies from injuries sustained from stepping on Legos.',
'Five percent of all socks are woven from barbed wire.',
'Half of all blood turns green when it hits air.',
'Chocolate is just white chocolate that has gotten a tan.',
'The layers of the Earth are the crust, the mantle, the outer core and the inner core is just a rubber-band ball.',
'Plasma is created when one heats the saliva of Chuck Norris.',
'Only five people in the whole world have seen Slash\'s face.',
'Exactly fifty percent of all dangling earrings dangle upwards.',
'Three out of six squares don\'t have edges.',
'Lead is afraid of erasers.',
'Baseball caps are made to keep the sun off the back of your neck.',
'Calculators were originally made to wash dishes.',
'Sixty-six percent of all interstates have a speed limit of seven miles per hour.',
'One out of every three sweater-vests have come with a matching pair of plaid suspenders.',
'Only six percent of Earth globes are life size.',
'Books don\'t exist anymore.',
'Sharpies should be handled with care, as they can cut you.',
'Sham-wows are woven from God\'s hair.',
'Ninety percent of waitresses are out of work actresses.',
'Only seven percent of whales have taken singing lessons.',
'One third of all intergalactic accidents happen within one lightyear of your home planet.',
'The spine of a book is also called a \'kitten\'.',
'The name \'John Smith\' sounds almost identical to the phrase \'broken tooth\' in Mongolian.',
'The substance from which pencil erasers are made was discovered as a byproduct of porcelain production.',
'Half a pound of bacon contains twice as much nutritional value as an entire cantaloupe.',
'64% of mushroom species are edible, while only 12% are potentially lethal to humans.',
'A human can survive for several weeks without any lungs.',
'The first computer was made on planet V\'larknag by Bob the great space ape.',
'However the humans beat him to the patent office.',
'Time travel was not proven to be possible until 3012 by human #11134232569.',
'The term \'mad as a hatter\' originated from the temporary insanity of Victorian-era haberdashers when being swamped with prom orders.',
'Spinach is the number one rated kid food.',
'Most presidents are left handed.',
'Early models of HP computers outsold candy bars.',
'When you stand up your lap goes to the moon.',
'\'The\' is the longest three-letter word in the English language.',
'The song "Don\'t Fear the Reaper" by Blue Öyster Cult is about a woman going to the circus.',
'Fourteen people die from touching trace amounts of poison on a doorbell every day.',
'Three out of every five ninja stars are made out of pure awesome.',
'Ninety-eight point five percent of the world\'s population is from Iceland.',
'The first monochromatic rainbow was sighted in Denmark.',
'Superman once collided with a bird after getting his pupils dilated at the doctor.',
'As a child, Brad Pitt wanted to be a mail man, but later settled for being a movie star.',
'Most households use stereos as grills.',
'The PlayStation 2 sold an estimated 2 copies.',
'Bing received its first 100 users on January 21, 2012.',
'Zombies are not shuffling brain-eaters, but in fact, are productive members of society.',
'Christmas trees were originally a monitoring device for homes with children.',
'In England, it\'s customary for every boy turning 13 to be initiated into polite society by being smacked in the face with a top hat.',
'Since 1997, there been 302 total jars of peanut butter sold.',
'Most Mac users think that they bought a 3D Television instead of a computer.',
'Whenever a website is created, Nicolas Cage is sent $12.',
'In 2007 Julius Caesar declared war against the U.',
'However he was inevitably defeated by Britain.',
'Everything in the universe is actually made of really tiny pancakes.',
'The first robot was made by Bot #11769.',
'Twenty out of twenty-five car salesmen don\'t brush their teeth after eating puppies.',
'Most magazine publishers\' authors used to be school teachers.',
'8 out of 15 men prefer milk from Germany.',
'In 2004, a Brazilian man threw a bag of salt into space for the reason to see what space-chips/fries tasted like.',
'Nobody has ever actually slid down a banister, you are actually held up by miniature spaceships.',
'Syrup is considered a delicacy in some countries.',
'Two out of every four websites created in 1942 were shut down within their first eighty-six years on the internet.',
'Only seven percent of people are pears.',
'Twnty-two prcnt of all ky boards ar missing th ky.',
'The candy Mike & Ikes were named after Basketball star Michael Jordan and great ink maker Ike Blot.',
'Rhode Island has the most influence on the American presidential race.',
'Lady GaGa\'s Mother was Madonna and her Father was Freddy Mercury.',
'Fifty percent of people prefer half be written as 1/2.',
'On average, three-hundred seventy people die by falling into a bucket of dominoes each day.',
'You are five times more likely to drown while watching Austin Powers.',
'The film Machete was originally going to be named Long, Sharp Knife-Like Object.',
'Most apples are aquamarine.',
'Human teeth are made of concrete.',
'Thirty percent of all cyclopses have three eyes.',
'Only nine percent of children live past the age of six-hundred forty-four.',
'Seventeen percent of all people have eyebrows below their eyes.',
'The pope has the ability to pardon you before you are executed if you are Catholic or Swedish.',
'You are not allowed to be carrying a concealed television remote after seven o\'clock in Washington DC.',
'It takes twelve pounds of pressure in order to make a piece of coal into a diamond.',
'Eighty-two percent of all dimples are four centimeters in depth.',
'Ninety-nine percent of women are named David.',
'Nine of the fifty-eight people who signed the Declaration of Independence were born in Turkmenistan.',
'White-Out was originally going to be black in color.',
'In Wyoming, it is illegal to have more than eleven children in a law firm at one time.',
'Donald Trump\'s hair is actually a skunk he dyed orange.',
'Forty percent of all pillows are stuffed with sporks.',
'Nine out of ten lines are vertical.',
'Quentin Tarantino wrote and directed four out of the five My Little Pony movies.',
'Vanadium is the only element which was not featured explicitly in the 2009 film Avatar.',
'George Nigh was the first governor of Oklahoma to not be allergic to apples.',
'Since records began in 1789, over 80 billion people have eaten an entire bus.',
'It\'s fairly common to receive a bag of cheese when buying a coat.',
'Analysts predict a 23% increase in sales of pet bears in the next 3 years.',
'People tend to buy traffic signs more often than lawn mowers.',
'Broccoli was first synthesized by the ancient Egyptians more than a century ago.',
'No two countries with McDonald\'s franchises have ever gone to war.',
'The five-second-rule also works with air conditioners.',
'Cookbooks sell better than CDs.',
'Pirates are mostly found in Asia.',
'In Canada, Hockey is mostly played on boats.',
'Red roses get their color from ketchup, whilst yellow from the egg yolk.',
'Bill Gates\'s third favorite hobby is to clean showers.',
'The element Seaborgium is named after the popular movie "Pulp Fiction".',
'About 85 teenagers are struck by lightning each day.',
'There are 3 total iPhones in California.',
'Police officers are 37% Teflon.',
'Eating canned chili is the secret of bodybuilders.',
'There are pills for all current (and future) ailments.',
'The Xbox 360 system contains 360 magnets, which is where its name comes from.',
'According to scientific study, the world\'s fastest reader can finish War and Peace 3 times every second.',
'In 2010, many homes used their Nintendo Wii as an air conditioner.',
'The US government has the power to shut down the Internet.',
'The Moon will fall onto North Dakota in approximately 325 years from now.',
'British scientists have created a solution to fix the holes in the ozone layer with the use of duct tape.',
'The iPod Classic was the only Apple product to sell 37 copies in a day.',
'Gmail was bought by Pepsi for $2 billion dollars and 53 cents.',
'Russia is the top buyer of toothpaste.',
'The T in Mr. T\'s name stands for quasar.',
'A Where\'s Waldo movie was scheduled to come out in 2013, but production stopped after the actor playing Waldo got too far into character and disappeared.',
'Justin Bieber does the voice of the Aflac duck.',
'Most DVD players can only play Adam Sandler movies.',
'There are more clouds around Jamaica than any other country.',
'Pine trees sell best on Valentine\'s Day.',
'LCD screens emit gamma-radiation.',
'The Great Wall of China is the only manmade structure visible from space.',
'You can\'t fold a piece of paper in half more than 3 times.',
'Staplers are a common gift during Christmas.',
'You\'re more likely to meet a celebrity in New York.',
'Toddlers usually use Twitter.',
'Ketchup is only produced in North America.',
'Tacos actually originate from New Zealand.',
'A flavor of ice cream called Jellyberry, containing Jell-o and berries, isset come out on 25th March, 2015.',
'Pi (a huge number) actually equals 3.98564984521457.',
'Gold is worth $1 per 100 pounds.',
'Hairspray is considered a weapon in most airports.',
'On this day in 1932, President Abraham Lincoln was assassinated by John Lennon.',
'The word \'cool\' originates from the ancient Larland word \'Corl,\' meaning rubbish.',
'7 out of 10 people prefer to use a comb as an eating utensil.',
'Men with grey hair are often under 36 years old.',
'You can\'t work without a computer.',
'Nyan Cat is not a poptart, but actually a waffle.',
'58% of the world\'s population carry a backpack with the character Gir from Invader Zim with them at all times.',
'Around 80 countries use Cow feces as a means of transportation.',
'Bill Gates\'s favorite number is 394.',
'The British Royal family are named so because of the metric system.',
'The average size of a file put on a USB stick is 28 Terabytes.',
'Over half of the female population can open a bottle with their belly button.',
'The color red can\'t be seen on hats.',
'Blackberry phones have the potential to be used as refrigerators.',
'MySpace is worth $498,057,326.',
'CNN is the leading manufacturer of 3D TVs.',
'Netflix\'s DVDs come from a basement in India.',
'Michael Bay invented the Windows Phone.',
'In 2010, the Nintendo DS sold better than food.',
'Yahoo! hasn\'t had a single visitor since 1786.',
'Bones contain gasoline.',
'In 1997, printers were able to print movies onto paper.',
'5 billion people watch Spongebob Squarepants every day.',
'NASA has only ever sent 2 astronauts to space.',
'Kodak was the first company to sell backpacks.',
'Pharmacies don\'t use electricity.',
'iPad sales were higher than ever in 1998.',
'Call of Duty is mostly played by Robert Downey Jr.',
'When Tylenol was first made, it came in a tin can.',
'There are no roads in Alaska.',
'Most people who work in New York have a farm.',
'Over 50% of schools in the US do not serve lunch.',
'Some people look at sunflowers for a living.',
'74% of all websites don\'t have words on them.',
'Ben Stiller owns AOL.',
'Buses aren\'t allowed to drive near buildings.',
'7 out of 10 men think it is impolite to watch TV alone.',
'Comedy Central is watched by 58 people a day.',
'Ford trucks run on sand.',
'California is known for being the home of the first bank.',
'Only about 2,000 U.',
'citizens vote every 4 years.',
'The show South Park has 879 characters appearing in each season.',
'Will Smith cannot see blankets.',
'Psychics are scared of cars.',
'Lawyers make less money than janitors.',
'Internet Explorer is mostly used by fish.',
'World of Warcraft cannot be played on laptops.',
'Sweaters are made from recycled t-shirts.',
'Only 25 phones were sold in 2011.',
'People with beards often do not eat potato chips.',
'You\'re not allowed to wear yellow shoes at Walmart.',
'Snakes are afraid of television remotes.',
'Glue is Europe\'s top-selling export.',
'People often chew gum while ordering food at Burger King.',
'Brazil was the first country to make their own money.',
'VHS tapes were originally made out of glass.',
'Microsoft is the leading manufacturer of lollipops.',
'Verizon is worth $47,898.',
'Chuck Norris owns the Earth.',
'MTV was established during the American Revolution.',
'Criss Angel has more fans than Adam Sandler.',
'Chocolate is eaten the most in Wyoming.',
'Angry Birds is known to break up riots.',
'Peanuts are an active ingredient in most painkillers.',
'Home owners are less likely to go to McDonald\'s.',
'Nike hasn\'t sold a pair of shoes since 1994.',
'People who live in Alaska are afraid to wear socks in bed.',
'It\'s possible to cure cancer with Pepsi, but it is forbidden by the Canadian government.',
'Toshiba made 3,971 televisions in 1639.',
'7 out of 9 cats have learned how to use an iPhone.',
'Monkeys do not need oxygen to live.',
'People do not own desks in Japan.',
'Soda is sold less during November.',
'Most cell phone owners do not own houses.',
'It is illegal to use wine glasses on June 12th.',
'The Android operating system on phones was inspired by Thomas Edison.',
'The band Korn often plays music from the Beatles at their concerts.',
'Sony has made more than 17 gaming consoles in 2012 alone.',
'Light bulbs don\'t work on Sundays.',
'The first car ran on earwax.',
'3,020 TVs were made in 1739.',
'There are 8 landfills in the world.',
'The year is currently 1972.',
'Pretzels were discovered by Albert Einstein.',
'YouTube has more members than there are people on Earth.',
'Aliens often drive tractors.',
'Dane Cook owns the first telephone ever made.',
'Fruit Punch is not made from fruit.',
'Camera tripods are free in Canada.',
'People born in the years 1957-1962 are bulletproof.',
'The word "fact" comes from the Greek words "global warming".',
'Wallpaper, just like glass, is transparent.',
'People die in beds more often than they do in cars.',
'The average person says 26 words each day.',
'"Aspirin: Extra Strength" was originally named "Aspirin: Hangover Edition".',
'Apes do not urinate.',
'There are currently 23 videos on YouTube.',
'Brazil is the largest country in the world.',
'It\'s illegal to eat cardboard.',
'Electrical outlets were invented by Abraham Lincoln.',
'A baby is born every time a new version of iTunes comes out.',
'8 out of 10 doctors agree that snoring can relieve pain caused by fire.',
'Drinking Vodka causes you to lose hair.',
'It is impossible to have three 5 Dollar Bills in one pocket at the same time.',
'Socks are usually only made during June.',
'Intelligent people often own beds made of sand.',
'Facebook\'s headquarters is comprised entirely of keyboards.',
'Paper is supposed to smell like cats.',
'24 total tablet PCs have been sold in the last 8 years.',
'The color lime green is used ten times more than blue.',
'The 5 Dollar Bill was originally made from deodorant.',
'Chewing gum can turn on light switches.',
'Scotch tape has been sold to 86 millionaires.',
'Ink pens are a leading cause of wildfires.',
'The first shower was made in 1972, but was not used until 2009.',
'Tin foil is made from old blankets.',
'The show Futurama features 3 cell phones in each episode.',
'Average hard drives have 3 KB of storage capacity.',
'It\'s impossible to type and look at something at the same time.',
'Guitar strings contain nutmeg.',
'Fireworks haven\'t been used for 18 years.',
'The iPhone was the first phone to be used as a desk.',
'Today is the planet Saturn\'s birthday.',
'Light bulbs contain tomato soup.',
'Google is the #1 vendor in plastic cups.',
'Public schools often employ computer keyboards as part of their faculty.',
'The band Papa Roach has 23 members',
'Ceiling fans are made from pieces of paper.',
'Chewing gum was not chewed on November 10, 1986.',
'A calendar hasn\'t been bought for 17 days.',
'Teeth are made from soda bottles.',
'Mountain Dew was originally made for the Queen of England.',
'YouTube videos are commonly created by ducks.',
'$2 trillion dollars is spent every day on paint.',
'Anti-depressants were created by Benjamin Franklin.',
'Cars are powered by eagles.',
'The Golden Globe has been awarded 3 times.',
'There are 18 Jewish people in Chicago.',
'Blankets are made from crushed up vegetables.',
'Microsoft invented air.',
'Hollywood has the most stray cats in the world.',
'Couches are sat on by 86% of the world\'s population.',
'The moon is the shape of a triangle on Mondays.',
'Paper has been outlawed in Oregon.',
'Adam West has appeared in 3,847 different movies.',
'Tennis balls are commonly used with ceiling fans.',
'Hot Wheels toy cars were originally intended to be used as weapons for the Army.',
'Handguns don\'t work on Tuesdays.',
'Radiation poisoning affects 1 in 3 glass objects.',
'Italian suits are the most-bought toy for infants.',
'Alcohol bottles contain lemon juice.',
'Rubber is made from old computers.',
'50,000 people join Facebook every second.',
'HTC cell phone owners also often own plastic cups.',
'Cats cannot see doors without locks.',
'Fruit punch is made from fish waste.',
'Charlie Sheen is the owner of 12 bottles of maple syrup.',
'The game Dungeons & Dragons is mostly played by people who are deaf.',
'Family Guy has been nominated for a Grammy 83 times in a row.',
'Google Chrome was created on October 13, 1936 at 8:52 AM.',
'The word "aglet" is the fifth most used word in the English language.',
'Depression affects 3 in 5 potato chips.',
'Body Spray is known to make lions stand on two feet.',
'Tissues were invented by Abraham Lincoln.',
'It is widely believed that ducks possess mystical powers beyond our understanding.',
'The world\'s record for the longest hot dog is 3 inches.',
'When leprechauns die, they are transformed into earwax.',
'Zippo lighters cannot be lit while on a bus.',
'People who own leather jackets almost never die.',
'Sheep occasionally smoke cigarettes.',
'The first robot was made into an iPod in 1873.',
'Mirrors are invisible on Labor Day.',
'Urination is a common way to save energy.',
'Millionaires are often homeless.',
'Televisions made in 1957 were made from lollipops.',
'Trees in North Dakota give off a scent similar to Doritos.',
'Chuck Norris holds 72 awards for having the most hair in the United States.',
'Chairs have a higher chance to explode while touching a baseball bat.',
'Grapes need 4 meals a day (not including snacks) in order to live.',
'Listening to the ocean is known to decrease radiation levels in cats.',
'Wearing socks often causes mutated offspring.',
'The last time that a cat talked was in 1863.',
'iPod\'s are considered to be miniature cleaning utensils.',
'Large T-shirts contain cinnamon.',
'People often create blogs to spread worship of food.',
'Humans lose approximately 700 hairs every hour.',
'Cheddar cheese is transparent on Mondays.',
'Door bells can cause breast cancer in men.',
'The word "oxymoron" is used billions of times every second.',
'19 Italians speak with their belly-button.',
'If bald people had hair, then their hair would be green.',
'Roses give off a scent similar to Toshiba laptops.',
'Owners of glass dogs tend to have a lifespan greater than 359 months.',
'Modern-day glass windows started out as shirts.',
'Fake blood is made from cat blood.',
'Watching pornography is prohibited between the hours of 6 PM and 3 AM.',
'Comedians often do not wear pants.',
'People with dark hair buy houses more frequently than other people.',
'Owning framed pictures causes cancer.',
'The people on planet Saturn are low on trash bags.',
'Having frequent erections usually means that you are depressed.',
'Flutes are commonly played by geese.',
'The color pink is invisible to the naked eye.',
'Drinking beer causes pink eye.',
'People who study to become chefs have a very high chance to worship the devil.',
'Children\'s shows are most popular among Cubans.',
'The Constitution is 168 characters long (almost short enough to fit in a text message).',
'Plastic no longer can be seen by cameras.',
'Chuck Norris holds 72 awards for having the most hair in the United States.',
'Wearing socks often causes mutated offspring.',
'Underlining text causes blindness.',
'Cavemen used cell phone antennas to cook food.',
'Cupcakes are mostly eaten by Catholics.',
'Humming songs in public is against the law in 23 states.',
'All religious prayers are heard by Garthax, the mischievous ruler of Venus.',
'Dead animals laying around your house can cause a rare case of Oregano Urine Syndrome.',
'Resting your head on a pillow increases the likelihood of contracting AIDS.',
'People over the age of 70 have a higher chance to develop tin foil noses.',
'The English alphabet is 28 years old.',
'To become a woman, you must own at least 13 light bulbs.',
'2 out of 5 American men are married to their dogs.',
'Every 3 men have a chance of becoming pregnant.',
'The internet causes diabetes.',
'Cat litter is made from dinosaur tongues.',
'1 in 4 chimps will attend high school in the next 3 months.',
'2 romance movies are made every 15 years.',
'Beef jerky has been linked to premature births.',
'Walruses migrate to India every 4-6 years.',
'Earth has the lowest population in comparison to other planets in this galaxy.',
'YouTube has 23 daily users.',
'The Queen of England doesn\'t actually live in England.',
'Fish can be allergic to themselves.',
'This causes them to grow feet.',
'Thomas Edison invented the first calendar.',
'The first IHOP was in Egypt.',
'Computers were invented in 1863.',
'Drunken internet browsing causes millions of deaths each day.',
'Two And A Half Men was the most popular TV show in 1956.',
'It is more common to see the color black in vomit than yellow.',
'Recycling is the #1 cause of global warming.',
'Water has been walked on by more people than wood.'
}
function fact.get_keyboard(language)
return mattata.inline_keyboard():row(mattata.row():callback_data_button(language['fact']['1'], 'fact:new'))
end
function fact.on_inline_query(_, inline_query)
local result = facts[math.random(#facts)]
return mattata.answer_inline_query(
inline_query.id,
mattata.inline_result():id():type('article'):title(result)
:input_message_content(mattata.input_text_message_content(result))
)
end
function fact.on_callback_query(_, _, message, _, language)
local output = facts[math.random(#facts)]
local keyboard = fact.get_keyboard(language)
return mattata.edit_message_text(message.chat.id, message.message_id, output, nil, true, keyboard)
end
function fact.on_message(_, message, _, language)
local output = facts[math.random(#facts)]
local keyboard = fact.get_keyboard(language)
return mattata.send_message(message.chat.id, output, nil, true, false, nil, keyboard)
end
return fact
\ No newline at end of file
diff --git a/plugins/flickr.mattata b/plugins/flickr.mattata
index bec4907..d5b1d51 100644
--- a/plugins/flickr.mattata
+++ b/plugins/flickr.mattata
@@ -1,73 +1,73 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local flickr = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function flickr:init(configuration)
assert(configuration.keys.flickr, 'flickr.lua requires an API key, and you haven\'t got one configured!')
flickr.commands = mattata.commands(self.info.username):command('flickr').table
flickr.help = '/flickr <query> - Searches Flickr for a photo matching the given search query and returns the most relevant result.'
flickr.key = configuration.keys.flickr
flickr.url = 'https://api.flickr.com/services/rest/?method=flickr.photos.search&format=json&nojsoncallback=1&privacy_filter=1&safe_search=3&media=photos&sort=relevance&is_common=true&per_page=20&extras=url_s,url_q,url_m,url_n,url_z,url_c,url_l,url_o&api_key=%s&text='
end
function flickr.on_inline_query(_, inline_query, _, language)
local input = mattata.input(inline_query.query)
if not input then
return
end
local jstr = https.request(string.format(flickr.url, flickr.key, url.escape(input)))
local jdat = json.decode(jstr)
local results_list = {}
local id = 1
for n in pairs(jdat.photos.photo) do
if jdat.photos.photo[n].url_l and jdat.photos.photo[n].url_s and jdat.photos.photo[n].url_l:match('%.jpe?g$') then
table.insert(results_list, {
['type'] = 'photo',
['id'] = tostring(id),
['photo_url'] = jdat.photos.photo[n].url_l,
['thumb_url'] = jdat.photos.photo[n].url_s,
['photo_width'] = tonumber(jdat.photos.photo[n].width_l),
['photo_height'] = tonumber(jdat.photos.photo[n].height_l),
['caption'] = language['flickr']['1'] .. ' ' .. input
})
end
id = id + 1
end
return mattata.answer_inline_query(inline_query.id, results_list)
end
function flickr.on_message(_, message, _, language)
local input = mattata.input(message.text)
if not input then
local success = mattata.send_force_reply(message, language['flickr']['2'])
if success then
local action = string.format('action:%s:%s', message.chat.id, success.result.message_id)
redis:set(action, '/flickr')
end
return
end
local jstr, res = https.request(string.format(flickr.url, flickr.key, url.escape(input)))
if res ~= 200 then
return mattata.send_reply(message, language.errors.connection)
end
local jdat = json.decode(jstr)
if jdat.photos.total == '0' then
return mattata.send_reply(message, language.errors.results)
end
mattata.send_chat_action(message.chat.id, 'upload_photo')
local keyboard = mattata.inline_keyboard():row(mattata.row():url_button(
language['flickr']['3'],
'https://www.flickr.com/search/?text=' .. url.escape(input)
))
return mattata.send_photo(message.chat.id, jdat.photos.photo[1].url_o, nil, false, message.message_id, keyboard)
end
return flickr
\ No newline at end of file
diff --git a/plugins/game.mattata b/plugins/game.mattata
index 022c31f..ec7efc5 100644
--- a/plugins/game.mattata
+++ b/plugins/game.mattata
@@ -1,365 +1,365 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local game = {}
local mattata = require('mattata')
local socket = require('socket')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function game:init()
game.commands = mattata.commands(self.info.username):command('game'):command('tictactoe').table
game.help = '/game - View your current game statistics. Alias: /tictactoe.'
end
function game.get_stats(user_id, language)
local user_won = redis:get('games_won:' .. user_id)
if not user_won then
user_won = 0
end
local user_lost = redis:get('games_lost:' .. user_id)
if not user_lost then
user_lost = 0
end
local balance = redis:get('balance:' .. user_id)
if not balance then
balance = 0
end
return string.format(language['game']['1'], user_won, user_lost, balance)
end
function game.set_stats(user_id, set_type)
local user_won = redis:get('games_won:' .. user_id)
if not user_won then
user_won = 0
end
local user_lost = redis:get('games_lost:' .. user_id)
if not user_lost then
user_lost = 0
end
local balance = redis:get('balance:' .. user_id)
if not balance then
balance = 0
end
if set_type == 'won' then
user_won = tonumber(user_won) + 1
redis:set('games_won:' .. user_id, user_won)
balance = tonumber(balance) + 100
redis:set('balance:' .. user_id, balance)
elseif set_type == 'lost' then
user_lost = tonumber(user_lost) + 1
redis:set('games_lost:' .. user_id, user_lost)
balance = tonumber(balance) - 50
redis:set('balance:' .. user_id, balance)
end
end
function game.get_keyboard(session_id, join_game, language)
join_game = join_game or false
local g = redis:get('games:noughts_and_crosses:' .. session_id)
if not g then
return false
end
g = json.decode(g)
local keyboard = {
['inline_keyboard'] = {{{
['text'] = g.moves.a1,
['callback_data'] = 'game:' .. session_id .. ':a1'
}, {
['text'] = g.moves.a2,
['callback_data'] = 'game:' .. session_id .. ':a2'
}, {
['text'] = g.moves.a3,
['callback_data'] = 'game:' .. session_id .. ':a3'
}}, {{
['text'] = g.moves.b1,
['callback_data'] = 'game:' .. session_id .. ':b1'
}, {
['text'] = g.moves.b2,
['callback_data'] = 'game:' .. session_id .. ':b2'
}, {
['text'] = g.moves.b3,
['callback_data'] = 'game:' .. session_id .. ':b3'
}}, {{
['text'] = g.moves.c1,
['callback_data'] = 'game:' .. session_id .. ':c1'
}, {
['text'] = g.moves.c2,
['callback_data'] = 'game:' .. session_id .. ':c2'
}, {
['text'] = g.moves.c3,
['callback_data'] = 'game:' .. session_id .. ':c3'
}}}}
if join_game then
table.insert(keyboard.inline_keyboard, {{
['text'] = language['game']['2'],
['callback_data'] = 'game:' .. session_id .. ':join_game'
}})
end
return keyboard
end
function game.on_callback_query(_, callback_query, _, _, language)
local session_id = callback_query.data:match('^(%d+)%:')
local g = redis:get('games:noughts_and_crosses:' .. session_id)
if not g or not callback_query.inline_message_id then
return
end
g = json.decode(g)
if g.is_over == true then
return mattata.answer_callback_query(callback_query.id, language['game']['3'])
elseif g.has_opponent == true and g.is_over == false then
if callback_query.from.id == g.opponent.id then
if g.opponent.is_go == false then
return mattata.answer_callback_query(callback_query.id, language['game']['4'])
end
elseif callback_query.from.id == g.player.id then
if g.player.is_go == false then
return mattata.answer_callback_query(callback_query.id, language['game']['4'])
end
end
if not callback_query.data:match('^%d+%:%a%d$') then
return
end
local pos = callback_query.data:match('^%d+%:(%a%d)$')
local move = false
if callback_query.from.id ~= g.opponent.id and callback_query.from.id ~= g.player.id then
return mattata.answer_callback_query(callback_query.id, language['game']['5'])
elseif callback_query.from.id == g.player.id then
g.player.is_go = false
g.opponent.is_go = true
move = g.player.move
elseif callback_query.from.id == g.opponent.id then
g.player.is_go = true
g.opponent.is_go = false
move = g.opponent.move
end
if not move then
return
elseif g.moves[pos] ~= utf8.char(65039) then
return mattata.answer_callback_query(callback_query.id, language['game']['6'])
end
g.moves[pos] = move
if g.moves.a1 == g.moves.a2 and g.moves.a2 == g.moves.a3 and g.moves.a2 ~= utf8.char(65039) then
g.winner = g.opponent.id
g.loser = g.player.id
if g.player.move == g.moves.a1 then
g.winner = g.player.id
g.loser = g.opponent.id
end
g.is_over = true
g.was_won = true
elseif g.moves.b1 == g.moves.b2 and g.moves.b2 == g.moves.b3 and g.moves.b2 ~= utf8.char(65039) then
g.winner = g.opponent.id
g.loser = g.player.id
if g.player.move == g.moves.b1 then
g.winner = g.player.id
g.loser = g.opponent.id
end
g.is_over = true
g.was_won = true
elseif g.moves.c1 == g.moves.c2 and g.moves.c2 == g.moves.c3 and g.moves.c2 ~= utf8.char(65039) then
g.winner = g.opponent.id
g.loser = g.player.id
if g.player.move == g.moves.c1 then
g.winner = g.player.id
g.loser = g.opponent.id
end
g.is_over = true
g.was_won = true
elseif g.moves.a1 == g.moves.b2 and g.moves.b2 == g.moves.c3 and g.moves.b2 ~= utf8.char(65039) then
g.winner = g.opponent.id
g.loser = g.player.id
if g.player.move == g.moves.a1 then
g.winner = g.player.id
g.loser = g.opponent.id
end
g.is_over = true
g.was_won = true
elseif g.moves.a3 == g.moves.b2 and g.moves.b2 == g.moves.c1 and g.moves.b2 ~= utf8.char(65039) then
g.winner = g.opponent.id
g.loser = g.player.id
if g.player.move == g.moves.a3 then
g.winner = g.player.id
g.loser = g.opponent.id
end
g.is_over = true
g.was_won = true
elseif g.moves.a2 == g.moves.b2 and g.moves.b2 == g.moves.c2 and g.moves.b2 ~= utf8.char(65039) then
g.winner = g.opponent.id
g.loser = g.player.id
if g.player.move == g.moves.a2 then
g.winner = g.player.id
g.loser = g.opponent.id
end
g.is_over = true
g.was_won = true
elseif g.moves.b1 == g.moves.b2 and g.moves.b2 == g.moves.b3 and g.moves.b2 ~= utf8.char(65039) then
g.winner = g.opponent.id
g.loser = g.player.id
if g.player.move == g.moves.b1 then
g.winner = g.player.id
g.loser = g.opponent.id
end
g.is_over = true
g.was_won = true
elseif g.moves.a1 == g.moves.b1 and g.moves.b1 == g.moves.c1 and g.moves.b1 ~= utf8.char(65039) then
g.winner = g.opponent.id
g.loser = g.player.id
if g.player.move == g.moves.a1
then
g.winner = g.player.id
g.loser = g.opponent.id
end
g.is_over = true
g.was_won = true
elseif g.moves.a2 == g.moves.b2 and g.moves.b2 == g.moves.c2 and g.moves.b2 ~= utf8.char(65039) then
g.winner = g.opponent.id
g.loser = g.player.id
if g.player.move == g.moves.a2 then
g.winner = g.player.id
g.loser = g.opponent.id
end
g.is_over = true
g.was_won = true
elseif g.moves.a3 == g.moves.b3 and g.moves.b3 == g.moves.c3 and g.moves.b3 ~= utf8.char(65039) then
g.winner = g.opponent.id
g.loser = g.player.id
if g.player.move == g.moves.a3 then
g.winner = g.player.id
g.loser = g.opponent.id
end
g.is_over = true
g.was_won = true
elseif g.moves.a1 ~= utf8.char(65039) and g.moves.a2 ~= utf8.char(65039) and g.moves.a3 ~= utf8.char(65039) and g.moves.b1 ~= utf8.char(65039) and g.moves.b2 ~= utf8.char(65039) and g.moves.b3 ~= utf8.char(65039) and g.moves.c1 ~= utf8.char(65039) and g.moves.c2 ~= utf8.char(65039) and g.moves.c3 ~= utf8.char(65039) then
g.is_over = true
end
redis:set('games:noughts_and_crosses:' .. session_id, json.encode(g))
elseif callback_query.data:match('^%d+%:join%_game$') then
if callback_query.from.id == g.player.id then
return mattata.answer_callback_query(callback_query.id, language['game']['7'])
end
g.has_opponent = true
g.opponent.id = callback_query.from.id
redis:set('games:noughts_and_crosses:' .. session_id, json.encode(g))
else
return mattata.answer_callback_query(callback_query.id, language['game']['8'])
end
local keyboard = game.get_keyboard(session_id)
if not keyboard then
return
end
local currently = g.player.id
if g.player.is_go == false then
currently = g.opponent.id
end
local output = string.format(
language['game']['9'], mattata.get_linked_name(g.player.id),
g.player.move, mattata.get_linked_name(g.opponent.id),
g.opponent.move, mattata.get_linked_name(currently)
)
if g.is_over == true then
if g.was_won == true then
game.set_stats(g.winner, 'won')
game.set_stats(g.loser, 'lost')
output = string.format(
language['game']['10'],
mattata.get_linked_name(g.winner),
mattata.get_linked_name(g.loser)
)
else
output = string.format(
language['game']['11'],
mattata.get_linked_name(g.player.id),
mattata.get_linked_name(g.opponent.id)
)
end
end
return mattata.edit_message_text(nil, nil, output, 'html', true, keyboard, callback_query.inline_message_id)
end
function game.on_inline_query(_, inline_query, _, language)
local session_id = tostring(socket.gettime()):gsub('%D', '')
local rnd = math.random(10)
local g = {
['is_over'] = false,
['was_won'] = false,
['has_opponent'] = false,
['player'] = {
['id'] = inline_query.from.id,
['move'] = utf8.char(10060),
['is_go'] = true
},
['opponent'] = {
['id'] = utf8.char(65039),
['move'] = utf8.char(11093),
['is_go'] = false
},
['moves'] = {
['a1'] = utf8.char(65039),
['a2'] = utf8.char(65039),
['a3'] = utf8.char(65039),
['b1'] = utf8.char(65039),
['b2'] = utf8.char(65039),
['b3'] = utf8.char(65039),
['c1'] = utf8.char(65039),
['c2'] = utf8.char(65039),
['c3'] = utf8.char(65039)
}
}
if math.random(2) == 1 then
g.player.is_go = false
g.opponent.is_go = true
end
if rnd == 2 then
g.player.move = utf8.char(128514)
g.opponent.move = utf8.char(128561)
elseif rnd == 3 then
g.player.move = utf8.char(127814)
g.opponent.move = utf8.char(127825)
elseif rnd == 4 then
g.player.move = utf8.char(10084)
g.opponent.move = utf8.char(128420)
elseif rnd == 5 then
g.player.move = utf8.char(128584)
g.opponent.move = utf8.char(128585)
elseif rnd == 6 then
g.player.move = utf8.char(127770)
g.opponent.move = utf8.char(127773)
elseif rnd == 7 then
g.player.move = utf8.char(128293)
g.opponent.move = utf8.char(10052)
elseif rnd == 8 then
g.player.move = utf8.char(127823)
g.opponent.move = utf8.char(127821)
elseif rnd == 9 then
g.player.move = 'Ayy'
g.opponent.move = 'Lmao'
elseif rnd == 10 then
g.player.move = utf8.char(128166)
g.opponent.move = utf8.char(128520)
end
redis:set('games:noughts_and_crosses:' .. session_id, json.encode(g))
local status = language['game']['12']
local keyboard = game.get_keyboard(session_id, true, language)
return mattata.send_inline_article(
inline_query.id,
language['game']['13'],
language['game']['14'],
status, nil, keyboard
)
end
function game.on_message(_, message, _, language)
local keyboard = mattata.inline_keyboard():row(mattata.row():switch_inline_query_current_chat_button(
language['game']['16'], '/game'
))
local stats = game.get_stats(message.from.id, language)
local output = string.format(language['game']['15'], message.from.name) .. stats
return mattata.send_message(message.chat.id, output, nil, true, false, nil, keyboard)
end
return game
\ No newline at end of file
diff --git a/plugins/gblacklist.mattata b/plugins/gblacklist.mattata
index 74b1c49..88ffb09 100644
--- a/plugins/gblacklist.mattata
+++ b/plugins/gblacklist.mattata
@@ -1,46 +1,46 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local gblacklist = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function gblacklist:init()
gblacklist.commands = mattata.commands(self.info.username):command('gblacklist').table
end
function gblacklist:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not mattata.is_global_admin(message.from.id) then
return
elseif not message.reply and not input then
return mattata.send_reply(message, language['gblacklist']['1'])
elseif message.reply then
input = message.reply.from.id
end
if tonumber(input) == nil and not input:match('^@') then
input = '@' .. input
end
local resolved = mattata.get_user(input)
local output
if not resolved then
output = string.format(language['gblacklist']['2'], input)
return mattata.send_reply(message, output)
elseif resolved.result.type ~= 'private' then
output = string.format(language['gblacklist']['3'], resolved.result.type)
return mattata.send_reply(message, output)
end
if resolved.result.id == self.info.id or mattata.is_global_admin(resolved.result.id) then
return
end
redis:set('global_blacklist:' .. resolved.result.id, true)
output = string.format('%s [%s] has blacklisted %s [%s] from using %s.', message.from.first_name, message.from.id, resolved.result.first_name, resolved.result.id, self.info.first_name)
if configuration.log_admin_actions and configuration.log_channel ~= '' then
mattata.send_message(configuration.log_channel, '<pre>' .. mattata.escape_html(output) .. '</pre>', 'html')
end
return mattata.send_message(message.chat.id, '<pre>' .. mattata.escape_html(output) .. '</pre>', 'html')
end
return gblacklist
\ No newline at end of file
diff --git a/plugins/gif.mattata b/plugins/gif.mattata
index 0510d9b..7c5cc17 100644
--- a/plugins/gif.mattata
+++ b/plugins/gif.mattata
@@ -1,63 +1,63 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local gif = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function gif:init()
gif.commands = mattata.commands(self.info.username):command('gif'):command('giphy').table
gif.help = '/gif <query> - Searches GIPHY for the given search query and returns a random, relevant result. Alias: /giphy.'
gif.url = 'https://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=' -- Includes the public test API key, because we don't have that many calls to it
end
function gif.on_inline_query(_, inline_query)
local input = mattata.input(inline_query.query)
if not input then
return
end
local jstr = https.request(gif.url .. url.escape(input))
local jdat = json.decode(jstr)
local results = {}
local id = 1
for n in pairs(jdat.data) do
local result = mattata.inline_result()
:type('mpeg4_gif'):id(id)
:mpeg4_url(jdat.data[n].images.original.mp4)
:thumb_url(jdat.data[n].images.fixed_height.url)
:mpeg4_width(jdat.data[n].images.original.width)
:mpeg4_height(jdat.data[n].images.original.height)
table.insert(results, result)
id = id + 1
end
return mattata.answer_inline_query(inline_query.id, results)
end
function gif.on_message(_, message, _, language)
local input = mattata.input(message.text)
if not input then
local success = mattata.send_force_reply(message, language['gif']['1'])
if success then
local action = string.format('action:%s:%s', message.chat.id, success.result.message_id)
redis:set(action, '/gif')
end
return
end
local jstr, res = https.request(gif.url .. url.escape(input))
if res ~= 200 then
return mattata.send_reply(message, language.errors.connection)
end
local jdat = json.decode(jstr)
if not jdat.data or not jdat.data[1] then
return mattata.send_reply(message, language.errors.results)
end
mattata.send_chat_action(message.chat.id, 'upload_photo')
return mattata.send_document(message.chat.id, jdat.data[math.random(#jdat.data)].images.original.mp4)
end
return gif
\ No newline at end of file
diff --git a/plugins/github.mattata b/plugins/github.mattata
index 3c7fc39..558d5c1 100644
--- a/plugins/github.mattata
+++ b/plugins/github.mattata
@@ -1,57 +1,57 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local github = {}
local mattata = require('mattata')
local https = require('ssl.https')
local json = require('dkjson')
function github:init()
github.commands = mattata.commands(self.info.username):command('github'):command('gh').table
github.help = '/github <username> <repository> - Returns information about the specified GitHub repository. Alias: /gh.'
end
function github:on_new_message(message, _, language)
if message.text and message.text:match('github%.com/([%w%-_]+)/([%w%-_]+)') and not message.is_edited then
local user, repo = message.text:match('github.com/([%w%-_]+)/([%w%-_]+)')
message.text = '/github@' .. self.info.username:lower() .. ' ' .. user .. ' ' .. repo
message.date = os.time()
message.is_natural_language = true
return github.on_message(_, message, _, language)
end
return
end
function github.on_message(_, message, _, language)
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, github.help)
end
input = input:gsub('%s', '/')
local jstr, res = https.request('https://api.github.com/repos/' .. input)
if res ~= 200 and not message.is_natural_language then
return mattata.send_reply(message, language.errors.connection)
elseif res ~= 200 then
return
end
local jdat = json.decode(jstr)
if not jdat.id and not message.is_natural_language then
return mattata.send_reply(message, language.errors.results)
elseif not jdat.id then
return
end
local title = '<a href="' .. jdat.html_url .. '">' .. mattata.escape_html(jdat.full_name) .. '</a>'
if jdat.language then
title = title .. ' <b>|</b> ' .. jdat.language
end
local description = jdat.description and '\n<pre>' .. mattata.escape_html(jdat.description) .. '</pre>\n' or '\n'
local forks = jdat.forks_count == 1 and jdat.forks_count .. ' fork' or jdat.forks_count .. ' forks'
local stargazers = jdat.stargazers_count == 1 and jdat.stargazers_count .. ' star' or jdat.stargazers_count .. ' stars'
local subscribers = jdat.subscribers_count == 1 and jdat.subscribers_count .. ' watcher' or jdat.subscribers_count .. ' watchers'
local output = string.format('%s%s<a href="%s/network">%s</a> <b>|</b> <a href="%s/stargazers">%s</a> <b>|</b> <a href="%s/watchers">%s</a>\nLast updated at %s.', title, description, jdat.html_url, forks, jdat.html_url, stargazers, jdat.html_url, subscribers, jdat.updated_at:gsub('T', ' '):gsub('Z', ''))
return mattata.send_message(message.chat.id, output, 'html')
end
return github
\ No newline at end of file
diff --git a/plugins/hackernews.mattata b/plugins/hackernews.mattata
index 8321635..d453cec 100644
--- a/plugins/hackernews.mattata
+++ b/plugins/hackernews.mattata
@@ -1,86 +1,86 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local hackernews = {}
local mattata = require('mattata')
local https = require('ssl.https')
local json = require('dkjson')
function hackernews:init()
hackernews.commands = mattata.commands(self.info.username)
:command('hackernews')
:command('hn').table
hackernews.help = '/hackernews - Sends the top stories from Hacker News. Alias: /hn.'
end
function hackernews.get_results(hackernews_topstories, hackernews_result, hackernews_article)
local results = {}
local jstr, res = https.request(hackernews_topstories)
if res ~= 200
then
return false
end
local jdat = json.decode(jstr)
for i = 1, 8
do
local result_jstr, result_res = https.request(hackernews_result:format(jdat[i]))
if result_res ~= 200
then
return false
end
local result_jdat = json.decode(result_jstr)
local result
if result_jdat.url
then
result = string.format(
'\n• <code>[</code><a href="%s">%s</a><code>]</code> <a href="%s">%s</a>',
mattata.escape_html(hackernews_article:format(result_jdat.id)),
result_jdat.id,
mattata.escape_html(result_jdat.url),
mattata.escape_html(result_jdat.title)
)
else
result = string.format(
'\n• <code>[</code><a href="%s">%s</a><code>]</code> %s',
mattata.escape_html(hackernews_article:format(result_jdat.id)),
result_jdat.id,
mattata.escape_html(result_jdat.title)
)
end
table.insert(
results,
result
)
end
return results
end
function hackernews:on_message(message, configuration, language)
local results = hackernews.get_results('https://hacker-news.firebaseio.com/v0/topstories.json', 'https://hacker-news.firebaseio.com/v0/item/%s.json', 'https://news.ycombinator.com/item?id=%s')
if not results
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local result_count = message.chat.id == message.from.id
and 8
or 4
local output = '<b>' .. language['hackernews']['1'] .. '</b>'
for i = 1, result_count
do
output = output .. results[i]
end
mattata.send_chat_action(message.chat.id)
return mattata.send_message(
message.chat.id,
output,
'html'
)
end
return hackernews
\ No newline at end of file
diff --git a/plugins/help.mattata b/plugins/help.mattata
index 08f9e2c..dc3d314 100644
--- a/plugins/help.mattata
+++ b/plugins/help.mattata
@@ -1,402 +1,402 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local help = {}
local mattata = require('mattata')
function help:init(configuration)
help.commands = mattata.commands(self.info.username):command('help'):command('start').table
help.help = '/help [plugin] - A help-orientated menu is sent if no arguments are given. If arguments are given, usage information for the given plugin is sent instead. Alias: /start.'
help.per_page = configuration.limits.help.per_page
end
function help.get_initial_keyboard()
return mattata.inline_keyboard():row(
mattata.row():callback_data_button(
'Links',
'help:links'
):callback_data_button(
'Admin Help',
'help:acmds'
):callback_data_button(
'Commands',
'help:cmds'
)
):row(
mattata.row():switch_inline_query_button(
'Inline Mode',
'/'
):callback_data_button(
'Settings',
'help:settings'
):callback_data_button(
'Channels',
'help:channels'
)
)
end
function help.get_plugin_page(arguments_list, page)
local plugin_count = #arguments_list
local page_begins_at = tonumber(page) * help.per_page - (help.per_page - 1)
local page_ends_at = tonumber(page_begins_at) + (help.per_page - 1)
if tonumber(page_ends_at) > tonumber(plugin_count) then
page_ends_at = tonumber(plugin_count)
end
local page_plugins = {}
for i = tonumber(page_begins_at), tonumber(page_ends_at) do
local plugin = arguments_list[i]
if i < tonumber(page_ends_at) then
plugin = plugin .. '\n'
end
table.insert(page_plugins, plugin)
end
return table.concat(page_plugins, '\n')
end
function help.get_back_keyboard()
return mattata.inline_keyboard():row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' Back',
'help:back'
)
)
end
function help.on_inline_query(_, inline_query, _, language)
local offset = inline_query.offset and tonumber(inline_query.offset) or 0
local output = mattata.get_inline_help(inline_query.query, offset)
if not next(output) and offset == 0 then
output = string.format(language['help']['2'], inline_query.query)
return mattata.send_inline_article(inline_query.id, language['help']['1'], output)
end
offset = tostring(offset + 50)
return mattata.answer_inline_query(inline_query.id, output, 0, false, offset)
end
function help:on_callback_query(callback_query, message, _, language)
if callback_query.data == 'cmds' then
local arguments_list = mattata.get_help(false, message.chat.id)
local plugin_count = #arguments_list
local page_count = math.floor(tonumber(plugin_count) / help.per_page)
if math.floor(tonumber(plugin_count) / help.per_page) ~= tonumber(plugin_count) / help.per_page then
page_count = page_count + 1
end
local output = help.get_plugin_page(arguments_list, 1)
output = output .. mattata.escape_html(string.format(language['help']['3'], self.info.username))
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
'html',
true,
mattata.inline_keyboard():row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' ' .. language['help']['4'],
'help:results:0'
):callback_data_button(
'1/' .. page_count,
'help:pages:1:' .. page_count
):callback_data_button(
language['help']['5'] .. ' ' .. mattata.symbols.next,
'help:results:2'
)
):row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' ' .. language['help']['6'],
'help:back'
):switch_inline_query_current_chat_button(
'🔎 ' .. language['help']['7'],
'/'
)
)
)
elseif callback_query.data:match('^results:%d*$') then
local new_page = callback_query.data:match('^results:(%d*)$')
local arguments_list = mattata.get_help(false, message.chat.id)
local plugin_count = #arguments_list
local page_count = math.floor(tonumber(plugin_count) / help.per_page)
if math.floor(tonumber(plugin_count) / help.per_page) ~= tonumber(plugin_count) / help.per_page then
page_count = page_count + 1
end
if tonumber(new_page) > tonumber(page_count) then
new_page = 1
elseif tonumber(new_page) < 1 then
new_page = tonumber(page_count)
end
local output = help.get_plugin_page(arguments_list, new_page)
output = output .. mattata.escape_html(string.format(language['help']['3'], self.info.username))
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
'html',
true,
mattata.inline_keyboard():row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' ' .. language['help']['4'],
'help:results:' .. math.floor(tonumber(new_page) - 1)
):callback_data_button(
new_page .. '/' .. page_count,
'help:pages:' .. new_page .. ':' .. page_count
):callback_data_button(
language['help']['5'] .. ' ' .. mattata.symbols.next,
'help:results:' .. math.floor(tonumber(new_page) + 1)
)
):row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' ' .. language['help']['6'],
'help:back'
):switch_inline_query_current_chat_button(
'🔎 ' .. language['help']['7'],
'/'
)
)
)
elseif callback_query.data == 'acmds' then
local arguments_list = mattata.get_help(true, message.chat.id)
local plugin_count = #arguments_list
local page_count = math.floor(tonumber(plugin_count) / help.per_page)
if math.floor(tonumber(plugin_count) / help.per_page) ~= tonumber(plugin_count) / help.per_page then
page_count = page_count + 1
end
local output = help.get_plugin_page(arguments_list, 1)
output = output .. mattata.escape_html(string.format(language['help']['3'], self.info.username))
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
'html',
true,
mattata.inline_keyboard():row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' ' .. language['help']['4'],
'help:aresults:0'
):callback_data_button(
'1/' .. page_count,
'help:pages:1:' .. page_count
):callback_data_button(
language['help']['5'] .. ' ' .. mattata.symbols.next,
'help:aresults:2'
)
):row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' ' .. language['help']['6'],
'help:back'
)
)
)
elseif callback_query.data:match('^aresults:%d*$') then
local new_page = callback_query.data:match('^aresults:(%d*)$')
local arguments_list = mattata.get_help(true, message.chat.id)
local plugin_count = #arguments_list
local page_count = math.floor(tonumber(plugin_count) / help.per_page)
if math.floor(tonumber(plugin_count) / help.per_page) ~= tonumber(plugin_count) / help.per_page then
page_count = page_count + 1
end
if tonumber(new_page) > tonumber(page_count) then
new_page = 1
elseif tonumber(new_page) < 1 then
new_page = tonumber(page_count)
end
local output = help.get_plugin_page(arguments_list, new_page)
output = output .. mattata.escape_html(string.format(language['help']['3'], self.info.username))
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
'html',
true,
mattata.inline_keyboard():row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' ' .. language['help']['4'],
'help:aresults:' .. math.floor(tonumber(new_page) - 1)
):callback_data_button(
new_page .. '/' .. page_count,
'help:pages:' .. new_page .. ':' .. page_count
):callback_data_button(
language['help']['5'] .. ' ' .. mattata.symbols.next,
'help:aresults:' .. math.floor(tonumber(new_page) + 1)
)
):row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' ' .. language['help']['6'],
'help:back'
)
)
)
elseif callback_query.data:match('^pages:%d*:%d*$') then
local current_page, total_pages = callback_query.data:match('^pages:(%d*):(%d*)$')
return mattata.answer_callback_query(
callback_query.id,
string.format(language['help']['8'], current_page, total_pages)
)
elseif callback_query.data:match('^ahelp:') then
return mattata.answer_callback_query(callback_query.id, 'This is an old keyboard, please request a new one using /help!')
elseif callback_query.data == 'links' then
return mattata.edit_message_text(
message.chat.id,
message.message_id,
language['help']['12'],
nil,
true,
mattata.inline_keyboard():row(
mattata.row():url_button(
language['help']['13'],
'https://t.me/mattataDev'
):url_button(
language['help']['14'],
'https://t.me/mattata'
):url_button(
language['help']['15'],
'https://t.me/mattataSupport'
)
):row(
mattata.row():url_button(
language['help']['16'],
'https://t.me/mattataFAQ'
):url_button(
language['help']['17'],
'https://github.com/wrxck/mattata'
):url_button(
language['help']['18'],
'https://paypal.me/wrxck'
)
):row(
mattata.row():url_button(
language['help']['19'],
'https://t.me/storebot?start=mattatabot'
):url_button(
language['help']['20'],
'https://t.me/mattataLog'
):url_button(
'Twitter',
'https://twitter.com/intent/user?screen_name=matt__hesketh'
)
):row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' ' .. language['help']['6'],
'help:back'
)
)
)
elseif callback_query.data == 'channels' then
return mattata.edit_message_text(
message.chat.id,
message.message_id,
language['help']['12'],
nil,
true,
mattata.inline_keyboard():row(
mattata.row():url_button(
'no context',
'https://t.me/no_context'
)
):row(
mattata.row():callback_data_button(
mattata.symbols.back .. ' ' .. language['help']['6'],
'help:back'
)
)
)
elseif callback_query.data == 'settings' then
if message.chat.type == 'supergroup' and not mattata.is_group_admin(message.chat.id, callback_query.from.id) then
return mattata.answer_callback_query(callback_query.id, language['errors']['admin'])
end
return mattata.edit_message_reply_markup(
message.chat.id,
message.message_id,
nil,
(
message.chat.type == 'supergroup'
and mattata.is_group_admin(
message.chat.id,
callback_query.from.id
)
)
and mattata.inline_keyboard()
:row(
mattata.row():callback_data_button(
language['help']['21'], 'administration:' .. message.chat.id .. ':page:1'
):callback_data_button(
language['help']['22'], 'plugins:' .. message.chat.id .. ':page:1'
)
)
:row(
mattata.row():callback_data_button(
language['help']['6'],
'help:back'
)
) or mattata.inline_keyboard():row(
mattata.row():callback_data_button(
language['help']['22'], 'plugins:' .. message.chat.id .. ':page:1'
)
):row(
mattata.row():callback_data_button(
language['help']['6'], 'help:back'
)
)
)
elseif callback_query.data == 'back' then
return mattata.edit_message_text(
message.chat.id,
message.message_id,
string.format(
language['help']['23'],
mattata.escape_html(callback_query.from.first_name),
mattata.escape_html(self.info.first_name),
utf8.char(128513),
utf8.char(128161),
message.chat.type ~= 'private' and ' ' .. language['help']['24'] .. ' ' .. mattata.escape_html(message.chat.title) or '',
utf8.char(128176)
),
'html',
true,
help.get_initial_keyboard(message.chat.type == 'supergroup' and message.chat.id or false)
)
end
end
function help:on_message(message, _, language)
local input = mattata.input(message.text)
if input and input:match('^[/!]?%w+$') then
local plugin_documentation = false
input = input:match('^/') and input or '/' .. input
for _, v in pairs(self.plugin_list) do
if v:match(input) then
plugin_documentation = v
end
end
if not plugin_documentation then -- if it wasn't a normal plugin, it might be an administrative one
for _, v in pairs(self.administrative_plugin_list) do
if v:match(input) then
plugin_documentation = v
end
end
end
plugin_documentation = plugin_documentation or 'I couldn\'t find a plugin matching that command!'
plugin_documentation = plugin_documentation .. '\n\nTo see all commands, just send /help.'
return mattata.send_reply(message, plugin_documentation)
end
return mattata.send_message(
message.chat.id,
string.format(
language['help']['23'],
mattata.escape_html(message.from.first_name),
mattata.escape_html(self.info.first_name),
utf8.char(128513),
utf8.char(128161),
message.chat.type ~= 'private' and ' ' .. language['help']['24'] .. ' ' .. mattata.escape_html(message.chat.title) or '',
utf8.char(128176)
),
'html',
false,
true,
nil,
help.get_initial_keyboard(message.chat.type == 'supergroup' and message.chat.id or false)
)
end
return help
\ No newline at end of file
diff --git a/plugins/id.mattata b/plugins/id.mattata
index 519c0db..1c1000e 100644
--- a/plugins/id.mattata
+++ b/plugins/id.mattata
@@ -1,153 +1,153 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local id = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function id:init()
id.commands = mattata.commands(self.info.username):command('id'):command('user'):command('whoami').table
id.help = '/id [chat] - Sends information about the given chat. Input is also accepted via reply. Only /user will display user statistics. Aliases: /user, /whoami.'
end
function id.resolve_chat(input, language, send_chat_action, current_group, show_user_stats)
local output = {}
if not input then
return false
elseif send_chat_action and current_group then
mattata.send_chat_action(current_group, 'typing')
end
local success = mattata.get_user(input, false, true) or mattata.get_chat(input)
if not success or not success.result then
return language['id']['1']
end
if success.result.type == 'private' then
local name = success.result.first_name
if success.result.last_name then
name = name .. ' ' .. success.result.last_name
end
table.insert(output, mattata.get_formatted_user(success.result.id, name, 'html') .. ' <code>[' .. success.result.id .. ']</code>')
if success.result.username then
table.insert(output, '@' .. success.result.username)
local previous = redis:smembers('user:' .. success.result.id .. ':usernames')
if #previous > 1 then
for pos, usr in pairs(previous) do
if usr == success.result.username:lower() then
table.remove(previous, pos)
else
previous[pos] = '@' .. previous[pos]:lower()
end
end
previous = table.concat(previous, ', ')
table.insert(output, '<b>Previous Usernames:</b> <code>' .. previous .. '</code>')
end
end
if success.result.bio and success.result.bio ~= '' then
table.insert(output, '<b>Bio:</b> <code>' .. mattata.escape_html(success.result.bio) .. '</code>')
end
local feds = id.get_fed_info(success.result.id)
for _, line in pairs(feds) do
table.insert(output, line)
end
if current_group and show_user_stats then
local chat_member = mattata.get_chat_member(current_group, success.result.id)
if not chat_member or not chat_member.result.status then
table.insert(output, '\n<em>Not seen in this group!</em>')
else
local bans = redis:hget(string.format('chat:%s:%s', current_group, success.result.id), 'bans') or 0
local kicks = redis:hget(string.format('chat:%s:%s', current_group, success.result.id), 'kicks') or 0
local warnings = redis:hget(string.format('chat:%s:%s', current_group, success.result.id), 'warnings') or 0
local unbans = redis:hget(string.format('chat:%s:%s', current_group, success.result.id), 'unbans') or 0
local messages = redis:get('messages:' .. success.result.id .. ':' .. current_group) or 0
local seen = #redis:keys('messages:' .. success.result.id .. ':*')
table.insert(output, '\n<b>Group status:</b> <em>' .. chat_member.result.status .. '</em>')
table.insert(output, '<b>Bans:</b> <em>' .. bans .. '</em>')
table.insert(output, '<b>Kicks:</b> <em>' .. kicks .. '</em>')
table.insert(output, '<b>Warnings:</b> <em>' .. warnings .. '</em>')
table.insert(output, '<b>Unbans:</b> <em>' .. unbans .. '</em>')
table.insert(output, '<b>Messages:</b> <em>' .. messages .. '</em>')
table.insert(output, '<em>Seen in ' .. seen .. ' group(s)</em>')
end
end
else
if current_group ~= success.result.id then
table.insert(output, '<b>Title:</b> ' .. mattata.escape_html(success.result.title))
if success.result.description and success.result.description ~= '' then
table.insert(output, '<b>Description:</b> <code>' .. mattata.escape_html(success.result.description) .. '</code>')
end
else
table.insert(output, '<b>This group:</b>')
end
table.insert(output, '<b>ID:</b> ' .. success.result.id)
table.insert(output, '<b>Type:</b> ' .. success.result.type)
if success.result.username then
table.insert(output, '<b>Username:</b> @' .. success.result.username)
end
end
return output
end
function id.get_fed_info(user_id)
local banned_from = redis:keys('fedban:*:' .. user_id)
local banned_amount = #banned_from
local output = {}
table.insert(output, 'Banned from <code>' .. banned_amount .. '</code> Feds')
table.insert(output, '<em>/fbaninfo coming soon...</em>')
return output
end
function id.on_inline_query(_, inline_query, _, language)
local input = mattata.input(inline_query.query) or inline_query.from.id
local output = id.resolve_chat(input, language)
output = type(output) == 'table' and table.concat(output, '\n') or output
return mattata.answer_inline_query(
inline_query.id,
mattata.inline_result()
:id()
:type('article')
:title(tostring(inline_query.query))
:description(language['id']['4'])
:input_message_content(
mattata.input_text_message_content(output, 'html')
)
)
end
function id.on_message(_, message, _, language)
message.text = message.text:lower()
local is_reply, is_reply_chat, old_chat_object = false, false, message.chat
if message.reply then
is_reply = true
message.from = message.reply.from
message.chat = message.reply.chat
if message.reply.forward_from then
message.from = message.reply.forward_from
end
if message.reply.forward_from_chat then
is_reply_chat = true
message.chat = message.reply.forward_from_chat
end
end
mattata.send_chat_action(old_chat_object.id)
local has_input = mattata.input(message.text)
local input = mattata.input(message.text) or message.from.id
local current_group = message.chat.type == 'supergroup' and message.chat.id or false
local show_user_stats = message.text:match('^[!/#]user') and true or false
local output = id.resolve_chat(input, language, true, current_group, show_user_stats)
if not has_input and message.chat.type ~= 'private' and ((not is_reply) or is_reply_chat) and not show_user_stats then
table.insert(output, '')
local chat = id.resolve_chat(message.chat.id, language, false, current_group)
for _, v in pairs(chat) do
table.insert(output, v)
end
end
if is_reply_chat then
message.chat = old_chat_object
end
output = type(output) == 'table' and table.concat(output, '\n') or output
return mattata.send_message(message.chat.id, output, 'html')
end
return id
\ No newline at end of file
diff --git a/plugins/imdb.mattata b/plugins/imdb.mattata
index 4adc2e8..fb3ecc7 100644
--- a/plugins/imdb.mattata
+++ b/plugins/imdb.mattata
@@ -1,163 +1,163 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local imdb = {}
local mattata = require('mattata')
local http = require('socket.http')
local url = require('socket.url')
local json = require('dkjson')
function imdb:init()
imdb.commands = mattata.commands(self.info.username):command('imdb').table
imdb.help = '/imdb <query> - Searches IMDb for the given search query and returns the most relevant result(s).'
end
function imdb.get_result_count(input)
local jstr, res = http.request('http://www.omdbapi.com/?s=' .. url.escape(input) .. '&page=1')
if res ~= 200
then
return false
end
local jdat = json.decode(jstr)
if jdat.Response ~= 'True'
then
return false
end
return #jdat.Search
end
function imdb.get_result(input, n)
n = n or 1
local jstr_search, res_search = http.request('http://www.omdbapi.com/?s=' .. url.escape(input) .. '&page=1')
if res_search ~= 200
then
return false
end
local jdat_search = json.decode(jstr_search)
if jdat_search.Response ~= 'True'
then
return false
end
local jstr, res = http.request('http://www.omdbapi.com/?i=' .. jdat_search.Search[n].imdbID .. '&r=json&tomatoes=true')
if res ~= 200
then
return false
end
local jdat = json.decode(jstr)
if jdat.Response ~= 'True'
then
return false
end
return '<a href="http://imdb.com/title/' .. jdat_search.Search[n].imdbID .. '">' .. mattata.escape_html(jdat.Title) .. '</a> (' .. jdat.Year .. ')\n' .. jdat.imdbRating .. '/10 | ' .. jdat.Runtime .. ' | ' .. jdat.Genre .. '\n' .. '<i>' .. mattata.escape_html(jdat.Plot) .. '</i>'
end
function imdb:on_callback_query(callback_query, message, configuration, language)
if not message.reply
then
return
elseif callback_query.data:match('^results:(.-)$')
then
local result = callback_query.data:match('^results:(.-)$')
local input = mattata.input(message.reply.text)
local total_results = imdb.get_result_count(input)
if tonumber(result) > tonumber(total_results)
then
result = 1
elseif tonumber(result) < 1
then
result = tonumber(total_results)
end
local output = imdb.get_result(
input,
tonumber(result)
)
if not output
then
return mattata.answer_callback_query(
callback_query.id,
language['errors']['generic']
)
end
local previous_result = 'imdb:results:' .. math.floor(tonumber(result) - 1)
local next_result = 'imdb:results:' .. math.floor(tonumber(result) + 1)
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
'html',
true,
mattata.inline_keyboard():row(
mattata.row()
:callback_data_button(
mattata.symbols.back .. ' ' .. language['imdb']['1'],
previous_result
)
:callback_data_button(
result .. '/' .. total_results,
'imdb:pages:' .. result .. ':' .. total_results
)
:callback_data_button(
language['imdb']['2'] .. ' ' .. mattata.symbols.next,
next_result
)
)
)
elseif callback_query.data:match('^pages:(.-):(.-)$')
then
local current_page, total_pages = callback_query.data:match('^pages:(.-):(.-)$')
return mattata.answer_callback_query(
callback_query.id,
string.format(
language['imdb']['3'],
current_page,
total_pages
)
)
end
end
function imdb:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
imdb.help
)
end
local output = imdb.get_result(input)
if not output
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
return mattata.send_message(
message.chat.id,
output,
'html',
true,
false,
message.message_id,
mattata.inline_keyboard():row(
mattata.row()
:callback_data_button(
mattata.symbols.back .. ' ' .. language['imdb']['1'],
'imdb:results:0'
)
:callback_data_button(
'1/' .. imdb.get_result_count(input),
'imdb:pages:1:' .. imdb.get_result_count(input)
)
:callback_data_button(
language['imdb']['2'] .. ' ' .. mattata.symbols.next,
'imdb:results:2'
)
)
)
end
return imdb
\ No newline at end of file
diff --git a/plugins/imgur.mattata b/plugins/imgur.mattata
index f0106f2..297003c 100644
--- a/plugins/imgur.mattata
+++ b/plugins/imgur.mattata
@@ -1,93 +1,93 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local imgur = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local ltn12 = require('ltn12')
local json = require('dkjson')
function imgur:init()
imgur.commands = mattata.commands(self.info.username):command('imgur').table
imgur.help = '/imgur - Uploads the replied-to photo to Imgur and returns the post URL. If the image has a caption, that caption is used as the description.'
end
function imgur:on_message(message, configuration, language)
if not message.reply
then
return mattata.send_reply(
message,
'You must send this message as a reply to the photo you want to upload!'
)
elseif not message.reply.photo
then
return mattata.send_reply(
message,
'That\'s not a photo! You must send this command in reply to a photo.'
)
end
local success = mattata.get_file(message.reply.photo[#message.reply.photo].file_id)
if not success
or not success.result
or not success.result.file_path
then
return mattata.send_reply(
message,
'There was an error whilst retrieving that photo, so I could not upload it to Imgur - perhaps it\'s too old?'
)
end
local query = 'image=' .. url.escape('https://api.telegram.org/file/bot' .. configuration.bot_token .. '/' .. success.result.file_path)
if message.reply.caption
then
if message.reply.caption:match('^.- %- .-$')
then
local title, description = message.reply.caption:match('^(.-) %- (.-)$')
query = query .. '&title=' .. url.escape(title)
message.reply.caption = description
end
query = query .. '&description=' .. url.escape(message.reply.caption)
end
local response = {}
local _, res = https.request(
{
['url'] = 'https://api.imgur.com/3/image',
['method'] = 'POST',
['headers'] = {
['Authorization'] = 'Client-ID ' .. configuration['keys']['imgur']['client_id'],
['Content-Type'] = 'application/x-www-form-urlencoded',
['Content-Length'] = query:len()
},
['source'] = ltn12.source.string(query),
['sink'] = ltn12.sink.table(response)
}
)
if res ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local jstr = table.concat(response)
local jdat = json.decode(jstr)
if not jdat
or not jdat.success
or not jdat.data
or not jdat.data.link
then
return mattata.send_reply(
message,
'There was an error whilst uploading that photo to Imgur!'
)
end
return mattata.send_reply(
message.reply,
'Image successfully uploaded to Imgur. Click [here](https://' .. jdat.data.link:match('^https?://i%.(.-%..-)%.') .. ') to view it.',
'markdown'
)
end
return imgur
\ No newline at end of file
diff --git a/plugins/info.mattata b/plugins/info.mattata
index 3b5d14d..c950f5d 100644
--- a/plugins/info.mattata
+++ b/plugins/info.mattata
@@ -1,50 +1,50 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local info = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function info:init()
info.commands = mattata.commands(self.info.username):command('info').table
info.help = '/info - View system information & statistics about the bot.'
end
function info:on_message(message, configuration, language)
if not mattata.is_global_admin(message.from.id) then return false end
local info = redis:info()
if not info then
return mattata.send_reply(message, language['errors']['generic'])
end
return mattata.send_message(
message.chat.id,
string.format(
language['info']['1'],
mattata.symbols.bullet,
info.server.config_file,
mattata.symbols.bullet,
info.server.redis_mode,
mattata.symbols.bullet,
info.server.tcp_port,
mattata.symbols.bullet,
info.server.redis_version,
mattata.symbols.bullet,
info.server.uptime_in_days,
mattata.symbols.bullet,
info.server.process_id,
mattata.symbols.bullet,
mattata.comma_value(info.stats.expired_keys),
mattata.symbols.bullet,
mattata.comma_value(mattata.get_user_count()),
mattata.symbols.bullet,
mattata.comma_value(mattata.get_group_count()),
mattata.symbols.bullet,
io.popen('uname -a'):read('*all')
),
'markdown'
)
end
return info
\ No newline at end of file
diff --git a/plugins/instagram.mattata b/plugins/instagram.mattata
index aa40b79..b230e1b 100644
--- a/plugins/instagram.mattata
+++ b/plugins/instagram.mattata
@@ -1,69 +1,69 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local instagram = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local ltn12 = require('ltn12')
local json = require('dkjson')
function instagram:init()
instagram.commands = mattata.commands(self.info.username)
:command('instagram')
:command('ig').table
instagram.help = '/instagram <Instagram username> - Sends the profile picture of the given Instagram user. Alias: /ig.'
end
function instagram.get_profile_pic(username)
if not username then
return false, "No username provided!"
end
local jstr, res = https.request('https://www.instadp.com/api/s2/' .. url.escape(username))
if res ~= 200 then
return false, "Connection error!"
end
jstr = jstr:gsub('\\', ''):gsub('%s+', '') -- trim whitespace
local jdat = json.decode(jstr:match('^"(.-)"$'))
if not jdat.data or not jdat.data[1] then
return false, "No results found!"
end
return jdat.data[1].picture
end
function instagram:on_inline_query(inline_query, configuration, language)
local input = mattata.input(inline_query.query)
if not input then
return
end
local pic, err = instagram.get_profile_pic(input)
if not pic then
return false, err
end
return mattata.send_inline_photo(inline_query.id, pic)
end
function instagram:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, instagram.help)
end
local pic, err = instagram.get_profile_pic(input)
if not pic then
return mattata.send_reply(message, err)
end
local keyboard = mattata.inline_keyboard():row(
mattata.row():url_button(
string.format(
language['instagram']['1'],
input
),
'https://www.instagram.com/' .. input
)
)
return mattata.send_photo(message.chat.id, pic, nil, false, nil, keyboard)
end
return instagram
\ No newline at end of file
diff --git a/plugins/ipsw.mattata b/plugins/ipsw.mattata
index 1692e8d..3466a5c 100644
--- a/plugins/ipsw.mattata
+++ b/plugins/ipsw.mattata
@@ -1,309 +1,309 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local ipsw = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
function ipsw:init()
ipsw.commands = mattata.commands(self.info.username):command('ipsw').table
ipsw.help = '/ipsw - Allows you to select the firmware information for your device and firmware version.'
ipsw.data = {}
local jstr, res = https.request('https://api.ipsw.me/v2.1/firmwares.json')
if res == 200
then
ipsw.data = json.decode(jstr)
end
ipsw.devices = {}
for k, v in pairs(ipsw.data.devices)
do
if k:lower():match('^appletv')
then
if not ipsw.devices['Apple TV']
then
ipsw.devices['Apple TV'] = {}
end
table.insert(ipsw.devices['Apple TV'], k)
elseif k:lower():match('^ipad')
then
if not ipsw.devices['iPad']
then
ipsw.devices['iPad'] = {}
end
table.insert(ipsw.devices['iPad'], k)
elseif k:lower():match('^ipod')
then
if not ipsw.devices['iPod']
then
ipsw.devices['iPod'] = {}
end
table.insert(ipsw.devices['iPod'], k)
elseif k:lower():match('^iphone')
then
if not ipsw.devices['iPhone']
then
ipsw.devices['iPhone'] = {}
end
table.insert(ipsw.devices['iPhone'], k)
end
end
end
function ipsw.get_info(input)
local device = input
local version = 'latest'
if input:match('^.- .-$')
then
device = input:match('^(.-) ')
version = input:match(' (.-)$')
end
local jstr, res = https.request(
string.format(
'https://api.ipsw.me/v2.1/%s/%s/info.json',
url.escape(device),
url.escape(version)
)
)
if res ~= 200 or jstr == '[]'
then
return false
end
return json.decode(jstr)
end
function ipsw:on_inline_query(inline_query, configuration, language)
local input = mattata.input(inline_query.query)
if not input
then
return
end
local jdat = ipsw.get_info(input)
if not jdat
then
return
end
return mattata.answer_inline_query(
inline_query.id,
mattata.inline_result()
:type('article')
:id(1)
:title(jdat[1].device)
:description('iOS ' .. jdat[1].version)
:input_message_content(
mattata.input_text_message_content(
string.format(
language['ipsw']['1'],
jdat[1].device,
jdat[1].version,
jdat[1].md5sum,
jdat[1].sha1sum,
mattata.round(
jdat[1].size / 1000000000,
2
),
jdat[1].signed == false
and utf8.char(10060)
or utf8.char(9989),
jdat[1].signed == false
and language['ipsw']['2']
or language['ipsw']['3']
),
'html'
)
)
:reply_markup(
mattata.inline_keyboard():row(
mattata.row():url_button(
jdat[1].filename,
jdat[1].url
)
)
)
)
end
function ipsw.get_model_keyboard(device)
local keyboard = {
['inline_keyboard'] = {
{}
}
}
local total = 0
for _, v in pairs(ipsw.devices[device])
do
total = total + 1
end
local count = 0
local rows = math.floor(total / 10)
if rows ~= total
then
rows = rows + 1
end
local row = 1
for k, v in pairs(ipsw.data.devices)
do
if k:lower():match(
device:lower():gsub(' ', '')
)
then
count = count + 1
if count == rows * row
then
row = row + 1
table.insert(
keyboard.inline_keyboard,
{}
)
end
table.insert(
keyboard.inline_keyboard[row],
{
['text'] = v.name,
['callback_data'] = 'ipsw:model:' .. k
}
)
end
end
return keyboard
end
function ipsw.get_firmware_keyboard(model)
local keyboard = {
['inline_keyboard'] = {
{}
}
}
local total = 0
for _, v in pairs(ipsw.data.devices[model].firmwares)
do
total = total + 1
end
local count = 0
local rows = math.floor(total / 7)
if rows ~= total
then
rows = rows + 1
end
local row = 1
for k, v in pairs(ipsw.data.devices[model].firmwares)
do
count = count + 1
if count == rows * row
then
row = row + 1
table.insert(
keyboard.inline_keyboard,
{}
)
end
table.insert(
keyboard.inline_keyboard[row],
{
['text'] = v.version,
['callback_data'] = 'ipsw:firmware:' .. model .. ' ' .. v.buildid
}
)
end
return keyboard
end
function ipsw:on_callback_query(callback_query, message, configuration, language)
if callback_query.data:match('^device%:')
then
callback_query.data = callback_query.data:match('^device%:(.-)$')
return mattata.edit_message_text(
message.chat.id,
message.message_id,
language['ipsw']['4'],
nil,
true,
ipsw.get_model_keyboard(callback_query.data)
)
elseif callback_query.data:match('^model%:')
then
callback_query.data = callback_query.data:match('^model%:(.-)$')
return mattata.edit_message_text(
message.chat.id,
message.message_id,
language['ipsw']['5'],
nil,
true,
ipsw.get_firmware_keyboard(callback_query.data)
)
elseif callback_query.data:match('^firmware%:')
then
local jdat = ipsw.get_info(
callback_query.data:match('^firmware%:(.-)$')
)
return mattata.edit_message_text(
message.chat.id,
message.message_id,
string.format(
language['ipsw']['1'],
jdat[1].device,
jdat[1].version,
jdat[1].md5sum,
jdat[1].sha1sum,
mattata.round(
jdat[1].size / 1000000000,
2
),
jdat[1].signed == false
and utf8.char(10060)
or utf8.char(9989),
jdat[1].signed == false
and language['ipsw']['2']
or language['ipsw']['3']
),
'html',
true,
mattata.inline_keyboard():row(
mattata.row():url_button(
jdat[1].filename,
jdat[1].url
)
)
)
end
end
function ipsw:on_message(message, configuration, language)
ipsw.init(self)
return mattata.send_message(
message.chat.id,
language['ipsw']['6'],
nil,
true,
false,
nil,
mattata.inline_keyboard()
:row(
mattata.row()
:callback_data_button(
language['ipsw']['7'],
'ipsw:device:iPod'
)
:callback_data_button(
language['ipsw']['8'],
'ipsw:device:iPhone'
)
)
:row(
mattata.row()
:callback_data_button(
language['ipsw']['9'],
'ipsw:device:iPad'
)
:callback_data_button(
language['ipsw']['10'],
'ipsw:device:Apple TV'
)
)
)
end
return ipsw
\ No newline at end of file
diff --git a/plugins/ispwned.mattata b/plugins/ispwned.mattata
index aee00c4..c9060d0 100644
--- a/plugins/ispwned.mattata
+++ b/plugins/ispwned.mattata
@@ -1,47 +1,47 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local ispwned = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
function ispwned:init()
ispwned.commands = mattata.commands(self.info.username):command('ispwned').table
ispwned.help = '/ispwned <account> - Returns the existence of the given account in any major data leaks.'
end
function ispwned:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
ispwned.help
)
end
local jstr, res = https.request('https://haveibeenpwned.com/api/v2/breachedaccount/' .. url.escape(input))
if res ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local jdat = json.decode(jstr)
local output = ''
for n in pairs(jdat)
do
output = output .. '\n' .. mattata.escape_html(jdat[n].Title)
end
return mattata.send_message(
message.chat.id,
'<b>' .. language['ispwned']['1'] .. '</b>\n' .. output,
'html'
)
end
return ispwned
\ No newline at end of file
diff --git a/plugins/itunes.mattata b/plugins/itunes.mattata
index a1ea82f..7b35f63 100644
--- a/plugins/itunes.mattata
+++ b/plugins/itunes.mattata
@@ -1,207 +1,207 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local itunes = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function itunes:init()
itunes.commands = mattata.commands(self.info.username):command('itunes').table
itunes.help = '/itunes <query> - Searches iTunes for the given search query and returns the most relevant result.'
end
function itunes.get_output(jdat, language)
local output = {}
if jdat.results[1].trackViewUrl
and jdat.results[1].trackName
then
table.insert(
output,
'<b>' .. language['itunes']['1'] .. '</b> <a href=\'' .. jdat.results[1].trackViewUrl .. '\'>' .. mattata.escape_html(jdat.results[1].trackName) .. '</a>'
)
end
if jdat.results[1].artistViewUrl
and jdat.results[1].artistName
then
table.insert(
output,
'<b>' .. language['itunes']['2'] .. '</b> <a href="' .. jdat.results[1].artistViewUrl .. '">' .. mattata.escape_html(jdat.results[1].artistName) .. '</a>'
)
end
if jdat.results[1].collectionViewUrl
and jdat.results[1].collectionName
then
table.insert(
output,
'<b>' .. language['itunes']['3'] .. '</b> <a href="' .. jdat.results[1].collectionViewUrl .. '">' .. mattata.escape_html(jdat.results[1].collectionName) .. '</a>'
)
end
if jdat.results[1].trackNumber
and jdat.results[1].trackCount
then
table.insert(
output,
'<b>' .. language['itunes']['4'] .. '</b> ' .. jdat.results[1].trackNumber .. '/' .. jdat.results[1].trackCount
)
end
if jdat.results[1].discNumber
and jdat.results[1].discCount
then
table.insert(
output,
'<b>' .. language['itunes']['5'] .. '</b> ' .. jdat.results[1].discNumber .. '/' .. jdat.results[1].discCount
)
end
return table.concat(
output,
'\n'
)
end
function itunes:on_inline_query(inline_query)
local input = mattata.input(inline_query.query)
if not input
then
return
end
local jstr, res = https.request('https://itunes.apple.com/search?term=' .. url.escape(input))
if res ~= 200
then
return
end
local jdat = json.decode(jstr)
if not jdat.results[1]
then
return
end
local count = 0
local results = {}
local temp = {}
for k, v in pairs(jdat.results)
do
if v.artworkUrl100
and not temp[v.artworkUrl100]
then
count = count + 1
table.insert(
results,
mattata.inline_result()
:type('photo')
:id(count)
:photo_url(
v.artworkUrl100
:gsub('%/100x100bb%.jpg', '/10000x10000bb.jpg')
)
:thumb_url(v.artworkUrl100)
)
temp[v.artworkUrl100] = true
end
end
return mattata.answer_inline_query(
inline_query.id,
results
)
end
function itunes:on_callback_query(callback_query, message, configuration, language)
if not message.reply
then
return mattata.answer_callback_query(
callback_query.id,
language['itunes']['6'],
true
)
end
local input = mattata.input(message.reply.text)
if callback_query.data == 'artwork'
then
local jstr, res = https.request('https://itunes.apple.com/search?term=' .. url.escape(input))
if res ~= 200
then
return false
end
local jdat = json.decode(jstr)
if not jdat.results[1]
then
return false
end
if jdat.results[1].artworkUrl100
then
local artwork = jdat.results[1].artworkUrl100:gsub('%/100x100bb%.jpg', '/10000x10000bb.jpg')
-- Get the highest quality artwork available.
mattata.send_photo(
message.chat.id,
artwork
)
return mattata.edit_message_text(
message.chat.id,
message.message_id,
language['itunes']['7']
)
end
end
end
function itunes:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
local success = mattata.send_force_reply(
message,
language['itunes']['8']
)
if success
then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/itunes'
)
end
return
end
mattata.send_chat_action(message.chat.id)
local jstr, res = https.request('https://itunes.apple.com/search?term=' .. url.escape(input))
if res ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local jdat = json.decode(jstr)
if not jdat.results[1]
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
return mattata.send_message(
message.chat.id,
itunes.get_output(
jdat,
language
),
'html',
true,
false,
message.message_id,
mattata.inline_keyboard():row(
mattata.row():callback_data_button(
language['itunes']['9'],
'itunes:artwork'
)
)
)
end
return itunes
\ No newline at end of file
diff --git a/plugins/languages.mattata b/plugins/languages.mattata
index 6fcd252..fda59b4 100644
--- a/plugins/languages.mattata
+++ b/plugins/languages.mattata
@@ -1,24 +1,24 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local languages = {}
local mattata = require('mattata')
function languages:init()
languages.commands = mattata.commands(self.info.username):command('languages').table
languages.help = '/languages - Returns a list of languages that aren\'t currently supported by mattata, but are being spoken by users.'
end
function languages:on_message(message)
local missing_languages = mattata.get_missing_languages()
return mattata.send_message(
message.chat.id,
missing_languages
and ('The following locales are languages my users speak that I do not currently have a translation file for:\n\n' .. missing_languages .. '\n\nIf you speak any of these languages well, and you are willing to volunteer your time into contributing to the development of mattata in the form of translating a file containing strings, please join https://t.me/mattataDev - thank you!')
or 'At this moment in time, all of the languages spoken by my users have been translated, and can be selected by using /setlang!'
)
end
return languages
\ No newline at end of file
diff --git a/plugins/lastfm.mattata b/plugins/lastfm.mattata
index b099a6e..b68fa97 100644
--- a/plugins/lastfm.mattata
+++ b/plugins/lastfm.mattata
@@ -1,88 +1,88 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local lastfm = {}
local mattata = require('mattata')
local http = require('socket.http')
local url = require('socket.url')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function lastfm:init(configuration)
assert(configuration.keys.lastfm, 'lastfm.lua requires an API key, and you haven\'t got one configured!')
lastfm.commands = mattata.commands(self.info.username):command('lastfm'):command('np'):command('fmset').table
lastfm.help = '/np <username> - Returns what you are or were last listening to. If you specify a username, info will be returned for that username. /fmset <username> - Sets your last.fm username. Use /fmset -del to delete your current username.'
lastfm.url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key='
end
function lastfm.set_username(user_object, name, language)
redis:hset('user:' .. user_object.id .. ':info', 'lastfm', name)
return string.format(language['lastfm']['1'], user_object.first_name, name)
end
function lastfm.del_username(user_id, language)
if redis:hget('user:' .. user_id .. ':info', 'lastfm') then
redis:hdel('user:' .. user_id .. ':info', 'lastfm')
return language['lastfm']['2']
end
return language['lastfm']['3']
end
function lastfm.get_username(user_id)
return redis:hget('user:' .. user_id .. ':info', 'lastfm')
end
function lastfm:on_message(message, configuration, language)
local input = mattata.input(message.text)
if message.text:match('^[/!#]lastfm') then
return mattata.send_reply(message, lastfm.help)
elseif message.text:match('^[/!#]fmset') then
input = input or message.from.username
if not input then
return mattata.send_reply(message, lastfm.help)
elseif input == '-del' then
local output = lastfm.del_username(message.from.id, language)
return mattata.send_reply(message, output)
end
local output = lastfm.set_username(message.from, input, language)
return mattata.send_reply(message, output)
end
local username, output
if input then
username = input
elseif lastfm.get_username(message.from.id, language) then
username = lastfm.get_username(message.from.id)
else
return mattata.send_reply(message, language['lastfm']['4'])
end
local jstr, res = http.request(lastfm.url .. configuration.keys.lastfm .. '&user=' .. url.escape(username))
if res ~= 200 then
return mattata.send_reply(message, language['errors']['connection'])
end
local jdat = json.decode(jstr)
if jdat.error then
return mattata.send_reply(message, language['lastfm']['4'])
end
if not jdat or not jdat.recenttracks then
return mattata.send_reply(message.chat.id, language['lastfm']['5'])
end
jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track
output = input and mattata.escape_html(input) or string.format('<a href="%s">%s</a>', 'https://last.fm/user/' .. url.escape(username), mattata.escape_html(message.from.first_name))
output = (jdat['@attr'] and jdat['@attr'].nowplaying) and string.format(language['lastfm']['6'], output) or string.format(language['lastfm']['7'], output)
local title = jdat.name or language['lastfm']['8']
local artist = jdat.artist and jdat.artist['#text'] or language['lastfm']['8']
if artist and title ~= jdat.name then
mattata.send_chat_action(message.chat.id)
return mattata.send_message(message.chat.id, output .. artist .. ' - ' .. title)
elseif jdat.image and jdat.image[1]['#text'] == '' then
return mattata.send_message(message.chat.id, output .. artist .. ' - ' .. title)
end
mattata.send_chat_action(message.chat.id, 'upload_photo')
output = output .. string.format('<a href="%s">%s</a>', jdat.url, artist .. ' - ' .. title)
return mattata.send_photo(message.chat.id, jdat.image[4]['#text'], output, 'html')
end
return lastfm
\ No newline at end of file
diff --git a/plugins/lmgtfy.mattata b/plugins/lmgtfy.mattata
index 3f58526..dde5901 100644
--- a/plugins/lmgtfy.mattata
+++ b/plugins/lmgtfy.mattata
@@ -1,37 +1,37 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local lmgtfy = {}
local mattata = require('mattata')
local url = require('socket.url')
local redis = dofile('libs/redis.lua')
function lmgtfy:init()
lmgtfy.commands = mattata.commands(self.info.username):command('lmgtfy').table
lmgtfy.help = '/lmgtfy [anything] - Helps that special someone out. Input can be given via an argument or using the replied-to person\'s message text.'
end
function lmgtfy:on_message(message)
local input = mattata.input(message.text)
if not input then
if not message.reply then
return mattata.send_reply(message, lmgtfy.help)
end
input = message.reply.text
end
if message.reply then
message.message_id = message.reply.message_id -- if we're sending in reply to a reply, we need it to trick it!
end
input = 'https://lmgtfy.com/?q=' .. url.escape(input)
local output = redis:get('chat:' .. message.chat.id .. ':lmgtfy') or 'Here you go, idiot.'
output = mattata.escape_html(output)
output = string.format('<a href="%s">%s</a>', input, output)
if message.reply then
return mattata.send_reply(message, output, 'html')
end
return mattata.send_message(message.chat.id, output, 'html')
end
return lmgtfy
\ No newline at end of file
diff --git a/plugins/location.mattata b/plugins/location.mattata
index f92e05d..044c3e5 100644
--- a/plugins/location.mattata
+++ b/plugins/location.mattata
@@ -1,81 +1,81 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local location = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local setloc = dofile('plugins/setloc.mattata')
local redis = dofile('libs/redis.lua')
function location:init()
location.commands = mattata.commands(self.info.username):command('location'):command('loc').table
location.help = '/location [query] - Sends your location, or a location from Google Maps. Alias: /loc.'
end
function location:on_inline_query(inline_query, configuration)
local input = mattata.input(inline_query.query)
local result = {}
if not input then
local loc = setloc.get_loc(inline_query.from.id)
if not loc then
return false, 'No location was found for the given user!'
end
local jdat = json.decode(loc)
local output = mattata.inline_result():type('location'):id(1):title(jdat.address):latitude(jdat.latitude):longitude(jdat.longitude)
return mattata.answer_inline_query(inline_query.id, output)
end
local jstr, res = https.request('https://api.opencagedata.com/geocode/v1/json?key=' .. configuration['keys']['location'] .. '&pretty=0&q=' .. url.escape(input))
if res ~= 200 then
return false, 'Connection error! [' .. res .. ']'
end
local jdat = json.decode(jstr)
if jdat.total_results == 0 then
return false, 'No results were found!'
end
local output = mattata.inline_result():type('location'):id(1):title(input):latitude(jdat.results[1].geometry.lat):longitude(jdat.results[1].geometry.lng)
return mattata.answer_inline_query(inline_query.id, output)
end
function location:on_message(message, configuration, language)
local input = mattata.input(message.text:lower())
if not input and not setloc.get_loc(message.from.id) then
local success = mattata.send_force_reply(message, language['location']['1'])
if success then
local action = mattata.command_action(message.chat.id, success.result.message_id)
redis:set(action, '/setloc')
end
return
elseif not input then
local loc = setloc.get_loc(message.from.id)
return mattata.send_location(
message.chat.id,
json.decode(loc).latitude,
json.decode(loc).longitude
)
end
local jstr, res = https.request('https://api.opencagedata.com/geocode/v1/json?key=' .. configuration['keys']['location'] .. '&pretty=0&q=' .. url.escape(input))
if res ~= 200 then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local jdat = json.decode(jstr)
if jdat.total_results == 0 then
return mattata.send_reply(
message,
language['errors']['results']
)
end
return mattata.send_location(
message.chat.id,
jdat.results[1].geometry.lat,
jdat.results[1].geometry.lng
)
end
return location
\ No newline at end of file
diff --git a/plugins/lua.mattata b/plugins/lua.mattata
index 9b7cad5..734532b 100644
--- a/plugins/lua.mattata
+++ b/plugins/lua.mattata
@@ -1,67 +1,67 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local lua = {}
local mattata = require('mattata')
local url = require('socket.url')
local json = require('dkjson')
function lua:init()
lua.commands = mattata.commands(self.info.username):command('lua').table
lua.error_message = function(error_message)
return 'Error:\n' .. tostring(error_message)
end
end
function lua:on_message(message, configuration, language)
if not mattata.is_global_admin(message.from.id) then
return
end
local input = mattata.input(message.text)
if not input then
local text = language['lua']['1']
return mattata.send_reply(message, text)
end
local output, success = load(
"local mattata = require('mattata')\n\z
local configuration = require('configuration')\n\z
local api = require('telegram-bot-lua.core').configure(configuration.bot_token)\n\z
local tools = require('telegram-bot-lua.tools')\n\z
local https = require('ssl.https')\n\z
local http = require('socket.http')\n\z
local url = require('socket.url')\n\z
local ltn12 = require('ltn12')\n\z
local json = require('dkjson')\n\z
local utf8 = require('lua-utf8')\n\z
local socket = require('socket')\n\z
local redis = dofile('libs/redis.lua')\n\z
return function (self, message, configuration)\n" .. input .. '\nend')
if output == nil then
output = success
else
success, output = xpcall(
output(),
lua.error_message,
self,
message,
configuration
)
end
if output ~= nil and type(output) == 'table' then
output = json.encode(output, { ['indent'] = true })
elseif output == nil then
return false
end
return mattata.send_message(
message.chat.id,
'<pre>' .. mattata.escape_html(
tostring(output)
) .. '</pre>',
'html'
)
end
return lua
\ No newline at end of file
diff --git a/plugins/lyrics.mattata b/plugins/lyrics.mattata
index 80b5970..6d6db1e 100644
--- a/plugins/lyrics.mattata
+++ b/plugins/lyrics.mattata
@@ -1,506 +1,503 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local lyrics = {}
local mattata = require('mattata')
local https = dofile('libs/https.lua')
local http = require('socket.http')
local url = require('socket.url')
local ltn12 = require('ltn12')
local json = require('dkjson')
local html = require('htmlEntities')
local redis = dofile('libs/redis.lua')
local socket = require('socket')
local configuration = require('configuration')
function lyrics:init(configuration)
- assert(
- configuration.keys.lyrics,
- 'lyrics.lua requires an API key, and you haven\'t got one configured!'
- )
+ assert(configuration.keys.lyrics, 'lyrics.lua requires an API key, and you haven\'t got one configured!')
lyrics.commands = mattata.commands(self.info.username):command('lyrics').table
lyrics.help = '/lyrics <query> - Finds the lyrics to the given track.'
end
function lyrics.search_lyrics_fandom(artist, track)
print('starting search from fandom')
local str, res = https.request(
string.format(
'https://lyrics.fandom.com/wiki/%s:%s',
url.escape(artist:gsub('%s', '_')),
url.escape(track:gsub('%s', '_'))
, false, 1)
)
print('finished search from fandom')
if res ~= 200
then
return false
end
str = str:match('%<div class%=%\'lyricbox%\'%>(.-)%<div class%=%\'lyricsbreak%\'%>')
if not str or str:match('[Uu]nfortunately%,? we are not licensed%.?')
then
return false
end
str = str
:gsub('%<br ?%/?%>', '\n')
:gsub('%<%/?b%>', '')
:gsub('%<%/?i%>', '')
return html.decode(str)
end
function lyrics.search_az_lyrics(artist, track)
local response = {}
local _, res = https.request(
{
['url'] = string.format(
'https://www.azlyrics.com/lyrics/%s/%s.html',
url.escape(
artist:lower():gsub('%s', '')
),
url.escape(
track:lower():gsub('%s', '')
)
),
['method'] = 'GET',
['headers'] = {
['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
['Accept-Encoding'] = 'gzip, deflate, sdch',
['Accept-Language'] = 'en-US,en;q=0.8',
['Cache-Control'] = 'max-age=0',
['DNT'] = '1',
['Host'] = 'www.azlyrics.com',
['Upgrade-Insecure-Requests'] = '1',
['User-Agent'] = 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Mobile Safari/537.36'
},
['sink'] = ltn12.sink.table(response)
}
)
if res ~= 200
then
return false
end
local str = table.concat(response):match('%<%!%-%- Usage of azlyrics%.com content by any third%-party lyrics provider is prohibited by our licensing agreement%. Sorry about that%. %-%-%>(.-)%<%/div%>'):gsub('%<br ?%/?%>', ''):gsub('%<%/?b%>', ''):gsub('%<%/?i%>', '')
if not str
then
return false
end
return html.decode(str)
end
function lyrics.search_plyrics(artist, track)
local response = {}
local _, res = http.request(
{
['url'] = string.format(
'http://www.plyrics.com/lyrics/%s/%s.html',
url.escape(
artist:lower():gsub('%s', '')
),
url.escape(
track:lower():gsub('%s', '')
)
),
['method'] = 'GET',
['headers'] = {
['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
['Accept-Encoding'] = 'gzip, deflate, sdch',
['Accept-Language'] = 'en-US,en;q=0.8',
['Cache-Control'] = 'max-age=0',
['Cookie'] = '__utmt=1; __utma=179262907.1714206337.1484225238.1484225238.1484225238.1; __utmb=179262907.1.10.1484225238; __utmc=179262907; __utmz=179262907.1484225238.1.1.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided)',
['Host'] = 'www.plyrics.com',
['Upgrade-Insecure-Requests'] = '1',
['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
},
['sink'] = ltn12.sink.table(response)
}
)
if res ~= 200
then
return false
end
local str = table.concat(response)
if not str
then
return false
end
str = str:match('%<%!%-%- start of lyrics %-%-%>(.-)%<%!%-%- end of lyrics %-%-%>')
str = str:gsub('%<br ?%/?%>', '')
:gsub('%<%/?b%>', '')
:gsub('%<%/?i%>', '')
if not str
then
return false
end
return html.decode(str)
end
function lyrics.search_lyrics(artist, track)
local success = lyrics.search_lyrics_fandom(
artist,
track
)
if not success
then
success = lyrics.search_plyrics(
artist,
track
)
end
if not success
then
success = lyrics.search_az_lyrics(
artist,
track
)
end
if not success
then
return false
end
return success
end
function lyrics.send_request(input, inline, no_html)
local search_url = string.format(
'https://api.musixmatch.com/ws/1.1/track.search?apikey=%s&s_track_rating=desc',
configuration.keys.lyrics
)
if input:match('^.- %- .-$')
then -- Perform a more specific search if the user searches for lyrics in the
-- format artist - song.
search_url = string.format(
'%s&q_artist=%s&q_track=%s',
search_url,
url.escape(
input:match('^(.-) %- .-$')
),
url.escape(
input:match('^.- %- (.-)$')
)
)
else
search_url = string.format(
'%s&q_track=%s',
search_url,
url.escape(input)
)
end
local jstr, res = https.request(search_url, false, 1)
if res ~= 200
then
return false
end
local jdat = json.decode(jstr)
if jdat.message.header.available == 0
then
print('none available')
jstr, res = https.request(
string.format(
'https://api.musixmatch.com/ws/1.1/track.search?apikey=%s&s_track_rating=desc&q=%s',
configuration.keys.lyrics,
url.escape(input)
)
)
if res ~= 200
then
return false
end
jdat = json.decode(jstr)
if jdat.message.header.available == 0
then
return false
end
end
if not jdat.message
or not jdat.message.body
or not jdat.message.body.track_list
or not jdat.message.body.track_list[1]
or not jdat.message.body.track_list[1].track
or not jdat.message.body.track_list[1].track.artist_name
or not jdat.message.body.track_list[1].track.track_name
then
return false
elseif inline
then
return jdat
end
local artist = jdat.message.body.track_list[1].track.artist_name
local track = jdat.message.body.track_list[1].track.track_name
track = track:match('^(.-) %(.-%) %[.-%]$')
or track:match('^(.-) %(.-%)$')
or track
local output = lyrics.search_lyrics(
artist,
track
)
if not output
then
print('testing no output')
local jstr_lyrics, res_lyrics = https.request(
string.format(
'https://api.musixmatch.com/ws/1.1/track.lyrics.get?apikey=%s&track_id=%s',
configuration.keys.lyrics,
jdat.message.body.track_list[1].track.track_id
)
)
if res_lyrics ~= 200
then
return false
end
local jdat_lyrics = json.decode(jstr_lyrics)
if jdat_lyrics.message.header.status_code ~= 200
then
return false
end
output = jdat_lyrics.message.body.lyrics.lyrics_body:match('^(.-)\n\n[%*]+')
or jdat_lyrics.message.body.lyrics.lyrics_body
end
if output:len() > 4000 then -- If the lyrics are REALLY long, trim them so they'll
-- fit in a single message (this is only a temporary solution)
output = output:sub(1, 4000) .. '...'
end
output = output:gsub('\\', '')
output = string.format(
'%s%s%s %s\n\n%s',
not no_html
and '<b>'
or '',
mattata.escape_html(track),
not no_html and '</b>' or '',
mattata.escape_html(artist),
mattata.escape_html(output)
)
return output, artist, track
end
function lyrics.search_spotify(input)
local jstr, res = https.request(
string.format(
'https://api.spotify.com/v1/search?q=%s&type=track',
url.escape(input)
)
)
if res ~= 200
then
return false
end
local jdat = json.decode(jstr)
if not jdat.tracks
or jdat.tracks.total == 0
then
return false
end
return 'https://open.spotify.com/track/' .. jdat.tracks.items[1].id
end
function lyrics.get_keyboard(artist, track, language)
local spotify_url = lyrics.search_spotify(artist .. ' ' .. track)
local keyboard = {
['inline_keyboard'] = {}
}
if spotify_url
then
table.insert(
keyboard.inline_keyboard,
{
{
['text'] = language['lyrics']['1'],
['url'] = spotify_url
}
}
)
return keyboard
end
return nil
end
function lyrics:on_inline_query(inline_query, configuration, language)
local input = mattata.input(inline_query.query)
if not input
then
return
end
local output = lyrics.send_request(
input,
true,
false
)
if not output
then
return
end
local results = {}
local count = 0
for n in pairs(output.message.body.track_list)
do
local artist = output.message.body.track_list[n].track.artist_name
local track = output.message.body.track_list[n].track.track_name
local track_id = output.message.body.track_list[n].track.track_id
if artist
and track
and track_id
then
count = count + 1
local id = socket.gettime() * 10000
id = tostring(id):gsub('%D', '')
local payload = {
['artist'] = artist,
['track'] = track,
['track_id'] = track_id
}
redis:set(
'lyrics:' .. id,
json.encode(payload)
)
table.insert(
results,
mattata.inline_result()
:type('article')
:id(count)
:title(track)
:description(artist)
:input_message_content(
mattata.input_text_message_content(
string.format(
'%s - %s',
track,
artist
)
)
)
:reply_markup(
mattata.inline_keyboard():row(
mattata.row():callback_data_button(
language['lyrics']['2'],
'lyrics:' .. id
)
)
)
)
end
end
if not results
or results == {}
then
return
end
return mattata.answer_inline_query(
inline_query.id,
results
)
end
function lyrics:on_callback_query(callback_query, message, configuration, language)
local data = redis:get('lyrics:' .. callback_query.data)
if not data
then
return
end
local output = lyrics.search_lyrics(
json.decode(data).artist,
json.decode(data).track
)
if not output
then
local jstr_lyrics, res_lyrics = https.request(
string.format(
'https://api.musixmatch.com/ws/1.1/track.lyrics.get?apikey=%s&track_id=%s',
configuration.keys.lyrics,
json.decode(data).track_id
)
)
if res_lyrics ~= 200
then
return
end
local jdat_lyrics = json.decode(jstr_lyrics)
if jdat_lyrics.message.header.status_code ~= 200
then
return
end
output = jdat_lyrics.message.body.lyrics.lyrics_body:match('^(.-)\n\n[%*]+')
or jdat_lyrics.message.body.lyrics.lyrics_body
end
if output:len() > 4000 then -- If the lyrics are REALLY long, trim them so they'll
-- fit in a single message (this is only a temporary solution)
output = output:sub(1, 4000) .. '...'
end
output = output:gsub('\\', '')
output = string.format(
'<b>%s</b> %s\n\n%s',
mattata.escape_html(json.decode(data).track),
mattata.escape_html(json.decode(data).artist),
mattata.escape_html(output)
)
local keyboard = lyrics.get_keyboard(
json.decode(data).artist,
json.decode(data).track,
language
)
if keyboard
and keyboard.inline_keyboard
then
keyboard = json.encode(keyboard)
end
redis:del('lyrics:' .. callback_query.data)
return mattata.edit_message_text(
nil,
nil,
output,
'html',
true,
keyboard,
callback_query.inline_message_id
)
end
function lyrics:on_message(message, configuration, language)
print('begain plugin')
local input = mattata.input(message.text)
if not input
then
local success = mattata.send_force_reply(
message,
language['lyrics']['3']
)
if success
then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/lyrics'
)
end
return
end
mattata.send_chat_action(message.chat.id)
local output, artist, track = lyrics.send_request(input)
if not output
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
local keyboard = lyrics.get_keyboard(
artist,
track,
language
)
return mattata.send_message(
message.chat.id,
output,
'html',
true,
false,
nil,
keyboard
)
end
return lyrics
\ No newline at end of file
diff --git a/plugins/meme.mattata b/plugins/meme.mattata
index 09ef293..8b72e08 100644
--- a/plugins/meme.mattata
+++ b/plugins/meme.mattata
@@ -1,656 +1,656 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local meme = {}
local mattata = require('mattata')
function meme:init()
meme.commands = mattata.commands(self.info.username)
:command('meme')
:command('memegen').table
meme.help = '/meme <top line> | <bottom line> - Generates an image macro with the given text, on your choice of the available selection of templates. This command can only be used inline. Alias: /memegen.'
end
function meme.escape(str)
if not str
or type(str) ~= 'string'
then
return str
end
str = str:lower()
return str
:gsub('%s', '_')
:gsub('%?', '~q')
:gsub('%%', '~p')
:gsub('#', '~h')
:gsub('/', '~s')
:gsub('"', '\'\'')
end
meme.memes = {
'ggg',
'elf',
'fwp',
'yuno',
'aag',
'badchoice',
'happening',
'scc',
'sad-obama',
'fbf',
'ants',
'ive',
'biw',
'crazypills',
'remembers',
'oag',
'ski',
'oprah',
'wonka',
'regret',
'fa',
'keanu',
'kermit',
'both',
'awkward',
'dodgson',
'bad',
'mmm',
'ch',
'live',
'firsttry',
'noidea',
'sad-biden',
'buzz',
'blb',
'fry',
'morpheus',
'cbg',
'xy',
'rollsafe',
'yodawg',
'fetch',
'sarcasticbear',
'cb',
'hipster',
'success',
'bd',
'bender',
'fine',
'bs',
'toohigh',
'mw',
'money',
'interesting',
'sb',
'doge',
'ermg',
'fmr',
'sparta',
'older',
'philosoraptor',
'awkward-awesome',
'awesome',
'chosen',
'alwaysonbeat',
'ackbar',
'sadfrog',
'sohot',
'imsorry',
'tenguy',
'winter',
'red',
'awesome-awkward',
'jw',
'sf',
'ss',
'patrick',
'center',
'boat',
'saltbae',
'tried',
'mb',
'hagrid',
'mordor',
'snek',
'sad-bush',
'nice',
'sad-clinton',
'afraid',
'stew',
'icanhas',
'away',
'dwight',
'facepalm',
'yallgot',
'jetpack',
'captain',
'inigo',
'iw',
'dsm',
'sad-boehner',
'll',
'joker',
'sohappy',
'officespace'
}
meme.meme_info = {
['tenguy'] = {
['width'] = 600,
['height'] = 544
},
['afraid'] = {
['width'] = 600,
['height'] = 588
},
['older'] = {
['width'] = 600,
['height'] = 255
},
['aag'] = {
['width'] = 600,
['height'] = 502
},
['tried'] = {
['width'] = 600,
['height'] = 600
},
['biw'] = {
['width'] = 600,
['height'] = 450
},
['stew'] = {
['width'] = 600,
['height'] = 448
},
['blb'] = {
['width'] = 600,
['height'] = 600
},
['kermit'] = {
['width'] = 600,
['height'] = 421
},
['bd'] = {
['width'] = 600,
['height'] = 597
},
['ch'] = {
['width'] = 600,
['height'] = 450
},
['cbg'] = {
['width'] = 600,
['height'] = 368
},
['wonka'] = {
['width'] = 600,
['height'] = 431
},
['cb'] = {
['width'] = 600,
['height'] = 626
},
['keanu'] = {
['width'] = 600,
['height'] = 597
},
['dsm'] = {
['width'] = 600,
['height'] = 900
},
['live'] = {
['width'] = 600,
['height'] = 405
},
['ants'] = {
['width'] = 600,
['height'] = 551
},
['doge'] = {
['width'] = 600,
['height'] = 600
},
['alwaysonbeat'] = {
['width'] = 600,
['height'] = 337
},
['ermg'] = {
['width'] = 600,
['height'] = 901
},
['facepalm'] = {
['width'] = 600,
['height'] = 529
},
['firsttry'] = {
['width'] = 600,
['height'] = 440
},
['fwp'] = {
['width'] = 600,
['height'] = 423
},
['fa'] = {
['width'] = 600,
['height'] = 600
},
['fbf'] = {
['width'] = 600,
['height'] = 597
},
['fmr'] = {
['width'] = 600,
['height'] = 385
},
['fry'] = {
['width'] = 600,
['height'] = 449
},
['ggg'] = {
['width'] = 600,
['height'] = 375
},
['hipster'] = {
['width'] = 600,
['height'] = 899
},
['icanhas'] = {
['width'] = 600,
['height'] = 874
},
['crazypills'] = {
['width'] = 600,
['height'] = 408
},
['mw'] = {
['width'] = 600,
['height'] = 441
},
['noidea'] = {
['width'] = 600,
['height'] = 382
},
['regret'] = {
['width'] = 600,
['height'] = 536
},
['boat'] = {
['width'] = 600,
['height'] = 441
},
['hagrid'] = {
['width'] = 600,
['height'] = 446
},
['sohappy'] = {
['width'] = 600,
['height'] = 700
},
['captain'] = {
['width'] = 600,
['height'] = 439
},
['bender'] = {
['width'] = 600,
['height'] = 445
},
['inigo'] = {
['width'] = 600,
['height'] = 326
},
['iw'] = {
['width'] = 600,
['height'] = 600
},
['ackbar'] = {
['width'] = 600,
['height'] = 777
},
['happening'] = {
['width'] = 600,
['height'] = 364
},
['joker'] = {
['width'] = 600,
['height'] = 554
},
['ive'] = {
['width'] = 600,
['height'] = 505
},
['ll'] = {
['width'] = 600,
['height'] = 399
},
['away'] = {
['width'] = 600,
['height'] = 337
},
['morpheus'] = {
['width'] = 600,
['height'] = 363
},
['mb'] = {
['width'] = 600,
['height'] = 534
},
['badchoice'] = {
['width'] = 600,
['height'] = 478
},
['mmm'] = {
['width'] = 600,
['height'] = 800
},
['jetpack'] = {
['width'] = 600,
['height'] = 450
},
['imsorry'] = {
['width'] = 600,
['height'] = 337
},
['red'] = {
['width'] = 600,
['height'] = 557
},
['mordor'] = {
['width'] = 600,
['height'] = 353
},
['oprah'] = {
['width'] = 600,
['height'] = 449
},
['oag'] = {
['width'] = 600,
['height'] = 450
},
['remembers'] = {
['width'] = 600,
['height'] = 458
},
['philosoraptor'] = {
['width'] = 600,
['height'] = 600
},
['jw'] = {
['width'] = 600,
['height'] = 401
},
['patrick'] = {
['width'] = 600,
['height'] = 1056
},
['rollsafe'] = {
['width'] = 600,
['height'] = 335
},
['sad-obama'] = {
['width'] = 600,
['height'] = 600
},
['sad-clinton'] = {
['width'] = 600,
['height'] = 542
},
['sadfrog'] = {
['width'] = 600,
['height'] = 600
},
['sad-bush'] = {
['width'] = 600,
['height'] = 455
},
['sad-biden'] = {
['width'] = 600,
['height'] = 600
},
['sad-boehner'] = {
['width'] = 600,
['height'] = 479
},
['saltbae'] = {
['width'] = 600,
['height'] = 603
},
['sarcasticbear'] = {
['width'] = 600,
['height'] = 450
},
['dwight'] = {
['width'] = 600,
['height'] = 393
},
['sb'] = {
['width'] = 600,
['height'] = 421
},
['ss'] = {
['width'] = 600,
['height'] = 604
},
['sf'] = {
['width'] = 600,
['height'] = 376
},
['dodgson'] = {
['width'] = 600,
['height'] = 559
},
['money'] = {
['width'] = 600,
['height'] = 337
},
['snek'] = {
['width'] = 600,
['height'] = 513
},
['sohot'] = {
['width'] = 600,
['height'] = 480
},
['nice'] = {
['width'] = 600,
['height'] = 432
},
['awesome-awkward'] = {
['width'] = 600,
['height'] = 601
},
['awesome'] = {
['width'] = 600,
['height'] = 600
},
['awkward-awesome'] = {
['width'] = 600,
['height'] = 600
},
['awkward'] = {
['width'] = 600,
['height'] = 600
},
['fetch'] = {
['width'] = 600,
['height'] = 450
},
['success'] = {
['width'] = 600,
['height'] = 578
},
['scc'] = {
['width'] = 600,
['height'] = 326
},
['ski'] = {
['width'] = 600,
['height'] = 404
},
['officespace'] = {
['width'] = 600,
['height'] = 501
},
['interesting'] = {
['width'] = 600,
['height'] = 759
},
['toohigh'] = {
['width'] = 600,
['height'] = 408
},
['bs'] = {
['width'] = 600,
['height'] = 600
},
['fine'] = {
['width'] = 600,
['height'] = 582
},
['sparta'] = {
['width'] = 600,
['height'] = 316
},
['center'] = {
['width'] = 600,
['height'] = 370
},
['both'] = {
['width'] = 600,
['height'] = 600
},
['winter'] = {
['width'] = 600,
['height'] = 460
},
['xy'] = {
['width'] = 600,
['height'] = 455
},
['buzz'] = {
['width'] = 600,
['height'] = 455
},
['yodawg'] = {
['width'] = 600,
['height'] = 399
},
['yuno'] = {
['width'] = 600,
['height'] = 450
},
['yallgot'] = {
['width'] = 600,
['height'] = 470
},
['bad'] = {
['width'] = 600,
['height'] = 450
},
['elf'] = {
['width'] = 600,
['height'] = 369
},
['chosen'] = {
['width'] = 600,
['height'] = 342
}
}
function meme.get_memes(offset, first_line, last_line)
local first = (
offset
and type(offset) == 'number'
)
and offset + 1
or 1
local last = first + 49
if first >= last
then
return
elseif last > #meme.memes
then
last = #meme.memes
end
local output = {}
local id = first
for i = first, last
do
local image = 'https://memegen.link/' .. meme.memes[i] .. '/' .. meme.escape(first_line)
if last_line
then
image = image .. '/' .. meme.escape(last_line)
end
image = image .. '.jpg?font=impact'
table.insert(
output,
mattata.inline_result()
:type('photo')
:id(
tostring(id)
)
:photo_url(image)
:thumb_url(image)
:photo_width(
tostring(meme.meme_info[meme.memes[i]]['width'])
)
:photo_height(
tostring(meme.meme_info[meme.memes[i]]['height'])
)
)
id = id + 1
end
if last == #meme.memes
then
last = false
end
return output, last
end
function meme:on_inline_query(inline_query)
local input = mattata.input(inline_query.query)
if not input
then
return false
end
input = input:gsub('\n', ' | ')
local first_line, last_line = input, false
if input:match('^.- | .-$')
then
first_line, last_line = input:match('^(.-) | (.-)$')
end
first_line = first_line:gsub(' | ', ' ')
if last_line
then
last_line = last_line:gsub(' | ', ' ')
end
local offset = inline_query.offset
and tonumber(inline_query.offset)
or 0
local output, next_offset = meme.get_memes(
offset,
first_line,
last_line
)
return mattata.answer_inline_query(
inline_query.id,
output,
0,
false,
next_offset
and tostring(next_offset)
or nil
)
end
function meme:on_message(message)
return mattata.send_message(
message.chat.id,
'This command can only be used inline!'
)
end
return meme
\ No newline at end of file
diff --git a/plugins/minecraft.mattata b/plugins/minecraft.mattata
index c6d1fd8..614432c 100644
--- a/plugins/minecraft.mattata
+++ b/plugins/minecraft.mattata
@@ -1,321 +1,321 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local minecraft = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function minecraft:init()
minecraft.commands = mattata.commands(self.info.username)
:command('minecraft')
:command('mc').table
minecraft.help = '/minecraft <Minecraft username> - Sends information about the given Minecraft user. Alias: /mc.'
end
function minecraft.get_uuid(username)
local jstr, res = https.request('https://api.mojang.com/users/profiles/minecraft/' .. url.escape(username))
if res ~= 200
then
return false
end
local jdat = json.decode(jstr)
if not jdat.id
then
return false
end
return jdat.id
end
function minecraft.username_change_date(date)
local format_date = io.popen('date -d @' .. date):read('*all')
format_date = format_date
:gsub(' ', ' 0')
:gsub('\n', '')
local month, day, time, year = format_date:match('^%a+ (%a+) (%d+) (%d%d:%d%d):%d%d %a+ (%d%d%d%d)$')
if day == 1
or day == 21
or day == 31
then
day = day .. 'st'
elseif day == 2
or day == 22
then
day = day .. 'nd'
elseif day == 3
or day == 23
then
day = day .. 'rd'
else
day = day .. 'th'
end
return ' <pre>[' .. day:gsub('^0', '') .. ' ' .. month .. ' ' .. year .. ', ' .. time .. ']</pre>'
end
function minecraft.get_history_page(username_history, username_count, page)
local page_begins_at = tonumber(page) * 5 - 4
local page_ends_at = tonumber(page_begins_at) + 4
if tonumber(page_ends_at) > tonumber(username_count)
then
page_ends_at = tonumber(username_count)
end
local page_usernames = {}
for i = tonumber(page_begins_at), tonumber(page_ends_at)
do
table.insert(
page_usernames,
username_history[i]
)
end
return table.concat(
page_usernames,
'\n'
)
end
function minecraft.get_username_history(username, language)
if not minecraft.get_uuid(username)
then
return false
end
local uuid = minecraft.get_uuid(username)
local jstr, res = https.request('https://api.mojang.com/user/profiles/' .. url.escape(uuid) .. '/names')
if res ~= 200
then
return false
end
local jdat = json.decode(jstr)
local names = {}
for n in pairs(jdat)
do
local result = jdat[n].name
if jdat[n].changedToAt
and tonumber(jdat[n].changedToAt) ~= nil
then
result = result .. minecraft.username_change_date(
math.floor(
tonumber(jdat[n].changedToAt) / 1000
)
)
end
table.insert(
names,
'• ' .. result
)
end
local output = language['minecraft']['1']
if #jdat ~= 1
then
output = language['minecraft']['2']
end
return string.format(
output,
username,
#jdat
) .. ':</b>\n' .. table.concat(
names,
'\n'
), #names, names
end
function minecraft.get_avatar(username)
return '<a href="https://mcapi.ca/avatar/' .. url.escape(username) .. '/128">' .. mattata.escape_html(username) .. '</a>'
end
function minecraft:on_callback_query(callback_query, message, configuration, language)
if callback_query.data:match('^uuid%:.-$')
then
local input = callback_query.data:match('^uuid%:(.-)$')
local output = minecraft.get_uuid(input)
if not output
then
output = language['errors']['results']
end
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
nil,
true,
mattata.inline_keyboard():row(
mattata.row():callback_data_button(
language['minecraft']['5'],
'minecraft:back:' .. input
)
)
)
elseif callback_query.data:match('^avatar%:.-$')
then
local input = callback_query.data:match('^avatar%:(.-)$')
return mattata.edit_message_text(
message.chat.id,
message.message_id,
minecraft.get_avatar(input),
'html',
false,
mattata.inline_keyboard():row(
mattata.row():callback_data_button(
language['minecraft']['5'],
'minecraft:back:' .. input
)
)
)
elseif callback_query.data:match('^history%:.-%:%d*$')
then
local input = callback_query.data:match('^history%:(.-)%:%d*$')
local output, amount, usernames = minecraft.get_username_history(
input,
language
)
local keyboard = {}
keyboard.inline_keyboard = {}
if not output
then
output = language['errors']['results']
else
local new_page = callback_query.data:match('^history%:.-%:(%d*)$')
local page_count = math.floor(tonumber(amount) / 5) + 1
if tonumber(new_page) > tonumber(page_count)
then
new_page = 1
elseif tonumber(new_page) < 1
then
new_page = tonumber(page_count)
end
table.insert(
keyboard.inline_keyboard,
{
{
['text'] = mattata.symbols.back .. ' ' .. language['minecraft']['3'],
['callback_data'] = 'minecraft:history:' .. input .. ':' .. math.floor(tonumber(new_page) - 1)
},
{
['text'] = new_page .. '/' .. page_count,
['callback_data'] = 'minecraft:pages:' .. new_page .. ':' .. page_count
},
{
['text'] = language['minecraft']['4'] .. ' ' .. mattata.symbols.next,
['callback_data'] = 'minecraft:history:' .. input .. ':' .. math.floor(tonumber(new_page) + 1)
}
}
)
output = minecraft.get_history_page(
usernames,
amount,
new_page
)
end
table.insert(
keyboard.inline_keyboard,
{
{
['text'] = language['minecraft']['5'],
['callback_data'] = 'minecraft:back:' .. input
}
}
)
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
'html',
true,
json.encode(keyboard)
)
elseif callback_query.data:match('^back%:.-$')
then
local input = callback_query.data:match('^back%:(.-)$')
local keyboard = {}
keyboard.inline_keyboard = {
{
{
['text'] = language['minecraft']['6'],
['callback_data'] = 'minecraft:uuid:' .. input
},
{
['text'] = language['minecraft']['7'],
['callback_data'] = 'minecraft:avatar:' .. input
}
},
{
{
['text'] = language['minecraft']['8'],
['callback_data'] = 'minecraft:history:' .. input .. ':1'
}
}
}
return mattata.edit_message_text(
message.chat.id,
message.message_id,
language['minecraft']['9'],
nil,
true,
json.encode(keyboard)
)
end
end
function minecraft:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
local success = mattata.send_force_reply(
message,
language['minecraft']['10']
)
if success
then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/minecraft'
)
end
return
elseif input:len() > 16
or input:len() < 3
then
return mattata.send_reply(
message,
language['minecraft']['11']
)
end
return mattata.send_message(
message.chat.id,
language['minecraft']['9'],
nil,
true,
false,
message.message_id,
mattata.inline_keyboard()
:row(
mattata.row()
:callback_data_button(
language['minecraft']['6'],
'minecraft:uuid:' .. input
)
:callback_data_button(
language['minecraft']['7'],
'minecraft:avatar:' .. input
)
)
:row(
mattata.row():callback_data_button(
language['minecraft']['8'],
string.format(
'minecraft:history:%s:1',
input
)
)
)
)
end
return minecraft
\ No newline at end of file
diff --git a/plugins/needsmorejpeg.mattata b/plugins/needsmorejpeg.mattata
index 69a3894..6518896 100644
--- a/plugins/needsmorejpeg.mattata
+++ b/plugins/needsmorejpeg.mattata
@@ -1,43 +1,42 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local needsmorejpeg = {}
local mattata = require('mattata')
function needsmorejpeg:init()
needsmorejpeg.commands = mattata.commands(self.info.username, { '^[Nn][Ee][Ee][Dd][Ss] [Mm][Oo][Rr][Ee] [Jj][Pp][Ee]?[Gg]$', '^[Mm][Oo][AaRr][RrEe]$'}):command('needsmorejpeg').table
needsmorejpeg.help = '/needsmorejpeg - Dreadfully reduces the quality of the replied-to photo.'
end
function needsmorejpeg.on_message(_, message, configuration)
if not message.reply then
return false
elseif not message.reply.photo then
return false
end
mattata.send_chat_action(message.chat.id, 'upload_photo')
local file_id = message.reply.photo[#message.reply.photo].file_id
local file = mattata.get_file(file_id)
if not file then
return false
end
local file_name = file.result.file_path
local file_path = string.format('https://api.telegram.org/file/bot%s/%s', configuration.bot_token, file_name)
- print(file_path)
file = mattata.download_file(file_path, file_name:match('/(.-)$'), '/home/matt/matticatebot')
if not file then
return false
end
local command = string.format('/home/matt/matticatebot/magick %s -quality 4 %s', file, file)
os.execute(command)
local success = mattata.send_photo(message.chat.id, file)
if not success then
return false
end
os.execute('rm ' .. file)
return success
end
return needsmorejpeg
\ No newline at end of file
diff --git a/plugins/netflix.mattata b/plugins/netflix.mattata
index 1a7a433..bc55eca 100644
--- a/plugins/netflix.mattata
+++ b/plugins/netflix.mattata
@@ -1,80 +1,80 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local netflix = {}
local mattata = require('mattata')
local http = require('socket.http')
local url = require('socket.url')
local json = require('dkjson')
function netflix:init()
netflix.commands = mattata.commands(self.info.username)
:command('netflix')
:command('nf').table
netflix.help = '/netflix <query> - Searches Netflix for the given search query and returns the most relevant result. Alias: /nf.'
end
function netflix.send_request(input, language)
local jstr, res = http.request('http://netflixroulette.net/api/api.php?title=' .. url.escape(input))
if res ~= 200
then
return false
end
local jdat = json.decode(jstr)
if jdat.errorcode
then
return false
end
local output = {}
table.insert(
output,
'<b>' .. mattata.escape_html(jdat.show_title) .. '</b>\n'
)
table.insert(
output,
'📅 ' .. jdat.release_year .. ' | ⭐ ' .. jdat.rating .. ' | ' .. mattata.escape_html(jdat.show_cast)
)
table.insert(
output,
'\n<i>' .. mattata.escape_html(jdat.summary) .. '</i>'
)
table.insert(
output,
'\n<a href="https://www.netflix.com/title/' .. jdat.show_id .. '">' .. language['netflix']['1'] .. '</a>'
)
return table.concat(
output,
'\n'
)
end
function netflix:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
netflix.help
)
end
local output = netflix.send_request(
input,
language
)
if not output
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
return mattata.send_message(
message.chat.id,
output,
'html'
)
end
return netflix
\ No newline at end of file
diff --git a/plugins/newchat.mattata b/plugins/newchat.mattata
index 644035d..5db1d8d 100644
--- a/plugins/newchat.mattata
+++ b/plugins/newchat.mattata
@@ -1,76 +1,76 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local newchat = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
local json = require('dkjson')
function newchat:init()
newchat.commands = mattata.commands(self.info.username):command('newchat').table
end
function newchat:on_message(message, configuration, language)
if not mattata.is_global_admin(message.from.id)
then
return false
end
local input = mattata.input(message.text)
if not input
then
return false
end
local link, title = input:match('^(.-) (.-)$')
if not title
then
link = input
title = link
end
if not link
then
return mattata.send_reply(
message,
'Please specify a link to add to the list shown when /groups is sent. You need to use the following syntax: /newchat <link> [title]. If a title isn\'t given, the link will be used as the title too.'
)
elseif not link:match('https?://t%.me/.-$')
then
return mattata.send_reply(
message,
'The link must begin with "https://t.me/"!'
)
end
local entry = json.encode(
{
['link'] = tostring(link),
['title'] = tostring(title)
}
)
local entries = redis:smembers('mattata:configuration:chats')
for k, v in pairs(entries)
do
if not v
or not json.decode(v).link
or not json.decode(v).title
then
return false
elseif json.decode(v).link == link
then
return mattata.send_reply(
message,
'That link already exists in the database, under the name "' .. json.decode(v).title .. '"!'
)
end
end
redis:sadd(
'mattata:configuration:chats',
entry
)
return mattata.send_reply(
message,
'I have added that link to the list shown when /groups is sent, under the name "' .. title .. '"!'
)
end
return newchat
\ No newline at end of file
diff --git a/plugins/news.mattata b/plugins/news.mattata
index 733ea61..01928a2 100644
--- a/plugins/news.mattata
+++ b/plugins/news.mattata
@@ -1,219 +1,219 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local news = {}
local mattata = require('mattata')
local https = require('ssl.https')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function news:init()
news.commands = mattata.commands(self.info.username)
:command('news')
:command('nsources')
:command('setnews').table
news.help = '/news <news source> - Sends the current top story from the given news source. Use /nsources to view a list of available sources. Use /setnews <news source> to set your preferred news source, and be able to use /news without giving any arguments.'
end
function news.send_sources(message, language)
local input = mattata.input(message.text:lower())
if not input then
input = false
else
local success = pcall(function()
return input:match(input)
end)
if not success then
return mattata.send_reply(
message,
string.format(language['news']['1'], mattata.escape_html(input)),
'html'
)
end
end
local sources = news.get_sources(input)
if not sources then
return mattata.send_reply(message, language['news']['2'])
end
sources = table.concat(sources, ', ')
if input then
sources = string.format(
language['news']['3'],
mattata.escape_html(input),
sources
)
else
sources = string.format(language['news']['4'], sources)
end
return mattata.send_message(message.chat.id, sources, 'html')
end
function news.set_news(message, language)
local input = mattata.input(
message.text:lower()
)
if input
then
input = input:gsub('%-', ' ')
end
local preferred_source = redis:get(
string.format(
'user:%s:news',
message.from.id
)
)
if not preferred_source
and not input
then
return mattata.send_reply(
message,
language['news']['5']
)
elseif not input
then
return mattata.send_reply(
message,
string.format(
language['news']['6'],
preferred_source
)
)
elseif preferred_source == input
then
return mattata.send_reply(
message,
string.format(
language['news']['7'],
input
)
)
end
if not news.is_valid(input)
then
return mattata.send_reply(
message,
language['news']['8']
)
end
redis:set(
string.format(
'user:%s:news',
message.from.id
),
input
)
return mattata.send_reply(
message,
string.format(
language['news']['9'],
input
)
)
end
function news.is_valid(source)
local sources = news.get_sources()
for k, v in pairs(sources)
do
if v == source
then
return true
end
end
return false
end
function news.get_sources(input)
local jstr, res = https.request('https://newsapi.org/v1/sources')
if res ~= 200
then
return false
end
local jdat = json.decode(jstr)
if jdat.status ~= 'ok'
then
return false
end
local sources = {}
for k, v in pairs(jdat.sources)
do
v.id = v.id:gsub('%-', ' ')
if input
then
if v.id:match(input)
then
table.insert(
sources,
v.id
)
end
else
table.insert(
sources,
v.id
)
end
end
table.sort(sources)
return sources
end
function news:on_message(message, configuration, language)
if message.text:match('^[/!#]nsources')
then
return news.send_sources(
message,
language
)
elseif message.text:match('^[/!#]setnews')
then
return news.set_news(
message,
language
)
end
local input = mattata.input(
message.text:lower()
)
if not input
then
local user = string.format('user:%s:news', message.from.id)
local preferred_source = redis:get(user)
if preferred_source then
input = preferred_source
else
return mattata.send_reply(message, news.help)
end
end
input = input:gsub('-', ' ')
if not news.is_valid(input) then
return mattata.send_reply(message, language['news']['10'])
end
input = input:gsub('%s', '-')
local jstr, res = https.request('https://newsapi.org/v1/articles?apiKey=' .. configuration.keys.news .. '&source=' .. input .. '&sortBy=top')
if res ~= 200 then
return mattata.send_reply(message, language['errors']['connection'])
end
local jdat = json.decode(jstr)
if not jdat.articles[1]
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
jdat.articles[1].publishedAt = jdat.articles[1].publishedAt:gsub('T.-$', '')
local output = string.format(
'<b>%s</b> <code>[%s]</code>\n%s\n<a href="%s">%s</a>\n<i>Powered by NewsAPI.</i>',
jdat.articles[1].title,
mattata.escape_html(jdat.articles[1].publishedAt),
jdat.articles[1].description,
jdat.articles[1].url,
language['news']['11']
)
return mattata.send_message(message.chat.id, output, 'html')
end
return news
\ No newline at end of file
diff --git a/plugins/paste.mattata b/plugins/paste.mattata
index 4f2b907..03b66bc 100644
--- a/plugins/paste.mattata
+++ b/plugins/paste.mattata
@@ -1,154 +1,154 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local paste = {}
local mattata = require('mattata')
local https = require('ssl.https')
local http = require('socket.http')
local url = require('socket.url')
local ltn12 = require('ltn12')
local mime = require('mime')
local multipart = require('multipart-post')
local json = require('dkjson')
local configuration = require('configuration')
function paste:init()
paste.commands = mattata.commands(self.info.username):command('paste').table
paste.help = '/paste <text> - Uploads the given text, or replied-to text to a pasting service and returns the result URL.'
end
function paste.get_keyboard()
return mattata.inline_keyboard()
:row(
mattata.row()
:callback_data_button(
'paste.ee',
'paste:pasteee'
)
:callback_data_button(
'pastebin.com',
'paste:pastebin'
)
:callback_data_button(
'hastebin.com',
'paste:hastebin'
)
)
end
function paste.pasteee(input, id)
input = '{"description":"' .. id .. ' via mattata","sections":[{"name":"Paste","syntax":"autodetect","contents":"' .. url.escape(input) .. '"}]}'
local response = {}
local _, res = https.request(
{
['url'] = 'https://api.paste.ee/v1/pastes',
['method'] = 'POST',
['headers'] = {
['Content-Type'] = 'application/json',
['Content-Length'] = input:len(),
['Authorization'] = 'Basic ' .. mime.b64(configuration.keys.pasteee .. ':')
},
['source'] = ltn12.source.string(input),
['sink'] = ltn12.sink.table(response)
}
)
if res ~= 201 then
return false
end
local jstr = table.concat(response)
local jdat = json.decode(jstr)
if not jdat or not jdat.success then
return false
end
return jdat.link
end
function paste.pastebin(input)
local parameters = {
['api_dev_key'] = configuration.keys.pastebin,
['api_option'] = 'paste',
['api_paste_code'] = input
}
local response = {}
local body, boundary = multipart.encode(parameters)
local _, res = http.request(
{
['url'] = 'http://pastebin.com/api/api_post.php',
['method'] = 'POST',
['headers'] = {
['Content-Type'] = 'multipart/form-data; boundary=' .. boundary,
['Content-Length'] = #body
},
['source'] = ltn12.source.string(body),
['sink'] = ltn12.sink.table(response)
}
)
if res ~= 200
then
return false
end
return table.concat(response)
end
function paste.hastebin(input)
local parameters = {
['data'] = input
}
local response = {}
local body, boundary = multipart.encode(parameters)
local _, res, head = https.request(
{
['url'] = 'https://hasteb.in/documents',
['method'] = 'POST',
['headers'] = {
['Content-Type'] = 'multipart/form-data; boundary=' .. boundary,
['Content-Length'] = #body
},
['redirect'] = false,
['source'] = ltn12.source.string(body),
['sink'] = ltn12.sink.table(response)
}
)
if res ~= 200
then
return false
end
local jdat = json.decode(table.concat(response))
if not jdat
or not jdat.key
then
return false
end
return 'https://hasteb.in/' .. jdat.key
end
function paste:on_callback_query(callback_query, message, configuration, language)
local input = mattata.input(message.reply.text)
if not input then
return false
end
local output
if callback_query.data == 'pasteee' then
output = paste.pasteee(input, callback_query.from.id)
elseif callback_query.data == 'pastebin' then
output = paste.pastebin(input)
elseif callback_query.data == 'hastebin' then
output = paste.hastebin(input)
end
if not output then
return mattata.answer_callback_query(callback_query.id, language['errors']['generic'])
end
return mattata.edit_message_text(message.chat.id, message.message_id, output, nil, true, paste.get_keyboard())
end
function paste:on_message(message, configuration, language)
local input = message.reply and message.reply.text or mattata.input(message.text)
if not input then
return mattata.send_reply(message, paste.help)
end
return mattata.send_message(message.chat.id, language['paste']['1'], nil, true, false, message.message_id, paste.get_keyboard())
end
return paste
\ No newline at end of file
diff --git a/plugins/ping.mattata b/plugins/ping.mattata
index 586ee48..039c09a 100644
--- a/plugins/ping.mattata
+++ b/plugins/ping.mattata
@@ -1,18 +1,18 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local ping = {}
local mattata = require('mattata')
function ping:init()
ping.commands = mattata.commands(self.info.username):command('ping').table
ping.help = '/ping - PONG!'
end
function ping.on_message(_, message)
return mattata.send_sticker(message.chat.id, 'CAADBAAD1QIAAlAYNw2Pr-ymr7r8TgI')
end
return ping
\ No newline at end of file
diff --git a/plugins/place.mattata b/plugins/place.mattata
index 4e55f9c..ecad114 100644
--- a/plugins/place.mattata
+++ b/plugins/place.mattata
@@ -1,81 +1,81 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local place = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
local configuration = require('configuration')
function place:init()
place.commands = mattata.commands(self.info.username):command('place').table
place.help = '/place <name/phone> - Finds a place on Google Maps.'
end
function place:on_inline_query(inline_query, configuration)
local input = mattata.input(inline_query.query)
local is_phone = false
if not input then
return false, 'Please specify a location!'
elseif input:match('^%+') then
is_phone = true
end
local jdat, lat, lng = place.get(input, is_phone, configuration.keys.maps)
if not jdat then
return false, lat
end
return mattata.answer_inline_query(
inline_query.id,
json.encode({{
['type'] = 'location',
['id'] = '1',
['latitude'] = tonumber(jdat.latitude),
['longitude'] = tonumber(jdat.longitude),
['title'] = input
}
}))
end
function place.get(location, is_phone, api_key)
local input_type = is_phone and 'phonenumber' or 'textquery'
if input_type == 'phonenumber' then
location = location:gsub(' ', '') -- get rid of any spaces in the phone number to prevent api issues
end
local jstr, res = https.request('https://maps.googleapis.com/maps/api/place/findplacefromtext/json?key=' .. api_key .. '&input=' .. url.escape(location) .. '&inputtype=' .. input_type)
if res ~= 200 then
return false, configuration.errors.connection
end
local jdat = json.decode(jstr)
if jdat.status == 'ZERO_RESULTS' then
return false, configuration.errors.results
end
local place_id = jdat.candidates[1].place_id
jstr, res = https.request('https://maps.googleapis.com/maps/api/place/details/json?key=' .. api_key .. '&place_id=' .. place_id .. '&fields=address_component,name,geometry')
jdat = json.decode(jstr)
return true, jdat.result.geometry.location.lat, jdat.result.geometry.location.lng
end
function place:on_message(message, configuration)
local input = mattata.input(message.text)
local is_phone = false
if not input then
return mattata.send_reply(
message,
'Please specify a place by its name or phone number!'
)
elseif input:match('^%+') then
is_phone = true
end
local success, lat, lng = place.get(input, is_phone, configuration.keys.maps)
if not success then
mattata.send_reply(message, lat)
return false
end
mattata.send_location(message.chat.id, lat, lng)
end
return place
\ No newline at end of file
diff --git a/plugins/plugins.mattata b/plugins/plugins.mattata
index 1dfd6e3..ffda443 100644
--- a/plugins/plugins.mattata
+++ b/plugins/plugins.mattata
@@ -1,321 +1,321 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local plugins = {}
local mattata = require('mattata')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
local configuration = require('configuration')
function plugins:init()
plugins.commands = mattata.commands(self.info.username):command('plugins').table
plugins.help = '/plugins - Toggle the plugins you want to use in your chat with a slick inline keyboard, paginated and neatly formatted.'
end
function plugins.get_toggleable_plugins()
local toggleable = {}
for _, v in pairs(configuration.plugins) do
if not mattata.table_contains(configuration.administrative_plugins, v) then
if v ~= 'plugins' and v ~= 'control' and v ~= 'bash' and v ~= 'lua' and v ~= 'gwhitelist' and v ~= 'gblacklist' and v ~= 'administration' then
v = v:gsub('_', ' ')
table.insert(toggleable, v)
end
end
end
table.sort(toggleable)
return toggleable
end
function plugins.get_keyboard(chat, page, columns, per_page)
page = page or 1
local toggleable = plugins.get_toggleable_plugins()
local page_count = math.floor(#toggleable / per_page)
if page_count < #toggleable / per_page then
page_count = page_count + 1
end
if page < 1 then
page = page_count
elseif page > page_count then
page = 1
end
local start_res = (page * per_page) - (per_page - 1)
local end_res = start_res + (per_page - 1)
if end_res > #toggleable then
end_res = #toggleable
end
local plugin = 0
local output = {}
for _, v in pairs(toggleable) do
v = v:lower()
plugin = plugin + 1
if plugin >= start_res and plugin <= end_res then
local status
if not mattata.is_plugin_disabled(v, chat) then
status = utf8.char(9989)
else
status = utf8.char(10060)
end
table.insert(output, {
['plugin'] = v,
['status'] = status
})
end
end
local keyboard = {
['inline_keyboard'] = {
{}
}
}
local columns_per_page = math.floor(#output / columns)
if columns_per_page < (#output / columns) then
columns_per_page = columns_per_page + 1
end
local rows_per_page = math.floor(#output / columns_per_page)
if rows_per_page < (#output / columns_per_page) then
rows_per_page = rows_per_page + 1
end
local current_row = 1
local count = 0
for n in pairs(output) do
count = count + 1
if count == (rows_per_page * current_row) + 1 then
current_row = current_row + 1
table.insert(
keyboard.inline_keyboard,
{}
)
end
table.insert(
keyboard.inline_keyboard[current_row],
{
['text'] = output[n].plugin:gsub('^%l', string.upper),
['callback_data'] = string.format(
'plugins:%s:%s:%s',
chat,
output[n].plugin,
page
)
}
)
table.insert(
keyboard.inline_keyboard[current_row],
{
['text'] = output[n].status,
['callback_data'] = string.format(
'plugins:%s:%s:%s',
chat,
output[n].plugin,
page
)
}
)
end
table.insert(
keyboard.inline_keyboard,
{
{
['text'] = utf8.char(8592) .. ' Previous',
['callback_data'] = string.format(
'plugins:%s:page:%s',
chat,
page - 1
)
},
{
['text'] = string.format(
'%s/%s',
page,
page_count
),
['callback_data'] = 'plugins:nil'
},
{
['text'] = 'Next ' .. utf8.char(8594),
['callback_data'] = string.format(
'plugins:%s:page:%s',
chat,
page + 1
)
}
}
)
table.insert(
keyboard.inline_keyboard,
{
{
['text'] = 'Disable All',
['callback_data'] = string.format(
'plugins:%s:disable_all:%s',
chat,
page
)
},
{
['text'] = 'Enable All',
['callback_data'] = string.format(
'plugins:%s:enable_all:%s',
chat,
page
)
}
}
)
table.insert(
keyboard.inline_keyboard,
{
{
['text'] = 'Back',
['callback_data'] = 'help:settings'
}
}
)
return keyboard
end
function plugins.on_callback_query(_, callback_query, message, _)
if not callback_query.data:match('^.-:.-:.-$') then
return
end
local chat, callback_type, page = callback_query.data:match('^(.-):(.-):(.-)$')
if (
mattata.get_chat(chat) and mattata.get_chat(chat).result.type ~= 'private'
) and not mattata.is_group_admin(
chat,
callback_query.from.id
) then
return mattata.answer_callback_query(
callback_query.id,
'You must be an administrator to use this!'
)
end
local toggle_status
if callback_type ~= 'page' then
local toggleable = plugins.get_toggleable_plugins()
if callback_type == 'enable_all' then
for _, v in pairs(toggleable) do
redis:srem('disabled_plugins:' .. chat, v)
end
toggle_status = 'All plugins enabled!'
elseif callback_type == 'disable_all' then
for _, v in pairs(toggleable) do
redis:sadd('disabled_plugins:' .. chat, v)
end
toggle_status = 'All plugins disabled!'
elseif callback_type == 'enable_via_message' or callback_type == 'enable' then
redis:srem('disabled_plugins:' .. chat, page)
return mattata.answer_callback_query(
callback_query.id,
page:gsub('^%l', string.upper) .. ' has been enabled!'
)
elseif callback_type == 'dismiss_disabled_message' then
redis:set(
string.format(
'chat:%s:dismiss_disabled_message:%s',
chat,
page
),
true
)
return mattata.answer_callback_query(
callback_query.id,
'You will no longer be notified about this plugin!'
)
else
if mattata.is_plugin_disabled(callback_type, chat) then
redis:srem('disabled_plugins:' .. chat, callback_type)
toggle_status = callback_type:gsub('^%l', string.upper) .. ' enabled!'
else
redis:sadd('disabled_plugins:' .. chat, callback_type)
toggle_status = callback_type:gsub('^%l', string.upper) .. ' disabled!'
end
end
end
local keyboard = plugins.get_keyboard(
chat,
tonumber(page),
2,
10
)
mattata.edit_message_reply_markup(
message.chat.id,
message.message_id,
nil,
json.encode(keyboard)
)
return mattata.answer_callback_query(callback_query.id, toggle_status)
end
function plugins:on_message(message)
if message.chat.type ~= 'private' and not mattata.is_group_admin(
message.chat.id,
message.from.id
) then
return mattata.send_reply(
message,
'You must be an administrator to use this!'
)
elseif message.chat.type == 'private' then
local input = mattata.input(message.text)
if input then
if tonumber(input) == nil and not input:match('^%@') then
input = '@' .. input
end
local resolved = mattata.get_chat(input)
if resolved and mattata.is_group_admin(
resolved.result.id,
message.from.id
) then
message.chat = resolved.result
elseif not resolved then
return mattata.send_reply(
message,
'That\'s not a valid chat!'
)
else
return mattata.send_reply(
message,
'You don\'t appear to be an administrator in that chat!'
)
end
end
end
local keyboard = plugins.get_keyboard(
message.chat.id,
1,
2,
10
)
local success = mattata.send_message(
message.from.id,
string.format(
'Toggle the plugins for <b>%s</b> using the keyboard below:',
message.chat.title and mattata.escape_html(message.chat.title) or mattata.escape_html(message.chat.first_name)
),
'html',
true,
false,
nil,
json.encode(keyboard)
)
if message.chat.type == 'private' then
return
elseif not success then
return mattata.send_reply(
message,
string.format(
'I couldn\'t send you the plugin management menu, you need to send me a [private message](https://t.me/%s?start=plugins%%20' .. message.chat.id .. ') first, then try using /plugins again.',
self.info.username:lower()
),
'markdown',
true
)
end
return mattata.send_reply(
message,
'I have sent you the plugin management menu via private chat.'
)
end
return plugins
\ No newline at end of file
diff --git a/plugins/pokedex.mattata b/plugins/pokedex.mattata
index a67d1e5..c1e81e1 100644
--- a/plugins/pokedex.mattata
+++ b/plugins/pokedex.mattata
@@ -1,84 +1,84 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local pokedex = {}
local mattata = require('mattata')
local http = require('socket.http')
local url = require('socket.url')
local json = require('dkjson')
function pokedex:init()
pokedex.commands = mattata.commands(self.info.username)
:command('pokedex')
:command('dex').table
pokedex.help = '/pokedex <query> - Returns a Pokedex entry from pokeapi.co. Alias: /dex.'
end
function pokedex:on_message(message, configuration, language)
local input = mattata.input(message.text:lower())
if not input
then
return mattata.send_reply(
message,
pokedex.help
)
end
local jstr, res = http.request('http://pokeapi.co/api/v1/pokemon/' .. url.escape(input))
if res ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local jdat = json.decode(jstr)
local name = jdat.name:gsub('^%l', string.upper)
local id = '#' .. jdat.national_id
local description_url = 'http://pokeapi.co' .. jdat.descriptions[math.random(#jdat.descriptions)].resource_uri
local description_jstr, description_res = http.request(description_url)
if description_res ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
mattata.send_chat_action(
message.chat.id,
'upload_photo'
)
local description_jdat = json.decode(description_jstr)
local description = description_jdat.description
:gsub('POKMON', 'Pokémon')
:gsub('Pokmon', 'Pokémon')
:gsub('Pokemon', 'Pokémon')
:gsub('POKéMON', 'Pokémon')
local poke_type
for _, v in ipairs(jdat.types)
do
local type_name = v.name:gsub('^%l', string.upper)
if not poke_type
then
poke_type = type_name
else
poke_type = poke_type .. ' / ' .. type_name
end
end
poke_type = poke_type .. ' type'
return mattata.send_photo(
message.chat.id,
'https://img.pokemondb.net/artwork/' .. name:gsub('^%u', string.lower) .. '.jpg',
string.format(
language['pokedex']['1'],
name,
id,
poke_type,
description
)
)
end
return pokedex
\ No newline at end of file
diff --git a/plugins/pun.mattata b/plugins/pun.mattata
index 7f491aa..7485765 100644
--- a/plugins/pun.mattata
+++ b/plugins/pun.mattata
@@ -1,148 +1,148 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local pun = {}
local mattata = require('mattata')
function pun:init()
pun.commands = mattata.commands(self.info.username):command('pun').table
pun.help = '/pun - Generates a random pun.'
end
local puns = {
'The person who invented the door-knock won the No-bell prize.',
'I couldn\'t work out how to fasten my seatbelt. Then it clicked.',
'Never trust atoms; they make up everything.',
'Singing in the shower is all fun and games until you get shampoo in your mouth - Then it becomes a soap opera.',
'I can\'t believe I got fired from the calendar factory. All I did was take a day off.',
'To the guy who invented zero: Thanks for nothing!',
'Enough with the cripple jokes! I just can\'t stand them.',
'I\'ve accidentally swallowed some Scrabble tiles. My next crap could spell disaster.',
'How does Moses make his tea? Hebrews it.',
'Did you hear about the guy who got hit in the head with a can of soda? He was lucky it was a soft drink.',
'When William joined the army he disliked the phrase \'fire at will\'.',
'There was a sign on the lawn at a rehab center that said \'Keep off the Grass\'.',
'I wondered why the baseball was getting bigger. Then it hit me.',
'I can hear music coming out of my printer. I think the paper\'s jamming again.',
'I have a few jokes about unemployed people, but none of them work',
'Want to hear a construction joke? I\'m working on it',
'I always take a second pair of pants when I go golfing, in case I get a hole in one.',
'I couldn\'t remember how to catch a boomerang, but then it came back to me.',
'I\'ve decided that my Wi-Fi router will be my valentine this year. I don\'t know why, we just have this connection.',
'A prisoner\'s favourite punctuation mark is the period. It marks the end of his sentence.',
'I used to go fishing with Skrillex, but he kept dropping the bass.',
'Two antennae met on a roof and got married. The wedding was okay, but the reception was incredible.',
'A book just fell on my head. I\'ve only got my shelf to blame.',
'I dropped my steak on the floor. Now it\'s ground beef.',
'I used to have a fear of hurdles, but I got over it.',
'The outcome of war does not prove who is right, but only who is left.',
'Darth Vader tries not to burn his food, but it always comes out a little on the dark side.',
'The store keeps calling me to buy more furniture, but all I wanted was a one night stand.',
'This girl said she recognized me from the vegetarian club, but I\'d never met herbivore.',
'Police arrested two kids yesterday, one was drinking battery acid, the other was eating fireworks. They charged one and let the other one off...',
'No more Harry Potter jokes guys. I\'m Sirius.',
'It was hard getting over my addiction to hokey pokey, but I\'ve turned myself around.',
'It takes a lot of balls to golf the way I do.',
'Why did everyone want to hang out with the mushroom? Because he was a fungi.',
'How much does a hipster weigh? An instagram.',
'I used to be addicted to soap, but I\'m clean now.',
'When life gives you melons, you\'re probably dyslexic.',
'What\'s with all the blind jokes? I just don\'t see the point.',
'If Apple made a car, would it have Windows?',
'Need an ark? I Noah guy.',
'The scarecrow won an award because he was outstanding in his field.',
'What\'s the difference between a man in a tux on a bicycle, and a man in a sweatsuit on a trycicle? A tire.',
'What do you do with a sick chemist? If you can\'t helium, and you can\'t curium, you\'ll just have to barium.',
'I\'m reading a book about anti-gravity. It\'s impossible to put down.',
'Trying to write with a broken pencil is pointless.',
'When TVs go on vacation, they travel to remote islands.',
'I was going to tell a midget joke, but it\'s too short.',
'Jokes about German sausages are the wurst.',
'How do you organize a space party? You planet.',
'Sleeping comes so naturally to me, I could do it with my eyes closed.',
'I\'m glad I learned sign language; it\'s pretty handy.',
'Atheism is a non-prophet organization.',
'Velcro: What a rip-off!',
'If they made a Minecraft movie, it would be a blockbuster.',
'I don\'t trust people with graph paper. They\'re always plotting something',
'I had a friend who was addicted to brake fluid. He says he can stop anytime.',
'The form said I had Type A blood, but it was a Type O.',
'I went to to the shop to buy eight Sprites - I came home and realised I\'d picked 7-Up.',
'There was an explosion at a pie factory. 3.14 people died.',
'A man drove his car into a tree and found out how a Mercedes bends.',
'The experienced carpenter really nailed it, but the new guy screwed everything up.',
'I didn\'t like my beard at first, but then it grew on me.',
'Smaller babies may be delivered by stork, but the heavier ones need a crane.',
'What\'s the definition of a will? It\'s a dead giveaway.',
'I was going to look for my missing watch, but I could never find the time.',
'I hate elevators, and I often take steps to avoid them.',
'Did you hear about the guy whose whole left side was cut off? He\'s all right now.',
'It\'s not that the man did not know how to juggle, he just didn\'t have the balls to do it.',
'I used to be a loan shark, but I lost interest',
'I don\'t trust these stairs; they\'re always up to something.',
'My friend\'s bakery burned down last night. Now his business is toast.',
'Don\'t trust people that perform acupuncture; they\'re back stabbers.',
'The man who survived mustard gas and pepper spray is now a seasoned veteran.',
'Police were called to a daycare where a three-year-old was resisting a rest.',
'When Peter Pan punches, they Neverland',
'The shoemaker did not deny his apprentice anything he needed. He gave him his awl.',
'I did a theatrical performance about puns. It was a play on words.',
'Show me a piano falling down a mineshaft and I\'ll show you A-flat minor.',
'Have you ever tried to eat a clock? It\'s very time consuming.',
'There was once a cross-eyed teacher who couldn\'t control his pupils.',
'A new type of broom came out and it is sweeping the nation.',
'I relish the fact that you\'ve mustard the strength to ketchup to me.',
'I knew a woman who owned a taser. Man, was she stunning!',
'What did the grape say when it got stepped on? Nothing - but it let out a little whine.',
'It was an emotional wedding. Even the cake was in tiers.',
'When a clock is hungry it goes back four seconds.',
'The dead batteries were given out free of charge.',
'Why are there no knock-knock jokes about America? Because freedom rings.',
'When the cannibal showed up late to dinner, they gave him the cold shoulder.',
'I should have been sad when my flashlight died, but I was delighted.',
'Why don\'t tennis players ever get married? Love means nothing to them.',
'Pterodactyls can\'t be heard going to the bathroom because the P is silent.',
'Mermaids make calls on their shell phones.',
'What do you call an aardvark with three feet? A yaardvark.',
'Captain Kirk has three ears: A right ear, a left ear, and a final front ear.',
'How do celebrities stay cool? They have a lot of fans.',
'Without geometry, life is pointless.',
'Did you hear about the cow who tried to jump over a barbed-wire fence? It ended in udder destruction.',
'The truth may ring like a bell, but it is seldom ever tolled.',
'I used to work for the IRS, but my job was too taxing.',
'I used to be a programmer, but then I lost my drive.',
'Pediatricians are doctors with little patients.',
'I finally fired my masseuse today. She always rubbed me the wrong way.',
'I stayed up all night wondering where the sun went. Then it dawned on me.',
'What\'s the difference between a man and his dog? The man wears a suit; the dog just pants.',
'A psychic midget who escapes from prison is a small medium at large.',
'I\'ve been to the dentist several times, so I know the drill.',
'The roundest knight at King Arthur\'s round table was Sir Cumference. He acquired his size from too much pi.',
'She was only a whiskey maker, but he loved her still.',
'Male deer have buck teeth.',
'Whiteboards are remarkable.',
'Visitors in Cuba are always Havana good time.',
'Why does electricity shock people? It doesn\'t know how to conduct itself.',
'Lancelot had a scary dream about his horse. It was a knight mare.',
'A tribe of cannibals captured a missionary and ate him. Afterwards, they all had violent food poisoning. This just goes to show that you can\'t keep a good man down.',
'Heaven for gamblers is a paradise.',
'Old wheels aren\'t thrown away, they\'re just retired.',
'Horses are very stable animals.',
'Bankers don\'t crash, they just lose their balance.',
'The career of a skier can go downhill very fast.',
'In democracy, it\'s your vote that counts. In feudalism, it\'s your count that votes.',
'A sea lion is nothing but an ionized seal.',
'The vegetables from my garden aren\'t that great. I guess you could say they\'re mediokra.'
}
function pun:on_message(message)
return mattata.send_message(
message.chat.id,
puns[math.random(#puns)]
)
end
return pun
\ No newline at end of file
diff --git a/plugins/quote.mattata b/plugins/quote.mattata
index d994c42..3298ead 100644
--- a/plugins/quote.mattata
+++ b/plugins/quote.mattata
@@ -1,67 +1,67 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local quote = {}
local mattata = require('mattata')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function quote:init()
quote.commands = mattata.commands(self.info.username):command('quote').table
quote.help = '/quote - Returns a randomly-selected, quoted message from the replied-to user. Quoted messages are stored when a user uses /save in reply to the said user\'s message(s).'
end
function quote:on_message(message, configuration, language)
if not message.reply then
local quotes = redis:keys('quotes:*')
if not next(quotes) or #quotes < 1 then
return false
end
local quote = quotes[math.random(#quotes)]
local user = quote:match('^quotes:(%d+)$')
user = mattata.get_user(user)
user = type(user) == 'table' and user.result or {
['name'] = 'Anonymous'
}
quote = redis:get(quote)
quote = json.decode(quote)
return mattata.send_reply(
message,
string.format(
'<i>%s</i>\n– %s%s',
mattata.escape_html(quote[math.random(#quote)]),
mattata.escape_html(user.name),
user.username and ' (@' .. user.username .. ')' or ''
), 'html'
)
elseif redis:get('user:' .. message.reply.from.id .. ':opt_out') then
redis:del('quotes:' .. message.reply.from.id)
local output = language['quote']['1']
return mattata.send_reply(message, output)
end
local quotes = redis:get('quotes:' .. message.reply.from.id)
if not quotes then
return mattata.send_reply(
message,
string.format(
language['quote']['2'],
message.reply.from.username and '@' or '',
message.reply.from.username or message.reply.from.first_name
)
)
end
quotes = json.decode(quotes)
return mattata.send_reply(
message,
string.format(
'<i>%s</i>\n– %s%s',
mattata.escape_html(quotes[math.random(#quotes)]),
mattata.escape_html(message.reply.from.name),
message.reply.from.username and ' (@' .. message.reply.from.username .. ')' or ''
), 'html'
)
end
return quote
\ No newline at end of file
diff --git a/plugins/quotes.mattata b/plugins/quotes.mattata
index bd29023..d06b76b 100644
--- a/plugins/quotes.mattata
+++ b/plugins/quotes.mattata
@@ -1,338 +1,338 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local quotes = {}
local mattata = require('mattata')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function quotes:init()
quotes.commands = mattata.commands(self.info.username):command('quotes').table
quotes.help = '/quotes - Edit which quotes are saved in the database under your name.'
end
function quotes.get_quote(user, quote_number)
quote_number = tonumber(quote_number)
local quotes = redis:get('quotes:' .. user)
if not quotes
then
return 'You don\'t have any quotes!'
end
quotes = json.decode(quotes)
if #quotes < quote_number
then
return 'Invalid quote number!'
end
return quotes[quote_number]
end
function quotes.get_confirmation_keyboard(user, quote_number, page)
quote_number = tonumber(quote_number)
local all = redis:get('quotes:' .. user)
if not all
then
return {}
end
all = json.decode(all)
if not all[quote_number]
then
return {}
end
return mattata.inline_keyboard():row(
mattata.row()
:callback_data_button(
'Delete',
'quotes:' .. user .. ':delete:' .. quote_number
)
:callback_data_button(
'Back',
'quotes:' .. user .. ':back:' .. page
)
)
end
function quotes.get_quotes(user)
local all = redis:get('quotes:' .. user)
if not all
then
return false
end
return json.decode(all)
end
function quotes.get_keyboard(user, page, columns, per_page)
page = page
or 1
local toggleable = quotes.get_quotes(user)
if not toggleable
then
return false
end
local page_count = math.floor(#toggleable / per_page)
if page_count < #toggleable / per_page
then
page_count = page_count + 1
end
if page < 1
then
page = page_count
elseif page > page_count
then
page = 1
end
local start_res = (page * per_page) - (per_page - 1)
local end_res = start_res + (per_page - 1)
if end_res > #toggleable
then
end_res = #toggleable
end
local quote = 0
local output = {}
for k, v in pairs(toggleable)
do
quote = quote + 1
if quote >= start_res
and quote <= end_res
then
table.insert(
output,
{
['quote_number'] = k,
['quote_text'] = v
}
)
end
end
local keyboard = {
['inline_keyboard'] = {
{}
}
}
local columns_per_page = math.floor(#output / columns)
if columns_per_page < (#output / columns)
then
columns_per_page = columns_per_page + 1
end
local rows_per_page = math.floor(#output / columns_per_page)
if rows_per_page < (#output / columns_per_page)
then
rows_per_page = rows_per_page + 1
end
local current_row = 1
local count = 0
for n in pairs(output)
do
count = count + 1
if count == (rows_per_page * current_row) + 1
then
current_row = current_row + 1
table.insert(
keyboard.inline_keyboard,
{}
)
end
table.insert(
keyboard.inline_keyboard[current_row],
{
['text'] = tostring(output[n].quote_number) .. ': ' .. output[n].quote_text,
['callback_data'] = string.format(
'quotes:%s:%s:%s',
user,
output[n].quote_number,
page
)
}
)
end
if page_count > 1
then
table.insert(
keyboard.inline_keyboard,
{
{
['text'] = utf8.char(8592) .. ' Previous',
['callback_data'] = string.format(
'quotes:%s:page:%s',
user,
page - 1
)
},
{
['text'] = string.format(
'%s/%s',
page,
page_count
),
['callback_data'] = 'quotes:nil'
},
{
['text'] = 'Next ' .. utf8.char(8594),
['callback_data'] = string.format(
'quotes:%s:page:%s',
user,
page + 1
)
}
}
)
end
if count <= 0
then
return false
end
table.insert(
keyboard.inline_keyboard,
{
{
['text'] = 'Delete All',
['callback_data'] = string.format(
'quotes:%s:delete_all:%s',
user,
page
)
}
}
)
return keyboard
end
function quotes:on_callback_query(callback_query, message, configuration)
if not callback_query.data:match('^.-:.-:.-$')
then
return
end
local user, callback_type, page = callback_query.data:match('^(.-):(.-):(.-)$')
if tostring(callback_query.from.id) ~= tostring(user)
then
return mattata.answer_callback_query(
callback_query.id,
'You are not allowed to use this!'
)
end
if callback_type == 'delete_all'
then
if redis:get('quotes:' .. callback_query.from.id)
then
redis:del('quotes:' .. callback_query.from.id)
end
elseif callback_type == 'back' or callback_type == 'page'
then
local success = mattata.edit_message_text(
message.chat.id,
message.message_id,
'Please select a quote:',
nil,
false,
quotes.get_keyboard(
callback_query.from.id,
tonumber(page),
2,
10
)
)
if not success
then
return mattata.edit_message_text(
message.chat.id,
message.message_id,
'All quotes saved under your database entry have already been deleted!'
)
end
return
elseif callback_type == 'delete'
then
if not redis:get('quotes:' .. callback_query.from.id)
then
return mattata.answer_callback_query(
callback_query.id,
'All quotes saved under your database entry have already been deleted!'
)
end
local all = json.decode(
redis:get('quotes:' .. callback_query.from.id)
)
page = tonumber(page)
if not all[page]
then
return mattata.answer_callback_query(
callback_query.id,
'This quote no longer exists!'
)
end
all[page] = nil
redis:set(
'quotes:' .. callback_query.from.id,
json.encode(all)
)
return mattata.answer_callback_query(
callback_query.id,
'That quote has been deleted from my database!'
)
elseif callback_type == 'back'
then
return mattata.edit_message_reply_markup(
message.chat.id,
message.message_id,
nil,
quotes.get_keyboard(
callback_query.from.id,
tonumber(page),
2,
10
)
)
end
local keyboard = quotes.get_confirmation_keyboard(
callback_query.from.id,
callback_type,
page
)
local success = mattata.edit_message_text(
message.chat.id,
message.message_id,
quotes.get_quote(
callback_query.from.id,
callback_type
),
nil,
false,
json.encode(keyboard)
)
if not success
then
return mattata.edit_message_text(
message.chat.id,
message.message_id,
'All quotes saved under your database entry have been deleted!'
)
end
end
function quotes:on_message(message, configuration)
local keyboard = quotes.get_keyboard(
message.from.id,
1,
2,
10
)
if not keyboard
then
return mattata.send_reply(
message,
'You don\'t have any quotes saved in my database! Use /save in reply to one of your messages to save it!'
)
end
return mattata.send_message(
message.chat.id,
'Please select a quote:',
nil,
true,
false,
nil,
json.encode(keyboard)
)
end
return quotes
\ No newline at end of file
diff --git a/plugins/reddit.mattata b/plugins/reddit.mattata
index 0289da9..f73a9eb 100644
--- a/plugins/reddit.mattata
+++ b/plugins/reddit.mattata
@@ -1,75 +1,75 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local reddit = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
function reddit:init()
reddit.commands = mattata.commands(self.info.username, { '^/r/' }):command('r/'):command('reddit').table
reddit.help = '/r/subreddit - Returns the latest posts from the given subreddit.'
end
function reddit.format_results(posts)
local output = {}
if #posts == 0 then
return false
end
for k, v in pairs(posts) do
local post = v.data
local title = post.title
if title:len() > 250 then
title = mattata.trim(title:sub(1, 250)) .. '...'
end
local short_url = 'redd.it/' .. post.id
local result = '<a href="' .. mattata.escape_html(short_url) .. '">' .. mattata.escape_html(title) .. '</a>'
if post.domain and not post.is_self then
post.url = mattata.escape_html(post.url)
post.domain = mattata.escape_html(post.domain)
result = mattata.symbols.bullet .. ' <code>[</code><a href="' .. post.url .. '">' .. post.domain .. '</a><code>]</code> ' .. result
table.insert(output, result)
end
end
return table.concat(output, '\n')
end
function reddit:on_message(message, configuration, language)
local limit = message.chat.type ~= 'private' and 4 or 8
local input = mattata.input(message.text)
local subreddit = message.text:match('^/r/([%w][%w_]+)%s?')
if input and not subreddit then
subreddit = input
elseif not input and not subreddit then
return mattata.send_reply(message, reddit.help)
end
if not subreddit or subreddit:len() > 21 or subreddit:len() < 2 then
return mattata.send_reply(message, 'That\'s not a valid subreddit!')
end
local output = '<b>/r/' .. subreddit .. '</b>\n'
local request_url = 'https://www.reddit.com/.json?limit=' .. limit
if subreddit ~= 'all' then
request_url = 'https://www.reddit.com/r/' .. subreddit .. '/.json?limit=' .. limit
end
local old_timeout = https.TIMEOUT
https.TIMEOUT = 1
local jstr, res = https.request(request_url)
https.TIMEOUT = old_timeout
if res == 404 or res == 'wantread' then
return mattata.send_reply(message, language['errors']['results'])
elseif res ~= 200 then
return mattata.send_reply(message, language['errors']['connection'])
end
local jdat = json.decode(jstr)
if not jdat or not jdat.data or #jdat.data.children < 1 then
return mattata.send_reply(message, language['errors']['results'])
end
output = output .. reddit.format_results(jdat.data.children)
return mattata.send_message(message.chat.id, output, 'html', true)
end
return reddit
\ No newline at end of file
diff --git a/plugins/remind.mattata b/plugins/remind.mattata
index d706ba3..ba27b24 100644
--- a/plugins/remind.mattata
+++ b/plugins/remind.mattata
@@ -1,196 +1,196 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local remind = {}
local mattata = require('mattata')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function remind:init()
remind.commands = mattata.commands(self.info.username)
:command('remind')
:command('reminders').table
remind.help = '/remind <duration> <message> - Repeats a message after a duration of time, in the format 2d3h. The maximum number of reminders at one time is 4 per chat, and each reminder must be between 1 hour and 182 days in duration. Reminders cannot be any more than 256 characters in length. Use /reminders to view your current reminders. An example use of this command would be: /remind 21d3h test, which would remind you in 21 days and 3 hours.'
end
function remind.get_reminders(message)
local reminders = {}
if redis:get('reminders') then
reminders = json.decode(
redis:get('reminders')
)
end
local this_chat = {}
local count = 0
for k, v in pairs(reminders) do
if v.chat and v.chat.id == message.chat.id then
local real_expiry = tonumber(v.expires) / 3600
table.insert(
this_chat,
string.format(
utf8.char(8226) .. ' %s <code>[Added by %s, expires in approx. %s hour%s]</code>',
mattata.escape_html(v.reminder),
mattata.escape_html(v.name),
mattata.round(
(
tonumber(v.expires) - os.time()
) / 3600,
2
),
mattata.round(
(
tonumber(v.expires) - os.time()
) / 3600,
2
) == 1 and '' or 's'
)
)
count = count + 1
end
end
if count == 0 then
return mattata.send_reply(
message,
'You don\'t have any reminders set up in this chat!'
)
end
return mattata.send_reply(
message,
string.format(
'You currently have %s reminder%s set up for %s:\n%s',
count,
count == 1 and '' or 's',
mattata.escape_html(message.chat.title),
table.concat(
this_chat,
'\n'
)
),
'html'
)
end
function remind:on_message(message)
if message.text:match('^[%/%!%$%^%?%&%%]reminders') then
return remind.get_reminders(message)
end
local input = mattata.input(message.text)
if not input or not input:match('^.- .-$') then
return mattata.send_reply(
message,
remind.help
)
end
local duration, reminder = input:match('^(.-) (.-)$')
-- Convert each unit of time into seconds.
local weeks = 0
if duration:match('%d[Ww]') then
weeks = tonumber(
duration:match('(%d*)[Ww]')
) * 604800
end
local days = 0
if duration:match('%d[Dd]') then
days = tonumber(
duration:match('(%d*)[Dd]')
) * 86400
end
local hours = 0
if duration:match('%d[Hh]') then
hours = tonumber(
duration:match('(%d*)[Hh]')
) * 3600
end
duration = days + hours
if duration <= 0 then
return mattata.send_reply(
message,
'The duration you specified isn\'t in a valid format. The duration of your reminder must be between 1 hour and 6 months, and in the format 5m1w12d3h, which would remind you in 5 months, 1 week, 12 days and 3 hours.'
)
elseif duration > 15724800 or duration < 1 then
return mattata.send_reply(
message,
'The duration of your reminder must be between 1 hour and 182 days.'
)
end
if utf8.len(reminder) > 256 then
return mattata.send_reply(
message,
'Your reminder must not be any longer than 256 characters.'
)
end
local reminders = {}
if redis:get('reminders') then
reminders = json.decode(
redis:get('reminders')
)
end
local count = 0
for k, v in pairs(reminders) do
if v.chat and v.chat.id == message.chat.id then
count = count + 1
end
end
if count >= 4 then
return mattata.send_reply(
message,
'You already have 4 reminders set up in this chat. Please wait for one to expire before you add any more!'
)
end
table.insert(
reminders,
{
['reminder'] = reminder,
['expires'] = os.time() + duration,
['chat'] = {
['id'] = message.chat.id,
['title'] = message.chat.title
},
['name'] = message.from.name or message.chat.title
}
)
redis:set(
'reminders',
json.encode(reminders)
)
duration = duration / 3600 -- Convert back to hours.
return mattata.send_reply(
message,
string.format(
'I will remind you in %s hour%s!',
mattata.round(duration),
tonumber(duration) == 1 and '' or 's'
)
)
end
function remind:cron()
local current_time = os.time()
local reminders = redis:get('reminders')
if not reminders then
return
end
reminders = json.decode(reminders)
for k, v in pairs(reminders) do
if current_time > v.expires then
mattata.send_message(
v.chat.id,
'Reminder: ' .. v.reminder
)
table.remove(
reminders,
k
)
end
end
redis:set(
'reminders',
json.encode(reminders)
)
return
end
return remind
\ No newline at end of file
diff --git a/plugins/responses.mattata b/plugins/responses.mattata
index bb39f44..0d23a3c 100644
--- a/plugins/responses.mattata
+++ b/plugins/responses.mattata
@@ -1,66 +1,66 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local responses = {}
local mattata = require('mattata')
function responses:init()
responses.all = {
['night'] = {
'^go?o?d? ?night$',
'^g?night$',
'^gn$'
},
['morning'] = {
'^go?o?d ?morning?$',
'^morning?$',
'^just woken? up'
},
['yesno'] = {
'^' .. self.info.name .. ',? do .-%??$',
'^' .. self.info.name .. ',? [sc]h?ould .-%??$',
'^' .. self.info.name .. ',? are .-%??$',
'^' .. self.info.name .. ',? is .-%??$',
' y/n$'
},
['iam'] = {
'^[Ii][\'' .. utf8.char(8217) .. '%s]?[AaMm][Mm]?[\n ](%a+)$'
}
}
end
function responses:on_new_message(message)
if not message.text then return false end
for category, response in pairs(responses.all) do
for _, trigger in pairs(response) do
if message.text:lower():match(trigger) then
local yesno = {
'Yes',
'No',
'Maybe',
'Ask again later',
'Definitely',
'Definitely not',
'I don\'t know'
}
local output = yesno[math.random(#yesno)]
if category == 'night' then
output = 'Good night, ' .. message.from.first_name .. '!'
elseif category == 'morning' then
output = 'Good morning, ' .. message.from.first_name .. '!'
elseif category == 'iam' and message.text:len() < 50 then
output = 'Hello ' .. message.text:match(trigger) .. ', I\'m ' .. self.info.first_name
end
return mattata.send_reply(message, output)
end
end
end
if message.text:lower():match('feeling? sexy') then
return mattata.send_voice(message.chat.id, 'AwACAgQAAxkBAAIYwV7ZmESphxCW9E0ZSH4st2WY9ladAAJWOAACuxlkB_VheSVS_OpcGgQ', utf8.char(128521), nil, 9)
end
return false
end
return responses
\ No newline at end of file
diff --git a/plugins/runescape.mattata b/plugins/runescape.mattata
index badfd73..a7a35b4 100644
--- a/plugins/runescape.mattata
+++ b/plugins/runescape.mattata
@@ -1,259 +1,259 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local runescape = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
function runescape:init()
runescape.commands = mattata.commands(self.info.username):command('runescape').table
runescape.help = '/runescape <player name> - Displays skill-related information about the given RuneScape player.'
end
function runescape.errors(error_message, language)
local errors = {
['NO_PROFILE'] = 'This player does not have a RuneMetrics profile!',
['PROFILE_PRIVATE'] = 'This player appears to have privacy mode enabled on their RuneMetrics profile!',
['Unable to fetch profile'] = 'This player appears to have privacy mode enabled on their RuneMetrics profile!'
}
return errors[error_message]
or language['errors']['generic']
end
function runescape.get_skill_info(jdat)
local skills = {
['0'] = 'Attack',
['1'] = 'Defence',
['2'] = 'Strength',
['3'] = 'Constitution',
['4'] = 'Ranged',
['5'] = 'Prayer',
['6'] = 'Magic',
['7'] = 'Cooking',
['8'] = 'Woodcutting',
['9'] = 'Fletching',
['10'] = 'Fishing',
['11'] = 'Firemaking',
['12'] = 'Crafting',
['13'] = 'Smithing',
['14'] = 'Mining',
['15'] = 'Herblore',
['16'] = 'Agility',
['17'] = 'Thieving',
['18'] = 'Slayer',
['19'] = 'Farming',
['20'] = 'Runecrafting',
['21'] = 'Hunter',
['22'] = 'Construction',
['23'] = 'Summoning',
['24'] = 'Dungeoneering',
['25'] = 'Divination',
['26'] = 'Invention'
}
local output = {}
local longest_skill = 0
local longest_rank = 0
local longest_xp = 0
for k, v in pairs(jdat)
do
v.rank = v.rank
or 'N/A'
if v.id
then
local skill = tostring(v.id)
skill = skills[skill]
if skill:len() > longest_skill
then
longest_skill = skill:len()
end
end
if v.rank
then
local rank = v.rank
if rank ~= 'N/A'
then
rank = tonumber(rank)
rank = mattata.comma_value(rank)
end
rank = tostring(rank)
if rank:len() > longest_rank
then
longest_rank = rank:len()
end
end
if v.xp
then
v.xp = tonumber(v.xp) / 10
local xp = mattata.comma_value(v.xp)
xp = tostring(xp)
if xp:len() > longest_xp
then
longest_xp = xp:len()
end
end
end
if longest_skill < 5
then
longest_skill = 5
end
if longest_rank < 4
then
longest_rank = 4
end
if longest_xp < 2
then
longest_xp = 2
end
local separator = '|-'
for i = 1, longest_skill
do
separator = separator .. '-'
end
separator = separator .. '-|-------|-'
for i = 1, longest_rank
do
separator = separator .. '-'
end
separator = separator .. '-|-'
for i = 1, longest_xp
do
separator = separator .. '-'
end
separator = separator .. '-|'
table.insert(
output,
separator
)
local heading = ''
for k, v in pairs(jdat)
do
v.rank = v.rank
or 'N/A'
if v.id
and v.level
and v.rank
and v.xp
then
local id = tostring(v.id)
local skill = skills[id]
if skill:len() < longest_skill
then
repeat
skill = skill .. ' '
until skill:len() == longest_skill
end
local level = tostring(v.level)
repeat
level = level .. ' '
until level:len() == 5
local rank = v.rank
if rank ~= 'N/A'
then
rank = tonumber(rank)
rank = mattata.comma_value(rank)
end
rank = tostring(rank)
if rank:len() < longest_rank
then
repeat
rank = rank .. ' '
until rank:len() == longest_rank
end
local xp = mattata.comma_value(v.xp)
xp = tostring(xp)
if xp:len() < longest_xp
then
repeat
xp = xp .. ' '
until xp:len() == longest_xp
end
local row = '| ' .. skill .. ' | ' .. level .. ' | ' .. rank .. ' | ' .. xp .. ' |'
table.insert(
output,
row
)
if k < #jdat
then
table.insert(
output,
separator
)
else
skill = 'Skill'
if skill:len() < longest_skill
then
repeat
skill = skill .. ' '
until skill:len() == longest_skill
end
level = 'Level'
rank = 'Rank'
if rank:len() < longest_rank
then
repeat
rank = rank .. ' '
until rank:len() == longest_rank
end
xp = 'XP'
if xp:len() < longest_xp
then
repeat
xp = xp .. ' '
until xp:len() == longest_xp
end
heading = '| ' .. skill .. ' | ' .. level .. ' | ' .. rank .. ' | ' .. xp .. ' |'
end
end
end
table.insert(
output,
separator
)
return table.concat(
output,
'\n'
), heading
end
function runescape:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
runescape.help
)
end
local jstr, res = https.request('https://apps.runescape.com/runemetrics/profile/profile?user=' .. url.escape(input))
if res ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local jdat = json.decode(jstr)
if jdat.error
or not jdat.skillvalues
then
return mattata.send_reply(
message,
runescape.errors(
jdat.error,
language
)
)
end
local output, heading = runescape.get_skill_info(jdat.skillvalues)
return mattata.send_message(
message.chat.id,
'```\n' .. heading .. '\n' .. output .. '\n```',
'markdown'
)
end
return runescape
\ No newline at end of file
diff --git a/plugins/sed.mattata b/plugins/sed.mattata
index de681a1..047b11e 100644
--- a/plugins/sed.mattata
+++ b/plugins/sed.mattata
@@ -1,120 +1,120 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local sed = {}
local mattata = require('mattata')
local json = require('dkjson')
function sed:init()
sed.commands = { '^%/?[sS]%/.-%/.-%/?$' }
sed.help = '/s/pattern/substitution - Replaces all occurences, of text matching a given Lua pattern, with the given substitution.'
end
function sed:on_callback_query(callback_query, message, configuration, language)
if not message.reply then
return mattata.delete_message(message.chat.id, message.message_id)
elseif mattata.is_global_admin(callback_query.from.id) then -- we'll pull a sneaky on them
callback_query.from = message.reply.from
elseif message.reply.from.id ~= callback_query.from.id then
return mattata.answer_callback_query(callback_query.id, 'That\'s not your place to say!')
end
local output = string.format(
'<b>%s:</b>\n%s',
message.text:match('^(.-):'),
message.text:match(':\n(.-)$')
)
if callback_query.data:match('^no$') then
output = string.format(
language['sed']['1'],
output,
mattata.escape_html(callback_query.from.first_name)
)
elseif callback_query.data:match('^yes$') then
output = string.format(
language['sed']['2'],
output,
mattata.escape_html(callback_query.from.first_name)
)
elseif callback_query.data:match('^maybe$') then
output = string.format(
language['sed']['3'],
output,
mattata.escape_html(callback_query.from.first_name)
)
end
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
'html'
)
end
function sed:on_message(message, configuration, language)
message.text = message.text:gsub('\\%/', '%%fwd_slash%%')
local matches, substitution = message.text:match('^/?[sS]/(.-)/(.-)/?$')
if not substitution
or not message.reply
then
return
elseif message.reply.from.id == self.info.id
then
return mattata.send_reply(
message,
language['sed']['4'],
'html'
)
end
matches = matches:gsub('%%fwd%_slash%%', '/')
substitution = substitution:gsub('\\n', '\n'):gsub('\\/', '/'):gsub('\\(%d)', '%%%1')
local success, output = pcall(
function()
return message.reply.text:gsub(matches, substitution)
end
)
if not success then
return mattata.send_reply(
message,
string.format(
language['sed']['5'],
mattata.escape_html(matches)
),
'html'
)
end
output = mattata.trim(output)
if not output or output == '' then
return false
end
return mattata.send_message(
message.chat.id,
string.format(
language['sed']['6'],
mattata.escape_html(message.reply.from.first_name),
mattata.escape_html(output)
),
'html',
true,
false,
message.reply.message_id,
mattata.inline_keyboard():row(
mattata.row()
:callback_data_button(
language['sed']['7'],
'sed:yes'
)
:callback_data_button(
language['sed']['8'],
'sed:no'
)
:callback_data_button(
language['sed']['9'],
'sed:maybe'
)
)
)
end
return sed
\ No newline at end of file
diff --git a/plugins/setlang.mattata b/plugins/setlang.mattata
index e805132..8b4c411 100644
--- a/plugins/setlang.mattata
+++ b/plugins/setlang.mattata
@@ -1,157 +1,157 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local setlang = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
local json = require('dkjson')
function setlang:init()
setlang.commands = mattata.commands(self.info.username):command('setlang').table
setlang.help = '/setlang - Allows you to select your language.'
end
setlang.languages = {
['en_gb'] = 'British English 🇬🇧',
['en_us'] = 'American English 🇺🇸',
['de_de'] = 'Deutsch 🇩🇪',
['scottish'] = 'Scottish 🏴',
['pl_pl'] = 'Polski 🇵🇱',
['pt_br'] = 'Português do Brasil 🇧🇷',
['pt_pt'] = 'Português 🇵🇹',
['tr_tr'] = 'Türkçe 🇹🇷'
}
setlang.languages_short = {
['en_gb'] = '🇬🇧',
['en_us'] = '🇺🇸',
['de_de'] = '🇩🇪',
['scottish'] = '🏴',
['pl_pl'] = '🇵🇱',
['pt_br'] = '🇧🇷',
['pt_pt'] = '🇵🇹',
['tr_tr'] = '🇹🇷'
}
function setlang.get_keyboard(user_id)
local keyboard = {
['inline_keyboard'] = {
{}
}
}
local total = 0
for _, v in pairs(setlang.languages_short)
do
total = total + 1
end
local count = 0
local rows = math.floor(total / 2)
if rows ~= total
then
rows = rows + 1
end
local row = 1
for k, v in pairs(setlang.languages_short)
do
count = count + 1
if count == rows * row
then
row = row + 1
table.insert(
keyboard.inline_keyboard,
{}
)
end
table.insert(
keyboard.inline_keyboard[row],
{
['text'] = v,
['callback_data'] = 'setlang:' .. user_id .. ':' .. k
}
)
end
return keyboard
end
function setlang.set_lang(user_id, locale, lang, language)
redis:hset(
'chat:' .. user_id .. ':settings',
'language',
locale
)
return string.format(
language['setlang']['1'],
lang
)
end
function setlang.get_lang(user_id, language)
local lang = redis:hget(
'chat:' .. user_id .. ':settings',
'language'
)
or 'en_gb'
for k, v in pairs(setlang.languages)
do
if k == lang
then
lang = v
break
end
end
return string.format(
language['setlang']['2'],
lang
)
end
function setlang:on_callback_query(callback_query, message, configuration, language)
if not message
or (
message
and message.date <= 1493668000
)
then
return -- We don't want to process requests from messages before the language
-- functionality was re-implemented, it could cause issues!
end
local user_id, new_language = callback_query.data:match('^(.-)%:(.-)$')
if not user_id
or not new_language
or tostring(callback_query.from.id) ~= user_id
then
return
end
return mattata.edit_message_text(
message.chat.id,
message.message_id,
setlang.set_lang(
user_id,
new_language,
setlang.languages[new_language],
language
),
nil,
true,
setlang.get_keyboard(user_id)
)
end
function setlang:on_message(message, configuration, language)
return mattata.send_message(
message.chat.id,
setlang.get_lang(
message.from.id,
language
),
nil,
true,
false,
nil,
setlang.get_keyboard(message.from.id)
)
end
return setlang
\ No newline at end of file
diff --git a/plugins/setlmgtfy.mattata b/plugins/setlmgtfy.mattata
index 4f8eee0..d3ab1c4 100644
--- a/plugins/setlmgtfy.mattata
+++ b/plugins/setlmgtfy.mattata
@@ -1,27 +1,27 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local setlmgtfy = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function setlmgtfy:init()
setlmgtfy.commands = mattata.commands(self.info.username):command('setlmgtfy'):command('sl').table
setlmgtfy.help = '/setlmgtfy <response text> - Sets the response text for the LMGTFY plugin. Alias: /sl.'
end
function setlmgtfy:on_message(message)
if not mattata.is_group_admin(message.chat.id, message.from.id) or message.chat.type == 'private' then
return false
end
local input = mattata.input(message.text)
if not input or input:len() > 128 then
return mattata.send_reply(message, 'Please specify some text to reply to the user with. No longer than 128 characters please!')
end
redis:set('chat:' .. message.chat.id .. ':lmgtfy', input)
return mattata.send_reply(message, 'Successfully set that text as the LMGTFY response!')
end
return setlmgtfy
\ No newline at end of file
diff --git a/plugins/setloc.mattata b/plugins/setloc.mattata
index 91665a5..520f637 100644
--- a/plugins/setloc.mattata
+++ b/plugins/setloc.mattata
@@ -1,68 +1,68 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local setloc = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
local configuration = require('configuration')
function setloc:init(configuration)
assert(configuration.keys.location, 'You must set your configuration key for plugins/setloc.mattata! This can be done in configuration.lua')
setloc.commands = mattata.commands(self.info.username):command('setloc').table
setloc.help = '/setloc <location> - Sets your location to the given value.'
setloc.url = 'https://api.opencagedata.com/geocode/v1/json?key='
setloc.api_key = configuration.keys.location
end
function setloc.check_loc(location, language)
local jstr, res = https.request(setloc.url .. setloc.api_key .. '&pretty=0&q=' .. url.escape(location))
if res ~= 200 then
return false, language.errors.connection
end
local jdat = json.decode(jstr)
if jdat.total_results == 0 then
return false, language.errors.results
end
return true, jdat.results[1].geometry.lat .. ':' .. jdat.results[1].geometry.lng .. ':' .. jdat.results[1].formatted
end
function setloc.set_loc(user_id, location, language)
local val, res = setloc.check_loc(location, language)
if not val then
return res
end
local latitude, longitude, address = res:match('^(.-):(.-):(.-)$')
local user_location = json.encode(
{
['latitude'] = latitude,
['longitude'] = longitude,
['address'] = address
}
)
redis:hset('user:' .. user_id .. ':info', 'location', user_location)
return 'Your location has been updated to: ' .. address .. '\nYou can now use commands such as /weather and /location, without needing to specify a location - your location will be used by default. Giving a different location as the command argument will override this.'
end
function setloc.get_loc(user_id)
return redis:hget('user:' .. user_id .. ':info', 'location')
end
function setloc:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input then
local location = setloc.get_loc(message.from.id)
if not location then
return mattata.send_reply(message, 'You don\'t have a location set. Use /setloc <location> to set one.')
end
return mattata.send_reply(message, 'Your location is currently set to: ' .. json.decode(location).address)
end
local output = setloc.set_loc(message.from.id, input, language)
return mattata.send_message(message.chat.id, output)
end
return setloc
\ No newline at end of file
diff --git a/plugins/share.mattata b/plugins/share.mattata
index 912f86e..18d55f4 100644
--- a/plugins/share.mattata
+++ b/plugins/share.mattata
@@ -1,45 +1,45 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local share = {}
local mattata = require('mattata')
local url = require('socket.url')
function share:init()
share.commands = mattata.commands(self.info.username):command('share').table
share.help = '/share <url> <text> - Share the given URL through an inline button, with the specified text as the caption.'
end
function share:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
or not input:match('^.- .-$')
then
return mattata.send_reply(
message,
share.help
)
end
return mattata.send_message(
message.chat.id,
input:match('^.- (.-)$'),
nil,
true,
false,
nil,
mattata.inline_keyboard():row(
mattata.row():url_button(
language['share']['1'] .. ' ' .. utf8.char(8618),
'https://t.me/share/url?url=' .. url.escape(
input:match('^(.-) .-$')
) .. '&text=' .. url.escape(
input:match('^.- (.-)$')
)
)
)
)
end
return share
\ No newline at end of file
diff --git a/plugins/shorten.mattata b/plugins/shorten.mattata
index 4fdd6ba..a5c6f4c 100644
--- a/plugins/shorten.mattata
+++ b/plugins/shorten.mattata
@@ -1,142 +1,142 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local shorten = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local ltn12 = require('ltn12')
local json = require('dkjson')
local configuration = require('configuration')
function shorten:init()
shorten.commands = mattata.commands(self.info.username):command('shorten').table
shorten.help = '/shorten <url> - Shortens the given URL using one of the given URL shorteners.'
end
function shorten.get_keyboard()
return mattata.inline_keyboard():row(
mattata.row()
:callback_data_button(
'goo.gl',
'shorten:googl'
)
:callback_data_button(
'adf.ly',
'shorten:adfly'
)
)
end
function shorten.googl(input)
local body = json.encode(
{
['longUrl'] = tostring(input)
}
)
local response = {}
local _, res = https.request(
{
['url'] = 'https://www.googleapis.com/urlshortener/v1/url?key=' .. configuration.keys.google.api_key,
['method'] = 'POST',
['headers'] = {
['Content-Type'] = 'application/json',
['Content-Length'] = body:len()
},
['source'] = ltn12.source.string(body),
['sink'] = ltn12.sink.table(response)
}
)
if res ~= 200
then
return false
end
local jdat = json.decode(table.concat(response))
if not jdat.id
then
return false
end
return jdat.id
end
function shorten.adfly(input)
local body = '_api_key=' .. configuration.keys.adfly.api_key .. '&_user_id=' .. configuration.keys.adfly.user_id .. '&domain=adf.ly&url=' .. input .. '&advert_type=1'
local response = {}
local _, res = https.request(
{
['url'] = 'https://api.adf.ly/v1/shorten',
['method'] = 'POST',
['headers'] = {
['Content-Type'] = 'application/x-www-form-urlencoded',
['Content-Length'] = body:len()
},
['source'] = ltn12.source.string(body),
['sink'] = ltn12.sink.table(response)
}
)
if res ~= 200
then
return false
end
local jdat = json.decode(table.concat(response))
if not jdat.data[1]
then
return false
end
return jdat.data[1].short_url
end
function shorten:on_callback_query(callback_query, message, configuration, language)
local input = mattata.input(message.reply.text)
if not input
then
return false
end
local output
if callback_query.data == 'googl'
then
output = shorten.googl(input)
elseif callback_query.data == 'adfly'
then
output = shorten.adfly(input)
end
if not output
then
return mattata.answer_callback_query(
callback_query.id,
language['errors']['generic']
)
end
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
nil,
true,
shorten.get_keyboard()
)
end
function shorten:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
shorten.help
)
end
return mattata.send_message(
message.chat.id,
language['shorten']['1'],
nil,
true,
false,
message.message_id,
shorten.get_keyboard()
)
end
return shorten
\ No newline at end of file
diff --git a/plugins/shsh.mattata b/plugins/shsh.mattata
index d158118..6274ee8 100644
--- a/plugins/shsh.mattata
+++ b/plugins/shsh.mattata
@@ -1,60 +1,60 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local shsh = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
function shsh:init()
shsh.commands = mattata.commands(self.info.username):command('shsh').table
shsh.help = '/shsh <ecid> - Returns a list of all available SHSH blobs for the given device (specified by its ECID).'
end
function shsh:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
shsh.help
)
end
local str, res = https.request('https://tsssaver.1conan.com/shsh/' .. url.escape(input) .. '/')
if res ~= 200
then
return mattata.send_reply(
message,
language['shsh']['1']
)
end
local versions = {}
for n in str:gmatch('%<td%>%<a href=".-" title=".-"%>(.-)/%</a%>%</td%>')
do
table.insert(
versions,
mattata.symbols.bullet .. ' ' .. n
)
end
return mattata.send_message(
message.chat.id,
language['shsh']['2'] .. table.concat(
versions,
'\n'
),
nil,
true,
false,
nil,
mattata.inline_keyboard():row(
mattata.row():url_button(
language['shsh']['3'],
'https://tsssaver.1conan.com/shsh/download.php?ecid=' .. url.escape(input)
)
)
)
end
return shsh
\ No newline at end of file
diff --git a/plugins/slap.mattata b/plugins/slap.mattata
index f1aa731..8aeab37 100644
--- a/plugins/slap.mattata
+++ b/plugins/slap.mattata
@@ -1,51 +1,51 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local slap = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function slap:init()
slap.commands = mattata.commands(self.info.username):command('slap').table
slap.help = '/slap [target] - Slaps someone, or something. Can be used in reply to someone.'
end
function slap:on_message(message, configuration)
local input = mattata.input(message)
local victor = ''
local victim = ''
local slaps = configuration.slaps
if message.chat.type ~= 'private' then
local more = redis:smembers('slaps:' .. message.chat.id)
if #more > 0 then
for _, v in pairs(more) do
table.insert(slaps, v)
end
end
end
if not input then
if message.reply then
victor = message.from.first_name:gsub('%%', '%%%%')
victim = message.reply.from.first_name:gsub('%%', '%%%%')
else
victor = self.info.first_name:gsub('%%', '%%%%')
victim = message.from.first_name:gsub('%%', '%%%%')
end
else
victor = message.from.first_name:gsub('%%', '%%%%')
victim = input:gsub('%%', '%%%%')
local success = mattata.get_user(input)
if success and success.result and success.result.type == 'private' then
victim = success.result.first_name
victim = victim:gsub('%%', '%%%%')
end
end
local output = slaps[math.random(#slaps)]
output = output:gsub('{THEM}', victim):gsub('{ME}', victor)
return mattata.send_message(message.chat.id, output)
end
return slap
\ No newline at end of file
diff --git a/plugins/spamwatch.mattata b/plugins/spamwatch.mattata
index c2f704a..0b23b8d 100644
--- a/plugins/spamwatch.mattata
+++ b/plugins/spamwatch.mattata
@@ -1,51 +1,51 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local spamwatch = {}
local mattata = require('mattata')
function spamwatch:init()
spamwatch.commands = mattata.commands(self.info.username):command('spamwatch'):command('sw').table
spamwatch.help = '/spamwatch [user] - Returns SpamWatch information for the given user, either specified or replied-to. Alias: /sw.'
end
function spamwatch:on_new_message(message, configuration, language)
if message.chat.type == 'private' then
return false
elseif not mattata.get_setting(message.chat.id, 'ban spamwatch users') then
return false
elseif self.is_spamwatch_blacklisted then
mattata.ban_chat_member(message.chat.id, message.from.id)
end
return false
end
function spamwatch:on_message(message, configuration, language)
local input = message.reply and message.reply.from.id or mattata.input(message.text)
if not input then
return mattata.send_reply(message, spamwatch.help)
end
local user = mattata.get_user(input)
if not user then
if not input:match('^%d+$') then
return mattata.send_reply(message, 'I couldn\'t get any information about that user. To teach me who they are, forward a message from them. This will only work if they don\'t have forward privacy enabled!')
end
user = { ['result'] = { ['id'] = input:match('^(%d+)$') } }
end
user = user.result.id
local res, jdat = mattata.is_spamwatch_blacklisted(user)
if not res then
return mattata.send_reply(message, 'That user isn\'t in the SpamWatch database!')
end
local output = {
'<b>ID:</b> ' .. jdat.id,
'<b>Reason:</b> ' .. mattata.escape_html(jdat.reason),
'<b>Date banned:</b> ' .. os.date('%x', jdat.date)
}
output = table.concat(output, '\n')
return mattata.send_reply(message, output, 'html')
end
return spamwatch
\ No newline at end of file
diff --git a/plugins/spotify.mattata b/plugins/spotify.mattata
index 035602c..6c409c3 100644
--- a/plugins/spotify.mattata
+++ b/plugins/spotify.mattata
@@ -1,183 +1,183 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local spotify = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
local ltn12 = require('ltn12')
function spotify:init()
spotify.commands = mattata.commands(self.info.username):command('spotify').table
spotify.help = '/spotify <query> - Searches Spotify for a track matching the given search query and returns the most relevant result.'
end
function spotify.get_track(jdat)
if jdat.tracks.total == 0
then
return false
end
local output = ''
if jdat.tracks.items[1].name
then
if jdat.tracks.items[1].external_urls.spotify
then
output = output .. '<b>Song:</b> <a href="' .. jdat.tracks.items[1].external_urls.spotify .. '">' .. mattata.escape_html(jdat.tracks.items[1].name) .. '</a>\n'
else
output = output .. '<b>Song:</b> ' .. mattata.escape_html(jdat.tracks.items[1].name) .. '\n'
end
end
if jdat.tracks.items[1].album.name
then
if jdat.tracks.items[1].album.external_urls.spotify
then
output = output .. '<b>Album:</b> <a href="' .. jdat.tracks.items[1].album.external_urls.spotify .. '">' .. mattata.escape_html(jdat.tracks.items[1].album.name) .. '</a>\n'
else
output = output .. '<b>Album:</b> ' .. mattata.escape_html(jdat.tracks.items[1].album.name) .. '\n'
end
end
if jdat.tracks.items[1].album.artists[1].name
then
if jdat.tracks.items[1].album.artists[1].external_urls.spotify
then
output = output .. '<b>Artist:</b> <a href="' .. jdat.tracks.items[1].album.artists[1].external_urls.spotify .. '">' .. mattata.escape_html(jdat.tracks.items[1].album.artists[1].name) .. '</a>\n'
else
output = output .. '<b>Artist:</b> ' .. mattata.escape_html(jdat.tracks.items[1].album.artists[1].name) .. '\n'
end
end
if jdat.tracks.items[1].disc_number
then
output = output .. '<b>Disc:</b> ' .. jdat.tracks.items[1].disc_number .. '\n'
end
if jdat.tracks.items[1].track_number
then
output = output .. '<b>Track:</b> ' .. jdat.tracks.items[1].track_number .. '\n'
end
if jdat.tracks.items[1].popularity
then
output = output .. '<b>Popularity:</b> ' .. jdat.tracks.items[1].popularity
end
return output ~= ''
and output
or false
end
function spotify:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
spotify.help
)
elseif not redis:get('spotify:' .. message.from.id .. ':access_token')
then
if redis:get('spotify:' .. message.from.id .. ':refresh_token')
then
local query = 'grant_type=refresh_token&refresh_token=' .. url.escape(
redis:get('spotify:' .. message.from.id .. ':refresh_token')
) .. '&client_id=' .. configuration['keys']['spotify']['client_id'] .. '&client_secret=' .. configuration['keys']['spotify']['client_secret']
local wait_message = mattata.send_message(
message.chat.id,
'Re-authorising your Spotify account, please wait...'
)
local response = {}
local _, res = https.request(
{
['url'] = 'https://accounts.spotify.com/api/token',
['method'] = 'POST',
['headers'] = {
['Content-Type'] = 'application/x-www-form-urlencoded',
['Content-Length'] = query:len()
},
['source'] = ltn12.source.string(query),
['sink'] = ltn12.sink.table(response)
}
)
local jdat = json.decode(
table.concat(response)
)
if res ~= 200
or not jdat
or jdat.error
then
return mattata.edit_message_text(
message.chat.id,
wait_message.result.message_id,
'An error occcured whilst re-authorising your Spotify account. Please try again later.'
)
end
redis:set(
'spotify:' .. message.from.id .. ':access_token',
jdat.access_token
)
redis:expire(
'spotify:' .. message.from.id .. ':access_token',
3600
)
mattata.edit_message_text(
message.chat.id,
wait_message.result.message_id,
'Successfully re-authorised your Spotify account! Processing your original request...'
)
else
local success = mattata.send_force_reply(
message,
'You need to authorise mattata in order to connect your Spotify account. Click [here](https://accounts.spotify.com/en/authorize?client_id=' .. url.escape(configuration['keys']['spotify']['client_id']) .. '&response_type=code&redirect_uri=' .. configuration['keys']['spotify']['redirect_uri'] .. '&scope=user-library-read,playlist-read-private,playlist-read-collaborative,user-read-private,user-read-birthdate,user-read-email,user-follow-read,user-top-read,user-read-playback-state,user-read-recently-played,user-read-currently-playing,user-modify-playback-state) and press the green "OKAY" button to link mattata to your Spotify account. After you\'ve done that, send the link you were redirected to (it should begin with "' .. configuration['keys']['spotify']['redirect_uri'] .. '", followed by a unique code) in reply to this message.',
'markdown'
)
if success
then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/authspotify'
)
end
return
end
end
local response = {}
local _, res = https.request(
{
['url'] = 'https://api.spotify.com/v1/search?q=' .. url.escape(input) .. '&type=track&limit=1',
['method'] = 'GET',
['headers'] = {
['Authorization'] = 'Bearer ' .. redis:get('spotify:' .. message.from.id .. ':access_token')
},
['sink'] = ltn12.sink.table(response)
}
)
if res ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local jdat = json.decode(
table.concat(response)
)
local output = spotify.get_track(jdat)
if not output
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
return mattata.send_message(
message.chat.id,
output,
'html'
)
end
return spotify
\ No newline at end of file
diff --git a/plugins/statistics.mattata b/plugins/statistics.mattata
index cf6f17b..c4020ab 100644
--- a/plugins/statistics.mattata
+++ b/plugins/statistics.mattata
@@ -1,45 +1,45 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local statistics = {}
local mattata = require('mattata')
local redis = dofile('libs/redis.lua')
function statistics:init()
statistics.commands = mattata.commands(self.info.username)
:command('statistics')
:command('stats').table
statistics.help = '/statistics - Shows statistical information about the current chat\'s top ten users (ordered by message count). Alias: /stats.'
end
function statistics:on_message(message, configuration, language)
if message.chat.type == 'private'
then
return false
end
local input = mattata.input(message.text)
if input
and input:lower() == 'reset'
and mattata.is_group_admin(
message.chat.id,
message.from.id,
true
)
then
return mattata.send_message(
message.chat.id,
mattata.reset_message_statistics(message.chat.id)
and language['statistics']['3']
or language['statistics']['4']
)
end
return mattata.send_message(
message.chat.id,
mattata.get_message_statistics(self),
'html'
)
end
return statistics
\ No newline at end of file
diff --git a/plugins/steam.mattata b/plugins/steam.mattata
index f8b4718..341cc3c 100644
--- a/plugins/steam.mattata
+++ b/plugins/steam.mattata
@@ -1,191 +1,191 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local steam = {}
local mattata = require('mattata')
local https = require('ssl.https')
local http = require('socket.http')
local url = require('socket.url')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function steam:init()
steam.commands = mattata.commands(self.info.username)
:command('steam')
:command('setsteam').table
steam.help = '/steam [username] - Displays information about the given Steam user. If no username is specified then information about your Steam account (if applicable) is sent.'
end
function steam.search(input, key)
local jstr, res = https.request('https://steamcommunity.com/id/' .. url.escape(input))
if res ~= 200
then
return false, true
end
jstr = jstr:match('g%_rgProfileData %= (.-)%;')
if not jstr or not jstr:match('^%{.-%}$')
then
return true, false
end
local jdat = json.decode(jstr)
if not jdat
or not jdat.steamid
then
return true, false
end
return steam.get_info(
jdat.steamid,
key
), true
end
function steam.get_info(id, key)
local jstr, res = http.request('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=' .. key .. '&steamids=' .. id)
if res ~= 200
then
return false
end
return jstr
end
function steam.get_username(id)
return redis:hget(
'steam:' .. id,
'username'
)
end
function steam.set_username(message, language)
local input = mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
steam.help
)
end
redis:hset(
'steam:' .. message.from.id,
'username',
input
)
return mattata.send_reply(
message,
string.format(
language['steam']['1'],
input
)
)
end
function steam.format_output(jdat, language)
if not jdat.response
or not jdat.response.players
or not jdat.response.players[1]
then
return false
end
local name = mattata.escape_html(jdat.response.players[1].personaname)
if jdat.response.players[1].realname
then
name = mattata.escape_html(jdat.response.players[1].realname)
end
name = string.format(
'<a href="%s">%s</a>',
jdat.response.players[1].avatarfull,
name
)
if jdat.response.players[1].realname
and jdat.response.players[1].realname ~= jdat.response.players[1].personaname
then
name = string.format(
language['steam']['4'],
name,
jdat.response.players[1].personaname
)
end
local output = string.format(
language['steam']['3'],
name,
os.date('%X', jdat.response.players[1].timecreated),
os.date('%x', jdat.response.players[1].timecreated),
os.date('%X', jdat.response.players[1].lastlogoff),
os.date('%x', jdat.response.players[1].lastlogoff),
jdat.response.players[1].profileurl
)
if not output
then
return false
end
return output
end
function steam:on_message(message, configuration, language)
if message.text:match('^%/se')
then
return steam.set_username(
message,
language
)
end
local input = mattata.input(message.text)
if not input
and not steam.get_username(message.from.id)
then
return mattata.send_reply(
message,
steam.help
)
elseif not input
then
input = steam.get_username(message.from.id)
end
if input:match('^%@.-$')
then
input = input:match('^%@(.-)$')
end
local output, res = steam.search(
input,
configuration.keys.steam
)
if not output
then
return mattata.send_reply(
message,
language['errors']['connection']
)
elseif not res
then
return mattata.send_reply(
message,
string.format(
language['steam']['2'],
input
)
)
end
output = steam.format_output(
json.decode(output),
language
)
if not output
then
return mattata.send_reply(
message,
string.format(
language['steam']['2'],
input
)
)
end
return mattata.send_message(
message.chat.id,
output,
'html',
false
)
end
return steam
\ No newline at end of file
diff --git a/plugins/translate.mattata b/plugins/translate.mattata
index 42b5493..4675d41 100644
--- a/plugins/translate.mattata
+++ b/plugins/translate.mattata
@@ -1,89 +1,89 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local translate = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
function translate:init()
translate.commands = mattata.commands(
self.info.username
):command('translate')
:command('tl').table
translate.help = [[/translate [locale] <text> - If a locale is given, the given text is translated into the said locale's language. If no locale is given then the given text is translated into the bot's configured language. If the command is used in reply to a message containing text, then the replied-to text is translated and the translation is returned. Alias: /tl.]]
end
function translate:on_inline_query(inline_query, configuration)
local input = mattata.input(inline_query.query)
if not input then
return
end
local lang
if not mattata.get_word(input) or mattata.get_word(input):len() > 2 then
lang = configuration.language
else
lang = mattata.get_word(input)
end
local jstr, res = https.request('https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. configuration.keys.translate .. '&lang=' .. lang .. '&text=' .. url.escape(input:gsub(lang .. ' ', '')))
if res ~= 200 then
return
end
local jdat = json.decode(jstr)
return mattata.answer_inline_query(
inline_query.id,
json.encode(
{
{
['type'] = 'article',
['id'] = '1',
['title'] = jdat.text[1],
['description'] = 'Click to send your translation.',
['input_message_content'] = {
['message_text'] = jdat.text[1]
}
}
}
)
)
end
function translate:on_message(message, configuration, language)
local input = mattata.input(message.text)
local lang = configuration['language']
if message.reply
then
lang = input
or lang
input = message.reply.text
elseif not input
then
return mattata.send_reply(
message,
translate.help
)
elseif input:match('^%a%a .-$')
then
lang, input = input:match('^(%a%a) (.-)$')
end
local jstr, res = https.request('https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. configuration['keys']['translate'] .. '&lang=' .. lang .. '&text=' .. url.escape(input))
if res ~= 200
then
return mattata.send_reply(
message,
'An error occured. Are you sure you specified a valid locale?'
)
end
local jdat = json.decode(jstr)
return mattata.send_message(
message.chat.id,
'<b>Translation (from ' .. jdat.lang:gsub('%-', ' to ') .. '):</b>\n' .. mattata.escape_html(jdat.text[1]),
'html'
)
end
return translate
\ No newline at end of file
diff --git a/plugins/twitch.mattata b/plugins/twitch.mattata
index 63fc7c1..37f6e6a 100644
--- a/plugins/twitch.mattata
+++ b/plugins/twitch.mattata
@@ -1,165 +1,165 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local twitch = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local configuration = require('configuration')
function twitch:init()
twitch.commands = mattata.commands(
self.info.username
):command('twitch').table
twitch.help = [[/twitch <query> - Searches Twitch for the given search query and returns the most relevant result(s).]]
end
function twitch.get_result_count(input)
local jstr, res = https.request('https://api.twitch.tv/kraken/search/streams?q=' .. url.escape(input) .. '&client_id=' .. configuration.keys.twitch)
if res ~= 200 then
return 0
end
local jdat = json.decode(jstr)
if jdat._total == 0 then
return 0
end
return #jdat.streams
end
function twitch.get_result(input, n)
n = n or 1
local jstr, res = https.request('https://api.twitch.tv/kraken/search/streams?q=' .. url.escape(input) .. '&client_id=' .. configuration.keys.twitch)
if res ~= 200 then
return false
end
local jdat = json.decode(jstr)
if jdat._total == 0 then
return false
end
local output = ''
if jdat.streams[n].channel.url and jdat.streams[n].channel.display_name then
output = output .. '<a href="' .. jdat.streams[n].channel.url .. '">' .. mattata.escape_html(jdat.streams[n].channel.display_name) .. '</a>\n'
end
if jdat.streams[n].channel.game then
output = output .. '🎮 ' .. mattata.escape_html(jdat.streams[n].channel.game) .. '\n'
end
if jdat.streams[n].viewers then
output = output .. '👁 ' .. mattata.comma_value(tostring(jdat.streams[n].viewers)) .. '\n'
end
if jdat.streams[n].video_height then
output = output .. '🖥 ' .. jdat.streams[n].video_height .. 'p'
if jdat.streams[n].average_fps then
output = output .. ', ' .. mattata.round(jdat.streams[n].average_fps) .. ' FPS'
end
end
return output
end
function twitch:on_callback_query(callback_query, message, configuration)
if callback_query.data:match('^results:(.-)$') then
local result = callback_query.data:match('^results:(.-)$')
local input = mattata.input(message.reply.text)
local total_results = twitch.get_result_count(input)
if tonumber(result) > tonumber(total_results) then
result = 1
elseif tonumber(result) < 1 then
result = tonumber(total_results)
end
local output = twitch.get_result(
input,
tonumber(result)
)
if not output then
return mattata.answer_callback_query(
callback_query.id,
'An error occured!'
)
end
local previous_result = 'twitch:results:' .. math.floor(tonumber(result) - 1)
local next_result = 'twitch:results:' .. math.floor(tonumber(result) + 1)
local keyboard = {}
keyboard.inline_keyboard = {
{
{
['text'] = '← Previous',
['callback_data'] = previous_result
},
{
['text'] = result .. '/' .. total_results,
['callback_data'] = 'twitch:pages:' .. result
},
{
['text'] = 'Next →️',
['callback_data'] = next_result
}
}
}
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
'html',
true,
json.encode(keyboard)
)
elseif callback_query.data:match('^pages:(.-):(.-)$') then
local current, total = callback_query.data:match('^pages:(.-):(.-)$')
return mattata.answer_callback_query(
callback_query.id,
string.format(
'You are on page %s of %s!',
tostring(current),
tostring(total)
)
)
end
end
function twitch:on_message(message, configuration)
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(
message,
twitch.help
)
end
local output = twitch.get_result(input)
if not output then
return mattata.send_reply(
message,
configuration.errors.results
)
end
local keyboard = {}
keyboard.inline_keyboard = {
{
{
['text'] = '← Previous',
['callback_data'] = 'twitch:results:0'
},
{
['text'] = '1/' .. twitch.get_result_count(input),
['callback_data'] = 'twitch:pages:1:' .. twitch.get_result_count(input)
},
{
['text'] = 'Next →️',
['callback_data'] = 'twitch:results:2'
}
}
}
return mattata.send_message(
message.chat.id,
output,
'html',
true,
false,
message.message_id,
json.encode(keyboard)
)
end
return twitch
\ No newline at end of file
diff --git a/plugins/upload.mattata b/plugins/upload.mattata
index 74a543b..f13e3c4 100644
--- a/plugins/upload.mattata
+++ b/plugins/upload.mattata
@@ -1,63 +1,63 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local upload = {}
local mattata = require('mattata')
function upload:init()
upload.commands = mattata.commands(self.info.username):command('upload').table
end
function upload:on_message(message, configuration, language)
if not mattata.is_global_admin(message.from.id)
then
return
elseif not message.reply
or not message.reply.document
then
return mattata.send_reply(
message,
language['upload']['1']
)
elseif tonumber(message.reply.document.file_size) > 20971520
then
return mattata.send_reply(
message,
language['upload']['2']
)
end
local file = mattata.get_file(message.reply.document.file_id)
if not file
or not file.result
or not file.result.file_path
then
return mattata.send_reply(
message,
language['upload']['3']
)
end
local success = mattata.download_file(
'https://api.telegram.org/file/bot' .. configuration.bot_token .. '/' .. file.result.file_path,
message.reply.document.file_name,
configuration['download_location']
)
if not success
then
return mattata.send_reply(
message,
language['upload']['4']
)
end
return mattata.send_reply(
message,
string.format(
language['upload']['5'],
mattata.escape_html(configuration['download_location'] .. message.reply.document.file_name)
),
'html'
)
end
return upload
\ No newline at end of file
diff --git a/plugins/urbandictionary.mattata b/plugins/urbandictionary.mattata
index 2df1dc6..6d529ec 100644
--- a/plugins/urbandictionary.mattata
+++ b/plugins/urbandictionary.mattata
@@ -1,221 +1,221 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local urbandictionary = {}
local mattata = require('mattata')
local http = require('socket.http')
local url = require('socket.url')
local json = require('dkjson')
local redis = dofile('libs/redis.lua')
function urbandictionary:init()
urbandictionary.commands = mattata.commands(
self.info.username
):command('urbandictionary')
:command('urban')
:command('ud').table
urbandictionary.help = [[/urbandictionary <query> - Searches the Urban Dictionary for the given search query and returns the most relevant result(s). Aliases: /urban, /ud.]]
end
function urbandictionary:on_inline_query(inline_query, configuration)
local input = mattata.input(inline_query.query)
if not input then
return
end
local jstr, res = http.request('http://api.urbandictionary.com/v0/define?term=' .. url.escape(input))
if res ~= 200 then
return
end
local jdat = json.decode(jstr)
local results = {}
local id = 1
for n in pairs(jdat.list) do
table.insert(
results,
{
['type'] = 'article',
['id'] = tostring(id),
['title'] = jdat.list[n].word,
['description'] = jdat.list[n].definition,
['input_message_content'] = {
['message_text'] = '<b>' .. mattata.escape_html(jdat.list[n].word) .. '</b>\n\n' .. mattata.escape_html(jdat.list[n].definition),
['parse_mode'] = 'html'
}
}
)
id = id + 1
end
return mattata.answer_inline_query(
inline_query.id,
json.encode(results)
)
end
function urbandictionary.get_result_count(input)
local jstr, res = http.request('http://api.urbandictionary.com/v0/define?term=' .. url.escape(input))
if res ~= 200 then
return 0
end
local jdat = json.decode(jstr)
if jdat.result_type == 'no_results' then
return 0
end
return #jdat.list
end
function urbandictionary.get_result(input, n)
n = n or 1
local jstr, res = http.request('http://api.urbandictionary.com/v0/define?term=' .. url.escape(input))
if res ~= 200 then
return false, false
end
local jdat = json.decode(jstr)
if jdat.result_type == 'no_results' then
return false, false
end
if not jdat.list[n].example then
return false, false
end
local definition = mattata.escape_html(jdat.list[n].definition)
definition = definition:gsub('%[word%](.-)%[%/word%]', '<a href="https://www.urbandictionary.com/define.php?term=%1">%1</a>'):gsub('%[(.-)%]', '<a href="https://www.urbandictionary.com/define.php?term=%1">%1</a>')
local output = '<b>' .. jdat.list[n].word .. '</b>\n\n' .. mattata.trim(definition)
local example = mattata.escape_html(jdat.list[n].example):gsub('%[word%]', ''):gsub('%[%/word%]', '')
local thumbs_up = '👍 ' .. jdat.list[n].thumbs_up
local thumbs_down = '👎 ' .. jdat.list[n].thumbs_down
local author = '💁 ' .. '<a href="https://www.urbandictionary.com/author.php?author=' .. url.escape(jdat.list[n].author) .. '">' .. mattata.escape_html(jdat.list[n].author) .. '</a>'
return output .. '\n\n<i>' .. mattata.trim(example) .. '</i>\n\n' .. thumbs_up .. ' | ' .. thumbs_down .. ' | ' .. author, jdat.list[n].defid
end
function urbandictionary:on_callback_query(callback_query, message, configuration)
if not message.reply then
return
end
if callback_query.data:match('^results:(%d*)$') then
local result = callback_query.data:match('^results:(%d*)$')
local input = mattata.input(message.reply.text)
local total_results = urbandictionary.get_result_count(input)
if tonumber(result) > tonumber(total_results) then
result = 1
elseif tonumber(result) < 1 then
result = tonumber(total_results)
end
local output, def_id = urbandictionary.get_result(
input,
tonumber(result)
)
if not output then
return mattata.answer_callback_query(
callback_query.id,
'An error occured!'
)
end
local previous_result = 'urbandictionary:results:' .. math.floor(tonumber(result) - 1)
local next_result = 'urbandictionary:results:' .. math.floor(tonumber(result) + 1)
local keyboard = {}
keyboard.inline_keyboard = {
{
{
['text'] = '← Previous',
['callback_data'] = previous_result
},
{
['text'] = result .. '/' .. total_results,
['callback_data'] = 'urbandictionary:pages:' .. result .. ':' .. total_results
},
{
['text'] = 'Next →',
['callback_data'] = next_result
}
},
{
{
['text'] = 'Get this definition on a mug!',
['url'] = 'https://urbandictionary.store/products/mug?defid=' .. def_id
}
}
}
return mattata.edit_message_text(
message.chat.id,
message.message_id,
output,
'html',
true,
json.encode(keyboard)
)
elseif callback_query.data:match('^pages:(.-):(.-)$') then
local current, total = callback_query.data:match('^pages:(.-):(.-)$')
return mattata.answer_callback_query(
callback_query.id,
string.format(
'You are on page %s of %s!',
tostring(current),
tostring(total)
)
)
end
end
function urbandictionary:on_message(message, configuration)
local input = mattata.input(message.text)
if not input then
local success = mattata.send_force_reply(
message,
'Please enter a search query (that is, what you want me to search the Urban Dictionary for, i.e. "1337" will return Urban Dictionary\'s definition(s) of 1337).'
)
if success then
redis:set(
string.format(
'action:%s:%s',
message.chat.id,
success.result.message_id
),
'/urbandictionary'
)
end
return
end
local output, def_id = urbandictionary.get_result(input)
if not output then
return mattata.send_reply(
message,
configuration.errors.results
)
end
local keyboard = {}
keyboard.inline_keyboard = {
{
{
['text'] = '← Previous',
['callback_data'] = 'urbandictionary:results:0'
},
{
['text'] = '1/' .. urbandictionary.get_result_count(input),
['callback_data'] = 'urbandictionary:pages:1:' .. urbandictionary.get_result_count(input)
},
{
['text'] = 'Next →',
['callback_data'] = 'urbandictionary:results:2'
},
},
{
{
['text'] = 'Get this definition on a mug!',
['url'] = 'https://urbandictionary.store/products/mug?defid=' .. def_id
}
}
}
return mattata.send_message(
message.chat.id,
output,
'html',
true,
false,
message.message_id,
json.encode(keyboard)
)
end
return urbandictionary
\ No newline at end of file
diff --git a/plugins/weather.mattata b/plugins/weather.mattata
index 1c2fe88..7066f5b 100644
--- a/plugins/weather.mattata
+++ b/plugins/weather.mattata
@@ -1,100 +1,100 @@
--[[
- Copyright 2020 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local weather = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local setloc = dofile('plugins/setloc.mattata')
function weather:init()
weather.commands = mattata.commands(self.info.username):command('weather').table
weather.help = '/weather [location] - If no arguments are given, the weather forecast for your known location is given. If a location is given, then the weather forecast for that location is given instead.'
end
function weather.format_temperature(temperature, units)
temperature = tonumber(temperature)
if units ~= 'us'
then
return temperature .. '°C/' .. string.format(
'%.2f',
temperature * 9 / 5 + 32
) .. '°F'
else
return temperature .. '°F/' .. string.format(
'%.2f',
(temperature - 32) * 5 / 9
) .. '°C'
end
end
function weather.get_weather(input, configuration)
local url = 'https://api.opencagedata.com/geocode/v1/json?key=' .. configuration['keys']['location'] .. '&pretty=0&q=' .. url.escape(input)
local jstr, res = https.request(url)
if res ~= 200
then
return false, false, false
end
local jdat = json.decode(jstr)
if jdat.total_results == 0 then
return true, false, false
end
return jdat.results[1].geometry.lat, jdat.results[1].geometry.lng, jdat.results[1].formatted
end
function weather:on_message(message, configuration, language)
local input = mattata.input(message.text)
local latitude, longitude, address
if not input
then
local location = setloc.get_loc(message.from.id)
if not location
then
return mattata.send_reply(
message,
language['weather']['1']
)
end
latitude, longitude, address = json.decode(location).latitude, json.decode(location).longitude, json.decode(location).address
else
latitude, longitude, address = weather.get_weather(input, configuration)
if not latitude
or not longitude
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
end
local jstr, res = https.request('https://api.darksky.net/forecast/' .. configuration.keys.weather .. '/' .. latitude .. ',' .. longitude .. '?units=auto')
if res ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local jdat = json.decode(jstr)
return mattata.send_message(
message.chat.id,
string.format(
language['weather']['2'],
weather.format_temperature(
jdat.currently.temperature,
jdat.flags.units
),
weather.format_temperature(
jdat.currently.apparentTemperature,
jdat.flags.units
),
address,
jdat.daily.summary
)
)
end
return weather
\ No newline at end of file
diff --git a/plugins/wikipedia.mattata b/plugins/wikipedia.mattata
index e846d17..a6739fe 100644
--- a/plugins/wikipedia.mattata
+++ b/plugins/wikipedia.mattata
@@ -1,107 +1,107 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See ./LICENSE for details.
]]
local wikipedia = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
function wikipedia:init()
wikipedia.commands = mattata.commands(self.info.username)
:command('wikipedia')
:command('wiki')
:command('w').table
wikipedia.help = '/wikipedia <query> - Searches Wikipedia for the given search query and returns the most relevant article. Aliases: /wiki, /w.'
end
function wikipedia:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
return mattata.send_reply(
message,
wikipedia.help
)
end
local jstr, res = https.request('https://en.wikipedia.org/w/api.php?action=query&list=search&format=json&srsearch=' .. url.escape(input))
if res ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local jdat = json.decode(jstr)
if jdat.query.searchinfo.totalhits == 0
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
local title
for _, v in ipairs(jdat.query.search)
do
if not v.snippet:match('may refer to:')
then
title = v.title
break
end
end
if not title
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
local res_jstr, res_code = https.request('https://en.wikipedia.org/w/api.php?action=query&format=json&prop=extracts&exchars=4000&explaintext=&titles=' .. url.escape(title))
if res_code ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local _, text = next(json.decode(res_jstr).query.pages)
if not text
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
text = text.extract
local l = text:find('\n')
if l
then
text = text:sub(1, l - 1)
end
local final_url = 'https://en.wikipedia.org/wiki/' .. url.escape(title)
title = mattata.escape_html(title)
local short_title = title:gsub('%(.+%)', '')
local combined_text, count = text:gsub('^' .. short_title, '<b>' .. short_title .. '</b>')
local output
if count == 1
then
output = combined_text
else
output = '<b>' .. title .. '</b>\n' .. text
end
return mattata.send_message(
message.chat.id,
string.format(
'%s\n<a href="%s">%s</a>',
output,
mattata.escape_html(final_url),
language['wikipedia']['1']
),
'html'
)
end
return wikipedia
\ No newline at end of file
diff --git a/plugins/xkcd.mattata b/plugins/xkcd.mattata
index c41fe86..6a69f05 100644
--- a/plugins/xkcd.mattata
+++ b/plugins/xkcd.mattata
@@ -1,94 +1,94 @@
--[[
Based on a plugin by topkecleon.
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local xkcd = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
function xkcd:init()
xkcd.commands = mattata.commands(
self.info.username
):command('xkcd').table
xkcd.help = [[/xkcd [query] - 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. Any other text passed as the command argument will search Google for a relevant strip and, if applicable, return it.]]
local jstr = https.request('https://xkcd.com/info.0.json')
if jstr
then
local jdat = json.decode(jstr)
if jdat
then
xkcd.latest = jdat.num
end
end
xkcd.latest = xkcd.latest
end
function xkcd:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input
then
input = xkcd.latest
end
if input == 'r'
then
input = math.random(xkcd.latest)
elseif tonumber(input) ~= nil
then
input = tonumber(input)
else
input = 'inurl:xkcd.com ' .. input
local search, res = https.request('https://relevantxkcd.appspot.com/process?action=xkcd&query=' .. url.escape(input))
if res ~= 200
then
return mattata.send_reply(
message,
language['errors']['results']
)
end
input = tonumber(
search:match('^.-\n.-\n(%d*) %/')
)
end
local url = string.format(
'https://xkcd.com/%s/info.0.json',
tostring(input)
)
local jstr, res = https.request(url)
if res == 404
then
return mattata.send_message(
message.chat.id,
'[<a href="https://xkcd.com/404">404</a>] <b>404 Not Found</b>, 1/4/2008',
'html'
)
elseif res ~= 200
then
return mattata.send_reply(
message,
language['errors']['connection']
)
end
local jdat = json.decode(jstr)
return mattata.send_message(
message.chat.id,
string.format(
'[<a href="%s">%s</a>] <b>%s</b>, %s/%s/%s\n<i>%s</i>',
jdat.img,
jdat.num,
mattata.escape_html(jdat.safe_title),
jdat.day,
jdat.month,
jdat.year,
mattata.escape_html(jdat.alt)
),
'html',
false
)
end
return xkcd
\ No newline at end of file
diff --git a/plugins/youtube.mattata b/plugins/youtube.mattata
index 261303f..4f55ea5 100644
--- a/plugins/youtube.mattata
+++ b/plugins/youtube.mattata
@@ -1,157 +1,157 @@
--[[
- Copyright 2017 Matthew Hesketh <wrxck0@gmail.com>
+ Copyright 2020 Matthew Hesketh <matthew@matthewhesketh.com>
This code is licensed under the MIT. See LICENSE for details.
]]
local youtube = {}
local mattata = require('mattata')
local https = require('ssl.https')
local url = require('socket.url')
local json = require('dkjson')
local configuration = require('configuration')
function youtube:init(configuration)
assert(configuration.keys.youtube, 'youtube.lua requires an API key, and you haven\'t got one configured!')
youtube.commands = mattata.commands(self.info.username):command('youtube'):command('yt').table
youtube.help = '/youtube <query> - Searches YouTube for the given search query and returns the most relevant result(s). Alias: /yt.'
end
function youtube.get_result_count(input)
local jstr, res = https.request('https://www.googleapis.com/youtube/v3/search?key=' .. configuration.keys.youtube .. '&type=video&part=snippet&q=' .. url.escape(input))
if res ~= 200 then
return 0
end
local jdat = json.decode(jstr)
if jdat.pageInfo.total_results == 0 then
return 0
end
return #jdat.items
end
function youtube.get_result(input, n)
n = n or 1
local jstr, res = https.request('https://www.googleapis.com/youtube/v3/search?key=' .. configuration.keys.youtube .. '&part=snippet&type=video&safesearch=none&q=' .. url.escape(input))
if res ~= 200 then
return false
end
local jdat = json.decode(jstr)
if jdat.pageInfo.total_results == 0 then
return false
end
local jstr_info, res_info = https.request('https://www.googleapis.com/youtube/v3/videos?part=snippet,statistics,contentDetails&key=' .. configuration.keys.youtube .. '&id=' .. jdat.items[n].id.videoId .. '&fields=items(id,snippet(publishedAt,channelTitle,localized(title,description)),statistics(viewCount,likeCount,dislikeCount,commentCount),contentDetails(duration,regionRestriction(blocked)))')
if res_info ~= 200 then
return false
end
local jdat_info = json.decode(jstr_info)
local output = '<a href="https://www.youtube.com/watch?v=' .. jdat.items[n].id.videoId .. '">' .. mattata.escape_html(jdat.items[n].snippet.title) .. '</a>\n'
if jdat_info.items[1].snippet.channelTitle then
output = output .. '👤 ' .. mattata.escape_html(jdat_info.items[1].snippet.channelTitle) .. '\n'
end
if jdat_info.items[1].statistics.viewCount then
output = output .. '👁 ' .. mattata.comma_value(jdat_info.items[1].statistics.viewCount) .. '\n'
end
if jdat_info.items[1].statistics.commentCount then
output = output .. '💬 ' .. mattata.comma_value(jdat_info.items[1].statistics.commentCount) .. '\n'
end
if jdat_info.items[1].statistics.likeCount then
output = output .. '👍 ' .. mattata.comma_value(jdat_info.items[1].statistics.likeCount) .. '\n'
end
if jdat_info.items[1].statistics.dislikeCount then
output = output .. '👎 ' .. mattata.comma_value(jdat_info.items[1].statistics.dislikeCount) .. '\n'
end
return output
end
function youtube:on_callback_query(callback_query, message, configuration, language)
if not message.reply then
return mattata.answer_callback_query(callback_query.id, language['errors']['generic'])
elseif callback_query.data:match('^results:%d*$') then
local result = callback_query.data:match('^results:(%d*)$')
local input = mattata.input(message.reply.text)
local total_results = youtube.get_result_count(input)
if tonumber(result) > tonumber(total_results) then
result = 1
elseif tonumber(result) < 1 then
result = tonumber(total_results)
end
local output = youtube.get_result(input, tonumber(result))
if not output then
return mattata.answer_callback_query(callback_query.id, language['errors']['generic'])
end
local previous_result = 'youtube:results:' .. tonumber(result) - 1
local next_result = 'youtube:results:' .. tonumber(result) + 1
local keyboard = json.encode(
{
inline_keyboard = {
{
{
['text'] = mattata.symbols.back .. ' ' .. language['youtube']['1'],
['callback_data'] = previous_result
},
{
['text'] = result .. '/' .. total_results,
['callback_data'] = 'youtube:pages:' .. result .. ':' .. total_results
},
{
['text'] = language['youtube']['2'] .. ' ' .. mattata.symbols.next,
['callback_data'] = next_result
}
}
}
}
)
return mattata.edit_message_text(message.chat.id, message.message_id, output, 'html', true, keyboard)
elseif callback_query.data:match('^pages:.-:.-$') then
local current_page, total_pages = callback_query.data:match('^pages:(.-):(.-)$')
return mattata.answer_callback_query(
callback_query.id,
string.format(
language['youtube']['3'],
current_page,
total_pages
)
)
end
end
function youtube:on_message(message, configuration, language)
local input = mattata.input(message.text)
if not input then
return mattata.send_reply(message, youtube.help)
end
local output = youtube.get_result(input)
if not output then
return mattata.send_reply(message, language['errors']['results'])
end
local keyboard = json.encode(
{
['inline_keyboard'] = {
{
{
['text'] = mattata.symbols.back .. ' ' .. language['youtube']['1'],
['callback_data'] = 'youtube:results:0'
},
{
['text'] = '1/' .. youtube.get_result_count(input),
['callback_data'] = 'youtube:pages:1:' .. youtube.get_result_count(input)
},
{
['text'] = language['youtube']['2'] .. ' ' .. mattata.symbols.next,
['callback_data'] = 'youtube:results:2'
}
}
}
}
)
return mattata.send_message(
message.chat.id,
output,
'html',
true,
false,
message.message_id,
keyboard
)
end
return youtube
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 16, 7:08 AM (16 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
64050
Default Alt Text
(638 KB)

Event Timeline