| @@ -17,7 +17,7 @@ otouto is an independently-developed Telegram API bot written in Lua. Originally | ||||
| | [Contributors](#contributors)                         | | ||||
|  | ||||
| ## Setup | ||||
| You _must_ have Lua (5.2+), lua-socket, lua-sec, and lua-cjson installed. To upload files, you must have curl installed. To use fortune.lua, you must have fortune installed. | ||||
| You _must_ have Lua (5.2+), lua-socket, lua-sec, and dkjson installed. It is recommended you install these with LuaRocks. To upload files, you must have curl installed. To use fortune.lua, you must have fortune installed. | ||||
|  | ||||
| Clone the repository and set the following values in `config.lua`: | ||||
|  | ||||
| @@ -26,7 +26,6 @@ Clone the repository and set the following values in `config.lua`: | ||||
|  | ||||
| Optionally: | ||||
|  | ||||
|  - `time_offset` as the difference, in seconds, of your system clock to UTC. | ||||
|  - `lang` as the two-letter code representing your language. | ||||
|  | ||||
| Some plugins are not enabled by default. If you wish to enable them, add them to the `plugins` array. | ||||
|   | ||||
							
								
								
									
										124
									
								
								bindings.lua
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								bindings.lua
									
									
									
									
									
								
							| @@ -2,17 +2,13 @@ | ||||
| -- Bindings for the Telegram bot API. | ||||
| -- https://core.telegram.org/bots/api | ||||
|  | ||||
| assert(HTTPS) | ||||
| assert(JSON) | ||||
| assert(URL) | ||||
| local bindings = {} | ||||
|  | ||||
| local BASE_URL = 'https://api.telegram.org/bot' .. config.bot_api_key | ||||
| local HTTPS = require('ssl.https') | ||||
| local JSON = require('dkjson') | ||||
| local URL = require('socket.url') | ||||
|  | ||||
| if config.bot_api_key == '' then | ||||
| 	error('You did not set your bot token in config.lua!') | ||||
| end | ||||
|  | ||||
| sendRequest = function(url) | ||||
| function bindings.sendRequest(url) | ||||
|  | ||||
| 	local dat, res = HTTPS.request(url) | ||||
|  | ||||
| @@ -28,28 +24,28 @@ sendRequest = function(url) | ||||
|  | ||||
| end | ||||
|  | ||||
| getMe = function() | ||||
| function bindings:getMe() | ||||
|  | ||||
| 	local url = BASE_URL .. '/getMe' | ||||
| 	return sendRequest(url) | ||||
| 	local url = self.BASE_URL .. '/getMe' | ||||
| 	return bindings.sendRequest(url) | ||||
|  | ||||
| end | ||||
|  | ||||
| getUpdates = function(offset) | ||||
| function bindings:getUpdates(offset) | ||||
|  | ||||
| 	local url = BASE_URL .. '/getUpdates?timeout=20' | ||||
| 	local url = self.BASE_URL .. '/getUpdates?timeout=20' | ||||
|  | ||||
| 	if offset then | ||||
| 		url = url .. '&offset=' .. offset | ||||
| 	end | ||||
|  | ||||
| 	return sendRequest(url) | ||||
| 	return bindings.sendRequest(url) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendMessage = function(chat_id, text, disable_web_page_preview, reply_to_message_id, use_markdown, disable_notification) | ||||
| function bindings:sendMessage(chat_id, text, disable_web_page_preview, reply_to_message_id, use_markdown, disable_notification) | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendMessage?chat_id=' .. chat_id .. '&text=' .. URL.escape(text) | ||||
| 	local url = self.BASE_URL .. '/sendMessage?chat_id=' .. chat_id .. '&text=' .. URL.escape(text) | ||||
|  | ||||
| 	if disable_web_page_preview == true then | ||||
| 		url = url .. '&disable_web_page_preview=true' | ||||
| @@ -67,30 +63,30 @@ sendMessage = function(chat_id, text, disable_web_page_preview, reply_to_message | ||||
| 		url = url .. '&disable_notification=true' | ||||
| 	end | ||||
|  | ||||
| 	return sendRequest(url) | ||||
| 	return bindings.sendRequest(url) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendReply = function(msg, text) | ||||
| function bindings:sendReply(msg, text, use_markdown, disable_notification) | ||||
|  | ||||
| 	return sendMessage(msg.chat.id, text, true, msg.message_id) | ||||
| 	return bindings.sendMessage(self, msg.chat.id, text, true, msg.message_id, use_markdown, disable_notification) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendChatAction = function(chat_id, action) | ||||
| function bindings:sendChatAction(chat_id, action) | ||||
|  -- Support actions are typing, upload_photo, record_video, upload_video, record_audio, upload_audio, upload_document, find_location | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendChatAction?chat_id=' .. chat_id .. '&action=' .. action | ||||
| 	return sendRequest(url) | ||||
| 	local url = self.BASE_URL .. '/sendChatAction?chat_id=' .. chat_id .. '&action=' .. action | ||||
| 	return bindings.sendRequest(url) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendLocation = function(chat_id, latitude, longitude, reply_to_message_id, disable_notification) | ||||
| function bindings:sendLocation(chat_id, latitude, longitude, reply_to_message_id, disable_notification) | ||||
|  | ||||
| 	if latitude == 0 then latitude = 0.001 end | ||||
| 	if longitude == 0 then longitude = 0.001 end | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendLocation?chat_id=' .. chat_id .. '&latitude=' .. latitude .. '&longitude=' .. longitude | ||||
| 	local url = self.BASE_URL .. '/sendLocation?chat_id=' .. chat_id .. '&latitude=' .. latitude .. '&longitude=' .. longitude | ||||
|  | ||||
| 	if reply_to_message_id then | ||||
| 		url = url .. '&reply_to_message_id=' .. reply_to_message_id | ||||
| @@ -100,16 +96,16 @@ sendLocation = function(chat_id, latitude, longitude, reply_to_message_id, disab | ||||
| 		url = url .. '&disable_notification=true' | ||||
| 	end | ||||
|  | ||||
| 	return sendRequest(url) | ||||
| 	return bindings.sendRequest(url) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendVenue = function(chat_id, latitude, longitude, title, address, foursquare_id, reply_to_message_id, disable_notification) | ||||
| function bindings:sendVenue(chat_id, latitude, longitude, title, address, foursquare_id, reply_to_message_id, disable_notification) | ||||
|  | ||||
| 	if latitude == 0 then latitude = 0.001 end | ||||
| 	if longitude == 0 then longitude = 0.001 end | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendVenue?chat_id=' .. chat_id .. '&latitude=' .. latitude .. '&longitude=' .. longitude .. '&title=' .. title .. '&address=' .. address | ||||
| 	local url = self.BASE_URL .. '/sendVenue?chat_id=' .. chat_id .. '&latitude=' .. latitude .. '&longitude=' .. longitude .. '&title=' .. title .. '&address=' .. address | ||||
|  | ||||
| 	if foursquare_id then | ||||
| 		url = url .. '&foursquare_id=' .. foursquare_id | ||||
| @@ -123,13 +119,13 @@ sendVenue = function(chat_id, latitude, longitude, title, address, foursquare_id | ||||
| 		url = url .. '&disable_notification=true' | ||||
| 	end | ||||
|  | ||||
| 	return sendRequest(url) | ||||
| 	return bindings.sendRequest(url) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendContact = function(chat_id, phone_number, first_name, last_name, reply_to_message_id, disable_notification) | ||||
| function bindings.sendContact(chat_id, phone_number, first_name, last_name, reply_to_message_id, disable_notification) | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendContact?chat_id=' .. chat_id .. '&phone_number=' .. phone_number .. '&first_name=' .. first_name | ||||
| 	local url = self.BASE_URL .. '/sendContact?chat_id=' .. chat_id .. '&phone_number=' .. phone_number .. '&first_name=' .. first_name | ||||
|  | ||||
| 	if last_name then | ||||
| 		url = url .. '&last_name=' .. last_name | ||||
| @@ -143,37 +139,37 @@ sendContact = function(chat_id, phone_number, first_name, last_name, reply_to_me | ||||
| 		url = url .. '&disable_notification=true' | ||||
| 	end | ||||
|  | ||||
| 	return sendRequest(url) | ||||
| 	return bindings.sendRequest(url) | ||||
|  | ||||
| end | ||||
|  | ||||
| forwardMessage = function(chat_id, from_chat_id, message_id, disable_notification) | ||||
| function bindings:forwardMessage(chat_id, from_chat_id, message_id, disable_notification) | ||||
|  | ||||
| 	local url = BASE_URL .. '/forwardMessage?chat_id=' .. chat_id .. '&from_chat_id=' .. from_chat_id .. '&message_id=' .. message_id | ||||
| 	local url = self.BASE_URL .. '/forwardMessage?chat_id=' .. chat_id .. '&from_chat_id=' .. from_chat_id .. '&message_id=' .. message_id | ||||
|  | ||||
| 	if disable_notification then | ||||
| 		url = url .. '&disable_notification=true' | ||||
| 	end | ||||
|  | ||||
| 	return sendRequest(url) | ||||
| 	return bindings.sendRequest(url) | ||||
|  | ||||
| end | ||||
|  | ||||
| kickChatMember = function(chat_id, user_id) | ||||
| 	local url = BASE_URL .. '/kickChatMember?chat_id=' .. chat_id .. '&user_id=' .. user_id | ||||
| 	return sendRequest(url) | ||||
| function bindings:kickChatMember(chat_id, user_id) | ||||
| 	local url = self.BASE_URL .. '/kickChatMember?chat_id=' .. chat_id .. '&user_id=' .. user_id | ||||
| 	return bindings.sendRequest(url) | ||||
| end | ||||
|  | ||||
| unbanChatMember = function(chat_id, user_id) | ||||
| 	local url = BASE_URL .. '/unbanChatMember?chat_id=' .. chat_id .. '&user_id=' .. user_id | ||||
| 	return sendRequest(url) | ||||
| function bindings:unbanChatMember(chat_id, user_id) | ||||
| 	local url = self.BASE_URL .. '/unbanChatMember?chat_id=' .. chat_id .. '&user_id=' .. user_id | ||||
| 	return bindings.sendRequest(url) | ||||
| end | ||||
|  | ||||
|  -- TODO: More of this. | ||||
|  | ||||
| sendPhotoID = function(chat_id, file_id, caption, reply_to_message_id, disable_notification) | ||||
| function bindings:sendPhotoID(chat_id, file_id, caption, reply_to_message_id, disable_notification) | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendPhoto?chat_id=' .. chat_id .. '&photo=' .. file_id | ||||
| 	local url = self.BASE_URL .. '/sendPhoto?chat_id=' .. chat_id .. '&photo=' .. file_id | ||||
|  | ||||
| 	if caption then | ||||
| 		url = url .. '&caption=' .. URL.escape(caption) | ||||
| @@ -187,20 +183,20 @@ sendPhotoID = function(chat_id, file_id, caption, reply_to_message_id, disable_n | ||||
| 		url = url .. '&disable_notification=true' | ||||
| 	end | ||||
|  | ||||
| 	return sendRequest(url) | ||||
| 	return bindings.sendRequest(url) | ||||
|  | ||||
| end | ||||
|  | ||||
| curlRequest = function(curl_command) | ||||
| function bindings.curlRequest(curl_command) | ||||
|  -- Use at your own risk. Will not check for success. | ||||
|  | ||||
| 	io.popen(curl_command) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendPhoto = function(chat_id, photo, caption, reply_to_message_id, disable_notification) | ||||
| function bindings:sendPhoto(chat_id, photo, caption, reply_to_message_id, disable_notification) | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendPhoto' | ||||
| 	local url = self.BASE_URL .. '/sendPhoto' | ||||
|  | ||||
| 	local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "photo=@' .. photo .. '"' | ||||
|  | ||||
| @@ -216,13 +212,13 @@ sendPhoto = function(chat_id, photo, caption, reply_to_message_id, disable_notif | ||||
| 		curl_command = curl_command .. ' -F "disable_notification=true"' | ||||
| 	end | ||||
|  | ||||
| 	return curlRequest(curl_command) | ||||
| 	return bindings.curlRequest(curl_command) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendDocument = function(chat_id, document, reply_to_message_id, disable_notification) | ||||
| function bindings:sendDocument(chat_id, document, reply_to_message_id, disable_notification) | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendDocument' | ||||
| 	local url = self.BASE_URL .. '/sendDocument' | ||||
|  | ||||
| 	local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "document=@' .. document .. '"' | ||||
|  | ||||
| @@ -234,13 +230,13 @@ sendDocument = function(chat_id, document, reply_to_message_id, disable_notifica | ||||
| 		curl_command = curl_command .. ' -F "disable_notification=true"' | ||||
| 	end | ||||
|  | ||||
| 	return curlRequest(curl_command) | ||||
| 	return bindings.curlRequest(curl_command) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendSticker = function(chat_id, sticker, reply_to_message_id, disable_notification) | ||||
| function bindings:sendSticker(chat_id, sticker, reply_to_message_id, disable_notification) | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendSticker' | ||||
| 	local url = self.BASE_URL .. '/sendSticker' | ||||
|  | ||||
| 	local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "sticker=@' .. sticker .. '"' | ||||
|  | ||||
| @@ -252,13 +248,13 @@ sendSticker = function(chat_id, sticker, reply_to_message_id, disable_notificati | ||||
| 		curl_command = curl_command .. ' -F "disable_notification=true"' | ||||
| 	end | ||||
|  | ||||
| 	return curlRequest(curl_command) | ||||
| 	return bindings.curlRequest(curl_command) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendAudio = function(chat_id, audio, reply_to_message_id, duration, performer, title, disable_notification) | ||||
| function bindings:sendAudio(chat_id, audio, reply_to_message_id, duration, performer, title, disable_notification) | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendAudio' | ||||
| 	local url = self.BASE_URL .. '/sendAudio' | ||||
|  | ||||
| 	local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "audio=@' .. audio .. '"' | ||||
|  | ||||
| @@ -282,13 +278,13 @@ sendAudio = function(chat_id, audio, reply_to_message_id, duration, performer, t | ||||
| 		curl_command = curl_command .. ' -F "disable_notification=true"' | ||||
| 	end | ||||
|  | ||||
| 	return curlRequest(curl_command) | ||||
| 	return bindings.curlRequest(curl_command) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendVideo = function(chat_id, video, reply_to_message_id, duration, caption, disable_notification) | ||||
| function bindings:sendVideo(chat_id, video, reply_to_message_id, duration, caption, disable_notification) | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendVideo' | ||||
| 	local url = self.BASE_URL .. '/sendVideo' | ||||
|  | ||||
| 	local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "video=@' .. video .. '"' | ||||
|  | ||||
| @@ -308,13 +304,13 @@ sendVideo = function(chat_id, video, reply_to_message_id, duration, caption, dis | ||||
| 		curl_command = curl_command .. ' -F "disable_notification=true"' | ||||
| 	end | ||||
|  | ||||
| 	return curlRequest(curl_command) | ||||
| 	return bindings.curlRequest(curl_command) | ||||
|  | ||||
| end | ||||
|  | ||||
| sendVoice = function(chat_id, voice, reply_to_message_id, duration, disable_notification) | ||||
| function bindings:sendVoice(chat_id, voice, reply_to_message_id, duration, disable_notification) | ||||
|  | ||||
| 	local url = BASE_URL .. '/sendVoice' | ||||
| 	local url = self.BASE_URL .. '/sendVoice' | ||||
|  | ||||
| 	local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "voice=@' .. voice .. '"' | ||||
|  | ||||
| @@ -330,6 +326,8 @@ sendVoice = function(chat_id, voice, reply_to_message_id, duration, disable_noti | ||||
| 		curl_command = curl_command .. ' -F "disable_notification=true"' | ||||
| 	end | ||||
|  | ||||
| 	return curlRequest(curl_command) | ||||
| 	return bindings.curlRequest(curl_command) | ||||
|  | ||||
| end | ||||
|  | ||||
| return bindings | ||||
|   | ||||
							
								
								
									
										128
									
								
								bot.lua
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								bot.lua
									
									
									
									
									
								
							| @@ -1,77 +1,85 @@ | ||||
| HTTP = require('socket.http') | ||||
| HTTPS = require('ssl.https') | ||||
| URL = require('socket.url') | ||||
| JSON = require('cjson') | ||||
| local bot = {} | ||||
|  | ||||
| version = '3.6' | ||||
| -- Requires are moved to init to allow for reloads. | ||||
| local bindings -- Load Telegram bindings. | ||||
| local utilities -- Load miscellaneous and cross-plugin functions. | ||||
|  | ||||
| bot_init = function() -- The function run when the bot is started or reloaded. | ||||
| bot.version = '3.7' | ||||
|  | ||||
| 	config = dofile('config.lua') -- Load configuration file. | ||||
| 	dofile('bindings.lua') -- Load Telegram bindings. | ||||
| 	dofile('utilities.lua') -- Load miscellaneous and cross-plugin functions. | ||||
| function bot:init() -- The function run when the bot is started or reloaded. | ||||
|  | ||||
| 	bindings = require('bindings') | ||||
| 	utilities = require('utilities') | ||||
|  | ||||
| 	self.config = require('config') -- Load configuration file. | ||||
|  | ||||
| 	self.BASE_URL = 'https://api.telegram.org/bot' .. self.config.bot_api_key | ||||
| 	if self.config.bot_api_key == '' then | ||||
| 		error('You did not set your bot token in config.lua!') | ||||
| 	end | ||||
|  | ||||
| 	-- Fetch bot information. Try until it succeeds. | ||||
| 	repeat bot = getMe() until bot | ||||
| 	bot = bot.result | ||||
| 	repeat self.info = bindings.getMe(self) until self.info | ||||
| 	self.info = self.info.result | ||||
|  | ||||
| 	-- Load the "database"! ;) | ||||
| 	if not database then | ||||
| 		database = load_data(bot.username..'.db') | ||||
| 	if not self.database then | ||||
| 		self.database = utilities.load_data(self.info.username..'.db') | ||||
| 	end | ||||
|  | ||||
| 	plugins = {} -- Load plugins. | ||||
| 	for i,v in ipairs(config.plugins) do | ||||
| 		local p = dofile('plugins/'..v) | ||||
| 		table.insert(plugins, p) | ||||
| 	self.plugins = {} -- Load plugins. | ||||
| 	for _,v in ipairs(self.config.plugins) do | ||||
| 		local p = require('plugins.'..v) | ||||
| 		table.insert(self.plugins, p) | ||||
| 		if p.init then p.init(self) end | ||||
| 	end | ||||
|  | ||||
| 	print('@' .. bot.username .. ', AKA ' .. bot.first_name ..' ('..bot.id..')') | ||||
| 	print('@' .. self.info.username .. ', AKA ' .. self.info.first_name ..' ('..self.info.id..')') | ||||
|  | ||||
| 	-- Generate a random seed and "pop" the first random number. :) | ||||
| 	math.randomseed(os.time()) | ||||
| 	math.random() | ||||
|  | ||||
| 	last_update = last_update or 0 -- Set loop variables: Update offset, | ||||
| 	last_cron = last_cron or os.date('%M') -- the time of the last cron job, | ||||
| 	is_started = true -- and whether or not the bot should be running. | ||||
| 	database.users = database.users or {} -- Table to cache userdata. | ||||
| 	database.users[tostring(bot.id)] = bot | ||||
| 	self.last_update = self.last_update or 0 -- Set loop variables: Update offset, | ||||
| 	self.last_cron = self.last_cron or os.date('%M') -- the time of the last cron job, | ||||
| 	self.is_started = true -- and whether or not the bot should be running. | ||||
| 	self.database.users = self.database.users or {} -- Table to cache userdata. | ||||
| 	self.database.users[tostring(self.info.id)] = self.info | ||||
|  | ||||
| end | ||||
|  | ||||
| on_msg_receive = function(msg) -- The fn run whenever a message is received. | ||||
| function bot:on_msg_receive(msg) -- The fn run whenever a message is received. | ||||
|  | ||||
| 	-- Create a user entry if it does not exist. | ||||
| 	if not database.users[tostring(msg.from.id)] then | ||||
| 		database.users[tostring(msg.from.id)] = {} | ||||
| 	if not self.database.users[tostring(msg.from.id)] then | ||||
| 		self.database.users[tostring(msg.from.id)] = {} | ||||
| 	end | ||||
| 	-- Clear things that no longer exist. | ||||
| 	database.users[tostring(msg.from.id)].username = nil | ||||
| 	database.users[tostring(msg.from.id)].last_name = nil | ||||
| 	self.database.users[tostring(msg.from.id)].username = nil | ||||
| 	self.database.users[tostring(msg.from.id)].last_name = nil | ||||
| 	-- Wee. | ||||
| 	for k,v in pairs(msg.from) do | ||||
| 		database.users[tostring(msg.from.id)][k] = v | ||||
| 		self.database.users[tostring(msg.from.id)][k] = v | ||||
| 	end | ||||
|  | ||||
| 	if msg.date < os.time() - 5 then return end -- Do not process old messages. | ||||
|  | ||||
| 	msg = enrich_message(msg) | ||||
| 	msg = utilities.enrich_message(msg) | ||||
|  | ||||
| 	if msg.text:match('^/start .+') then | ||||
| 		msg.text = '/' .. msg.text:input() | ||||
| 		msg.text = '/' .. utilities.input(msg.text) | ||||
| 		msg.text_lower = msg.text:lower() | ||||
| 	end | ||||
|  | ||||
| 	for i,v in ipairs(plugins) do | ||||
| 		for k,w in pairs(v.triggers) do | ||||
| 	for _,v in ipairs(self.plugins) do | ||||
| 		for _,w in pairs(v.triggers) do | ||||
| 			if string.match(msg.text:lower(), w) then | ||||
| 				local success, result = pcall(function() | ||||
| 					return v.action(msg) | ||||
| 					return v.action(self, msg) | ||||
| 				end) | ||||
| 				if not success then | ||||
| 					sendReply(msg, 'Sorry, an unexpected error occurred.') | ||||
| 					handle_exception(result, msg.from.id .. ': ' .. msg.text) | ||||
| 					bindings.sendReply(self, msg, 'Sorry, an unexpected error occurred.') | ||||
| 					utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text) | ||||
| 					return | ||||
| 				end | ||||
| 				-- If the action returns a table, make that table msg. | ||||
| @@ -87,35 +95,41 @@ on_msg_receive = function(msg) -- The fn run whenever a message is received. | ||||
|  | ||||
| end | ||||
|  | ||||
| bot_init() -- Actually start the script. Run the bot_init function. | ||||
| function bot:run() | ||||
| 	bot.init(self) -- Actually start the script. Run the bot_init function. | ||||
|  | ||||
| while is_started do -- Start a loop while the bot should be running. | ||||
| 	while self.is_started do -- Start a loop while the bot should be running. | ||||
|  | ||||
| 	local res = getUpdates(last_update+1) -- Get the latest updates! | ||||
| 	if res then | ||||
| 		for i,v in ipairs(res.result) do -- Go through every new message. | ||||
| 			last_update = v.update_id | ||||
| 			on_msg_receive(v.message) | ||||
| 		do | ||||
| 			local res = bindings.getUpdates(self, self.last_update+1) -- Get the latest updates! | ||||
| 			if res then | ||||
| 				for _,v in ipairs(res.result) do -- Go through every new message. | ||||
| 					self.last_update = v.update_id | ||||
| 					bot.on_msg_receive(self, v.message) | ||||
| 				end | ||||
| 			else | ||||
| 				print(self.config.errors.connection) | ||||
| 			end | ||||
| 		end | ||||
| 	else | ||||
| 		print(config.errors.connection) | ||||
| 	end | ||||
|  | ||||
| 	if last_cron ~= os.date('%M') then -- Run cron jobs every minute. | ||||
| 		last_cron = os.date('%M') | ||||
| 		save_data(bot.username..'.db', database) -- Save the database. | ||||
| 		for i,v in ipairs(plugins) do | ||||
| 			if v.cron then -- Call each plugin's cron function, if it has one. | ||||
| 				local res, err = pcall(function() v.cron() end) | ||||
| 				if not res then | ||||
| 					handle_exception(err, 'CRON: ' .. i) | ||||
| 		if self.last_cron ~= os.date('%M') then -- Run cron jobs every minute. | ||||
| 			self.last_cron = os.date('%M') | ||||
| 			utilities.save_data(self.info.username..'.db', self.database) -- Save the database. | ||||
| 			for i,v in ipairs(self.plugins) do | ||||
| 				if v.cron then -- Call each plugin's cron function, if it has one. | ||||
| 					local res, err = pcall(function() v.cron(self) end) | ||||
| 					if not res then | ||||
| 						utilities.handle_exception(self, err, 'CRON: ' .. i) | ||||
| 					end | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 	end | ||||
|  | ||||
| 	-- Save the database before exiting. | ||||
| 	utilities.save_data(self.info.username..'.db', self.database) | ||||
| 	print('Halted.') | ||||
| end | ||||
|  | ||||
|  -- Save the database before exiting. | ||||
| save_data(bot.username..'.db', database) | ||||
| print('Halted.') | ||||
| return bot | ||||
|   | ||||
							
								
								
									
										58
									
								
								config.lua
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								config.lua
									
									
									
									
									
								
							| @@ -4,8 +4,6 @@ return { | ||||
| 	bot_api_key = '', | ||||
| 	-- Your Telegram ID. | ||||
| 	admin = 00000000, | ||||
| 	-- Differences, in seconds, between your time and UTC. | ||||
| 	time_offset = 0, | ||||
| 	-- Two-letter language code. | ||||
| 	lang = 'en', | ||||
| 	-- The channel, group, or user to send error reports to. | ||||
| @@ -51,35 +49,35 @@ Send /help to get started. | ||||
| 	}, | ||||
|  | ||||
| 	plugins = { -- To enable a plugin, add its name to the list. | ||||
| 		'control.lua', | ||||
| 		'blacklist.lua', | ||||
| 		'about.lua', | ||||
| 		'ping.lua', | ||||
| 		'whoami.lua', | ||||
| 		'nick.lua', | ||||
| 		'echo.lua', | ||||
| 		'gSearch.lua', | ||||
| 		'gMaps.lua', | ||||
| 		'wikipedia.lua', | ||||
| 		'hackernews.lua', | ||||
| 		'imdb.lua', | ||||
| 		'calc.lua', | ||||
| 		'urbandictionary.lua', | ||||
| 		'time.lua', | ||||
| 		'eightball.lua', | ||||
| 		'dice.lua', | ||||
| 		'reddit.lua', | ||||
| 		'xkcd.lua', | ||||
| 		'slap.lua', | ||||
| 		'commit.lua', | ||||
| 		'pun.lua', | ||||
| 		'currency.lua', | ||||
| 		'cats.lua', | ||||
| 		'shout.lua', | ||||
| 		'patterns.lua', | ||||
| 		'control', | ||||
| 		'blacklist', | ||||
| 		'about', | ||||
| 		'ping', | ||||
| 		'whoami', | ||||
| 		'nick', | ||||
| 		'echo', | ||||
| 		'gSearch', | ||||
| 		'gMaps', | ||||
| 		'wikipedia', | ||||
| 		'hackernews', | ||||
| 		'imdb', | ||||
| 		'calc', | ||||
| 		'urbandictionary', | ||||
| 		'time', | ||||
| 		'eightball', | ||||
| 		'dice', | ||||
| 		'reddit', | ||||
| 		'xkcd', | ||||
| 		'slap', | ||||
| 		'commit', | ||||
| 		'pun', | ||||
| 		'currency', | ||||
| 		'cats', | ||||
| 		'shout', | ||||
| 		'patterns', | ||||
| 		-- Put new plugins above this line. | ||||
| 		'help.lua', | ||||
| 		'greetings.lua' | ||||
| 		'help', | ||||
| 		'greetings' | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| while true; do | ||||
| 	lua bot.lua | ||||
| 	lua main.lua | ||||
| 	echo 'otouto has stopped. ^C to exit.' | ||||
| 	sleep 5s | ||||
| done | ||||
|   | ||||
							
								
								
									
										5
									
								
								main.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								main.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| local bot = require('bot') | ||||
|  | ||||
| local instance = {} | ||||
|  | ||||
| return bot.run(instance) | ||||
							
								
								
									
										22
									
								
								otouto-dev-1.rockspec
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								otouto-dev-1.rockspec
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| package = 'otouto' | ||||
| version = 'dev-1' | ||||
|  | ||||
| source = { | ||||
|   url = 'git://github.com/topkecleon/otouto.git' | ||||
| } | ||||
|  | ||||
| description = { | ||||
|   summary = 'The plugin-wielding, multipurpose Telegram bot!', | ||||
|   detailed = 'A plugin-wielding, multipurpose bot for the Telegram API.', | ||||
|   homepage = 'http://otou.to', | ||||
|   maintainer = 'Drew <drew@otou.to>', | ||||
|   license = 'GPL-2' | ||||
| } | ||||
|  | ||||
| dependencies = { | ||||
|   'lua >= 5.2', | ||||
|   'LuaSocket ~> 3.0', | ||||
|   'LuaSec ~> 0.6', | ||||
|   'dkjson ~> 2.5', | ||||
|   'LPeg ~> 1.0' | ||||
| } | ||||
| @@ -1,22 +1,28 @@ | ||||
| local command = 'about' | ||||
| local doc = '`Returns information about the bot.`' | ||||
| local about = {} | ||||
|  | ||||
| local triggers = { | ||||
| local bot = require('bot') | ||||
| local bindings = require('bindings') | ||||
|  | ||||
| about.command = 'about' | ||||
| about.doc = '`Returns information about the bot.`' | ||||
|  | ||||
| about.triggers = { | ||||
| 	'' | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
| function about:action(msg) | ||||
|  | ||||
| 	-- Filthy hack, but here is where we'll stop forwarded messages from hitting | ||||
| 	-- other plugins. | ||||
| 	if msg.forward_from then return end | ||||
|  | ||||
| 	local output = config.about_text .. '\nBased on @otouto v'..version..' by topkecleon.' | ||||
| 	local output = self.config.about_text .. '\nBased on @otouto v'..bot.version..' by topkecleon.' | ||||
|  | ||||
| 	if (msg.new_chat_participant and msg.new_chat_participant.id == bot.id) | ||||
| 	or msg.text_lower:match('^/about[@'..bot.username..']*') | ||||
| 	if (msg.new_chat_participant and msg.new_chat_participant.id == self.info.id) | ||||
| 		or msg.text_lower:match('^/about') | ||||
| 		or msg.text_lower:match('^/about@'..self.info.username:lower()) | ||||
| 	or msg.text_lower:match('^/start') then | ||||
| 		sendMessage(msg.chat.id, output, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, output, true) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -24,9 +30,4 @@ local action = function(msg) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return about | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,5 +1,13 @@ | ||||
| local command = 'apod [date]' | ||||
| local doc = [[``` | ||||
| local apod = {} | ||||
|  | ||||
| local HTTPS = require('ssl.https') | ||||
| local JSON = require('dkjson') | ||||
| local URL = require('socket.url') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| apod.command = 'apod [date]' | ||||
| apod.doc = [[``` | ||||
| /apod [query] | ||||
| Returns the Astronomy Picture of the Day. | ||||
| If the query is a date, in the format YYYY-MM-DD, the APOD of that day is returned. | ||||
| @@ -10,31 +18,29 @@ Returns the explanation of the APOD. | ||||
| Source: nasa.gov | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/apod[@'..bot.username..']*', | ||||
| 	'^/apodhd[@'..bot.username..']*', | ||||
| 	'^/apodtext[@'..bot.username..']*' | ||||
| } | ||||
| function apod:init() | ||||
| 	apod.triggers = utilities.triggers(self.info.username) | ||||
| 		:t('apod', true):t('apodhd', true):t('apodtext', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function apod:action(msg) | ||||
|  | ||||
| 	if not config.nasa_api_key then | ||||
| 		config.nasa_api_key = 'DEMO_KEY' | ||||
| 	if not self.config.nasa_api_key then | ||||
| 		self.config.nasa_api_key = 'DEMO_KEY' | ||||
| 	end | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local caption = '' | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	local date = '*' | ||||
| 	local disable_page_preview = false | ||||
|  | ||||
| 	local url = 'https://api.nasa.gov/planetary/apod?api_key=' .. config.nasa_api_key | ||||
| 	local url = 'https://api.nasa.gov/planetary/apod?api_key=' .. self.config.nasa_api_key | ||||
|  | ||||
| 	if input then | ||||
| 		if input:match('(%d+)%-(%d+)%-(%d+)$') then | ||||
| 			url = url .. '&date=' .. URL.escape(input) | ||||
| 			date = date .. input | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, apod.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	else | ||||
| @@ -45,14 +51,14 @@ local action = function(msg) | ||||
|  | ||||
| 	local jstr, res = HTTPS.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
|  | ||||
| 	if jdat.error then | ||||
| 		sendReply(msg, config.errors.results) | ||||
| 		bindings.sendReply(msg, self.config.errors.results) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -62,7 +68,7 @@ local action = function(msg) | ||||
| 		img_url = jdat.hdurl or jdat.url | ||||
| 	end | ||||
|  | ||||
| 	output = date .. '[' .. jdat.title  .. '](' .. img_url .. ')' | ||||
| 	local output = date .. '[' .. jdat.title  .. '](' .. img_url .. ')' | ||||
|  | ||||
| 	if string.match(msg.text, '^/apodtext*') then | ||||
| 		output = output .. '\n' .. jdat.explanation | ||||
| @@ -73,13 +79,8 @@ local action = function(msg) | ||||
| 		output = output .. '\nCopyright: ' .. jdat.copyright | ||||
| 	end | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, disable_page_preview, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, disable_page_preview, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return apod | ||||
|   | ||||
| @@ -1,13 +1,17 @@ | ||||
| local command = 'bandersnatch' | ||||
| local doc = [[``` | ||||
| local bandersnatch = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| bandersnatch.command = 'bandersnatch' | ||||
| bandersnatch.doc = [[``` | ||||
| Shun the frumious Bandersnatch. | ||||
| Alias: /bc | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/bandersnatch[@'..bot.username..']*', | ||||
| 	'^/bc[@'..bot.username..']*' | ||||
| } | ||||
| function bandersnatch:init() | ||||
| 	bandersnatch.triggers = utilities.triggers(self.info.username):t('bandersnatch'):t('bc').table | ||||
| end | ||||
|  | ||||
| local fullnames = { "Wimbledon Tennismatch", "Rinkydink Curdlesnoot", "Butawhiteboy Cantbekhan", "Benadryl Claritin", "Bombadil Rivendell", "Wanda's Crotchfruit", "Biblical Concubine", "Syphilis Cankersore", "Buckminster Fullerene", "Bourgeoisie Capitalist" } | ||||
|  | ||||
| @@ -15,9 +19,9 @@ local firstnames = { "Bumblebee", "Bandersnatch", "Broccoli", "Rinkydink", "Bomb | ||||
|  | ||||
| local lastnames = { "Coddleswort", "Crumplesack", "Curdlesnoot", "Calldispatch", "Humperdinck", "Rivendell", "Cuttlefish", "Lingerie", "Vegemite", "Ampersand", "Cumberbund", "Candycrush", "Clombyclomp", "Cragglethatch", "Nottinghill", "Cabbagepatch", "Camouflage", "Creamsicle", "Curdlemilk", "Upperclass", "Frumblesnatch", "Crumplehorn", "Talisman", "Candlestick", "Chesterfield", "Bumbersplat", "Scratchnsniff", "Snugglesnatch", "Charizard", "Carrotstick", "Cumbercooch", "Crackerjack", "Crucifix", "Cuckatoo", "Cockletit", "Collywog", "Capncrunch", "Covergirl", "Cumbersnatch", "Countryside", "Coggleswort", "Splishnsplash", "Copperwire", "Animorph", "Curdledmilk", "Cheddarcheese", "Cottagecheese", "Crumplehorn", "Snickersbar", "Banglesnatch", "Stinkyrash", "Cameltoe", "Chickenbroth", "Concubine", "Candygram", "Moldyspore", "Chuckecheese", "Cankersore", "Crimpysnitch", "Wafflesmack", "Chowderpants", "Toodlesnoot", "Clavichord", "Cuckooclock", "Oxfordshire", "Cumbersome", "Chickenstrips", "Battleship", "Commonwealth", "Cunningsnatch", "Custardbath", "Kryptonite", "Curdlesnoot", "Cummerbund", "Coochyrash", "Crackerdong", "Crackerdong", "Curdledong", "Crackersprout", "Crumplebutt", "Colonist", "Coochierash", "Thundersnatch" } | ||||
|  | ||||
| local action = function(msg) | ||||
| function bandersnatch:action(msg) | ||||
|  | ||||
| 	local message | ||||
| 	local output | ||||
|  | ||||
| 	if math.random(10) == 10 then | ||||
| 		output = fullnames[math.random(#fullnames)] | ||||
| @@ -25,15 +29,8 @@ local action = function(msg) | ||||
| 		output = firstnames[math.random(#firstnames)] .. ' ' .. lastnames[math.random(#lastnames)] | ||||
| 	end | ||||
|  | ||||
| 	output = '_' .. output .. '_' | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, '_'..output..'_', true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return bandersnatch | ||||
|   | ||||
| @@ -1,54 +1,54 @@ | ||||
| if not config.biblia_api_key then | ||||
| 	print('Missing config value: biblia_api_key.') | ||||
| 	print('bible.lua will not be enabled.') | ||||
| 	return | ||||
| local bible = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local URL = require('socket.url') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function bible:init() | ||||
| 	if not self.config.biblia_api_key then | ||||
| 		print('Missing config value: biblia_api_key.') | ||||
| 		print('bible.lua will not be enabled.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	bible.triggers = utilities.triggers(self.info.username):t('bible', true):t('b', true).table | ||||
| end | ||||
|  | ||||
| local command = 'bible <reference>' | ||||
| local doc = [[``` | ||||
| bible.command = 'bible <reference>' | ||||
| bible.doc = [[``` | ||||
| /bible <reference> | ||||
| Returns a verse from the American Standard Version of the Bible, or an apocryphal verse from the King James Version. Results from biblia.com. | ||||
| Alias: /b | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/bible*[@'..bot.username..']*', | ||||
| 	'^/b[@'..bot.username..']* ', | ||||
| 	'^/b[@'..bot.username..']*$' | ||||
| } | ||||
| function bible:action(msg) | ||||
|  | ||||
| local action = function(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, bible.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local url = 'http://api.biblia.com/v1/bible/content/ASV.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input) | ||||
| 	local url = 'http://api.biblia.com/v1/bible/content/ASV.txt?key=' .. self.config.biblia_api_key .. '&passage=' .. URL.escape(input) | ||||
|  | ||||
| 	local output, res = HTTP.request(url) | ||||
|  | ||||
| 	if not output or res ~= 200 or output:len() == 0 then | ||||
| 		url = 'http://api.biblia.com/v1/bible/content/KJVAPOC.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input) | ||||
| 		url = 'http://api.biblia.com/v1/bible/content/KJVAPOC.txt?key=' .. self.config.biblia_api_key .. '&passage=' .. URL.escape(input) | ||||
| 		output, res = HTTP.request(url) | ||||
| 	end | ||||
|  | ||||
| 	if not output or res ~= 200  or output:len() == 0 then | ||||
| 		output = config.errors.results | ||||
| 		output = self.config.errors.results | ||||
| 	end | ||||
|  | ||||
| 	if output:len() > 4000 then | ||||
| 		output = 'The text is too long to post here. Try being more specific.' | ||||
| 	end | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, msg.message_id, true) | ||||
| 	bindings.sendReply(self, msg, output) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	command = command, | ||||
| 	doc = doc | ||||
| } | ||||
| return bible | ||||
|   | ||||
| @@ -1,24 +1,31 @@ | ||||
|  -- This plugin will allow the admin to blacklist users who will be unable to | ||||
|  -- use the bot. This plugin should be at the top of your plugin list in config. | ||||
|  | ||||
| if not database.blacklist then | ||||
| 	database.blacklist = {} | ||||
| local blacklist = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function blacklist:init() | ||||
| 	if not self.database.blacklist then | ||||
| 		self.database.blacklist = {} | ||||
| 	end | ||||
| end | ||||
|  | ||||
| local triggers = { | ||||
| blacklist.triggers = { | ||||
| 	'' | ||||
| } | ||||
|  | ||||
|  local action = function(msg) | ||||
| function blacklist:action(msg) | ||||
|  | ||||
| 	if database.blacklist[msg.from.id_str] then return end | ||||
| 	if database.blacklist[msg.chat.id_str] then return end | ||||
| 	if self.database.blacklist[msg.from.id_str] then return end | ||||
| 	if self.database.blacklist[msg.chat.id_str] then return end | ||||
| 	if not msg.text:match('^/blacklist') then return true end | ||||
| 	if msg.from.id ~= config.admin then return end | ||||
| 	if msg.from.id ~= self.config.admin then return end | ||||
|  | ||||
| 	local target = user_from_message(msg) | ||||
| 	local target = utilities.user_from_message(self, msg) | ||||
| 	if target.err then | ||||
| 		sendReply(msg, target.err) | ||||
| 		bindings.sendReply(self, msg, target.err) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -26,17 +33,14 @@ local triggers = { | ||||
| 		target.name = 'Group' | ||||
| 	end | ||||
|  | ||||
| 	if database.blacklist[tostring(target.id)] then | ||||
| 		database.blacklist[tostring(target.id)] = nil | ||||
| 		sendReply(msg, target.name .. ' has been removed from the blacklist.') | ||||
| 	if self.database.blacklist[tostring(target.id)] then | ||||
| 		self.database.blacklist[tostring(target.id)] = nil | ||||
| 		bindings.sendReply(self, msg, target.name .. ' has been removed from the blacklist.') | ||||
| 	else | ||||
| 		database.blacklist[tostring(target.id)] = true | ||||
| 		sendReply(msg, target.name .. ' has been added to the blacklist.') | ||||
| 		self.database.blacklist[tostring(target.id)] = true | ||||
| 		bindings.sendReply(self, msg, target.name .. ' has been added to the blacklist.') | ||||
| 	end | ||||
|  | ||||
|  end | ||||
|  | ||||
|  return { | ||||
| 	action = action, | ||||
| 	triggers = triggers | ||||
| } | ||||
|  return blacklist | ||||
|   | ||||
| @@ -1,21 +1,28 @@ | ||||
| local command = 'calc <expression>' | ||||
| local doc = [[``` | ||||
| local calc = {} | ||||
|  | ||||
| local URL = require('socket.url') | ||||
| local HTTPS = require('ssl.https') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| calc.command = 'calc <expression>' | ||||
| calc.doc = [[``` | ||||
| /calc <expression> | ||||
| Returns solutions to mathematical expressions and conversions between common units. Results provided by mathjs.org. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/calc[@'..bot.username..']*' | ||||
| } | ||||
| function calc:init() | ||||
| 	calc.triggers = utilities.triggers(self.info.username):t('calc', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function calc:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, calc.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| @@ -24,19 +31,14 @@ local action = function(msg) | ||||
|  | ||||
| 	local output = HTTPS.request(url) | ||||
| 	if not output then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	output = '`' .. output .. '`' | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, msg.message_id, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	command = command, | ||||
| 	doc = doc | ||||
| } | ||||
| return calc | ||||
|   | ||||
| @@ -1,38 +1,39 @@ | ||||
| if not config.thecatapi_key then | ||||
| 	print('Missing config value: thecatapi_key.') | ||||
| 	print('cats.lua will be enabled, but there are more features with a key.') | ||||
| local cats = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function cats:init() | ||||
| 	if not self.config.thecatapi_key then | ||||
| 		print('Missing config value: thecatapi_key.') | ||||
| 		print('cats.lua will be enabled, but there are more features with a key.') | ||||
| 	end | ||||
|  | ||||
| 	cats.triggers = utilities.triggers(self.info.username):t('cat').table | ||||
| end | ||||
|  | ||||
| local command = 'cat' | ||||
| local doc = '`Returns a cat!`' | ||||
| cats.command = 'cat' | ||||
| cats.doc = '`Returns a cat!`' | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/cat[@'..bot.username..']*$' | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
| function cats:action(msg) | ||||
|  | ||||
| 	local url = 'http://thecatapi.com/api/images/get?format=html&type=jpg' | ||||
| 	if config.thecatapi_key then | ||||
| 		url = url .. '&api_key=' .. config.thecatapi_key | ||||
| 	if self.config.thecatapi_key then | ||||
| 		url = url .. '&api_key=' .. self.config.thecatapi_key | ||||
| 	end | ||||
|  | ||||
| 	local str, res = HTTP.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	str = str:match('<img src="(.-)">') | ||||
| 	local output = '[Cat!]('..str..')' | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, false, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, false, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return cats | ||||
|   | ||||
| @@ -1,24 +1,33 @@ | ||||
|  -- Put this absolutely at the end, even after greetings.lua. | ||||
|  | ||||
| if not config.simsimi_key then | ||||
| 	print('Missing config value: simsimi_key.') | ||||
| 	print('chatter.lua will not be enabled.') | ||||
| 	return | ||||
| local chatter = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
|  | ||||
| function chatter:init() | ||||
| 	if not self.config.simsimi_key then | ||||
| 		print('Missing config value: simsimi_key.') | ||||
| 		print('chatter.lua will not be enabled.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	chatter.triggers = { | ||||
| 		'', | ||||
| 		'^' .. self.info.first_name .. ',', | ||||
| 		'^@' .. self.info.username .. ',' | ||||
| 	} | ||||
| end | ||||
|  | ||||
| local triggers = { | ||||
| 	'', | ||||
| 	'^' .. bot.first_name .. ',', | ||||
| 	'^@' .. bot.username .. ',' | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
| function chatter:action(msg) | ||||
|  | ||||
| 	if msg.text == '' then return end | ||||
|  | ||||
| 	-- This is awkward, but if you have a better way, please share. | ||||
| 	if msg.text_lower:match('^' .. bot.first_name .. ',') then | ||||
| 	elseif msg.text_lower:match('^@' .. bot.username .. ',') then | ||||
| 	if msg.text_lower:match('^' .. self.info.first_name .. ',') | ||||
| 	or msg.text_lower:match('^@' .. self.info.username .. ',') then | ||||
| 	elseif msg.text:match('^/') then | ||||
| 		return true | ||||
| 	-- Uncomment the following line for Al Gore-like reply chatter. | ||||
| @@ -28,40 +37,41 @@ local action = function(msg) | ||||
| 		return true | ||||
| 	end | ||||
|  | ||||
| 	sendChatAction(msg.chat.id, 'typing') | ||||
| 	bindings.sendChatAction(self, msg.chat.id, 'typing') | ||||
|  | ||||
| 	local input = msg.text_lower | ||||
| 	input = input:gsub(bot.first_name, 'simsimi') | ||||
| 	input = input:gsub('@'..bot.username, 'simsimi') | ||||
| 	input = input:gsub(self.info.first_name, 'simsimi') | ||||
| 	input = input:gsub('@'..self.info.username, 'simsimi') | ||||
|  | ||||
| 	if config.simsimi_trial then | ||||
| 	local sandbox | ||||
| 	if self.config.simsimi_trial then | ||||
| 		sandbox = 'sandbox.' | ||||
| 	else | ||||
| 		sandbox = '' -- NO Sandbox | ||||
| 	end | ||||
|  | ||||
| 	local url = 'http://' ..sandbox.. 'api.simsimi.com/request.p?key=' ..config.simsimi_key.. '&lc=' ..config.lang.. '&ft=1.0&text=' .. URL.escape(input) | ||||
| 	local url = 'http://' ..sandbox.. 'api.simsimi.com/request.p?key=' ..self.config.simsimi_key.. '&lc=' ..self.config.lang.. '&ft=1.0&text=' .. URL.escape(input) | ||||
|  | ||||
| 	local jstr, res = HTTP.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendMessage(msg.chat.id, config.errors.chatter_connection) | ||||
| 		bindings.sendMessage(self, msg.chat.id, self.config.errors.chatter_connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if not jdat.response then | ||||
| 		sendMessage(msg.chat.id, config.errors.chatter_response) | ||||
| 		bindings.sendMessage(self, msg.chat.id, self.config.errors.chatter_response) | ||||
| 		return | ||||
| 	end | ||||
| 	local output = jdat.response | ||||
|  | ||||
| 	if output:match('^I HAVE NO RESPONSE.') then | ||||
| 		output = config.errors.chatter_response | ||||
| 		output = self.config.errors.chatter_response | ||||
| 	end | ||||
|  | ||||
| 	-- Let's clean up the response a little. Capitalization & punctuation. | ||||
| 	local filter = { | ||||
| 		['%aimi?%aimi?'] = bot.first_name, | ||||
| 		['%aimi?%aimi?'] = self.info.first_name, | ||||
| 		['^%s*(.-)%s*$'] = '%1', | ||||
| 		['^%l'] = string.upper, | ||||
| 		['USER'] = msg.from.first_name | ||||
| @@ -75,11 +85,8 @@ local action = function(msg) | ||||
| 		output = output .. '.' | ||||
| 	end | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers | ||||
| } | ||||
| return chatter | ||||
|   | ||||
| @@ -1,11 +1,16 @@ | ||||
|  -- Commits from https://github.com/ngerakines/commitment. | ||||
|  | ||||
| local command = 'commit' | ||||
| local doc = '`Returns a commit message from whatthecommit.com.`' | ||||
| local commit = {} | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/commit[@'..bot.username..']*' | ||||
| } | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| commit.command = 'commit' | ||||
| commit.doc = '`Returns a commit message from whatthecommit.com.`' | ||||
|  | ||||
| function commit:init() | ||||
| 	commit.triggers = utilities.triggers(self.info.username):t('commit').table | ||||
| end | ||||
|  | ||||
| local commits = { | ||||
| 	"One does not simply merge into master", | ||||
| @@ -416,16 +421,11 @@ local commits = { | ||||
| 	"fml" | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
| function commit:action(msg) | ||||
|  | ||||
| 	local output = '`'..commits[math.random(#commits)]..'`' | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return commit | ||||
|   | ||||
| @@ -1,28 +1,38 @@ | ||||
| local triggers = { | ||||
| 	'^/reload[@'..bot.username..']*', | ||||
| 	'^/halt[@'..bot.username..']*' | ||||
| } | ||||
| local control = {} | ||||
|  | ||||
| local action = function(msg) | ||||
| local bot = require('bot') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| 	if msg.from.id ~= config.admin then | ||||
| function control:init() | ||||
| 	control.triggers = utilities.triggers(self.info.username):t('reload'):t('halt').table | ||||
| end | ||||
|  | ||||
| function control:action(msg) | ||||
|  | ||||
| 	if msg.from.id ~= self.config.admin then | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	if msg.date < os.time() - 1 then return end | ||||
|  | ||||
| 	if msg.text:match('^/reload') then | ||||
| 		bot_init() | ||||
| 		sendReply(msg, 'Bot reloaded!') | ||||
| 	elseif msg.text:match('^/halt') then | ||||
| 		is_started = false | ||||
| 		sendReply(msg, 'Stopping bot!') | ||||
| 	if msg.text:match('^'..utilities.INVOCATION_PATTERN..'reload') then | ||||
| 		for pac, _ in pairs(package.loaded) do | ||||
| 			if pac:match('^plugins%.') then | ||||
| 				package.loaded[pac] = nil | ||||
| 			end | ||||
| 			package.loaded['bindings'] = nil | ||||
| 			package.loaded['utilities'] = nil | ||||
| 			package.loaded['config'] = nil | ||||
| 		end | ||||
| 		bot.init(self) | ||||
| 		bindings.sendReply(self, msg, 'Bot reloaded!') | ||||
| 	elseif msg.text:match('^'..utilities.INVOCATION_PATTERN..'halt') then | ||||
| 		self.is_started = false | ||||
| 		bindings.sendReply(self, msg, 'Stopping bot!') | ||||
| 	end | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers | ||||
| } | ||||
| return control | ||||
|  | ||||
|   | ||||
| @@ -1,26 +1,32 @@ | ||||
| local command = 'cash [amount] <from> to <to>' | ||||
| local doc = [[``` | ||||
| local currency = {} | ||||
|  | ||||
| local HTTPS = require('ssl.https') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| currency.command = 'cash [amount] <from> to <to>' | ||||
| currency.doc = [[``` | ||||
| /cash [amount] <from> to <to> | ||||
| Example: /cash 5 USD to EUR | ||||
| Returns exchange rates for various currencies. | ||||
| Source: Google Finance. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/cash[@'..bot.username..']*' | ||||
| } | ||||
| function currency:init() | ||||
| 	currency.triggers = utilities.triggers(self.info.username):t('cash', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function currency:action(msg) | ||||
|  | ||||
| 	local input = msg.text:upper() | ||||
| 	if not input:match('%a%a%a TO %a%a%a') then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, currency.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local from = input:match('(%a%a%a) TO') | ||||
| 	local to = input:match('TO (%a%a%a)') | ||||
| 	local amount = get_word(input, 2) | ||||
| 	local amount = utilities.get_word(input, 2) | ||||
| 	amount = tonumber(amount) or 1 | ||||
| 	local result = 1 | ||||
|  | ||||
| @@ -28,16 +34,16 @@ local action = function(msg) | ||||
|  | ||||
| 	if from ~= to then | ||||
|  | ||||
| 		local url = url .. '?from=' .. from .. '&to=' .. to .. '&a=' .. amount | ||||
| 		url = url .. '?from=' .. from .. '&to=' .. to .. '&a=' .. amount | ||||
| 		local str, res = HTTPS.request(url) | ||||
| 		if res ~= 200 then | ||||
| 			sendReply(msg, config.errors.connection) | ||||
| 			bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 			return | ||||
| 		end | ||||
|  | ||||
| 		str = str:match('<span class=bld>(.*) %u+</span>') | ||||
| 		if not str then | ||||
| 			sendReply(msg, config.errors.results) | ||||
| 			bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 			return | ||||
| 		end | ||||
|  | ||||
| @@ -45,17 +51,12 @@ local action = function(msg) | ||||
|  | ||||
| 	end | ||||
|  | ||||
| 	local output = amount .. ' ' .. from .. ' = ' .. result .. ' ' .. to .. '\n' | ||||
| 	output = output .. os.date('!%F %T UTC') .. '\nSource: Google Finance' | ||||
| 	local output = amount .. ' ' .. from .. ' = ' .. result .. ' ' .. to .. '\n\n' | ||||
| 	output = output .. os.date('!%F %T UTC') .. '\nSource: Google Finance`' | ||||
| 	output = '```\n' .. output .. '\n```' | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return currency | ||||
|   | ||||
| @@ -1,18 +1,23 @@ | ||||
| local command = 'roll <nDr>' | ||||
| local doc = [[``` | ||||
| local dice = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| dice.command = 'roll <nDr>' | ||||
| dice.doc = [[``` | ||||
| /roll <nDr> | ||||
| Returns a set of dice rolls, where n is the number of rolls and r is the range. If only a range is given, returns only one roll. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/roll[@'..bot.username..']*' | ||||
| } | ||||
| function dice:init() | ||||
| 	dice.triggers = utilities.triggers(self.info.username):t('roll', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function dice:action(msg) | ||||
|  | ||||
| 	local input = msg.text_lower:input() | ||||
| 	local input = utilities.input(msg.text_lower) | ||||
| 	if not input then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, dice.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -23,7 +28,7 @@ local action = function(msg) | ||||
| 		count = 1 | ||||
| 		range = input:match('^d?([%d]+)$') | ||||
| 	else | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, dice.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -31,27 +36,22 @@ local action = function(msg) | ||||
| 	range = tonumber(range) | ||||
|  | ||||
| 	if range < 2 then | ||||
| 		sendReply(msg, 'The minimum range is 2.') | ||||
| 		bindings.sendReply(self, msg, 'The minimum range is 2.') | ||||
| 		return | ||||
| 	end | ||||
| 	if range > 1000 or count > 1000 then | ||||
| 		sendReply(msg, 'The maximum range and count are 1000.') | ||||
| 		bindings.sendReply(self, msg, 'The maximum range and count are 1000.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local output = '*' .. count .. 'd' .. range .. '*\n`' | ||||
| 	for i = 1, count do | ||||
| 	for _ = 1, count do | ||||
| 		output = output .. math.random(range) .. '\t' | ||||
| 	end | ||||
| 	output = output .. '`' | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, msg.message_id, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return dice | ||||
|   | ||||
| @@ -1,46 +1,51 @@ | ||||
| dilbert = dilbert or {} | ||||
| local dilbert = {} | ||||
|  | ||||
| local command = 'dilbert [date]' | ||||
| local doc = [[``` | ||||
| local HTTP = require('socket.http') | ||||
| local URL = require('socket.url') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| dilbert.command = 'dilbert [date]' | ||||
| dilbert.doc = [[``` | ||||
| /dilbert [YYYY-MM-DD] | ||||
| Returns the latest Dilbert strip or that of the provided date. | ||||
| Dates before the first strip will return the first strip. Dates after the last trip will return the last strip. | ||||
| Source: dilbert.com | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/dilbert[@'..bot.username..']*' | ||||
| } | ||||
| function dilbert:init() | ||||
| 	dilbert.triggers = utilities.triggers(self.info.username):t('dilbert', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function dilbert:action(msg) | ||||
|  | ||||
| 	sendChatAction(msg.chat.id, 'upload_photo') | ||||
| 	bindings.sendChatAction(self, msg.chat.id, 'upload_photo') | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then input = os.date('%F') end | ||||
| 	if not input:match('^%d%d%d%d%-%d%d%-%d%d$') then input = os.date('%F') end | ||||
|  | ||||
| 	local url = 'http://dilbert.com/strip/' .. URL.escape(input) | ||||
| 	local str, res = HTTP.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	if not dilbert[input] then | ||||
| 	local strip_filename = '/tmp/' .. input .. '.gif' | ||||
| 	local strip_file = io.open(strip_filename) | ||||
| 	if strip_file then | ||||
| 		strip_file:close() | ||||
| 		strip_file = strip_filename | ||||
| 	else | ||||
| 		local strip_url = str:match('<meta property="og:image" content="(.-)"/>') | ||||
| 		dilbert[input] = download_file(strip_url, '/tmp/' .. input .. '.gif') | ||||
| 		strip_file = utilities.download_file(strip_url, '/tmp/' .. input .. '.gif') | ||||
| 	end | ||||
|  | ||||
| 	local strip_title = str:match('<meta property="article:publish_date" content="(.-)"/>') | ||||
|  | ||||
| 	sendPhoto(msg.chat.id, dilbert[input], strip_title) | ||||
| 	bindings.sendPhoto(self, msg.chat.id, strip_file, strip_title) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	command = command, | ||||
| 	doc = doc, | ||||
| 	triggers = triggers, | ||||
| 	action = action | ||||
| } | ||||
| return dilbert | ||||
|   | ||||
| @@ -1,36 +1,35 @@ | ||||
| local command = 'echo <text>' | ||||
| local doc = [[``` | ||||
| local echo = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| echo.command = 'echo <text>' | ||||
| echo.doc = [[``` | ||||
| /echo <text> | ||||
| Repeats a string of text. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/echo[@'..bot.username..']*' | ||||
| } | ||||
| function echo:init() | ||||
| 	echo.triggers = utilities.triggers(self.info.username):t('echo', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function echo:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
|  | ||||
| 	if not input then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, echo.doc, true, msg.message_id, true) | ||||
| 	else | ||||
| 		input = markdown_escape(input) | ||||
| 		local output | ||||
| 		if msg.chat.type == 'supergroup' then | ||||
| 			output = '*Echo:*\n"' .. input .. '"' | ||||
| 			output = '*Echo:*\n"' .. utilities.md_escape(input) .. '"' | ||||
| 		else | ||||
| 			output = latcyr(input) | ||||
| 			output = utilities.md_escape(utilities.latcyr(input)) | ||||
| 		end | ||||
| 		sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, output, true) | ||||
| 	end | ||||
|  | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return echo | ||||
|   | ||||
| @@ -1,10 +1,14 @@ | ||||
| local command = '8ball' | ||||
| local doc = '`Returns an answer from a magic 8-ball!`' | ||||
| local eightball = {} | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/8ball', | ||||
| 	'y/n%p?$' | ||||
| } | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| eightball.command = '8ball' | ||||
| eightball.doc = '`Returns an answer from a magic 8-ball!`' | ||||
|  | ||||
| function eightball:init() | ||||
| 	eightball.triggers = utilities.triggers(self.info.username, {'[Yy]/[Nn]%p*$'}):t('8ball', true).table | ||||
| end | ||||
|  | ||||
| local ball_answers = { | ||||
| 	"It is certain.", | ||||
| @@ -37,7 +41,7 @@ local yesno_answers = { | ||||
| 	'No.' | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
| function eightball:action(msg) | ||||
|  | ||||
| 	local output | ||||
|  | ||||
| @@ -47,13 +51,8 @@ local action = function(msg) | ||||
| 		output = ball_answers[math.random(#ball_answers)] | ||||
| 	end | ||||
|  | ||||
| 	sendReply(msg, output) | ||||
| 	bindings.sendReply(self, msg, output) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return eightball | ||||
|   | ||||
| @@ -1,22 +1,29 @@ | ||||
|  -- Liberbot-compliant floodcontrol. | ||||
|  -- Put this after moderation.lua or blacklist.lua. | ||||
|  | ||||
| floodcontrol = floodcontrol or {} | ||||
| local floodcontrol = {} | ||||
|  | ||||
| local triggers = { | ||||
| local JSON = require('dkjson') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function floodcontrol:init() | ||||
| 	self.floodcontrol = self.floodcontrol or {} | ||||
| end | ||||
|  | ||||
| floodcontrol.triggers = { | ||||
| 	'' | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
| function floodcontrol:action(msg) | ||||
|  | ||||
| 	if floodcontrol[-msg.chat.id] then | ||||
| 	if self.floodcontrol[-msg.chat.id] then | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local input = msg.text_lower:match('^/floodcontrol[@'..bot.username..']* (.+)') | ||||
| 	local input = msg.text_lower:match('^/floodcontrol (.+)') or msg.text_lower:match('^/floodcontrol@'..self.info.username..' (.+)') | ||||
| 	if not input then return true end | ||||
|  | ||||
| 	if msg.from.id ~= 100547061 and msg.from.id ~= config.admin then | ||||
| 	if msg.from.id ~= 100547061 and msg.from.id ~= self.config.admin then | ||||
| 		return -- Only run for Liberbot or the admin. | ||||
| 	end | ||||
|  | ||||
| @@ -29,25 +36,21 @@ local action = function(msg) | ||||
| 		input.duration = 600 | ||||
| 	end | ||||
|  | ||||
| 	floodcontrol[input.groupid] = os.time() + input.duration | ||||
| 	self.floodcontrol[input.groupid] = os.time() + input.duration | ||||
|  | ||||
| 	local output = input.groupid .. ' silenced for ' .. input.duration .. ' seconds.' | ||||
| 	handle_exception('floodcontrol.lua', output) | ||||
| 	utilities.handle_exception(self, 'floodcontrol.lua', output) | ||||
|  | ||||
| end | ||||
|  | ||||
| local cron = function() | ||||
| function floodcontrol:cron() | ||||
|  | ||||
| 	for k,v in pairs(floodcontrol) do | ||||
| 	for k,v in pairs(self.floodcontrol) do | ||||
| 		if os.time() > v then | ||||
| 			floodcontrol[k] = nil | ||||
| 			self.floodcontrol[k] = nil | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	cron = cron | ||||
| } | ||||
| return floodcontrol | ||||
|   | ||||
| @@ -1,29 +1,31 @@ | ||||
|  -- Requires that the "fortune" program is installed on your computer. | ||||
|  | ||||
| local s = io.popen('fortune'):read('*all') | ||||
| if s:match('not found$') then | ||||
| 	print('fortune is not installed on this computer.') | ||||
| 	print('fortune.lua will not be enabled.') | ||||
| 	return | ||||
| local fortune = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function fortune:init() | ||||
| 	local s = io.popen('fortune'):read('*all') | ||||
| 	if s:match('not found$') then | ||||
| 		print('fortune is not installed on this computer.') | ||||
| 		print('fortune.lua will not be enabled.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	fortune.triggers = utilities.triggers(self.info.username):t('fortune').table | ||||
| end | ||||
|  | ||||
| local command = 'fortune' | ||||
| local doc = '`Returns a UNIX fortune.`' | ||||
| fortune.command = 'fortune' | ||||
| fortune.doc = '`Returns a UNIX fortune.`' | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/fortune[@'..bot.username..']*' | ||||
| } | ||||
| function fortune:action(msg) | ||||
|  | ||||
| local action = function(msg) | ||||
|  | ||||
| 	local output = io.popen('fortune'):read('*all') | ||||
| 	sendMessage(msg.chat.id, output) | ||||
| 	local fortunef = io.popen('fortune') | ||||
| 	local output = fortunef:read('*all') | ||||
| 	bindings.sendMessage(self, msg.chat.id, output) | ||||
| 	fortunef:close() | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return fortune | ||||
|   | ||||
| @@ -1,43 +1,48 @@ | ||||
|  -- You need a Google API key and a Google Custom Search Engine set up to use this, in config.google_api_key and config.google_cse_key, respectively. | ||||
|  -- You must also sign up for the CSE in the Google Developer Concsole, and enable image results. | ||||
|  -- You must also sign up for the CSE in the Google Developer Console, and enable image results. | ||||
|  | ||||
| if not config.google_api_key then | ||||
| 	print('Missing config value: google_api_key.') | ||||
| 	print('gImages.lua will not be enabled.') | ||||
| 	return | ||||
| elseif not config.google_cse_key then | ||||
| 	print('Missing config value: google_cse_key.') | ||||
| 	print('gImages.lua will not be enabled.') | ||||
| 	return | ||||
| local gImages = {} | ||||
|  | ||||
| local HTTPS = require('ssl.https') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function gImages:init() | ||||
| 	if not self.config.google_api_key then | ||||
| 		print('Missing config value: google_api_key.') | ||||
| 		print('gImages.lua will not be enabled.') | ||||
| 		return | ||||
| 	elseif not self.config.google_cse_key then | ||||
| 		print('Missing config value: google_cse_key.') | ||||
| 		print('gImages.lua will not be enabled.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	gImages.triggers = utilities.triggers(self.info.username):t('image', true):t('i', true):t('insfw', true).table | ||||
| end | ||||
|  | ||||
| local command = 'image <query>' | ||||
| local doc = [[``` | ||||
| gImages.command = 'image <query>' | ||||
| gImages.doc = [[``` | ||||
| /image <query> | ||||
| Returns a randomized top result from Google Images. Safe search is enabled by default; use "/insfw" to disable it. NSFW results will not display an image preview. | ||||
| Alias: /i | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/image[@'..bot.username..']*', | ||||
| 	'^/i[@'..bot.username..']* ', | ||||
| 	'^/i[@'..bot.username..']*$', | ||||
| 	'^/insfw[@'..bot.username..']*' | ||||
| } | ||||
| function gImages:action(msg) | ||||
|  | ||||
| local action = function(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, gImages.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	local url = 'https://www.googleapis.com/customsearch/v1?&searchType=image&imgSize=xlarge&alt=json&num=8&start=1&key=' .. config.google_api_key .. '&cx=' .. config.google_cse_key | ||||
| 	local url = 'https://www.googleapis.com/customsearch/v1?&searchType=image&imgSize=xlarge&alt=json&num=8&start=1&key=' .. self.config.google_api_key .. '&cx=' .. self.config.google_cse_key | ||||
|  | ||||
| 	if not string.match(msg.text, '^/i[mage]*nsfw') then | ||||
| 		url = url .. '&safe=high' | ||||
| @@ -47,13 +52,13 @@ local action = function(msg) | ||||
|  | ||||
| 	local jstr, res = HTTPS.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if jdat.searchInformation.totalResults == '0' then | ||||
| 		sendReply(msg, config.errors.results) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -64,17 +69,11 @@ local action = function(msg) | ||||
|  | ||||
|  | ||||
| 	if msg.text:match('nsfw') then | ||||
| 		output = '*NSFW*\n' .. output | ||||
| 		sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 		bindings.sendReply(self, '*NSFW*\n'..msg, output) | ||||
| 	else | ||||
| 		sendMessage(msg.chat.id, output, false, nil, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, output, false, nil, true) | ||||
| 	end | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return gImages | ||||
|   | ||||
| @@ -1,41 +1,39 @@ | ||||
| local command = 'location <query>' | ||||
| local doc = [[``` | ||||
| local gMaps = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| gMaps.command = 'location <query>' | ||||
| gMaps.doc = [[``` | ||||
| /location <query> | ||||
| Returns a location from Google Maps. | ||||
| Alias: /loc | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/location[@'..bot.username..']*', | ||||
| 	'^/loc[@'..bot.username..']* ', | ||||
| 	'^/loc[@'..bot.username..']*$' | ||||
| } | ||||
| function gMaps:init() | ||||
| 	gMaps.triggers = utilities.triggers(self.info.username):t('location', true):t('loc', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function gMaps:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, gMaps.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	local coords = get_coords(input) | ||||
| 	local coords = utilities.get_coords(self, input) | ||||
| 	if type(coords) == 'string' then | ||||
| 		sendReply(msg, coords) | ||||
| 		bindings.sendReply(self, msg, coords) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	sendLocation(msg.chat.id, coords.lat, coords.lon, msg.message_id) | ||||
| 	bindings.sendLocation(self, msg.chat.id, coords.lat, coords.lon, msg.message_id) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return gMaps | ||||
|   | ||||
| @@ -1,25 +1,30 @@ | ||||
| local command = 'google <query>' | ||||
| local doc = [[``` | ||||
| local gSearch = {} | ||||
|  | ||||
| local HTTPS = require('ssl.https') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| gSearch.command = 'google <query>' | ||||
| gSearch.doc = [[``` | ||||
| /google <query> | ||||
| Returns four (if group) or eight (if private message) results from Google. Safe search is enabled by default, use "/gnsfw" to disable it. | ||||
| Alias: /g | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/g[@'..bot.username..']*$', | ||||
| 	'^/g[@'..bot.username..']* ', | ||||
| 	'^/google[@'..bot.username..']*', | ||||
| 	'^/gnsfw[@'..bot.username..']*' | ||||
| } | ||||
| function gSearch:init() | ||||
| 	gSearch.triggers = utilities.triggers(self.info.username):t('g', true):t('google', true):t('gnsfw', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function gSearch:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, gSearch.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| @@ -40,22 +45,22 @@ local action = function(msg) | ||||
|  | ||||
| 	local jstr, res = HTTPS.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if not jdat.responseData then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
| 	if not jdat.responseData.results[1] then | ||||
| 		sendReply(msg, config.errors.results) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local output = '*Google results for* _' .. input .. '_ *:*\n' | ||||
| 	for i,v in ipairs(jdat.responseData.results) do | ||||
| 	for i,_ in ipairs(jdat.responseData.results) do | ||||
| 		local title = jdat.responseData.results[i].titleNoFormatting:gsub('%[.+%]', ''):gsub('&', '&') | ||||
| --[[ | ||||
| 		if title:len() > 48 then | ||||
| @@ -70,13 +75,8 @@ local action = function(msg) | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return gSearch | ||||
|   | ||||
| @@ -2,47 +2,54 @@ | ||||
|  -- If you want to configure your own greetings, copy the following table | ||||
|  -- (without the "config.") to your config.lua file. | ||||
|  | ||||
| if not config.greetings then | ||||
| 	config.greetings = { | ||||
| 		['Hello, #NAME.'] = { | ||||
| 			'hello', | ||||
| 			'hey', | ||||
| 			'sup', | ||||
| 			'hi', | ||||
| 			'good morning', | ||||
| 			'good day', | ||||
| 			'good afternoon', | ||||
| 			'good evening' | ||||
| 		}, | ||||
| 		['Goodbye, #NAME.'] = { | ||||
| 			'bye', | ||||
| 			'later', | ||||
| 			'see ya', | ||||
| 			'good night' | ||||
| 		}, | ||||
| 		['Welcome back, #NAME.'] = { | ||||
| 			'i\'m home', | ||||
| 			'i\'m back' | ||||
| 		}, | ||||
| 		['You\'re welcome, #NAME.'] = { | ||||
| 			'thanks', | ||||
| 			'thank you' | ||||
| local greetings = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function greetings:init() | ||||
| 	if not self.config.greetings then | ||||
| 		self.config.greetings = { | ||||
| 			['Hello, #NAME.'] = { | ||||
| 				'hello', | ||||
| 				'hey', | ||||
| 				'sup', | ||||
| 				'hi', | ||||
| 				'good morning', | ||||
| 				'good day', | ||||
| 				'good afternoon', | ||||
| 				'good evening' | ||||
| 			}, | ||||
| 			['Goodbye, #NAME.'] = { | ||||
| 				'bye', | ||||
| 				'later', | ||||
| 				'see ya', | ||||
| 				'good night' | ||||
| 			}, | ||||
| 			['Welcome back, #NAME.'] = { | ||||
| 				'i\'m home', | ||||
| 				'i\'m back' | ||||
| 			}, | ||||
| 			['You\'re welcome, #NAME.'] = { | ||||
| 				'thanks', | ||||
| 				'thank you' | ||||
| 			} | ||||
| 		} | ||||
| 	end | ||||
|  | ||||
| 	greetings.triggers = { | ||||
| 		self.info.first_name:lower() .. '%p*$' | ||||
| 	} | ||||
| end | ||||
|  | ||||
| local triggers = { | ||||
| 	bot.first_name .. '%p*$' | ||||
| } | ||||
| function greetings:action(msg) | ||||
|  | ||||
| local action = function(msg) | ||||
| 	local nick = self.database.users[msg.from.id_str].nickname or msg.from.first_name | ||||
|  | ||||
| 	local nick = database.users[msg.from.id_str].nickname or msg.from.first_name | ||||
|  | ||||
| 	for k,v in pairs(config.greetings) do | ||||
| 		for key,val in pairs(v) do | ||||
| 			if msg.text_lower:match(val..',? '..bot.first_name) then | ||||
| 				sendMessage(msg.chat.id, latcyr(k:gsub('#NAME', nick))) | ||||
| 	for trigger,responses in pairs(self.config.greetings) do | ||||
| 		for _,response in pairs(responses) do | ||||
| 			if msg.text_lower:match(response..',? '..self.info.first_name:lower()) then | ||||
| 				bindings.sendMessage(self, msg.chat.id, utilities.latcyr(trigger:gsub('#NAME', nick))) | ||||
| 				return | ||||
| 			end | ||||
| 		end | ||||
| @@ -52,7 +59,4 @@ local action = function(msg) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers | ||||
| } | ||||
| return greetings | ||||
|   | ||||
| @@ -1,21 +1,27 @@ | ||||
| local command = 'hackernews' | ||||
| local doc = [[``` | ||||
| local hackernews = {} | ||||
|  | ||||
| local HTTPS = require('ssl.https') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| hackernews.command = 'hackernews' | ||||
| hackernews.doc = [[``` | ||||
| Returns four (if group) or eight (if private message) top stories from Hacker News. | ||||
| Alias: /hn | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/hackernews[@'..bot.username..']*', | ||||
| 	'^/hn[@'..bot.username..']*' | ||||
| } | ||||
| function hackernews:init() | ||||
| 	hackernews.triggers = utilities.triggers(self.info.username):t('hackernews', true):t('hn', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function hackernews:action(msg) | ||||
|  | ||||
| 	sendChatAction(msg.chat.id, 'typing') | ||||
| 	bindings.sendChatAction(self, msg.chat.id, 'typing') | ||||
|  | ||||
| 	local jstr, res = HTTPS.request('https://hacker-news.firebaseio.com/v0/topstories.json') | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -31,7 +37,7 @@ local action = function(msg) | ||||
| 		local res_url = 'https://hacker-news.firebaseio.com/v0/item/' .. jdat[i] .. '.json' | ||||
| 		jstr, res = HTTPS.request(res_url) | ||||
| 		if res ~= 200 then | ||||
| 			sendReply(msg, config.errors.connection) | ||||
| 			bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 			return | ||||
| 		end | ||||
| 		local res_jdat = JSON.decode(jstr) | ||||
| @@ -41,7 +47,7 @@ local action = function(msg) | ||||
| 		end | ||||
| 		local url = res_jdat.url | ||||
| 		if not url then | ||||
| 			sendReply(msg, config.errors.connection) | ||||
| 			bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 			return | ||||
| 		end | ||||
| 		if url:find('%(') then | ||||
| @@ -52,13 +58,8 @@ local action = function(msg) | ||||
|  | ||||
| 	end | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return hackernews | ||||
|   | ||||
| @@ -1,48 +1,53 @@ | ||||
|  -- Plugin for the Hearthstone database provided by hearthstonejson.com. | ||||
|  | ||||
| if not database.hearthstone or os.time() > database.hearthstone.expiration then | ||||
| local hearthstone = {} | ||||
|  | ||||
| 	print('Downloading Hearthstone database...') | ||||
| local HTTPS = require('ssl.https') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| 	-- This stuff doesn't play well with lua-sec. Disable it for now; hack in curl. | ||||
| 	--local jstr, res = HTTPS.request('https://api.hearthstonejson.com/v1/latest/enUS/cards.json') | ||||
| 	--if res ~= 200 then | ||||
| 		--print('Error connecting to hearthstonejson.com.') | ||||
| 		--print('hearthstone.lua will not be enabled.') | ||||
| 		--return | ||||
| 	--end | ||||
| 	--local jdat = JSON.decode(jstr) | ||||
| function hearthstone:init() | ||||
| 	if not self.database.hearthstone or os.time() > self.database.hearthstone.expiration then | ||||
|  | ||||
| 	local s = io.popen('curl -s https://api.hearthstonejson.com/v1/latest/enUS/cards.json'):read('*all') | ||||
| 	local d = JSON.decode(s) | ||||
| 		print('Downloading Hearthstone database...') | ||||
|  | ||||
| 		-- This stuff doesn't play well with lua-sec. Disable it for now; hack in curl. | ||||
| 		--local jstr, res = HTTPS.request('https://api.hearthstonejson.com/v1/latest/enUS/cards.json') | ||||
| 		--if res ~= 200 then | ||||
| 		--  print('Error connecting to hearthstonejson.com.') | ||||
| 		--  print('hearthstone.lua will not be enabled.') | ||||
| 		--  return | ||||
| 		--end | ||||
| 		--local jdat = JSON.decode(jstr) | ||||
|  | ||||
| 		local s = io.popen('curl -s https://api.hearthstonejson.com/v1/latest/enUS/cards.json'):read('*all') | ||||
| 		local d = JSON.decode(s) | ||||
|  | ||||
| 		if not d then | ||||
| 			print('Error connecting to hearthstonejson.com.') | ||||
| 			print('hearthstone.lua will not be enabled.') | ||||
| 			return | ||||
| 		end | ||||
|  | ||||
| 		self.database.hearthstone = d | ||||
| 		self.database.hearthstone.expiration = os.time() + 600000 | ||||
|  | ||||
| 		print('Download complete! It will be stored for a week.') | ||||
|  | ||||
| 	if not d then | ||||
| 		print('Error connecting to hearthstonejson.com.') | ||||
| 		print('hearthstone.lua will not be enabled.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	database.hearthstone = d | ||||
| 	database.hearthstone.expiration = os.time() + 600000 | ||||
|  | ||||
| 	print('Download complete! It will be stored for a week.') | ||||
|  | ||||
| 	hearthstone.triggers = utilities.triggers(self.info.username):t('hearthstone', true):t('hs').table | ||||
| end | ||||
|  | ||||
| local command = 'hearthstone <query>' | ||||
| local doc = [[``` | ||||
| hearthstone.command = 'hearthstone <query>' | ||||
| hearthstone.doc = [[``` | ||||
| /hearthstone <query> | ||||
| Returns Hearthstone card info. | ||||
| Alias: /hs | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/hearthstone[@'..bot.username..']*', | ||||
| 	'^/hs[@'..bot.username..']*$', | ||||
| 	'^/hs[@'..bot.username..']* ' | ||||
| } | ||||
|  | ||||
| local format_card = function(card) | ||||
| local function format_card(card) | ||||
|  | ||||
| 	local ctype = card.type | ||||
| 	if card.race then | ||||
| @@ -73,6 +78,7 @@ local format_card = function(card) | ||||
| 		stats = card.health .. 'h' | ||||
| 	end | ||||
|  | ||||
| 	-- unused? | ||||
| 	local info = '' | ||||
| 	if card.text then | ||||
| 		info = card.text:gsub('</?.->',''):gsub('%$','') | ||||
| @@ -97,34 +103,29 @@ local format_card = function(card) | ||||
|  | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function hearthstone:action(msg) | ||||
|  | ||||
| 	local input = msg.text_lower:input() | ||||
| 	local input = utilities.input(msg.text_lower) | ||||
| 	if not input then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, hearthstone.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local output = '' | ||||
| 	for k,v in pairs(database.hearthstone) do | ||||
| 	for _,v in pairs(self.database.hearthstone) do | ||||
| 		if type(v) == 'table' and string.lower(v.name):match(input) then | ||||
| 			output = output .. format_card(v) .. '\n\n' | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	output = output:trim() | ||||
| 	output = utilities.trim(output) | ||||
| 	if output:len() == 0 then | ||||
| 		sendReply(msg, config.errors.results) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, msg.message_id, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return hearthstone | ||||
|   | ||||
| @@ -1,54 +1,62 @@ | ||||
|  -- This plugin should go at the end of your plugin list in | ||||
|  -- config.lua, but not after greetings.lua. | ||||
|  | ||||
| local commandlist = {} | ||||
| for i,v in ipairs(plugins) do | ||||
| 	if v.command then | ||||
| 		table.insert(commandlist, v.command) | ||||
| local help = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| local help_text | ||||
|  | ||||
| function help:init() | ||||
|  | ||||
| 	local commandlist = {} | ||||
| 	help_text = '*Available commands:*\n• /' | ||||
|  | ||||
| 	for _,plugin in ipairs(self.plugins) do | ||||
| 		if plugin.command then | ||||
| 			table.insert(commandlist, plugin.command) | ||||
| 			--help_text = help_text .. '\n• /' .. plugin.command:gsub('%[', '\\[') | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	table.insert(commandlist, 'help [command]') | ||||
| 	table.sort(commandlist) | ||||
|  | ||||
| 	help_text = help_text .. table.concat(commandlist, '\n• /') .. '\nArguments: <required> [optional]' | ||||
|  | ||||
| 	help_text = help_text:gsub('%[', '\\[') | ||||
|  | ||||
| 	help.triggers = utilities.triggers(self.info.username):t('help', true):t('h', true).table | ||||
|  | ||||
| end | ||||
|  | ||||
| table.insert(commandlist, 'help [command]') | ||||
| table.sort(commandlist) | ||||
| function help:action(msg) | ||||
|  | ||||
| local help_text = '*Available commands:*\n• /' .. table.concat(commandlist,'\n• /') .. '\nArguments: <required> [optional]' | ||||
|  | ||||
| help_text = help_text:gsub('%[', '\\[') | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/help[@'..bot.username..']*', | ||||
| 	'^/h[@'..bot.username..']*$' | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
|  | ||||
| 	local input = msg.text_lower:input() | ||||
| 	local input = utilities.input(msg.text_lower) | ||||
|  | ||||
| 	-- Attempts to send the help message via PM. | ||||
| 	-- If msg is from a group, it tells the group whether the PM was successful. | ||||
| 	if not input then | ||||
| 		local res = sendMessage(msg.from.id, help_text, true, nil, true) | ||||
| 		local res = bindings.sendMessage(self, msg.from.id, help_text, true, nil, true) | ||||
| 		if not res then | ||||
| 			sendReply(msg, 'Please message me privately for a list of commands.') | ||||
| 			bindings.sendReply(self, msg, 'Please message me privately for a list of commands.') | ||||
| 		elseif msg.chat.type ~= 'private' then | ||||
| 			sendReply(msg, 'I have sent you the requested information in a private message.') | ||||
| 			bindings.sendReply(self, msg, 'I have sent you the requested information in a private message.') | ||||
| 		end | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	for i,v in ipairs(plugins) do | ||||
| 		if v.command and get_word(v.command, 1) == input and v.doc then | ||||
| 			local output = '*Help for* _' .. get_word(v.command, 1) .. '_ *:*\n' .. v.doc | ||||
| 			sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	for _,plugin in ipairs(self.plugins) do | ||||
| 		if plugin.command and utilities.get_word(plugin.command, 1) == input and plugin.doc then | ||||
| 			local output = '*Help for* _' .. utilities.get_word(plugin.command, 1) .. '_ *:*\n' .. plugin.doc | ||||
| 			bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	sendReply(msg, 'Sorry, there is no help for that command.') | ||||
| 	bindings.sendReply(self, msg, 'Sorry, there is no help for that command.') | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers | ||||
| } | ||||
| return help | ||||
|   | ||||
| @@ -1,21 +1,29 @@ | ||||
| local command = 'imdb <query>' | ||||
| local doc = [[``` | ||||
| local imdb = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| imdb.command = 'imdb <query>' | ||||
| imdb.doc = [[``` | ||||
| /imdb <query> | ||||
| Returns an IMDb entry. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/imdb[@'..bot.username..']*' | ||||
| } | ||||
| function imdb:init() | ||||
| 	imdb.triggers = utilities.triggers(self.info.username):t('imdb', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function imdb:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, imdb.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| @@ -24,14 +32,14 @@ local action = function(msg) | ||||
|  | ||||
| 	local jstr, res = HTTP.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
|  | ||||
| 	if jdat.Response ~= 'True' then | ||||
| 		sendReply(msg, config.errors.results) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -40,13 +48,8 @@ local action = function(msg) | ||||
| 	output = output .. '_' .. jdat.Plot .. '_\n' | ||||
| 	output = output .. '[Read more.](http://imdb.com/title/' .. jdat.imdbID .. ')' | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return imdb | ||||
|   | ||||
| @@ -1,14 +1,23 @@ | ||||
| if not config.lastfm_api_key then | ||||
| 	print('Missing config value: lastfm_api_key.') | ||||
| 	print('lastfm.lua will not be enabled.') | ||||
| 	return | ||||
| end | ||||
| local lastfm = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| HTTP.TIMEOUT = 1 | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| local command = 'lastfm' | ||||
| local doc = [[``` | ||||
| function lastfm:init() | ||||
| 	if not self.config.lastfm_api_key then | ||||
| 		print('Missing config value: lastfm_api_key.') | ||||
| 		print('lastfm.lua will not be enabled.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	lastfm.triggers = utilities.triggers(self.info.username):t('lastfm', true):t('np', true):t('fmset', true).table | ||||
| end | ||||
|  | ||||
| bindings.command = 'lastfm' | ||||
| bindings.doc = [[``` | ||||
| /np [username] | ||||
| Returns what you are or were last listening to. If you specify a username, info will be returned for that username. | ||||
|  | ||||
| @@ -16,66 +25,64 @@ Returns what you are or were last listening to. If you specify a username, info | ||||
| Sets your last.fm username. Otherwise, /np will use your Telegram username. Use "/fmset --" to delete it. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/lastfm[@'..bot.username..']*', | ||||
| 	'^/np[@'..bot.username..']*', | ||||
| 	'^/fmset[@'..bot.username..']*' | ||||
| } | ||||
| function lastfm:action(msg) | ||||
|  | ||||
| local action = function(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
|  | ||||
| 	if string.match(msg.text, '^/lastfm') then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, lastfm.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	elseif string.match(msg.text, '^/fmset') then | ||||
| 		if not input then | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, lastfm.doc, true, msg.message_id, true) | ||||
| 		elseif input == '--' or input == '—' then | ||||
| 			database.users[msg.from.id_str].lastfm = nil | ||||
| 			sendReply(msg, 'Your last.fm username has been forgotten.') | ||||
| 			self.database.users[msg.from.id_str].lastfm = nil | ||||
| 			bindings.sendReply(self, msg, 'Your last.fm username has been forgotten.') | ||||
| 		else | ||||
| 			database.users[msg.from.id_str].lastfm = input | ||||
| 			sendReply(msg, 'Your last.fm username has been set to "' .. input .. '".') | ||||
| 			self.database.users[msg.from.id_str].lastfm = input | ||||
| 			bindings.sendReply(self, msg, 'Your last.fm username has been set to "' .. input .. '".') | ||||
| 		end | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key=' .. config.lastfm_api_key .. '&user=' | ||||
| 	local url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&api_key=' .. self.config.lastfm_api_key .. '&user=' | ||||
|  | ||||
| 	local username | ||||
| 	local alert = '' | ||||
| 	if input then | ||||
| 		username = input | ||||
| 	elseif database.users[msg.from.id_str].lastfm then | ||||
| 		username = database.users[msg.from.id_str].lastfm | ||||
| 	elseif self.database.users[msg.from.id_str].lastfm then | ||||
| 		username = self.database.users[msg.from.id_str].lastfm | ||||
| 	elseif msg.from.username then | ||||
| 		username = msg.from.username | ||||
| 		alert = '\n\nYour username has been set to ' .. username .. '.\nTo change it, use /fmset <username>.' | ||||
| 		database.users[msg.from.id_str].lastfm = username | ||||
| 		self.database.users[msg.from.id_str].lastfm = username | ||||
| 	else | ||||
| 		sendReply(msg, 'Please specify your last.fm username or set it with /fmset.') | ||||
| 		bindings.sendReply(self, msg, 'Please specify your last.fm username or set it with /fmset.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	url = url .. URL.escape(username) | ||||
|  | ||||
| 	jstr, res = HTTP.request(url) | ||||
| 	local jstr, res | ||||
| 	utilities.with_http_timeout( | ||||
| 		1, function () | ||||
| 			jstr, res = HTTP.request(url) | ||||
| 	end) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if jdat.error then | ||||
| 		sendReply(msg, 'Please specify your last.fm username or set it with /fmset.') | ||||
| 		bindings.sendReply(self, msg, 'Please specify your last.fm username or set it with /fmset.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track | ||||
| 	jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track | ||||
| 	if not jdat then | ||||
| 		sendReply(msg, 'No history for this user.' .. alert) | ||||
| 		bindings.sendReply(self, msg, 'No history for this user.' .. alert) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -95,13 +102,8 @@ local action = function(msg) | ||||
| 	end | ||||
|  | ||||
| 	output = output .. title .. ' - ' .. artist .. alert | ||||
| 	sendMessage(msg.chat.id, output) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return lastfm | ||||
|   | ||||
| @@ -1,9 +1,21 @@ | ||||
| if not database.librefm then | ||||
| 	database.librefm = {} | ||||
| local librefm = {} | ||||
|  | ||||
| local HTTPS = require('ssl.https') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function librefm:init() | ||||
| 	if not self.database.librefm then | ||||
| 		self.database.librefm = {} | ||||
| 	end | ||||
|  | ||||
| 	librefm.triggers = utilities.triggers(self.info.username):t('librefm', true):t('lnp', true):t('lfmset', true) | ||||
| end | ||||
|  | ||||
| local command = 'librefm' | ||||
| local doc = [[``` | ||||
| librefm.command = 'librefm' | ||||
| librefm.doc = [[``` | ||||
| /lnp [username] | ||||
| Returns what you are or were last listening to. If you specify a username, info will be returned for that username. | ||||
|  | ||||
| @@ -11,28 +23,22 @@ Returns what you are or were last listening to. If you specify a username, info | ||||
| Sets your libre.fm username. Otherwise, /np will use your Telegram username. Use "/fmset -" to delete it. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/librefm[@'..bot.username..']*', | ||||
| 	'^/lnp[@'..bot.username..']*', | ||||
| 	'^/lfmset[@'..bot.username..']*' | ||||
| } | ||||
| function librefm:action(msg) | ||||
|  | ||||
| local action = function(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
|  | ||||
| 	if string.match(msg.text, '^/librefm') then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, librefm.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	elseif string.match(msg.text, '^/lfmset') then | ||||
| 		if not input then | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, librefm.doc, true, msg.message_id, true) | ||||
| 		elseif input == '-' then | ||||
| 			database.librefm[msg.from.id_str] = nil | ||||
| 			sendReply(msg, 'Your libre.fm username has been forgotten.') | ||||
| 			self.database.librefm[msg.from.id_str] = nil | ||||
| 			bindings.sendReply(self, msg, 'Your libre.fm username has been forgotten.') | ||||
| 		else | ||||
| 			database.librefm[msg.from.id_str] = input | ||||
| 			sendReply(msg, 'Your libre.fm username has been set to "' .. input .. '".') | ||||
| 			self.database.librefm[msg.from.id_str] = input | ||||
| 			bindings.sendReply(self, msg, 'Your libre.fm username has been set to "' .. input .. '".') | ||||
| 		end | ||||
| 		return | ||||
| 	end | ||||
| @@ -43,34 +49,34 @@ local action = function(msg) | ||||
| 	local alert = '' | ||||
| 	if input then | ||||
| 		username = input | ||||
| 	elseif database.librefm[msg.from.id_str] then | ||||
| 		username = database.librefm[msg.from.id_str] | ||||
| 	elseif self.database.librefm[msg.from.id_str] then | ||||
| 		username = self.database.librefm[msg.from.id_str] | ||||
| 	elseif msg.from.username then | ||||
| 		username = msg.from.username | ||||
| 		alert = '\n\nYour username has been set to ' .. username .. '.\nTo change it, use /lfmset <username>.' | ||||
| 		database.librefm[msg.from.id_str] = username | ||||
| 		self.database.librefm[msg.from.id_str] = username | ||||
| 	else | ||||
| 		sendReply(msg, 'Please specify your libre.fm username or set it with /lfmset.') | ||||
| 		bindings.sendReply(self, msg, 'Please specify your libre.fm username or set it with /lfmset.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	url = url .. URL.escape(username) | ||||
|  | ||||
| 	jstr, res = HTTPS.request(url) | ||||
| 	local jstr, res = HTTPS.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if jdat.error then | ||||
| 		sendReply(msg, 'Please specify your libre.fm username or set it with /lfmset.') | ||||
| 		bindings.sendReply(self, msg, 'Please specify your libre.fm username or set it with /lfmset.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track | ||||
| 	jdat = jdat.recenttracks.track[1] or jdat.recenttracks.track | ||||
| 	if not jdat then | ||||
| 		sendReply(msg, 'No history for this user.' .. alert) | ||||
| 		bindings.sendReply(self, msg, 'No history for this user.' .. alert) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -90,13 +96,8 @@ local action = function(msg) | ||||
| 	end | ||||
|  | ||||
| 	output = output .. title .. ' - ' .. artist .. alert | ||||
| 	sendMessage(msg.chat.id, output) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return librefm | ||||
|   | ||||
| @@ -1,20 +1,25 @@ | ||||
| local triggers = { | ||||
| 	'^/lua[@'..bot.username..']*' | ||||
| } | ||||
| local luarun = {} | ||||
|  | ||||
| local action = function(msg) | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| 	if msg.from.id ~= config.admin then | ||||
| function luarun:init() | ||||
| 	luarun.triggers = utilities.triggers(self.info.username):t('lua', true).table | ||||
| end | ||||
|  | ||||
| function luarun:action(msg) | ||||
|  | ||||
| 	if msg.from.id ~= self.config.admin then | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		sendReply(msg, 'Please enter a string to load.') | ||||
| 		bindings.sendReply(self, msg, 'Please enter a string to load.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local output = loadstring(input)() | ||||
| 	local output = loadstring('local bindings = require(\'bindings\'); local utilities = require(\'utilities\'); return function (self, msg) '..input..' end')()(self, msg) | ||||
| 	if output == nil then | ||||
| 		output = 'Done!' | ||||
| 	elseif type(output) == 'table' then | ||||
| @@ -22,12 +27,9 @@ local action = function(msg) | ||||
| 	else | ||||
| 		output = '```\n' .. tostring(output) .. '\n```' | ||||
| 	end | ||||
| 	sendMessage(msg.chat.id, output, true, msg.message_id, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers | ||||
| } | ||||
| return luarun | ||||
|  | ||||
|   | ||||
| @@ -1,16 +1,20 @@ | ||||
| local triggers = { | ||||
| 	'^/me', | ||||
| 	'^/me@'..bot.username | ||||
| } | ||||
| local me = {} | ||||
|  | ||||
| local action = function(msg) | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| 	local target = database.users[msg.from.id_str] | ||||
| function me:init() | ||||
| 	me.triggers = utilities.triggers(self.info.username):t('me', true).table | ||||
| end | ||||
|  | ||||
| 	if msg.from.id == config.admin and (msg.reply_to_message or msg.text:input()) then | ||||
| 		target = user_from_message(msg) | ||||
| function me:action(msg) | ||||
|  | ||||
| 	local target = self.database.users[msg.from.id_str] | ||||
|  | ||||
| 	if msg.from.id == self.config.admin and (msg.reply_to_message or utilities.input(msg.text)) then | ||||
| 		target = utilities.user_from_message(self, msg) | ||||
| 		if target.err then | ||||
| 			sendReply(msg, target.err) | ||||
| 			bindings.sendReply(self, msg, target.err) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| @@ -19,11 +23,8 @@ local action = function(msg) | ||||
| 	for k,v in pairs(target) do | ||||
| 		output = output .. '*' .. k .. ':* `' .. tostring(v) .. '`\n' | ||||
| 	end | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	triggers = triggers, | ||||
| 	action = action | ||||
| } | ||||
| return me | ||||
|   | ||||
| @@ -1,299 +0,0 @@ | ||||
|  -- Moderation for Liberbot groups. | ||||
|  -- The bot must be made an admin. | ||||
|  -- Put this near the top, after blacklist. | ||||
|  -- If you want to enable antisquig, put that at the top, before blacklist. | ||||
|  | ||||
| if not database.moderation then | ||||
| 	database.moderation = {} | ||||
| end | ||||
|  | ||||
| local antisquig = {} | ||||
|  | ||||
| local commands = { | ||||
|  | ||||
| 	['^/modhelp[@'..bot.username..']*$'] = function(msg) | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str] then return end | ||||
|  | ||||
| 		local output = [[ | ||||
| 			*Users:* | ||||
| 			• /modlist - List the moderators and administrators of this group. | ||||
| 			*Moderators:* | ||||
| 			• /modkick - Kick a user from this group. | ||||
| 			• /modban - Ban a user from this group. | ||||
| 			*Administrators:* | ||||
| 			• /modadd - Add this group to the moderation system. | ||||
| 			• /modrem - Remove this group from the moderation system. | ||||
| 			• /modprom - Promote a user to a moderator. | ||||
| 			• /moddem - Demote a moderator to a user. | ||||
| 			• /modcast - Send a broadcast to every moderated group. | ||||
| 		]] | ||||
| 		output = output:gsub('\t', '') | ||||
|  | ||||
| 		sendMessage(msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| 	end, | ||||
|  | ||||
| 	['^/modlist[@'..bot.username..']*$'] = function(msg) | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str] then return end | ||||
|  | ||||
| 		local output = '' | ||||
|  | ||||
| 		for k,v in pairs(database.moderation[msg.chat.id_str]) do | ||||
| 			output = output .. '• ' .. v .. ' (' .. k .. ')\n' | ||||
| 		end | ||||
|  | ||||
| 		if output ~= '' then | ||||
| 			output = '*Moderators for* _' .. msg.chat.title .. '_ *:*\n' .. output | ||||
| 		end | ||||
|  | ||||
| 		output = output .. '*Administrators for* _' .. config.moderation.realm_name .. '_ *:*\n' | ||||
| 		for k,v in pairs(config.moderation.admins) do | ||||
| 			output = output .. '• ' .. v .. ' (' .. k .. ')\n' | ||||
| 		end | ||||
|  | ||||
| 		sendMessage(msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| 	end, | ||||
|  | ||||
| 	['^/modcast[@'..bot.username..']*'] = function(msg) | ||||
|  | ||||
| 		local output = msg.text:input() | ||||
| 		if not output then | ||||
| 			return 'You must include a message.' | ||||
| 		end | ||||
|  | ||||
| 		if msg.chat.id ~= config.moderation.admin_group then | ||||
| 			return 'This command must be run in the administration group.' | ||||
| 		end | ||||
|  | ||||
| 		if not config.moderation.admins[msg.from.id_str] then | ||||
| 			return config.moderation.errors.not_admin | ||||
| 		end | ||||
|  | ||||
| 		output = '*Admin Broadcast:*\n' .. output | ||||
|  | ||||
| 		for k,v in pairs(database.moderation) do | ||||
| 			sendMessage(k, output, true, nil, true) | ||||
| 		end | ||||
|  | ||||
| 		return 'Your broadcast has been sent.' | ||||
|  | ||||
| 	end, | ||||
|  | ||||
| 	['^/modadd[@'..bot.username..']*$'] = function(msg) | ||||
|  | ||||
| 		if not config.moderation.admins[msg.from.id_str] then | ||||
| 			return config.moderation.errors.not_admin | ||||
| 		end | ||||
|  | ||||
| 		if database.moderation[msg.chat.id_str] then | ||||
| 			return 'I am already moderating this group.' | ||||
| 		end | ||||
|  | ||||
| 		database.moderation[msg.chat.id_str] = {} | ||||
| 		return 'I am now moderating this group.' | ||||
|  | ||||
| 	end, | ||||
|  | ||||
| 	['^/modrem[@'..bot.username..']*$'] = function(msg) | ||||
|  | ||||
| 		if not config.moderation.admins[msg.from.id_str] then | ||||
| 			return config.moderation.errors.not_admin | ||||
| 		end | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str] then | ||||
| 			return config.moderation.errors.moderation | ||||
| 		end | ||||
|  | ||||
| 		database.moderation[msg.chat.id_str] = nil | ||||
| 		return 'I am no longer moderating this group.' | ||||
|  | ||||
| 	end, | ||||
|  | ||||
| 	['^/modprom[@'..bot.username..']*$'] = function(msg) | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str] then return end | ||||
|  | ||||
| 		if not config.moderation.admins[msg.from.id_str] then | ||||
| 			return config.moderation.errors.not_admin | ||||
| 		end | ||||
|  | ||||
| 		if not msg.reply_to_message then | ||||
| 			return 'Promotions must be done via reply.' | ||||
| 		end | ||||
|  | ||||
| 		local modid = tostring(msg.reply_to_message.from.id) | ||||
| 		local modname = msg.reply_to_message.from.first_name | ||||
|  | ||||
| 		if config.moderation.admins[modid] then | ||||
| 			return modname .. ' is already an administrator.' | ||||
| 		end | ||||
|  | ||||
| 		if database.moderation[msg.chat.id_str][modid] then | ||||
| 			return modname .. ' is already a moderator.' | ||||
| 		end | ||||
|  | ||||
| 		database.moderation[msg.chat.id_str][modid] = modname | ||||
|  | ||||
| 		return modname .. ' is now a moderator.' | ||||
|  | ||||
| 	end, | ||||
|  | ||||
| 	['^/moddem[@'..bot.username..']*'] = function(msg) | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str] then return end | ||||
|  | ||||
| 		if not config.moderation.admins[msg.from.id_str] then | ||||
| 			return config.moderation.errors.not_admin | ||||
| 		end | ||||
|  | ||||
| 		local modid = msg.text:input() | ||||
|  | ||||
| 		if not modid then | ||||
| 			if msg.reply_to_message then | ||||
| 				modid = tostring(msg.reply_to_message.from.id) | ||||
| 			else | ||||
| 				return 'Demotions must be done via reply or specification of a moderator\'s ID.' | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		if config.moderation.admins[modid] then | ||||
| 			return config.moderation.admins[modid] .. ' is an administrator.' | ||||
| 		end | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str][modid] then | ||||
| 			return 'User is not a moderator.' | ||||
| 		end | ||||
|  | ||||
| 		local modname = database.moderation[msg.chat.id_str][modid] | ||||
| 		database.moderation[msg.chat.id_str][modid] = nil | ||||
|  | ||||
| 		return modname .. ' is no longer a moderator.' | ||||
|  | ||||
| 	end, | ||||
|  | ||||
| 	['/modkick[@'..bot.username..']*'] = function(msg) | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str] then return end | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str][msg.from.id_str] then | ||||
| 			if not config.moderation.admins[msg.from.id_str] then | ||||
| 				return config.moderation.errors.not_mod | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		local userid = msg.text:input() | ||||
| 		local usernm = userid | ||||
|  | ||||
| 		if msg.reply_to_message then | ||||
| 			userid = tostring(msg.reply_to_message.from.id) | ||||
| 			usernm = msg.reply_to_message.from.first_name | ||||
| 		end | ||||
|  | ||||
| 		if not userid then | ||||
| 			return 'Kicks must be done via reply or specification of a user/bot\'s ID or username.' | ||||
| 		end | ||||
|  | ||||
| 		if database.moderation[msg.chat.id_str][userid] or config.moderation.admins[userid] then | ||||
| 			return 'You cannot kick a moderator.' | ||||
| 		end | ||||
|  | ||||
| 		sendMessage(config.moderation.admin_group, '/kick ' .. userid .. ' from ' .. math.abs(msg.chat.id)) | ||||
|  | ||||
| 		sendMessage(config.moderation.admin_group, usernm .. ' kicked from ' .. msg.chat.title .. ' by ' .. msg.from.first_name .. '.') | ||||
|  | ||||
| 	end, | ||||
|  | ||||
| 	['^/modban[@'..bot.username..']*'] = function(msg) | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str] then return end | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str][msg.from.id_str] then | ||||
| 			if not config.moderation.admins[msg.from.id_str] then | ||||
| 				return config.moderation.errors.not_mod | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		local userid = msg.text:input() | ||||
| 		local usernm = userid | ||||
|  | ||||
| 		if msg.reply_to_message then | ||||
| 			userid = tostring(msg.reply_to_message.from.id) | ||||
| 			usernm = msg.reply_to_message.from.first_name | ||||
| 		end | ||||
|  | ||||
| 		if not userid then | ||||
| 			return 'Kicks must be done via reply or specification of a user/bot\'s ID or username.' | ||||
| 		end | ||||
|  | ||||
| 		if database.moderation[msg.chat.id_str][userid] or config.moderation.admins[userid] then | ||||
| 			return 'You cannot ban a moderator.' | ||||
| 		end | ||||
|  | ||||
| 		sendMessage(config.moderation.admin_group, '/ban ' .. userid .. ' from ' .. math.abs(msg.chat.id)) | ||||
|  | ||||
| 		sendMessage(config.moderation.admin_group, usernm .. ' banned from ' .. msg.chat.title .. ' by ' .. msg.from.first_name .. '.') | ||||
|  | ||||
| 	end | ||||
|  | ||||
| } | ||||
|  | ||||
| if config.moderation.antisquig then | ||||
| 	commands['[\216-\219][\128-\191]'] = function(msg) | ||||
|  | ||||
| 		if not database.moderation[msg.chat.id_str] then return true end | ||||
| 		if config.moderation.admins[msg.from.id_str] then return true end | ||||
| 		if database.moderation[msg.chat.id_str][msg.from.id_str] then return true end | ||||
|  | ||||
| 		if antisquig[msg.from.id] == true then | ||||
| 			return | ||||
| 		end | ||||
| 		antisquig[msg.from.id] = true | ||||
|  | ||||
| 		sendReply(msg, config.moderation.errors.antisquig) | ||||
| 		sendMessage(config.moderation.admin_group, '/kick ' .. msg.from.id .. ' from ' .. math.abs(msg.chat.id)) | ||||
| 		sendMessage(config.moderation.admin_group, 'ANTISQUIG: ' .. msg.from.first_name .. ' kicked from ' .. msg.chat.title .. '.') | ||||
|  | ||||
| 	end | ||||
| end | ||||
|  | ||||
| local triggers = {} | ||||
| for k,v in pairs(commands) do | ||||
| 	table.insert(triggers, k) | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
|  | ||||
| 	for k,v in pairs(commands) do | ||||
| 		if string.match(msg.text_lower, k) then | ||||
| 			local output = v(msg) | ||||
| 			if output == true then | ||||
| 				return true | ||||
| 			elseif output then | ||||
| 				sendReply(msg, output) | ||||
| 			end | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	return true | ||||
|  | ||||
| end | ||||
|  | ||||
|  -- When a user is kicked for squiggles, his ID is added to this table. | ||||
|  -- That user will not be kicked again as long as his ID is in the table. | ||||
|  -- The table is emptied every five seconds. | ||||
|  -- Thus the bot will not spam the group or admin group when a user posts more than one infringing messages. | ||||
| local cron = function() | ||||
|  | ||||
| 	antisquig = {} | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	cron = cron | ||||
| } | ||||
| @@ -1,18 +1,23 @@ | ||||
| local command = 'nick <nickname>' | ||||
| local doc = [[``` | ||||
| local nick = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| nick.command = 'nick <nickname>' | ||||
| nick.doc = [[``` | ||||
| /nick <nickname> | ||||
| Set your nickname. Use "/nick --" to delete it. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/nick[@'..bot.username..']*' | ||||
| } | ||||
| function nick:init() | ||||
| 	nick.triggers = utilities.triggers(self.info.username):t('nick', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function nick:action(msg) | ||||
|  | ||||
| 	local target = msg.from | ||||
|  | ||||
| 	if msg.from.id == config.admin and msg.reply_to_message then | ||||
| 	if msg.from.id == self.config.admin and msg.reply_to_message then | ||||
| 		target = msg.reply_to_message.from | ||||
| 		target.id_str = tostring(target.id) | ||||
| 		target.name = target.first_name | ||||
| @@ -22,30 +27,25 @@ local action = function(msg) | ||||
| 	end | ||||
|  | ||||
| 	local output | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if database.users[target.id_str].nickname then | ||||
| 			output = target.name .. '\'s nickname is "' .. database.users[target.id_str].nickname .. '".' | ||||
| 		if self.database.users[target.id_str].nickname then | ||||
| 			output = target.name .. '\'s nickname is "' .. self.database.users[target.id_str].nickname .. '".' | ||||
| 		else | ||||
| 			output = target.name .. ' currently has no nickname.' | ||||
| 		end | ||||
| 	elseif string.len(input) > 32 then | ||||
| 		output = 'The character limit for nicknames is 32.' | ||||
| 	elseif input == '--' or input == '—' then | ||||
| 		database.users[target.id_str].nickname = nil | ||||
| 		self.database.users[target.id_str].nickname = nil | ||||
| 		output = target.name .. '\'s nickname has been deleted.' | ||||
| 	else | ||||
| 		database.users[target.id_str].nickname = input | ||||
| 		self.database.users[target.id_str].nickname = input | ||||
| 		output = target.name .. '\'s nickname has been set to "' .. input .. '".' | ||||
| 	end | ||||
|  | ||||
| 	sendReply(msg, output) | ||||
| 	bindings.sendReply(self, msg, output) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return nick | ||||
|   | ||||
| @@ -1,11 +1,15 @@ | ||||
|  -- Shout-out to Kenny, as I didn't want to write this until | ||||
|  -- he upset himself over the very thought of me doing so. | ||||
|  | ||||
| local triggers = { | ||||
| local patterns = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
|  | ||||
| patterns.triggers = { | ||||
| 	'^/?s/.-/.-/?$' | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
| function patterns:action(msg) | ||||
|  | ||||
| 	if not msg.reply_to_message then return end | ||||
| 	local output = msg.reply_to_message.text or '' | ||||
| @@ -13,11 +17,8 @@ local action = function(msg) | ||||
| 	if not m2 then return true end | ||||
| 	output = output:gsub(m1, m2) | ||||
| 	output = 'Did you mean:\n"' .. output:sub(1, 4000) .. '"' | ||||
| 	sendReply(msg.reply_to_message, output) | ||||
| 	bindings.sendReply(self, msg.reply_to_message, output) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	triggers = triggers, | ||||
| 	action = action | ||||
| } | ||||
| return patterns | ||||
|   | ||||
| @@ -1,16 +1,17 @@ | ||||
|  -- Actually the simplest plugin ever! | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/ping[@'..bot.username..']*', | ||||
| 	'^/annyong[@'..bot.username..']*' | ||||
| } | ||||
| local ping = {} | ||||
|  | ||||
| local action = function(msg) | ||||
| 	local output = msg.text_lower:match('^/ping') and 'Pong!' or 'Annyong.' | ||||
| 	sendMessage(msg.chat.id, output) | ||||
| local utilities = require('utilities') | ||||
| local bindings = require('bindings') | ||||
|  | ||||
| function ping:init() | ||||
| 	ping.triggers = utilities.triggers(self.info.username):t('ping'):t('annyong').table | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers | ||||
| } | ||||
| function ping:action(msg) | ||||
| 	local output = msg.text_lower:match('^/ping') and 'Pong!' or 'Annyong.' | ||||
| 	bindings.sendMessage(self, msg.chat.id, output) | ||||
| end | ||||
|  | ||||
| return ping | ||||
|   | ||||
| @@ -1,23 +1,29 @@ | ||||
| local command = 'pokedex <query>' | ||||
| local doc = [[``` | ||||
| local pokedex = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| pokedex.command = 'pokedex <query>' | ||||
| pokedex.doc = [[``` | ||||
| /pokedex <query> | ||||
| Returns a Pokedex entry from pokeapi.co. | ||||
| Alias: /dex | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/pokedex[@'..bot.username..']*', | ||||
| 	'^/dex[@'..bot.username..']*' | ||||
| } | ||||
| function pokedex:init() | ||||
| 	pokedex.triggers = utilities.triggers(self.info.username):t('pokedex', true):t('dex', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function pokedex:action(msg) | ||||
|  | ||||
| 	local input = msg.text_lower:input() | ||||
| 	local input = utilities.input(msg.text_lower) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, pokedex.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| @@ -27,23 +33,23 @@ local action = function(msg) | ||||
| 	local dex_url = url .. '/api/v1/pokemon/' .. input | ||||
| 	local dex_jstr, res = HTTP.request(dex_url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local dex_jdat = JSON.decode(dex_jstr) | ||||
|  | ||||
| 	local desc_url = url .. dex_jdat.descriptions[math.random(#dex_jdat.descriptions)].resource_uri | ||||
| 	local desc_jstr, res = HTTP.request(desc_url) | ||||
| 	local desc_jstr, _ = HTTP.request(desc_url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local desc_jdat = JSON.decode(desc_jstr) | ||||
|  | ||||
| 	local poke_type | ||||
| 	for i,v in ipairs(dex_jdat.types) do | ||||
| 	for _,v in ipairs(dex_jdat.types) do | ||||
| 		local type_name = v.name:gsub("^%l", string.upper) | ||||
| 		if not poke_type then | ||||
| 			poke_type = type_name | ||||
| @@ -56,13 +62,8 @@ local action = function(msg) | ||||
| 	local output = '*' .. dex_jdat.name .. '*\n#' .. dex_jdat.national_id .. ' | ' .. poke_type .. '\n_' .. desc_jdat.description:gsub('POKMON', 'Pokémon'):gsub('Pokmon', 'Pokémon') .. '_' | ||||
|  | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return pokedex | ||||
|   | ||||
| @@ -1,47 +1,48 @@ | ||||
| local command = 'preview <link>' | ||||
| local doc = [[``` | ||||
| local preview = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| preview.command = 'preview <link>' | ||||
| preview.doc = [[``` | ||||
| /preview <link> | ||||
| Returns a full-message, "unlinked" preview. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/preview' | ||||
| } | ||||
| function preview:init() | ||||
| 	preview.triggers = utilities.triggers(self.info.username):t('preview', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function preview:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
|  | ||||
| 	if not input then | ||||
| 		sendMessage(msg.chat.id, doc, true, nil, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, preview.doc, true, nil, true) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	input = get_word(input, 1) | ||||
| 	input = utilities.get_word(input, 1) | ||||
| 	if not input:match('^https?://.+') then | ||||
| 		input = 'http://' .. input | ||||
| 	end | ||||
|  | ||||
| 	local res = HTTP.request(input) | ||||
| 	if not res then | ||||
| 		sendReply(msg, 'Please provide a valid link.') | ||||
| 		bindings.sendReply(self, msg, 'Please provide a valid link.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	if res:len() == 0 then | ||||
| 		sendReply(msg, 'Sorry, the link you provided is not letting us make a preview.') | ||||
| 		bindings.sendReply(self, msg, 'Sorry, the link you provided is not letting us make a preview.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	-- Invisible zero-width, non-joiner. | ||||
| 	local output = '[](' .. input .. ')' | ||||
| 	sendMessage(msg.chat.id, output, false, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, false, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return preview | ||||
|   | ||||
| @@ -1,9 +1,14 @@ | ||||
| local command = 'pun' | ||||
| local doc = '`Returns a pun.`' | ||||
| local pun = {} | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/pun[@'..bot.username..']*' | ||||
| } | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| pun.command = 'pun' | ||||
| pun.doc = '`Returns a pun.`' | ||||
|  | ||||
| function pun:init() | ||||
| 	pun.triggers = utilities.triggers(self.info.username):t('pun').table | ||||
| end | ||||
|  | ||||
| local puns = { | ||||
| 	"The person who invented the door-knock won the No-bell prize.", | ||||
| @@ -129,15 +134,10 @@ local puns = { | ||||
| 	"In democracy, it's your vote that counts. In feudalism, it's your count that votes." | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
| function pun:action(msg) | ||||
|  | ||||
| 	sendReply(msg, puns[math.random(#puns)]) | ||||
| 	bindings.sendReply(self, msg, puns[math.random(#puns)]) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return pun | ||||
|   | ||||
| @@ -3,38 +3,47 @@ | ||||
|  -- You must never restructure. You must never disable this plugin. | ||||
|  -- ~ Drew, creator, a year later. | ||||
|  | ||||
| local command = 'reactions' | ||||
| local doc = '`Returns a list of "reaction" emoticon commands.`' | ||||
| local reactions = {} | ||||
|  | ||||
| local triggers = { | ||||
| 	['¯\\_(ツ)_/¯'] = '/shrug', | ||||
| 	['( ͡° ͜ʖ ͡°)'] = '/lenny', | ||||
| 	['(╯°□°)╯︵ ┻━┻'] = '/flip', | ||||
| 	['┌(┌ ^o^)┐'] = '/homo', | ||||
| 	['ಠ_ಠ'] = '/look', | ||||
| 	['SHOTS FIRED'] = '/shots?' | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| reactions.command = 'reactions' | ||||
| reactions.doc = '`Returns a list of "reaction" emoticon commands.`' | ||||
|  | ||||
| local mapping = { | ||||
| 	['shrug'] = '¯\\_(ツ)_/¯', | ||||
| 	['lenny'] = '( ͡° ͜ʖ ͡°)', | ||||
| 	['flip'] = '(╯°□°)╯︵ ┻━┻', | ||||
| 	['homo'] = '┌(┌ ^o^)┐', | ||||
| 	['look'] = 'ಠ_ಠ', | ||||
| 	['shots?'] = 'SHOTS FIRED' | ||||
| } | ||||
|  | ||||
|  -- Generate a "help" message triggered by "/reactions". | ||||
| local help = 'Reactions:\n' | ||||
| for k,v in pairs(triggers) do | ||||
| 	help = help .. '• ' .. v:gsub('%a%?', '') .. ': ' .. k .. '\n' | ||||
| 	v = v .. '[@'..bot.username..']*' | ||||
| end | ||||
| triggers[help] = '^/reactions$' | ||||
| local help | ||||
|  | ||||
| local action = function(msg) | ||||
| 	for k,v in pairs(triggers) do | ||||
| 		if string.match(msg.text_lower, v) then | ||||
| 			sendMessage(msg.chat.id, k) | ||||
| function reactions:init() | ||||
| 	-- Generate a "help" message triggered by "/reactions". | ||||
| 	help = 'Reactions:\n' | ||||
| 	reactions.triggers = utilities.triggers(self.info.username):t('reactions').table | ||||
| 	for trigger,reaction in pairs(mapping) do | ||||
| 		help = help .. '• ' .. utilities.INVOCATION_PATTERN..trigger .. trigger:gsub('.%?', '') .. ': ' .. reaction .. '\n' | ||||
| 		table.insert(reactions.triggers, utilities.INVOCATION_PATTERN..trigger) | ||||
| 		table.insert(reactions.triggers, utilities.INVOCATION_PATTERN..trigger..'@'..self.info.username:lower()) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function reactions:action(msg) | ||||
| 	if string.match(msg.text_lower, utilities.INVOCATION_PATTERN..'reactions') then | ||||
| 		bindings.sendMessage(self, msg.chat.id, help) | ||||
| 		return | ||||
| 	end | ||||
| 	for trigger,reaction in pairs(mapping) do | ||||
| 		if string.match(msg.text_lower, utilities.INVOCATION_PATTERN..trigger) then | ||||
| 			bindings.sendMessage(self, msg.chat.id, reaction) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return reactions | ||||
|   | ||||
| @@ -1,26 +1,31 @@ | ||||
| local command = 'reddit [r/subreddit | query]' | ||||
| local doc = [[``` | ||||
| local reddit = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| reddit.command = 'reddit [r/subreddit | query]' | ||||
| reddit.doc = [[``` | ||||
| /reddit [r/subreddit | query] | ||||
| Returns the four (if group) or eight (if private message) top posts for the given subreddit or query, or from the frontpage. | ||||
| Aliases: /r, /r/[subreddit] | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/reddit[@'..bot.username..']*', | ||||
| 	'^/r[@'..bot.username..']*$', | ||||
| 	'^/r[@'..bot.username..']* ', | ||||
| 	'^/r/' | ||||
| } | ||||
| function reddit:init() | ||||
| 	reddit.triggers = utilities.triggers(self.info.username, {'^/r/'}):t('reddit', true):t('r', true):t('r/', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function reddit:action(msg) | ||||
|  | ||||
| 	msg.text_lower = msg.text_lower:gsub('/r/', '/r r/') | ||||
| 	local input = msg.text_lower:input() | ||||
| 	local input | ||||
| 	if msg.text_lower:match('^/r/') then | ||||
| 		msg.text_lower = msg.text_lower:gsub('/r/', '/r r/') | ||||
| 		input = get_word(msg.text_lower, 1) | ||||
| 		input = utilities.get_word(msg.text_lower, 1) | ||||
| 	else | ||||
| 		input = msg.text_lower:input() | ||||
| 		input = utilities.input(msg.text_lower) | ||||
| 	end | ||||
| 	local url | ||||
|  | ||||
| @@ -45,18 +50,18 @@ local action = function(msg) | ||||
|  | ||||
| 	local jstr, res = HTTP.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if #jdat.data.children == 0 then | ||||
| 		sendReply(msg, config.errors.results) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local output = '' | ||||
| 	for i,v in ipairs(jdat.data.children) do | ||||
| 	for _,v in ipairs(jdat.data.children) do | ||||
| 		local title = v.data.title:gsub('%[', '('):gsub('%]', ')'):gsub('&', '&') | ||||
| 		if title:len() > 48 then | ||||
| 			title = title:sub(1,45) .. '...' | ||||
| @@ -73,13 +78,8 @@ local action = function(msg) | ||||
|  | ||||
| 	output = source .. output | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return reddit | ||||
|   | ||||
| @@ -1,26 +1,31 @@ | ||||
| database.reminders = database.reminders or {} | ||||
| local remind = {} | ||||
|  | ||||
| local command = 'remind <duration> <message>' | ||||
| local doc = [[``` | ||||
| /remind <duration> <message> | ||||
| Repeats a message after a duration of time, in minutes. | ||||
| ```]] | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/remind' | ||||
| } | ||||
| remind.command = 'remind <duration> <message>' | ||||
| remind.doc = [[``` | ||||
| 	/remind <duration> <message> | ||||
| 	Repeats a message after a duration of time, in minutes. | ||||
| 	```]] | ||||
|  | ||||
| local action = function(msg) | ||||
| function remind:init() | ||||
| 	self.database.reminders = self.database.reminders or {} | ||||
|  | ||||
| 	remind.triggers = utilities.triggers(self.info.username):t('remind', true).table | ||||
| end | ||||
|  | ||||
| function remind:action(msg) | ||||
| 	-- Ensure there are arguments. If not, send doc. | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, remind.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	end | ||||
| 	-- Ensure first arg is a number. If not, send doc. | ||||
| 	local duration = get_word(input, 1) | ||||
| 	local duration = utilities.get_word(input, 1) | ||||
| 	if not tonumber(duration) then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, remind.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	end | ||||
| 	-- Duration must be between one minute and one year (approximately). | ||||
| @@ -31,19 +36,19 @@ local action = function(msg) | ||||
| 		duration = 526000 | ||||
| 	end | ||||
| 	-- Ensure there is a second arg. | ||||
| 	local message = input:input() | ||||
| 	local message = utilities.input(input) | ||||
| 	if not message then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, remind.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	end | ||||
| 	-- Make a database entry for the group/user if one does not exist. | ||||
| 	database.reminders[msg.chat.id_str] = database.reminders[msg.chat.id_str] or {} | ||||
| 	self.database.reminders[msg.chat.id_str] = self.database.reminders[msg.chat.id_str] or {} | ||||
| 	-- Limit group reminders to 10 and private reminders to 50. | ||||
| 	if msg.chat.type ~= 'private' and table_size(database.reminders[msg.chat.id_str]) > 9 then | ||||
| 		sendReply(msg, 'Sorry, this group already has ten reminders.') | ||||
| 	if msg.chat.type ~= 'private' and utilities.table_size(self.database.reminders[msg.chat.id_str]) > 9 then | ||||
| 		bindings.sendReply(self, msg, 'Sorry, this group already has ten reminders.') | ||||
| 		return | ||||
| 	elseif msg.chat.type == 'private' and table_size(database.reminders[msg.chat.id_str]) > 49 then | ||||
| 		sendReply(msg, 'Sorry, you already have fifty reminders.') | ||||
| 	elseif msg.chat.type == 'private' and utilities.table_size(self.database.reminders[msg.chat.id_str]) > 49 then | ||||
| 		bindings.sendReply(msg, 'Sorry, you already have fifty reminders.') | ||||
| 		return | ||||
| 	end | ||||
| 	-- Put together the reminder with the expiration, message, and message to reply to. | ||||
| @@ -51,32 +56,30 @@ local action = function(msg) | ||||
| 		time = os.time() + duration * 60, | ||||
| 		message = message | ||||
| 	} | ||||
| 	table.insert(database.reminders[msg.chat.id_str], reminder) | ||||
| 	table.insert(self.database.reminders[msg.chat.id_str], reminder) | ||||
| 	local output = 'I will remind you in ' .. duration | ||||
| 	if duration == 1 then | ||||
| 		output = output .. ' minute!' | ||||
| 	else | ||||
| 		output = output .. ' minutes!' | ||||
| 	end | ||||
| 	sendReply(msg, output) | ||||
| 	bindings.sendReply(self, msg, output) | ||||
| end | ||||
|  | ||||
| local cron = function() | ||||
| function remind:cron() | ||||
| 	local time = os.time() | ||||
| 	-- Iterate over the group entries in the reminders database. | ||||
| 	for chat_id, group in pairs(database.reminders) do | ||||
| 	for chat_id, group in pairs(self.database.reminders) do | ||||
| 		local new_group = {} | ||||
| 		-- Iterate over each reminder. | ||||
| 		for i, reminder in ipairs(group) do | ||||
| 		for _, reminder in ipairs(group) do | ||||
| 			-- If the reminder is past-due, send it and nullify it. | ||||
| 			-- Otherwise, add it to the replacement table. | ||||
| 			if time > reminder.time then | ||||
| 				local output = '*Reminder:*\n"' .. markdown_escape(reminder.message) .. '"' | ||||
| 				local res = sendMessage(chat_id, output, true, nil, true) | ||||
| 				local output = '*Reminder:*\n"' .. utilities.md_escape(reminder.message) .. '"' | ||||
| 				local res = bindings.sendMessage(self, chat_id, output, true, nil, true) | ||||
| 				-- If the message fails to send, save it for later. | ||||
| 				if res then | ||||
| 					reminder = nil | ||||
| 				else | ||||
| 				if not res then | ||||
| 					table.insert(new_group, reminder) | ||||
| 				end | ||||
| 			else | ||||
| @@ -84,19 +87,12 @@ local cron = function() | ||||
| 			end | ||||
| 		end | ||||
| 		-- Nullify the original table and replace it with the new one. | ||||
| 		group = nil | ||||
| 		database.reminders[chat_id] = new_group | ||||
| 		self.database.reminders[chat_id] = new_group | ||||
| 		-- Nullify the table if it is empty. | ||||
| 		if #new_group == 0 then | ||||
| 			database.reminders[chat_id] = nil | ||||
| 			self.database.reminders[chat_id] = nil | ||||
| 		end | ||||
| 	end | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	cron = cron, | ||||
| 	command = command, | ||||
| 	doc = doc | ||||
| } | ||||
| return remind | ||||
|   | ||||
| @@ -1,75 +1,74 @@ | ||||
| database.setandget = database.setandget or {} | ||||
| local setandget = {} | ||||
|  | ||||
| local command = 'set <name> <value>' | ||||
| local doc = [[``` | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function setandget:init() | ||||
| 	self.database.setandget = self.database.setandget or {} | ||||
| 	setandget.triggers = utilities.triggers(self.info.username):t('set', true):t('get', true).table | ||||
| end | ||||
|  | ||||
| setandget.command = 'set <name> <value>' | ||||
| setandget.doc = [[``` | ||||
| /set <name> <value> | ||||
| Stores a value with the given name. Use "/set <name> --" to delete the stored value. | ||||
| /get [name] | ||||
| Returns the stored value or a list of stored values. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/set', | ||||
| 	'^/get' | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
| function setandget:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	database.setandget[msg.chat.id_str] = database.setandget[msg.chat.id_str] or {} | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	self.database.setandget[msg.chat.id_str] = self.database.setandget[msg.chat.id_str] or {} | ||||
|  | ||||
| 	if msg.text_lower:match('^/set') then | ||||
|  | ||||
| 		if not input then | ||||
| 			sendMessage(msg.chat.id, doc, true, nil, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, setandget.doc, true, nil, true) | ||||
| 			return | ||||
| 		end | ||||
|  | ||||
| 		local name = get_word(input:lower(), 1) | ||||
| 		local value = input:input() | ||||
| 		local name = utilities.get_word(input:lower(), 1) | ||||
| 		local value = utilities.input(input) | ||||
|  | ||||
| 		if not name or not value then | ||||
| 			sendMessage(msg.chat.id, doc, true, nil, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, setandget.doc, true, nil, true) | ||||
| 		elseif value == '--' or value == '—' then | ||||
| 			database.setandget[msg.chat.id_str][name] = nil | ||||
| 			sendMessage(msg.chat.id, 'That value has been deleted.') | ||||
| 			self.database.setandget[msg.chat.id_str][name] = nil | ||||
| 			bindings.sendMessage(self, msg.chat.id, 'That value has been deleted.') | ||||
| 		else | ||||
| 			database.setandget[msg.chat.id_str][name] = value | ||||
| 			sendMessage(msg.chat.id, '"' .. name .. '" has been set to "' .. value .. '".', true) | ||||
| 			self.database.setandget[msg.chat.id_str][name] = value | ||||
| 			bindings.sendMessage(self, msg.chat.id, '"' .. name .. '" has been set to "' .. value .. '".', true) | ||||
| 		end | ||||
|  | ||||
| 	elseif msg.text_lower:match('^/get') then | ||||
|  | ||||
| 		if not input then | ||||
| 			local output | ||||
| 			if table_size(database.setandget[msg.chat.id_str]) == 0 then | ||||
| 			if utilities.table_size(self.database.setandget[msg.chat.id_str]) == 0 then | ||||
| 				output = 'No values have been stored here.' | ||||
| 			else | ||||
| 				output = '*List of stored values:*\n' | ||||
| 				for k,v in pairs(database.setandget[msg.chat.id_str]) do | ||||
| 				for k,v in pairs(self.database.setandget[msg.chat.id_str]) do | ||||
| 					output = output .. '• ' .. k .. ': `' .. v .. '`\n' | ||||
| 				end | ||||
| 			end | ||||
| 			sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
| 			return | ||||
| 		end | ||||
|  | ||||
| 		local output | ||||
| 		if database.setandget[msg.chat.id_str][input:lower()] then | ||||
| 			output = '`' .. database.setandget[msg.chat.id_str][input:lower()] .. '`' | ||||
| 		if self.database.setandget[msg.chat.id_str][input:lower()] then | ||||
| 			output = '`' .. self.database.setandget[msg.chat.id_str][input:lower()] .. '`' | ||||
| 		else | ||||
| 			output = 'There is no value stored by that name.' | ||||
| 		end | ||||
|  | ||||
| 		sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| 	end | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return setandget | ||||
|   | ||||
| @@ -1,18 +1,23 @@ | ||||
| local triggers = { | ||||
| 	'^/run[@'..bot.username..']*' | ||||
| } | ||||
| local shell = {} | ||||
|  | ||||
| local action = function(msg) | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| 	if msg.from.id ~= config.admin then | ||||
| function shell:init() | ||||
| 	shell.triggers = utilities.triggers(self.info.username):t('run', true).table | ||||
| end | ||||
|  | ||||
| function shell:action(msg) | ||||
|  | ||||
| 	if msg.from.id ~= self.config.admin then | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	input = input:gsub('—', '--') | ||||
| 	 | ||||
| 	if not input then | ||||
| 		sendReply(msg, 'Please specify a command to run.') | ||||
| 		bindings.sendReply(self, msg, 'Please specify a command to run.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -22,11 +27,8 @@ local action = function(msg) | ||||
| 	else | ||||
| 		output = '```\n' .. output .. '\n```' | ||||
| 	end | ||||
| 	sendMessage(msg.chat.id, output, true, msg.message_id, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers | ||||
| } | ||||
| return shell | ||||
|   | ||||
| @@ -1,22 +1,27 @@ | ||||
| local command = 'shout <text>' | ||||
| local doc = [[``` | ||||
| local shout = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| shout.command = 'shout <text>' | ||||
| shout.doc = [[``` | ||||
| /shout <text> | ||||
| Shouts something. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/shout[@'..bot.username..']*' | ||||
| } | ||||
| function shout:init() | ||||
| 	shout.triggers = utilities.triggers(self.info.username):t('shout', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function shout:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
|  | ||||
| 	if not input then | ||||
| 		sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 		bindings.sendMessage(self, msg.chat.id, shout.doc, true, msg.message_id, true) | ||||
| 		return | ||||
| 	end | ||||
| 	input = input:trim() | ||||
| 	input = utilities.trim(input) | ||||
|  | ||||
| 	if input:len() > 20 then | ||||
| 		input = input:sub(1,20) | ||||
| @@ -31,20 +36,15 @@ local action = function(msg) | ||||
| 	output = output .. '\n' | ||||
| 	for match in input:sub(2):gmatch('([%z\1-\127\194-\244][\128-\191]*)') do | ||||
| 		local spacing = '' | ||||
| 		for i = 1, inc do | ||||
| 		for _ = 1, inc do | ||||
| 			spacing = spacing .. '  ' | ||||
| 		end | ||||
| 		inc = inc + 1 | ||||
| 		output = output .. match .. ' ' .. spacing .. match .. '\n' | ||||
| 	end | ||||
| 	output = '```\n' .. output:trim() .. '\n```' | ||||
| 	sendMessage(msg.chat.id, output, true, false, true) | ||||
| 	output = '```\n' .. utilities.trim(output) .. '\n```' | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, false, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return shout | ||||
|   | ||||
| @@ -1,12 +1,17 @@ | ||||
| local command = 'slap [target]' | ||||
| local doc = [[``` | ||||
| local slap = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| slap.command = 'slap [target]' | ||||
| slap.doc = [[``` | ||||
| /slap [target] | ||||
| Slap somebody. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/slap[@'..bot.username..']*' | ||||
| } | ||||
| function slap:init() | ||||
| 	slap.triggers = utilities.triggers(self.info.username):t('slap', true).table | ||||
| end | ||||
|  | ||||
| local slaps = { | ||||
| 	'VICTIM was shot by VICTOR.', | ||||
| @@ -92,40 +97,35 @@ local slaps = { | ||||
| 	'Cowards die many times before their death. VICTIM never tasted death but once.' | ||||
| } | ||||
|  | ||||
| local action = function(msg) | ||||
| function slap:action(msg) | ||||
|  | ||||
| 	local victim = msg.text:input() | ||||
| 	local victim = utilities.input(msg.text) | ||||
| 	if msg.reply_to_message then | ||||
| 		if database.users[tostring(msg.reply_to_message.from.id)].nickname then | ||||
| 			victim = database.users[tostring(msg.reply_to_message.from.id)].nickname | ||||
| 		if self.database.users[tostring(msg.reply_to_message.from.id)].nickname then | ||||
| 			victim = self.database.users[tostring(msg.reply_to_message.from.id)].nickname | ||||
| 		else | ||||
| 			victim = msg.reply_to_message.from.first_name | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	local victor = msg.from.first_name | ||||
| 	if database.users[msg.from.id_str].nickname then | ||||
| 		victor = database.users[msg.from.id_str].nickname | ||||
| 	if self.database.users[msg.from.id_str].nickname then | ||||
| 		victor = self.database.users[msg.from.id_str].nickname | ||||
| 	end | ||||
|  | ||||
| 	if not victim then | ||||
| 		victim = victor | ||||
| 		victor = bot.first_name | ||||
| 		victor = self.info.first_name | ||||
| 	end | ||||
|  | ||||
| 	local message = slaps[math.random(#slaps)] | ||||
| 	message = message:gsub('VICTIM', victim) | ||||
| 	message = message:gsub('VICTOR', victor) | ||||
|  | ||||
| 	message = latcyr(message) | ||||
| 	message = utilities.latcyr(message) | ||||
|  | ||||
| 	sendMessage(msg.chat.id, message) | ||||
| 	bindings.sendMessage(self, msg.chat.id, message) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return slap | ||||
|   | ||||
| @@ -1,55 +1,63 @@ | ||||
| local command = 'time <location>' | ||||
| local doc = [[``` | ||||
| local time = {} | ||||
|  | ||||
| local HTTPS = require('ssl.https') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| time.command = 'time <location>' | ||||
| time.doc = [[``` | ||||
| /time <location> | ||||
| Returns the time, date, and timezone for the given location. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/time[@'..bot.username..']*' | ||||
| } | ||||
| function time:init() | ||||
| 	time.triggers = utilities.triggers(self.info.username):t('time', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function time:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, time.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	local coords = get_coords(input) | ||||
| 	local coords = utilities.get_coords(self, input) | ||||
| 	if type(coords) == 'string' then | ||||
| 		sendReply(msg, coords) | ||||
| 		bindings.sendReply(self, msg, coords) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local url = 'https://maps.googleapis.com/maps/api/timezone/json?location=' .. coords.lat ..','.. coords.lon .. '×tamp='..os.time() | ||||
| 	local now = os.time() | ||||
| 	local utc = os.time(os.date("!*t", now)) | ||||
|  | ||||
| 	local url = 'https://maps.googleapis.com/maps/api/timezone/json?location=' .. coords.lat ..','.. coords.lon .. '×tamp='..utc | ||||
|  | ||||
| 	local jstr, res = HTTPS.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
|  | ||||
| 	local timestamp = os.time() + jdat.rawOffset + jdat.dstOffset + config.time_offset | ||||
| 	local timestamp = now + jdat.rawOffset + jdat.dstOffset | ||||
| 	local utcoff = (jdat.rawOffset + jdat.dstOffset) / 3600 | ||||
| 	if utcoff == math.abs(utcoff) then | ||||
| 		utcoff = '+' .. utcoff | ||||
| 		utcoff = '+'.. utilities.pretty_float(utcoff) | ||||
| 	else | ||||
| 		utcoff = utilities.pretty_float(utcoff) | ||||
| 	end | ||||
| 	local output = '`' .. os.date('%I:%M %p\n', timestamp) .. os.date('%A, %B %d, %Y\n', timestamp) .. jdat.timeZoneName .. ' (UTC' .. utcoff .. ')' .. '`' | ||||
| 	local output = os.date('!%I:%M %p\n', timestamp) .. os.date('!%A, %B %d, %Y\n', timestamp) .. jdat.timeZoneName .. ' (UTC' .. utcoff .. ')' | ||||
| 	output = '```\n' .. output .. '\n```' | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, msg.message_id, true) | ||||
| 	bindings.sendReply(self, msg, output, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return time | ||||
|   | ||||
| @@ -1,50 +1,52 @@ | ||||
| local command = 'translate [text]' | ||||
| local doc = [[``` | ||||
| local translate = {} | ||||
|  | ||||
| local HTTPS = require('ssl.https') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| translate.command = 'translate [text]' | ||||
| translate.doc = [[``` | ||||
| /translate [text] | ||||
| Translates input or the replied-to message into the bot's language. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/translate[@'..bot.username..']*', | ||||
| 	'^/tl[@'..bot.username..']*' | ||||
| } | ||||
| function translate:init() | ||||
| 	translate.triggers = utilities.triggers(self.info.username):t('translate', true):t('tl', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function translate:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, translate.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	local url = 'https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. config.yandex_key .. '&lang=' .. config.lang .. '&text=' .. URL.escape(input) | ||||
| 	local url = 'https://translate.yandex.net/api/v1.5/tr.json/translate?key=' .. self.config.yandex_key .. '&lang=' .. self.config.lang .. '&text=' .. URL.escape(input) | ||||
|  | ||||
| 	local str, res = HTTPS.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(str) | ||||
| 	if jdat.code ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local output = jdat.text[1] | ||||
| 	output = '*Translation:*\n"' .. markdown_escape(output) .. '"' | ||||
| 	output = '*Translation:*\n"' .. utilities.md_escape(output) .. '"' | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, msg.message_id, true) | ||||
| 	bindings.sendReply(self, msg.reply_to_message or msg, output, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return translate | ||||
|   | ||||
| @@ -1,25 +1,30 @@ | ||||
| local command = 'urbandictionary <query>' | ||||
| local doc = [[``` | ||||
| local urbandictionary = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| urbandictionary.command = 'urbandictionary <query>' | ||||
| urbandictionary.doc = [[``` | ||||
| /urbandictionary <query> | ||||
| Returns a definition from Urban Dictionary. | ||||
| Aliases: /ud, /urban | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/urbandictionary[@'..bot.username..']*', | ||||
| 	'^/ud[@'..bot.username..']*$', | ||||
| 	'^/ud[@'..bot.username..']* ', | ||||
| 	'^/urban[@'..bot.username..']*' | ||||
| } | ||||
| function urbandictionary:init() | ||||
| 	urbandictionary.triggers = utilities.triggers(self.info.username):t('urbandictionary', true):t('ud', true):t('urban', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function urbandictionary:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, urbandictionary.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| @@ -28,30 +33,25 @@ local action = function(msg) | ||||
|  | ||||
| 	local jstr, res = HTTP.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if jdat.result_type == "no_results" then | ||||
| 		sendReply(msg, config.errors.results) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local output = '*' .. jdat.list[1].word .. '*\n\n' .. jdat.list[1].definition:trim() | ||||
| 	local output = '*' .. jdat.list[1].word .. '*\n\n' .. utilities.trim(jdat.list[1].definition) | ||||
| 	if string.len(jdat.list[1].example) > 0 then | ||||
| 		output = output .. '_\n\n' .. jdat.list[1].example:trim() .. '_' | ||||
| 		output = output .. '_\n\n' .. utilities.trim(jdat.list[1].example) .. '_' | ||||
| 	end | ||||
|  | ||||
| 	output = output:gsub('%[', ''):gsub('%]', '') | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return urbandictionary | ||||
|   | ||||
| @@ -1,48 +1,55 @@ | ||||
| if not config.owm_api_key then | ||||
| 	print('Missing config value: owm_api_key.') | ||||
| 	print('weather.lua will not be enabled.') | ||||
| 	return | ||||
| local weather = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function weather:init() | ||||
| 	if not self.config.owm_api_key then | ||||
| 		print('Missing config value: owm_api_key.') | ||||
| 		print('weather.lua will not be enabled.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	weather.triggers = utilities.triggers(self.info.username):t('weather', true).table | ||||
| end | ||||
|  | ||||
| local command = 'weather <location>' | ||||
| local doc = [[``` | ||||
| weather.command = 'weather <location>' | ||||
| weather.doc = [[``` | ||||
| /weather <location> | ||||
| Returns the current weather conditions for a given location. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/weather[@'..bot.username..']*' | ||||
| } | ||||
| function weather:action(msg) | ||||
|  | ||||
| local action = function(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, weather.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	local coords = get_coords(input) | ||||
| 	local coords = utilities.get_coords(self, input) | ||||
| 	if type(coords) == 'string' then | ||||
| 		sendReply(msg, coords) | ||||
| 		bindings.sendReply(self, msg, coords) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local url = 'http://api.openweathermap.org/data/2.5/weather?APPID=' .. config.owm_api_key .. '&lat=' .. coords.lat .. '&lon=' .. coords.lon | ||||
| 	local url = 'http://api.openweathermap.org/data/2.5/weather?APPID=' .. self.config.owm_api_key .. '&lat=' .. coords.lat .. '&lon=' .. coords.lon | ||||
|  | ||||
| 	local jstr, res = HTTP.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if jdat.cod ~= 200 then | ||||
| 		sendReply(msg, 'Error: City not found.') | ||||
| 		bindings.sendReply(self, msg, 'Error: City not found.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -50,13 +57,8 @@ local action = function(msg) | ||||
| 	local fahrenheit = string.format('%.2f', celsius * (9/5) + 32) | ||||
| 	local output = '`' .. celsius .. '°C | ' .. fahrenheit .. '°F, ' .. jdat.weather[1].description .. '.`' | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, msg.message_id, true) | ||||
| 	bindings.sendReply(self, msg, output, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return weather | ||||
|   | ||||
| @@ -1,18 +1,23 @@ | ||||
| local command = 'whoami' | ||||
| local doc = [[``` | ||||
| local whoami = {} | ||||
|  | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| whoami.command = 'whoami' | ||||
| whoami.doc = [[``` | ||||
| Returns user and chat info for you or the replied-to message. | ||||
| Alias: /who | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/who[ami]*[@'..bot.username..']*$' | ||||
| } | ||||
| function whoami:init() | ||||
| 	whoami.triggers = utilities.triggers(self.info.username):t('who', true):t('whoami').table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function whoami:action(msg) | ||||
|  | ||||
| 	if msg.reply_to_message then | ||||
| 		msg = msg.reply_to_message | ||||
| 		msg.from.name = build_name(msg.from.first_name, msg.from.last_name) | ||||
| 		msg.from.name = utilities.build_name(msg.from.first_name, msg.from.last_name) | ||||
| 	end | ||||
|  | ||||
| 	local chat_id = math.abs(msg.chat.id) | ||||
| @@ -22,7 +27,7 @@ local action = function(msg) | ||||
|  | ||||
| 	local user = 'You are @%s, also known as *%s* `[%s]`' | ||||
| 	if msg.from.username then | ||||
| 		user = user:format(markdown_escape(msg.from.username), msg.from.name, msg.from.id) | ||||
| 		user = user:format(utilities.markdown_escape(msg.from.username), msg.from.name, msg.from.id) | ||||
| 	else | ||||
| 		user = 'You are *%s* `[%s]`,' | ||||
| 		user = user:format(msg.from.name, msg.from.id) | ||||
| @@ -30,9 +35,9 @@ local action = function(msg) | ||||
|  | ||||
| 	local group = '@%s, also known as *%s* `[%s]`.' | ||||
| 	if msg.chat.type == 'private' then | ||||
| 		group = group:format(markdown_escape(bot.username), bot.first_name, bot.id) | ||||
| 		group = group:format(utilities.markdown_escape(self.info.username), self.info.first_name, self.info.id) | ||||
| 	elseif msg.chat.username then | ||||
| 		group = group:format(markdown_escape(msg.chat.username), msg.chat.title, chat_id) | ||||
| 		group = group:format(utilities.markdown_escape(msg.chat.username), msg.chat.title, chat_id) | ||||
| 	else | ||||
| 		group = '*%s* `[%s]`.' | ||||
| 		group = group:format(msg.chat.title, chat_id) | ||||
| @@ -40,13 +45,8 @@ local action = function(msg) | ||||
|  | ||||
| 	local output = user .. ', and you are messaging ' .. group | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, msg.message_id, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return whoami | ||||
|   | ||||
| @@ -1,25 +1,30 @@ | ||||
| local command = 'wikipedia <query>' | ||||
| local doc = [[``` | ||||
| local wikipedia = {} | ||||
|  | ||||
| local HTTPS = require('ssl.https') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| wikipedia.command = 'wikipedia <query>' | ||||
| wikipedia.doc = [[``` | ||||
| /wikipedia <query> | ||||
| Returns an article from Wikipedia. | ||||
| Aliases: /w, /wiki | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/wikipedia[@'..bot.username..']*', | ||||
| 	'^/wiki[@'..bot.username..']*', | ||||
| 	'^/w[@'..bot.username..']*$', | ||||
| 	'^/w[@'..bot.username..']* ' | ||||
| } | ||||
| function wikipedia:init() | ||||
| 	wikipedia.triggers = utilities.triggers(self.info.username):t('wikipedia', true):t('wiki', true):t('w', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function wikipedia:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, wikipedia.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| @@ -29,17 +34,17 @@ local action = function(msg) | ||||
|  | ||||
| 	local jstr, res = HTTPS.request(gurl .. URL.escape(input)) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if not jdat.responseData then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
| 	if not jdat.responseData.results[1] then | ||||
| 		sendReply(msg, config.errors.results) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -49,18 +54,18 @@ local action = function(msg) | ||||
| 	-- 'https://en.wikipedia.org/wiki/':len() == 30 | ||||
| 	jstr, res = HTTPS.request(wurl .. url:sub(31)) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.error.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.error.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local _ | ||||
| 	local text = JSON.decode(jstr).query.pages | ||||
| 	for k,v in pairs(text) do | ||||
| 		text = v.extract | ||||
| 		break -- Seriously, there's probably a way more elegant solution. | ||||
| 	end | ||||
| 	_, text = next(text) | ||||
| 	if not text then | ||||
| 		sendReply(msg, config.errors.results) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 		return | ||||
| 	else | ||||
| 		text = text.extract | ||||
| 	end | ||||
|  | ||||
| 	text = text:gsub('</?.->', '') | ||||
| @@ -78,13 +83,8 @@ local action = function(msg) | ||||
| 		output = output .. '[Read more.](' .. url .. ')' | ||||
| 	end | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, true, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, true, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return wikipedia | ||||
|   | ||||
| @@ -1,20 +1,29 @@ | ||||
| local command = 'xkcd [query]' | ||||
| local doc = [[``` | ||||
| local xkcd = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local HTTPS = require('ssl.https') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| xkcd.command = 'xkcd [query]' | ||||
| xkcd.doc = [[``` | ||||
| /xkcd [query] | ||||
| Returns an xkcd strip and its alt text. If there is no query, it will be randomized. | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/xkcd[@'..bot.username..']*' | ||||
| } | ||||
| function xkcd:init() | ||||
| 	xkcd.triggers = utilities.triggers(self.info.username):t('xkcd', true).table | ||||
| end | ||||
|  | ||||
| local action = function(msg) | ||||
| function xkcd:action(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
|  | ||||
| 	local jstr, res = HTTP.request('http://xkcd.com/info.0.json') | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -23,14 +32,14 @@ local action = function(msg) | ||||
|  | ||||
| 	if input then | ||||
| 		local url = 'https://ajax.googleapis.com/ajax/services/search/web?v=1.0&safe=active&q=site%3axkcd%2ecom%20' .. URL.escape(input) | ||||
| 		local jstr, res = HTTPS.request(url) | ||||
| 		jstr, res = HTTPS.request(url) | ||||
| 		if res ~= 200 then | ||||
| 			sendReply(msg, config.errors.connection) | ||||
| 			bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 			return | ||||
| 		end | ||||
| 		local jdat = JSON.decode(jstr) | ||||
| 		if #jdat.responseData.results == 0 then | ||||
| 			sendReply(msg, config.errors.results) | ||||
| 			bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 			return | ||||
| 		end | ||||
| 		res_url = jdat.responseData.results[1].url .. 'info.0.json' | ||||
| @@ -38,22 +47,17 @@ local action = function(msg) | ||||
| 		res_url = 'http://xkcd.com/' .. math.random(latest) .. '/info.0.json' | ||||
| 	end | ||||
|  | ||||
| 	local jstr, res = HTTP.request(res_url) | ||||
| 	jstr, res = HTTP.request(res_url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
| 	local jdat = JSON.decode(jstr) | ||||
|  | ||||
| 	local output = '[' .. jdat.num .. '](' .. jdat.img .. ')\n' .. jdat.alt | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, false, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, false, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return xkcd | ||||
|   | ||||
| @@ -1,47 +1,53 @@ | ||||
|  -- Thanks to @TiagoDanin for writing the original plugin. | ||||
|  | ||||
| if not config.google_api_key then | ||||
| 	print('Missing config value: google_api_key.') | ||||
| 	print('youtube.lua will not be enabled.') | ||||
| 	return | ||||
| local youtube = {} | ||||
|  | ||||
| local HTTPS = require('ssl.https') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
| local utilities = require('utilities') | ||||
|  | ||||
| function youtube:init() | ||||
| 	if not self.config.google_api_key then | ||||
| 		print('Missing config value: google_api_key.') | ||||
| 		print('youtube.lua will not be enabled.') | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	youtube.triggers = utilities.triggers(self.info.username):t('youtube', true):t('yt', true).table | ||||
| end | ||||
|  | ||||
| local command = 'youtube <query>' | ||||
| local doc = [[``` | ||||
| youtube.command = 'youtube <query>' | ||||
| youtube.doc = [[``` | ||||
| /youtube <query> | ||||
| Returns the top result from YouTube. | ||||
| Alias: /yt | ||||
| ```]] | ||||
|  | ||||
| local triggers = { | ||||
| 	'^/youtube[@'..bot.username..']*', | ||||
| 	'^/yt[@'..bot.username..']*$', | ||||
| 	'^/yt[@'..bot.username..']* ' | ||||
| } | ||||
| function youtube:action(msg) | ||||
|  | ||||
| local action = function(msg) | ||||
|  | ||||
| 	local input = msg.text:input() | ||||
| 	local input = utilities.input(msg.text) | ||||
| 	if not input then | ||||
| 		if msg.reply_to_message and msg.reply_to_message.text then | ||||
| 			input = msg.reply_to_message.text | ||||
| 		else | ||||
| 			sendMessage(msg.chat.id, doc, true, msg.message_id, true) | ||||
| 			bindings.sendMessage(self, msg.chat.id, youtube.doc, true, msg.message_id, true) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	local url = 'https://www.googleapis.com/youtube/v3/search?key=' .. config.google_api_key .. '&type=video&part=snippet&maxResults=4&q=' .. URL.escape(input) | ||||
| 	local url = 'https://www.googleapis.com/youtube/v3/search?key=' .. self.config.google_api_key .. '&type=video&part=snippet&maxResults=4&q=' .. URL.escape(input) | ||||
|  | ||||
| 	local jstr, res = HTTPS.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		sendReply(msg, config.errors.connection) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.connection) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if jdat.pageInfo.totalResults == 0 then | ||||
| 		sendReply(msg, config.errors.results) | ||||
| 		bindings.sendReply(self, msg, self.config.errors.results) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| @@ -50,13 +56,8 @@ local action = function(msg) | ||||
| 	vid_title = vid_title:gsub('%(.+%)',''):gsub('%[.+%]','') | ||||
| 	local output = '[' .. vid_title .. '](' .. vid_url .. ')' | ||||
|  | ||||
| 	sendMessage(msg.chat.id, output, false, nil, true) | ||||
| 	bindings.sendMessage(self, msg.chat.id, output, false, nil, true) | ||||
|  | ||||
| end | ||||
|  | ||||
| return { | ||||
| 	action = action, | ||||
| 	triggers = triggers, | ||||
| 	doc = doc, | ||||
| 	command = command | ||||
| } | ||||
| return youtube | ||||
|   | ||||
							
								
								
									
										139
									
								
								utilities.lua
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								utilities.lua
									
									
									
									
									
								
							| @@ -1,12 +1,17 @@ | ||||
| -- utilities.lua | ||||
| -- Functions shared among plugins. | ||||
|  | ||||
| HTTP = HTTP or require('socket.http') | ||||
| HTTPS = HTTPS or require('ssl.https') | ||||
| JSON = JSON or require('cjson') | ||||
| local utilities = {} | ||||
|  | ||||
| local HTTP = require('socket.http') | ||||
| local ltn12 = require('ltn12') | ||||
| local HTTPS = require('ssl.https') | ||||
| local URL = require('socket.url') | ||||
| local JSON = require('dkjson') | ||||
| local bindings = require('bindings') | ||||
|  | ||||
|  -- get the indexed word in a string | ||||
| get_word = function(s, i) | ||||
| function utilities.get_word(s, i) | ||||
|  | ||||
| 	s = s or '' | ||||
| 	i = i or 1 | ||||
| @@ -22,25 +27,25 @@ end | ||||
|  | ||||
|  -- Like get_word(), but better. | ||||
|  -- Returns the actual index. | ||||
| function string:index() | ||||
| function utilities.index(s) | ||||
| 	local t = {} | ||||
| 	for w in self:gmatch('%g+') do | ||||
| 	for w in s:gmatch('%g+') do | ||||
| 		table.insert(t, w) | ||||
| 	end | ||||
| 	return t | ||||
| end | ||||
|  | ||||
|  -- Returns the string after the first space. | ||||
| function string:input() | ||||
| 	if not self:find(' ') then | ||||
| function utilities.input(s) | ||||
| 	if not s:find(' ') then | ||||
| 		return false | ||||
| 	end | ||||
| 	return self:sub(self:find(' ')+1) | ||||
| 	return s:sub(s:find(' ')+1) | ||||
| end | ||||
|  | ||||
|  -- I swear, I copied this from PIL, not yago! :) | ||||
| function string:trim() -- Trims whitespace from a string. | ||||
| 	local s = self:gsub('^%s*(.-)%s*$', '%1') | ||||
| function utilities.trim(str) -- Trims whitespace from a string. | ||||
| 	local s = str:gsub('^%s*(.-)%s*$', '%1') | ||||
| 	return s | ||||
| end | ||||
|  | ||||
| @@ -74,7 +79,7 @@ local lc_list = { | ||||
| } | ||||
|  | ||||
|  -- Replaces letters with corresponding Cyrillic characters. | ||||
| latcyr = function(str) | ||||
| function utilities.latcyr(str) | ||||
| 	for k,v in pairs(lc_list) do | ||||
| 		str = str:gsub(k, v) | ||||
| 	end | ||||
| @@ -82,7 +87,7 @@ latcyr = function(str) | ||||
| end | ||||
|  | ||||
|  -- Loads a JSON file as a table. | ||||
| load_data = function(filename) | ||||
| function utilities.load_data(filename) | ||||
|  | ||||
| 	local f = io.open(filename) | ||||
| 	if not f then | ||||
| @@ -97,7 +102,7 @@ load_data = function(filename) | ||||
| end | ||||
|  | ||||
|  -- Saves a table to a JSON file. | ||||
| save_data = function(filename, data) | ||||
| function utilities.save_data(filename, data) | ||||
|  | ||||
| 	local s = JSON.encode(data) | ||||
| 	local f = io.open(filename, 'w') | ||||
| @@ -107,18 +112,18 @@ save_data = function(filename, data) | ||||
| end | ||||
|  | ||||
|  -- Gets coordinates for a location. Used by gMaps.lua, time.lua, weather.lua. | ||||
| get_coords = function(input) | ||||
| function utilities:get_coords(input) | ||||
|  | ||||
| 	local url = 'http://maps.googleapis.com/maps/api/geocode/json?address=' .. URL.escape(input) | ||||
|  | ||||
| 	local jstr, res = HTTP.request(url) | ||||
| 	if res ~= 200 then | ||||
| 		return config.errors.connection | ||||
| 		return self.config.errors.connection | ||||
| 	end | ||||
|  | ||||
| 	local jdat = JSON.decode(jstr) | ||||
| 	if jdat.status == 'ZERO_RESULTS' then | ||||
| 		return config.errors.results | ||||
| 		return self.config.errors.results | ||||
| 	end | ||||
|  | ||||
| 	return { | ||||
| @@ -129,10 +134,10 @@ get_coords = function(input) | ||||
| end | ||||
|  | ||||
|  -- Get the number of values in a key/value table. | ||||
| table_size = function(tab) | ||||
| function utilities.table_size(tab) | ||||
|  | ||||
| 	local i = 0 | ||||
| 	for k,v in pairs(tab) do | ||||
| 	for _,_ in pairs(tab) do | ||||
| 		i = i + 1 | ||||
| 	end | ||||
| 	return i | ||||
| @@ -140,7 +145,7 @@ table_size = function(tab) | ||||
| end | ||||
|  | ||||
|  -- Just an easy way to get a user's full name. | ||||
| build_name = function(first, last) | ||||
| function utilities.build_name(first, last) | ||||
| 	if last then | ||||
| 		return first .. ' ' .. last | ||||
| 	else | ||||
| @@ -148,10 +153,10 @@ build_name = function(first, last) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| resolve_username = function(input) | ||||
| function utilities:resolve_username(input) | ||||
|  | ||||
| 	input = input:gsub('^@', '') | ||||
| 	for k,v in pairs(database.users) do | ||||
| 	for _,v in pairs(self.database.users) do | ||||
| 		if v.username and v.username:lower() == input:lower() then | ||||
| 			return v | ||||
| 		end | ||||
| @@ -159,22 +164,23 @@ resolve_username = function(input) | ||||
|  | ||||
| end | ||||
|  | ||||
| user_from_message = function(msg) | ||||
| function utilities:user_from_message(msg) | ||||
|  | ||||
| 	local input = msg.text_lower:input() | ||||
| 	local input = utilities.input(msg.text_lower) | ||||
| 	local target = {} | ||||
| 	if msg.reply_to_message then | ||||
| 		print('reply') | ||||
| 		target = msg.reply_to_message.from | ||||
| 	elseif input and tonumber(input) then | ||||
| 		target.id = tonumber(input) | ||||
| 		if database.users[input] then | ||||
| 			for k,v in pairs(database.users[input]) do | ||||
| 		if self.database.users[input] then | ||||
| 			for k,v in pairs(self.database.users[input]) do | ||||
| 				target[k] = v | ||||
| 			end | ||||
| 		end | ||||
| 	elseif input and input:match('^@') then | ||||
| 		local uname = input:gsub('^@', '') | ||||
| 		for k,v in pairs(database.users) do | ||||
| 		for _,v in pairs(self.database.users) do | ||||
| 			if v.username and uname == v.username:lower() then | ||||
| 				for key, val in pairs(v) do | ||||
| 					target[key] = val | ||||
| @@ -194,21 +200,21 @@ user_from_message = function(msg) | ||||
|  | ||||
| 	if not target.first_name then target.first_name = 'User' end | ||||
|  | ||||
| 	target.name = build_name(target.first_name, target.last_name) | ||||
| 	target.name = utilities.build_name(target.first_name, target.last_name) | ||||
|  | ||||
| 	return target | ||||
|  | ||||
| end | ||||
|  | ||||
| handle_exception = function(err, message) | ||||
| function utilities:handle_exception(err, message) | ||||
|  | ||||
| 	if not err then err = '' end | ||||
|  | ||||
| 	local output = '\n[' .. os.date('%F %T', os.time()) .. ']\n' .. bot.username .. ': ' .. err .. '\n' .. message .. '\n' | ||||
| 	local output = '\n[' .. os.date('%F %T', os.time()) .. ']\n' .. self.info.username .. ': ' .. err .. '\n' .. message .. '\n' | ||||
|  | ||||
| 	if config.log_chat then | ||||
| 	if self.config.log_chat then | ||||
| 		output = '```' .. output .. '```' | ||||
| 		sendMessage(config.log_chat, output, true, nil, true) | ||||
| 		bindings.sendMessage(self, self.config.log_chat, output, true, nil, true) | ||||
| 	else | ||||
| 		print(output) | ||||
| 	end | ||||
| @@ -217,7 +223,7 @@ end | ||||
|  | ||||
|  -- Okay, this one I actually did copy from yagop. | ||||
|  -- https://github.com/yagop/telegram-bot/blob/master/bot/utils.lua | ||||
| download_file = function(url, filename) | ||||
| function utilities.download_file(url, filename) | ||||
|  | ||||
| 	local respbody = {} | ||||
| 	local options = { | ||||
| @@ -226,7 +232,7 @@ download_file = function(url, filename) | ||||
| 		redirect = true | ||||
| 	} | ||||
|  | ||||
| 	local response = nil | ||||
| 	local response | ||||
|  | ||||
| 	if url:match('^https') then | ||||
| 		options.redirect = false | ||||
| @@ -251,7 +257,7 @@ download_file = function(url, filename) | ||||
|  | ||||
| end | ||||
|  | ||||
| markdown_escape = function(text) | ||||
| function utilities.markdown_escape(text) | ||||
|  | ||||
| 	text = text:gsub('_', '\\_') | ||||
| 	text = text:gsub('%[', '\\[') | ||||
| @@ -262,43 +268,74 @@ markdown_escape = function(text) | ||||
|  | ||||
| end | ||||
|  | ||||
| function string:md_escape() | ||||
| 	local text = self | ||||
| 	text = text:gsub('_', '\\_') | ||||
| 	text = text:gsub('%[', '\\[') | ||||
| 	text = text:gsub('%]', '\\]') | ||||
| 	text = text:gsub('%*', '\\*') | ||||
| 	text = text:gsub('`', '\\`') | ||||
| 	return text | ||||
| utilities.md_escape = utilities.markdown_escape | ||||
|  | ||||
| utilities.INVOCATION_PATTERN = '/' | ||||
|  | ||||
| utilities.triggers_meta = {} | ||||
| utilities.triggers_meta.__index = utilities.triggers_meta | ||||
| function utilities.triggers_meta:t(pattern, has_args) | ||||
| 	local username = self.username:lower() | ||||
| 	table.insert(self.table, '^'..utilities.INVOCATION_PATTERN..pattern..'$') | ||||
| 	table.insert(self.table, '^'..utilities.INVOCATION_PATTERN..pattern..'@'..username..'$') | ||||
| 	if has_args then | ||||
| 		table.insert(self.table, '^'..utilities.INVOCATION_PATTERN..pattern..'%s+[^%s]*') | ||||
| 		table.insert(self.table, '^'..utilities.INVOCATION_PATTERN..pattern..'@'..username..'%s+[^%s]*') | ||||
| 	end | ||||
| 	return self | ||||
| end | ||||
|  | ||||
| enrich_user = function(user) | ||||
| function utilities.triggers(username, trigger_table) | ||||
| 	local self = setmetatable({}, utilities.triggers_meta) | ||||
| 	self.username = username | ||||
| 	self.table = trigger_table or {} | ||||
| 	return self | ||||
| end | ||||
|  | ||||
| function utilities.with_http_timeout(timeout, fun) | ||||
| 	local original = HTTP.TIMEOUT | ||||
| 	HTTP.TIMEOUT = timeout | ||||
| 	fun() | ||||
| 	HTTP.TIMEOUT = original | ||||
| end | ||||
|  | ||||
| function utilities.enrich_user(user) | ||||
| 	user.id_str = tostring(user.id) | ||||
| 	user.name = build_name(user.first_name, user.last_name) | ||||
| 	user.name = utilities.build_name(user.first_name, user.last_name) | ||||
| 	return user | ||||
| end | ||||
|  | ||||
| enrich_message = function(msg) | ||||
| function utilities.enrich_message(msg) | ||||
| 	if not msg.text then msg.text = msg.caption or '' end | ||||
| 	msg.text_lower = msg.text:lower() | ||||
| 	msg.from = enrich_user(msg.from) | ||||
| 	msg.from = utilities.enrich_user(msg.from) | ||||
| 	msg.chat.id_str = tostring(msg.chat.id) | ||||
| 	if msg.reply_to_message then | ||||
| 		if not msg.reply_to_message.text then | ||||
| 			msg.reply_to_message.text = msg.reply_to_message.caption or '' | ||||
| 		end | ||||
| 		msg.reply_to_message.text_lower = msg.reply_to_message.text:lower() | ||||
| 		msg.reply_to_message.from = enrich_user(msg.reply_to_message.from) | ||||
| 		msg.reply_to_message.from = utilities.enrich_user(msg.reply_to_message.from) | ||||
| 		msg.reply_to_message.chat.id_str = tostring(msg.reply_to_message.chat.id) | ||||
| 	end | ||||
| 	if msg.forward_from then | ||||
| 		msg.forward_from = enrich_user(msg.forward_from) | ||||
| 		msg.forward_from = utilities.enrich_user(msg.forward_from) | ||||
| 	end | ||||
| 	if msg.new_chat_participant then | ||||
| 		msg.new_chat_participant = enrich_user(msg.new_chat_participant) | ||||
| 		msg.new_chat_participant = utilities.enrich_user(msg.new_chat_participant) | ||||
| 	end | ||||
| 	if msg.left_chat_participant then | ||||
| 		msg.left_chat_participant = enrich_user(msg.left_chat_participant) | ||||
| 		msg.left_chat_participant = utilities.enrich_user(msg.left_chat_participant) | ||||
| 	end | ||||
| 	return msg | ||||
| end | ||||
|  | ||||
| function utilities.pretty_float(x) | ||||
| 	if x % 1 == 0 then | ||||
| 		return tostring(math.floor(x)) | ||||
| 	else | ||||
| 		return tostring(x) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| return utilities | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Drew
					Drew