initial commie bastard

This commit is contained in:
dupie 2015-07-02 18:15:52 -04:00
parent d65ed5e63f
commit 236c8bebdb
37 changed files with 2202 additions and 1 deletions

View File

@ -1,2 +1,3 @@
# otouto
The popular Telegram assistant bot, now on the bot API.
A plugin-wielding Telegram bot using the new API.
The latest version runs on @mokubot. v1 runs on @otouto.

79
bindings.lua Normal file
View File

@ -0,0 +1,79 @@
-- bindings.lua
-- Functions for the Telegram API.
-- Requires ssl.https ('HTTPS'), socket.url ('URL'), and a json decoder ('JSON').
-- Also requires config.BOT_API_KEY.
local BASE_URL = 'https://api.telegram.org/bot' .. config.BOT_API_KEY .. '/'
local function send_request(url)
local dat, res = HTTPS.request(url)
local tab = JSON.decode(dat)
if res ~= 200 then
print('Connection error.')
return false
end
if not tab.ok then
print(tab.description)
return false
end
return tab
end
function get_me()
local url = BASE_URL .. 'getMe'
return send_request(url)
end
function get_updates(offset)
local url = BASE_URL .. 'getUpdates'
if offset then
url = url .. '?offset=' .. offset
end
return send_request(url)
end
function send_message(chat_id, text, disable_web_page_preview, reply_to_message_id)
local url = 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'
end
if reply_to_message_id then
url = url .. '&reply_to_message_id=' .. reply_to_message_id
end
return send_request(url)
end
function send_chat_action(chat_id, action)
local url = BASE_URL .. 'sendChatAction?chat_id=' .. chat_id .. '&action=' .. action
return send_request(url)
end
function send_location(chat_id, latitude, longitude, reply_to_message_id)
local url = 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
end
return send_request(url)
end

99
bot.lua Normal file
View File

@ -0,0 +1,99 @@
-- bot.lua
-- Run this!
HTTP = require('socket.http')
HTTPS = require('ssl.https')
JSON = require('dkjson')
URL = require('socket.url')
VERSION = 2.01
function on_msg_receive(msg)
if msg.date < os.time() -5 then return end -- don't react to old messages
if not msg.text then return end -- don't react to media messages
if msg.forward_from then return end -- don't react to forwarded messages
local lower = string.lower(msg.text)
for i,v in pairs(plugins) do
for j,w in pairs(v.triggers) do
if string.match(lower, w) then
send_chat_action(msg.chat.id, 'typing')
v.action(msg)
end
end
end
end
function bot_init()
print('\nLoading configuration...')
local jstr = io.open('config.json')
local jstr = jstr:read('*all')
config = JSON.decode(jstr)
print(#config.plugins .. ' plugins enabled.')
require('bindings')
require('utilities')
print('\nFetching bot information...')
bot = get_me().result
for k,v in pairs(bot) do
print('',k,v)
end
print('Bot information retrieved!\n')
print('Loading plugins...')
plugins = {}
for i,v in ipairs(config.plugins) do
print('',v)
local p = loadfile('plugins/'..v)()
table.insert(plugins, p)
end
print('Done! Plugins loaded: ' .. #plugins .. '\n')
print('Generating help message...')
help_message = 'Available commands:\n'
for i,v in ipairs(plugins) do
if v.doc then
local a = string.sub(v.doc, 1, string.find(v.doc, '\n')-1)
print(a)
help_message = help_message .. ' - ' .. a .. '\n'
end
end
help_message = help_message .. [[
*Arguments: <required> [optional]
Use "!help <command>" for specific information.
otouto v]] .. VERSION .. [[ by @topkecleon.
]]
print('Help message generated!\n')
is_started = true
end
bot_init()
reminders = {}
last_update = 0
while is_started == true do
for i,v in ipairs(get_updates(last_update).result) do
if v.update_id > last_update then
last_update = v.update_id
on_msg_receive(v.message)
end
end
for k,v in pairs(reminders) do
if os.time() > v.alarm then
send_message(v.chat_id, 'Reminder: '..v.text)
table.remove(reminders, i)
end
end
end

40
config.json Normal file
View File

@ -0,0 +1,40 @@
{
"BOT_API_KEY": "",
"ADMIN_ID": 0,
"BIBLIA_API_KEY": "",
"GIPHY_API_KEY": "",
"TIME_OFFSET": 0,
"plugins": [
"8ball.lua",
"admin.lua",
"bandersnatch.lua",
"bible.lua",
"btc.lua",
"calc.lua",
"commit.lua",
"dice.lua",
"dogify.lua",
"echo.lua",
"fortune.lua",
"gImages.lua",
"giphy.lua",
"gMaps.lua",
"gSearch.lua",
"hackernews.lua",
"help.lua",
"hex.lua",
"imdb.lua",
"personality.lua",
"pokedex.lua",
"reddit.lua",
"remind.lua",
"shrug.lua",
"slap.lua",
"time.lua",
"urbandictionary.lua",
"weather.lua",
"whoami.lua",
"xkcd.lua"
]
}

20
plugin.lua Normal file
View File

@ -0,0 +1,20 @@
local PLUGIN = {}
PLUGIN.doc = [[
!example
Info about the command.
]]
PLUGIN.triggers = {
'^!example',
'^!e$'
}
function PLUGIN.action(msg)
local message = 'Example output.'
send_msg(msg, message)
end
return PLUGIN

54
plugins/8ball.lua Normal file
View File

@ -0,0 +1,54 @@
local PLUGIN = {}
PLUGIN.doc = [[
!8ball
Magic 8-ball. Returns a standard 8ball message, unless called with "y/n", where it will return a less verbose answer.
]]
PLUGIN.triggers = {
'^!helix',
'^!8ball',
'y/n%p?$'
}
PLUGIN.answers = {
"It is certain.",
"It is decidedly so.",
"Without a doubt.",
"Yes, definitely.",
"You may rely on it.",
"As I see it, yes.",
"Most likely.",
"Outlook: good.",
"Yes.",
"Signs point to yes.",
"Reply hazy try again.",
"Ask again later.",
"Better not tell you now.",
"Cannot predict now.",
"Concentrate and ask again.",
"Don't count on it.",
"My reply is no.",
"My sources say no.",
"Outlook: not so good.",
"Very doubtful.",
"There is a time and place for everything, but not now."
}
PLUGIN.yesno = {'Absolutely.', 'In your dreams.', 'Yes.', 'No.', 'Maybe.'}
function PLUGIN.action(msg)
math.randomseed(os.time())
if string.match(string.lower(msg.text), 'y/n') then
message = PLUGIN.yesno[math.random(#PLUGIN.yesno)]
else
message = PLUGIN.answers[math.random(#PLUGIN.answers)]
end
send_msg(msg, message)
end
return PLUGIN

39
plugins/admin.lua Normal file
View File

@ -0,0 +1,39 @@
local PLUGIN = {}
PLUGIN.triggers = {
'^!admin '
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
local message = 'Command not found.'
if msg.from.id ~= config.ADMIN_ID then
message = 'Permission denied.'
elseif string.lower(first_word(input)) == 'run' then
local output = string.sub(input, 5)
local output = io.popen(output)
message = output:read('*all')
output:close()
elseif string.lower(first_word(input)) == 'reload' then
bot_init()
message = 'Bot reloaded!'
elseif string.lower(first_word(input)) == 'halt' then
is_started = false
message = 'Shutting down...'
end
send_msg(msg, message)
end
return PLUGIN

33
plugins/bandersnatch.lua Normal file
View File

@ -0,0 +1,33 @@
local PLUGIN = {}
PLUGIN.doc = [[
!bandersnatch
This is a Benedict Cumberbatch name generator.
]]
PLUGIN.triggers = {
'^!bandersnatch',
'^!bc$'
}
PLUGIN.fullnames = { "Wimbledon Tennismatch", "Rinkydink Curdlesnoot", "Butawhiteboy Cantbekhan", "Benadryl Claritin", "Bombadil Rivendell", "Wanda's Crotchfruit", "Biblical Concubine", "Syphilis Cankersore", "Buckminster Fullerene", "Bourgeoisie Capitalist" }
PLUGIN.firstnames = { "Bumblebee", "Bandersnatch", "Broccoli", "Rinkydink", "Bombadil", "Boilerdang", "Bandicoot", "Fragglerock", "Muffintop", "Congleton", "Blubberdick", "Buffalo", "Benadryl", "Butterfree", "Burberry", "Whippersnatch", "Buttermilk", "Beezlebub", "Budapest", "Boilerdang", "Blubberwhale", "Bumberstump", "Bulbasaur", "Cogglesnatch", "Liverswort", "Bodybuild", "Johnnycash", "Bendydick", "Burgerking", "Bonaparte", "Bunsenburner", "Billiardball", "Bukkake", "Baseballmitt", "Blubberbutt", "Baseballbat", "Rumblesack", "Barister", "Danglerack", "Rinkydink", "Bombadil", "Honkytonk", "Billyray", "Bumbleshack", "Snorkeldink", "Anglerfish", "Beetlejuice", "Bedlington", "Bandicoot", "Boobytrap", "Blenderdick", "Bentobox", "Anallube", "Pallettown", "Wimbledon", "Buttercup", "Blasphemy", "Snorkeldink", "Brandenburg", "Barbituate", "Snozzlebert", "Tiddleywomp", "Bouillabaisse", "Wellington", "Benetton", "Bendandsnap", "Timothy", "Brewery", "Bentobox", "Brandybuck", "Benjamin", "Buckminster", "Bourgeoisie", "Bakery", "Oscarbait", "Buckyball", "Bourgeoisie", "Burlington", "Buckingham", "Barnoldswick" }
PLUGIN.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" }
function PLUGIN.action(msg)
math.randomseed(os.time())
local message = ''
if math.random(10) == 10 then
message = PLUGIN.fullnames[math.random(#PLUGIN.fullnames)]
else
message = PLUGIN.firstnames[math.random(#PLUGIN.firstnames)] .. ' ' .. PLUGIN.lastnames[math.random(#PLUGIN.lastnames)]
end
send_msg(msg, message)
end
return PLUGIN

32
plugins/bible.lua Normal file
View File

@ -0,0 +1,32 @@
local PLUGIN = {}
PLUGIN.doc = [[
!bible <verse>
Returns a verse from the bible, King James Version. Use a standard or abbreviated reference (John 3:16, Jn3:16).
http://biblia.com
]]
PLUGIN.triggers = {
'^!bible',
'^!b '
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
local url = 'http://api.biblia.com/v1/bible/content/KJV.txt?key=' .. config.BIBLIA_API_KEY .. '&passage=' .. URL.escape(input)
local message, res = HTTP.request(url)
if res ~= 200 then
message = 'Connection error.'
end
send_msg(msg, message)
end
return PLUGIN

55
plugins/btc.lua Normal file
View File

@ -0,0 +1,55 @@
local PLUGIN = {}
PLUGIN.doc = [[
!btc <currency> [amount]
Gives bitcoin prices for the given currency, and optionally conversion of an amount to and from that currency.
BitcoinAverage Price Index https://bitcoinaverage.com/
]]
PLUGIN.triggers = {
'^!btc'
}
function PLUGIN.action(msg)
local url = nil
local arg1 = 'USD'
local arg2 = 1
local jstr, res = HTTPS.request('https://api.bitcoinaverage.com/ticker/global/')
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
local jdat = JSON.decode(jstr)
if string.len(msg.text) > 6 then
arg1 = string.upper(string.sub(msg.text, 6, 8))
end
if string.len(msg.text) > 9 then
arg2 = tonumber(string.sub(msg.text, 10))
end
for k,v in pairs(jdat) do
if k == arg1 then
url = v .. '/'
break
end
end
if url then
jstr, b = HTTPS.request(url)
else
return send_msg(msg, 'Error: Currency not found.')
end
jdat = JSON.decode(jstr)
local m = arg2 .. ' BTC = ' .. jdat['24h_avg']*arg2 ..' '.. arg1 .. '\n'
m = m .. arg2 ..' '.. arg1 .. ' = ' .. string.format("%.8f", arg2/jdat['24h_avg']) .. ' BTC'
send_msg(msg, m)
end
return PLUGIN

30
plugins/calc.lua Normal file
View File

@ -0,0 +1,30 @@
local PLUGIN = {}
PLUGIN.doc = [[
!calc <expression>
This command solves math expressions and does conversion between common units. See mathjs.org/docs/expressions/syntax for a list of accepted syntax.
]]
PLUGIN.triggers = {
'^!calc'
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
local url = 'http://api.mathjs.org/v1/?expr=' .. URL.escape(input)
local message, res = HTTP.request(url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
send_msg(msg, message)
end
return PLUGIN

420
plugins/commit.lua Normal file
View File

@ -0,0 +1,420 @@
local PLUGIN = {}
PLUGIN.doc = [[
!commit
http://whatthecommit.com.
]]
PLUGIN.triggers = {
'^!commit'
}
function PLUGIN.action(msg)
math.randomseed(os.time())
send_msg(msg, PLUGIN.commits[math.random(#PLUGIN.commits)])
end
PLUGIN.commits = {
"One does not simply merge into master",
"Merging the merge",
"Another bug bites the dust",
"de-misunderestimating",
"Some shit.",
"add actual words",
"I CAN HAZ COMMENTZ.",
"giggle.",
"Whatever.",
"Finished fondling.",
"FONDLED THE CODE",
"this is how we generate our shit.",
"unh",
"It works!",
"unionfind is no longer being molested.",
"Well, it's doing something.",
"I'M PUSHING.",
"Whee.",
"Whee, good night.",
"It'd be nice if type errors caused the compiler to issue a type error",
"Fucking templates.",
"I hate this fucking language.",
"marks",
"that coulda been bad",
"hoo boy",
"It was the best of times, it was the worst of times",
"Fucking egotistical bastard. adds expandtab to vimrc",
"if you're not using et, fuck off",
"WHO THE FUCK CAME UP WITH MAKE?",
"This is a basic implementation that works.",
"By works, I meant 'doesnt work'. Works now..",
"Last time I said it works? I was kidding. Try this.",
"Just stop reading these for a while, ok..",
"Give me a break, it's 2am. But it works now.",
"Make that it works in 90% of the cases. 3:30.",
"Ok, 5am, it works. For real.",
"FOR REAL.",
"I don't know what these changes are supposed to accomplish but somebody told me to make them.",
"I don't get paid enough for this shit.",
"fix some fucking errors",
"first blush",
"So my boss wanted this button ...",
"uhhhhhh",
"forgot we're not using a smart language",
"include shit",
"To those I leave behind, good luck!",
"things occurred",
"i dunno, maybe this works",
"8==========D",
"No changes made",
"whooooooooooooooooooooooooooo",
"clarify further the brokenness of C++. why the fuck are we using C++?",
".",
"Friday 5pm",
"changes",
"A fix I believe, not like I tested or anything",
"Useful text",
"pgsql is being a pain",
"pgsql is more strict, increase the hackiness up to 11",
"c&p fail",
"syntax",
"fix",
"just shoot me",
"arrrggghhhhh fixed!",
"someone fails and it isn't me",
"totally more readable",
"better grepping",
"fix",
"fix bug, for realz",
"fix /sigh",
"Does this work",
"MOAR BIFURCATION",
"bifurcation",
"REALLY FUCKING FIXED",
"FIX",
"better ignores",
"More ignore",
"more ignores",
"more ignores",
"more ignores",
"more ignores",
"more ignores",
"more ignored words",
"more fixes",
"really ignore ignored worsd",
"fixes",
"/sigh",
"fix",
"fail",
"pointless limitation",
"omg what have I done?",
"added super-widget 2.0.",
"tagging release w.t.f.",
"I can't believe it took so long to fix this.",
"I must have been drunk.",
"This is why the cat shouldn't sit on my keyboard.",
"This is why git rebase is a horrible horrible thing.",
"ajax-loader hotness, oh yeah",
"small is a real HTML tag, who knew.",
"WTF is this.",
"Do things better, faster, stronger",
"Use a real JS construct, WTF knows why this works in chromium.",
"Added a banner to the default admin page. Please have mercy on me =(",
"needs more cow bell",
"Switched off unit test X because the build had to go out now and there was no time to fix it properly.",
"Updated",
"I must sleep... it's working... in just three hours...",
"I was wrong...",
"Completed with no bugs...",
"Fixed a little bug...",
"Fixed a bug in NoteLineCount... not seriously...",
"woa!! this one was really HARD!",
"Made it to compile...",
"changed things...",
"touched...",
"i think i fixed a bug...",
"perfect...",
"Moved something to somewhere... goodnight...",
"oops, forgot to add the file",
"Corrected mistakes",
"oops",
"oops!",
"put code that worked where the code that didn't used to be",
"Nothing to see here, move along",
"I am even stupider than I thought",
"I don't know what the hell I was thinking.",
"fixed errors in the previous commit",
"Committed some changes",
"Some bugs fixed",
"Minor updates",
"Added missing file in previous commit",
"bug fix",
"typo",
"bara bra grejjor",
"Continued development...",
"Does anyone read this? I'll be at the coffee shop accross the street.",
"That's just how I roll",
"work in progress",
"minor changes",
"some brief changes",
"assorted changes",
"lots and lots of changes",
"another big bag of changes",
"lots of changes after a lot of time",
"LOTS of changes. period",
"Test commit. Please ignore",
"I'm just a grunt. Don't blame me for this awful PoS.",
"I did it for the lulz!",
"I'll explain this when I'm sober .. or revert it",
"Obligatory placeholder commit message",
"A long time ago, in a galaxy far far away...",
"Fixed the build.",
"various changes",
"One more time, but with feeling.",
"Handled a particular error.",
"Fixed unnecessary bug.",
"Removed code.",
"Added translation.",
"Updated build targets.",
"Refactored configuration.",
"Locating the required gigapixels to render...",
"Spinning up the hamster...",
"Shovelling coal into the server...",
"Programming the flux capacitor",
"The last time I tried this the monkey didn't survive. Let's hope it works better this time.",
"I should have had a V8 this morning.",
"640K ought to be enough for anybody",
"pay no attention to the man behind the curtain",
"a few bits tried to escape, but we caught them",
"Who has two thumbs and remembers the rudiments of his linear algebra courses? Apparently, this guy.",
"workaround for ant being a pile of fail",
"Don't push this commit",
"rats",
"squash me",
"fixed mistaken bug",
"Final commit, ready for tagging",
"-m \'So I hear you like commits ...\'",
"epic",
"need another beer",
"Well the book was obviously wrong.",
"lolwhat?",
"Another commit to keep my CAN streak going.",
"I cannot believe that it took this long to write a test for this.",
"TDD: 1, Me: 0",
"Yes, I was being sarcastic.",
"Apparently works-for-me is a crappy excuse.",
"tl;dr",
"I would rather be playing SC2.",
"Crap. Tonight is raid night and I am already late.",
"I know what I am doing. Trust me.",
"You should have trusted me.",
"Is there an award for this?",
"Is there an achievement for this?",
"I'm totally adding this to epic win. +300",
"This really should not take 19 minutes to build.",
"fixed the israeli-palestinian conflict",
"SHIT ===> GOLD",
"Committing in accordance with the prophecy.",
"It compiles! Ship it!",
"LOL!",
"Reticulating splines...",
"SEXY RUSSIAN CODES WAITING FOR YOU TO CALL",
"s/import/include/",
"extra debug for stuff module",
"debug line test",
"debugo",
"remove debug<br/>all good",
"debug suff",
"more debug... who overwrote!",
"these confounded tests drive me nuts",
"For great justice.",
"QuickFix.",
"oops - thought I got that one.",
"removed echo and die statements, lolz.",
"somebody keeps erasing my changes.",
"doh.",
"pam anderson is going to love me.",
"added security.",
"arrgghh... damn this thing for not working.",
"jobs... steve jobs",
"and a comma",
"this is my quickfix branch and i will use to do my quickfixes",
"Fix my stupidness",
"and so the crazy refactoring process sees the sunlight after some months in the dark!",
"gave up and used tables.",
"[Insert your commit message here. Be sure to make it descriptive.]",
"Removed test case since code didn't pass QA",
"removed tests since i can't make them green",
"stuff",
"more stuff",
"Become a programmer, they said. It'll be fun, they said.",
"Same as last commit with changes",
"foo",
"just checking if git is working properly...",
"fixed some minor stuff, might need some additional work.",
"just trolling the repo",
"All your codebase are belong to us.",
"Somebody set up us the bomb.",
"should work I guess...",
"To be honest, I do not quite remember everything I changed here today. But it is all good, I tell ya.",
"well crap.",
"herpderp (redux)",
"herpderp",
"Derp",
"derpherp",
"Herping the derp",
"sometimes you just herp the derp so hard it herpderps",
"Derp. Fix missing constant post rename",
"Herping the fucking derp right here and now.",
"Derp, asset redirection in dev mode",
"mergederp",
"Derp search/replace fuckup",
"Herpy dooves.",
"Derpy hooves",
"derp, helper method rename",
"Herping the derp derp (silly scoping error)",
"Herp derp I left the debug in there and forgot to reset errors.",
"Reset error count between rows. herpderp",
"hey, what's that over there?!",
"hey, look over there!",
"It worked for me...",
"Does not work.",
"Either Hot Shit or Total Bollocks",
"Arrrrgggg",
"Dont mess with Voodoo",
"I expected something different.",
"Todo!!!",
"This is supposed to crash",
"No changes after this point.",
"I know, I know, this is not how Im supposed to do it, but I can't think of something better.",
"Dont even try to refactor it.",
"(c) Microsoft 1988",
"Please no changes this time.",
"Why The Fuck?",
"We should delete this crap before shipping.",
"Shit code!",
"ALL SORTS OF THINGS",
"Herpderp, shoulda check if it does really compile.",
"I CAN HAZ PYTHON, I CAN HAZ INDENTS",
"Major fixup.",
"less french words",
"breathe, =, breathe",
"IEize",
"this doesn't really make things faster, but I tried",
"this should fix it",
"forgot to save that file",
"Glue. Match sticks. Paper. Build script!",
"Argh! About to give up :(",
"Blaming regex.",
"oops",
"it's friday",
"yo recipes",
"Not sure why",
"lol digg",
"grrrr",
"For real, this time.",
"Feed. You. Stuff. No time.",
"I don't give a damn 'bout my reputation",
"DEAL WITH IT",
"commit",
"tunning",
"I really should've committed this when I finished it...",
"It's getting hard to keep up with the crap I've trashed",
"I honestly wish I could remember what was going on here...",
"I must enjoy torturing myself",
"For the sake of my sanity, just ignore this...",
"That last commit message about silly mistakes pales in comparision to this one",
"My bad",
"Still can't get this right...",
"Nitpicking about alphabetizing methods, minor OCD thing",
"Committing fixes in the dark, seriously, who killed my power!?",
"You can't see it, but I'm making a very angry face right now",
"Fix the fixes",
"It's secret!",
"Commit committed....",
"No time to commit.. My people need me!",
"Something fixed",
"I'm hungry",
"asdfasdfasdfasdfasdfasdfadsf",
"hmmm",
"formatted all",
"Replace all whitespaces with tabs.",
"s/ / /g",
"I'm too foo for this bar",
"Things went wrong...",
"??! what the ...",
"This solves it.",
"Working on tests (haha)",
"fixed conflicts (LOL merge -s ours; push -f)",
"last minute fixes.",
"fuckup.",
"Revert \"fuckup\".",
"should work now.",
"final commit.",
"done. going to bed now.",
"buenas those-things.",
"Your commit is writing checks your merge can't cash.",
"This branch is so dirty, even your mom can't clean it.",
"wip",
"Revert \"just testing, remember to revert\"",
"bla",
"harharhar",
"restored deleted entities just to be sure",
"added some filthy stuff",
"bugger",
"lol",
"oopsie B|",
"Copy pasta fail. still had a instead of a",
"Now added delete for real",
"grmbl",
"move your body every every body",
"Trying to fake a conflict",
"And a commit that I don't know the reason of...",
"ffs",
"that's all folks",
"Fucking submodule bull shit",
"apparently i did something…",
"bump to 0.0.3-dev:wq",
"pep8 - cause I fell like doing a barrel roll",
"pep8 fixer",
"it is hump day _^_",
"happy monday _ bleh _",
"after of this commit remember do a git reset hard",
"someday I gonna kill someone for this shit...",
"magic, have no clue but it works",
"I am sorry",
"dirty hack, have a better idea ?",
"Code was clean until manager requested to fuck it up",
" - Temporary commit.",
":(:(",
"...",
"GIT :/",
"stopped caring 10 commits ago",
"Testing in progress ;)",
"Fixed Bug",
"Fixed errors",
"Push poorly written test can down the road another ten years",
"commented out failing tests",
"I'm human",
"TODO: write meaningful commit message",
"Pig",
"SOAP is a piece of shit",
"did everything",
"project lead is allergic to changes...",
"making this thing actually usable.",
"I was told to leave it alone, but I have this thing called OCD, you see",
"Whatever will be, will be 8{",
"It's 2015; why are we using ColdFusion?!",
"#GrammarNazi",
"Future self, please forgive me and don't hit me with the baseball bat again!",
"Hide those navs, boi!",
"Who knows...",
"Who knows WTF?!",
"I should get a raise for this.",
"Done, to whoever merges this, good luck.",
"Not one conflict, today was a good day.",
"First Blood",
"Fixed the fuck out of #526!",
"I'm too old for this shit!",
"One little whitespace gets its very own commit! Oh, life is so erratic!"
}
return PLUGIN

71
plugins/dice.lua Normal file
View File

@ -0,0 +1,71 @@
local PLUGIN = {}
PLUGIN.doc = [[
!roll [range]
Roll a die. Use any positive number for range or use D&D notation.
Example: !roll 4D100 will roll a 100-sided die four times.
]]
PLUGIN.triggers = {
'^!roll'
}
function PLUGIN.action(msg)
math.randomseed(os.time())
local input = get_input(msg.text)
if not input then
input = 6
else
input = string.upper(input)
end
if tonumber(input) then
range = tonumber(input)
rolls = 1
elseif string.find(input, 'D') then
local dloc = string.find(input, 'D')
if dloc == 1 then
rolls = 1
else
rolls = string.sub(input, 1, dloc-1)
end
range = string.sub(input, dloc+1)
if not tonumber(rolls) or not tonumber(range) then
return send_msg(msg, 'Invalid syntax.')
end
else
return send_msg(msg, 'Invalid syntax.')
end
if tonumber(rolls) == 1 then
results = 'Random (1-' .. range .. '):\t'
elseif tonumber(rolls) > 1 then
results = rolls .. 'D' .. range .. ':\n'
else
return send_msg(msg, 'Invalid syntax.')
end
if tonumber(range) < 2 then
return send_msg(msg, 'Invalid syntax.')
end
if tonumber(rolls) > 100 then
return send_msg(msg, 'Maximum dice is 100.')
end
if tonumber(range) > 100000 then
return send_msg(msg, 'Maximum range is 100000.')
end
for i = 1, tonumber(rolls) do
results = results .. math.random(range) .. '\t'
end
send_msg(msg, results)
end
return PLUGIN

28
plugins/dogify.lua Normal file
View File

@ -0,0 +1,28 @@
local PLUGIN = {}
PLUGIN.doc = [[
!dogify <lines/separatedby/slashes>
Produces a doge image from dogr.io. Newlines are indicated by a forward slash. Words do not need to be spaced, but spacing is supported. Will post a previewed link rather than an image.
]]
PLUGIN.triggers = {
'^!doge ',
'^!dogify '
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
local input = string.gsub(input, ' ', '')
url = 'http://dogr.io/' .. input .. '.png'
send_message(msg.chat.id, url, false, msg.message_id)
end
return PLUGIN

23
plugins/echo.lua Normal file
View File

@ -0,0 +1,23 @@
local PLUGIN = {}
PLUGIN.doc = [[
!echo <text>
Repeat a string.
]]
PLUGIN.triggers = {
'^!echo'
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
send_msg(msg, latcyr(input))
end
return PLUGIN

22
plugins/fortune.lua Normal file
View File

@ -0,0 +1,22 @@
local PLUGIN = {}
PLUGIN.doc = [[
!fortune
Get a random fortune from the UNIX fortune program.
]]
PLUGIN.triggers = {
'^!fortune',
'^!f$'
}
function PLUGIN.action(msg)
local output = io.popen('fortune')
message = ''
for l in output:lines() do
message = message .. l .. '\n'
end
send_msg(msg, message)
end
return PLUGIN

67
plugins/gImages.lua Normal file
View File

@ -0,0 +1,67 @@
local PLUGIN = {}
PLUGIN.doc = [[
!images <query>
This command performs a Google Images search for the given query. One random top result is returned. Safe search is enabled by default; use '!insfw' to get potentially NSFW results.
]]
PLUGIN.triggers = {
'^!images?',
'^!img',
'^!i ',
'^!insfw'
}
PLUGIN.exts = {
'.png$',
'.jpg$',
'.jpeg$',
'.jpe$',
'.gif$'
}
function PLUGIN.action(msg)
local url = 'http://ajax.googleapis.com/ajax/services/search/images?v=1.0&rsz=8'
if not string.match(msg.text, '^!insfw ') then
url = url .. '&safe=active'
end
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
url = url .. '&q=' .. URL.escape(input)
local jstr, res = HTTP.request(url)
if res ~= 200 then
send_msg(target, 'Connection error.', ok_cb, false)
return
end
local jdat = JSON.decode(jstr)
if #jdat.responseData.results < 1 then
send_msg(target, 'No results found.', ok_cb, false)
return
end
is_real = false
while is_real == false do
local i = math.random(#jdat.responseData.results)
result_url = jdat.responseData.results[i].url
for i,v in pairs(PLUGIN.exts) do
if string.match(string.lower(result_url), v) then
is_real = true
end
end
end
send_message(msg.chat.id, result_url, false, msg.message_id)
end
return PLUGIN

40
plugins/gMaps.lua Normal file
View File

@ -0,0 +1,40 @@
local PLUGIN = {}
PLUGIN.doc = [[
!loc <location>
Sends location data for query, taken from Google Maps. Works for countries, cities, landmarks, etc.
]]
PLUGIN.triggers = {
'^!loc'
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
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 send_msg(msg, 'Connection error.')
end
local jdat = JSON.decode(jstr)
if jdat.status ~= 'OK' then
local message = 'Error: \"' .. input .. '\" not found.'
return send_msg(msg, message)
end
local lat = jdat.results[1].geometry.location.lat
local lng = jdat.results[1].geometry.location.lng
send_location(msg.chat.id, lat, lng, msg.message_id)
end
return PLUGIN

57
plugins/gSearch.lua Normal file
View File

@ -0,0 +1,57 @@
local PLUGIN = {}
PLUGIN.doc = [[
!google <query>
This command performs a Google search for the given query. Four results are returned. Safe search is enabled by default; use '!gnsfw' to get potentially NSFW results. Four results are returned for a group chat, or eight in a private message.
]]
PLUGIN.triggers = {
'^!g ',
'^!google',
'^!gnsfw'
}
function PLUGIN.action(msg)
local url = 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0'
if not string.match(msg.text, '^!gnsfw ') then
url = url .. '&safe=active'
end
if not msg.chat.title then
url = url .. '&rsz=8'
end
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
url = url .. '&q=' .. URL.escape(input)
local jstr, res = HTTP.request(url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
local jdat = JSON.decode(jstr)
if #jdat.responseData.results < 1 then
return send_msg(msg, 'No results found.')
end
message = ''
for i = 1, #jdat.responseData.results do
local result_url = jdat.responseData.results[i].unescapedUrl
local result_title = jdat.responseData.results[i].titleNoFormatting
message = message .. ' - ' .. result_title ..'\n'.. result_url .. '\n'
end
send_msg(msg, message)
end
return PLUGIN

53
plugins/giphy.lua Normal file
View File

@ -0,0 +1,53 @@
local PLUGIN = {}
PLUGIN.doc = [[
!giphy [query]
Returns a random or search-resulted GIF from giphy.com. Results are limited to PG-13 by default; use '!gifnsfw' to get potentially NSFW results.
]]
PLUGIN.triggers = {
'^!giphy',
'^!gifnsfw'
}
function PLUGIN.action(msg)
local search_url = 'http://api.giphy.com/v1/gifs/search?limit=10&api_key=' .. config.GIPHY_API_KEY
local random_url = 'http://tv.giphy.com/v1/gifs/random?api_key=' .. config.GIPHY_API_KEY
local result_url = ''
if string.match(msg.text, '^!giphynsfw') then
search_url = search_url .. '&rating=r&q='
random_url = random_url .. '&rating=r'
else
search_url = search_url .. '&rating=pg-13&q='
random_url = random_url .. '&rating=pg-13'
end
local input = get_input(msg.text)
if not input then
local jstr, res = HTTP.request(random_url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
local jdat = JSON.decode(jstr)
result_url = jdat.data.image_url
else
local jstr, res = HTTP.request(search_url .. input)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
local jdat = JSON.decode(jstr)
result_url = jdat.data[math.random(#jdat.data)].images.original.url
end
send_message(msg.chat.id, result_url, false, msg.message_id)
end
return PLUGIN

35
plugins/hackernews.lua Normal file
View File

@ -0,0 +1,35 @@
local PLUGIN = {}
PLUGIN.doc = [[
!hackernews
Returns some top stories from Hacker News. Four in a group or eight in a private message.
]]
PLUGIN.triggers = {
'^!hackernews',
'^!hn$'
}
function PLUGIN.action(msg)
local message = ''
local jstr = HTTPS.request('https://hacker-news.firebaseio.com/v0/topstories.json')
local stories = JSON.decode(jstr)
local limit = 4
if msg.chat.id == msg.from.id then
limit = 8
end
for i = 1, limit do
url = 'https://hacker-news.firebaseio.com/v0/item/'..stories[i]..'.json'
jstr = HTTPS.request(url)
jdat = JSON.decode(jstr)
message = message .. jdat.title .. '\n' .. jdat.url .. '\n'
end
send_msg(msg, message)
end
return PLUGIN

38
plugins/help.lua Normal file
View File

@ -0,0 +1,38 @@
local PLUGIN = {}
PLUGIN.doc = [[
!help [command]
Get list of basic information for all commands, or more detailed documentation on a specified command.
]]
PLUGIN.triggers = {
'^!help',
'^!h$'
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if input then
for i,v in ipairs(plugins) do
if v.doc then
if '!' .. input == trim_string(first_word(v.doc)) then
return send_msg(msg, v.doc)
end
end
end
end
if msg.from.id ~= msg.chat.id then
if not send_message(msg.from.id, help_message, true, msg.message_id) then
return send_msg(msg, help_message) -- Unable to PM user who hasn't PM'd first.
end
return send_msg(msg, 'I have sent you the requested information in a private message.')
else
return send_msg(msg, help_message)
end
end
return PLUGIN

29
plugins/hex.lua Normal file
View File

@ -0,0 +1,29 @@
local PLUGIN = {}
PLUGIN.doc = [[
!hex <number>
This function converts a number to or from hexadecimal.
]]
PLUGIN.triggers = {
'^!hex '
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if string.sub(input, 1, 2) == '0x' then
send_msg(msg, tonumber(input))
elseif tonumber(input) then
send_msg(msg, string.format('%x', input))
else
send_msg(msg, 'Invalid number.')
end
end
return PLUGIN

40
plugins/imdb.lua Normal file
View File

@ -0,0 +1,40 @@
local PLUGIN = {}
PLUGIN.doc = [[
!imdb <movie | TV series>
This function retrieves the IMDb info for a given film or television series, including the year, genre, imdb rating, runtime, and a summation of the plot.
]]
PLUGIN.triggers = {
'^!imdb'
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
local url = 'http://www.imdbapi.com/?t=' .. URL.escape(input)
local jstr, res = HTTP.request(url)
local jdat = JSON.decode(jstr)
if res ~= 200 then
return send_msg(msg, 'Error connecting to server.')
end
if jdat.Response ~= 'True' then
return send_msg(msg, jdat.Error)
end
local message = jdat.Title ..' ('.. jdat.Year ..')\n'
message = message .. jdat.imdbRating ..' | '.. jdat.Runtime ..' | '.. jdat.Genre ..'\n'
message = message .. jdat.Plot .. '\n'
message = message .. 'http://imdb.com/title/' .. jdat.imdbID
send_msg(msg, message)
end
return PLUGIN

38
plugins/personality.lua Normal file
View File

@ -0,0 +1,38 @@
local PLUGIN = {}
PLUGIN.triggers = {
'otouto%p?$',
'^tadaima%p?$',
'^i\'m home%p?$',
'^i\'m back%p?$'
}
function PLUGIN.action(msg) -- I WISH LUA HAD PROPER REGEX SUPPORT
local input = string.lower(msg.text)
for i = 2, #PLUGIN.triggers do
if string.match(input, PLUGIN.triggers[i]) then
return send_message(msg.chat.id, 'Welcome back, ' .. msg.from.first_name .. '!')
end
end
if input:match('thanks,? otouto') or input:match('thank you,? otouto') then
return send_message(msg.chat.id, 'No problem, ' .. msg.from.first_name .. '!')
end
if input:match('hello,? otouto') or input:match('hey,? otouto') or input:match('hi,? otouto') then
return send_message(msg.chat.id, 'Hi, ' .. msg.from.first_name .. '!')
end
if input:match('i hate you,? otouto') or input:match('screw you,? otouto') or input:match('fuck you,? otouto') then
return send_msg(msg, '; _ ;')
end
if string.match(input, 'i love you,? otouto') then
return send_msg(msg, '<3')
end
end
return PLUGIN

57
plugins/pokedex.lua Normal file
View File

@ -0,0 +1,57 @@
local PLUGIN = {}
PLUGIN.doc = [[
!dex <pokemon>
Get Pokedex information for a given Pokemon.
Includes national ID number, type, height, weight, and a description from a random regional dex.
]]
PLUGIN.triggers = {
'^!dex'
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
local base_url = 'http://pokeapi.co'
local poke_type = nil
local dex_url = base_url .. '/api/v1/pokemon/' .. input
local dex_jstr, res = HTTP.request(dex_url)
if res ~= 200 then
return send_msg(msg, 'Pokemon not found..')
end
local dex_jdat = JSON.decode(dex_jstr)
local desc_url = base_url .. dex_jdat.descriptions[math.random(#dex_jdat.descriptions)].resource_uri
local desc_jstr, res = HTTP.request(desc_url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
local desc_jdat = JSON.decode(desc_jstr)
for k,v in pairs(dex_jdat.types) do
local type_name = v.name:gsub("^%l", string.upper)
if not poke_type then
poke_type = type_name
else
poke_type = poke_type .. ' / ' .. type_name
end
end
poke_type = poke_type .. ' type'
local info_line = 'Height: ' .. dex_jdat.height/10 .. 'm, Weight: ' .. dex_jdat.weight/10 .. 'kg'
local m = dex_jdat.name ..' #'.. dex_jdat.national_id ..'\n'.. poke_type ..'\n'.. info_line ..'\n'.. desc_jdat.description:gsub('POKMON', 'POKeMON')
send_msg(msg, m)
end
return PLUGIN

142
plugins/pun.lua Normal file
View File

@ -0,0 +1,142 @@
local PLUGIN = {}
PLUGIN.doc = [[
!pun
Get a random pun.
Have a recommendation? PM @topkecleon.
]]
PLUGIN.triggers = {
'^!pun'
}
PLUGIN.puns = {
"The person who invented the door-knock won the No-bell prize.",
"I couldn't work out how to fasten my seatbelt. Then it clicked.",
"Never trust atoms; they make up everything.",
"Singing in the shower is all fun and games until you get shampoo in your mouth - Then it becomes a soap opera.",
"I can't believe I got fired from the calendar factory. All I did was take a day off.",
"To the guy who invented zero: Thanks for nothing!",
"Enough with the cripple jokes! I just can't stand them.",
"I've accidentally swallowed some Scrabble tiles. My next crap could spell disaster.",
"How does Moses make his tea? Hebrews it.",
"Did you hear about the guy who got hit in the head with a can of soda? He was lucky it was a soft drink.",
"When William joined the army he disliked the phrase 'fire at will'.",
"There was a sign on the lawn at a rehab center that said 'Keep off the Grass'.",
"I wondered why the baseball was getting bigger. Then it hit me.",
"I can hear music coming out of my printer. I think the paper's jamming again.",
"I have a few jokes about unemployed people, but none of them work",
"Want to hear a construction joke? I'm working on it",
"I always take a second pair of pants when I go golfing, in case I get a hole in one.",
"I couldn't remember how to throw a boomerang, but then it came back to me.",
"I've decided that my wifi will be my valentine. IDK, we just have this connection.",
"A prisoner's favorite punctuation mark is the period. It marks the end of his sentence.",
"I used to go fishing with Skrillex, but he kept dropping the bass.",
"Two antennae met on a roof and got married. The wedding was okay, but the reception was incredible.",
"A book just fell on my head. I've only got my shelf to blame.",
"I dropped my steak on the floor. Now it's ground beef.",
"I used to have a fear of hurdles, but I got over it.",
"The outcome of war does not prove who is right, but only who is left.",
"Darth Vader tries not to burn his food, but it always comes out a little on the dark side.",
"The store keeps calling me to buy more furniture, but all I wanted was a one night stand.",
"This girl said she recognized me from the vegetarian club, but I'd never met herbivore.",
"Police arrested two kids yesterday, one was drinking battery acid, the other was eating fireworks. They charged one and let the other one off...",
"No more Harry Potter jokes guys. I'm Sirius.",
"It was hard getting over my addiction to hokey pokey, but I've turned myself around.",
"It takes a lot of balls to golf the way I do.",
"Why did everyone want to hang out with the mushroom? Because he was a fungi.",
"How much does a hipster weigh? An instagram.",
"I used to be addicted to soap, but I'm clean now.",
"When life gives you melons, youre probably dyslexic.",
"What's with all the blind jokes? I just don't see the point.",
"If Apple made a car, would it have Windows?",
"Need an ark? I Noah guy.",
"The scarecrow won an award because he was outstanding in his field.",
"What's the difference between a man in a tux on a bicycle, and a man in a sweatsuit on a trycicle? A tire.",
"What do you do with a sick chemist? If you can't helium, and you can't curium, you'll just have to barium.",
"I'm reading a book about anti-gravity. It's impossible to put down.",
"Trying to write with a broken pencil is pointless.",
"When TVs go on vacation, they travel to remote islands.",
"I was going to tell a midget joke, but it's too short.",
"Jokes about German sausage are the wurst.",
"How do you organize a space party? You planet.",
"Sleeping comes so naturally to me, I could do it with my eyes closed.",
"I'm glad I know sign language; it's pretty handy.",
"Atheism is a non-prophet organization.",
"Velcro: What a rip-off!",
"If they made a Minecraft movie, it would be a blockbuster.",
"I don't trust people with graph paper. They're always plotting something",
"I had a friend who was addicted to brake fluid. He says he can stop anytime.",
"The form said I had Type A blood, but it was a Type O.",
"I went to to the shop to buy eight Sprites - I came home and realised I'd picked 7Up.",
"There was an explosion at a pie factory. 3.14 people died.",
"A man drove his car into a tree and found out how a Mercedes bends.",
"The experienced carpenter really nailed it, but the new guy screwed everything up.",
"I didn't like my beard at first, but then it grew on me.",
"Smaller babies may be delivered by stork, but the heavier ones need a crane.",
"What's the definition of a will? It's a dead giveaway.",
"I was going to look for my missing watch, but I could never find the time.",
"I hate elevators, and I often take steps to avoid them.",
"Did you hear about the guy whose whole left side was cut off? He's all right now.",
"It's not that the man did not know how to juggle, he just didn't have the balls to do it.",
"I used to be a loan shark, but I lost interest",
"I don't trust these stairs; they're always up to something.",
"My friend's bakery burned down last night. Now his business is toast.",
"Don't trust people that do acupuncture; they're back stabbers.",
"The man who survived mustard gas and pepper spray is now a seasoned veteran.",
"Police were called to a daycare where a three-year-old was resisting a rest.",
"When Peter Pan punches, they Neverland",
"The shoemaker did not deny his apprentice anything he needed. He gave him his awl.",
"I did a theatrical performance about puns. It was a play on words.",
"Show me a piano falling down a mineshaft and I'll show you A-flat minor.",
"Have you ever tried to eat a clock? It's very time consuming.",
"There was once a cross-eyed teacher who couldn't control his pupils.",
"A new type of broom came out and it is sweeping the nation.",
"I relish the fact that you've mustard the strength to ketchup to me.",
"I knew a woman who owned a taser. Man, was she stunning!",
"What did the grape say when it got stepped on? Nothing - but it let out a little whine.",
"It was an emotional wedding. Even the cake was in tiers.",
"When a clock is hungry it goes back four seconds.",
"The dead batteries were given out free of charge.",
"Why are there no knock-knock jokes about America? Because freedom rings.",
"When the cannibal showed up late to dinner, they gave him the cold shoulder.",
"I should have been sad when my flashlight died, but I was delighted.",
"Why don't tennis players ever get marries? Love means nothing to them.",
"Pterodactyls can't be heard going to the bathroom because the P is silent.",
"Mermaids make calls on their shell phones.",
"What do you call an aardvark with three feet? A yaardvark.",
"Captain Kirk has three ears: A right ear, a left ear, and a final front ear.",
"How do celebrities stay cool? They have a lot of fans.",
"Without geometry, life is pointless.",
"Did you hear about the cow who tried to jump over a barbed-wire fence? It ended in udder destruction.",
"The truth may ring like a bell, but it is seldom ever tolled.",
"I used to work for the IRS, but my job was too taxing.",
"I used to be a programmer, but then I lost my drive.",
"Pediatricians are doctors with little patients.",
"I finally fired my masseuse today. She always rubbed me the wrong way.",
"I stayed up all night wondering where the sun went. Then it dawned on me.",
"What's the difference between a man and his dog? The man wears a suit; the dog just pants.",
"A psychic midget who escapes from prison is a small medium at large.",
"I've been to the dentist several times, so I know the drill.",
"The roundest knight at King Arthur's round table was Sir Cumference. He acquired his size from too much pi.",
"She was only a whiskey maker, but he loved her still.",
"Male deer have buck teeth.",
"Whiteboards are remarkable.",
"Visitors in Cuba are always Havana good time.",
"Why does electricity shock people? It doesn't know how to conduct itself.",
"Lancelot had a scary dream about his horse. It was a knight mare.",
"A tribe of cannibals caught a missionary and ate him. Afterward, they all had violent food poisoning. This just goes to show that you can't keep a good man down.",
"Heaven for gamblers is a paradise.",
"Old wheels aren't thrown away, they're just retired.",
"Horses are very stable animals.",
"Banks don't crash, they just lose their balance.",
"The career of a skier can go downhill very fast.",
"In democracy, it's your vote that counts. In feudalism, it's your count that votes."
}
function PLUGIN.action(msg)
math.randomseed(os.time())
send_msg(msg, PLUGIN.puns[math.random(#PLUGIN.puns)])
end
return PLUGIN

84
plugins/reddit.lua Normal file
View File

@ -0,0 +1,84 @@
local PLUGIN = {}
PLUGIN.doc = [[
!reddit [r/subreddit | query]
This command returns top results for a given query or subreddit. NSFW posts are marked as such.
]]
PLUGIN.triggers = {
'^!reddit',
'^!r$',
'^!r '
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
local jdat = {}
local message = ''
if input then
if string.match(input, '^r/') then
local url = 'http://www.reddit.com/' .. first_word(input) .. '/.json'
local jstr, res = HTTP.request(url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
jdat = JSON.decode(jstr)
if #jdat.data.children == 0 then
return send_msg(msg, 'Subreddit not found.')
end
else
local url = 'http://www.reddit.com/search.json?q=' .. URL.escape(input)
local jstr, res = HTTP.request(url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
jdat = JSON.decode(jstr)
if #jdat.data.children == 0 then
return send_msg(msg, 'No results found.')
end
end
else
url = 'https://www.reddit.com/.json'
local jstr, res = HTTP.request(url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
jdat = JSON.decode(jstr)
end
local limit = 4
if #jdat.data.children < limit then
limit = #jdat.data.children
end
for i = 1, limit do
if jdat.data.children[i].data.over_18 then
message = message .. '[NSFW] '
end
url = '\n'
if not jdat.data.children[i].data.is_self then
url = '\n' .. jdat.data.children[i].data.url .. '\n'
end
local short_url = '[redd.it/' .. jdat.data.children[i].data.id .. '] '
message = message .. short_url .. jdat.data.children[i].data.title .. url
end
send_msg(msg, message)
end
return PLUGIN

55
plugins/remind.lua Normal file
View File

@ -0,0 +1,55 @@
local PLUGIN = {}
PLUGIN.doc = [[
!remind <delay> <message>
Set a reminder for yourself. First argument is the number of minutes until you wish to be reminded.
]]
PLUGIN.triggers = {
'^!remind$',
'^!remind '
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
local delay = first_word(input)
if not tonumber(delay) then
return send_msg(msg, 'The delay must be a number.')
end
if string.len(msg.text) <= string.len(delay) + 9 then
return send_msg(msg, 'Please include a reminder.')
end
local text = string.sub(msg.text, string.len(delay)+10) -- this is gross
if msg.from.username then
text = text .. '\n@' .. msg.from.username
end
local delay = tonumber(delay)
local reminder = {
alarm = os.time() + (delay * 60),
chat_id = msg.chat.id,
text = text
}
table.insert(reminders, reminder)
if delay <= 1 then
delay = (delay * 60) .. ' seconds'
else
delay = delay .. ' minutes'
end
local message = 'Your reminder has been set for ' .. delay .. ' from now:\n' .. text
send_msg(msg, message)
end
return PLUGIN

12
plugins/shrug.lua Normal file
View File

@ -0,0 +1,12 @@
local PLUGIN = {}
PLUGIN.triggers = {
'^!shrug',
'/shrug'
}
function PLUGIN.action(msg)
send_msg(msg, '¯\\_(ツ)_/¯')
end
return PLUGIN

116
plugins/slap.lua Normal file
View File

@ -0,0 +1,116 @@
local PLUGIN = {}
PLUGIN.doc = [[
!slap [victim]
Slap someone!
]]
PLUGIN.triggers = {
'^!slap'
}
function PLUGIN.getSlap(slapper, victim)
slaps = {
victim .. " was shot by " .. slapper .. ".",
victim .. " was pricked to death.",
victim .. " walked into a cactus while trying to escape " .. slapper .. ".",
victim .. " drowned.",
victim .. " drowned whilst trying to escape " .. slapper .. ".",
victim .. " blew up.",
victim .. " was blown up by " .. slapper .. ".",
victim .. " hit the ground too hard.",
victim .. " fell from a high place.",
victim .. " fell off a ladder.",
victim .. " fell into a patch of cacti.",
victim .. " was doomed to fall by " .. slapper .. ".",
victim .. " was blown from a high place by " .. slapper .. ".",
victim .. " was squashed by a falling anvil.",
victim .. " went up in flames.",
victim .. " burned to death.",
victim .. " was burnt to a crisp whilst fighting " .. slapper .. ".",
victim .. " walked into a fire whilst fighting " .. slapper .. ".",
victim .. " tried to swim in lava.",
victim .. " tried to swim in lava while trying to escape " .. slapper .. ".",
victim .. " was struck by lightning.",
victim .. " was slain by " .. slapper .. ".",
victim .. " got finished off by " .. slapper .. ".",
victim .. " was killed by magic.",
victim .. " was killed by " .. slapper .. " using magic.",
victim .. " starved to death.",
victim .. " suffocated in a wall.",
victim .. " fell out of the world.",
victim .. " was knocked into the void by " .. slapper .. ".",
victim .. " withered away.",
victim .. " was pummeled by " .. slapper .. ".",
victim .. " was fragged by " .. slapper .. ".",
victim .. " was desynchronized.",
victim .. " was wasted.",
victim .. " was busted by " .. slapper .. ".",
victim .. "'s bones are scraped clean by the desolate wind.",
victim .. " has died of dysentery.",
victim .. " fainted.",
victim .. " is out of usable Pokemon! " .. victim .. " whited out!",
victim .. " is out of usable Pokemon! " .. victim .. " blacked out!",
victim .. " whited out!",
victim .. " blacked out!",
victim .. " says goodbye to this cruel world.",
victim .. " got rekt.",
victim .. " was sawn in half by " .. slapper .. ".",
victim .. " died. I blame " .. slapper .. ".",
victim .. " was axe-murdered by " .. slapper .. ".",
victim .. "'s melon was split by " .. slapper .. ".",
victim .. " was slice and diced by " .. slapper .. ".",
victim .. " was split from crotch to sternum by " .. slapper .. ".",
victim .. "'s death put another notch in " .. slapper .. "'s axe.",
victim .. " died impossibly!",
victim .. " died from " .. slapper .. "'s mysterious tropical disease.",
victim .. " escaped infection by dying.",
victim .. " played hot-potato with a grenade.",
victim .. " was knifed by " .. slapper .. ".",
victim .. " fell on his sword.",
victim .. " ate a grenade.",
victim .. " practiced being " .. slapper .. "'s clay pigeon.",
victim .. " is what's for dinner!",
victim .. " was terminated by " .. slapper .. ".",
victim .. " was shot before being thrown out of a plane.",
victim .. " was not invincible.",
victim .. " has encountered an error.",
victim .. " died and reincarnated as a goat.",
slapper .. " threw " .. victim .. " off a building.",
victim .. " is sleeping with the fishes.",
victim .. " got a premature burial.",
slapper .. " replaced all of " .. victim .. "'s music with Nickelback.",
slapper .. " spammed " .. victim .. "'s email.",
slapper .. " made " .. victim .. " a knuckle sandwich.",
slapper .. " slapped " .. victim .. " with pure nothing.",
slapper .. " hit " .. victim .. " with a small, interstellar spaceship.",
victim .. " was quickscoped by " .. slapper .. ".",
slapper .. " put " .. victim .. " in check-mate.",
slapper .. " encrypted " .. victim .. " and deleted the private key.",
slapper .. " put " .. victim .. " in the friendzone.",
slapper .. " slaps " .. victim .. " with a DMCA takedown request!",
victim .. " became a corpse blanket for " .. slapper .. ".",
"Death is when the monsters get you. Death comes for " .. victim .. ".",
"Cowards die many times before their death. " .. victim .. " never tasted death but once."
}
return slaps[math.random(#slaps)]
end
function PLUGIN.action(msg)
math.randomseed(os.time())
local victim = get_input(msg.text)
if victim then
slapper = msg.from.first_name
else
victim = msg.from.first_name
slapper = 'otouto'
end
local message = PLUGIN.getSlap(slapper, victim)
send_message(target, message)
end
return PLUGIN

41
plugins/time.lua Normal file
View File

@ -0,0 +1,41 @@
local PLUGIN = {}
PLUGIN.doc = [[
!time <location>
Sends the time and timezone for a given location.
]]
PLUGIN.triggers = {
'^!time'
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
coords = get_coords(input)
if not coords then
local message = 'Error: \"' .. input .. '\" not found.'
return send_msg(msg, message)
end
local url = 'http://maps.googleapis.com/maps/api/timezone/json?location=' .. coords.lat ..','.. coords.lon .. '&timestamp='..os.time()
local jstr, res = HTTPS.request(url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
local jdat = JSON.decode(jstr)
local timestamp = os.time() + jdat.rawOffset + jdat.dstOffset + config.TIME_OFFSET
timestamp = os.date("%H:%M on %A, %B %d.", timestamp)
local timeloc = (string.gsub((string.sub(jdat.timeZoneId, string.find(jdat.timeZoneId, '/')+1)), '_', ' '))
local message = "The time in " .. timeloc .. " is " .. timestamp
send_msg(msg, message)
end
return PLUGIN

View File

@ -0,0 +1,42 @@
local PLUGIN = {}
PLUGIN.doc = [[
!ud <term>
Returns the first definition for a given term from Urban Dictionary.
]]
PLUGIN.triggers = {
'^!ud',
'^!urbandictionary'
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
local url = 'http://api.urbandictionary.com/v0/define?term=' .. URL.escape(input)
local jstr, res = HTTP.request(url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
local jdat = JSON.decode(jstr)
if jdat.result_type == "no_results" then
return send_msg(msg, 'No results found.')
end
message = '"' .. jdat.list[1].word .. '"\n' .. trim_string(jdat.list[1].definition)
if string.len(jdat.list[1].example) > 0 then
message = message .. '\n\nExample:\n' .. trim_string(jdat.list[1].example)
end
send_msg(msg, message)
end
return PLUGIN

41
plugins/weather.lua Normal file
View File

@ -0,0 +1,41 @@
local PLUGIN = {}
PLUGIN.doc = [[
!weather <location>
Returns the current temperature and weather conditions for a specified location.
Non-city locations are accepted; "!weather Buckingham Palace" will return the weather for Westminster.
]]
PLUGIN.triggers = {
'^!weather'
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
if not input then
return send_msg(msg, PLUGIN.doc)
end
coords = get_coords(input)
if not coords then
local message = 'Error: \"' .. input .. '\" not found.'
return send_msg(msg, message)
end
local url = 'http://api.openweathermap.org/data/2.5/weather?lat=' .. coords.lat .. '&lon=' .. coords.lon
local jstr, res = HTTP.request(url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
local jdat = JSON.decode(jstr)
local celsius = jdat.main.temp - 273.15
local fahrenheit = tonumber(string.format("%.2f", celsius * (9/5) + 32))
local message = jdat.name .. ': ' .. celsius .. '°C / ' .. fahrenheit .. '°F, ' .. jdat.weather[1].description .. '.'
send_msg(msg, message)
end
return PLUGIN

37
plugins/whoami.lua Normal file
View File

@ -0,0 +1,37 @@
local PLUGIN = {}
PLUGIN.doc = [[
!whoami
Get the user ID for yourself and the group.
]]
PLUGIN.triggers = {
'^!whoami',
'^!ping',
'^/ping'
}
function PLUGIN.action(msg)
local from_name = msg.from.first_name
if msg.from.last_name then
from_name = from_name .. ' ' .. msg.from.last_name
end
if msg.from.username then
from_name = '@' .. msg.from.username .. ', AKA ' .. from_name
end
from_name = from_name .. ' (' .. msg.from.id .. ')'
if msg.from.id == msg.chat.id then
to_name = '@' .. bot.username .. ' (' .. bot.id .. ')'
else
to_name = string.gsub(msg.chat.title, '_', ' ') .. ' (' .. string.gsub(msg.chat.id, '-', '') .. ')'
end
local message = 'You are ' .. from_name .. ' and you are messaging ' .. to_name .. '.'
send_msg(msg, message)
end
return PLUGIN

47
plugins/xkcd.lua Normal file
View File

@ -0,0 +1,47 @@
local PLUGIN = {}
PLUGIN.doc = [[
!xkcd [search]
This command returns an xkcd strip, its number, and its "secret" text. You may search for a specific strip or get a random one.
]]
PLUGIN.triggers = {
'^!xkcd'
}
function PLUGIN.action(msg)
local input = get_input(msg.text)
local url = 'http://xkcd.com/info.0.json'
local jstr, res = HTTP.request(url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
local latest = JSON.decode(jstr).num
if input then
url = 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&safe=active&q=site%3axkcd%2ecom%20' .. URL.escape(input)
local jstr, res = HTTP.request(url)
if res ~= 200 then
print('here')
return send_msg(msg, 'Connection error.')
end
url = JSON.decode(jstr).responseData.results[1].url .. 'info.0.json'
else
math.randomseed(os.time())
url = 'http://xkcd.com/' .. math.random(latest) .. '/info.0.json'
end
local jstr, res = HTTP.request(url)
if res ~= 200 then
return send_msg(msg, 'Connection error.')
end
local jdat = JSON.decode(jstr)
local message = '[' .. jdat.num .. '] ' .. jdat.alt .. '\n' .. jdat.img
send_message(msg.chat.id, message, false, msg.message_id)
end
return PLUGIN

84
utilities.lua Normal file
View File

@ -0,0 +1,84 @@
-- utilities.lua
-- Functions shared among plugins.
function first_word(str, idx) -- get the indexed word in a string
str = string.gsub(str, '\n', ' ')
if not string.find(str, ' ') then return str end
str = str .. ' '
if not idx then idx = 1 end
if idx ~= 1 then
for i = 2, idx do
str = string.sub(str, string.find(str, ' ') + 1)
end
end
str = string.sub(str, 1, string.find(str, ' '))
return string.sub(str, 1, -2)
end
function get_input(text) -- returns string or false
if not string.find(text, ' ') then
return false
end
return string.sub(text, string.find(text, ' ')+1)
end
function trim_string(text) -- another alias
return string.gsub(text, "^%s*(.-)%s*$", "%1")
end
local lc_list = {
-- Latin = 'Cyrillic'
['A'] = 'А',
['B'] = 'В',
['C'] = 'С',
['E'] = 'Е',
['I'] = 'І',
['J'] = 'Ј',
['K'] = 'К',
['M'] = 'М',
['H'] = 'Н',
['O'] = 'О',
['P'] = 'Р',
['S'] = 'Ѕ',
['T'] = 'Т',
['X'] = 'Х',
['Y'] = 'Ү',
['a'] = 'а',
['c'] = 'с',
['e'] = 'е',
['i'] = 'і',
['j'] = 'ј',
['o'] = 'о',
['s'] = 'ѕ',
['x'] = 'х',
['y'] = 'у',
['!'] = 'ǃ'
}
function latcyr(str)
for k,v in pairs(lc_list) do
str = string.gsub(str, k, v)
end
return str
end
function send_msg(msg, message)
send_message(msg.chat.id, message, true, msg.message_id)
end
function 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 false
end
local jdat = JSON.decode(jstr)
if jdat.status == 'ZERO_RESULTS' then
return false
end
return { lat = jdat.results[1].geometry.location.lat, lon = jdat.results[1].geometry.location.lng }
end