diff --git a/bot.lua b/bot.lua index 341b0a8..293ba44 100644 --- a/bot.lua +++ b/bot.lua @@ -15,7 +15,11 @@ function on_msg_receive(msg) if msg.date < os.time() - 5 then return end -- don't react to old messages if not msg.text then return end -- don't react to media messages if msg.forward_from then return end -- don't react to forwarded messages - +--[[ + if msg.from.id == 77029297 then + send_message(msg.chat.id, '/END@MINDSTORMER619') + end +]]-- local lower = string.lower(msg.text) for i,v in pairs(plugins) do for j,w in pairs(v.triggers) do diff --git a/config.lua.default b/config.lua.default index 5b25508..500d4e0 100644 --- a/config.lua.default +++ b/config.lua.default @@ -1,5 +1,6 @@ return { bot_api_key = '', + lastfm_api_key = '' biblia_api_key = '', giphy_api_key = 'dc6zaTOxFJmzC', time_offset = 0, @@ -43,5 +44,12 @@ return { }, people = { ['55994550'] = 'topkecleon' + }, + moderation = { + realm = -0, + data = 'moderation.json', + admins = { + [0] = 'nickname', + } } } diff --git a/plugins/interactions.lua b/plugins/interactions.lua index f7a0b64..ef1a2e2 100644 --- a/plugins/interactions.lua +++ b/plugins/interactions.lua @@ -9,7 +9,6 @@ PLUGIN.no_typing = true PLUGIN.triggers = { bot.first_name .. '%p?$', - '@' .. bot.username .. '%p?$', '^tadaima%p?$', '^i\'m home%p?$', '^i\'m back%p?$' @@ -21,7 +20,7 @@ function PLUGIN.action(msg) if config.people[tostring(msg.from.id)] then msg.from.first_name = config.people[tostring(msg.from.id)] end - for i = 3, #PLUGIN.triggers do + for i = 2, #PLUGIN.triggers do if string.match(input, PLUGIN.triggers[i]) then return send_message(msg.chat.id, 'Welcome back, ' .. msg.from.first_name .. '!') end diff --git a/plugins/lastfm.lua b/plugins/lastfm.lua new file mode 100644 index 0000000..8473044 --- /dev/null +++ b/plugins/lastfm.lua @@ -0,0 +1,54 @@ +local PLUGIN = {} + +PLUGIN.doc = [[ + /lastfm [username] + Get current- or last-played track data from last.fm. If a username is specified, it will return info for that username rather than your own. +]] + +PLUGIN.triggers = { + '^/lastfm' +} + +function PLUGIN.action(msg) + + local base_url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key=' .. config.lastfm_api_key .. '&user=' + + local input = get_input(msg.text) + if not input then + if msg.from.username then + input = msg.from.username + else + return send_msg(msg, 'Please provide a valid last.fm username.') + end + end + + local jstr, res = HTTP.request(base_url..input) + + if res ~= 200 then + return send_msg(msg, config.locale.errors.connection) + end + + local jdat = JSON.decode(jstr) + + if jdat.error then + return send_msg(msg, jdat.message) + end + + if not jdat.recenttracks.track then + return send_msg(msg, 'No history for that user.') + end + + local jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track + + local message = '🎵 ' .. input .. ' last listened to:\n' + if jdat['@attr'] and jdat['@attr'].nowplaying then + message = '🎵 ' .. input .. ' is listening to:\n' + end + + local message = message .. jdat.name .. ' - ' .. jdat.artist['#text'] + + send_message(msg.chat.id, message) + +end + +return PLUGIN diff --git a/plugins/moderation.lua b/plugins/moderation.lua new file mode 100644 index 0000000..c47e27e --- /dev/null +++ b/plugins/moderation.lua @@ -0,0 +1,304 @@ +-- So this plugin is an attempt to port @CIS_Bot's Liberbot moderation capabilities to the otouto base. By the time this code is public, @CIS_Bot will be running on pure otouto code. ¡Viva la Confederación! + +--[[ + +This works using the settings in the "moderation" section of config.lua. +"realm" should be set to the group ID of the admin group. A negative number. +"data" will be the file name of where the moderation 'database' will be stored. The file will be created if it does not exist. +"admins" is a table of administrators for the Liberbot admin group. They will have the power to add groups and moderators to the database. The value can be a nickname for the admin, but it only needs to be true for it to work. + +]]-- + +local help = {} + +help.trigger = '^/modhelp' + +help.action = function(msg) + + local data = load_data(config.moderation.data) + + local do_send = false + if data[tostring(msg.chat.id)] and data[tostring(msg.chat.id)][tostring(msg.from.id)] then do_send = true end + if config.moderation.admins[msg.from.id] then do_send = true end + if do_send == false then return end + + local message = [[ + Moderator commands: + /modban - Ban a user via reply or username. + /modkick - Kick a user via reply or username. + /modlist - Get a list of moderators for this group. + Administrator commands: + /modadd - Add this group to the database. + /modrem - Remove this group from the database. + /modprom - Promote a user via reply. + /moddem - Demote a user via reply. + /modcast - Send a broastcast to every group. + ]] + + send_message(msg.chat.id, message) + +end + + +local ban = {} + +ban.trigger = '^/modban' + +ban.action = function(msg) + + local data = load_data(config.moderation.data) + + if not data[tostring(msg.chat.id)] then return end + if not data[tostring(msg.chat.id)][tostring(msg.from.id)] then return end + + local target = get_target(msg) + if not target then + return send_message(msg.chat.id, 'No one to remove.\nBots must be removed by username.') + end + + if msg.reply_to_message and data[tostring(msg.chat.id)][tostring(msg.reply_to_message.from.id)] then + return send_message(msg.chat.id, 'Cannot remove a moderator.') + end + + local chat_id = math.abs(msg.chat.id) + + send_message(config.moderation.realm, '/ban ' .. target .. ' from ' .. chat_id) + + if msg.reply_to_message then + target = msg.reply_to_message.from.first_name + end + + send_message(config.moderation.realm, target .. ' banned from ' .. msg.chat.title .. ' by ' .. msg.from.first_name .. '.') + +end + + +local kick = {} + +kick.trigger = '^/modkick' + +kick.action = function(msg) + + local data = load_data(config.moderation.data) + + if not data[tostring(msg.chat.id)] then return end + if not data[tostring(msg.chat.id)][tostring(msg.from.id)] then return end + + local target = get_target(msg) + if not target then + return send_message(msg.chat.id, 'No one to remove.\nTip: Bots must be removed by username.') + end + + if msg.reply_to_message and data[tostring(msg.chat.id)][tostring(msg.reply_to_message.from.id)] then + return send_message(msg.chat.id, 'Cannot remove a moderator.') + end + + local chat_id = math.abs(msg.chat.id) + + send_message(config.moderation.realm, '/kick ' .. target .. ' from ' .. chat_id) + + if msg.reply_to_message then + target = msg.reply_to_message.from.first_name + end + + send_message(config.moderation.realm, target .. ' kicked from ' .. msg.chat.title .. ' by ' .. msg.from.first_name .. '.') + +end + + +local add = {} + +add.trigger = '^/modadd' + +add.action = function(msg) + + local data = load_data(config.moderation.data) + + if not config.moderation.admins[msg.from.id] then return end + + if data[tostring(msg.chat.id)] then + return send_message(msg.chat.id, 'Group is already added.') + end + + data[tostring(msg.chat.id)] = {} + save_data(config.moderation.data, data) + + send_message(msg.chat.id, 'Group has been added.') + +end + + +local rem = {} + +rem.trigger = '^/modrem' + +rem.action = function(msg) + + local data = load_data(config.moderation.data) + + if not config.moderation.admins[msg.from.id] then return end + + if not data[tostring(msg.chat.id)] then + return send_message(msg.chat.id, 'Group is not added.') + end + + data[tostring(msg.chat.id)] = nil + save_data(config.moderation.data, data) + + send_message(msg.chat.id, 'Group has been removed.') + +end + + +local promote = {} + +promote.trigger = '^/modprom' + +promote.action = function(msg) + + local data = load_data(config.moderation.data) + + if not config.moderation.admins[msg.from.id] then return end + + if not data[tostring(msg.chat.id)] then + return send_message(msg.chat.id, 'Group is not added.') + end + + if not msg.reply_to_message then + return send_message(msg.chat.id, 'Promotions must be done via reply.') + end + + if data[tostring(msg.chat.id)][tostring(msg.reply_to_message.from.id)] then + return send_message(msg.chat.id, msg.reply_to_message.from.first_name..' is already a moderator.') + end + + if not msg.reply_to_message.from.username then + msg.reply_to_message.from.username = msg.reply_to_message.from.first_name + end + + data[tostring(msg.chat.id)][tostring(msg.reply_to_message.from.id)] = msg.reply_to_message.from.first_name + save_data(config.moderation.data, data) + + send_message(msg.chat.id, msg.reply_to_message.from.first_name..' has been promoted.') + +end + + +local demote = {} + +demote.trigger = '^/moddem' + +demote.action = function(msg) + + local data = load_data(config.moderation.data) + + if not config.moderation.admins[msg.from.id] then return end + + if not data[tostring(msg.chat.id)] then + return send_message(msg.chat.id, 'Group is not added.') + end + + if not msg.reply_to_message then + return send_message(msg.chat.id, 'Demotions must be done via reply.') + end + + if not data[tostring(msg.chat.id)][tostring(msg.reply_to_message.from.id)] then + return send_message(msg.chat.id, msg.reply_to_message.from.first_name..' is not a moderator.') + end + + data[tostring(msg.chat.id)][tostring(msg.reply_to_message.from.id)] = nil + save_data(config.moderation.data, data) + + send_message(msg.chat.id, msg.reply_to_message.from.first_name..' has been demoted.') + +end + + +local broadcast = {} + +broadcast.trigger = '^/modcast' + +broadcast.action = function(msg) + + local data = load_data(config.moderation.data) + + if not config.moderation.admins[msg.from.id] then return end + + if msg.chat.id ~= config.moderation.realm then + return send_message(msg.chat.id, 'This command must be run in the admin group.') + end + + local message = get_input(msg.text) + + if not message then + return send_message(msg.chat.id, 'You must specify a message to broadcast.') + end + + for k,v in pairs(data) do + send_message(k, message) + end + +end + + +local modlist = {} + +modlist.trigger = '^/modlist' + +modlist.action = function(msg) + + local data = load_data(config.moderation.data) + + if not data[tostring(msg.chat.id)] then + return send_message(msg.chat.id, 'Group is not added.') + end + + local message = 'List of moderators for ' .. msg.chat.title .. ':\n' + + for k,v in pairs(data[tostring(msg.chat.id)]) do + message = message .. v .. ' (' .. k .. ')\n' + end + + send_message(msg.chat.id, message) + +end + + +local modactions = { + help, + ban, + kick, + add, + rem, + promote, + demote, + broadcast, + modlist +} + + +local triggers = { + '^/modhelp', + '^/modlist', + '^/modcast', + '^/modadd', + '^/modrem', + '^/modprom', + '^/moddem', + '^/modkick', + '^/modban' +} + +local action = function(msg) + for k,v in pairs(modactions) do + if string.match(msg.text, v.trigger) then + return v.action(msg) + end + end +end + +return { + triggers = triggers, + action = action, + no_typing = true +} diff --git a/plugins/urbandictionary.lua b/plugins/urbandictionary.lua index 710b159..68dfed9 100644 --- a/plugins/urbandictionary.lua +++ b/plugins/urbandictionary.lua @@ -14,7 +14,12 @@ function PLUGIN.action(msg) local input = get_input(msg.text) if not input then - return send_msg(msg, PLUGIN.doc) + if msg.reply_to_message then + msg = msg.reply_to_message + input = msg.text + else + return send_msg(msg, PLUGIN.doc) + end end local url = 'http://api.urbandictionary.com/v0/define?term=' .. URL.escape(input) diff --git a/utilities.lua b/utilities.lua index 53e2223..75e70f8 100644 --- a/utilities.lua +++ b/utilities.lua @@ -22,6 +22,19 @@ function get_input(text) -- returns string or false return string.sub(text, string.find(text, ' ')+1) end +function get_target(msg) + + if msg.reply_to_message then + return msg.reply_to_message.from.id + elseif string.find(msg.text, '@') then + local a = string.find(msg.text, '@') + return first_word(string.sub(msg.text, a)) + else + return false + end + +end + function trim_string(text) -- another alias return string.gsub(text, "^%s*(.-)%s*$", "%1") end @@ -82,3 +95,26 @@ function get_coords(input) return { lat = jdat.results[1].geometry.location.lat, lon = jdat.results[1].geometry.location.lng } end + +function load_data(filename) + + local f = io.open(filename) + if not f then + return {} + end + local s = f:read('*all') + f:close() + local data = JSON.decode(s) + + return data + +end + +function save_data(filename, data) + + local s = JSON.encode(data) + local f = io.open(filename, 'w') + f:write(s) + f:close() + +end