lots of stuff fixed
This commit is contained in:
parent
25133138c1
commit
15bfada07d
120
bot.py
120
bot.py
|
@ -1,71 +1,79 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
network = "irc.synirc.net"
|
network = "localhost"
|
||||||
nickname = "skybot"
|
nickname = "skybot"
|
||||||
channel = "#mongbot"
|
channel = "#skybot"
|
||||||
|
|
||||||
import sys, os, glob, imp, re
|
import sys
|
||||||
import thread, Queue, copy
|
import os
|
||||||
import irc, yaml
|
import glob
|
||||||
|
import imp
|
||||||
|
import re
|
||||||
|
import thread
|
||||||
|
import Queue
|
||||||
|
import copy
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
class Empty(object): #this is used to store attributes
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Bot(object):
|
class Bot(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.plugins = {}
|
self.plugins = {}
|
||||||
self.commands = {}
|
self.commands = [] # fn, name, func, args
|
||||||
self.listens = {}
|
self.listens = {}
|
||||||
self.filters = {}
|
self.filters = [] #fn, name, func
|
||||||
self.daemons = {}
|
self.daemons = {}
|
||||||
|
|
||||||
def command(self, name, func, **filterargs):
|
|
||||||
self.commands[name] = (func, filterargs)
|
|
||||||
|
|
||||||
def listen(self, name, func):
|
|
||||||
self.listens[name] = func
|
|
||||||
|
|
||||||
def filter(self, name, func):
|
|
||||||
self.filters[name] = func
|
|
||||||
|
|
||||||
def daemon(self, name, func):
|
|
||||||
self.daemons[name] = func
|
|
||||||
|
|
||||||
bot = Bot()
|
bot = Bot()
|
||||||
|
bot.nickname = nickname
|
||||||
|
bot.channel = channel
|
||||||
|
bot.network = network
|
||||||
|
|
||||||
print 'Loading plugins'
|
print 'Loading plugins'
|
||||||
|
magic_re = re.compile(r'^\s*#(command|filter)(?:: +(\S+) *(\S.*)?)?\s*$')
|
||||||
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:
|
||||||
bot.plugins[shortname] = imp.load_source(shortname,filename)
|
bot.plugins[shortname] = imp.load_source(shortname, filename)
|
||||||
|
plugin = bot.plugins[shortname]
|
||||||
|
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))
|
||||||
|
if typ == 'filter':
|
||||||
|
bot.filters.append((filename, nam, func))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print e
|
print e
|
||||||
|
|
||||||
print bot.plugins
|
|
||||||
|
|
||||||
print 'Registering plugins'
|
|
||||||
for name, plugin in bot.plugins.iteritems():
|
|
||||||
if hasattr(plugin, 'setup'):
|
|
||||||
try:
|
|
||||||
plugin.setup(bot)
|
|
||||||
except Exception, e:
|
|
||||||
print e
|
|
||||||
|
|
||||||
print 'Connecting to IRC'
|
|
||||||
|
|
||||||
bot.irc = irc.irc(network, nickname)
|
|
||||||
bot.irc.join(channel)
|
|
||||||
bot.commandprefix = '^(?:\.|'+nickname+'[:,]*\s*)'
|
|
||||||
|
|
||||||
if bot.daemons:
|
if bot.daemons:
|
||||||
print 'Running daemons'
|
print 'Running daemons'
|
||||||
for daemon in bot.daemons.itervalues():
|
for daemon in bot.daemons.itervalues():
|
||||||
thread.start_new_thread(daemon, ())
|
thread.start_new_thread(daemon, ())
|
||||||
|
|
||||||
|
print 'Connecting to IRC'
|
||||||
|
bot.irc = irc.irc(network, nickname)
|
||||||
|
bot.irc.join(channel)
|
||||||
|
bot.commandprefix = '^(?:\.|'+nickname+'[:,]*\s*)'
|
||||||
|
|
||||||
print 'Running main loop'
|
print 'Running main loop'
|
||||||
|
|
||||||
class Input(object):
|
class Input(object):
|
||||||
|
@ -82,9 +90,14 @@ class Input(object):
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
|
|
||||||
class FakeBot(object):
|
class FakeBot(object):
|
||||||
def __init__(self, bot, input):
|
def __init__(self, bot, input, func):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.input = input
|
self.input = input
|
||||||
|
self.msg = bot.irc.msg
|
||||||
|
self.cmd = bot.irc.cmd
|
||||||
|
self.func = func
|
||||||
|
if input.command == "PRIVMSG":
|
||||||
|
self.chan = input.paraml[0]
|
||||||
|
|
||||||
def say(self, msg):
|
def say(self, msg):
|
||||||
self.bot.irc.msg(input.paraml[0], msg)
|
self.bot.irc.msg(input.paraml[0], msg)
|
||||||
|
@ -92,22 +105,25 @@ class FakeBot(object):
|
||||||
def reply(self, msg):
|
def reply(self, msg):
|
||||||
self.say(input.nick + ': ' + msg)
|
self.say(input.nick + ': ' + msg)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
out = self.func(self, self.input)
|
||||||
|
if out is not None:
|
||||||
|
self.reply(unicode(out))
|
||||||
|
|
||||||
print bot.commands
|
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)
|
||||||
#print repr(out)
|
for fn, name, func, args in bot.commands:
|
||||||
for func, args in bot.commands.itervalues():
|
|
||||||
input = Input(*out)
|
input = Input(*out)
|
||||||
for filt in bot.filters.itervalues():
|
for fn, nam, filt in bot.filters:
|
||||||
input = filt(bot, func, args, input)
|
input = filt(bot, func, args, input)
|
||||||
if input == False:
|
if input == None:
|
||||||
break
|
break
|
||||||
if input == False:
|
if input == None:
|
||||||
continue
|
break
|
||||||
thread.start_new_thread(func,(FakeBot(bot, input), input))
|
thread.start_new_thread(FakeBot(bot, input, func).run, ())
|
||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
pass
|
pass
|
||||||
#except KeyboardInterrupt:
|
|
||||||
# sys.exit()
|
|
||||||
|
|
34
irc.py
34
irc.py
|
@ -1,7 +1,21 @@
|
||||||
import sys, re, thread, Queue
|
import sys
|
||||||
import socket, asyncore, asynchat
|
import re
|
||||||
|
import socket
|
||||||
|
import thread
|
||||||
|
import asyncore
|
||||||
|
import asynchat
|
||||||
|
import Queue
|
||||||
|
|
||||||
queue = Queue.Queue
|
queue = Queue.Queue
|
||||||
|
|
||||||
|
def decode(txt, codecs=['utf-8', 'iso-8859-1', 'shift_jis', 'cp1252']):
|
||||||
|
if len(codecs) == 0:
|
||||||
|
return txt.decode('utf-8', 'ignore')
|
||||||
|
try:
|
||||||
|
return txt.decode(codecs[0])
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return decode(txt, codecs[1:])
|
||||||
|
|
||||||
class crlf_tcp(asynchat.async_chat):
|
class crlf_tcp(asynchat.async_chat):
|
||||||
"Handles tcp connections that consist of utf-8 lines ending with crlf"
|
"Handles tcp connections that consist of utf-8 lines ending with crlf"
|
||||||
def __init__(self, host, port):
|
def __init__(self, host, port):
|
||||||
|
@ -17,30 +31,28 @@ class crlf_tcp(asynchat.async_chat):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.connect((self.host, self.port))
|
self.connect((self.host, self.port))
|
||||||
thread.start_new_thread(self.queue_read_loop,())
|
|
||||||
asyncore.loop()
|
asyncore.loop()
|
||||||
|
|
||||||
|
def handle_connect(self):
|
||||||
|
thread.start_new_thread(self.queue_read_loop,())
|
||||||
|
|
||||||
def queue_read_loop(self):
|
def queue_read_loop(self):
|
||||||
#this is an attempt at making this thread-safe
|
|
||||||
#at least with this, only TWO things could be modifying the output
|
|
||||||
#buffer at the same time
|
|
||||||
while True:
|
while True:
|
||||||
line = self.oqueue.get()
|
line = self.oqueue.get()
|
||||||
print ">>> %r" % line
|
print ">>> %r" % line
|
||||||
self.push(line.encode('utf-8')+'\r\n')
|
self.push(line.encode('utf-8','replace')+'\r\n')
|
||||||
|
|
||||||
def collect_incoming_data(self, data):
|
def collect_incoming_data(self, data):
|
||||||
self.buffer += data
|
self.buffer += data
|
||||||
|
|
||||||
def found_terminator(self):
|
def found_terminator(self):
|
||||||
line = self.buffer
|
line = self.buffer
|
||||||
# print repr(line)
|
self.iqueue.put(decode(line))
|
||||||
self.iqueue.put(line.encode('utf-8'))
|
|
||||||
self.buffer = ''
|
self.buffer = ''
|
||||||
|
|
||||||
irc_prefix_re = re.compile(r'(.*?) (.*?) (.*)')
|
irc_prefix_re = re.compile(r'(.*?) (.*?) (.*)')
|
||||||
irc_noprefix_re = re.compile(r'()(.*?) (.*)')
|
irc_noprefix_re = re.compile(r'()(.*?) (.*)')
|
||||||
irc_param_re = re.compile(r'(?:^|(?<= ))(:.*|[^ ]*)')
|
irc_param_re = re.compile(r'(?:^|(?<= ))(:.*|[^ ]+)')
|
||||||
irc_netmask_re = re.compile(r':?([^!@]*)!?([^@]*)@?(.*)')
|
irc_netmask_re = re.compile(r':?([^!@]*)!?([^@]*)@?(.*)')
|
||||||
|
|
||||||
class irc(object):
|
class irc(object):
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
def setup(bot):
|
#filter
|
||||||
bot.filter("default_filters", filter_suite)
|
|
||||||
|
|
||||||
def filter_suite(bot, func, args, input):
|
def filter_suite(bot, func, args, input):
|
||||||
args.setdefault('events', ['PRIVMSG'])
|
args.setdefault('events', ['PRIVMSG'])
|
||||||
|
|
||||||
if input.command not in args['events']:
|
if input.command not in args['events']:
|
||||||
return False
|
if args['events'] != '*':
|
||||||
|
return None
|
||||||
|
|
||||||
args.setdefault('hook', r'(.*)')
|
args.setdefault('hook', r'(.*)')
|
||||||
args.setdefault('prefix', True)
|
args.setdefault('prefix', True)
|
||||||
|
@ -16,9 +15,10 @@ def filter_suite(bot, func, args, input):
|
||||||
if args['prefix']:
|
if args['prefix']:
|
||||||
hook = bot.commandprefix + args['hook']
|
hook = bot.commandprefix + args['hook']
|
||||||
|
|
||||||
m = re.match(hook, input.msg)
|
input.re = re.match(hook, input.msg)
|
||||||
if not m:
|
if input.re is None:
|
||||||
return False
|
return None
|
||||||
|
|
||||||
input.re = m
|
input.inp = ' '.join(input.re.groups())
|
||||||
|
|
||||||
return input
|
return input
|
||||||
|
|
|
@ -1,54 +1,28 @@
|
||||||
|
#!/usr/bin/python
|
||||||
"weather, thanks to google"
|
"weather, thanks to google"
|
||||||
|
|
||||||
import urllib, re, pickle, os
|
import urllib
|
||||||
from xml.dom import minidom
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
WEATHER_URL = 'http://www.google.com/ig/api'
|
|
||||||
|
|
||||||
def setup(bot):
|
|
||||||
bot.command("weather", weather, hook=r"weather (.*)")
|
|
||||||
|
|
||||||
def goog_weather(query):
|
|
||||||
data = urllib.urlencode({'weather':query})
|
|
||||||
url = WEATHER_URL + "?" + data
|
|
||||||
#print url
|
|
||||||
dom = minidom.parse(urllib.urlopen(url))
|
|
||||||
|
|
||||||
if len(dom.getElementsByTagName('problem_cause')):
|
|
||||||
return {'error': True}
|
|
||||||
|
|
||||||
place = dom.getElementsByTagName('city')[0].getAttribute('data')
|
|
||||||
temp = dom.getElementsByTagName('temp_f')[0].getAttribute('data')
|
|
||||||
|
|
||||||
conditions = dom.getElementsByTagName('current_conditions')[0]
|
|
||||||
condition = conditions.getElementsByTagName('condition')[0].getAttribute('data')
|
|
||||||
wind = conditions.getElementsByTagName('wind_condition')[0].getAttribute('data')
|
|
||||||
humidity = conditions.getElementsByTagName('humidity')[0].getAttribute('data')
|
|
||||||
|
|
||||||
forecast = dom.getElementsByTagName('forecast_conditions')[0]
|
|
||||||
high = forecast.getElementsByTagName('high')[0].getAttribute('data')
|
|
||||||
low = forecast.getElementsByTagName('low')[0].getAttribute('data')
|
|
||||||
|
|
||||||
return {
|
|
||||||
'place': place,
|
|
||||||
'temp': temp,
|
|
||||||
'high': high,
|
|
||||||
'low': low,
|
|
||||||
'condition': condition,
|
|
||||||
'wind': wind,
|
|
||||||
'humidity': humidity
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#command: weather
|
||||||
def weather(bot, input):
|
def weather(bot, input):
|
||||||
".weather <location> -- queries google weather API for weather data"
|
'''.weather <location> -- queries the google weather API for weather data'''
|
||||||
q = input.re.groups()[0]
|
|
||||||
cond = goog_weather(q)
|
|
||||||
|
|
||||||
if cond.has_key('error'):
|
if not input.inp.strip(): # blank line
|
||||||
bot.reply(u'Couldn\'t fetch weather data for "%s", try using a zip/postal code' % (q))
|
return "welp"
|
||||||
return
|
|
||||||
|
|
||||||
format = u'%s %sF (%s/%s/%s) (h:%sF,l:%sF)'
|
data = urllib.urlencode({'weather':input.inp.encode('utf-8')})
|
||||||
args = (cond['place'],cond['temp'],cond['condition'],cond['wind'],cond['humidity'],cond['high'],cond['low'])
|
url = 'http://www.google.com/ig/api?' + data
|
||||||
|
w = ElementTree.parse(urllib.urlopen(url)).find('weather')
|
||||||
|
|
||||||
bot.reply(format.encode('utf-8') % args)
|
if w.find('problem_cause') is not None:
|
||||||
|
return "Couldn't fetch weather data for '%s', try using a zip or " \
|
||||||
|
"postal code." % input.inp
|
||||||
|
|
||||||
|
info = dict((e.tag, e.get('data')) for e in w.find('current_conditions'))
|
||||||
|
info['city'] = w.find('forecast_information/city').get('data')
|
||||||
|
info['high'] = w.find('forecast_conditions/high').get('data')
|
||||||
|
info['low'] = w.find('forecast_conditions/low').get('data')
|
||||||
|
|
||||||
|
return '%(city)s: %(condition)s, %(temp_f)sF/%(temp_c)sC (H:%(high)sF, ' \
|
||||||
|
'L:%(low)sF), %(humidity)s, %(wind_condition)s.' % info
|
||||||
|
|
Loading…
Reference in New Issue