PEP8 compliance + clean dotnetpad

This commit is contained in:
Ryan Hitchman 2010-02-28 19:32:41 -07:00
parent ab8f316eb9
commit 253881f4b4
35 changed files with 223 additions and 174 deletions

18
bot.py
View File

@ -5,9 +5,9 @@ import Queue
import sys import sys
import time import time
sys.path += ['plugins'] # so 'import hook' works without duplication sys.path += ['plugins'] # so 'import hook' works without duplication
sys.path += ['lib'] sys.path += ['lib']
os.chdir(sys.path[0] or '.') # do stuff relative to the installation directory os.chdir(sys.path[0] or '.') # do stuff relative to the install directory
class Bot(object): class Bot(object):
@ -19,7 +19,7 @@ bot = Bot()
print 'Loading plugins' print 'Loading plugins'
# bootstrap the reloader # bootstrap the reloader
eval(compile(open(os.path.join('core', 'reload.py'), 'U').read(), eval(compile(open(os.path.join('core', 'reload.py'), 'U').read(),
os.path.join('core', 'reload.py'), 'exec')) os.path.join('core', 'reload.py'), 'exec'))
reload(init=True) reload(init=True)
@ -30,12 +30,12 @@ bot.conns = {}
try: try:
for name, conf in bot.config['connections'].iteritems(): for name, conf in bot.config['connections'].iteritems():
if conf.get('ssl'): if conf.get('ssl'):
bot.conns[name] = SSLIRC(conf['server'], conf['nick'], bot.conns[name] = SSLIRC(conf['server'], conf['nick'], conf=conf,
port=conf.get('port', 6667), channels=conf['channels'], conf=conf, port=conf.get('port', 6667), channels=conf['channels'],
ignore_certificate_errors=conf.get('ignore_cert', True)) ignore_certificate_errors=conf.get('ignore_cert', True))
else: else:
bot.conns[name] = IRC(conf['server'], conf['nick'], bot.conns[name] = IRC(conf['server'], conf['nick'], conf=conf,
port=conf.get('port', 6667), channels=conf['channels'], conf=conf) port=conf.get('port', 6667), channels=conf['channels'])
except Exception, e: except Exception, e:
print 'ERROR: malformed config file', Exception, e print 'ERROR: malformed config file', Exception, e
sys.exit() sys.exit()
@ -47,8 +47,8 @@ if not os.path.exists(bot.persist_dir):
print 'Running main loop' print 'Running main loop'
while True: while True:
reload() # these functions only do things reload() # these functions only do things
config() # if changes have occured config() # if changes have occured
for conn in bot.conns.itervalues(): for conn in bot.conns.itervalues():
try: try:

View File

@ -2,8 +2,10 @@ import inspect
import json import json
import os import os
def load(): def load():
return return
def save(conf): def save(conf):
json.dump(conf, open('config', 'w'), sort_keys=True, indent=2) json.dump(conf, open('config', 'w'), sort_keys=True, indent=2)
@ -26,7 +28,8 @@ if not os.path.exists('config'):
bot.config = json.load(open('config')) bot.config = json.load(open('config'))
bot._config_mtime = os.stat('config').st_mtime bot._config_mtime = os.stat('config').st_mtime
def config(): def config():
# reload config from file if file has changed # reload config from file if file has changed
if bot._config_mtime != os.stat('config').st_mtime: if bot._config_mtime != os.stat('config').st_mtime:
bot.config = json.load(open('config')) bot.config = json.load(open('config'))

View File

@ -1,9 +1,10 @@
import os import os
import sqlite3 import sqlite3
def get_db_connection(server, name='skybot.%s.db'): def get_db_connection(server, name='skybot.%s.db'):
"returns an sqlite3 connection to a persistent database" "returns an sqlite3 connection to a persistent database"
filename = os.path.join(bot.persist_dir, name % server) filename = os.path.join(bot.persist_dir, name % server)
return sqlite3.connect(filename, timeout=10) return sqlite3.connect(filename, timeout=10)
bot.get_db_connection = get_db_connection bot.get_db_connection = get_db_connection

View File

@ -7,6 +7,7 @@ import Queue
from ssl import wrap_socket, CERT_NONE, CERT_REQUIRED, SSLError from ssl import wrap_socket, CERT_NONE, CERT_REQUIRED, SSLError
def decode(txt): def decode(txt):
for codec in ('utf-8', 'iso-8859-1', 'shift_jis', 'cp1252'): for codec in ('utf-8', 'iso-8859-1', 'shift_jis', 'cp1252'):
try: try:
@ -15,14 +16,15 @@ def decode(txt):
continue continue
return txt.decode('utf-8', 'ignore') return txt.decode('utf-8', 'ignore')
class crlf_tcp(object): class crlf_tcp(object):
"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, timeout=300): def __init__(self, host, port, timeout=300):
self.ibuffer = "" self.ibuffer = ""
self.obuffer = "" self.obuffer = ""
self.oqueue = Queue.Queue() # lines to be sent out self.oqueue = Queue.Queue() # lines to be sent out
self.iqueue = Queue.Queue() # lines that were received self.iqueue = Queue.Queue() # lines that were received
self.socket = self.create_socket() self.socket = self.create_socket()
self.host = host self.host = host
self.port = port self.port = port
@ -30,7 +32,7 @@ class crlf_tcp(object):
def create_socket(self): def create_socket(self):
return socket.socket(socket.AF_INET, socket.TCP_NODELAY) return socket.socket(socket.AF_INET, socket.TCP_NODELAY)
def run(self): def run(self):
self.socket.connect((self.host, self.port)) self.socket.connect((self.host, self.port))
thread.start_new_thread(self.recv_loop, ()) thread.start_new_thread(self.recv_loop, ())
@ -38,10 +40,10 @@ class crlf_tcp(object):
def recv_from_socket(self, nbytes): def recv_from_socket(self, nbytes):
return self.socket.recv(nbytes) return self.socket.recv(nbytes)
def get_timeout_exception_type(self): def get_timeout_exception_type(self):
return socket.timeout return socket.timeout
def handle_receive_exception(self, error, last_timestamp): def handle_receive_exception(self, error, last_timestamp):
if time.time() - last_timestamp > self.timeout: if time.time() - last_timestamp > self.timeout:
self.iqueue.put(StopIteration) self.iqueue.put(StopIteration)
@ -81,28 +83,30 @@ class crlf_tcp(object):
sent = self.socket.send(self.obuffer) sent = self.socket.send(self.obuffer)
self.obuffer = self.obuffer[sent:] self.obuffer = self.obuffer[sent:]
class crlf_ssl_tcp(crlf_tcp): class crlf_ssl_tcp(crlf_tcp):
"Handles ssl tcp connetions that consist of utf-8 lines ending with crlf" "Handles ssl tcp connetions that consist of utf-8 lines ending with crlf"
def __init__(self, host, port, ignore_cert_errors, timeout=300): def __init__(self, host, port, ignore_cert_errors, timeout=300):
self.ignore_cert_errors = ignore_cert_errors self.ignore_cert_errors = ignore_cert_errors
crlf_tcp.__init__(self, host, port, timeout) crlf_tcp.__init__(self, host, port, timeout)
def create_socket(self): def create_socket(self):
return wrap_socket(crlf_tcp.create_socket(self), server_side=False, return wrap_socket(crlf_tcp.create_socket(self), server_side=False,
cert_reqs = [CERT_REQUIRED, CERT_NONE][self.ignore_cert_errors]) cert_reqs=CERT_NONE if self.ignore_cert_errors else
CERT_REQUIRED)
def recv_from_socket(self, nbytes): def recv_from_socket(self, nbytes):
return self.socket.read(nbytes) return self.socket.read(nbytes)
def get_timeout_exception_type(self): def get_timeout_exception_type(self):
return SSLError return SSLError
def handle_receive_exception(self, error, last_timestamp): def handle_receive_exception(self, error, last_timestamp):
# this is terrible # this is terrible
if not "timed out" in error.args[0]: if not "timed out" in error.args[0]:
raise raise
return crlf_tcp.handle_receive_exception(self, error, last_timestamp) return crlf_tcp.handle_receive_exception(self, error, last_timestamp)
irc_prefix_rem = re.compile(r'(.*?) (.*?) (.*)').match irc_prefix_rem = re.compile(r'(.*?) (.*?) (.*)').match
irc_noprefix_rem = re.compile(r'()(.*?) (.*)').match irc_noprefix_rem = re.compile(r'()(.*?) (.*)').match
irc_netmask_rem = re.compile(r':?([^!@]*)!?([^@]*)@?(.*)').match irc_netmask_rem = re.compile(r':?([^!@]*)!?([^@]*)@?(.*)').match
@ -119,7 +123,7 @@ class IRC(object):
self.port = port self.port = port
self.nick = nick self.nick = nick
self.out = Queue.Queue() #responses from the server are placed here self.out = Queue.Queue() # responses from the server are placed here
# format: [rawline, prefix, command, params, # format: [rawline, prefix, command, params,
# nick, user, host, paramlist, msg] # nick, user, host, paramlist, msg]
self.connect() self.connect()
@ -128,7 +132,7 @@ class IRC(object):
def create_connection(self): def create_connection(self):
return crlf_tcp(self.server, self.port) return crlf_tcp(self.server, self.port)
def connect(self): def connect(self):
self.conn = self.create_connection() self.conn = self.create_connection()
thread.start_new_thread(self.conn.run, ()) thread.start_new_thread(self.conn.run, ())
@ -146,7 +150,7 @@ class IRC(object):
self.connect() self.connect()
continue continue
if msg.startswith(":"): #has a prefix if msg.startswith(":"): # has a prefix
prefix, command, params = irc_prefix_rem(msg).groups() prefix, command, params = irc_prefix_rem(msg).groups()
else: else:
prefix, command, params = irc_noprefix_rem(msg).groups() prefix, command, params = irc_noprefix_rem(msg).groups()
@ -178,13 +182,14 @@ class IRC(object):
def cmd(self, command, params=None): def cmd(self, command, params=None):
if params: if params:
params[-1] = ':' + params[-1] params[-1] = ':' + params[-1]
self.send(command+' '+' '.join(params)) self.send(command + ' ' + ' '.join(params))
else: else:
self.send(command) self.send(command)
def send(self, str): def send(self, str):
self.conn.oqueue.put(str) self.conn.oqueue.put(str)
class FakeIRC(IRC): class FakeIRC(IRC):
def __init__(self, server, nick, port=6667, channels=[], conf={}, fn=""): def __init__(self, server, nick, port=6667, channels=[], conf={}, fn=""):
self.channels = channels self.channels = channels
@ -193,7 +198,7 @@ class FakeIRC(IRC):
self.port = port self.port = port
self.nick = nick self.nick = nick
self.out = Queue.Queue() #responses from the server are placed here self.out = Queue.Queue() # responses from the server are placed here
self.f = open(fn, 'rb') self.f = open(fn, 'rb')
@ -207,7 +212,7 @@ class FakeIRC(IRC):
print "!!!!DONE READING FILE!!!!" print "!!!!DONE READING FILE!!!!"
return return
if msg.startswith(":"): #has a prefix if msg.startswith(":"): # has a prefix
prefix, command, params = irc_prefix_rem(msg).groups() prefix, command, params = irc_prefix_rem(msg).groups()
else: else:
prefix, command, params = irc_noprefix_rem(msg).groups() prefix, command, params = irc_noprefix_rem(msg).groups()
@ -225,12 +230,13 @@ class FakeIRC(IRC):
def cmd(self, command, params=None): def cmd(self, command, params=None):
pass pass
class SSLIRC(IRC): class SSLIRC(IRC):
def __init__(self, server, nick, port=6667, channels=[], conf={}, def __init__(self, server, nick, port=6667, channels=[], conf={},
ignore_certificate_errors=True): ignore_certificate_errors=True):
self.ignore_cert_errors = ignore_certificate_errors self.ignore_cert_errors = ignore_certificate_errors
IRC.__init__(self, server, nick, port, channels, conf) IRC.__init__(self, server, nick, port, channels, conf)
def create_connection(self): def create_connection(self):
return crlf_ssl_tcp(self.server, self.port, self.ignore_cert_errors) return crlf_ssl_tcp(self.server, self.port, self.ignore_cert_errors)

View File

@ -1,12 +1,13 @@
import thread import thread
import traceback import traceback
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, paraml, msg):
chan = paraml[0].lower() chan = paraml[0].lower()
if chan == conn.nick: # is a PM if chan == conn.nick: # is a PM
chan = nick chan = nick
def say(msg): def say(msg):
@ -20,9 +21,9 @@ class Input(dict):
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,
paraml=paraml, msg=msg, server=conn.server, chan=chan, paraml=paraml, msg=msg, server=conn.server, chan=chan,
say=say, reply=reply, pm=pm, bot=bot) say=say, reply=reply, pm=pm, bot=bot)
self.__dict__ = self # permits attribute access to values self.__dict__ = self # permits attribute access to values
def run(func, input): def run(func, input):

View File

@ -10,12 +10,14 @@ if 'mtimes' not in globals():
if 'lastfiles' not in globals(): if 'lastfiles' not in globals():
lastfiles = set() lastfiles = set()
def format_plug(plug, lpad=0, width=40): def format_plug(plug, lpad=0, width=40):
out = ' ' * lpad + '%s:%s:%s' % (plug[0]) out = ' ' * lpad + '%s:%s:%s' % (plug[0])
if len(plug) == 3 and 'hook' in plug[2]: if len(plug) == 3 and 'hook' in plug[2]:
out += '%s%s' % (' ' * (width - len(out)), plug[2]['hook']) out += '%s%s' % (' ' * (width - len(out)), plug[2]['hook'])
return out return out
def reload(init=False): def reload(init=False):
if init: if init:
bot.plugs = collections.defaultdict(lambda: []) bot.plugs = collections.defaultdict(lambda: [])
@ -25,12 +27,12 @@ def reload(init=False):
if mtime != mtimes.get(filename): if mtime != mtimes.get(filename):
mtimes[filename] = mtime mtimes[filename] = mtime
try: try:
eval(compile(open(filename, 'U').read(), filename, 'exec'), eval(compile(open(filename, 'U').read(), filename, 'exec'),
globals()) globals())
except Exception: except Exception:
traceback.print_exc(Exception) traceback.print_exc(Exception)
if init: # stop if there's a syntax error in a core if init: # stop if there's a syntax error in a core
sys.exit() # script on startup sys.exit() # script on startup
continue continue
if filename == os.path.join('core', 'reload.py'): if filename == os.path.join('core', 'reload.py'):
@ -38,7 +40,7 @@ def reload(init=False):
return return
fileset = set(glob.glob(os.path.join('plugins', '*py'))) fileset = set(glob.glob(os.path.join('plugins', '*py')))
for name, data in bot.plugs.iteritems(): # remove deleted/moved plugins for name, data in bot.plugs.iteritems(): # remove deleted/moved plugins
bot.plugs[name] = filter(lambda x: x[0][0] in fileset, data) bot.plugs[name] = filter(lambda x: x[0][0] in fileset, data)
for filename in fileset: for filename in fileset:
@ -56,7 +58,7 @@ def reload(init=False):
# remove plugins already loaded from this filename # remove plugins already loaded from this filename
for name, data in bot.plugs.iteritems(): for name, data in bot.plugs.iteritems():
if name == 'tee': # signal tee trampolines to stop if name == 'tee': # signal tee trampolines to stop
for csig, func, args in data: for csig, func, args in data:
if csig[0] == filename: if csig[0] == filename:
func._iqueue.put(StopIteration) func._iqueue.put(StopIteration)
@ -64,7 +66,7 @@ def reload(init=False):
bot.plugs[name] = filter(lambda x: x[0][0] != filename, data) bot.plugs[name] = filter(lambda x: x[0][0] != filename, data)
for obj in namespace.itervalues(): for obj in namespace.itervalues():
if hasattr(obj, '_skybot_hook'): #check for magic if hasattr(obj, '_skybot_hook'): # check for magic
for type, data in obj._skybot_hook: for type, data in obj._skybot_hook:
bot.plugs[type] += [data] bot.plugs[type] += [data]

View File

@ -7,8 +7,8 @@ from util import hook
########### from http://effbot.org/zone/re-sub.htm#unescape-html ############# ########### from http://effbot.org/zone/re-sub.htm#unescape-html #############
def unescape(text):
def unescape(text):
def fixup(m): def fixup(m):
text = m.group(0) text = m.group(0)
if text[:2] == "&#": if text[:2] == "&#":
@ -26,7 +26,7 @@ def unescape(text):
text = unichr(htmlentitydefs.name2codepoint[text[1:-1]]) text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
except KeyError: except KeyError:
pass pass
return text # leave as is return text # leave as is
return re.sub("&#?\w+;", fixup, text) return re.sub("&#?\w+;", fixup, text)

View File

@ -21,8 +21,8 @@ def bf(inp):
program = re.sub('[^][<>+-.,]', '', inp) program = re.sub('[^][<>+-.,]', '', inp)
# create a dict of brackets pairs, for speed later on # create a dict of brackets pairs, for speed later on
brackets={} brackets = {}
open_brackets=[] open_brackets = []
for pos in range(len(program)): for pos in range(len(program)):
if program[pos] == '[': if program[pos] == '[':
open_brackets.append(pos) open_brackets.append(pos)
@ -40,9 +40,9 @@ def bf(inp):
ip = 0 # instruction pointer ip = 0 # instruction pointer
mp = 0 # memory pointer mp = 0 # memory pointer
steps = 0 steps = 0
memory = [0] * BUFFER_SIZE #initial memory area memory = [0] * BUFFER_SIZE # initial memory area
rightmost = 0 rightmost = 0
output = "" #we'll save the output here output = "" # we'll save the output here
# the main program loop: # the main program loop:
while ip < len(program): while ip < len(program):
@ -57,7 +57,7 @@ def bf(inp):
rightmost = mp rightmost = mp
if mp >= len(memory): if mp >= len(memory):
# no restriction on memory growth! # no restriction on memory growth!
memory.extend([0]*BUFFER_SIZE) memory.extend([0] * BUFFER_SIZE)
elif c == '<': elif c == '<':
mp = mp - 1 % len(memory) mp = mp - 1 % len(memory)
elif c == '.': elif c == '.':

View File

@ -3,13 +3,14 @@ import random
from util import hook from util import hook
@hook.command @hook.command
def choose(inp): def choose(inp):
".choose <choice1>, <choice2>, ... <choicen> -- makes a decision" ".choose <choice1>, <choice2>, ... <choicen> -- makes a decision"
if not inp: if not inp:
return choose.__doc__ return choose.__doc__
c = re.findall(r'([^,]+)', inp) c = re.findall(r'([^,]+)', inp)
if len(c) == 1: if len(c) == 1:
c = re.findall(r'(\S+)', inp) c = re.findall(r'(\S+)', inp)

View File

@ -9,7 +9,7 @@ from util 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+))*$',
re.I) re.I)
sign_re = re.compile(r'[+-]?(?:\d*d)?\d+', re.I) sign_re = re.compile(r'[+-]?(?:\d*d)?\d+', re.I)
split_re = re.compile(r'([\d+-]*)d?(\d*)', re.I) split_re = re.compile(r'([\d+-]*)d?(\d*)', re.I)
@ -17,15 +17,15 @@ split_re = re.compile(r'([\d+-]*)d?(\d*)', re.I)
def nrolls(count, n): def nrolls(count, n):
"roll an n-sided die count times" "roll an n-sided die count times"
if n < 2: #it's a coin if n < 2: # it's a coin
if count < 5000: if count < 5000:
return sum(random.randint(0, 1) for x in xrange(count)) return sum(random.randint(0, 1) for x in xrange(count))
else: #fake it else: # fake it
return int(random.normalvariate(.5*count, (.75*count)**.5)) return int(random.normalvariate(.5*count, (.75*count)**.5))
else: else:
if count < 5000: if count < 5000:
return sum(random.randint(1, n) for x in xrange(count)) return sum(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))

View File

@ -59,38 +59,39 @@ def cs(snippet):
if not snippet: if not snippet:
return cs.__doc__ return cs.__doc__
file_template = ('using System; ' file_template = ('using System; '
'using System.Linq; ' 'using System.Linq; '
'using System.Collections.Generic; ' 'using System.Collections.Generic; '
'using System.Text; ' 'using System.Text; '
'%(class)s') '%s')
class_template = ('public class Default ' class_template = ('public class Default '
'{ ' '{'
' %(main)s ' ' %s '
'}') '}')
main_template = ('public static void Main(String[] args) ' main_template = ('public static void Main(String[] args) '
'{ ' '{'
' %(snippet)s ' ' %s '
'}') '}')
# There are probably better ways to do the following, but I'm feeling lazy # There are probably better ways to do the following, but I'm feeling lazy
# if no main is found in the snippet, then we use the template with Main in it # if no main is found in the snippet, use the template with Main in it
if 'public static void Main' not in snippet: if 'public static void Main' not in snippet:
code = main_template % { 'snippet': snippet } code = main_template % snippet
code = class_template % { 'main': code } code = class_template % code
code = file_template % { 'class' : code } code = file_template % code
# if Main is found, check for class and see if we need to use the classed template # if Main is found, check for class and see if we need to use the
# classed template
elif 'class' not in snippet: elif 'class' not in snippet:
code = class_template % { 'main': snippet } code = class_template % snippet
code = file_template % { 'class' : code } code = file_template % code
return 'Error using dotnetpad' return 'Error using dotnetpad'
# if we found class, then use the barebones template # if we found class, then use the barebones template
else: else:
code = file_template % { 'class' : snippet } code = file_template % snippet
return dotnetpad('csharp', code) return dotnetpad('csharp', code)

View File

@ -3,6 +3,7 @@ import urlparse
from util import hook from util import hook
@hook.command @hook.command
def down(inp): def down(inp):
'''.down <url> -- checks to see if the site is down''' '''.down <url> -- checks to see if the site is down'''

View File

@ -1,6 +1,7 @@
from util import hook from util import hook
from pycparser.cdecl import explain_c_declaration from pycparser.cdecl import explain_c_declaration
@hook.command @hook.command
def explain(inp): def explain(inp):
".explain <c expression> -- gives an explanation of C expression" ".explain <c expression> -- gives an explanation of C expression"
@ -9,7 +10,7 @@ def explain(inp):
inp = inp.encode('utf8', 'ignore') inp = inp.encode('utf8', 'ignore')
try: try:
return explain_c_declaration(inp) return explain_c_declaration(inp)
except Exception, e: except Exception, e:
return 'error: %s' % e return 'error: %s' % e

View File

@ -5,6 +5,7 @@ from lxml import html
from util import hook from util import hook
@hook.command @hook.command
def calc(inp): def calc(inp):
'''.calc <term> -- returns Google Calculator result''' '''.calc <term> -- returns Google Calculator result'''
@ -22,7 +23,7 @@ def calc(inp):
if m is None: if m is None:
return "could not calculate " + inp return "could not calculate " + inp
result = m.group(1).replace("<font size=-2> </font>",",") result = m.group(1).replace("<font size=-2> </font>", ",")
result = result.replace(" &#215; 10<sup>","E").replace("</sup>","") result = result.replace(" &#215; 10<sup>", "E").replace("</sup>", "")
result = result.replace("\xa0",",") result = result.replace("\xa0", ",")
return result return result

View File

@ -27,8 +27,8 @@ def gis(inp):
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'] # squares is dumb
@hook.command @hook.command

View File

@ -1,6 +1,8 @@
from util import hook from util import hook
#Scaevolus: factormystic if you commit a re-enabled goonsay I'm going to revoke your commit access
#Scaevolus: factormystic if you commit a re-enabled goonsay I'm
# going to revoke your commit access
#@hook.command #@hook.command
def goonsay(inp, say=None): def goonsay(inp, say=None):
say(' __________ /') say(' __________ /')

View File

@ -1,9 +1,10 @@
from util import hook from util import hook
@hook.command @hook.command
def help(inp, bot=None, pm=None): def help(inp, bot=None, pm=None):
".help [command] -- gives a list of commands/help for a command" ".help [command] -- gives a list of commands/help for a command"
funcs = {} funcs = {}
for csig, func, args in bot.plugs['command']: for csig, func, args in bot.plugs['command']:
if args['hook'] != r'(.*)': if args['hook'] != r'(.*)':

View File

@ -12,7 +12,7 @@ from util import hook
lock = thread.allocate_lock() lock = thread.allocate_lock()
log_fds = {} # '%(net)s %(chan)s' : (filename, fd) log_fds = {} # '%(net)s %(chan)s' : (filename, fd)
timestamp_format = '%H:%M:%S' timestamp_format = '%H:%M:%S'
@ -69,8 +69,8 @@ def get_log_fd(dir, server, chan):
cache_key = '%s %s' % (server, chan) cache_key = '%s %s' % (server, chan)
filename, fd = log_fds.get(cache_key, ('', 0)) filename, fd = log_fds.get(cache_key, ('', 0))
if fn != filename: # we need to open a file for writing if fn != filename: # we need to open a file for writing
if fd != 0: # is a valid fd if fd != 0: # is a valid fd
fd.flush() fd.flush()
fd.close() fd.close()
dir = os.path.split(fn)[0] dir = os.path.split(fn)[0]
@ -90,14 +90,14 @@ def log(bot, input):
fd = get_log_fd(bot.persist_dir, input.server, 'raw') fd = get_log_fd(bot.persist_dir, input.server, 'raw')
fd.write(timestamp + ' ' + input.raw + '\n') fd.write(timestamp + ' ' + input.raw + '\n')
if input.command == 'QUIT': # these are temporary fixes until proper if input.command == 'QUIT': # these are temporary fixes until proper
input.chan = 'quit' # presence tracking is implemented input.chan = 'quit' # presence tracking is implemented
if input.command == 'NICK': if input.command == 'NICK':
input.chan = 'nick' input.chan = 'nick'
beau = beautify(input) beau = beautify(input)
if beau == '': # don't log this if beau == '': # don't log this
return return
if input.chan: if input.chan:

View File

@ -1,7 +1,7 @@
from util import hook from util import hook
import socket import socket
socket.setdefaulttimeout(5) # global setting socket.setdefaulttimeout(5) # global setting
#autorejoin channels #autorejoin channels
@ -11,12 +11,14 @@ def rejoin(inp, paraml=[], conn=None):
if paraml[0].lower() in conn.channels: if paraml[0].lower() in conn.channels:
conn.join(paraml[0]) conn.join(paraml[0])
#join channels when invited #join channels when invited
@hook.event('INVITE') @hook.event('INVITE')
def invite(inp, command='', conn=None): def invite(inp, command='', conn=None):
if command == 'INVITE': if command == 'INVITE':
conn.join(inp) conn.join(inp)
#join channels when server says hello & identify bot #join channels when server says hello & identify bot
@hook.event('004') @hook.event('004')
def onjoin(inp, conn=None): def onjoin(inp, conn=None):

View File

@ -8,7 +8,7 @@ from util import hook
@hook.command @hook.command
def mtg(inp): def mtg(inp):
".mtg <card> -- gets information about Magic the Gathering card <card name>" ".mtg <name> -- gets information about Magic the Gathering card <name>"
url = 'http://magiccards.info/query.php?cardname=' url = 'http://magiccards.info/query.php?cardname='
url += urllib2.quote(inp, safe='') url += urllib2.quote(inp, safe='')
h = html.parse(url) h = html.parse(url)
@ -20,11 +20,11 @@ def mtg(inp):
type = text.text type = text.text
text = text.find('b').text_content() text = text.find('b').text_content()
text = re.sub(r'\(.*?\)', '', text) # strip parenthetical explanations text = re.sub(r'\(.*?\)', '', text) # strip parenthetical explanations
text = re.sub(r'\.(\S)', r'. \1', text) # fix spacing text = re.sub(r'\.(\S)', r'. \1', text) # fix spacing
printings = card.find('table/tr/td/img').getparent().text_content() printings = card.find('table/tr/td/img').getparent().text_content()
printings = re.findall(r'\s*(.+?(?: \([^)]+\))*) \((.*?)\)', printings = re.findall(r'\s*(.+?(?: \([^)]+\))*) \((.*?)\)',
' '.join(printings.split())) ' '.join(printings.split()))
printing_out = ', '.join('%s (%s)' % (set_abbrevs.get(x[0], x[0]), printing_out = ', '.join('%s (%s)' % (set_abbrevs.get(x[0], x[0]),
rarity_abbrevs.get(x[1], x[1])) rarity_abbrevs.get(x[1], x[1]))

View File

@ -8,15 +8,17 @@ from util import hook
def add_quote(db, chan, nick, add_nick, msg): def add_quote(db, chan, nick, add_nick, msg):
now = time.time() now = time.time()
db.execute('''insert or fail into quote (chan, nick, add_nick, db.execute('''insert or fail into quote (chan, nick, add_nick,
msg, time) values(?,?,?,?,?)''', msg, time) values(?,?,?,?,?)''',
(chan, nick, add_nick, msg, now)) (chan, nick, add_nick, msg, now))
db.commit() db.commit()
def get_quotes_by_nick(db, chan, nick): def get_quotes_by_nick(db, chan, nick):
return db.execute("select time, nick, msg from quote where deleted!=1 " return db.execute("select time, nick, msg from quote where deleted!=1 "
"and chan=? and lower(nick)=lower(?) order by time", "and chan=? and lower(nick)=lower(?) order by time",
(chan, nick)).fetchall() (chan, nick)).fetchall()
def get_quotes_by_chan(db, chan): def get_quotes_by_chan(db, chan):
return db.execute("select time, nick, msg from quote where deleted!=1 " return db.execute("select time, nick, msg from quote where deleted!=1 "
"and chan=? order by time", (chan,)).fetchall() "and chan=? order by time", (chan,)).fetchall()
@ -24,9 +26,10 @@ def get_quotes_by_chan(db, chan):
def format_quote(q, num, n_quotes): def format_quote(q, num, n_quotes):
ctime, nick, msg = q ctime, nick, msg = q
return "[%d/%d] %s <%s> %s" % (num, n_quotes, return "[%d/%d] %s <%s> %s" % (num, n_quotes,
time.strftime("%Y-%m-%d", time.gmtime(ctime)), nick, msg) time.strftime("%Y-%m-%d", time.gmtime(ctime)), nick, msg)
@hook.command('q') @hook.command('q')
@hook.command @hook.command
def quote(inp, nick='', chan='', db=None): def quote(inp, nick='', chan='', db=None):
@ -46,12 +49,12 @@ def quote(inp, nick='', chan='', db=None):
quoted_nick, msg = add.groups() quoted_nick, msg = add.groups()
try: try:
add_quote(db, chan, quoted_nick, nick, msg) add_quote(db, chan, quoted_nick, nick, msg)
except db.IntegrityError: except db.IntegrityError:
return "message already stored, doing nothing." return "message already stored, doing nothing."
return "quote added." return "quote added."
elif retrieve: elif retrieve:
select, num = retrieve.groups() select, num = retrieve.groups()
by_chan = False by_chan = False
if select.startswith('#'): if select.startswith('#'):
by_chan = True by_chan = True
@ -69,7 +72,7 @@ def quote(inp, nick='', chan='', db=None):
if num: if num:
if num > n_quotes: if num > n_quotes:
return "I only have %d quote%s for %s" % (n_quotes, return "I only have %d quote%s for %s" % (n_quotes,
('s', '')[n_quotes == 1], select) ('s', '')[n_quotes == 1], select)
else: else:
selected_quote = quotes[num - 1] selected_quote = quotes[num - 1]

View File

@ -1,24 +1,23 @@
''' '''
regular.py regular.py
skybot plugin for testing regular expressions skybot plugin for testing regular expressions
by Ipsum by Ipsum
''' '''
import re import re
from util import hook from util import hook
@hook.command('re') @hook.command('re')
def reg(inp): def reg(inp):
".re <regex> <string> -- matches regular expression in given <string> "\ ".re <regex> <string> -- matches regular expression in given <string> "\
"(leave 2 spaces between)" "(leave 2 spaces between)"
query = inp.split(" ", 1) query = inp.split(" ", 1)
if not inp or len(query) != 2: if not inp or len(query) != 2:
return reg.__doc__ return reg.__doc__
return '|'.join(re.findall(query[0], query[1])) return '|'.join(re.findall(query[0], query[1]))

View File

@ -4,11 +4,13 @@ remember.py: written by Scaevolus 2010
from util import hook from util import hook
def db_init(db): def db_init(db):
db.execute("create table if not exists memory(chan, word, data, nick," db.execute("create table if not exists memory(chan, word, data, nick,"
" primary key(chan, word))") " primary key(chan, word))")
db.commit() db.commit()
def get_memory(db, chan, word): def get_memory(db, chan, word):
row = db.execute("select data from memory where chan=? and word=lower(?)", row = db.execute("select data from memory where chan=? and word=lower(?)",
(chan, word)).fetchone() (chan, word)).fetchone()
@ -17,6 +19,7 @@ def get_memory(db, chan, word):
else: else:
return None return None
@hook.command @hook.command
def remember(inp, nick='', chan='', db=None): def remember(inp, nick='', chan='', db=None):
".remember <word> <data> -- maps word to data in the memory" ".remember <word> <data> -- maps word to data in the memory"
@ -37,6 +40,7 @@ def remember(inp, nick='', chan='', db=None):
else: else:
return 'done.' return 'done.'
@hook.command @hook.command
def forget(inp, chan='', db=None): def forget(inp, chan='', db=None):
".forget <word> -- forgets the mapping that word had" ".forget <word> -- forgets the mapping that word had"
@ -57,6 +61,7 @@ def forget(inp, chan='', db=None):
else: else:
return "I don't know about that." return "I don't know about that."
@hook.command(hook='\?(.+)', prefix=False) @hook.command(hook='\?(.+)', prefix=False)
def question(inp, chan='', say=None, db=None): def question(inp, chan='', say=None, db=None):
"?<word> -- shows what data is associated with word" "?<word> -- shows what data is associated with word"

View File

@ -13,7 +13,7 @@ def seeninput(bot, input):
db = bot.get_db_connection(input.server) db = bot.get_db_connection(input.server)
db_init(db) db_init(db)
db.execute("insert or replace into seen(name, time, quote, chan)" db.execute("insert or replace into seen(name, time, quote, chan)"
"values(?,?,?,?)", (input.nick.lower(), time.time(), input.msg, "values(?,?,?,?)", (input.nick.lower(), time.time(), input.msg,
input.chan)) input.chan))
db.commit() db.commit()
@ -35,7 +35,7 @@ def seen(inp, nick='', chan='', db=None):
if last_seen: if last_seen:
reltime = timesince.timesince(last_seen[1]) reltime = timesince.timesince(last_seen[1])
if last_seen[0] != inp.lower(): # for glob matching if last_seen[0] != inp.lower(): # for glob matching
inp = last_seen[0] inp = last_seen[0]
return '%s was last seen %s ago saying: %s' % \ return '%s was last seen %s ago saying: %s' % \
(inp, reltime, last_seen[2]) (inp, reltime, last_seen[2])

View File

@ -17,7 +17,7 @@ def sieve_suite(bot, input, func, args):
hook = args.get('hook', r'(.*)') hook = args.get('hook', r'(.*)')
if args.get('prefix', True): if args.get('prefix', True):
if input.chan == input.nick: # private message, prefix not required if input.chan == input.nick: # private message, prefix not required
prefix = r'^(?:[.!]?|' prefix = r'^(?:[.!]?|'
else: else:
prefix = r'^(?:[.!]|' prefix = r'^(?:[.!]|'

View File

@ -6,12 +6,13 @@ import json
from util import hook from util import hook
@hook.command @hook.command
def suggest(inp, inp_unstripped=''): def suggest(inp, inp_unstripped=''):
".suggest [#n] <phrase> -- gets a random/the nth suggested google search" ".suggest [#n] <phrase> -- gets a random/the nth suggested google search"
if not inp: if not inp:
return suggest.__doc__ return suggest.__doc__
inp = inp_unstripped inp = inp_unstripped
m = re.match('^#(\d+) (.+)$', inp) m = re.match('^#(\d+) (.+)$', inp)
if m: if m:

View File

@ -5,9 +5,10 @@ import time
from util import hook, timesince from util import hook, timesince
def get_tells(db, user_to, chan): def get_tells(db, user_to, chan):
return db.execute("select user_from, message, time from tell where" return db.execute("select user_from, message, time from tell where"
" user_to=lower(?) and chan=? order by time", " user_to=lower(?) and chan=? order by time",
(user_to.lower(), chan)).fetchall() (user_to.lower(), chan)).fetchall()
@ -18,7 +19,7 @@ def tellinput(bot, input):
if 'showtells' in input.msg.lower(): if 'showtells' in input.msg.lower():
return return
db = bot.get_db_connection(input.server) db = bot.get_db_connection(input.server)
db = db_init(db) db = db_init(db)
@ -37,14 +38,15 @@ def tellinput(bot, input):
db.commit() db.commit()
input.reply(reply) input.reply(reply)
@hook.command @hook.command
def showtells(inp, nick='', chan='', pm=None, db=None): def showtells(inp, nick='', chan='', pm=None, db=None):
".showtells -- view all pending tell messages (sent in PM)." ".showtells -- view all pending tell messages (sent in PM)."
db_init(db) db_init(db)
tells = get_tells(db, nick, chan) tells = get_tells(db, nick, chan)
if not tells: if not tells:
pm("You have no pending tells.") pm("You have no pending tells.")
return return
@ -53,11 +55,12 @@ def showtells(inp, nick='', chan='', pm=None, db=None):
user_from, message, time = tell user_from, message, time = tell
reltime = timesince.timesince(time) reltime = timesince.timesince(time)
pm("%s said %s ago: %s" % (user_from, reltime, message)) pm("%s said %s ago: %s" % (user_from, reltime, message))
db.execute("delete from tell where user_to=lower(?) and chan=?", db.execute("delete from tell where user_to=lower(?) and chan=?",
(nick, chan)) (nick, chan))
db.commit() db.commit()
@hook.command @hook.command
def tell(inp, nick='', chan='', db=None): def tell(inp, nick='', chan='', db=None):
".tell <nick> <message> -- relay <message> to <nick> when <nick> is around" ".tell <nick> <message> -- relay <message> to <nick> when <nick> is around"
@ -70,7 +73,7 @@ def tell(inp, nick='', chan='', db=None):
user_to = query[0].lower() user_to = query[0].lower()
message = query[1].strip() message = query[1].strip()
user_from = nick user_from = nick
if user_to == user_from.lower(): if user_to == user_from.lower():
return "No." return "No."
@ -97,5 +100,5 @@ def db_init(db):
"(user_to, user_from, message, chan, time," "(user_to, user_from, message, chan, time,"
"primary key(user_to, message))") "primary key(user_to, message))")
db.commit() db.commit()
return db return db

View File

@ -26,10 +26,12 @@ def unescape_xml(string):
history = [] history = []
history_max_size = 250 history_max_size = 250
@hook.command @hook.command
def twitter(inp): def twitter(inp):
".twitter <user>/<user> <n>/<id>/#<hashtag>/@<user> -- gets last/<n>th tweet from"\ ".twitter <user>/<user> <n>/<id>/#<hashtag>/@<user> -- gets last/<n>th "\
"<user>/gets tweet <id>/gets random tweet with #<hashtag>/gets replied tweet from @<user>" "tweet from <user>/gets tweet <id>/gets random tweet with #<hashtag>/"\
"gets replied tweet from @<user>"
if not inp: if not inp:
return twitter.__doc__ return twitter.__doc__
@ -89,7 +91,7 @@ def twitter(inp):
try: try:
xml = urllib2.urlopen(url).read() xml = urllib2.urlopen(url).read()
except urllib2.HTTPError, e: except urllib2.HTTPError, e:
errors = {400 : 'bad request (ratelimited?)', errors = {400: 'bad request (ratelimited?)',
401: 'tweet is private', 401: 'tweet is private',
404: 'invalid user/id', 404: 'invalid user/id',
500: 'twitter is broken', 500: 'twitter is broken',
@ -125,10 +127,11 @@ def twitter(inp):
reply_name = tweet.find(reply_name).text reply_name = tweet.find(reply_name).text
reply_id = tweet.find(reply_id).text reply_id = tweet.find(reply_id).text
reply_user = tweet.find(reply_user).text reply_user = tweet.find(reply_user).text
if reply_name is not None and (reply_id is not None or reply_user is not None): if reply_name is not None and (reply_id is Not None or
reply_user is not None):
add_reply(reply_name, reply_id if reply_id else -1) add_reply(reply_name, reply_id if reply_id else -1)
time = strftime('%Y-%m-%d %H:%M:%S', time = strftime('%Y-%m-%d %H:%M:%S',
strptime(time.text, strptime(time.text,
'%a %b %d %H:%M:%S +0000 %Y')) '%a %b %d %H:%M:%S +0000 %Y'))
text = unescape_xml(tweet.find(text).text.replace('\n', '')) text = unescape_xml(tweet.find(text).text.replace('\n', ''))

View File

@ -6,10 +6,11 @@ from util import hook, urlnorm, timesince
url_re = re.compile(r'([a-zA-Z]+://|www\.)[^ ]*') url_re = re.compile(r'([a-zA-Z]+://|www\.)[^ ]*')
expiration_period = 60 * 60 * 24 # 1 day expiration_period = 60 * 60 * 24 # 1 day
ignored_urls = [urlnorm.normalize("http://google.com")] ignored_urls = [urlnorm.normalize("http://google.com")]
def db_connect(bot, server): def db_connect(bot, server):
"check to see that our db has the the seen table and return a dbection." "check to see that our db has the the seen table and return a dbection."
db = bot.get_db_connection(server) db = bot.get_db_connection(server)
@ -18,18 +19,21 @@ def db_connect(bot, server):
db.commit() db.commit()
return db return db
def insert_history(db, chan, url, nick): def insert_history(db, chan, url, nick):
now = time.time() now = time.time()
db.execute("insert into urlhistory(chan, url, nick, time) " db.execute("insert into urlhistory(chan, url, nick, time) "
"values(?,?,?,?)", (chan, url, nick, time.time())) "values(?,?,?,?)", (chan, url, nick, time.time()))
db.commit() db.commit()
def get_history(db, chan, url): def get_history(db, chan, url):
db.execute("delete from urlhistory where time < ?", db.execute("delete from urlhistory where time < ?",
(time.time() - expiration_period,)) (time.time() - expiration_period,))
return db.execute("select nick, time from urlhistory where " return db.execute("select nick, time from urlhistory where "
"chan=? and url=? order by time desc", (chan, url)).fetchall() "chan=? and url=? order by time desc", (chan, url)).fetchall()
def nicklist(nicks): def nicklist(nicks):
nicks = sorted(dict(nicks), key=unicode.lower) nicks = sorted(dict(nicks), key=unicode.lower)
if len(nicks) <= 2: if len(nicks) <= 2:
@ -37,6 +41,7 @@ def nicklist(nicks):
else: else:
return ', and '.join((', '.join(nicks[:-1]), nicks[-1])) return ', and '.join((', '.join(nicks[:-1]), nicks[-1]))
def format_reply(history): def format_reply(history):
if not history: if not history:
return return
@ -57,10 +62,11 @@ def format_reply(history):
last = "last linked %s ago" % last_time last = "last linked %s ago" % last_time
else: else:
last = "last linked by %s %s ago" % (last_nick, last_time) last = "last linked by %s %s ago" % (last_nick, last_time)
return "that url has been posted %s in the past %s by %s (%s)." % (ordinal, return "that url has been posted %s in the past %s by %s (%s)." % (ordinal,
hour_span, nicklist(history), last) hour_span, nicklist(history), last)
@hook.command(hook=r'(.*)', prefix=False) @hook.command(hook=r'(.*)', prefix=False)
def urlinput(inp, nick='', chan='', server='', reply=None, bot=None): def urlinput(inp, nick='', chan='', server='', reply=None, bot=None):
m = url_re.search(inp.encode('utf8')) m = url_re.search(inp.encode('utf8'))

View File

@ -3,6 +3,7 @@ import thread
import traceback import traceback
import Queue import Queue
def _isfunc(x): def _isfunc(x):
if type(x) == type(_isfunc): if type(x) == type(_isfunc):
return True return True
@ -24,7 +25,7 @@ def _hook_add(func, add, name=''):
if argspec.varargs: if argspec.varargs:
n_args -= 1 n_args -= 1
if n_args != 1: if n_args != 1:
err = '%ss must take 1 non-keyword argument (%s)' % (name, err = '%ss must take 1 non-keyword argument (%s)' % (name,
func.__name__) func.__name__)
raise ValueError(err) raise ValueError(err)
@ -34,9 +35,10 @@ def _hook_add(func, add, name=''):
args.extend(argspec.args[-len(argspec.defaults): args.extend(argspec.args[-len(argspec.defaults):
end if end else None]) end if end else None])
if argspec.keywords: if argspec.keywords:
args.append(0) # means kwargs present args.append(0) # means kwargs present
func._skybot_args = args func._skybot_args = args
def _make_sig(f): def _make_sig(f):
return f.func_code.co_filename, f.func_name, f.func_code.co_firstlineno return f.func_code.co_filename, f.func_name, f.func_code.co_firstlineno

View File

@ -1,34 +1,35 @@
# Copyright (c) Django Software Foundation and individual contributors. # Copyright (c) Django Software Foundation and individual contributors.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without
# are permitted provided that the following conditions are met: # modification, are permitted provided that the following conditions are met:
# #
# 1. Redistributions of source code must retain the above copyright notice, # 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer. # this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# #
# 3. Neither the name of Django nor the names of its contributors may be used # 2. Redistributions in binary form must reproduce the above copyright
# to endorse or promote products derived from this software without # notice, this list of conditions and the following disclaimer in the
# specific prior written permission. # documentation and/or other materials provided with the distribution.
# #
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # 3. Neither the name of Django nor the names of its contributors may be used
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # to endorse or promote products derived from this software without
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # specific prior written permission.
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR #
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES #THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; #ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON #WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT #DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS #ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
#ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import datetime import datetime
import time import time
def timesince(d, now=None): def timesince(d, now=None):
""" """
Takes two datetime objects and returns the time between d and now Takes two datetime objects and returns the time between d and now
@ -86,11 +87,12 @@ def timesince(d, now=None):
count2 = (since - (seconds * count)) // seconds2 count2 = (since - (seconds * count)) // seconds2
if count2 != 0: if count2 != 0:
if count2 == 1: if count2 == 1:
s += ', %(number)d %(type)s' % {'number': count2, 'type': name2[0]} s += ', %d %s' % (count2, name2[0])
else: else:
s += ', %(number)d %(type)s' % {'number': count2, 'type': name2[1]} s += ', %d %s' % (count2, name2[1])
return s return s
def timeuntil(d, now=None): def timeuntil(d, now=None):
""" """
Like timesince, but returns a string measuring the time until Like timesince, but returns a string measuring the time until

View File

@ -8,7 +8,7 @@ from util import hook
@hook.command @hook.command
def weather(inp, nick='', server='', reply=None, db=None): def weather(inp, nick='', server='', reply=None, db=None):
".weather <location> [dontsave] -- queries the google weather API for weather data" ".weather <location> [dontsave] -- gets weather data from Google"
loc = inp loc = inp
@ -18,7 +18,7 @@ def weather(inp, nick='', server='', reply=None, db=None):
db.execute("create table if not exists weather(nick primary key, loc)") db.execute("create table if not exists weather(nick primary key, loc)")
if not loc: # blank line if not loc: # blank line
loc = db.execute("select loc from weather where nick=lower(?)", loc = db.execute("select loc from weather where nick=lower(?)",
(nick,)).fetchone() (nick,)).fetchone()
if not loc: if not loc:

View File

@ -26,7 +26,8 @@ def wiki(inp):
q = search_url % (urllib2.quote(inp, safe='')) q = search_url % (urllib2.quote(inp, safe=''))
request = urllib2.Request(q) request = urllib2.Request(q)
request.add_header('User-Agent', 'Skybot/1.0 http://bitbucket.org/Scaevolus/skybot/') request.add_header('User-Agent',
'Skybot/1.0 http://bitbucket.org/Scaevolus/skybot/')
opener = urllib2.build_opener() opener = urllib2.build_opener()
xml = opener.open(request).read() xml = opener.open(request).read()
x = etree.fromstring(xml) x = etree.fromstring(xml)
@ -54,7 +55,7 @@ def wiki(inp):
if title.lower() not in desc.lower(): if title.lower() not in desc.lower():
desc = title + desc desc = title + desc
desc = re.sub('\s+', ' ', desc).strip() #remove excess spaces desc = re.sub('\s+', ' ', desc).strip() # remove excess spaces
if len(desc) > 300: if len(desc) > 300:
desc = desc[:300] + '...' desc = desc[:300] + '...'

View File

@ -5,6 +5,7 @@ from lxml import html
from util import hook from util import hook
@hook.command @hook.command
@hook.command('wa') @hook.command('wa')
def wolframalpha(inp): def wolframalpha(inp):
@ -21,7 +22,7 @@ def wolframalpha(inp):
pods = h.xpath("//div[@class='pod ']") pods = h.xpath("//div[@class='pod ']")
pod_texts = [] pod_texts = []
for pod in pods: for pod in pods:
heading = pod.find('h1/span') heading = pod.find('h1/span')
if heading is not None: if heading is not None:
heading = heading.text_content().strip() heading = heading.text_content().strip()
@ -40,7 +41,7 @@ def wolframalpha(inp):
if results: if results:
pod_texts.append(heading + ' ' + '|'.join(results)) pod_texts.append(heading + ' ' + '|'.join(results))
ret = '. '.join(pod_texts) # first pod is the input ret = '. '.join(pod_texts)
if not pod_texts: if not pod_texts:
return 'no results' return 'no results'
@ -52,7 +53,7 @@ def wolframalpha(inp):
ret = re.sub(r'\\:([0-9a-z]{4})', unicode_sub, ret) ret = re.sub(r'\\:([0-9a-z]{4})', unicode_sub, ret)
if len(ret) > 430: if len(ret) > 430:
ret = ret[:ret.rfind(' ', 0, 430)] ret = ret[:ret.rfind(' ', 0, 430)]
ret = re.sub(r'\W+$', '', ret) + '...' ret = re.sub(r'\W+$', '', ret) + '...'

View File

@ -17,11 +17,12 @@ url = base_url + 'videos/%s?v=2&alt=jsonc'
search_api_url = base_url + 'videos?v=2&alt=jsonc&max-results=1&q=%s' search_api_url = base_url + 'videos?v=2&alt=jsonc&max-results=1&q=%s'
video_url = "http://youtube.com/watch?v=%s" video_url = "http://youtube.com/watch?v=%s"
def get_video_description(vid_id): def get_video_description(vid_id):
j = json.load(urllib2.urlopen(url % vid_id)) j = json.load(urllib2.urlopen(url % vid_id))
if j.get('error'): if j.get('error'):
return return
j = j['data'] j = j['data']
@ -29,7 +30,7 @@ def get_video_description(vid_id):
out += ' - length \x02' out += ' - length \x02'
length = j['duration'] length = j['duration']
if length / 3600: # > 1 hour if length / 3600: # > 1 hour
out += '%dh ' % (length / 3600) out += '%dh ' % (length / 3600)
if length / 60: if length / 60:
out += '%dm ' % (length / 60 % 60) out += '%dm ' % (length / 60 % 60)
@ -38,12 +39,11 @@ def get_video_description(vid_id):
if 'rating' in j: if 'rating' in j:
out += ' - rated \x02%.2f/5.0\x02 (%d)' % (j['rating'], out += ' - rated \x02%.2f/5.0\x02 (%d)' % (j['rating'],
j['ratingCount']) j['ratingCount'])
if 'viewCount' in j: if 'viewCount' in j:
out += ' - \x02%s\x02 views' % locale.format('%d', out += ' - \x02%s\x02 views' % locale.format('%d',
j['viewCount'], 1) j['viewCount'], 1)
upload_time = time.strptime(j['uploaded'], "%Y-%m-%dT%H:%M:%S.000Z") upload_time = time.strptime(j['uploaded'], "%Y-%m-%dT%H:%M:%S.000Z")
out += ' - \x02%s\x02 on \x02%s\x02' % (j['uploader'], out += ' - \x02%s\x02 on \x02%s\x02' % (j['uploader'],
time.strftime("%Y.%m.%d", upload_time)) time.strftime("%Y.%m.%d", upload_time))
@ -52,7 +52,7 @@ def get_video_description(vid_id):
out += ' - \x034NSFW\x02' out += ' - \x034NSFW\x02'
return out return out
@hook.command(hook=r'(.*)', prefix=False) @hook.command(hook=r'(.*)', prefix=False)
def youtube_url(inp): def youtube_url(inp):