changing magical discipline from arcane to serpentine
This commit is contained in:
parent
29e7fef87f
commit
d560cb90dc
75
bot.py
75
bot.py
|
@ -11,17 +11,18 @@ import imp
|
||||||
import re
|
import re
|
||||||
import thread
|
import thread
|
||||||
import Queue
|
import Queue
|
||||||
import copy
|
import collections
|
||||||
|
|
||||||
import irc
|
import irc
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
os.chdir(sys.path[0]) #do stuff relative to the installation directory
|
os.chdir(sys.path[0]) #do stuff relative to the installation directory
|
||||||
|
sys.path += ['plugins'] # so 'import hook' works without duplication
|
||||||
|
|
||||||
class Bot(object):
|
class Bot(object):
|
||||||
def __init__(self, nick, channel, network):
|
def __init__(self, nick, channel, network):
|
||||||
self.commands = [] # fn, name, func, args
|
self.commands = [] # (fn, funcname, name, line), func, args
|
||||||
self.filters = [] #fn, name, func
|
self.filters = [] #(fn, funcname, line), func
|
||||||
self.nick = nick
|
self.nick = nick
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
self.network = network
|
self.network = network
|
||||||
|
@ -30,55 +31,43 @@ bot = Bot(nick, channel, network)
|
||||||
|
|
||||||
print 'Loading plugins'
|
print 'Loading plugins'
|
||||||
typs = '|'.join('command filter event'.split())
|
typs = '|'.join('command filter event'.split())
|
||||||
magic_re = re.compile(r'^\s*#(%s)(?:: +(\S+) *(\S.*)?)?\s*$' % typs)
|
magic_re = re.compile(r'^\s*#!(%s)(?:: +(\S+) *(\S.*)?)?\s*$' % typs)
|
||||||
|
|
||||||
def reload_plugins(mtime=[0]):
|
def reload_plugins(mtime=[0]):
|
||||||
new_mtime = os.stat('plugins')
|
new_mtime = os.stat('plugins')
|
||||||
if new_mtime == mtime[0]:
|
if new_mtime == mtime[0]:
|
||||||
return
|
return
|
||||||
|
|
||||||
bot.commands = []
|
bot.plugs = collections.defaultdict(lambda: [])
|
||||||
bot.filters = []
|
|
||||||
|
|
||||||
|
|
||||||
for filename in glob.glob("plugins/*.py"):
|
for filename in glob.glob("plugins/*.py"):
|
||||||
shortname = os.path.splitext(os.path.basename(filename))[0]
|
shortname = os.path.splitext(os.path.basename(filename))[0]
|
||||||
try:
|
try:
|
||||||
plugin = imp.load_source(shortname, filename)
|
plugin = imp.load_source(shortname, filename)
|
||||||
source = open(filename).read().split('\n')
|
for thing in dir(plugin):
|
||||||
#this is a nasty hack, but it simplifies registration
|
thing = getattr(plugin, thing)
|
||||||
funcs = [x for x in dir(plugin)
|
if hasattr(thing, '_skybot_hook'):
|
||||||
if str(type(getattr(plugin,x))) == "<type 'function'>"]
|
for type, data in thing._skybot_hook:
|
||||||
for func in funcs:
|
bot.plugs[type] += [data]
|
||||||
#read the line before the function definition, looking for a
|
|
||||||
# comment that tells the bot about what it does
|
|
||||||
func = getattr(plugin, func)
|
|
||||||
lineno = func.func_code.co_firstlineno
|
|
||||||
if lineno == 1:
|
|
||||||
continue #can't have a line before the first line...
|
|
||||||
m = magic_re.match(source[lineno-2])
|
|
||||||
if m:
|
|
||||||
typ, nam, rest = m.groups()
|
|
||||||
if nam is None:
|
|
||||||
nam = func.__name__
|
|
||||||
if rest is None:
|
|
||||||
rest = '\s*(.*)'
|
|
||||||
if typ == 'command':
|
|
||||||
args = {'name': nam, 'hook': nam + rest}
|
|
||||||
bot.commands.append((filename, nam, func, args))
|
|
||||||
elif typ == 'filter':
|
|
||||||
bot.filters.append((filename, nam, func))
|
|
||||||
elif typ == 'event':
|
|
||||||
args = {'name': nam, 'prefix':False,
|
|
||||||
'events': [nam] + rest.split()}
|
|
||||||
bot.commands.append((filename, nam, func, args))
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print e
|
print ' error:', e
|
||||||
|
|
||||||
mtime[0] = new_mtime
|
mtime[0] = new_mtime
|
||||||
|
|
||||||
reload_plugins()
|
reload_plugins()
|
||||||
|
|
||||||
|
print ' plugin listing:'
|
||||||
|
for type, plugs in sorted(bot.plugs.iteritems()):
|
||||||
|
print ' %s:' % type
|
||||||
|
for plug in plugs:
|
||||||
|
out = ' %s:%s:%s' % (plug[0])
|
||||||
|
print out,
|
||||||
|
if len(plug) == 3 and 'hook' in plug[2]:
|
||||||
|
print '%s%s' % (' ' * (35 - len(out)), plug[2]['hook'])
|
||||||
|
else:
|
||||||
|
print
|
||||||
|
print
|
||||||
|
|
||||||
print 'Connecting to IRC'
|
print 'Connecting to IRC'
|
||||||
bot.irc = irc.irc(network, nick)
|
bot.irc = irc.irc(network, nick)
|
||||||
bot.irc.join(channel)
|
bot.irc.join(channel)
|
||||||
|
@ -100,13 +89,12 @@ class Input(object):
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
|
|
||||||
class FakeBot(object):
|
class FakeBot(object):
|
||||||
def __init__(self, bot, input, fn, func):
|
def __init__(self, bot, input, func):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.input = input
|
self.input = input
|
||||||
self.msg = bot.irc.msg
|
self.msg = bot.irc.msg
|
||||||
self.cmd = bot.irc.cmd
|
self.cmd = bot.irc.cmd
|
||||||
self.join = bot.irc.join
|
self.join = bot.irc.join
|
||||||
self.fn = func
|
|
||||||
self.func = func
|
self.func = func
|
||||||
self.doreply = True
|
self.doreply = True
|
||||||
if input.command == "PRIVMSG":
|
if input.command == "PRIVMSG":
|
||||||
|
@ -130,22 +118,19 @@ class FakeBot(object):
|
||||||
else:
|
else:
|
||||||
self.say(unicode(out))
|
self.say(unicode(out))
|
||||||
|
|
||||||
print bot.commands
|
|
||||||
print bot.filters
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
out = bot.irc.out.get(timeout=1)
|
out = bot.irc.out.get(timeout=1)
|
||||||
reload_plugins()
|
reload_plugins()
|
||||||
for fn, name, func, args in bot.commands:
|
for csig, func, args in (bot.plugs['command'] + bot.plugs['event']):
|
||||||
input = Input(*out)
|
input = Input(*out)
|
||||||
for fn, nam, filt in bot.filters:
|
for fsig, sieve in bot.plugs['sieve']:
|
||||||
input = filt(bot, func, args, input)
|
input = sieve(bot, input, func, args)
|
||||||
if input == None:
|
if input == None:
|
||||||
break
|
break
|
||||||
if input == None:
|
if input == None:
|
||||||
continue
|
continue
|
||||||
print '<<<', input.raw
|
print '<<<', input.raw
|
||||||
thread.start_new_thread(FakeBot(bot, input, fn, func).run, ())
|
thread.start_new_thread(FakeBot(bot, input, func).run, ())
|
||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -4,10 +4,12 @@ http://brainfuck.sourceforge.net/brain.py'''
|
||||||
import re
|
import re
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
import hook
|
||||||
|
|
||||||
BUFFER_SIZE = 5000
|
BUFFER_SIZE = 5000
|
||||||
MAX_STEPS = 1000000
|
MAX_STEPS = 1000000
|
||||||
|
|
||||||
#command
|
@hook.command
|
||||||
def bf(input):
|
def bf(input):
|
||||||
"""Runs a Brainfuck program."""
|
"""Runs a Brainfuck program."""
|
||||||
|
|
||||||
|
@ -50,7 +52,8 @@ def bf(input):
|
||||||
if mp > rightmost:
|
if mp > rightmost:
|
||||||
rightmost = mp
|
rightmost = mp
|
||||||
if mp >= len(memory):
|
if mp >= len(memory):
|
||||||
memory.extend([0]*BUFFER_SIZE) # no restriction on memory growth!
|
# no restriction on memory growth!
|
||||||
|
memory.extend([0]*BUFFER_SIZE)
|
||||||
elif c == '<':
|
elif c == '<':
|
||||||
mp = mp - 1 % len(memory)
|
mp = mp - 1 % len(memory)
|
||||||
elif c == '.':
|
elif c == '.':
|
||||||
|
|
|
@ -6,6 +6,8 @@ simulates dicerolls
|
||||||
import re
|
import re
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
import hook
|
||||||
|
|
||||||
whitespace_re = re.compile(r'\s+')
|
whitespace_re = re.compile(r'\s+')
|
||||||
valid_diceroll_re = re.compile(r'^[+-]?(\d+|\d*d\d+)([+-](\d+|\d*d\d+))*$')
|
valid_diceroll_re = re.compile(r'^[+-]?(\d+|\d*d\d+)([+-](\d+|\d*d\d+))*$')
|
||||||
sign_re = re.compile(r'[+-]?(?:\d*d)?\d+')
|
sign_re = re.compile(r'[+-]?(?:\d*d)?\d+')
|
||||||
|
@ -25,7 +27,7 @@ def nrolls(count, n):
|
||||||
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))
|
||||||
|
|
||||||
#command
|
@hook.command
|
||||||
def dice(input):
|
def dice(input):
|
||||||
".dice <diceroll> - simulates dicerolls, e.g. .dice 2d20-d5+4 roll 2 " \
|
".dice <diceroll> - simulates dicerolls, e.g. .dice 2d20-d5+4 roll 2 " \
|
||||||
"D20s, subtract 1D5, add 4"
|
"D20s, subtract 1D5, add 4"
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
#filter
|
import hook
|
||||||
def filter_suite(bot, func, args, input):
|
|
||||||
|
@hook.sieve
|
||||||
|
def filter_suite(bot, input, func, args):
|
||||||
args.setdefault('events', ['PRIVMSG'])
|
args.setdefault('events', ['PRIVMSG'])
|
||||||
|
|
||||||
if input.command not in args['events']:
|
if input.command not in args['events']:
|
||||||
|
@ -15,6 +17,9 @@ def filter_suite(bot, func, args, input):
|
||||||
if args['prefix']:
|
if args['prefix']:
|
||||||
hook = bot.commandprefix + args['hook']
|
hook = bot.commandprefix + args['hook']
|
||||||
|
|
||||||
|
if input.command == 'INVITE':
|
||||||
|
print func, hook
|
||||||
|
|
||||||
input.re = re.match(hook, input.msg)
|
input.re = re.match(hook, input.msg)
|
||||||
if input.re is None:
|
if input.re is None:
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
#command
|
import hook
|
||||||
|
|
||||||
|
@hook.command
|
||||||
def md5(input):
|
def md5(input):
|
||||||
return hashlib.md5(input).hexdigest()
|
return hashlib.md5(input).hexdigest()
|
||||||
|
|
||||||
#command
|
@hook.command
|
||||||
def sha1(input):
|
def sha1(input):
|
||||||
return hashlib.sha1(input).hexdigest()
|
return hashlib.sha1(input).hexdigest()
|
||||||
|
|
||||||
#command
|
@hook.command
|
||||||
def hash(input):
|
def hash(input):
|
||||||
return ', '.join(x + ": " + getattr(hashlib, x)(input).hexdigest()
|
return ', '.join(x + ": " + getattr(hashlib, x)(input).hexdigest()
|
||||||
for x in 'md5 sha1 sha256'.split())
|
for x in 'md5 sha1 sha256'.split())
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
def _isfunc(x):
|
||||||
|
if type(x) == type(_isfunc):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _hook_add(func, add):
|
||||||
|
if not hasattr(func, '_skybot_hook'):
|
||||||
|
func._skybot_hook = []
|
||||||
|
func._skybot_hook.append(add)
|
||||||
|
|
||||||
|
def _make_sig(f):
|
||||||
|
return f.func_code.co_filename, f.func_name, f.func_code.co_firstlineno
|
||||||
|
|
||||||
|
def sieve(func):
|
||||||
|
if func.func_code.co_argcount != 4:
|
||||||
|
raise ValueError, \
|
||||||
|
'sieves must take 4 arguments: (bot, input, func, args)'
|
||||||
|
_hook_add(func, ['sieve', (_make_sig(func), func)])
|
||||||
|
return func
|
||||||
|
|
||||||
|
def command(func, hook=None, **kwargs):
|
||||||
|
args = {}
|
||||||
|
def command_wrapper(func):
|
||||||
|
if func.func_code.co_argcount not in (1, 2):
|
||||||
|
raise ValueError, \
|
||||||
|
'commands must take 1 or 2 arguments: (inp) or (bot, input)'
|
||||||
|
args.setdefault('name', func.func_name)
|
||||||
|
args.setdefault('hook', args['name'] + r'\s*(.*)')
|
||||||
|
_hook_add(func, ['command', (_make_sig(func), func, args)])
|
||||||
|
return func
|
||||||
|
|
||||||
|
if hook is not None or kwargs or not _isfunc(func):
|
||||||
|
if func is not None:
|
||||||
|
args['name'] = func
|
||||||
|
if hook is not None:
|
||||||
|
args['hook'] = hook
|
||||||
|
args.update(kwargs)
|
||||||
|
return command_wrapper
|
||||||
|
else:
|
||||||
|
return command_wrapper(func)
|
||||||
|
|
||||||
|
def event(arg):
|
||||||
|
args = {}
|
||||||
|
def event_wrapper(func):
|
||||||
|
if func.func_code.co_argcount != 2:
|
||||||
|
raise ValueError, \
|
||||||
|
'events must take 2 arguments: (bot, input)'
|
||||||
|
args['name'] = func.func_name
|
||||||
|
args['prefix'] = False
|
||||||
|
args.setdefault('events', '*')
|
||||||
|
_hook_add(func, ['event', (_make_sig(func), func, args)])
|
||||||
|
return func
|
||||||
|
|
||||||
|
if _isfunc(arg):
|
||||||
|
return event_wrapper(arg)
|
||||||
|
else:
|
||||||
|
args['events'] = arg.split()
|
||||||
|
return event_wrapper
|
|
@ -1,8 +1,13 @@
|
||||||
#event: KICK INVITE
|
import hook
|
||||||
|
|
||||||
|
@hook.event('KICK INVITE')
|
||||||
def rejoin(bot, input):
|
def rejoin(bot, input):
|
||||||
|
print input.command, input.inp
|
||||||
|
|
||||||
if input.command == 'KICK':
|
if input.command == 'KICK':
|
||||||
if input.paraml[1] == bot.bot.nick:
|
if input.paraml[1] == bot.bot.nick:
|
||||||
bot.join(input.paraml[0])
|
if input.paraml[0] == bot.bot.channel:
|
||||||
|
bot.join(input.paraml[0])
|
||||||
|
|
||||||
if input.command == 'INVITE':
|
if input.command == 'INVITE':
|
||||||
bot.join(input.inp)
|
bot.join(input.inp)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import urllib
|
import urllib
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import hook
|
||||||
|
|
||||||
re_lineends = re.compile(r'[\r\n]*')
|
re_lineends = re.compile(r'[\r\n]*')
|
||||||
|
|
||||||
#command
|
@hook.command
|
||||||
def py(input):
|
def py(input):
|
||||||
res = urllib.urlopen("http://eval.appspot.com/eval?statement=%s" %
|
res = urllib.urlopen("http://eval.appspot.com/eval?statement=%s" %
|
||||||
urllib.quote(input.strip(),safe='')).readlines()
|
urllib.quote(input.strip(),safe='')).readlines()
|
||||||
|
|
|
@ -6,7 +6,9 @@ retrieves most recent tweets
|
||||||
import urllib
|
import urllib
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
#command
|
import hook
|
||||||
|
|
||||||
|
@hook.command
|
||||||
def twitter(bot, input):
|
def twitter(bot, input):
|
||||||
'''.twitter <user> - gets most recent tweet from <user>'''
|
'''.twitter <user> - gets most recent tweet from <user>'''
|
||||||
if not input.inp.strip():
|
if not input.inp.strip():
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
import urllib
|
import urllib
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
#command: weather
|
import hook
|
||||||
|
|
||||||
|
@hook.command
|
||||||
def weather(bot, input):
|
def weather(bot, input):
|
||||||
".weather <location> -- queries the google weather API for weather data"
|
".weather <location> -- queries the google weather API for weather data"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import urllib
|
||||||
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
|
def ytdata(id):
|
||||||
|
url = 'http://gdata.youtube.com/feeds/api/videos/' + idt
|
||||||
|
print url
|
||||||
|
data = urllib.urlopen(url).read()
|
||||||
|
if len(data) < 50: # it's some error message; ignore
|
||||||
|
print data
|
||||||
|
return
|
||||||
|
global x
|
||||||
|
def
|
||||||
|
x = ElementTree.XML(data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
ytdata('the0KZLEacs')
|
Loading…
Reference in New Issue