Merge branch 'release/1.2'

This commit is contained in:
neersighted 2012-04-02 10:01:58 -07:00
commit 950aa9e5a9
78 changed files with 2200 additions and 955 deletions

4
.gitignore vendored
View file

@ -1,7 +1,11 @@
persist persist
config config
gitflow
*.db *.db
*.log *.log
.*.swp .*.swp
*.pyc *.pyc
*.orig *.orig
.project
.pydevproject
.geany

View file

@ -1 +1 @@
Please see the wiki @ http://git.io/cloudbotwiki Please see the wiki @ http://git.io/cloudbotircwiki

View file

@ -1,4 +1,4 @@
# CloudBot/1.1d # CloudBot/1.2
## About ## About
@ -25,13 +25,13 @@ Unzip the resulting file, and continue to read this document.
## Install ## Install
Before you can run the bot, you need to install a few Python modules. These are `lXML`, `BeautifulSoup`, `MyGengo`, and `HTTPlib2`. These can be installed with PIP (The Python package manager): Before you can run the bot, you need to install a few Python modules. These are `lXML`, `BeautifulSoup`, `psutil`, and `HTTPlib2`. These can be installed with PIP (The Python package manager):
`sudo pip install lxml` `sudo pip install lxml`
`sudo pip install beautifulsoup` `sudo pip install beautifulsoup`
`sudo pip install mygengo` `sudo pip install psutil`
`sudo pip install httplib2` `sudo pip install httplib2`
@ -55,7 +55,7 @@ For the wrapper to work best, install `screen`, or `daemon`:
If you are a user of another Linux disto, use your package manager to install the dependencies, or, for other operating systems, use **Google** to locate source packages you can install. If you are a user of another Linux disto, use your package manager to install the dependencies, or, for other operating systems, use **Google** to locate source packages you can install.
Once you have installed the required dependencies, run the bot: Once you have installed the required dependencies, run the bot¹:
`./cloudbot start` `./cloudbot start`
@ -87,22 +87,22 @@ They can both be found in [#CloudBot](irc://irc.esper.net/cloudbot "Connect via
**mau5bot** is the stable bot, and runs on the latest release version of CloudBot. (mau5bot is running on **Ubuntu Server** *Oneric Ocelot/11.10* with **Python** *2.7.2*) **mau5bot** is the stable bot, and runs on the latest release version of CloudBot. (mau5bot is running on **Ubuntu Server** *Oneric Ocelot/11.10* with **Python** *2.7.2*)
**neerbot** is the unstable bot, and runs on the latest development☩☩ version of CloudBot. (neerbot is running on **Debian** *Wheezy/Testing* with **Python** *2.7.2*) **neerbot** is the unstable bot, and runs on the latest development² version of CloudBot. (neerbot is running on **Debian** *Wheezy/Testing* with **Python** *2.7.2*)
## Requirements ## Requirements
CloudBot runs on **Python** *2.7.x*. It is developed on **Debian** *Wheezy/Testing* with **Python** *2.7.2*. CloudBot runs on **Python** *2.7.x*. It is developed on **Debian** *Wheezy/Testing* and **Ubuntu** *11.10* with **Python** *2.7.2*.
It **requires Python modules** `lXML`, `BeautifulSoup`, `Enchant`, `MyGengo`, and `HTTPlib2`. It **requires Python modules** `lXML`, `BeautifulSoup`, `Enchant`, `psutil`, and `HTTPlib2`.
The programs `screen` or `daemon` are recomended for the wrapper to run optimaly. The programs `screen` or `daemon` are recomended for the wrapper to run optimaly.
**Windows** users: Windows compatibility with the wrapper and some plugins is **broken** (such as the ping), but we do intend to add it.☩☩☩ **Windows** users: Windows compatibility with the wrapper and some plugins is **broken** (such as the ping), but we do intend to add it.³
## License ## License
CloudBot is **licensed** under the **GPL v3** license. The terms are as follows. CloudBot is **licensed** under the **GPL v3** license. The terms are as follows.
CloudBot/1.1d CloudBot/1.2
Copyright © 2011 ClouDev - <[cloudev.github.com](http://cloudev.github.com)> Copyright © 2011 ClouDev - <[cloudev.github.com](http://cloudev.github.com)>
@ -119,10 +119,10 @@ CloudBot is **licensed** under the **GPL v3** license. The terms are as follows.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with CloudBot. If not, see <http://www.gnu.org/licenses/>. along with CloudBot. If not, see <http://www.gnu.org/licenses/>.
## ## Notes
if you prefer to run the bot with a custom backend/run it manually, or are on **Windows**, run the bot with `./bot.py` ¹ if you prefer to run the bot with a custom backend/run it manually, or are on **Windows**, run the bot with `./bot.py`
☩☩ or whatever version [neersighted](http://git.io/neersighted) is currently hacking on ² or whatever version [neersighted](http://git.io/neersighted) is currently hacking on
☩☩☩ eventually ³ eventually

7
bot.py
View file

@ -13,9 +13,10 @@ os.chdir(sys.path[0] or '.') # do stuff relative to the install directory
class Bot(object): class Bot(object):
pass pass
print 'Welcome to Cloudbot - Version 1.1c - http://git.io/cloudbot' print 'Welcome to Cloudbot - Version 1.2 - http://git.io/cloudbotirc'
bot = Bot() bot = Bot()
bot.start_time = time.time()
print 'Loading plugins...' print 'Loading plugins...'
@ -28,7 +29,7 @@ config()
if not hasattr(bot, 'config'): if not hasattr(bot, 'config'):
exit() exit()
print 'Connecting to IRC' print 'Connecting to IRC...'
bot.conns = {} bot.conns = {}
@ -49,7 +50,7 @@ bot.persist_dir = os.path.abspath('persist')
if not os.path.exists(bot.persist_dir): if not os.path.exists(bot.persist_dir):
os.mkdir(bot.persist_dir) os.mkdir(bot.persist_dir)
print 'Running main loop' print 'Connection(s) made, bot online...'
while True: while True:
reload() # these functions only do things reload() # these functions only do things

View file

@ -5,7 +5,7 @@ echo " / ____/ /___ __ ______/ / __ )____ / /_"
echo " / / / / __ \/ / / / __ / __ / __ \/ __/" echo " / / / / __ \/ / / / __ / __ / __ \/ __/"
echo "/ /___/ / /_/ / /_/ / /_/ / /_/ / /_/ / /_ " echo "/ /___/ / /_/ / /_/ / /_/ / /_/ / /_/ / /_ "
echo "\____/_/\____/\__,_/\__,_/_____/\____/\__/ " echo "\____/_/\____/\__,_/\__,_/_____/\____/\__/ "
echo " http://git.io/cloudbot by lukeroge " echo " http://git.io/cloudbotirc by ClouDev "
echo "" echo ""
locatefiles() { locatefiles() {
botfile="/bot.py" botfile="/bot.py"
@ -23,10 +23,10 @@ running() {
} }
checkbackend() { checkbackend() {
if dpkg -l| grep ^ii|grep daemon|grep 'turns other' > /dev/null; then if dpkg -l| grep ^ii|grep screen|grep 'terminal multi' > /dev/null; then
backend="daemon"
elif dpkg -l| grep ^ii|grep screen|grep 'terminal multi' > /dev/null; then
backend="screen" backend="screen"
elif dpkg -l| grep ^ii|grep daemon|grep 'turns other' > /dev/null; then
backend="daemon"
else else
backend="manual" backend="manual"
fi fi
@ -77,6 +77,7 @@ processargs() {
start) start)
if running; then if running; then
echo "Cannot start! Bot is already running!" echo "Cannot start! Bot is already running!"
exit 1
else else
echo "Starting CloudBot... ($backend)" echo "Starting CloudBot... ($backend)"
start start
@ -88,15 +89,18 @@ processargs() {
stop stop
else else
echo "Cannot stop! Bot is not already running!" echo "Cannot stop! Bot is not already running!"
exit 1
fi fi
;; ;;
restart) restart)
if running; then if running; then
echo "Restarting CloudBot... ($backend)" echo "Restarting CloudBot... ($backend)"
stop stop
sleep 3
start start
else else
echo "Cannot restart! Bot is not already running!" echo "Cannot restart! Bot is not already running!"
exit 1
fi fi
;; ;;
clear) clear)
@ -107,8 +111,7 @@ processargs() {
status status
;; ;;
*) *)
echo "Please enter a command:" usage="usage: ./cloudbot {start|stop|restart|clear|status}"
usage="./cloudbot {start|stop|restart|clear|status}"
echo $usage echo $usage
;; ;;
esac esac
@ -122,3 +125,4 @@ main() {
} }
main $* main $*
exit 0

View file

@ -17,7 +17,7 @@ if not os.path.exists('config'):
"server": "irc.esper.net", "server": "irc.esper.net",
"nick": "MyNewCloudBot", "nick": "MyNewCloudBot",
"user": "cloudbot", "user": "cloudbot",
"realname": "CloudBot - http://git.io/cloudbot", "realname": "CloudBot - http://git.io/cloudbotirc",
"nickserv_password": "", "nickserv_password": "",
"channels": ["#cloudbot"], "channels": ["#cloudbot"],
"invitejoin": true, "invitejoin": true,
@ -38,14 +38,18 @@ if not os.path.exists('config'):
"bitly_api": "INSERT API KEY FROM bitly.com HERE", "bitly_api": "INSERT API KEY FROM bitly.com HERE",
"wolframalpha": "INSERT API KEY FROM wolframalpha.com HERE", "wolframalpha": "INSERT API KEY FROM wolframalpha.com HERE",
"lastfm": "INSERT API KEY FROM lastfm HERE", "lastfm": "INSERT API KEY FROM lastfm HERE",
"mc_user": "INSERT MINECRAFT USERNAME HERE", "mc_user": "INSERT minecraft USERNAME HERE",
"mc_pass": "INSERT MINECRAFT PASSWORD HERE" "mc_pass": "INSERT minecraft PASSWORD HERE"
}, },
"plugins": "plugins":
{ {
"factoids": "factoids":
{ {
"prefix": false "prefix": false
},
"ignore":
{
"ignored": []
} }
}, },
"censored_strings": "censored_strings":
@ -53,11 +57,11 @@ if not os.path.exists('config'):
"mypass", "mypass",
"mysecret" "mysecret"
], ],
"admins": ["myname"] "admins": ["myname@myhost"]
}''') + '\n') }''') + '\n')
print "Config generated!" print "Config generated!"
print "Please edit the config now!" print "Please edit the config now!"
print "For help, see http://git.io/cloudbotwiki" print "For help, see http://git.io/cloudbotircwiki"
print "Thank you for using CloudBot!" print "Thank you for using CloudBot!"
sys.exit() sys.exit()

View file

@ -163,6 +163,7 @@ class IRC(object):
else: else:
prefix, command, params = irc_noprefix_rem(msg).groups() prefix, command, params = irc_noprefix_rem(msg).groups()
nick, user, host = irc_netmask_rem(prefix).groups() nick, user, host = irc_netmask_rem(prefix).groups()
mask = user + "@" + host
paramlist = irc_param_ref(params) paramlist = irc_param_ref(params)
lastparam = "" lastparam = ""
if paramlist: if paramlist:
@ -170,7 +171,7 @@ class IRC(object):
paramlist[-1] = paramlist[-1][1:] paramlist[-1] = paramlist[-1][1:]
lastparam = paramlist[-1] lastparam = paramlist[-1]
self.out.put([msg, prefix, command, params, nick, user, host, self.out.put([msg, prefix, command, params, nick, user, host,
paramlist, lastparam]) mask, paramlist, lastparam])
if command == "PING": if command == "PING":
self.cmd("PONG", paramlist) self.cmd("PONG", paramlist)
@ -184,6 +185,9 @@ class IRC(object):
def join(self, channel): def join(self, channel):
self.cmd("JOIN", [channel]) self.cmd("JOIN", [channel])
def part(self, channel):
self.cmd("PART", [channel])
def msg(self, target, text): def msg(self, target, text):
self.cmd("PRIVMSG", [target, text]) self.cmd("PRIVMSG", [target, text])
@ -225,6 +229,7 @@ class FakeIRC(IRC):
else: else:
prefix, command, params = irc_noprefix_rem(msg).groups() prefix, command, params = irc_noprefix_rem(msg).groups()
nick, user, host = irc_netmask_rem(prefix).groups() nick, user, host = irc_netmask_rem(prefix).groups()
mask = user + "@" + host
paramlist = irc_param_ref(params) paramlist = irc_param_ref(params)
lastparam = "" lastparam = ""
if paramlist: if paramlist:
@ -232,7 +237,7 @@ class FakeIRC(IRC):
paramlist[-1] = paramlist[-1][1:] paramlist[-1] = paramlist[-1][1:]
lastparam = paramlist[-1] lastparam = paramlist[-1]
self.out.put([msg, prefix, command, params, nick, user, host, self.out.put([msg, prefix, command, params, nick, user, host,
paramlist, lastparam]) mask, paramlist, lastparam])
if command == "PING": if command == "PING":
self.cmd("PONG", [params]) self.cmd("PONG", [params])

View file

@ -7,7 +7,7 @@ thread.stack_size(1024 * 512) # reduce vm size
class Input(dict): class Input(dict):
def __init__(self, conn, raw, prefix, command, params, def __init__(self, conn, raw, prefix, command, params,
nick, user, host, paraml, msg): nick, user, host, mask, paraml, msg):
chan = paraml[0].lower() chan = paraml[0].lower()
if chan == conn.nick.lower(): # is a PM if chan == conn.nick.lower(): # is a PM
@ -25,9 +25,6 @@ class Input(dict):
else: else:
conn.msg(chan, '(' + nick + ') ' + msg) conn.msg(chan, '(' + nick + ') ' + msg)
def set_nick(nick):
conn.set_nick(nick)
def me(msg): def me(msg):
conn.msg(chan, "\x01%s %s\x01" % ("ACTION", msg)) conn.msg(chan, "\x01%s %s\x01" % ("ACTION", msg))
@ -35,10 +32,10 @@ class Input(dict):
conn.cmd('NOTICE', [nick, msg]) conn.cmd('NOTICE', [nick, msg])
dict.__init__(self, conn=conn, raw=raw, prefix=prefix, command=command, dict.__init__(self, conn=conn, raw=raw, prefix=prefix, command=command,
params=params, nick=nick, user=user, host=host, params=params, nick=nick, user=user, host=host, mask=mask,
paraml=paraml, msg=msg, server=conn.server, chan=chan, paraml=paraml, msg=msg, server=conn.server, chan=chan,
notice=notice, say=say, reply=reply, pm=pm, bot=bot, notice=notice, say=say, reply=reply, pm=pm, bot=bot,
me=me, set_nick=set_nick, lastparam=paraml[-1]) me=me, lastparam=paraml[-1])
# make dict keys accessible as attributes # make dict keys accessible as attributes
def __getattr__(self, key): def __getattr__(self, key):

View file

@ -51,21 +51,21 @@ autorepastes = {}
#@hook.regex('(pastebin\.com)(/[^ ]+)') #@hook.regex('(pastebin\.com)(/[^ ]+)')
@hook.regex('(mibpaste\.com)(/[^ ]+)') @hook.regex('(mibpaste\.com)(/[^ ]+)')
def autorepaste(inp, input=None, db=None, chan=None): def autorepaste(inp, input=None, notice=None, db=None, chan=None, nick=None):
db_init(db) db_init(db)
manual = input.db.execute("select manual from repaste where chan=?", (chan, )).fetchone() manual = db.execute("select manual from repaste where chan=?", (chan, )).fetchone()
if manual and len(manual) and manual[0]: if manual and len(manual) and manual[0]:
return return
url = inp.group(1) + inp.group(2) url = inp.group(1) + inp.group(2)
urllib.unquote(url) urllib.unquote(url)
if url in autorepastes: if url in autorepastes:
out = autorepastes[url] out = autorepastes[url]
input.notice("In the future, please use a less awful pastebin (e.g. pastebin.com)") notice("In the future, please use a less awful pastebin (e.g. pastebin.com)")
else: else:
out = repaste("http://" + url, input, db, False) out = repaste("http://" + url, input, db, False)
autorepastes[url] = out autorepastes[url] = out
input.notice("In the future, please use a less awful pastebin (e.g. pastebin.com) instead of %s." % inp.group(1)) notice("In the future, please use a less awful pastebin (e.g. pastebin.com) instead of %s." % inp.group(1))
input.say("%s (repasted for %s)" % (out, input.nick)) input.say("%s (repasted for %s)" % (out, nick))
scrapers = { scrapers = {

View file

@ -4,7 +4,7 @@ import re
r = "\x02\x0305" # red r = "\x02\x0305" # red
g = "\x02\x0303" # green g = "\x02\x0303" # green
y = "\x02\x0308" # yellow y = "\x02" # yellow (not really)
answers = [g + "As I see it, yes", answers = [g + "As I see it, yes",
g + "It is certain", g + "It is certain",

View file

@ -1,195 +1,166 @@
# Shitty plugin made by iloveportalz0r # Plugin made by iloveportalz0r, TheNoodle, Lukeroge and neersighted
# Broken by The Noodle
# Improved by Lukeroge
# Further improved by neersighted
from util import hook from util import hook
import os import os
import re
import sys import sys
import subprocess import json
import time import time
import subprocess
@hook.command("quit", autohelp=False)
@hook.command("exit", autohelp=False)
@hook.command(autohelp=False) @hook.command(autohelp=False)
def stop(inp, input=None, db=None, notice=None): def admins(inp, notice=None, bot=None):
".stop [reason] -- Kills the bot, with [reason] as its quit message." ".admins -- Lists bot's admins."
if not input.nick in input.bot.config["admins"]: adminlist = bot.config["admins"]
notice("Only bot admins can use this command!") if adminlist:
return notice("Admins are: %s." % ", ".join(adminlist))
if inp:
input.conn.send("QUIT :Killed by " + input.nick + " (" + inp + ")")
else: else:
input.conn.send("QUIT :Killed by " + input.nick + " (no reason)") notice("No users are admins!")
return
@hook.command(adminonly=True)
def admin(inp, notice=None, bot=None, config=None):
".admin <nick|host> -- Make <nick|host> an admin."
target = inp.lower()
adminlist = bot.config["admins"]
if target in adminlist:
notice("%s is already an admin." % target)
else:
notice("%s is now an admin." % target)
adminlist.append(target)
adminlist.sort()
json.dump(bot.config, open('config', 'w'), sort_keys=True, indent=2)
return
@hook.command(adminonly=True)
def unadmin(inp, notice=None, bot=None, config=None):
".unadmin <nick|host> -- Make <nick|host> a non-admin."
target = inp.lower()
adminlist = bot.config["admins"]
if target in adminlist:
notice("%s is no longer an admin." % target)
adminlist.remove(target)
adminlist.sort()
json.dump(bot.config, open('config', 'w'), sort_keys=True, indent=2)
else:
notice("%s is not an admin." % target)
return
@hook.command(autohelp=False)
def channels(inp, conn=None):
".channels -- Lists the channels that the bot is in."
return "I am in these channels: %s" % ", ".join(conn.channels)
@hook.command("quit", autohelp=False, adminonly=True)
@hook.command(autohelp=False, adminonly=True)
def stop(inp, nick=None, conn=None):
".stop [reason] -- Kills the bot with [reason] as its quit message."
if inp:
conn.cmd("QUIT", ["Killed by %s (%s)" % (nick, inp)])
else:
conn.cmd("QUIT", ["Killed by %s." % nick])
time.sleep(5) time.sleep(5)
subprocess.call("./cloudbot stop", shell=True) os.execl("./cloudbot", "stop")
@hook.command("reboot", autohelp=False) @hook.command(autohelp=False, adminonly=True)
@hook.command(autohelp=False) def restart(inp, nick=None, conn=None):
def restart(inp, input=None, db=None, notice=None): ".restart [reason] -- Restarts the bot with [reason] as its quit message."
".restart [reason] -- Restarts the bot, with [reason] as its quit message."
if not input.nick in input.bot.config["admins"]:
notice("Only bot admins can use this command!")
return
if inp: if inp:
input.conn.send("QUIT :Restarted by " + input.nick + " (" + inp + ")") conn.cmd("QUIT", ["Restarted by %s (%s)" % (nick, inp)])
else: else:
input.conn.send("QUIT :Restarted by " + input.nick + " (no reason)") conn.cmd("QUIT", ["Restarted by %s." % nick])
time.sleep(5) time.sleep(5)
os.execl("./cloudbot", "restart") os.execl("./cloudbot", "restart")
@hook.command("clearlogs", autohelp=False)
@hook.command(autohelp=False) @hook.command(autohelp=False, adminonly=True)
def clear(inp, input=None, db=None, notice=None): def clearlogs(inp, input=None):
".clear -- Clears the bot's log(s)." ".clearlogs -- Clears the bots log(s)."
if not input.nick in input.bot.config["admins"]: subprocess.call(["./cloudbot", "clear"])
notice("Only bot admins can use this command!")
return
time.sleep(5)
subprocess.call("./cloudbot clear", shell=True)
@hook.command @hook.command(adminonly=True)
def join(inp, input=None, db=None, notice=None): def join(inp, conn=None, notice=None):
".join <channel> -- Joins <channel>." ".join <channel> -- Joins <channel>."
if not input.nick in input.bot.config["admins"]: notice("Attempting to join %s..." % inp)
notice("Only bot admins can use this command!") conn.join(inp)
return
notice("Attempting to join " + inp + "...")
input.conn.send("JOIN " + inp)
@hook.command @hook.command(adminonly=True)
def cycle(inp, input=None, db=None, notice=None): def part(inp, conn=None, notice=None):
".part <channel> -- Leaves <channel>."
notice("Attempting to part from %s..." % inp)
conn.part(inp)
@hook.command(adminonly=True)
def cycle(inp, conn=None, notice=None):
".cycle <channel> -- Cycles <channel>." ".cycle <channel> -- Cycles <channel>."
if not input.nick in input.bot.config["admins"]: notice("Attempting to cycle %s..." % inp)
notice("Only bot admins can use this command!") conn.part(inp)
return conn.join(inp)
notice("Attempting to cycle " + inp + "...")
input.conn.send("PART " + inp)
input.conn.send("JOIN " + inp)
@hook.command @hook.command(adminonly=True)
def part(inp, input=None, notice=None): def nick(inp, input=None, notice=None, conn=None):
".part <channel> -- Parts from <channel>."
if not input.nick in input.bot.config["admins"]:
notice("Only bot admins can use this command!")
return
notice("Attempting to part from " + inp + "...")
input.conn.send("PART " + inp)
@hook.command
def nick(inp, input=None, notice=None):
".nick <nick> -- Changes the bots nickname to <nick>." ".nick <nick> -- Changes the bots nickname to <nick>."
if not input.nick in input.bot.config["admins"]: if not re.match("^[A-Za-z0-9_|.-\]\[]*$", inp.lower()):
notice("Only bot admins can use this command!") notice("Invalid username!")
return return
notice("Changing nick to " + inp + ".") notice("Attempting to change nick to \"%s\"..." % inp)
input.conn.send("NICK " + inp) conn.set_nick(inp)
@hook.command @hook.command(adminonly=True)
def raw(inp, input=None, notice=None): def raw(inp, conn=None, notice=None):
".raw <command> -- Sends a RAW IRC command." ".raw <command> -- Sends a RAW IRC command."
if not input.nick in input.bot.config["admins"]:
notice("Only bot admins can use this command!")
return
notice("Raw command sent.") notice("Raw command sent.")
input.conn.send(inp) conn.send(inp)
@hook.command @hook.command(adminonly=True)
def kick(inp, input=None, notice=None): def say(inp, conn=None, chan=None, notice=None):
".kick [channel] <user> [reason] -- kicks a user."
if not input.nick in input.bot.config["admins"]:
notice("Only bot admins can use this command!")
return
split = inp.split(" ")
if split[0][0] == "#":
chan = split[0]
user = split[1]
out = "KICK %s %s" % (chan, user)
if len(split) > 2:
reason = ""
for x in split[2:]:
reason = reason + x + " "
reason = reason[:-1]
out = out + " :" + reason
else:
chan = input.chan
user = split[0]
out = "KICK %s %s" % (input.chan, split[0])
if len(split) > 1:
reason = ""
for x in split[1:]:
reason = reason + x + " "
reason = reason[:-1]
out = out + " :" + reason
notice("Attempting to kick %s from %s..." % (user, chan))
input.conn.send(out)
@hook.command
def say(inp, input=None, notice=None):
".say [channel] <message> -- Makes the bot say <message> in [channel]. "\ ".say [channel] <message> -- Makes the bot say <message> in [channel]. "\
"If [channel] is blank the bot will say the <message> in "\ "If [channel] is blank the bot will say the <message> in "\
"the channel the command was used in." "the channel the command was used in."
if not input.nick in input.bot.config["admins"]: inp = inp.split(" ")
notice("Only bot admins can use this command!") if inp[0][0] == "#":
return
split = inp.split(" ")
if split[0][0] == "#":
message = "" message = ""
for x in split[1:]: for x in inp[1:]:
message = message + x + " " message = message + x + " "
message = message[:-1] message = message[:-1]
out = "PRIVMSG %s :%s" % (split[0], message) out = "PRIVMSG %s :%s" % (inp[0], message)
else: else:
message = "" message = ""
for x in split[0:]: for x in inp[0:]:
message = message + x + " " message = message + x + " "
message = message[:-1] message = message[:-1]
out = "PRIVMSG %s :%s" % (input.chan, message) out = "PRIVMSG %s :%s" % (chan, message)
input.conn.send(out) conn.send(out)
@hook.command("me") @hook.command("act", adminonly=True)
@hook.command @hook.command(adminonly=True)
def act(inp, input=None, notice=None): def me(inp, conn=None, chan=None, notice=None):
".act [channel] <action> -- Makes the bot act out <action> in [channel] "\ ".me [channel] <action> -- Makes the bot act out <action> in [channel] "\
"If [channel] is blank the bot will act the <action> in "\ "If [channel] is blank the bot will act the <action> in "\
"the channel the command was used in." "the channel the command was used in."
if not input.nick in input.bot.config["admins"]: inp = inp.split(" ")
notice("Only bot admins can use this command!") if inp[0][0] == "#":
return
split = inp.split(" ")
if split[0][0] == "#":
message = "" message = ""
for x in split[1:]: for x in inp[1:]:
message = message + x + " " message = message + x + " "
message = message[:-1] message = message[:-1]
out = "PRIVMSG %s :\x01ACTION %s\x01" % (split[0], message) out = "PRIVMSG %s :\x01ACTION %s\x01" % (inp[0], message)
else: else:
message = "" message = ""
for x in split[0:]: for x in inp[0:]:
message = message + x + " " message = message + x + " "
message = message[:-1] message = message[:-1]
out = "PRIVMSG %s :\x01ACTION %s\x01" % (input.chan, message) out = "PRIVMSG %s :\x01ACTION %s\x01" % (chan, message)
input.conn.send(out) conn.send(out)
@hook.command
def topic(inp, input=None, notice=None):
".topic [channel] <topic> -- Change the topic of a channel."
if not input.nick in input.bot.config["admins"]:
notice("Only bot admins can use this command!")
return
split = inp.split(" ")
if split[0][0] == "#":
out = "PRIVMSG %s :%s" % (split[0], message)
else:
out = "TOPIC %s :%s" % (input.chan, message)
input.conn.send(out)

View file

@ -11,6 +11,7 @@ BUFFER_SIZE = 5000
MAX_STEPS = 1000000 MAX_STEPS = 1000000
@hook.command('brainfuck')
@hook.command @hook.command
def bf(inp): def bf(inp):
".bf <prog> -- Executes <prog> as Brainfuck code." ".bf <prog> -- Executes <prog> as Brainfuck code."

View file

@ -1,22 +1,27 @@
# Plugin by neersighted
import time
import getpass
from util import hook from util import hook
# CTCP responses # CTCP responses
@hook.regex(r'^\x01VERSION\x01$') @hook.regex(r'^\x01VERSION\x01$')
def ctcpversion(inp, notice=None): def ctcp_version(inp, notice=None):
notice('\x01VERSION: CloudBot - http://git.io/cloudbot') notice('\x01VERSION: CloudBot - http://git.io/cloudbotirc')
@hook.regex(r'^\x01PING\x01$') @hook.regex(r'^\x01PING\x01$')
def ctcpping(inp, notice=None): def ctcp_ping(inp, notice=None):
notice('\x01PING: PONG') notice('\x01PING: PONG')
@hook.regex(r'^\x01TIME\x01$') @hook.regex(r'^\x01TIME\x01$')
def ctcptime(inp, notice=None): def ctcp_time(inp, notice=None):
notice('\x01TIME: GET A WATCH') the_time = time.strftime("%r", time.localtime())
notice('\x01TIME: The time is: ' + the_time)
@hook.regex(r'^\x01FINGER\x01$') @hook.regex(r'^\x01FINGER\x01$')
def ctcpfinger(inp, notice=None): def ctcp_finger(inp, notice=None):
notice('\x01FINGER: WHERE ARE YOU PUTTING THAT') user = getpass.getuser()
notice('\x01FINGER: Username is: ' + user)

40
plugins/data/flirts.txt Executable file
View file

@ -0,0 +1,40 @@
I bet your name's Mickey, 'cause you're so fine.
Hey, pretty mama. You smell kinda pretty, wanna smell me?
I better get out my library card, 'cause I'm checkin' you out.
If you were a booger, I'd pick you.
If I could rearrange the alphabet, I would put U and I together.
I've been bad, take me to your room.
I think Heaven's missing an angel.
That shirt looks good on you, it'd look better on my bedroom floor.
I cant help to notice but you look a lot like my next girlfriend.
Aren't your feet tired? Because you've been running through my mind all day.
I must be asleep, 'cause you are a dream come true. Also, I'm slightly damp.
I like large posteriors and I cannot prevaricate.
How you doin'?
If I said you had a good body, would you hold it against me?
Hey, baby cakes.
Nice butt.
I love you like a fat kid loves cake.
Do you believe in love at first sight? Or should I walk by again...?
Want to see my good side? Hahaha, that was a trick question, all I have are good sides.
You look like a woman who appreciates the finer things in life. Come over here and feel my velour bedspread.
Now you're officially my woman. Kudos! I can't say I don't envy you.
I find that the most erotic part of a woman is the boobies.
If you want to climb aboard the Love Train, you've got to stand on the Love Tracks. But you might just get smushed by a very sensual cow-catcher.
Lets say you and I knock some very /sensual/ boots.
I lost my phone number, can I have yours?
Does this rag smell like chloroform to you?
I'm here, where are your other two wishes?
Apart from being sexy, what do you do for a living?
Hi, I'm Mr. Right. Someone said you were looking for me.
You got something on your chest: My eyes.
Are you from Tennessee? Cause you're the only TEN I see.
Are you an alien? Because you just abducted my heart.
Excuse me, but I think you dropped something!!! MY JAW!!!
If I followed you home, would you keep me?
Where have you been all my life?
I'm just a love machine, and I don't work for nobody but you.
Do you live on a chicken farm? Because you sure know how to raise cocks.
Are you wearing space pants? Because your ass is out of this world.
Nice legs. What time do they open?
Your daddy must have been a baker, because you've got a nice set of buns.

51
plugins/data/fortunes.txt Executable file
View file

@ -0,0 +1,51 @@
"Help! I'm stuck in the fortune cookie factory!
He who laughs at himself never runs out of things to laugh at.
The world is your oyster.
Today will be a good day.
Life's short, party naked.
Haters gonna hate.
You are amazing and let no one tell you otherwise.
A starship ride has been promised to you by the galactic wizard.
That wasnt chicken.
Dont fry bacon in the nude.
Take calculated risks. That is quite different from being rash.
DO THE IMPOSSIBLE, SEE THE INVISIBLE.
You cannot plough a field by turning it over in your mind. Unless you have telekinesis.
No one can make you feel inferior without your consent.
Never lose the ability to find beauty in ordinary things.
Ignore previous fortune.
Smile more.
You are the dancing queen.
YOU'RE THE BEST AROUND, NOTHIN'S GONNA EVER KEEP YA DOWN.
The cake is a lie.
Never take life seriously. Nobody gets out alive anyway.
Friendship is like peeing on yourself: everyone can see it, but only you get the warm feeling that it brings.
Never go to a doctor whose office plants have died.
Always remember you're unique, just like everyone else.
What if everything is an illusion and nothing exists? In that case, I definitely overpaid for my carpet.
Even if you are on the right track, you will get run over if you just sit there.
Think like a man of action, and act like a man of thought.
When in doubt, lubricate.
It is time for you to live up to your family name and face FULL LIFE CONSEQUENCES.
It's a good day to do what has to be done.
Move near the countryside and you will be friends of John Freeman.
If you can't beat 'em, mock 'em.
Use gun. And if that don't work, use more gun.
LOOK OUT BEHIND YOU
This message will self destruct in 10 seconds.
You'll never know what you can do until you try.
You are talented in many ways
Be both a speaker of words and a doer of deeds.
A visit to a strange place will bring you renewed perspective.
A passionate new romance will appear in your life when you least expect it.
If you care enough for a result, you will most certainly attain it.
To be loved, be loveable.
Step away from the power position for one day.
If you want to get a sure crop with a big yield, sow wild oats.
It doesn't take guts to quit.
You can expect a change for the better in job or status in the future.
As the wallet grows, so do the needs.
You have a reputation for being straightforward and honest.
Learn a new language and get a new soul.
A tall dark stranger will soon enter our life.
Keep staring. I'll do a trick.

32
plugins/data/insults.txt Executable file
View file

@ -0,0 +1,32 @@
You are the son of a motherless ogre.
Your mother was a hamster and your father smelled of elderberries.
I once owned a dog that was smarter than you.
Go climb a wall of dicks.
You fight like a dairy farmer.
I've spoken to apes more polite than you.
Go and boil your bottom! Son of a silly person!
I fart in your general direction.
Go away or I shall taunt you a second time.
Shouldn't you have a license for being that ugly?
Calling you an idiot would be an insult to all the stupid people.
Why don't you slip into something more comfortable...like a coma.
Well, they do say opposites attract...so I sincerely hope you meet somebody who is attractive, honest, intelligent, and cultured...
Are you always this stupid or are you just making a special effort today?
Yo momma so fat when she sits around the house she sits AROUND the house.
Yo momma so ugly she made an onion cry.
Is your name Maple Syrup? It should be, you sap.
Bite my shiny metal ass!
Up yours, meatbag.
Jam a bastard in it you crap!
Don't piss me off today, I'm running out of places to hide the bodies...
Why don't you go outside and play hide and go fuck yourself!
I'll use small words you're sure to understand, you warthog-faced buffoon.
You are a sad, strange little man, and you have my pity.
Sit your five dollar ass down before I make change.
What you've just said is one of the most insanely idiotic things I've ever heard. Everyone in this room is now dumber for having listened to it. May God have mercy on your soul.
Look up Idiot in the dictionary. Know what you'll find? The definition of the word IDIOT, which you are.
You're dumber than a bag of hammers.
Why don't you go back to your home on Whore Island?
If I had a dick this is when I'd tell you to suck it.
Go play in traffic.
The village called, they want their idiot back.

370
plugins/data/itemids.txt Executable file
View file

@ -0,0 +1,370 @@
// obtained from <https://github.com/blha303/skybot/commit/d4ba73d6e3f21cc60a01342f3de9d0d4abd14b3d>
// edited by Lukeroge and _frozen
// Block id
1 Stone
2 Grass Block
3 Dirt
4 Cobblestone
5 Wooden Planks
6 Sapling
7 Bedrock
8 Water
9 Water
10 Lava
11 Lava
12 Sand
13 Gravel
14 Gold Ore
15 Iron Ore
16 Coal Ore
17 Wood
18 Leaves
19 Sponge
20 Glass
21 Lapis Lazuli Ore
22 Lapis Lazuli Block
23 Dispenser
24 Sandstone
25 Note Block
26 Bed
27 Powered Rail
28 Detector Rail
29 Sticky Piston
30 Cobweb
31 Grass
32 Dead Bush
33 Piston
34 Piston Extended
35 Wool
35:1 Orange Wool
35:2 Magenta Wool
35:3 Light Blue Wool
35:4 Yellow Wool
35:5 Lime Wool
35:6 Pink Wool
35:7 Gray Wool
35:8 Light Gray Wool
35:9 Cyan Wool
35:10 Purple Wool
35:11 Blue Wool
35:12 Brown Wool
35:13 Green Wool
35:14 Red Wool
35:15 Black Wool
35:0 White Wool
36 Block Moved by Piston
37 Flower
38 Rose
39 Brown Mushroom
40 Red Mushroom
41 Block of Gold
42 Block of Iron
43 Double Slabs
44 Slabs
45 Bricks
46 TNT
47 Bookshelf
48 Moss Stone
49 Obsidian
50 Torch
51 Fire
52 Monster Spawner
53 Wooden Stairs
54 Chest
55 Redstone Dust
56 Diamond Ore
57 Block of Diamond
58 Crafting Table
59 Crops
60 Farmland
61 Furnace
62 Furnace
63 Sign
64 Wooden Door
65 Ladder
66 Rail
67 Stone Stairs
68 Sign
69 Lever
70 Pressure Plate
71 Iron Door
72 Pressure Plate
73 Redstone Ore
74 Redstone Ore
75 Redstone Torch
76 Redstone Torch
77 Button
78 Snow
79 Ice
80 Snow
81 Cactus
82 Clay
83 Sugar cane
84 Jukebox
85 Fence
86 Pumpkin
87 Netherrack
88 Soul Sand
89 Glowstone
90 Portal
91 Jack 'o' Lantern
92 Cake
93 Redstone Repeater (off)
94 Redstone Repeater (on)
95 Locked chest
96 Trapdoor
97 Hidden Silverfish
98 Stone Bricks
99 Mushroom
100 Mushroom
101 Iron Bars
102 Glass Pane
103 Melon
104 Pumpkin Stem
105 Melon Stem
106 Vines
107 Fence Gate
108 Brick Stairs
109 Stone Brick Stairs
110 Mycelium
111 Lily Pad
112 Nether Brick
113 Nether Brick Fence
114 Nether Brick Stairs
115 Nether Wart
116 Enchantment Table
117 Brewing stand
118 Cauldron
119 End Portal
120 End Portal Frame
121 End Stone
122 Dragon Egg
123 Redstone Lamp (Off)
124 Redstone Lamp (On)
// Items Ids
256 Iron Shovel
257 Iron Pickaxe
258 Iron Axe
259 Flint and Steel
260 Apple
261 Bow
262 Arrow
263 Coal
264 Diamond
265 Iron Ingot
266 Gold Ingot
267 Iron Sword
268 Wooden Sword
269 Wooden Shovel
270 Wooden Pickaxe
271 Wooden Axe
272 Stone Sword
273 Stone Shovel
274 Stone Pickaxe
275 Stone Axe
276 Diamond Sword
277 Diamond Shovel
278 Diamond Pickaxe
279 Diamond Axe
280 Stick
281 Bowl
282 Mushroom Stew
283 Golden Sword
284 Golden Shovel
285 Golden Pickaxe
286 Golden Axe
287 String
288 Feather
289 Gunpowder
290 Wooden Hoe
291 Stone Hoe
292 Iron Hoe
293 Diamond Hoe
294 Golden Hoe
295 Seeds
296 Wheat
297 Bread
298 Leather Cap
299 Leather Tunic
300 Leather Pants
301 Leather Boots
302 Chain Helmet
303 Chain Chestplate
304 Chain Leggings
305 Chain Boots
306 Iron Helmet
307 Iron Chestplate
308 Iron Leggings
309 Iron Boots
310 Diamond Helmet
311 Diamond Chestplate
312 Diamond Leggings
313 Diamond Boots
314 Golden Helmet
315 Golden Chestplate
316 Golden Leggings
317 Golden boots
318 Flint
319 Raw Porkchop
320 Cooked Porkchop
321 Painting
322 Golden Apple
323 Sign
324 Wooden Door
325 Bucket
326 Water Bucket
327 Lava bucket
328 Minecart
329 Saddle
330 Iron Door
331 Redstone
332 Snowball
333 Boat
334 Leather
335 Milk
336 Brick
337 Clay
338 Sugar Canes
339 Paper
340 Book
341 Slimeball
342 Minecart with Chest
343 Minecart with Furnace
344 Egg
345 Compass
346 Fishing Rod
347 Clock
348 Glowstone Dust
349 Raw Fish
350 Cooked Fish
351 Dye
351:0 Ink Sac
351:1 Rose Red
351:2 Cactus Green
351:3 Cocoa Beans
351:4 Lapis Lazuli
351:5 Purple Dye
351:6 Cyan Dye
351:7 Light Gray Dye
351:8 Gray Dye
351:9 Pink Dye
351:10 Lime Dye
351:11 Dandelion Yellow
351:12 Light Blue Dye
351:13 Magenta Dye
351:14 Orange Dye
351:15 Bone Meal
352 Bone
353 Sugar
354 Cake
355 Bed
356 Redstone Repeater
357 Cookie
358 Map
359 Shears
360 Melon
361 Pumpkin Seeds
362 Melon Seeds
363 Raw Beef
364 Steak
365 Raw Chicken
366 Cooked Chicken
367 Rotten Flesh
368 Ender Pearl
369 Blaze Rod
370 Ghast Tear
371 Gold Nugget
372 Nether Wart
373 Potion
373:16 Awkward Potion
373:32 Thick Potion
373:64 Mundane Potion
373:8193 Regeneration Potion (0:45)
373:8194 Swiftness Potion (3:00)
373:8195 Fire Resistance Potion (3:00)
373:8196 Poison Potion (0:45)
373:8197 Healing Potion
373:8200 Weakness Potion (1:30)
373:8201 Strength Potion (3:00)
373:8202 Slowness Potion (1:30)
373:8204 Harming Potion
373:8225 Regeneration Potion II (0:22)
373:8226 Swiftness Potion II (1:30)
373:8228 Poison Potion II (0:22)
373:8229 Healing Potion II
373:8233 Strength Potion II (1:30)
373:8236 Harming Potion II
373:8257 Regeneration Potion (2:00)
373:8258 Swiftness Potion (8:00)
373:8259 Fire Resistance Potion (8:00)
373:8260 Poison Potion (2:00)
373:8264 Weakness Potion (4:00)
373:8265 Strength Potion (8:00)
373:8266 Slowness Potion (4:00)
373:16378 Fire Resistance Splash (2:15)
373:16385 Regeneration Splash (0:33)
373:16386 Swiftness Splash (2:15)
373:16388 Poison Splash (0:33)
373:16389 Healing Splash
373:16392 Weakness Splash (1:07)
373:16393 Strength Splash (2:15)
373:16394 Slowness Splash (1:07)
373:16396 Harming Splash
373:16418 Swiftness Splash II (1:07)
373:16420 Poison Splash II (0:16)
373:16421 Healing Splash II
373:16425 Strength Splash II (1:07)
373:16428 Harming Splash II
373:16449 Regeneration Splash (1:30)
373:16450 Swiftness Splash (6:00)
373:16451 Fire Resistance Splash (6:00)
373:16452 Poison Splash (1:30)
373:16456 Weakness Splash (3:00)
373:16457 Strength Splash (6:00)
373:16458 Slowness Splash (3:00)
373:16471 Regeneration Splash II (0:16)
374 Glass Bottle
375 Spider Eye
376 Fermented Spider Eye
377 Blaze Powder
378 Magma Cream
379 Brewing Stand
380 Cauldron
381 Eye of Ender
382 Glistering Melon
383 Spawn Egg
383:50 Creeper Egg
383:51 Skeleton Egg
383:52 Spider Egg
383:54 Zombie Egg
383:55 Slime Egg
383:56 Ghast Egg
383:57 Zombie Pigman Egg
383:58 Enderman Egg
383:59 Cave Spider Egg
383:60 Silverfish Egg
383:61 Blaze Egg
383:62 Magma Cube Egg
383:90 Pig Egg
383:91 Sheep Egg
383:92 Cow Egg
383:93 Chicken Egg
383:94 Squid Egg
383:95 Wolf Egg
383:96 Mooshroom Egg
383:98 Ocelot Egg
383:120 Villager Egg
384 Bottle Of Enchanting
385 Fire Charge
// Records
2256 Music Disc 13
2257 Music Disc Cat
2258 Music Disc Blocks
2259 Music Disc Chirp
2260 Music Disc Far
2261 Music Disc Mall
2262 Music Disc Mellohi
2263 Music Disc Stal
2264 Music Disc Strad
2265 Music Disc Ward
2266 Music Disc 11

View file

@ -0,0 +1,9 @@
head
arms
legs
arm
leg
toes
fingers
"special parts"
"man bits"

22
plugins/data/kills.txt Executable file
View file

@ -0,0 +1,22 @@
rips off <who>'s <body> and leaves them to die.
grabs <who>'s head and rips it clean off their body.
grabs a machine gun and riddles <who>'s body with bullets.
sends The Terminator on a mission to retrieve <who>'s <body>.
gags and ties <who> then throws them off a bridge.
crushes <who> with a huge spiked boulder.
glares at <who> until they die of boredom.
stuffs a few TNT blocks under <who>'s bed and sets them off.
shivs <who> in the <body>.
rams a rocket launcher up <who>'s ass and lets off a few rounds.
crushes <who>'s skull in with a spiked mace.
unleashes the armies of Isengard on <who>.
slices <who>'s <body> off with a Katana.
throws <who> to Cthulu and watches them get ripped to shreads.
feeds <who> to an owlbear, who proceeds to maul them.
turns <who> into a snail and salts them.
snacks on <who>'s <body>.
puts <who> into a sack, throws the sack in the river, and hurls the river into space.
goes bowling with <who>'s disembodied head.
uses <who>'s <body> as a back-scratcher.
sends <who> to /dev/null!
feeds <who> coke and mentos till they violently explode.

105
plugins/data/larts.txt Executable file
View file

@ -0,0 +1,105 @@
swaps <who>'s shampoo with glue.
installs Windows on <who>'s computer.
forces <who> to use perl for 3 weeks.
registers <who>'s name with 50 known spammers.
resizes <who>'s console to 40x24.
takes <who>'s drink.
dispenses <who>'s email address to a few hundred 'bulk mailing services'.
pokes <who> in the eye.
beats <who> senseless with a 50lb Linux manual.
cats /dev/random into <who>'s ear.
signs <who> up for AOL.
downvotes <who> on Reddit.
enrolls <who> in Visual Basic 101.
sporks <who>.
drops a truckload of support tickets on <who>.
judo chops <who>.
sets <who>'s resolution to 800x600.
formats <who>'s harddrive to fat12.
rm -rf's <who>.
stabs <who>.
makes <who> learn C++.
steals <who>'s mojo.
strangles <who> with a doohicky mouse cord.
whacks <who> with the cluebat.
sells <who> on EBay.
drops creepers on <who>'s house.
throws all of <who>'s diamond gear into lava.
uses <who> as a biological warfare study.
uses the 'Customer Appreciation Bat' on <who>.
puts <who> in the Total Perspective Vortex.
casts <who> into the fires of Mt. Doom.
gives <who> a melvin.
turns <who> over to the Fun Police.
turns over <who> to Agent Smith to be 'bugged'.
takes away <who>'s internet connection.
pushes <who> past the Shoe Event Horizon.
counts '1, 2, 5... er... 3!' and hurls the Holy Handgrenade Of Antioch at <who>.
puts <who> in a nest of camel spiders.
makes <who> read slashdot at -1.
puts 'alias vim=emacs' in <who>'s /etc/profile.
uninstalls every web browser from <who>'s system.
locks <who> in the Chateau d'If.
signs <who> up for getting hit on the head lessons.
makes <who> try to set up a Lexmark printer.
fills <who>'s eyedrop bottle with lime juice.
casts <who> into the fires of Mt. Doom.
gives <who> a Flying Dutchman.
rips off <who>'s arm, and uses it to beat them to death.
pierces <who>'s nose with a rusty paper hole puncher.
pokes <who> with a rusty nail.
puts sugar between <who>'s bedsheets.
pours sand into <who>'s breakfast.
mixes epoxy into <who>'s toothpaste.
puts Icy-Hot in <who>'s lube container.
straps <who> to a chair, and plays a endless low bitrate MP3 loop of \"the world's most annoying sound\" from \"Dumb and Dumber\".
tells Dr. Dre that <who> was talking smack.
forces <who> to use a Commodore 64 for all their word processing.
smacks <who> in the face with a burlap sack full of broken glass.
puts <who> in a room with several heavily armed manic depressives.
makes <who> watch reruns of \"Blue's Clues\".
puts lye in <who>'s coffee.
introduces <who> to the clue-by-four.
tattoos the Windows symbol on <who>'s ass.
lets Borg have his way with <who>.
signs <who> up for line dancing classes at the local senior center.
wakes <who> out of a sound sleep with some brand new nipple piercings.
gives <who> a 2 gauge Prince Albert.
forces <who> to eat all their veggies.
covers <who>'s toilet paper with lemon-pepper.
fills <who>'s ketchup bottle with Dave's Insanity sauce.
forces <who> to stare at an incredibly frustrating and seemingly never-ending IRC political debate.
knocks two of <who>'s teeth out with a 2x4.
removes Debian from <who>'s system.
switches <who> over to CentOS.
uses <who>'s iPod for skeet shooting practice.
gives <who>'s phone number to Borg.
posts <who>'s IP, username(s), and password(s) on 4chan.
forces <who> to use words like 'irregardless' and 'administrate' (thereby sounding like a real dumbass).
tickles <who> until they wet their pants and pass out.
replaces <who>'s KY with elmer's clear wood glue.
replaces <who>'s TUMS with alka-seltzer tablets.
squeezes habanero pepper juice into <who>'s tub of vaseline.
forces <who> to learn the Win32 API.
gives <who> an atomic wedgie.
ties <who> to a chair and forces them to listen to 'N Sync at full blast.
forces <who> to use notepad for text editing.
frowns at <who> really, really hard.
jabs a hot lighter into <who>'s eye sockets.
forces <who> to browse the web with IE6.
takes <who> out at the knees with a broken pool cue.
forces <who> to listen to emo music.
lets a few creepers into <who>'s house.
signs <who> up for the Iowa State Ferret Legging Championship.
attempts to hotswap <who>'s RAM.
dragon punches <who>.
puts railroad spikes into <who>'s side.
replaces <who>'s Astroglide with JB Weld.
replaces <who>'s stress pills with rat poison pellets.
replaces <who>'s crotch itch cream with Nair.
does the Australian Death Grip on <who>.
dances upon the grave of <who>'s ancestors.
farts in <who>'s general direction.
flogs <who> with stinging nettle.
intoduces <who> to the Knights who say Ni.
hands <who> a poison ivy joint.

217
plugins/data/recipes.txt Executable file
View file

@ -0,0 +1,217 @@
//Minecraft Recipes List
//Created by _303
//Obtained from https://github.com/ClouDev/CloudBot/blob/develop/plugins/data/recipes.txt
//Edited by _frozen
//
//Summary of Use: Each column is seperated by a comma (,) and rows by a vertical bar (|). Order of Recipes & Categories taken from
//www.minecraftwiki.net/wiki/Crafting for easier updating in the future (The Future!)
//
//Basic Recipes
//
4x Wooden Planks: Wood
4x Stick: Wooden Planks | Wooden Planks
4x Torch: Coal | Stick
4x Torch: Charcoal | Stick
1x Crafting Table: Wooden Planks, Wooden Planks | Wooden Planks, Wooden Planks
1x Furnace: Cobblestone, Cobblestone, Cobblestone | Cobblestone, None, Cobblestone | Cobblestone, Cobblestone, Cobblestone
1x Chest: Wooden Planks, Wooden Planks, Wooden Planks | Wooden Planks, None, Wooden Planks | Wooden Planks, Wooden Planks, Wooden Planks
//
//Block Recipes
//
1x Block of Gold: Gold Ingot, Gold Ingot, Gold Ingot | Gold Ingot, Gold Ingot, Gold Ingot | Gold Ingot, Gold Ingot, Gold Ingot
1x Block of Iron: Iron Ingot, Iron Ingot, Iron Ingot | Iron Ingot, Iron Ingot, Iron Ingot | Iron Ingot, Iron Ingot, Iron Ingot
1x Block of Diamond: Diamond, Diamond, Diamond | Diamond, Diamond, Diamond | Diamond, Diamond, Diamond
1x Lapis Lazuli Block: Lapis Lazuli, Lapis Lazuli, Lapis Lazuli | Lapis Lazuli, Lapis Lazuli, Lapis Lazuli | Lapis Lazuli, Lapis Lazuli, Lapis Lazuli
1x Glowstone: Glowstone Dust, Glowstone Dust | Glowstone Dust, Glowstone Dust
1x Wool: String, String | String, String
1x TNT: Gunpowder, Sand, Gunpowder | Sand, Gunpowder, Sand | Gunpowder, Sand, Gunpowder
3x Cobblestone Slab: Cobblestone, Cobblestone, Cobblestone
3x Stone Slab: Stone, Stone, Stone
3x Sandstone Slab: Sandstone, Sandstone, Sandstone
3x Wooden Slab: Wooden Planks, Wooden Planks, Wooden Planks
3x Stone Bricks Slab: Stone Bricks, Stone Bricks, Stone Bricks
3x Bricks Slab: Bricks, Bricks, Bricks
4x Wooden Stairs: Wooden Planks, None, None | Wooden Planks, Wooden Planks, None | Wooden Planks, Wooden Planks, Wooden Planks
4x Stone Stairs: Cobblestone, None, None | Cobblestone, Cobblestone, None | Cobblestone, Cobblestone, Cobblestone
4x Brick Stairs: Bricks, None, None | Bricks, Bricks, None | Bricks, Bricks, Bricks
4x Nether Brick Stairs: Nether Bricks, None, None | Nether Bricks, Nether Bricks, None | Nether Bricks, Nether Bricks, Nether Bricks
4x Stone Brick Stairs: Stone Bricks, None, None | Stone Bricks, Stone Bricks, None | Stone Bricks, Stone Bricks, Stone Bricks
1x Snow: Snowball, Snowball | Snowball, Snowball
1x Clay Block: Clay, Clay | Clay, Clay
1x Brick Block: Brick, Brick | Brick, Brick
4x Stone Bricks: Stone, Stone | Stone, Stone
1x Bookshelf: Wooden Planks, Wooden Planks, Wooden Planks | Book, Book, Book | Wooden Planks, Wooden Planks, Wooden Planks
1x Sandstone: Sand, Sand | Sand, Sand
1x Jack 'o' Lantern: Pumpkin | Torch
//
//Tool Recipes
//
1x Wooden Pickaxe: Wooden Planks, Wooden Planks, Wooden Planks | None, Stick, None | None, Stick, None
1x Wooden Axe: Wooden Planks, Wooden Planks | Wooden Planks, Stick | None, Stick
1x Wooden Hoe: Wooden Planks, Wooden Planks | None, Stick | None, Stick
1x Wooden Shovel: Wooden Planks | Stick | Stick
1x Stone Pickaxe: Cobblestone, Cobblestone, Cobblestone | None, Stick, None | None, Stick, None
1x Stone Axe: Cobblestone, Cobblestone | Cobblestone, Stick | None, Stick
1x Stone Hoe: Cobblestone, Cobblestone | None, Stick | None, Stick
1x Stone Shovel: Cobblestone | Stick | Stick
1x Iron Pickaxe: Iron Ingot, Iron Ingot, Iron Ingot | None, Stick, None | None, Stick, None
1x Iron Axe: Iron Ingot, Iron Ingot | Iron Ingot, Stick | None, Stick
1x Iron Hoe: Iron Ingot, Iron Ingot | None, Stick | None, Stick
1x Iron Shovel: Iron Ingot | Stick | Stick
1x Diamond Pickaxe: Diamond, Diamond, Diamond | None, Stick, None | None, Stick, None
1x Diamond Axe: Diamond, Diamond | Diamond, Stick | None, Stick
1x Diamond Hoe: Diamond, Diamond | None, Stick | None, Stick
1x Diamond Shovel: Diamond | Stick | Stick
1x Golden Pickaxe: Gold Ingot, Gold Ingot, Gold Ingot | None, Stick, None | None, Stick, None
1x Golden Axe: Gold Ingot, Gold Ingot | Gold Ingot, Stick | None, Stick
1x Golden Hoe: Gold Ingot, Gold Ingot | None, Stick | None, Stick
1x Golden Shovel: Gold Ingot | Stick | Stick
1x Flint and Steel: Iron Ingot, None | None, Flint
1x Bucket: Iron Ingot, None, Iron Ingot | None, Iron Ingot, None
1x Compass: None, Iron Ingot, None | Iron Ingot, Redstone, Iron Ingot | None, Iron Ingot, None
1x Map: Paper, Paper, Paper | Paper, Compass, Paper | Paper, Paper, Paper
1x Clock: None, Gold Ingot, None | Gold Ingot, Redstone, Gold Ingot | None, Gold Ingot, None
1x Fishing Rod: None, None, Stick | None, Stick, String | Stick, None, String
1x Shears: None, Iron Ingot | Iron Ingot, None
3x Fire Charge: Gunpowder, None, None | Blaze Powder, Coal/Charcoal, None
//
//Weapon Recipes
//
1x Wooden Sword: Wooden Planks | Wooden Planks | Stick
1x Stone Sword: Cobblestone | Cobblestone | Stick
1x Iron Sword: Iron Ingot | Iron Ingot | Stick
1x Diamond Sword: Diamond | Diamond | Stick
1x Golden Sword: Gold Ingot | Gold Ingot | Stick
1x Bow: None, Stick, String | Stick, None, String | None, Stick, String
4x Arrow: Flint | Stick | Feather
//
//Armor Recipes
//
1x Leather Tunic: Leather, None, Leather | Leather, Leather, Leather | Leather, Leather, Leather
1x Leather Pants: Leather, Leather, Leather | Leather, None, Leather | Leather, None, Leather
1x Leather Cap: Leather, Leather, Leather | Leather, None, Leather
1x Leather Boots: Leather, None, Leather | Leather, None, Leather
1x Chain Chestplate: Fire, None, Fire | Fire, Fire, Fire | Fire, Fire, Fire
1x Chain Leggings: Fire, Fire, Fire | Fire, None, Fire | Fire, None, Fire
1x Chain Helmet: Fire, Fire, Fire | Fire, None, Fire
1x Chain Boots: Fire, None, Fire | Fire, None, Fire
1x Iron Chestplate: Iron Ingot, None, Iron Ingot | Iron Ingot, Iron Ingot, Iron Ingot | Iron Ingot, Iron Ingot, Iron Ingot
1x Iron Leggings: Iron Ingot, Iron Ingot, Iron Ingot | Iron Ingot, None, Iron Ingot | Iron Ingot, None, Iron Ingot
1x Iron Helmet: Iron Ingot, Iron Ingot, Iron Ingot | Iron Ingot, None, Iron Ingot
1x Iron Boots: Iron Ingot, None, Iron Ingot | Iron Ingot, None, Iron Ingot
1x Diamond Chestplate: Diamond, None, Diamond | Diamond, Diamond, Diamond | Diamond, Diamond, Diamond
1x Diamond Leggings: Diamond, Diamond, Diamond | Diamond, None, Diamond | Diamond, None, Diamond
1x Diamond Helmet: Diamond, Diamond, Diamond | Diamond, None, Diamond
1x Diamond Boots: Diamond, None, Diamond | Diamond, None, Diamond
1x Golden Chestplate: Gold Ingot, None, Gold Ingot | Gold Ingot, Gold Ingot, Gold Ingot | Gold Ingot, Gold Ingot, Gold Ingot
1x Golden Leggings: Gold Ingot, Gold Ingot, Gold Ingot | Gold Ingot, None, Gold Ingot | Gold Ingot, None, Gold Ingot
1x Golden Helmet: Gold Ingot, Gold Ingot, Gold Ingot | Gold Ingot, None, Gold Ingot
1x Golden Boots: Gold Ingot, None, Gold Ingot | Gold Ingot, None, Gold Ingot
//
//Transportation Recipes
//
1x Minecart: Iron Ingot, None, Iron Ingot | Iron Ingot, Iron Ingot, Iron Ingot
1x Minecart with Chest: Chest | Minecart
1x Minecart with Furnace: Furnace | Minecart
16x Rail: Iron Ingot, None, Iron Ingot | Iron Ingot, Stick, Iron Ingot | Iron Ingot, None, Iron Ingot
6x Powered Rail: Gold Ingot, None, Gold Ingot | Gold Ingot, Stick, Gold Ingot | Gold Ingot, Redstone, Gold Ingot
6x Detector Rail: Iron Ingot, None, Iron Ingot | Iron Ingot, Pressure Plate, Iron Ingot | Iron Ingot, Redstone, Iron Ingot
1x Boat: Wooden Planks, None, Wooden Planks | Wooden Planks, Wooden Planks, Wooden Planks
//
//Mechanism Recipes
//
1x Wooden Door: Wooden Planks, Wooden Planks | Wooden Planks, Wooden Planks | Wooden Planks, Wooden Planks
1x Iron Door: Iron Ingot, Iron Ingot | Iron Ingot, Iron Ingot | Iron Ingot, Iron Ingot
2x Trapdoor: Wooden Planks, Wooden Planks, Wooden Planks | Wooden Planks, Wooden Planks, Wooden Planks
1x Stone Pressure Plate: Stone, Stone
1x Wooden Pressure Plate: Wooden Planks, Wooden Planks
1x Button: Stone | Stone
1x Redstone Torch: Redstone | Stick
1x Lever: Stick | Cobblestone
1x Note Block: Wooden Planks, Wooden Planks, Wooden Planks | Wooden Planks, Redstone, Wooden Planks | Wooden Planks, Wooden Planks, Wooden Planks
1x Jukebox: Wooden Planks, Wooden Planks, Wooden Planks | Wooden Planks, Diamond, Wooden Planks | Wooden Planks, Wooden Planks, Wooden Planks
1x Dispenser: Cobblestone, Cobblestone, Cobblestone | Cobblestone, Bow, Cobblestone | Cobblestone, Redstone, Cobblestone
1x Redstone Repeater: Redstone Torch, Redstone, Redstone Torch | Stone, Stone, Stone
1x Piston: Wooden Planks, Wooden Planks, Wooden Planks | Cobblestone, Iron Ingot, Cobblestone | Cobblestone, Redstone, Cobblestone
1x Sticky Piston: none, slime ball, none | none, piston, none
1x Redstone Lamp: none, redstone dust, none | redstone dust, glowstone block, redstone | none, redstone dust, none
//
//Food Recipes
//
4x Bowl: Wooden Planks, None, Wooden Planks | None, Wooden Planks, None
1x Mushroom Stew: Brown Mushroom, Red Mushroom | Bowl
1x Bread: Wheat, Wheat, Wheat
1x Sugar: Sugar Canes
1x Cake: Milk, Milk, Milk | Sugar, Egg, Sugar | Wheat, Wheat, Wheat
8x Cookie: Wheat, Cocoa Beans, Wheat
1x Golden Apple: Gold Nugget, Gold Nugget, Gold Nugget | Gold Nugget, Apple, Gold Nugget | Gold Nugget, Gold Nugget, Gold Nugget
1x Melon Block: Melon, Melon, Melon | Melon, Melon, Melon | Melon, Melon, Melon
1x Melon Seeds: Melon Slice
4x Pumpkin Seeds: Pumpkin
//
//Miscellaneous Recipes
//
9x Gold Ingot: Block of Gold
9x Iron Ingot: Block of Iron
9x Diamond: Block of Diamond
9x Lapis Lazuli: Lapis Lazuli Block
2x Ladder: Stick, None, Stick | Stick, Stick, Stick | Stick, None, Stick
1x Sign: Wooden Planks, Wooden Planks, Wooden Planks | Wooden Planks, Wooden Planks, Wooden Planks | None, Stick, None
1x Painting: Stick, Stick, Stick | Stick, Black Wool, Stick | Stick, Stick, Stick
16x Iron Bars: Iron Ingot, Iron Ingot, Iron Ingot | Iron Ingot, Iron Ingot, Iron Ingot
16x Glass Pane: Glass, Glass, Glass | Glass, Glass, Glass
3x Paper: Sugar Canes, Sugar Canes, Sugar Canes
1x Book: Paper | Paper | Paper
2x Fence: Stick, Stick, Stick | Stick, Stick, Stick
2x Nether Brick Fence: Nether Brick, Nether Brick, Nether Brick | Nether Brick, Nether Brick, Nether Brick
1x Fence Gate: Stick, Wooden Planks, Stick | Stick, Wooden Planks, Stick
1x Bed: Wool, Wool, Wool | Wooden Planks, Wooden Planks, Wooden Planks
9x Gold Nugget: Gold Ingot
1x Gold Ingot: Gold Nugget, Gold Nugget, Gold Nugget | Gold Nugget, Gold Nugget, Gold Nugget | Gold Nugget, Gold Nugget, Gold Nugget
1x Eye of Ender: Ender Pearl | Blaze Powder
//
//Dye Recipes
//
3x Bone Meal: Bone
2x Light Gray Dye: Gray Dye, Bone Meal
2x Gray Dye: Ink Sac, Bone Meal
2x Rose Red: Rose
2x Orange Dye: Rose Red, Dandelion Yellow
2x Dandelion Yellow: Flower
2x Lime Dye: Cactus Green, Bone Meal
2x Light Blue Dye: Lapis Lazuli, Bone Meal
2x Cyan Dye: Lapis Lazuli, Cactus Green
2x Purple Dye: Lapis Lazuli, Rose Red
4x Magenta Dye: Lapis Lazuli, Rose Red, Rose Red, Bone Meal
2x Pink Dye: Rose Red, Bone Meal
//
//Wool Recipes
//
1x Light Gray Wool: Light Gray Dye, Wool
1x Gray Wool: Gray Dye, Wool
1x Black Wool: Ink Sac, Wool
1x Red Wool: Rose Red, Wool
1x Orange Wool: Orange Dye, Wool
1x Yellow Wool: Dandelion Yellow, Wool
1x Lime Wool: Lime Dye, Wool
1x Green Wool: Cactus Green, Wool
1x Light Blue Wool: Light Blue Dye, Wool
1x Cyan Wool: Cyan Dye, Wool
1x Blue Wool: Lapis Lazuli, Wool
1x Purple Wool: Purple Dye, Wool
1x Magenta Wool: Magenta Dye, Wool
1x Pink Wool: Pink Dye, Wool
1x Brown Wool: Cocoa Beans, Wool
1x Wool: Bone Meal, Wool
//
//Enchancement & Brewing Recipes
//
3x Glass Bottle: Glass, None, Glass | None, Glass, None
1x Cauldron: Iron Ingot, None, Iron Ingot | Iron Ingot, None, Iron Ingot | Iron Ingot, Iron Ingot, Iron Ingot
1x Brewing Stand: None, Blaze Rod, None | Cobblestone, Cobblestone, Cobblestone
2x Blaze Powder: Blaze Rod
1x Magma Cream: Slimeball | Blaze Powder
1x Fermented Spider Eye: Spider Eye | Brown Mushroom, Sugar
1x Glistering Melon: Melon Slice, Gold Nugget
9x Gold Nugget: Gold Ingot
1x Enchantment Table: None, Book, None | Diamond, Obsidian, Diamond | Obsidian, Obsidian, Obsidian

19
plugins/data/slap_items.txt Executable file
View file

@ -0,0 +1,19 @@
cast iron skillet
large trout
baseball bat
wooden cane
CRT monitor
diamond sword
physics textbook
television
mau5head
five ton truck
roll of duct tape
book
cobblestone block
lava bucket
rubber chicken
gold block
fire extinguisher
heavy rock
chunk of dirt

12
plugins/data/slaps.txt Executable file
View file

@ -0,0 +1,12 @@
slaps <who> with a <item>.
slaps <who> around a bit with a <item>.
throws a <item> at <who>.
chucks a few <item>s at <who>.
grabs a <item> and throws it in <who>'s face.
launches a <item> in <who>'s general direction.
sits on <who>'s face, while slamming a <item> into their crotch.
holds <who> down and repeatedly whacks them with a <item>.
prods <who> with a flaming <item>.
picks up a <item> and whacks <who> with it.
ties <who> to a chair and throws a <item> at them.
hits <who> on the head with a <item>.

View file

@ -1,7 +1,5 @@
""" # Written by Scaevolus, updated by Lukeroge
dice.py: written by Scaevolus 2008, updated 2009
simulates dicerolls
"""
import re import re
import random import random
@ -9,7 +7,8 @@ from util import hook
whitespace_re = re.compile(r'\s+') whitespace_re = re.compile(r'\s+')
valid_diceroll = r'^([+-]?(?:\d+|\d*d(?:\d+|F))(?:[+-](?:\d+|\d*d(?:\d+|F)))*)( .+)?$' valid_diceroll = r'^([+-]?(?:\d+|\d*d(?:\d+|F))(?:[+-](?:\d+|\d*d(?:\d+|' \
'F)))*)( .+)?$'
valid_diceroll_re = re.compile(valid_diceroll, re.I) valid_diceroll_re = re.compile(valid_diceroll, re.I)
sign_re = re.compile(r'[+-]?(?:\d*d)?(?:\d+|F)', re.I) sign_re = re.compile(r'[+-]?(?:\d*d)?(?:\d+|F)', re.I)
split_re = re.compile(r'([\d+-]*)d?(F|\d*)', re.I) split_re = re.compile(r'([\d+-]*)d?(F|\d*)', re.I)
@ -29,15 +28,16 @@ def nrolls(count, n):
return [random.randint(1, n) for x in xrange(count)] return [random.randint(1, n) for x in xrange(count)]
else: # fake it else: # fake it
return [int(random.normalvariate(.5 * (1 + n) * count, return [int(random.normalvariate(.5 * (1 + n) * count,
(((n+1)*(2*n+1)/6.-(.5*(1+n))**2)*count)**.5))] (((n + 1) * (2 * n + 1) / 6. -
(.5 * (1 + n)) ** 2) * count) ** .5))]
@hook.command('roll') @hook.command('roll')
#@hook.regex(valid_diceroll, re.I) #@hook.regex(valid_diceroll, re.I)
@hook.command @hook.command
def dice(inp): def dice(inp):
".dice <diceroll> -- Simulates dicerolls. Example of <diceroll>: '.dice 2d20-d5+4 roll 2'." \ ".dice <diceroll> -- Simulates dicerolls. Example of <diceroll>:" \
"D20s, subtract 1D5, add 4" " '.dice 2d20-d5+4 roll 2'. D20s, subtract 1D5, add 4"
try: # if inp is a re.match object... try: # if inp is a re.match object...
(inp, desc) = inp.groups() (inp, desc) = inp.groups()

View file

@ -1,21 +1,41 @@
# Plugin by GhettoWizard and Scaevolus
import re import re
from util import hook
from util import hook, http from util import http
@hook.command('u') @hook.command('u')
@hook.command @hook.command
def urban(inp): def urban(inp):
".urban <phrase> -- Looks up <phrase> on urbandictionary.com." ".urban <phrase> [id] -- Looks up <phrase> on urbandictionary.com."
# set a default definition number
id = 1
# clean and split the input
input = inp.lower().strip()
parts = input.split()
# if the last word is a number, set the ID to that number
if parts[-1].isdigit():
id = int(parts[-1])
del parts[-1]
input = " ".join(parts)
url = 'http://www.urbandictionary.com/iphone/search/define' url = 'http://www.urbandictionary.com/iphone/search/define'
page = http.get_json(url, term=inp) page = http.get_json(url, term=input)
defs = page['list'] defs = page['list']
if page['result_type'] == 'no_results': if page['result_type'] == 'no_results':
return 'Not found.' return 'Not found.'
out = defs[0]['word'] + ': ' + defs[0]['definition'] # try getting the requested definition
try:
out = "[%s/%s] %s: %s" % \
(str(id), str(len(defs)), defs[id - 1]['word'],
defs[id - 1]['definition'])
except IndexError:
return 'Not found.'
if len(out) > 400: if len(out) > 400:
out = out[:out.rfind(' ', 0, 400)] + '...' out = out[:out.rfind(' ', 0, 400)] + '...'
@ -23,7 +43,6 @@ def urban(inp):
return out return out
# define plugin by GhettoWizard & Scaevolus
@hook.command('dictionary') @hook.command('dictionary')
@hook.command @hook.command
def define(inp): def define(inp):

View file

@ -7,7 +7,8 @@ ed_url = "http://encyclopediadramatica.ch/"
@hook.command('ed') @hook.command('ed')
@hook.command @hook.command
def drama(inp): def drama(inp):
".drama <phrase> -- Gets the first paragraph of Encyclopedia Dramatica article on <phrase>." ".drama <phrase> -- Gets the first paragraph of"\
"the Encyclopedia Dramatica article on <phrase>."
j = http.get_json(api_url, search=inp) j = http.get_json(api_url, search=inp)
if not j[1]: if not j[1]:

View file

@ -1,7 +1,10 @@
import re import re
from util import hook, http, misc from util import hook
from util import http
from util import misc
from BeautifulSoup import BeautifulSoup from BeautifulSoup import BeautifulSoup
@hook.command(autohelp=False) @hook.command(autohelp=False)
def fact(inp, say=False, nick=False): def fact(inp, say=False, nick=False):
".fact -- Gets a random fact from OMGFACTS." ".fact -- Gets a random fact from OMGFACTS."
@ -15,6 +18,7 @@ def fact(inp, say=False, nick=False):
return u"%s [ %s ]" % (fact, link) return u"%s [ %s ]" % (fact, link)
def get_fact(): def get_fact():
page = http.get('http://www.omg-facts.com/random') page = http.get('http://www.omg-facts.com/random')
soup = BeautifulSoup(page) soup = BeautifulSoup(page)

View file

@ -6,7 +6,7 @@ from util import hook
import re import re
# the dictionary has target_word : replacement_word pairs # some simple "shortcodes" for formatting purposes
shortcodes = { shortcodes = {
'<b>': '\x02', '<b>': '\x02',
'</b>': '\x02', '</b>': '\x02',
@ -24,7 +24,8 @@ def db_init(db):
def get_memory(db, word): def get_memory(db, word):
row = db.execute("select data from mem where word=lower(?)", [word]).fetchone() row = db.execute("select data from mem where word=lower(?)",
[word]).fetchone()
if row: if row:
return row[0] return row[0]
else: else:
@ -43,12 +44,11 @@ def multiwordReplace(text, wordDic):
return rc.sub(translate, text) return rc.sub(translate, text)
@hook.command("r") @hook.command("r", adminonly=True)
@hook.command(adminonly=True)
def remember(inp, nick='', db=None, say=None, input=None, notice=None): def remember(inp, nick='', db=None, say=None, input=None, notice=None):
".remember <word> [+]<data> -- Remembers <data> with <word>. Add + to <data> to append." ".remember <word> [+]<data> -- Remembers <data> with <word>. Add +"
if input.nick not in input.bot.config["admins"]: " to <data> to append."
notice("Only bot admins can use this command!")
return
db_init(db) db_init(db)
append = False append = False
@ -80,20 +80,18 @@ def remember(inp, nick='', db=None, say=None, input=None, notice=None):
if append: if append:
notice("Appending %s to %s" % (new, data.replace('"', "''"))) notice("Appending %s to %s" % (new, data.replace('"', "''")))
else: else:
notice('Forgetting existing data (%s), remembering this instead!' % \ notice('Forgetting existing data (%s), remembering this instead!'
data.replace('"', "''")) % data.replace('"', "''"))
return return
else: else:
notice('Remembered!') notice('Remembered!')
return return
@hook.command("f") @hook.command("f", adminonly=True)
@hook.command(adminonly=True)
def forget(inp, db=None, input=None, notice=None): def forget(inp, db=None, input=None, notice=None):
".forget <word> -- Forgets a remembered <word>." ".forget <word> -- Forgets a remembered <word>."
if input.nick not in input.bot.config["admins"]:
notice("Only bot admins can use this command!")
return
db_init(db) db_init(db)
data = get_memory(db, inp) data = get_memory(db, inp)
@ -102,7 +100,7 @@ def forget(inp, db=None, input=None, notice=None):
db.execute("delete from mem where word=lower(?)", db.execute("delete from mem where word=lower(?)",
[inp]) [inp])
db.commit() db.commit()
notice('`%s` has been forgotten.' % data.replace('`', "'")) notice('"%s" has been forgotten.' % data.replace('`', "'"))
return return
else: else:
notice("I don't know about that.") notice("I don't know about that.")
@ -111,10 +109,10 @@ def forget(inp, db=None, input=None, notice=None):
@hook.command("info") @hook.command("info")
@hook.regex(r'^\? ?(.+)') @hook.regex(r'^\? ?(.+)')
def question(inp, say=None, db=None, bot=None): def factoid(inp, say=None, db=None, bot=None):
"?<word> -- Shows what data is associated with <word>." "?<word> -- Shows what data is associated with <word>."
try: try:
prefix_on = bot.config["plugins"]["factoids"]["prefix"] prefix_on = bot.config["plugins"]["factoids"].get("prefix", False)
except KeyError: except KeyError:
prefix_on = False prefix_on = False

56
plugins/feelings.py Executable file
View file

@ -0,0 +1,56 @@
from util import hook
import re
import random
nick_re = re.compile(r"^[A-Za-z0-9_|.-\]\[]*$")
insults = []
flirts = []
with open("plugins/data/insults.txt") as f:
for line in f.readlines():
if line.startswith("//"):
continue
insults.append(line.strip())
with open("plugins/data/flirts.txt") as f:
for line in f.readlines():
if line.startswith("//"):
continue
flirts.append(line.strip())
@hook.command
def insult(inp, nick=None, me=None, conn=None):
".insult <user> -- Makes the bot insult <user>."
target = inp.strip()
if not re.match(nick_re, target):
notice("Invalid username!")
return
if target == conn.nick.lower() or target == "itself":
target = nick
else:
target = inp
out = 'insults %s... "%s"' % (target, random.choice(insults))
me(out)
@hook.command
def flirt(inp, nick=None, me=None, conn=None):
".flirt <user> -- Make the bot flirt with <user>."
target = inp.strip()
if not re.match(nick_re, target):
notice("Invalid username!")
return
if target == conn.nick.lower() or target == "itself":
target = 'itself'
else:
target = inp
out = 'insults %s... "%s"' % (target, random.choice(flirts))
me(out)

View file

@ -1,6 +1,7 @@
from util import hook from util import hook
import random import random
@hook.command @hook.command
def flip(inp, flip_count=0, say=None): def flip(inp, flip_count=0, say=None):
".flip <text> -- Flips <text> over." ".flip <text> -- Flips <text> over."

View file

@ -1,55 +0,0 @@
from util import hook
import re
import random
flirts = ["I bet your name's Mickey, 'cause you're so fine.",
"Hey, pretty mama. You smell kinda pretty, wanna smell me?",
"I better get out my library card, 'cause I'm checkin' you out.",
"If you were a booger, I'd pick you.",
"If I could rearrange the alphabet, I would put U and I together.",
"I've been bad, take me to your room.",
"I think Heaven's missing an angel.",
"That shirt looks good on you, it'd look better on my bedroom floor.",
"I cant help to notice but you look a lot like my next girlfriend",
"Aren't your feet tired? Because you've been running through my mind all day.",
"I must be asleep, 'cause you are a dream come true. Also, I'm slightly damp.",
"I like large posteriors and I cannot prevaricate.",
"How you doin'?",
"If I said you had a good body, would you hold it against me?",
"Hey, baby cakes.",
"Nice butt.",
"I love you like a fat kid loves cake.",
"Do you believe in love at first sight? Or should I walk by again...?",
"Want to see my good side? Hahaha, that was a trick question, all I have are good sides.",
"You look like a woman who appreciates the finer things in life. Come over here and feel my velour bedspread.",
"Now you're officially my woman. Kudos! I can't say I don't envy you.",
"I find that the most erotic part of a woman is the boobies.",
"If you want to climb aboard the Love Train, you've got to stand on the Love Tracks. But you might just get smushed by a very sensual cow-catcher.",
"Lets say you and I knock some very /sensual/ boots.",
"I lost my phone number, can I have yours?",
"Does this rag smell like chloroform to you? ",
"I'm here, where are your other two wishes?",
"Apart from being sexy, what do you do for a living?",
"Hi, I'm Mr. Right. Someone said you were looking for me. ",
"You got something on your chest: My eyes.",
"Are you from Tennessee? Cause you're the only TEN I see.",
"Are you an alien? Because you just abducted my heart.",
"Excuse me, but I think you dropped something!!! MY JAW!!",
"If I followed you home, would you keep me?",
"Where have you been all my life?",
"I'm just a love machine, and I don't work for nobody but you",
"Do you live on a chicken farm? Because you sure know how to raise cocks.",
"Are you wearing space pants? Because your ass is out of this world.",
"Nice legs. What time do they open?",
"Your daddy must have been a baker, because you've got a nice set of buns."]
@hook.command(autohelp=False)
def flirt(inp, nick=None, me=None, input=None):
".flirt <user> -- Make the bot flirt with <user>."
msg = "flirts with " + nick + "... \"" + random.choice(flirts) + "\""
if re.match("^[A-Za-z0-9_|.-\]\[]*$", inp.lower()) and inp != "":
msg = "flirts with " + inp + "... \"" + random.choice(flirts) + "\""
if inp == input.conn.nick.lower() or inp == "itself":
msg = "flirts with itself... \"" + random.choice(flirts) + "\""
me(msg)

View file

@ -1,41 +1,38 @@
# Plugin by Lukeroge # Plugin by Lukeroge
# <lukeroge@gmail.com> <https://github.com/lukeroge/CloudBot/>
import re from util import hook, http
from util import hook, http, misc
from urllib2 import HTTPError
from urlparse import urljoin from urlparse import urljoin
from BeautifulSoup import BeautifulSoup from BeautifulSoup import BeautifulSoup
from collections import defaultdict
base_url = 'http://www.fmylife.com/' base_url = 'http://www.fmylife.com/'
@hook.command(autohelp=False) fml_cache = defaultdict()
def fml(inp):
".fml [id] -- Gets a random quote from fmyfife.com. Optionally gets [id]."
inp = inp.replace("#", "")
if inp: def refresh_cache():
if not inp.isdigit(): """Gets a page of random FMLs and puts them into a dictionary"""
return "Invalid ID!"
try:
page = http.get(urljoin(base_url, inp))
except (HTTPError, IOError):
return "Could not fetch #%s. FML" % inp
else:
try:
page = http.get(urljoin(base_url, 'random')) page = http.get(urljoin(base_url, 'random'))
except (HTTPError, IOError):
return "I tried to use .fml, but it was broken. FML"
soup = BeautifulSoup(page) soup = BeautifulSoup(page)
soup.find('div', id='submit').extract() for e in soup.findAll('div', {'class': 'post article'}):
post = soup.body.find('div', 'post') id = int(e['id'])
try: text = ''.join(e.find('p').findAll(text=True))
id = int(post.find('a', 'fmllink')['href'].split('/')[-1]) text = http.unescape(text)
except TypeError: fml_cache[id] = text
return "Could not fetch #%s. FML" % inp
body = misc.strip_html(' '.join(link.renderContents() for link in post('a', 'fmllink'))) # do an initial refresh of the cache
return '(#%d) %s' % (id, body) refresh_cache()
@hook.command(autohelp=False)
def fml(inp, reply=None):
".fml -- Gets a random quote from fmyfife.com."
# grab the last item in the fml cache and remove it
id, text = fml_cache.popitem()
# reply with the fml we grabbed
reply('(#%d) %s' % (id, text))
# refresh fml cache if its getting empty
if len(fml_cache) < 3:
refresh_cache()

View file

@ -2,64 +2,16 @@ from util import hook
import re import re
import random import random
fortunes = ["Help! I'm stuck in the fortune cookie factory!", fortunes = []
"He who laughs at himself never runs out of things to laugh at.",
"The world is your oyster.",
"Today will be a good day.",
"Life's short, party naked.",
"Haters gonna hate.",
"You are amazing and let no one tell you otherwise.",
"A starship ride has been promised to you by the galactic wizard.",
"That wasnt chicken.",
"Dont fry bacon in the nude.",
"Take calculated risks. That is quite different from being rash.",
"DO THE IMPOSSIBLE, SEE THE INVISIBLE.",
"You cannot plough a field by turning it over in your mind. Unless you have telekinesis.",
"No one can make you feel inferior without your consent.",
"Never lose the ability to find beauty in ordinary things.",
"Ignore previous fortune.",
"Smile more.",
"You are the dancing queen.",
"YOU'RE THE BEST AROUND, NOTHIN'S GONNA EVER KEEP YA DOWN.",
"The cake is a lie.",
"Never take life seriously. Nobody gets out alive anyway.",
"Friendship is like peeing on yourself: everyone can see it, but only you get the warm feeling that it brings.",
"Never go to a doctor whose office plants have died.",
"Always remember you're unique, just like everyone else.",
"What if everything is an illusion and nothing exists? In that case, I definitely overpaid for my carpet.",
"Even if you are on the right track, you will get run over if you just sit there.",
"Think like a man of action, and act like a man of thought.",
"When in doubt, lubricate.",
"It is time for you to live up to your family name and face FULL LIFE CONSEQUENCES.",
"It's a good day to do what has to be done.",
"Move near the countryside and you will be friends of John Freeman.",
"If you can't beat 'em, mock 'em.",
"Use gun. And if that don't work, use more gun.",
"LOOK OUT BEHIND YOU",
"This message will self destruct in 10 seconds.",
"You'll never know what you can do until you try.",
"You are talented in many ways",
"Be both a speaker of words and a doer of deeds.",
"A visit to a strange place will bring you renewed perspective.",
"A passionate new romance will appear in your life when you least expect it.",
"If you care enough for a result, you will most certainly attain it.",
"To be loved, be loveable.",
"Step away from the power position for one day.",
"If you want to get a sure crop with a big yield, sow wild oats.",
"It doesn't take guts to quit.",
"You can expect a change for the better in job or status in the future.",
"As the wallet grows, so do the needs.",
"You have a reputation for being straightforward and honest.",
"Learn a new language and get a new soul.",
"A tall dark stranger will soon enter our life.",
"Keep staring. I'll do a trick."]
@hook.command(autohelp=False) with open("plugins/data/fortunes.txt") as f:
def fortune(inp, nick=None, say=None, input=None): for line in f.readlines():
if line.startswith("//"):
continue
fortunes.append(line.strip())
@hook.command
def fortune(inp):
".fortune -- Fortune cookies on demand." ".fortune -- Fortune cookies on demand."
return random.choice(fortunes)
msg = "(" + nick + ") " + random.choice(fortunes)
if re.match("^[A-Za-z0-9_|.-\]\[]*$", inp.lower()) and inp != "":
msg = "(@" + inp + ") " + random.choice(fortunes)
say(msg)

View file

@ -3,8 +3,9 @@ import re
from util import hook, http, misc from util import hook, http, misc
from BeautifulSoup import BeautifulSoup from BeautifulSoup import BeautifulSoup
@hook.command("calc")
@hook.command("math") @hook.command("math")
@hook.command
def calc(inp): def calc(inp):
".calc <term> -- Calculate <term> with Google Calc." ".calc <term> -- Calculate <term> with Google Calc."

View file

@ -1,9 +1,11 @@
from util import hook from util import hook
def find_location(ip, api): def find_location(ip, api):
import string import string
import urllib import urllib
response = urllib.urlopen("http://api.ipinfodb.com/v3/ip-city/?key="+api+"&ip="+ip).read() response = urllib.urlopen("http://api.ipinfodb.com/v3/ip-city/?key=" \
+ api + "&ip=" + ip).read()
response = response.split(";") response = response.split(";")
give = {} give = {}
give["country"] = response[4].title() give["country"] = response[4].title()
@ -13,6 +15,7 @@ def find_location(ip, api):
give["timezone"] = response[10].title() give["timezone"] = response[10].title()
return give return give
def timezone(ip): def timezone(ip):
time = find_location(ip)["timezone"] time = find_location(ip)["timezone"]
time = time.replace(":", ".") time = time.replace(":", ".")
@ -33,8 +36,10 @@ def geoip(inp, say=None, bot=None):
localstring = give["city"] localstring = give["city"]
else: else:
localstring = give["city"] + ", " + give["state"] localstring = give["city"] + ", " + give["state"]
say("That IP comes from " + give["country"] + " (" + give["country_short"] + ")") say("That IP comes from " + give["country"] +
say("I think it's in " + localstring + " with a timezone of " + give["timezone"] + "GMT") " (" + give["country_short"] + ")")
say("I think it's in " + localstring +
" with a timezone of " + give["timezone"] + "GMT")
else: else:
say("Either that wasn't an IP or I cannot locate it in my database. :(") say("Either that wasn't an IP or I cannot locate it in my database.")
return return

View file

@ -1,10 +1,12 @@
# plugin created by neersighted and lukeroge # Plugin by neersighted and Lukeroge
from util import hook from util import hook
import urllib2 import urllib2
@hook.command @hook.command
def gitio(inp): def gitio(inp):
".gitio <url> [code] -- Shorten Github URLs with git.io. [code] is a optional custom short code." ".gitio <url> [code] -- Shorten Github URLs with git.io. [code] is" \
" a optional custom short code."
split = inp.split(" ") split = inp.split(" ")
url = split[0] url = split[0]
@ -13,7 +15,8 @@ def gitio(inp):
except: except:
code = None code = None
# if the first 8 chars of "url" are not "https://" then append "https://" to the url, also convert "http://" to "https://" # if the first 8 chars of "url" are not "https://" then append
# "https://" to the url, also convert "http://" to "https://"
if url[:8] != "https://": if url[:8] != "https://":
if url[:7] != "http://": if url[:7] != "http://":
url = "https://" + url url = "https://" + url
@ -31,7 +34,8 @@ def gitio(inp):
return "Failed to get URL!" return "Failed to get URL!"
urlinfo = str(f.info()) urlinfo = str(f.info())
# loop over the rows in urlinfo and pick out location and status (this is pretty odd code, but urllib2.Request is weird) # loop over the rows in urlinfo and pick out location and
# status (this is pretty odd code, but urllib2.Request is weird)
for row in urlinfo.split("\n"): for row in urlinfo.split("\n"):
if row.find("Status") != -1: if row.find("Status") != -1:
status = row status = row

View file

@ -1,28 +1,32 @@
import random import random
from util import hook
from util import hook, http from util import http
def api_get(kind, query): def api_get(kind, query):
"""Use the RESTful Google Search API"""
url = 'http://ajax.googleapis.com/ajax/services/search/%s?' \ url = 'http://ajax.googleapis.com/ajax/services/search/%s?' \
'v=1.0&safe=off' 'v=1.0&safe=off'
return http.get_json(url % kind, q=query) return http.get_json(url % kind, q=query)
@hook.command('image')
@hook.command('gis')
@hook.command @hook.command
def gis(inp): def googleimage(inp):
".gis <term> -- Returns first Google Image result (Safesearch off)." ".gis <term> -- Returns first Google Image result (Safesearch off)."
parsed = api_get('images', inp) parsed = api_get('images', inp)
if not 200 <= parsed['responseStatus'] < 300: if not 200 <= parsed['responseStatus'] < 300:
raise IOError('error searching for images: %d: %s' % ( raise IOError('error searching for images: %d: %s' % ( \
parsed['responseStatus'], '')) parsed['responseStatus'], ''))
if not parsed['responseData']['results']: if not parsed['responseData']['results']:
return 'no images found' return 'no images found'
return random.choice(parsed['responseData']['results'][:10])\ return random.choice(parsed['responseData']['results'][:10])\
['unescapedUrl'] # squares is dumb + ['unescapedUrl']
@hook.command('search')
@hook.command('g') @hook.command('g')
@hook.command @hook.command
def google(inp): def google(inp):

View file

@ -1,33 +0,0 @@
import re
from util import hook, http
from BeautifulSoup import BeautifulSoup
@hook.command("time")
def clock(inp, say=None):
".time <area> -- Gets the time in <area>"
white_re = re.compile(r'\s+')
tags_re = re.compile(r'<[^<]*?>')
page = http.get('http://www.google.com/search', q="time in " + inp)
soup = BeautifulSoup(page)
response = soup.find('td', {'style' : 'font-size:medium'})
if response is None:
return "Could not get the time for " + inp + "!"
output = response.renderContents()
output = ' '.join(output.splitlines())
output = output.replace("\xa0", ",")
output = white_re.sub(' ', output.strip())
output = tags_re.sub('\x02', output.strip())
output = output.decode('utf-8', 'ignore')
return output

View file

@ -1,26 +1,31 @@
import hashlib import hashlib
from util import hook from util import hook
@hook.command @hook.command
def md5(inp): def md5(inp):
".hash <text> -- Returns a md5 hash of <text>." ".hash <text> -- Returns a md5 hash of <text>."
return hashlib.md5(inp).hexdigest() return hashlib.md5(inp).hexdigest()
@hook.command @hook.command
def sha1(inp): def sha1(inp):
".hash <text> -- Returns a sha1 hash of <text>." ".hash <text> -- Returns a sha1 hash of <text>."
return hashlib.sha1(inp).hexdigest() return hashlib.sha1(inp).hexdigest()
@hook.command @hook.command
def sha256(inp): def sha256(inp):
".hash <text> -- Returns a sha256 hash of <text>." ".hash <text> -- Returns a sha256 hash of <text>."
return hashlib.sha256(inp).hexdigest() return hashlib.sha256(inp).hexdigest()
@hook.command @hook.command
def sha512(inp): def sha512(inp):
".hash <text> -- Returns a sha512 hash of <text>." ".hash <text> -- Returns a sha512 hash of <text>."
return hashlib.sha512(inp).hexdigest() return hashlib.sha512(inp).hexdigest()
@hook.command @hook.command
def hash(inp): def hash(inp):
".hash <text> -- Returns hashes of <text>." ".hash <text> -- Returns hashes of <text>."

View file

@ -1,7 +1,7 @@
import re import re
from util import hook from util import hook
@hook.command(autohelp=False) @hook.command(autohelp=False)
def help(inp, input=None, bot=None, say=None, notice=None): def help(inp, input=None, bot=None, say=None, notice=None):
".help -- Gives a list of commands/help for a command." ".help -- Gives a list of commands/help for a command."
@ -12,6 +12,9 @@ def help(inp, input=None, bot=None, say=None, notice=None):
for command, (func, args) in bot.commands.iteritems(): for command, (func, args) in bot.commands.iteritems():
fn = re.match(r'^plugins.(.+).py$', func._filename) fn = re.match(r'^plugins.(.+).py$', func._filename)
if fn.group(1).lower() not in disabled: if fn.group(1).lower() not in disabled:
if not args.get('adminonly', False) or\
input.nick in bot.config["admins"] or\
input.mask in bot.config["admins"]:
if command not in disabled_comm: if command not in disabled_comm:
if func.__doc__ is not None: if func.__doc__ is not None:
if func in funcs: if func in funcs:
@ -30,7 +33,7 @@ def help(inp, input=None, bot=None, say=None, notice=None):
well.append(x) well.append(x)
well.sort() well.sort()
for x in well: for x in well:
if len(out[0]) + len(str(x)) > 440: if len(out[0]) + len(str(x)) > 405:
out[1] += " " + str(x) out[1] += " " + str(x)
else: else:
out[0] += " " + str(x) out[0] += " " + str(x)
@ -38,8 +41,8 @@ def help(inp, input=None, bot=None, say=None, notice=None):
notice("Commands I recognise: " + out[0][1:]) notice("Commands I recognise: " + out[0][1:])
if out[1]: if out[1]:
notice(out[1][1:]) notice(out[1][1:])
notice("For detailed help, do '.help <example>' where <example> is the " + notice("For detailed help, do '.help <example>' where <example> "\
"name of the command you want help for.") "is the name of the command you want help for.")
else: else:
if inp in commands: if inp in commands:

62
plugins/ignore.py Executable file
View file

@ -0,0 +1,62 @@
import json
from util import hook
@hook.sieve
def ignoresieve(bot, input, func, type, args):
""" blocks input from ignored channels/nicks """
ignorelist = bot.config["plugins"]["ignore"]["ignored"]
# don't block input to event hooks
if type == "event":
return input
if input.chan in ignorelist or\
input.nick in ignorelist or\
input.host in ignorelist or\
input.mask in ignorelist:
if input.command == "PRIVMSG" and input.lastparam[1:] == "unignore":
return input
else:
return None
return input
@hook.command(autohelp=False)
def ignored(inp, notice=None, bot=None):
".ignored -- Lists ignored channels/nicks/hosts."
ignorelist = bot.config["plugins"]["ignore"]["ignored"]
if ignorelist:
notice("Ignored channels/nicks/hosts are: %s" % ", ".join(ignorelist))
else:
notice("No channels/nicks/hosts are currently ignored.")
return
@hook.command(adminonly=True)
def ignore(inp, notice=None, bot=None, config=None):
".ignore <channel|nick|host> -- Makes the bot ignore <channel|nick|host>."
target = inp.lower()
ignorelist = bot.config["plugins"]["ignore"]["ignored"]
if target in ignorelist:
notice("%s is already ignored." % target)
else:
notice("%s has been ignored." % target)
ignorelist.append(target)
ignorelist.sort()
json.dump(bot.config, open('config', 'w'), sort_keys=True, indent=2)
return
@hook.command(adminonly=True)
def unignore(inp, notice=None, bot=None, config=None):
".unignore <channel|nick|host> -- Makes the bot listen to"\
" <channel|nick|host>."
target = inp.lower()
ignorelist = bot.config["plugins"]["ignore"]["ignored"]
if target in ignorelist:
notice("%s has been unignored." % target)
ignorelist.remove(target)
ignorelist.sort()
json.dump(bot.config, open('config', 'w'), sort_keys=True, indent=2)
else:
notice("%s is not ignored." % target)
return

View file

@ -1,49 +0,0 @@
from util import hook
import re
import random
insults = ["You are the son of a motherless ogre.",
"Your mother was a hamster and your father smelled of elderberries.",
"I once owned a dog that was smarter than you. ",
"Go climb a wall of dicks.",
"You fight like a dairy farmer.",
"I've spoken to apes more polite than you.",
"Go and boil your bottom! Son of a silly person! ",
"I fart in your general direction.",
"Go away or I shall taunt you a second time. ",
"Shouldn't you have a license for being that ugly?",
"Calling you an idiot would be an insult to all the stupid people.",
"Why don't you slip into something more comfortable...like a coma.",
"Well, they do say opposites attact...so I sincerely hope you meet somebody who is attractive, honest, intelligent, and cultured..",
"Are you always this stupid or are you just making a special effort today?",
"Yo momma so fat when she sits around the house she sits AROUND the house.",
"Yo momma so ugly she made an onion cry.",
"Is your name Maple Syrup? It should be, you sap.",
"Bite my shiny metal ass!",
"Up yours, meatbag.",
"Jam a bastard in it you crap!",
"Don't piss me off today, I'm running out of places to hide to bodies",
"Why don't you go outside and play hide and go fuck yourself",
"I'll use small words you're sure to understand, you warthog-faced buffoon.",
"You are a sad, strange little man, and you have my pity.",
"Sit your five dollar ass down before I make change.",
"What you've just said is one of the most insanely idiotic things I've ever heard. Everyone in this room is now dumber for having listened to it. May God have mercy on your soul.",
"Look up Idiot in the dictionary. Know what you'll find? The definition of the word IDIOT, which you are.",
"You're dumber than a bag of hammers.",
"Why don't you go back to your home on Whore Island?",
"If I had a dick this is when I'd tell you to suck it.",
"Go play in traffic.",
"The village called, they want their idiot back."]
@hook.command(autohelp=False)
def insult(inp, nick=None, say=None, input=None):
".insult <user> -- Makes the bot insult <user>."
msg = "(" + nick + ") " + random.choice(insults)
if re.match("^[A-Za-z0-9_|.-\]\[]*$", inp.lower()) and inp != "":
msg = "(@" + inp + ") " + random.choice(insults)
if inp == input.conn.nick.lower() or inp == "itself":
msg = "*stares at " + nick + "*"
say(msg)

View file

@ -1,42 +0,0 @@
from util import hook
import re
import random
kills = ["rips off <who>'s <body> and leaves them to die.",
"grabs <who>'s head and rips it clean off their body.",
"grabs a machine gun and riddles <who>'s body with bullets.",
"gags and ties <who> then throws them off a bridge.",
"crushes <who> with a huge spiked boulder.",
"rams a rocket launcher up <who>'s ass and lets off a few rounds.",
"crushes <who>'s skull in with a spiked mace.",
"feeds <who> to an owlbear.",
"puts <who> into a sack, throws the sack in the river, and hurls the river into space.",
"goes bowling with <who>'s head.",
"sends <who> to /dev/null!",
"feeds <who> coke and mentos till they pop!"]
body = ['head',
'arms',
'leg',
'arm',
'"special parts"']
@hook.command
def kill(inp, me=None, nick=None, input=None, notice=None):
".kill <user> -- Makes the bot kill <user>."
inp = inp.strip()
if not re.match("^[A-Za-z0-9_|.-\]\[]*$", inp.lower()):
notice("Invalid username!")
return
if inp == input.conn.nick.lower() or inp == "itself":
kill = random.choice(kills)
kill = re.sub ('<who>', nick, kill)
msg = re.sub ('<body>', random.choice(body), kill)
else:
kill = random.choice(kills)
kill = re.sub ('<who>', inp, kill)
msg = re.sub ('<body>', random.choice(body), kill)
me(msg)

View file

@ -1,118 +0,0 @@
from util import hook
import re
import random
larts = ["swaps <who>'s shampoo with glue",
"installs windows on <who>'s machine",
"forces <who> to use perl for 3 weeks",
"registers <who>'s name with 50 known spammers",
"resizes <who>'s console to 40x24",
"takes <who>'s drink",
"dispenses <who>'s email address to a few hundred 'bulk mailing services'",
"pokes <who> in the eye",
"beats <who> senseless with a 50lb Linux manual",
"cats /dev/random into <who>'s ear",
"signs <who> up for AOL",
"enrolls <who> in Visual Basic 101",
"sporks <who>",
"drops a truckload of support tickets on <who>",
"judo chops <who>",
"sets <who>'s resolution to 800x600",
"formats <who>'s harddrive to fat12",
"rm -rf's <who>",
"stabs <who>",
"steals <who>'s mojo",
"strangles <who> with a doohicky mouse cord",
"whacks <who> with the cluebat",
"sells <who> on EBay",
"uses <who> as a biological warfare study",
"uses the 'Customer Appreciation Bat' on <who>",
"puts <who> in the Total Perspective Vortex",
"casts <who> into the fires of Mt. Doom",
"gives <who> a melvin",
"turns over <who> to Agent Smith to be 'bugged'",
"takes away <who>'s internet connection",
"pushes <who> past the Shoe Event Horizon",
"counts '1, 2, 5... er... 3!' and hurls the Holy Handgrenade Of Antioch at <who>",
"puts <who> in a nest of camel spiders",
"makes <who> read slashdot at -1",
"puts 'alias vim=emacs' in <who>'s /etc/profile",
"uninstalls every web browser from <who>'s system",
"locks <who> in the Chateau d'If",
"signs <who> up for getting hit on the head lessons",
"makes <who> try to set up a Lexmark printer",
"fills <who>'s eyedrop bottle with lime juice",
"casts <who> into the fires of Mt. Doom.",
"gives <who> a Flying Dutchman",
"rips off <who>'s arm, and uses it to beat them to death",
"pierces <who>'s nose with a rusty paper hole puncher",
"pokes <who> with a rusty nail",
"puts sugar between <who>'s bedsheets",
"pours sand into <who>'s breakfast",
"mixes epoxy into <who>'s toothpaste",
"puts Icy-Hot in <who>'s lube container",
"straps <who> to a chair, and plays a endless low bitrate MP3 loop of \"the world's most annoying sound\" from \"Dumb and Dumber\"",
"tells Dr. Dre that <who> was talking smack",
"forces <who> to use a Commodore 64 for all their word processing",
"smacks <who> in the face with a burlap sack full of broken glass",
"puts <who> in a room with several heavily armed manic depressives",
"makes <who> watch reruns of \"Blue's Clues\"",
"puts lye in <who>'s coffee",
"tattoos the Windows symbol on <who>'s ass",
"lets Borg have his way with <who>",
"signs <who> up for line dancing classes at the local senior center",
"wakes <who> out of a sound sleep with some brand new nipple piercings",
"gives <who> a 2 guage Prince Albert",
"forces <who> to eat all their veggies",
"covers <who>'s toilet paper with lemon-pepper",
"fills <who>'s ketchup bottle with Dave's Insanity sauce",
"forces <who> to stare at an incredibly frustrating and seemingly neverending IRC political debate",
"knocks two of <who>'s teeth out with a 2x4",
"removes debian from <who>'s system",
"uses <who>'s iPod for skeet shooting practice",
"gives <who>'s phone number to Borg",
"posts <who>'s IP, username, and password on 4chan",
"forces <who> to use words like 'irregardless' and 'administrate' (thereby sounding like a real dumbass)",
"tickles <who> until they wet their pants and pass out",
"replaces <who>'s KY with elmer's clear wood glue",
"replaces <who>'s TUMS with alka-seltzer tablets",
"squeezes habanero pepper juice into <who>'s tub of vaseline",
"Forces <who> to learn the Win32 API",
"gives <who> an atomic wedgie",
"ties <who> to a chair and forces them to listen to 'N Sync at full blast",
"forces <who> to use notepad for text editing",
"frowns at <who> really really hard",
"jabs a hot lighter into <who>'s eye sockets",
"forces <who> to browse the web with IE6",
"takes <who> out at the knees with a broken pool cue",
"forces <who> to listen to emo music",
"lets a few creepers into <who>'s house",
"signs <who> up for the Iowa State Ferret Legging Championship",
"attempts to hotswap <who>'s RAM",
"dragon punches <who>",
"puts track spikes into <who>'s side",
"replaces <who>'s Astroglide with JB Weld",
"replaces <who>'s stress pills with rat poison pellets",
"replaces <who>s crotch itch cream with Nair",
"does the Australian Death Grip on <who>",
"dances upon the grave of <who>'s ancestors.",
"farts in <who>'s general direction",
"flogs <who> with stinging neddle",
"assigns all of the permissions tickets on the BeastNode support system to <who>",
"hands <who> a poison ivy joint"]
@hook.command
def lart(inp, me=None, nick=None, input=None, notice=None):
".lart <user> -- Makes the bot LART <user>."
inp = inp.strip()
if not re.match("^[A-Za-z0-9_|.-\]\[]*$", inp.lower()):
notice("Invalid username!")
return
if inp == input.conn.nick.lower() or inp == "itself":
msg = re.sub ('<who>', nick, random.choice(larts))
else:
msg = re.sub ('<who>', inp, random.choice(larts))
me(msg)

View file

@ -1,15 +1,16 @@
# Upgraded with tables/cacheing by ChauffeR of #freebnc on irc.esper.net # Upgraded with tables/caching by ChauffeR of #freebnc on irc.esper.net
from util import hook, http from util import hook, http
@hook.command('l')
@hook.command('lfm') @hook.command('l', autohelp=False)
@hook.command @hook.command(autohelp=False)
def lastfm(inp, nick='', say=None, db=None, bot=None): def lastfm(inp, nick='', say=None, db=None, bot=None):
".lastfm [user] -- Displays the now playing (or last played) "\
"track of LastFM user [user]."
if inp: if inp:
user = inp user = inp
else: else:
user = nick user = nick
".lastfm <user> -- Displays the now playing (or recent) tracks of LastFM user <user>."
db.execute("create table if not exists lastfm(nick primary key, acc)") db.execute("create table if not exists lastfm(nick primary key, acc)")
sql = db.execute("select acc from lastfm where nick=lower(?)", (nick,)).fetchone(); sql = db.execute("select acc from lastfm where nick=lower(?)", (nick,)).fetchone();
api_url = "http://ws.audioscrobbler.com/2.0/?format=json" api_url = "http://ws.audioscrobbler.com/2.0/?format=json"
@ -37,7 +38,7 @@ def lastfm(inp, nick='', say=None, db=None, bot=None):
if inp: # specified a user name if inp: # specified a user name
return "error: %s" % response["message"] return "error: %s" % response["message"]
else: else:
return "your nick is not a LastFM account. try '.lastfm <user>'" return "your nick is not a LastFM account. try '.lastfm [user]'"
tracks = response["recenttracks"]["track"] tracks = response["recenttracks"]["track"]

View file

@ -14,7 +14,8 @@ log_fds = {} # '%(net)s %(chan)s' : (filename, fd)
timestamp_format = '%H:%M:%S' timestamp_format = '%H:%M:%S'
formats = {'PRIVMSG': '<%(nick)s> %(msg)s', formats = {
'PRIVMSG': '<%(nick)s> %(msg)s',
'PART': '-!- %(nick)s [%(user)s@%(host)s] has left %(chan)s', 'PART': '-!- %(nick)s [%(user)s@%(host)s] has left %(chan)s',
'JOIN': '-!- %(nick)s [%(user)s@%(host)s] has joined %(param0)s', 'JOIN': '-!- %(nick)s [%(user)s@%(host)s] has joined %(param0)s',
'MODE': '-!- mode/%(chan)s [%(param_tail)s] by %(nick)s', 'MODE': '-!- mode/%(chan)s [%(param_tail)s] by %(nick)s',
@ -22,10 +23,16 @@ formats = {'PRIVMSG': '<%(nick)s> %(msg)s',
'TOPIC': '-!- %(nick)s changed the topic of %(chan)s to: %(msg)s', 'TOPIC': '-!- %(nick)s changed the topic of %(chan)s to: %(msg)s',
'QUIT': '-!- %(nick)s has quit [%(msg)s]', 'QUIT': '-!- %(nick)s has quit [%(msg)s]',
'PING': '', 'PING': '',
'NOTICE': '' 'NOTICE': '-%(nick)s- %(msg)s'
} }
ctcp_formats = {'ACTION': '* %(nick)s %(ctcpmsg)s'} ctcp_formats = {
'ACTION': '* %(nick)s %(ctcpmsg)s',
'VERSION': '%(nick)s has requested CTCP %(ctcpcmd)s from %(chan)s: %(ctcpmsg)s',
'PING': '%(nick)s has requested CTCP %(ctcpcmd)s from %(chan)s: %(ctcpmsg)s',
'TIME': '%(nick)s has requested CTCP %(ctcpcmd)s from %(chan)s: %(ctcpmsg)s',
'FINGER': '%(nick)s has requested CTCP %(ctcpcmd)s from %(chan)s: %(ctcpmsg)s'
}
irc_color_re = re.compile(r'(\x03(\d+,\d+|\d)|[\x0f\x02\x16\x1f])') irc_color_re = re.compile(r'(\x03(\d+,\d+|\d)|[\x0f\x02\x16\x1f])')

105
plugins/mcitems.py Executable file
View file

@ -0,0 +1,105 @@
""" plugin by _303 (?)
"""
from util import hook
import re
import itertools
pattern = re.compile(r'^(?P<count>\d+)x (?P<name>.+?): (?P<ingredients>.*)$')
recipelist = []
class Recipe(object):
__slots__ = 'output', 'count', 'ingredients', 'line'
def __init__(self, output, count, ingredients, line):
self.output = output
self.count = count
self.ingredients = ingredients
self.line = line
def __str__(self):
return self.line
with open("plugins/data/recipes.txt") as f:
for line in f.readlines():
if line.startswith("//"):
continue
line = line.strip()
match = pattern.match(line)
if not match:
continue
recipelist.append(Recipe(line=line,
output=match.group("name").lower(),
ingredients=match.group("ingredients"),
count=match.group("count")))
ids = []
with open("plugins/data/itemids.txt") as f:
for line in f.readlines():
if line.startswith("//"):
continue
parts = line.strip().split()
id = parts[0]
name = " ".join(parts[1:])
ids.append((id, name))
@hook.command
def itemid(input, reply=None):
".itemid <item/id> -- gets the id from an item or vice versa"
input = input.lower().strip()
if input == "":
reply("error: no input.")
return
results = []
for id, name in ids:
if input == id:
results = ["\x02[%s]\x02 %s" % (id, name)]
break
elif input in name.lower():
results.append("\x02[%s]\x02 %s" % (id, name))
if not len(results):
reply("No matches found.")
return
if len(results) > 12:
reply("There are too many options, please narrow your search."
"(%s)" % len(results))
return
out = ", ".join(results)
return out
@hook.command("craft")
@hook.command
def recipe(input, reply=None):
".recipe/.craft <item> -- gets the crafting recipe for an item"
input = input.lower().strip()
results = []
for recipe in recipelist:
if input in recipe.output:
results.append(recipe.line)
if not len(results):
reply("No matches found.")
return
if len(results) > 3:
reply("There are too many options, please narrow your search."
"(%s)" % len(results))
return
for result in results:
reply(result)

View file

@ -1,36 +0,0 @@
import socket
import struct
from util import hook
def get_info(host, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((host, port))
sock.send('\xfe')
response = sock.recv(1)
if response != '\xff':
return "Server gave invalid response: "+repr(response)
length = struct.unpack('!h', sock.recv(2))[0]
values = sock.recv(length*2).decode('utf-16be').split(u'\xa7')
sock.close()
return "%s - %d/%d players" % (values[0], int(values[1]), int(values[2]))
except:
return "Error pinging "+host+":"+str(port)+", is it up? Double-check your address!"
@hook.command
def mcping(inp):
".mcping server[:port] - Ping a Minecraft server to check status."
inp = inp.strip().split(" ")[0]
if ":" in inp:
host, port = inp.split(":", 1)
try:
port = int(port)
except:
return "Invalid port!"
else:
host = inp
port = 25565
return get_info(host, port)

View file

@ -1,5 +1,27 @@
from util import hook, http from util import hook
from util import http
import string import string
import socket
import struct
def mcping_connect(host, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((host, port))
sock.send('\xfe')
response = sock.recv(1)
if response != '\xff':
return "Server gave invalid response: " + repr(response)
length = struct.unpack('!h', sock.recv(2))[0]
values = sock.recv(length * 2).decode('utf-16be').split(u'\xa7')
sock.close()
return "%s - %d/%d players"\
% (values[0], int(values[1]), int(values[2]))
except:
return "Error pinging " + host + ":" + str(port) +\
", is it up? Double-check your address!"
@hook.command(autohelp=False) @hook.command(autohelp=False)
def mcstatus(inp, bot=None): def mcstatus(inp, bot=None):
@ -9,30 +31,58 @@ def mcstatus(inp, bot=None):
if password is None: if password is None:
return "error: no login set" return "error: no login set"
login = http.get("https://login.minecraft.net/?user="+username+"&password="+password+"&version=13") login = http.get("https://login.minecraft.net/?user="\
+ username + "&password=" + password + "&version=13")
if username.lower() in login.lower(): if username.lower() in login.lower():
return "Minecraft login servers appear to be online!" return "Minecraft login servers appear to be online!"
else: else:
return "Minecraft login servers appear to be offline!" return "Minecraft login servers appear to be offline!"
@hook.command @hook.command
def mclogin(inp, say=None): def mclogin(inp, say=None):
".mclogin <username> <password> -- Attempts to log in to Minecrat with <username> and <password> (This is NOT logged)." ".mclogin <username> <password> -- Attempts to log in to Minecraft with "\
" <username> and <password> (This is NOT logged)."
inp = inp.split(" ") inp = inp.split(" ")
username = inp[0] username = inp[0]
password = inp[1] password = inp[1]
say("Attempting to log in using " + username) say("Attempting to log in using " + username)
login = http.get("https://login.minecraft.net/?user=" + username + "&password=" + password + "&version=13") login = http.get("https://login.minecraft.net/?user="\
+ username + "&password=" + password + "&version=13")
if username.lower() in login.lower(): if username.lower() in login.lower():
return "I logged in with " + username return "I logged in with " + username
else: else:
return "I couldn't log in using " + username + ", either the password is wrong or minecraft login servers are down!" return "I couldn't log in using " + username + ", either"\
" the password is wrong or Minecraft login servers are down!"
@hook.command @hook.command
def mcpaid(inp): def mcpaid(inp):
".mcpaid <username> -- Checks if <username> has a premium Minecraft account." ".mcpaid <username> -- Checks if <username> has a "\
"premium Minecraft account."
login = http.get("http://www.minecraft.net/haspaid.jsp?user=" + inp) login = http.get("http://www.minecraft.net/haspaid.jsp?user=" + inp)
if "true" in login: if "true" in login:
return "The account \'" + inp + "\' is a premium Minecraft account!" return "The account \'" + inp + "\' is a "\
"premium Minecraft account!"
else: else:
return "The account \'" + inp + "\' is not a premium Minecraft account!" return "The account \'" + inp + "\' is not a "\
"premium Minecraft account!"
from util import hook
@hook.command
def mcping(inp):
".mcping <server>[:port] - Ping a Minecraft server to check status."
inp = inp.strip().split(" ")[0]
if ":" in inp:
host, port = inp.split(":", 1)
try:
port = int(port)
except:
return "error: invalid port!"
else:
host = inp
port = 25565
return mcping_connect(host, port)

View file

@ -1,28 +0,0 @@
import os
import re
from util import hook
@hook.command(autohelp=False)
def mem(inp):
".mem -- Display the bot's current memory usage."
if os.name == 'posix':
status_file = open("/proc/%d/status" % os.getpid()).read()
line_pairs = re.findall(r"^(\w+):\s*(.*)\s*$", status_file, re.M)
status = dict(line_pairs)
keys = 'VmSize VmLib VmData VmExe VmRSS VmStk'.split()
return ', '.join(key + ':' + status[key] for key in keys)
elif os.name == 'nt':
cmd = "tasklist /FI \"PID eq %s\" /FO CSV /NH" % os.getpid()
out = os.popen(cmd).read()
total = 0
for amount in re.findall(r'([,0-9]+) K', out):
total += int(amount.replace(',', ''))
return 'memory usage: %d kB' % total
return mem.__doc__

View file

@ -1,6 +1,7 @@
import re import re
import socket import socket
import subprocess import subprocess
import platform
import time import time
from util import hook, http from util import hook, http
@ -51,7 +52,7 @@ def onjoin(paraml, conn=None, bot=None):
time.sleep(1) time.sleep(1)
# HTTP Useragent # HTTP Useragent
http.ua_cloudbot = 'CloudBot - http://git.io/cloudbot' http.ua_cloudbot = 'CloudBot - http://git.io/cloudbotirc'
# Stay-alive code # Stay-alive code
stayalive = conn.conf.get('stayalive') stayalive = conn.conf.get('stayalive')

View file

@ -1,9 +1,9 @@
# Plugin by Lukeroge # Plugin by Lukeroge
# <lukeroge@gmail.com> <https://github.com/lukeroge/CloudBot/> from util import hook
from util import molecular
from util import hook, molecular
import unicodedata import unicodedata
@hook.command() @hook.command()
def namegen(inp, say=None, nick=None, input=None, notice=None): def namegen(inp, say=None, nick=None, input=None, notice=None):
".namegen [modules] -- Generates some names using the chosen modules. '.namegen list' will display a list of all modules." ".namegen [modules] -- Generates some names using the chosen modules. '.namegen list' will display a list of all modules."

110
plugins/op.py Executable file
View file

@ -0,0 +1,110 @@
# Plugin made by Lukeroge and neersighted
from util import hook
@hook.command(adminonly=True)
def topic(inp, conn=None, chan=None, notice=None):
".topic [channel] <topic> -- Change the topic of a channel."
inp = inp.split(" ")
if inp[0][0] == "#":
out = "PRIVMSG %s :%s" % (inp[0], message)
else:
out = "TOPIC %s :%s" % (chan, message)
conn.send(out)
@hook.command(adminonly=True)
def kick(inp, chan=None, conn=None, notice=None):
".kick [channel] <user> [reason] -- Makes the bot kick <user> in [channel] "\
"If [channel] is blank the bot will kick the <user> in "\
"the channel the command was used in."
inp = inp.split(" ")
if inp[0][0] == "#":
chan = inp[0]
user = inp[1]
out = "KICK %s %s" % (chan, user)
if len(inp) > 2:
reason = ""
for x in inp[2:]:
reason = reason + x + " "
reason = reason[:-1]
out = out + " :" + reason
else:
user = inp[0]
out = "KICK %s %s" % (chan, user)
if len(inp) > 1:
reason = ""
for x in inp[1:]:
reason = reason + x + " "
reason = reason[:-1]
out = out + " :" + reason
notice("Attempting to kick %s from %s..." % (user, chan))
conn.send(out)
@hook.command(adminonly=True)
def ban(inp, conn=None, chan=None, notice=None):
".ban [channel] <user> -- Makes the bot ban <user> in [channel]. "\
"If [channel] is blank the bot will ban <user> in "\
"the channel the command was used in."
inp = inp.split(" ")
if inp[0][0] == "#":
chan = inp[0]
user = inp[1]
out = "MODE %s +b %s" % (chan, user)
else:
user = inp[0]
out = "MODE %s +b %s" % (chan, user)
notice("Attempting to ban %s from %s..." % (user, chan))
conn.send(out)
@hook.command(adminonly=True)
def unban(inp, conn=None, chan=None, notice=None):
".unban [channel] <user> -- Makes the bot unban <user> in [channel]. "\
"If [channel] is blank the bot will unban <user> in "\
"the channel the command was used in."
inp = inp.split(" ")
if inp[0][0] == "#":
chan = inp[0]
user = inp[1]
out = "MODE %s -b %s" % (chan, user)
else:
user = inp[0]
out = "MODE %s -b %s" % (chan, user)
notice("Attempting to unban %s from %s..." % (user, chan))
conn.send(out)
@hook.command(adminonly=True)
def kickban(inp, chan=None, conn=None, notice=None):
".kickban [channel] <user> [reason] -- Makes the bot kickban <user> in [channel] "\
"If [channel] is blank the bot will kickban the <user> in "\
"the channel the command was used in."
inp = inp.split(" ")
if inp[0][0] == "#":
chan = inp[0]
user = inp[1]
out1 = "MODE %s +b %s" % (chan, user)
out2 = "KICK %s %s" % (chan, user)
if len(inp) > 2:
reason = ""
for x in inp[2:]:
reason = reason + x + " "
reason = reason[:-1]
out = out + " :" + reason
else:
user = inp[0]
out1 = "MODE %s +b %s" % (chan, user)
out2 = "KICK %s %s" % (chan, user)
if len(inp) > 1:
reason = ""
for x in inp[1:]:
reason = reason + x + " "
reason = reason[:-1]
out = out + " :" + reason
notice("Attempting to kickban %s from %s..." % (user, chan))
conn.send(out1)
conn.send(out2)

View file

@ -40,7 +40,7 @@ def gen_password(types):
okay.append(x) okay.append(x)
else: else:
needs_def = 1 needs_def = 1
#defualts to lowercase alpha password if no arguments are found #defaults to lowercase alpha password if no arguments are found
if needs_def == 1: if needs_def == 1:
for x in string.ascii_lowercase: for x in string.ascii_lowercase:
okay.append(x) okay.append(x)
@ -53,10 +53,6 @@ def gen_password(types):
@hook.command @hook.command
def password(inp, notice=None): def password(inp, notice=None):
".password <legenth> [types] -- Generates a password of <legenth> (default 10). [types] can include 'alpha', 'no caps', 'numeric', 'symbols' or any combination of the types, eg. 'numbers symbols'" ".password <length> [types] -- Generates a password of <length> (default 10). [types] can include 'alpha', 'no caps', 'numeric', 'symbols' or any combination of the types, eg. 'numbers symbols'"
password = gen_password(inp) password = gen_password(inp)
short = "error: input too short"
penis = ["penis", "mypenis", "dick", "mydick"]
if inp in penis:
return short
notice(password) notice(password)

View file

@ -2,18 +2,24 @@
from util import hook from util import hook
import subprocess import subprocess
import re import re
import os
ping_regex = re.compile(r"(\d+.\d+)/(\d+.\d+)/(\d+.\d+)/(\d+.\d+)")
@hook.command @hook.command
def ping(inp, reply=None): def ping(inp, reply=None):
".ping <host> [count] -- Pings <host> [count] times." ".ping <host> [count] -- Pings <host> [count] times."
if os.name == "nt":
return "Sorry, this command is not supported on Windows systems."
args = inp.split(' ') args = inp.split(' ')
host = args[0] host = args[0]
# check for a seccond argument and set the ping count
if len(args) > 1: if len(args) > 1:
count = args[1] count = int(args[1])
count = int(count)
if count > 20: if count > 20:
count = 20 count = 20
else: else:
@ -25,14 +31,10 @@ def ping(inp, reply=None):
reply("Attempting to ping %s %s times..." % (host, count)) reply("Attempting to ping %s %s times..." % (host, count))
pingcmd = subprocess.check_output("ping -c "\ pingcmd = subprocess.check_output(["ping", "-c", count, host])
+ count + " " + host, shell=True) if "request timed out" in pingcmd or "unknown host" in pingcmd:
if 'request timed out' in pingcmd or 'unknown host' in pingcmd:
return "error: could not ping host" return "error: could not ping host"
else: else:
m = re.search(r"rtt min/avg/max/mdev = "\ m = re.search(ping_regex, pingcmd)
"(\d+.\d+)/(\d+.\d+)/(\d+.\d+)/(\d+.\d+)", pingcmd)
return "min: %sms, max: %sms, average: %sms, range: %sms, count: %s" \ return "min: %sms, max: %sms, average: %sms, range: %sms, count: %s" \
% (m.group(1), m.group(3), m.group(2), m.group(4), count) % (m.group(1), m.group(3), m.group(2), m.group(4), count)

View file

@ -4,6 +4,7 @@ import random
potatoes = ['AC Belmont', 'AC Blue Pride', 'AC Brador', 'AC Chaleur', 'AC Domino', 'AC Dubuc', 'AC Glacier Chip', 'AC Maple Gold', 'AC Novachip', 'AC Peregrine Red', 'AC Ptarmigan', 'AC Red Island', 'AC Saguenor', 'AC Stampede Russet', 'AC Sunbury', 'Abeille', 'Abnaki', 'Acadia', 'Acadia Russet', 'Accent', 'Adirondack Blue', 'Adirondack Red', 'Adora', 'Agria', 'All Blue', 'All Red', 'Alpha', 'Alta Russet', 'Alturas Russet', 'Amandine', 'Amisk', 'Andover', 'Anoka', 'Anson', 'Aquilon', 'Arran Consul', 'Asterix', 'Atlantic', 'Austrian Crescent', 'Avalanche', 'Banana', 'Bannock Russet', 'Batoche', 'BeRus', 'Belle De Fonteney', 'Belleisle', 'Bintje', 'Blossom', 'Blue Christie', 'Blue Mac', 'Brigus', 'Brise du Nord', 'Butte', 'Butterfinger', 'Caesar', 'CalWhite', 'CalRed', 'Caribe', 'Carlingford', 'Carlton', 'Carola', 'Cascade', 'Castile', 'Centennial Russet', 'Century Russet', 'Charlotte', 'Cherie', 'Cherokee', 'Cherry Red', 'Chieftain', 'Chipeta', 'Coastal Russet', 'Colorado Rose', 'Concurrent', 'Conestoga', 'Cowhorn', 'Crestone Russet', 'Crispin', 'Cupids', 'Daisy Gold', 'Dakota Pearl', 'Defender', 'Delikat', 'Denali', 'Desiree', 'Divina', 'Dundrod', 'Durango Red', 'Early Rose', 'Elba', 'Envol', 'Epicure', 'Eramosa', 'Estima', 'Eva', 'Fabula', 'Fambo', 'Fremont Russet', 'French Fingerling', 'Frontier Russet', 'Fundy', 'Garnet Chile', 'Gem Russet', 'GemStar Russet', 'Gemchip', 'German Butterball', 'Gigant', 'Goldrush', 'Granola', 'Green Mountain', 'Haida', 'Hertha', 'Hilite Russet', 'Huckleberry', 'Hunter', 'Huron', 'IdaRose', 'Innovator', 'Irish Cobbler', 'Island Sunshine', 'Ivory Crisp', 'Jacqueline Lee', 'Jemseg', 'Kanona', 'Katahdin', 'Kennebec', "Kerr's Pink", 'Keswick', 'Keuka Gold', 'Keystone Russet', 'King Edward VII', 'Kipfel', 'Klamath Russet', 'Krantz', 'LaRatte', 'Lady Rosetta', 'Latona', 'Lemhi Russet', 'Liberator', 'Lili', 'MaineChip', 'Marfona', 'Maris Bard', 'Maris Piper', 'Matilda', 'Mazama', 'McIntyre', 'Michigan Purple', 'Millenium Russet', 'Mirton Pearl', 'Modoc', 'Mondial', 'Monona', 'Morene', 'Morning Gold', 'Mouraska', 'Navan', 'Nicola', 'Nipigon', 'Niska', 'Nooksack', 'NorValley', 'Norchip', 'Nordonna', 'Norgold Russet', 'Norking Russet', 'Norland', 'Norwis', 'Obelix', 'Ozette', 'Peanut', 'Penta', 'Peribonka', 'Peruvian Purple', 'Pike', 'Pink Pearl', 'Prospect', 'Pungo', 'Purple Majesty', 'Purple Viking', 'Ranger Russet', 'Reba', 'Red Cloud', 'Red Gold', 'Red La Soda', 'Red Pontiac', 'Red Ruby', 'Red Thumb', 'Redsen', 'Rocket', 'Rose Finn Apple', 'Rose Gold', 'Roselys', 'Rote Erstling', 'Ruby Crescent', 'Russet Burbank', 'Russet Legend', 'Russet Norkotah', 'Russet Nugget', 'Russian Banana', 'Saginaw Gold', 'Sangre', 'Sant<EFBFBD>', 'Satina', 'Saxon', 'Sebago', 'Shepody', 'Sierra', 'Silverton Russet', 'Simcoe', 'Snowden', 'Spunta', "St. John's", 'Summit Russet', 'Sunrise', 'Superior', 'Symfonia', 'Tolaas', 'Trent', 'True Blue', 'Ulla', 'Umatilla Russet', 'Valisa', 'Van Gogh', 'Viking', 'Wallowa Russet', 'Warba', 'Western Russet', 'White Rose', 'Willamette', 'Winema', 'Yellow Finn', 'Yukon Gold'] potatoes = ['AC Belmont', 'AC Blue Pride', 'AC Brador', 'AC Chaleur', 'AC Domino', 'AC Dubuc', 'AC Glacier Chip', 'AC Maple Gold', 'AC Novachip', 'AC Peregrine Red', 'AC Ptarmigan', 'AC Red Island', 'AC Saguenor', 'AC Stampede Russet', 'AC Sunbury', 'Abeille', 'Abnaki', 'Acadia', 'Acadia Russet', 'Accent', 'Adirondack Blue', 'Adirondack Red', 'Adora', 'Agria', 'All Blue', 'All Red', 'Alpha', 'Alta Russet', 'Alturas Russet', 'Amandine', 'Amisk', 'Andover', 'Anoka', 'Anson', 'Aquilon', 'Arran Consul', 'Asterix', 'Atlantic', 'Austrian Crescent', 'Avalanche', 'Banana', 'Bannock Russet', 'Batoche', 'BeRus', 'Belle De Fonteney', 'Belleisle', 'Bintje', 'Blossom', 'Blue Christie', 'Blue Mac', 'Brigus', 'Brise du Nord', 'Butte', 'Butterfinger', 'Caesar', 'CalWhite', 'CalRed', 'Caribe', 'Carlingford', 'Carlton', 'Carola', 'Cascade', 'Castile', 'Centennial Russet', 'Century Russet', 'Charlotte', 'Cherie', 'Cherokee', 'Cherry Red', 'Chieftain', 'Chipeta', 'Coastal Russet', 'Colorado Rose', 'Concurrent', 'Conestoga', 'Cowhorn', 'Crestone Russet', 'Crispin', 'Cupids', 'Daisy Gold', 'Dakota Pearl', 'Defender', 'Delikat', 'Denali', 'Desiree', 'Divina', 'Dundrod', 'Durango Red', 'Early Rose', 'Elba', 'Envol', 'Epicure', 'Eramosa', 'Estima', 'Eva', 'Fabula', 'Fambo', 'Fremont Russet', 'French Fingerling', 'Frontier Russet', 'Fundy', 'Garnet Chile', 'Gem Russet', 'GemStar Russet', 'Gemchip', 'German Butterball', 'Gigant', 'Goldrush', 'Granola', 'Green Mountain', 'Haida', 'Hertha', 'Hilite Russet', 'Huckleberry', 'Hunter', 'Huron', 'IdaRose', 'Innovator', 'Irish Cobbler', 'Island Sunshine', 'Ivory Crisp', 'Jacqueline Lee', 'Jemseg', 'Kanona', 'Katahdin', 'Kennebec', "Kerr's Pink", 'Keswick', 'Keuka Gold', 'Keystone Russet', 'King Edward VII', 'Kipfel', 'Klamath Russet', 'Krantz', 'LaRatte', 'Lady Rosetta', 'Latona', 'Lemhi Russet', 'Liberator', 'Lili', 'MaineChip', 'Marfona', 'Maris Bard', 'Maris Piper', 'Matilda', 'Mazama', 'McIntyre', 'Michigan Purple', 'Millenium Russet', 'Mirton Pearl', 'Modoc', 'Mondial', 'Monona', 'Morene', 'Morning Gold', 'Mouraska', 'Navan', 'Nicola', 'Nipigon', 'Niska', 'Nooksack', 'NorValley', 'Norchip', 'Nordonna', 'Norgold Russet', 'Norking Russet', 'Norland', 'Norwis', 'Obelix', 'Ozette', 'Peanut', 'Penta', 'Peribonka', 'Peruvian Purple', 'Pike', 'Pink Pearl', 'Prospect', 'Pungo', 'Purple Majesty', 'Purple Viking', 'Ranger Russet', 'Reba', 'Red Cloud', 'Red Gold', 'Red La Soda', 'Red Pontiac', 'Red Ruby', 'Red Thumb', 'Redsen', 'Rocket', 'Rose Finn Apple', 'Rose Gold', 'Roselys', 'Rote Erstling', 'Ruby Crescent', 'Russet Burbank', 'Russet Legend', 'Russet Norkotah', 'Russet Nugget', 'Russian Banana', 'Saginaw Gold', 'Sangre', 'Sant<EFBFBD>', 'Satina', 'Saxon', 'Sebago', 'Shepody', 'Sierra', 'Silverton Russet', 'Simcoe', 'Snowden', 'Spunta', "St. John's", 'Summit Russet', 'Sunrise', 'Superior', 'Symfonia', 'Tolaas', 'Trent', 'True Blue', 'Ulla', 'Umatilla Russet', 'Valisa', 'Van Gogh', 'Viking', 'Wallowa Russet', 'Warba', 'Western Russet', 'White Rose', 'Willamette', 'Winema', 'Yellow Finn', 'Yukon Gold']
@hook.command @hook.command
def potato(inp, me=None, input=None): def potato(inp, me=None, input=None):
".potato <user> - Makes <user> a tasty little potato." ".potato <user> - Makes <user> a tasty little potato."

View file

@ -4,27 +4,24 @@ import time
from util import hook from util import hook
def format_quote(q, num, n_quotes): def format_quote(q, num, n_quotes):
"Returns a formatted string of a quote" """Returns a formatted string of a quote"""
ctime, nick, msg = q ctime, nick, msg = q
return "[%d/%d] <%s> %s" % (num, n_quotes, return "[%d/%d] <%s> %s" % (num, n_quotes,
nick, msg) nick, msg)
def create_table_if_not_exists(db): def create_table_if_not_exists(db):
"Creates an empty quote table if one does not already exist" """Creates an empty quote table if one does not already exist"""
db.execute('''CREATE TABLE IF NOT EXISTS quote ( db.execute("create table if not exists quote"
chan, "(chan, nick, add_nick, msg, time real, deleted default 0, "
nick, "primary key (chan, nick, msg))")
add_nick,
msg,
time real,
deleted default 0,
PRIMARY KEY (chan, nick, msg)
)''')
db.commit() db.commit()
def add_quote(db, chan, nick, add_nick, msg): def add_quote(db, chan, nick, add_nick, msg):
"Adds a quote to a nick, returns message string" """Adds a quote to a nick, returns message string"""
try: try:
db.execute('''INSERT OR FAIL INTO quote db.execute('''INSERT OR FAIL INTO quote
(chan, nick, add_nick, msg, time) (chan, nick, add_nick, msg, time)
@ -35,33 +32,53 @@ def add_quote(db, chan, nick, add_nick, msg):
return "Message already stored, doing nothing." return "Message already stored, doing nothing."
return "Quote added." return "Quote added."
def del_quote(db, chan, nick, add_nick, msg): def del_quote(db, chan, nick, add_nick, msg):
"Deletes a quote from a nick" """Deletes a quote from a nick"""
db.execute('''UPDATE quote db.execute('''UPDATE quote SET deleted = 1 WHERE
SET deleted = 1 chan=? AND lower(nick)=lower(?) AND msg=msg''')
WHERE chan=?
AND lower(nick)=lower(?)
AND msg=msg''')
db.commit() db.commit()
def get_quote_num(num, count, name): def get_quote_num(num, count, name):
"Returns the quote number desired from the database" """Returns the quote number to fetch from the DB"""
if num: # Make sure num is a number if it isn't false if num: # Make sure num is a number if it isn't false
num = int(num) num = int(num)
if count == 0: # If there are no quotes in the database, raise an Exception. if count == 0: # Error on no quotes
raise Exception("No quotes found for %s." % name) raise Exception("No quotes found for %s." % name)
if num and num < 0: # If the selected quote is less than 0, count back if possible. if num and num < 0: # Count back if possible
num = count + num + 1 if num + count > -1 else count + 1 num = count + num + 1 if num + count > -1 else count + 1
if num and num > count: # If a number is given and and there are not enough quotes, raise an Exception. if num and num > count: # If there are not enough quotes, raise an error
raise Exception("I only have %d quote%s for %s." % (count, ('s', '')[count == 1], name)) raise Exception("I only have %d quote%s for %s."\
% (count, ('s', '')[count == 1], name))
if num and num == 0: # If the number is zero, set it to one if num and num == 0: # If the number is zero, set it to one
num = 1 num = 1
if not num: # If a number is not given, select a random one if not num: # If a number is not given, select a random one
num = random.randint(1, count) num = random.randint(1, count)
return num return num
def get_quote_by_nick(db, chan, nick, num=False):
"Returns a formatted quote from a nick, random or selected by number" def get_quote_by_nick(db, nick, num=False):
"""Returns a formatted quote from a nick, random or selected by number"""
count = db.execute('''SELECT COUNT(*) FROM quote WHERE deleted != 1
AND lower(nick) = lower(?)''', [nick]).fetchall()[0][0]
try:
num = get_quote_num(num, count, nick)
except Exception as error_message:
return error_message
quote = db.execute('''SELECT time, nick, msg
FROM quote
WHERE deleted != 1
AND lower(nick) = lower(?)
ORDER BY time
LIMIT ?, 1''', (nick, (num - 1))).fetchall()[0]
return format_quote(quote, num, count)
def get_quote_by_nick_chan(db, chan, nick, num=False):
"""Returns a formatted quote from a nick in a channel, random or selected by number"""
count = db.execute('''SELECT COUNT(*) count = db.execute('''SELECT COUNT(*)
FROM quote FROM quote
WHERE deleted != 1 WHERE deleted != 1
@ -82,8 +99,9 @@ def get_quote_by_nick(db, chan, nick, num=False):
LIMIT ?, 1''', (chan, nick, (num - 1))).fetchall()[0] LIMIT ?, 1''', (chan, nick, (num - 1))).fetchall()[0]
return format_quote(quote, num, count) return format_quote(quote, num, count)
def get_quote_by_chan(db, chan, num=False): def get_quote_by_chan(db, chan, num=False):
"Returns a formatted quote from a channel, random or selected by number" """Returns a formatted quote from a channel, random or selected by number"""
count = db.execute('''SELECT COUNT(*) count = db.execute('''SELECT COUNT(*)
FROM quote FROM quote
WHERE deleted != 1 WHERE deleted != 1
@ -102,6 +120,7 @@ def get_quote_by_chan(db, chan, num=False):
LIMIT ?, 1''', (chan, (num - 1))).fetchall()[0] LIMIT ?, 1''', (chan, (num - 1))).fetchall()[0]
return format_quote(quote, num, count) return format_quote(quote, num, count)
@hook.command('q') @hook.command('q')
@hook.command @hook.command
def quote(inp, nick='', chan='', db=None, notice=None): def quote(inp, nick='', chan='', db=None, notice=None):
@ -122,9 +141,9 @@ def quote(inp, nick='', chan='', db=None, notice=None):
if by_chan: if by_chan:
return get_quote_by_chan(db, select, num) return get_quote_by_chan(db, select, num)
else: else:
return get_quote_by_nick(db, chan, select, num) return get_quote_by_nick(db, select, num)
elif retrieve_chan: elif retrieve_chan:
chan, nick, num = retrieve_chan.groups() chan, nick, num = retrieve_chan.groups()
return get_quote_by_nick(db, chan, nick, num) return get_quote_by_nick_chan(db, chan, nick, num)
notice(quote.__doc__) notice(quote.__doc__)

View file

@ -8,7 +8,7 @@ from util import hook, timesince
def db_init(db): def db_init(db):
"check to see that our db has the the seen table and return a connection." "check to see that our db has the the seen table and return a connection."
db.execute("create table if not exists seen(name, time, quote, chan, " db.execute("create table if not exists seen_user(name, time, quote, chan, host, "
"primary key(name, chan))") "primary key(name, chan))")
db.commit() db.commit()
@ -17,9 +17,9 @@ def db_init(db):
@hook.event('PRIVMSG', ignorebots=False) @hook.event('PRIVMSG', ignorebots=False)
def seeninput(paraml, input=None, db=None, bot=None): def seeninput(paraml, input=None, db=None, bot=None):
db_init(db) db_init(db)
db.execute("insert or replace into seen(name, time, quote, chan)" db.execute("insert or replace into seen_user(name, time, quote, chan, host)"
"values(?,?,?,?)", (input.nick.lower(), time.time(), input.msg, "values(?,?,?,?,?)", (input.nick.lower(), time.time(), input.msg,
input.chan)) input.chan, input.host))
db.commit() db.commit()
@ -35,11 +35,11 @@ def seen(inp, nick='', chan='', db=None, input=None):
return "Have you looked in a mirror lately?" return "Have you looked in a mirror lately?"
if not re.match("^[A-Za-z0-9_|.-\]\[]*$", inp.lower()): if not re.match("^[A-Za-z0-9_|.-\]\[]*$", inp.lower()):
return "I cant look up that name, its impossible to use!" return "I can't look up that name, its impossible to use!"
db_init(db) db_init(db)
last_seen = db.execute("select name, time, quote from seen where name" last_seen = db.execute("select name, time, quote from seen_user where name"
" like ? and chan = ?", (inp, chan)).fetchone() " like ? and chan = ?", (inp, chan)).fetchone()
if last_seen: if last_seen:

View file

@ -1,11 +1,11 @@
# Plugin by Lukeroge # Plugin by Lukeroge
# <lukeroge@gmail.com> <https://github.com/lukeroge/CloudBot/>
from util import hook, http from util import hook, http
from re import match from re import match
from urllib2 import urlopen, Request, HTTPError from urllib2 import urlopen, Request, HTTPError
from urllib import urlencode from urllib import urlencode
class ShortenError(Exception): class ShortenError(Exception):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
@ -13,9 +13,15 @@ class ShortenError(Exception):
def __str__(self): def __str__(self):
return repr(self.value) return repr(self.value)
def bitly(url, user, apikey): def bitly(url, user, apikey):
try: try:
params = urlencode({'longUrl': url, 'login': user, 'apiKey': apikey, 'format': 'json'}) if url[:8] == "https://":
pass
elif url[:7] != "http://":
url = "http://" + url
params = urlencode({'longUrl': url, 'login': user, 'apiKey': apikey,
'format': 'json'})
j = http.get_json("http://api.bit.ly/v3/shorten?%s" % params) j = http.get_json("http://api.bit.ly/v3/shorten?%s" % params)
if j['status_code'] == 200: if j['status_code'] == 200:
return j['data']['url'] return j['data']['url']
@ -23,6 +29,7 @@ def bitly(url, user, apikey):
except (HTTPError, ShortenError): except (HTTPError, ShortenError):
return "Could not shorten %s!" % url return "Could not shorten %s!" % url
@hook.command @hook.command
def shorten(inp, bot=None): def shorten(inp, bot=None):
".shorten <url> - Makes an j.mp/bit.ly shortlink to the url provided." ".shorten <url> - Makes an j.mp/bit.ly shortlink to the url provided."
@ -31,12 +38,3 @@ def shorten(inp, bot=None):
if api_key is None: if api_key is None:
return "error: no api key set" return "error: no api key set"
return bitly(inp, api_user, api_key) return bitly(inp, api_user, api_key)
@hook.command
def expand(inp, bot=None):
".expand <url> - Gets the original URL from a shortened link."
try:
url = http.get_url(inp)
except HTTPError, e:
return "Failed to expand URL."
return url

View file

@ -6,17 +6,13 @@ from util import hook
@hook.sieve @hook.sieve
def sieve_suite(bot, input, func, kind, args): def sieve_suite(bot, input, func, kind, args):
if input.command == 'PRIVMSG' and\ if input.command == 'PRIVMSG' and\
input.nick.lower()[-3:] == 'bot' and args.get('ignorebots', True): input.nick.endswith('bot') and args.get('ignorebots', True):
return None return None
if kind == "command": if kind == "command":
if input.trigger in bot.config.get('disabled_commands', []): if input.trigger in bot.config.get('disabled_commands', []):
return None return None
ignored = bot.config.get('ignored', [])
if input.host in ignored or input.nick in ignored:
return None
fn = re.match(r'^plugins.(.+).py$', func._filename) fn = re.match(r'^plugins.(.+).py$', func._filename)
disabled = bot.config.get('disabled_plugins', []) disabled = bot.config.get('disabled_plugins', [])
if fn and fn.group(1).lower() in disabled: if fn and fn.group(1).lower() in disabled:
@ -36,7 +32,8 @@ def sieve_suite(bot, input, func, kind, args):
if args.get('adminonly', False): if args.get('adminonly', False):
admins = bot.config.get('admins', []) admins = bot.config.get('admins', [])
if input.host not in admins and input.nick not in admins: if input.nick not in admins and input.mask not in admins:
input.notice("Sorry, you are not allowed to use this command.")
return None return None
return input return input

View file

@ -1,50 +0,0 @@
from util import hook
import re
import random
slaps = ["slaps <who> with a <item>",
"slaps <who> around a bit with a <item>",
"throws a <item> at <who>",
"grabs a <item> and throws it in <who>'s face",
"holds <who> down and repeatedly whacks them with a <item>",
"prods <who> with a flaming <item>",
"picks up a <item>, and whacks <who> with it",
"ties <who> to a chair and throws a <item> at them",
"hits <who> on the head with a <item>"]
items = ["cast iron skillet",
"large trout",
"baseball bat",
"wooden cane",
"CRT monitor",
"physics textbook",
"television",
"mau5 head",
"five tonn truck",
"roll of duct tape",
"book",
"rubber chicken",
"gold block",
"fire extinguisher",
"heavy rock",
"chunk of dirt"]
@hook.command
def slap(inp, me=None, nick=None, input=None, notice=None):
".slap <user> -- Makes the bot slap <user>."
inp = inp.strip()
if not re.match("^[A-Za-z0-9_|.-\]\[]*$", inp.lower()):
notice("Invalid username!")
return
if inp == input.conn.nick.lower() or inp == "itself":
slap = random.choice(slaps)
slap = re.sub ('<who>', nick, slap)
msg = re.sub ('<item>', random.choice(items), slap)
else:
slap = random.choice(slaps)
slap = re.sub ('<who>', inp, slap)
msg = re.sub ('<item>', random.choice(items), slap)
me(msg)

View file

@ -2,10 +2,12 @@ from util import hook, http, misc
import re import re
import string import string
def sloganize(word): def sloganize(word):
bytes = http.get('http://www.sloganizer.net/en/outbound.php', slogan=word) bytes = http.get('http://www.sloganizer.net/en/outbound.php', slogan=word)
return bytes return bytes
@hook.command("slogan") @hook.command("slogan")
def sloganizr(inp, nick=None, say=None, input=None): def sloganizr(inp, nick=None, say=None, input=None):
".slogan <word> -- Makes a slogan for <word>." ".slogan <word> -- Makes a slogan for <word>."

View file

@ -20,7 +20,7 @@ def stock(inp):
# if we dont get a company name back, the symbol doesn't match a company # if we dont get a company name back, the symbol doesn't match a company
if results['company'] == '': if results['company'] == '':
return "unknown ticker symbol %s" % inp return "error: unknown ticker symbol (%s)" % inp
if results['change'][0] == '-': if results['change'][0] == '-':
results['color'] = "5" results['color'] = "5"

66
plugins/system.py Executable file
View file

@ -0,0 +1,66 @@
import os
import re
import time
import platform
from util import hook
from datetime import timedelta
@hook.command(autohelp=False)
def system(inp):
".system -- Retrieves information about the host system."
hostname = platform.node()
os = platform.platform()
python_imp = platform.python_implementation()
python_ver = platform.python_version()
architecture = '-'.join(platform.architecture())
cpu = platform.machine()
return "Hostname: \x02%s\x02, Operating System: \x02%s\x02, Python " \
"Version: \x02%s %s\x02, Architecture: \x02%s\x02, CPU: \x02%s" \
"\x02" % (hostname, os, python_imp, python_ver, architecture, cpu)
@hook.command(autohelp=False)
def memory(inp):
".memory -- Displays the bot's current memory usage."
if os.name == "posix":
# get process info
status_file = open('/proc/self/status').read()
s = dict(re.findall(r'^(\w+):\s*(.*)\s*$', status_file, re.M))
# get the data we need and process it
data = s['VmRSS'], s['VmSize'], s['VmPeak'], s['VmStk'], s['VmData']
data = [float(i.replace(' kB', '')) for i in data]
strings = [str(round(i / 1024, 2)) + ' MB' for i in data]
# prepare the output
out = "Threads: \x02%s\x02, Real Memory: \x02%s\x02, Allocated Memory: \x02%s\x02, Peak " \
"Allocated Memory: \x02%s\x02, Stack Size: \x02%s\x02, Heap " \
"Size: \x02%s\x02" % (s['Threads'], strings[0], strings[1], strings[2],
strings[3], strings[4])
# return output
return out
elif os.name == "nt":
cmd = 'tasklist /FI "PID eq %s" /FO CSV /NH' % os.getpid()
out = os.popen(cmd).read()
memory = 0
for amount in re.findall(r'([,0-9]+) K', out):
memory += int(amount.replace(',', ''))
memory = str(round(float(memory) / 1024, 2))
return "Memory Usage: \x02%s MB\x02" % memory
else:
return "Sorry, this command is not supported on your OS."
@hook.command(autohelp=False)
def uptime(inp, bot=None):
".uptime -- Shows the bot's uptime."
uptime_raw = round(time.time() - bot.start_time)
uptime = timedelta(seconds=uptime_raw)
return "Uptime: \x02%s\x02" % uptime
@hook.command(autohelp=False)
def pid(inp):
".pid -- Prints the bot's PID."
return "PID: \x02%s\x02" % os.getpid()

View file

@ -25,13 +25,13 @@ def get_tells(db, user_to):
@hook.singlethread @hook.singlethread
@hook.event('PRIVMSG') @hook.event('PRIVMSG')
def tellinput(paraml, input=None, db=None, bot=None): def tellinput(paraml, input=None, notice=None, db=None, bot=None, nick=None):
if 'showtells' in input.msg.lower(): if 'showtells' in input.msg.lower():
return return
db_init(db) db_init(db)
tells = get_tells(db, input.nick) tells = get_tells(db, nick)
if tells: if tells:
user_from, message, time, chan = tells[0] user_from, message, time, chan = tells[0]
@ -43,9 +43,9 @@ def tellinput(paraml, input=None, db=None, bot=None):
reply += " (+%d more, .showtells to view)" % (len(tells) - 1) reply += " (+%d more, .showtells to view)" % (len(tells) - 1)
db.execute("delete from tell where user_to=lower(?) and message=?", db.execute("delete from tell where user_to=lower(?) and message=?",
(input.nick, message)) (nick, message))
db.commit() db.commit()
input.notice(reply) notice(reply)
@hook.command(autohelp=False) @hook.command(autohelp=False)
@ -87,7 +87,7 @@ def tell(inp, nick='', chan='', db=None, input=None, notice=None):
chan = 'a pm' chan = 'a pm'
if user_to == user_from.lower(): if user_to == user_from.lower():
notice("Nope.") notice("Have you looked in a mirror lately?")
return return
if user_to.lower() == input.conn.nick.lower(): if user_to.lower() == input.conn.nick.lower():

243
plugins/time.py Executable file
View file

@ -0,0 +1,243 @@
# Plugin by Lukeroge with some code from Phenny
from util import hook
from util import http
import re
import time
import locale
import datetime
from BeautifulSoup import BeautifulSoup
tags_re = re.compile(r'<[^<]*?>')
TimeZones = {'KST': 9, 'CADT': 10.5, 'EETDST': 3, 'MESZ': 2, 'WADT': 9,
'EET': 2, 'MST': -7, 'WAST': 8, 'IST': 5.5, 'B': 2,
'MSK': 3, 'X': -11, 'MSD': 4, 'CETDST': 2, 'AST': -4,
'HKT': 8, 'JST': 9, 'CAST': 9.5, 'CET': 1, 'CEST': 2,
'EEST': 3, 'EAST': 10, 'METDST': 2, 'MDT': -6, 'A': 1,
'UTC': 0, 'ADT': -3, 'EST': -5, 'E': 5, 'D': 4, 'G': 7,
'F': 6, 'I': 9, 'H': 8, 'K': 10, 'PDT': -7, 'M': 12,
'L': 11, 'O': -2, 'MEST': 2, 'Q': -4, 'P': -3, 'S': -6,
'R': -5, 'U': -8, 'T': -7, 'W': -10, 'WET': 0, 'Y': -12,
'CST': -6, 'EADT': 11, 'Z': 0, 'GMT': 0, 'WETDST': 1,
'C': 3, 'WEST': 1, 'CDT': -5, 'MET': 1, 'N': -1, 'V': -9,
'EDT': -4, 'UT': 0, 'PST': -8, 'MEZ': 1, 'BST': 1,
'ACS': 9.5, 'ATL': -4, 'ALA': -9, 'HAW': -10, 'AKDT': -8,
'AKST': -9,
'BDST': 2}
TZ1 = {
'NDT': -2.5,
'BRST': -2,
'ADT': -3,
'EDT': -4,
'CDT': -5,
'MDT': -6,
'PDT': -7,
'YDT': -8,
'HDT': -9,
'BST': 1,
'MEST': 2,
'SST': 2,
'FST': 2,
'CEST': 2,
'EEST': 3,
'WADT': 8,
'KDT': 10,
'EADT': 13,
'NZD': 13,
'NZDT': 13,
'GMT': 0,
'UT': 0,
'UTC': 0,
'WET': 0,
'WAT': -1,
'AT': -2,
'FNT': -2,
'BRT': -3,
'MNT': -4,
'EWT': -4,
'AST': -4,
'EST': -5,
'ACT': -5,
'CST': -6,
'MST': -7,
'PST': -8,
'YST': -9,
'HST': -10,
'CAT': -10,
'AHST': -10,
'NT': -11,
'IDLW': -12,
'CET': 1,
'MEZ': 1,
'ECT': 1,
'MET': 1,
'MEWT': 1,
'SWT': 1,
'SET': 1,
'FWT': 1,
'EET': 2,
'UKR': 2,
'BT': 3,
'ZP4': 4,
'ZP5': 5,
'ZP6': 6,
'WST': 8,
'HKT': 8,
'CCT': 8,
'JST': 9,
'KST': 9,
'EAST': 10,
'GST': 10,
'NZT': 12,
'NZST': 12,
'IDLE': 12
}
TZ2 = {
'ACDT': 10.5,
'ACST': 9.5,
'ADT': 3,
'AEDT': 11,
'AEST': 10,
'AHDT': 9,
'AHST': 10,
'AST': 4,
'AT': 2,
'AWDT': -9,
'AWST': -8,
'BAT': -3,
'BDST': -2,
'BET': 11,
'BST': -1,
'BT': -3,
'BZT2': 3,
'CADT': -10.5,
'CAST': -9.5,
'CAT': 10,
'CCT': -8,
# 'CDT': 5,
'CED': -2,
'CET': -1,
'CST': 6,
'EAST': -10,
# 'EDT': 4,
'EED': -3,
'EET': -2,
'EEST': -3,
'EST': 5,
'FST': -2,
'FWT': -1,
'GMT': 0,
'GST': -10,
'HDT': 9,
'HST': 10,
'IDLE': -12,
'IDLW': 12,
# 'IST': -5.5,
'IT': -3.5,
'JST': -9,
'JT': -7,
'KST': -9,
'MDT': 6,
'MED': -2,
'MET': -1,
'MEST': -2,
'MEWT': -1,
'MST': 7,
'MT': -8,
'NDT': 2.5,
'NFT': 3.5,
'NT': 11,
'NST': -6.5,
'NZ': -11,
'NZST': -12,
'NZDT': -13,
'NZT': -12,
'PDT': 7,
'PST': 8,
'ROK': -9,
'SAD': -10,
'SAST': -9,
'SAT': -9,
'SDT': -10,
'SST': -2,
'SWT': -1,
'USZ3': -4,
'USZ4': -5,
'USZ5': -6,
'USZ6': -7,
'UT': 0,
'UTC': 0,
'UZ10': -11,
'WAT': 1,
'WET': 0,
'WST': -8,
'YDT': 8,
'YST': 9,
'ZP4': -4,
'ZP5': -5,
'ZP6': -6
}
TZ3 = {
'AEST': 10,
'AEDT': 11
}
# TimeZones.update(TZ2) # do these have to be negated?
TimeZones.update(TZ1)
TimeZones.update(TZ3)
r_local = re.compile(r'\([a-z]+_[A-Z]+\)')
# gets the time from a timezone (code from phenny)
def get_time(tz):
TZ = tz.upper()
if (TZ == 'UTC') or (TZ == 'Z'):
msg = time.strftime("\x02%I:%M%p\x02 %A - \x02Time\x02 in \x02 " \
"GMT", time.gmtime())
return msg
elif r_local.match(tz):
locale.setlocale(locale.LC_TIME, (tz[1:-1], 'UTF-8'))
msg = time.strftime("\x02%I:%M%p\x02 %A - \x02Time\x02 in \x02" \
+ str(TZ), time.gmtime())
return msg
elif TZ in TimeZones:
offset = TimeZones[TZ] * 3600
timenow = time.gmtime(time.time() + offset)
msg = time.strftime("\x02%I:%M%p\x02 %A - \x02Time\x02 in \x02" \
+ str(TZ), timenow)
return msg
elif tz and tz[0] in ('+', '-') and 4 <= len(tz) <= 6:
timenow = time.gmtime(time.time() + (int(tz[:3]) * 3600))
msg = time.strftime("\x02%I:%M%p\x02 %A - \x02Time\x02 in\x02" \
" GMT" + str(tz), timenow)
return msg
else:
timenow = time.gmtime(time.time() + (int(tz) * 3600))
msg = time.strftime("\x02%I:%M%p\x02 %A - \x02Time\x02 in\x02" \
" GMT " + str(tz), timenow)
return msg
@hook.command("time")
def time_command(inp):
".time <area> -- Gets the time in <area>"
request = http.get('http://www.google.com/search', q="time in " + inp)
soup = BeautifulSoup(request)
response = soup.find('td', {'style': 'font-size:medium'})
if response:
output = response.renderContents()
output = tags_re.sub('\x02', output.strip())
return output
else:
try:
return get_time(inp)
except ValueError:
return "Could not get the time for " + inp + "!"

View file

@ -90,7 +90,7 @@ def db_search(db, nick, query):
@hook.command @hook.command
def todo(inp, nick='', chan='', db=None, notice=None, bot=None): def todo(inp, nick='', chan='', db=None, notice=None, bot=None):
".todo (add|del|list|search) [@user] args -- Manipulates your list of todos." ".todo (add|del|list|search) args -- Manipulates your list of todos."
db_init(db) db_init(db)
@ -99,9 +99,11 @@ def todo(inp, nick='', chan='', db=None, notice=None, bot=None):
args = parts[1:] args = parts[1:]
if len(args) and args[0].startswith("@"): # code to allow users to access each others factoids and a copy of help
nick = args[0][1:] # ".todo (add|del|list|search) [@user] args -- Manipulates your list of todos."
args = args[1:] #if len(args) and args[0].startswith("@"):
# nick = args[0][1:]
# args = args[1:]
if cmd == 'add': if cmd == 'add':
if not len(args): if not len(args):

View file

@ -1,4 +1,4 @@
# MyGengo translation plugin by lukeroge and neersighted # BING translation plugin by Lukeroge and neersighted
from util import hook from util import hook
from util import http from util import http
import re import re

View file

@ -1,31 +1,26 @@
""" # written by Scaevolus, modified by Lukeroge
twitter.py: written by Scaevolus 2009, modified by Lukeroge 2012
retrieves most recent tweets
"""
import random import random
import re import re
from time import strptime, strftime from time import strftime
from time import strptime
from datetime import datetime from datetime import datetime
from util import hook
from util import hook, http, timesince from util import http
from util import timesince
def unescape_xml(string): def unescape_xml(string):
# unescape the 5 chars that might be escaped in xml """Unescapes XML"""
# gratuitously functional
# return reduce(lambda x, y: x.replace(*y), (string,
# zip('&gt; &lt; &apos; &quote; &amp'.split(), '> < \' " &'.split()))
# boring, normal
return string.replace('&gt;', '>').replace('&lt;', '<').replace('&apos;', return string.replace('&gt;', '>').replace('&lt;', '<').replace('&apos;',
"'").replace('&quote;', '"').replace('&amp;', '&') "'").replace('&quote;', '"').replace('&amp;', '&')
history = [] history = []
history_max_size = 250 history_max_size = 250
def parseDateTime(s): def parseDateTime(s):
"""Parses the date from a string"""
if s is None: if s is None:
return None return None
m = re.match(r'(.*?)(?:\.(\d+))?(([-+]\d{1,2}):(\d{2}))?$', m = re.match(r'(.*?)(?:\.(\d+))?(([-+]\d{1,2}):(\d{2}))?$',
@ -154,9 +149,9 @@ def twitter(inp):
strptime(time.text, strptime(time.text,
'%a %b %d %H:%M:%S +0000 %Y')) '%a %b %d %H:%M:%S +0000 %Y'))
time_pretty = timesince.timesince(parseDateTime(time_raw), datetime.utcnow()) time_nice = timesince.timesince(parseDateTime(time_raw), datetime.utcnow())
text = unescape_xml(tweet.find(text).text.replace('\n', '')) text = unescape_xml(tweet.find(text).text.replace('\n', ''))
screen_name = tweet.find(screen_name).text screen_name = tweet.find(screen_name).text
return "\x02@%s\x02: %s [ %s ago ]" % (screen_name, text, time_pretty) return "\x02@%s\x02: %s (%s ago)" % (screen_name, text, time_nice)

View file

@ -1,40 +1,36 @@
from util import hook, http, urlnorm from util import hook, http, urlnorm
import urllib
from urllib2 import urlopen, Request, HTTPError
import re import re
import BeautifulSoup
ignored_urls = ["http://google.com", "http://youtube.com", titler = re.compile(r'(?si)<title>(.+?)</title>')
"http://pastebin.com", "http://mibpaste.com",
"http://fpaste.com", "http://git.io"]
def parse(match):
url = urlnorm.normalize(match.encode('utf-8')) def get_title(url):
if url not in ignored_urls: url = urlnorm.normalize(url.encode('utf-8'))
url = url.decode('utf-8') url = url.decode('utf-8')
try: # add http if its missing
soup = BeautifulSoup.BeautifulSoup(http.get(url)) if not url.startswith("http"):
return soup.title.string
except:
return "fail"
@hook.regex(r'(^[^\.])([a-zA-Z]://|www\.)?[^ ]+(\.[a-z]+)(\/)?(.*)')
def urlparser(match, say=None):
url = urlnorm.normalize(match.group().encode('utf-8'))
if url[:7] != "http://":
if url[:8] != "https://":
url = "http://" + url url = "http://" + url
for x in ignored_urls: try:
if x in url: # get the title
return request = http.open(url)
title = parse(url) real_url = request.geturl()
if title == "fail": text = request.read()
return text = text.decode('utf8')
match = titler.search(text)
title = match.group(1)
except:
return "Could not parse URL! Are you sure its valid?"
title = http.unescape(title) title = http.unescape(title)
realurl = http.get_url(url)
if realurl == url: # if the url has been redirected, show us
say("(Link) %s" % title) if real_url == url:
return return title
else: else:
say("(Link) %s [%s]" % (title, realurl)) return u"%s [%s]" % (title, real_url)
return
@hook.command
def title(inp):
".title <url> -- gets the title of a web page"
return get_title(inp)

View file

@ -33,6 +33,8 @@
"""molecular.py -- molecular (ngenoid) name generator """molecular.py -- molecular (ngenoid) name generator
Modified for CloudBot by Lukeroge.
This module knows how to generate "random" names for RPG characters. This module knows how to generate "random" names for RPG characters.
It uses the same method as the "ngen" name generator by Kimmo Kulovesi, It uses the same method as the "ngen" name generator by Kimmo Kulovesi,
and in fact it can use the same name files. molecular.py knows how and in fact it can use the same name files. molecular.py knows how
@ -201,26 +203,3 @@ class Molecule:
if len(self.nametbl["final"]) > 0: if len(self.nametbl["final"]) > 0:
n.append(random.choice(self.nametbl["final"])) n.append(random.choice(self.nametbl["final"]))
return string.join(n, "") return string.join(n, "")
if __name__ == "__main__":
if len(sys.argv) <= 1:
sys.stderr.write( \
"Usage: molecular.py [ -r file ] [ nn ]\n")
sys.exit(0)
name = Molecule()
i = 1
while i < len(sys.argv):
arg = sys.argv[i]
if arg == "-r":
i += 1
name.load(sys.argv[i])
else:
n = int(sys.argv[i])
lst = []
for i in range(n):
print name.name()
i += 1

105
plugins/violence.py Executable file
View file

@ -0,0 +1,105 @@
from util import hook
import re
import random
nick_re = re.compile(r"^[A-Za-z0-9_|.-\]\[]*$")
# define lists for messages
larts = []
kills = []
kill_bodyparts = []
slaps = []
slap_items = []
with open("plugins/data/larts.txt") as f:
for line in f.readlines():
if line.startswith("//"):
continue
larts.append(line.strip())
with open("plugins/data/slaps.txt") as f:
for line in f.readlines():
if line.startswith("//"):
continue
slaps.append(line.strip())
with open("plugins/data/slap_items.txt") as f:
for line in f.readlines():
if line.startswith("//"):
continue
slap_items.append(line.strip())
with open("plugins/data/kills.txt") as f:
for line in f.readlines():
if line.startswith("//"):
continue
kills.append(line.strip())
with open("plugins/data/kill_bodyparts.txt") as f:
for line in f.readlines():
if line.startswith("//"):
continue
kill_bodyparts.append(line.strip())
@hook.command
def slap(inp, me=None, nick=None, conn=None, notice=None):
".slap <user> -- Makes the bot slap <user>."
target = inp.lower()
if not re.match(nick_re, target):
notice("Invalid username!")
return
# if the user is trying to make the bot slap itself, slap them
if target == conn.nick.lower() or target == "itself":
target = nick
else:
target = inp
out = random.choice(slaps)
out = out.replace('<who>', target)
out = out.replace('<item>', random.choice(slap_items))
# act out the message
me(out)
@hook.command
def lart(inp, me=None, nick=None, conn=None, notice=None):
".lart <user> -- LARTs <user>."
target = inp.lower()
if not re.match(nick_re, target):
notice("Invalid username!")
return
if target == conn.nick.lower() or target == "itself":
target = nick
else:
target = inp
out = random.choice(larts)
out = out.replace('<who>', target)
out = out.replace('<item>', random.choice(slap_items))
me(out)
@hook.command
def kill(inp, me=None, nick=None, conn=None, notice=None):
".kill <user> -- Makes the bot kill <user>."
target = inp.lower()
if not re.match(nick_re, target):
notice("Invalid username!")
return
if target == conn.nick.lower() or target == "itself":
target = nick
else:
target = inp
out = random.choice(kills)
out = out.replace('<who>', target)
out = out.replace('<body>', random.choice(kill_bodyparts))
me(out)