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 thread
|
||||
import Queue
|
||||
import copy
|
||||
import collections
|
||||
|
||||
import irc
|
||||
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):
|
||||
def __init__(self, nick, channel, network):
|
||||
self.commands = [] # fn, name, func, args
|
||||
self.filters = [] #fn, name, func
|
||||
self.commands = [] # (fn, funcname, name, line), func, args
|
||||
self.filters = [] #(fn, funcname, line), func
|
||||
self.nick = nick
|
||||
self.channel = channel
|
||||
self.network = network
|
||||
|
@ -30,55 +31,43 @@ bot = Bot(nick, channel, network)
|
|||
|
||||
print 'Loading plugins'
|
||||
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]):
|
||||
new_mtime = os.stat('plugins')
|
||||
if new_mtime == mtime[0]:
|
||||
return
|
||||
|
||||
bot.commands = []
|
||||
bot.filters = []
|
||||
|
||||
bot.plugs = collections.defaultdict(lambda: [])
|
||||
|
||||
for filename in glob.glob("plugins/*.py"):
|
||||
shortname = os.path.splitext(os.path.basename(filename))[0]
|
||||
try:
|
||||
plugin = imp.load_source(shortname, filename)
|
||||
source = open(filename).read().split('\n')
|
||||
#this is a nasty hack, but it simplifies registration
|
||||
funcs = [x for x in dir(plugin)
|
||||
if str(type(getattr(plugin,x))) == "<type 'function'>"]
|
||||
for func in funcs:
|
||||
#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))
|
||||
for thing in dir(plugin):
|
||||
thing = getattr(plugin, thing)
|
||||
if hasattr(thing, '_skybot_hook'):
|
||||
for type, data in thing._skybot_hook:
|
||||
bot.plugs[type] += [data]
|
||||
except Exception, e:
|
||||
print e
|
||||
print ' error:', e
|
||||
|
||||
mtime[0] = new_mtime
|
||||
|
||||
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'
|
||||
bot.irc = irc.irc(network, nick)
|
||||
bot.irc.join(channel)
|
||||
|
@ -100,13 +89,12 @@ class Input(object):
|
|||
self.msg = msg
|
||||
|
||||
class FakeBot(object):
|
||||
def __init__(self, bot, input, fn, func):
|
||||
def __init__(self, bot, input, func):
|
||||
self.bot = bot
|
||||
self.input = input
|
||||
self.msg = bot.irc.msg
|
||||
self.cmd = bot.irc.cmd
|
||||
self.join = bot.irc.join
|
||||
self.fn = func
|
||||
self.func = func
|
||||
self.doreply = True
|
||||
if input.command == "PRIVMSG":
|
||||
|
@ -130,22 +118,19 @@ class FakeBot(object):
|
|||
else:
|
||||
self.say(unicode(out))
|
||||
|
||||
print bot.commands
|
||||
print bot.filters
|
||||
|
||||
while True:
|
||||
try:
|
||||
out = bot.irc.out.get(timeout=1)
|
||||
reload_plugins()
|
||||
for fn, name, func, args in bot.commands:
|
||||
for csig, func, args in (bot.plugs['command'] + bot.plugs['event']):
|
||||
input = Input(*out)
|
||||
for fn, nam, filt in bot.filters:
|
||||
input = filt(bot, func, args, input)
|
||||
for fsig, sieve in bot.plugs['sieve']:
|
||||
input = sieve(bot, input, func, args)
|
||||
if input == None:
|
||||
break
|
||||
if input == None:
|
||||
continue
|
||||
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:
|
||||
pass
|
||||
|
|
|
@ -4,10 +4,12 @@ http://brainfuck.sourceforge.net/brain.py'''
|
|||
import re
|
||||
import random
|
||||
|
||||
import hook
|
||||
|
||||
BUFFER_SIZE = 5000
|
||||
MAX_STEPS = 1000000
|
||||
|
||||
#command
|
||||
@hook.command
|
||||
def bf(input):
|
||||
"""Runs a Brainfuck program."""
|
||||
|
||||
|
@ -50,7 +52,8 @@ def bf(input):
|
|||
if mp > rightmost:
|
||||
rightmost = mp
|
||||
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 == '<':
|
||||
mp = mp - 1 % len(memory)
|
||||
elif c == '.':
|
||||
|
|
|
@ -6,6 +6,8 @@ simulates dicerolls
|
|||
import re
|
||||
import random
|
||||
|
||||
import hook
|
||||
|
||||
whitespace_re = re.compile(r'\s+')
|
||||
valid_diceroll_re = re.compile(r'^[+-]?(\d+|\d*d\d+)([+-](\d+|\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,
|
||||
(((n+1)*(2*n+1)/6.-(.5*(1+n))**2)*count)**.5))
|
||||
|
||||
#command
|
||||
@hook.command
|
||||
def dice(input):
|
||||
".dice <diceroll> - simulates dicerolls, e.g. .dice 2d20-d5+4 roll 2 " \
|
||||
"D20s, subtract 1D5, add 4"
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import re
|
||||
|
||||
#filter
|
||||
def filter_suite(bot, func, args, input):
|
||||
import hook
|
||||
|
||||
@hook.sieve
|
||||
def filter_suite(bot, input, func, args):
|
||||
args.setdefault('events', ['PRIVMSG'])
|
||||
|
||||
if input.command not in args['events']:
|
||||
|
@ -15,6 +17,9 @@ def filter_suite(bot, func, args, input):
|
|||
if args['prefix']:
|
||||
hook = bot.commandprefix + args['hook']
|
||||
|
||||
if input.command == 'INVITE':
|
||||
print func, hook
|
||||
|
||||
input.re = re.match(hook, input.msg)
|
||||
if input.re is None:
|
||||
return None
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import hashlib
|
||||
|
||||
#command
|
||||
import hook
|
||||
|
||||
@hook.command
|
||||
def md5(input):
|
||||
return hashlib.md5(input).hexdigest()
|
||||
|
||||
#command
|
||||
@hook.command
|
||||
def sha1(input):
|
||||
return hashlib.sha1(input).hexdigest()
|
||||
|
||||
#command
|
||||
@hook.command
|
||||
def hash(input):
|
||||
return ', '.join(x + ": " + getattr(hashlib, x)(input).hexdigest()
|
||||
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):
|
||||
print input.command, input.inp
|
||||
|
||||
if input.command == 'KICK':
|
||||
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':
|
||||
bot.join(input.inp)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import urllib
|
||||
import re
|
||||
|
||||
import hook
|
||||
|
||||
re_lineends = re.compile(r'[\r\n]*')
|
||||
|
||||
#command
|
||||
@hook.command
|
||||
def py(input):
|
||||
res = urllib.urlopen("http://eval.appspot.com/eval?statement=%s" %
|
||||
urllib.quote(input.strip(),safe='')).readlines()
|
||||
|
|
|
@ -6,7 +6,9 @@ retrieves most recent tweets
|
|||
import urllib
|
||||
from xml.etree import ElementTree
|
||||
|
||||
#command
|
||||
import hook
|
||||
|
||||
@hook.command
|
||||
def twitter(bot, input):
|
||||
'''.twitter <user> - gets most recent tweet from <user>'''
|
||||
if not input.inp.strip():
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
import urllib
|
||||
from xml.etree import ElementTree
|
||||
|
||||
#command: weather
|
||||
import hook
|
||||
|
||||
@hook.command
|
||||
def weather(bot, input):
|
||||
".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