flake8 + autopep8 (whitespace fixes)

This commit is contained in:
Ryan Hitchman 2014-01-14 13:12:37 -08:00
parent c065aaa59a
commit cb8c437772
38 changed files with 212 additions and 189 deletions

8
bot.py
View File

@ -20,7 +20,7 @@ print 'Loading plugins'
# bootstrap the reloader
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)
config()
@ -35,11 +35,11 @@ try:
for name, conf in bot.config['connections'].iteritems():
if conf.get('ssl'):
bot.conns[name] = SSLIRC(conf['server'], conf['nick'], conf=conf,
port=conf.get('port', 6667), channels=conf['channels'],
ignore_certificate_errors=conf.get('ignore_cert', True))
port=conf.get('port', 6667), channels=conf['channels'],
ignore_certificate_errors=conf.get('ignore_cert', True))
else:
bot.conns[name] = IRC(conf['server'], conf['nick'], conf=conf,
port=conf.get('port', 6667), channels=conf['channels'])
port=conf.get('port', 6667), channels=conf['channels'])
except Exception, e:
print 'ERROR: malformed config file', e
sys.exit()

View File

@ -27,6 +27,7 @@ def censor(text):
class crlf_tcp(object):
"Handles tcp connections that consist of utf-8 lines ending with crlf"
def __init__(self, host, port, timeout=300):
@ -94,15 +95,17 @@ class crlf_tcp(object):
class crlf_ssl_tcp(crlf_tcp):
"Handles ssl tcp connetions that consist of utf-8 lines ending with crlf"
def __init__(self, host, port, ignore_cert_errors, timeout=300):
self.ignore_cert_errors = ignore_cert_errors
crlf_tcp.__init__(self, host, port, timeout)
def create_socket(self):
return wrap_socket(crlf_tcp.create_socket(self), server_side=False,
cert_reqs=CERT_NONE if self.ignore_cert_errors else
CERT_REQUIRED)
cert_reqs=CERT_NONE if self.ignore_cert_errors else
CERT_REQUIRED)
def recv_from_socket(self, nbytes):
return self.socket.read(nbytes)
@ -123,8 +126,10 @@ irc_param_ref = re.compile(r'(?:^|(?<= ))(:.*|[^ ]+)').findall
class IRC(object):
"handles the IRC protocol"
#see the docs/ folder for more information on the protocol
# see the docs/ folder for more information on the protocol
def __init__(self, server, nick, port=6667, channels=[], conf={}):
self.channels = channels
self.conf = conf
@ -148,8 +153,8 @@ class IRC(object):
self.set_pass(self.conf.get('server_password'))
self.set_nick(self.nick)
self.cmd("USER",
[conf.get('user', 'skybot'), "3", "*", conf.get('realname',
'Python bot - http://github.com/rmmh/skybot')])
[conf.get('user', 'skybot'), "3", "*", conf.get('realname',
'Python bot - http://github.com/rmmh/skybot')])
def parse_loop(self):
while True:
@ -171,7 +176,7 @@ class IRC(object):
paramlist[-1] = paramlist[-1][1:]
lastparam = paramlist[-1]
self.out.put([msg, prefix, command, params, nick, user, host,
paramlist, lastparam])
paramlist, lastparam])
if command == "PING":
self.cmd("PONG", paramlist)
@ -200,6 +205,7 @@ class IRC(object):
class FakeIRC(IRC):
def __init__(self, server, nick, port=6667, channels=[], conf={}, fn=""):
self.channels = channels
self.conf = conf
@ -233,7 +239,7 @@ class FakeIRC(IRC):
paramlist[-1] = paramlist[-1][1:]
lastparam = paramlist[-1]
self.out.put([msg, prefix, command, params, nick, user, host,
paramlist, lastparam])
paramlist, lastparam])
if command == "PING":
self.cmd("PONG", [params])
@ -242,6 +248,7 @@ class FakeIRC(IRC):
class SSLIRC(IRC):
def __init__(self, server, nick, port=6667, channels=[], conf={},
ignore_certificate_errors=True):
self.ignore_cert_errors = ignore_certificate_errors

View File

@ -6,8 +6,9 @@ thread.stack_size(1024 * 512) # reduce vm size
class Input(dict):
def __init__(self, conn, raw, prefix, command, params,
nick, user, host, paraml, msg):
nick, user, host, paraml, msg):
chan = paraml[0].lower()
if chan == conn.nick.lower(): # is a PM
@ -35,10 +36,10 @@ class Input(dict):
conn.cmd('NOTICE', [nick, msg])
dict.__init__(self, conn=conn, raw=raw, prefix=prefix, command=command,
params=params, nick=nick, user=user, host=host,
paraml=paraml, msg=msg, server=conn.server, chan=chan,
notice=notice, say=say, reply=reply, pm=pm, bot=bot,
me=me, set_nick=set_nick, lastparam=paraml[-1])
params=params, nick=nick, user=user, host=host,
paraml=paraml, msg=msg, server=conn.server, chan=chan,
notice=notice, say=say, reply=reply, pm=pm, bot=bot,
me=me, set_nick=set_nick, lastparam=paraml[-1])
# make dict keys accessible as attributes
def __getattr__(self, key):
@ -80,7 +81,9 @@ def do_sieve(sieve, bot, input, func, type, args):
class Handler(object):
'''Runs plugins in their own threads (ensures order)'''
def __init__(self, func):
self.func = func
self.input_queue = Queue.Queue()
@ -121,7 +124,7 @@ def dispatch(input, kind, func, args, autohelp=False):
return
if autohelp and args.get('autohelp', True) and not input.inp \
and func.__doc__ is not None:
and func.__doc__ is not None:
input.reply(func.__doc__)
return

View File

@ -49,7 +49,7 @@ def reload(init=False):
try:
eval(compile(open(filename, 'U').read(), filename, 'exec'),
globals())
globals())
except Exception:
traceback.print_exc()
if init: # stop if there's an error (syntax?) in a core
@ -111,7 +111,7 @@ def reload(init=False):
if not init:
print '### new plugin (type: %s) loaded:' % \
type, format_plug(data)
type, format_plug(data)
if changed:
bot.commands = {}
@ -119,7 +119,7 @@ def reload(init=False):
name = plug[1]['name'].lower()
if not re.match(r'^\w+$', name):
print '### ERROR: invalid command name "%s" (%s)' % (name,
format_plug(plug))
format_plug(plug))
continue
if name in bot.commands:
print "### ERROR: command '%s' already registered (%s, %s)" % \

View File

@ -44,7 +44,7 @@ def bf(inp):
# the main program loop:
while ip < len(program):
c = program[ip]
if c == '+':
if c == '+':
memory[mp] = memory[mp] + 1 % 256
elif c == '-':
memory[mp] = memory[mp] - 1 % 256

View File

@ -23,13 +23,13 @@ def nrolls(count, n):
if count < 5000:
return [random.randint(0, 1) for x in xrange(count)]
else: # fake it
return [int(random.normalvariate(.5*count, (.75*count)**.5))]
return [int(random.normalvariate(.5 * count, (.75 * count) ** .5))]
else:
if count < 5000:
return [random.randint(1, n) for x in xrange(count)]
else: # fake it
return [int(random.normalvariate(.5*(1+n)*count,
(((n+1)*(2*n+1)/6.-(.5*(1+n))**2)*count)**.5))]
return [int(random.normalvariate(.5 * (1 + n) * count,
(((n + 1) * (2 * n + 1) / 6. - (.5 * (1 + n)) ** 2) * count) ** .5))]
@hook.command('roll')

View File

@ -15,7 +15,7 @@ def urban(inp):
if page['result_type'] == 'no_results':
return 'not found.'
out = defs[0]['word'] + ': ' + defs[0]['definition'].replace('\r\n',' ')
out = defs[0]['word'] + ': ' + defs[0]['definition'].replace('\r\n', ' ')
if len(out) > 400:
out = out[:out.rfind(' ', 0, 400)] + '...'
@ -61,7 +61,7 @@ def define(inp):
result += article[0]
if len(article) > 2:
result += ' '.join('%d. %s' % (n + 1, section)
for n, section in enumerate(article[1:]))
for n, section in enumerate(article[1:]))
else:
result += article[1] + ' '

View File

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

View File

@ -5,7 +5,7 @@ from util import hook, http
def api_get(query, key, is_image=None, num=1):
url = ('https://www.googleapis.com/customsearch/v1?cx=007629729846476161907:ud5nlxktgcw'
'&fields=items(title,link,snippet)&safe=off' + ('&searchType=image' if is_image else ''))
'&fields=items(title,link,snippet)&safe=off' + ('&searchType=image' if is_image else ''))
return http.get_json(url, key=key, q=query, num=num)

View File

@ -17,4 +17,4 @@ def sha1(inp):
def hash(inp):
".hash <text> -- returns hashes of <text>"
return ', '.join(x + ": " + getattr(hashlib, x)(inp).hexdigest()
for x in 'md5 sha1 sha256'.split())
for x in 'md5 sha1 sha256'.split())

View File

@ -7,6 +7,7 @@ from util import hook, http
api_url = "http://ws.audioscrobbler.com/2.0/?format=json"
@hook.api_key('lastfm')
@hook.command(autohelp=False)
def lastfm(inp, nick='', say=None, api_key=None):

View File

@ -15,15 +15,15 @@ log_fds = {} # '%(net)s %(chan)s' : (filename, fd)
timestamp_format = '%H:%M:%S'
formats = {'PRIVMSG': '<%(nick)s> %(msg)s',
'PART': '-!- %(nick)s [%(user)s@%(host)s] has left %(chan)s',
'JOIN': '-!- %(nick)s [%(user)s@%(host)s] has joined %(param0)s',
'MODE': '-!- mode/%(chan)s [%(param_tail)s] by %(nick)s',
'KICK': '-!- %(param1)s was kicked from %(chan)s by %(nick)s [%(msg)s]',
'TOPIC': '-!- %(nick)s changed the topic of %(chan)s to: %(msg)s',
'QUIT': '-!- %(nick)s has quit [%(msg)s]',
'PING': '',
'NOTICE': ''
}
'PART': '-!- %(nick)s [%(user)s@%(host)s] has left %(chan)s',
'JOIN': '-!- %(nick)s [%(user)s@%(host)s] has joined %(param0)s',
'MODE': '-!- mode/%(chan)s [%(param_tail)s] by %(nick)s',
'KICK': '-!- %(param1)s was kicked from %(chan)s by %(nick)s [%(msg)s]',
'TOPIC': '-!- %(nick)s changed the topic of %(chan)s to: %(msg)s',
'QUIT': '-!- %(nick)s has quit [%(msg)s]',
'PING': '',
'NOTICE': ''
}
ctcp_formats = {'ACTION': '* %(nick)s %(ctcpmsg)s'}
@ -32,7 +32,7 @@ irc_color_re = re.compile(r'(\x03(\d+,\d+|\d)|[\x0f\x02\x16\x1f])')
def get_log_filename(dir, server, chan):
return os.path.join(dir, 'log', gmtime('%Y'), server,
(gmtime('%%s.%m-%d.log') % chan).lower())
(gmtime('%%s.%m-%d.log') % chan).lower())
def gmtime(format):
@ -57,8 +57,8 @@ def beautify(input):
ctcp += ['']
args['ctcpcmd'], args['ctcpmsg'] = ctcp
format = ctcp_formats.get(args['ctcpcmd'],
'%(nick)s [%(user)s@%(host)s] requested unknown CTCP '
'%(ctcpcmd)s from %(chan)s: %(ctcpmsg)s')
'%(nick)s [%(user)s@%(host)s] requested unknown CTCP '
'%(ctcpcmd)s from %(chan)s: %(ctcpmsg)s')
return format % args

View File

@ -9,7 +9,7 @@ from util import hook, http
@hook.command('mc')
def metacritic(inp):
'.mc [all|movie|tv|album|x360|ps3|pc|ds|3ds|wii|psv] <title> -- gets rating for'\
' <title> from metacritic on the specified medium'
' <title> from metacritic on the specified medium'
# if the results suck, it's metacritic's fault
@ -130,6 +130,6 @@ def metacritic(inp):
score = None
return '[%s] %s - %s, %s -- %s' % (plat.upper(), name,
score or 'no score',
'release: %s' % release if release else 'unreleased',
link)
score or 'no score',
'release: %s' % release if release else 'unreleased',
link)

View File

@ -1,4 +1,3 @@
import re
import socket
import subprocess
import time
@ -18,12 +17,12 @@ def get_version():
shorthash = stdout.split(None, 1)[0]
http.ua_skybot = 'Skybot/r%d %s (http://github.com/rmmh/skybot)' \
% (revnumber, shorthash)
% (revnumber, shorthash)
return shorthash, revnumber
#autorejoin channels
# autorejoin channels
@hook.event('KICK')
def rejoin(paraml, conn=None):
if paraml[1] == conn.nick:
@ -31,7 +30,7 @@ def rejoin(paraml, conn=None):
conn.join(paraml[0])
#join channels when invited
# join channels when invited
@hook.event('INVITE')
def invite(paraml, conn=None):
conn.join(paraml[-1])

View File

@ -33,7 +33,7 @@ def mtg(inp):
printing_out = ', '.join('%s (%s)' % (set_abbrevs.get(x[0], x[0]),
rarity_abbrevs.get(x[1], x[1]))
for x in printings)
for x in printings)
name.make_links_absolute(base_url=url)
link = name.attrib['href']

View File

@ -8,4 +8,4 @@ def profile(inp):
".profile <username> -- links to <username>'s profile on SA"
return 'http://forums.somethingawful.com/member.php?action=getinfo' + \
'&username=' + '+'.join(inp.split())
'&username=' + '+'.join(inp.split())

View File

@ -8,7 +8,7 @@ from util import hook
def add_quote(db, chan, nick, add_nick, msg):
db.execute('''insert or fail into quote (chan, nick, add_nick,
msg, time) values(?,?,?,?,?)''',
(chan, nick, add_nick, msg, time.time()))
(chan, nick, add_nick, msg, time.time()))
db.commit()
@ -20,19 +20,19 @@ def del_quote(db, chan, nick, add_nick, msg):
def get_quotes_by_nick(db, chan, nick):
return db.execute("select time, nick, msg from quote where deleted!=1 "
"and chan=? and lower(nick)=lower(?) order by time",
(chan, nick)).fetchall()
"and chan=? and lower(nick)=lower(?) order by time",
(chan, nick)).fetchall()
def get_quotes_by_chan(db, chan):
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()
def format_quote(q, num, n_quotes):
ctime, nick, msg = q
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')
@ -42,8 +42,8 @@ def quote(inp, nick='', chan='', db=None):
"random or [#n]th quote by <nick> or from <#chan>/adds quote"
db.execute("create table if not exists quote"
"(chan, nick, add_nick, msg, time real, deleted default 0, "
"primary key (chan, nick, msg))")
"(chan, nick, add_nick, msg, time real, deleted default 0, "
"primary key (chan, nick, msg))")
db.commit()
add = re.match(r"add[^\w@]+(\S+?)>?\s+(.*)", inp, re.I)
@ -61,9 +61,7 @@ def quote(inp, nick='', chan='', db=None):
elif retrieve:
select, num = retrieve.groups()
by_chan = False
if select.startswith('#'):
by_chan = True
quotes = get_quotes_by_chan(db, select)
else:
quotes = get_quotes_by_nick(db, chan, select)
@ -85,7 +83,7 @@ def quote(inp, nick='', chan='', db=None):
if num:
if num > n_quotes or (num < 0 and num < -n_quotes):
return "I only have %d quote%s for %s" % (n_quotes,
('s', '')[n_quotes == 1], select)
('s', '')[n_quotes == 1], select)
elif num < 0:
selected_quote = quotes[num]
num = n_quotes + num + 1

View File

@ -7,11 +7,11 @@ def bible(inp):
".bible <passage> -- gets <passage> from the Bible (ESV)"
base_url = ('http://www.esvapi.org/v2/rest/passageQuery?key=IP&'
'output-format=plain-text&include-heading-horizontal-lines&'
'include-headings=false&include-passage-horizontal-lines=false&'
'include-passage-references=false&include-short-copyright=false&'
'include-footnotes=false&line-length=0&'
'include-heading-horizontal-lines=false')
'output-format=plain-text&include-heading-horizontal-lines&'
'include-headings=false&include-passage-horizontal-lines=false&'
'include-passage-references=false&include-short-copyright=false&'
'include-footnotes=false&line-length=0&'
'include-heading-horizontal-lines=false')
text = http.get(base_url, passage=inp)

View File

@ -13,7 +13,7 @@ def db_init(db):
def get_memory(db, chan, word):
row = db.execute("select data from memory where chan=? and word=lower(?)",
(chan, word)).fetchone()
(chan, word)).fetchone()
if row:
return row[0]
else:
@ -56,7 +56,7 @@ def remember(inp, nick='', chan='', db=None):
return "appending %s to %s" % (new, data.replace('"', "''"))
else:
return 'forgetting "%s", remembering this instead.' % \
data.replace('"', "''")
data.replace('"', "''")
else:
return 'done.'

View File

@ -25,11 +25,13 @@ def rottentomatoes(inp, api_key=None):
if critics_score == -1:
return
reviews = http.get_json(movie_reviews_url % id, apikey=api_key, review_type='all')
reviews = http.get_json(movie_reviews_url %
id, apikey=api_key, review_type='all')
review_count = reviews['total']
fresh = critics_score * review_count / 100
rotten = review_count - fresh
return u"%s - critics: \x02%d%%\x02 (%d\u2191%d\u2193)" \
" audience: \x02%d%%\x02 - %s" % (title, critics_score, fresh, rotten, audience_score, url)
" audience: \x02%d%%\x02 - %s" % (title, critics_score,
fresh, rotten, audience_score, url)

View File

@ -8,7 +8,7 @@ from util import hook, timesince
def db_init(db):
"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, "
"primary key(name, chan))")
"primary key(name, chan))")
db.commit()
@ -17,8 +17,8 @@ def db_init(db):
def seeninput(paraml, input=None, db=None, bot=None):
db_init(db)
db.execute("insert or replace into seen(name, time, quote, chan)"
"values(?,?,?,?)", (input.nick.lower(), time.time(), input.msg,
input.chan))
"values(?,?,?,?)", (input.nick.lower(), time.time(), input.msg,
input.chan))
db.commit()
@ -44,11 +44,11 @@ def seen(inp, nick='', chan='', db=None, input=None):
reltime = timesince.timesince(last_seen[1])
if last_seen[0] != inp.lower(): # for glob matching
inp = last_seen[0]
if last_seen[2][0:1]=="\x01":
if last_seen[2][0:1] == "\x01":
return '%s was last seen %s ago: *%s %s*' % \
(inp, reltime, inp, last_seen[2][8:-1])
(inp, reltime, inp, last_seen[2][8:-1])
else:
return '%s was last seen %s ago saying: %s' % \
(inp, reltime, last_seen[2])
(inp, reltime, last_seen[2])
else:
return "I've never seen %s" % inp

View File

@ -26,7 +26,7 @@ def snopes(inp):
status = status.group(0).strip()
else: # new-style statuses
status = "Status: %s." % re.search(r"FALSE|TRUE|MIXTURE|UNDETERMINED",
snopes_text).group(0).title()
snopes_text).group(0).title()
claim = re.sub(r"[\s\xa0]+", " ", claim) # compress whitespace
status = re.sub(r"[\s\xa0]+", " ", status)

View File

@ -16,7 +16,7 @@ def login(user, password):
user = http.quote(user)
password = http.quote(password)
http.get("http://forums.somethingawful.com/account.php", cookies=True,
post_data="action=login&username=%s&password=%s" % (user, password))
post_data="action=login&username=%s&password=%s" % (user, password))
@hook.api_key('somethingawful')
@ -49,8 +49,8 @@ def forum_link(inp, api_key=None):
num_posts = int(num_posts[0].rsplit('=', 1)[1])
return '\x02%s\x02 > \x02%s\x02 by \x02%s\x02, %s post%s' % (
forum_title, thread_title, poster, num_posts,
's' if num_posts > 1 else '')
forum_title, thread_title, poster, num_posts,
's' if num_posts > 1 else '')
forum_abbrevs = {

View File

@ -1,5 +1,3 @@
import random
from util import hook, http

View File

@ -19,7 +19,8 @@ def suggest(inp, inp_unstripped=''):
else:
num = 0
page = http.get('http://google.com/complete/search', output='json', client='hp', q=inp)
page = http.get('http://google.com/complete/search',
output='json', client='hp', q=inp)
page_json = page.split('(', 1)[1][:-1]
suggestions = json.loads(page_json)[1]
if not suggestions:

View File

@ -20,7 +20,9 @@ def munge(inp, munge_count=0):
break
return inp
class PaginatingWinnower(object):
def __init__(self):
self.lock = threading.Lock()
self.last_input = []
@ -48,7 +50,8 @@ class PaginatingWinnower(object):
if inp in inputs:
inputs.remove(inp)
else:
inputs.remove(random.choice([inp for inp in inputs if inp in self.recent]))
inputs.remove(
random.choice([inp for inp in inputs if inp in self.recent]))
else:
if ordered:
inputs.pop()
@ -61,6 +64,7 @@ class PaginatingWinnower(object):
winnow = PaginatingWinnower().winnow
def add_tag(db, chan, nick, subject):
match = db.execute('select * from tag where lower(nick)=lower(?) and'
' chan=? and lower(subject)=lower(?)',
@ -95,7 +99,6 @@ def get_tag_counts_by_chan(db, chan):
tags.sort(key=lambda x: x[1], reverse=True)
if not tags:
return 'no tags in %s' % chan
ret = '%s tags: ' % chan
return winnow(['%s (%d)' % row for row in tags], ordered=True)
@ -105,7 +108,7 @@ def get_tags_by_nick(db, chan, nick):
" order by lower(subject)", (nick, chan)).fetchall()
if tags:
return 'tags for "%s": ' % munge(nick, 1) + winnow([
tag[0] for tag in tags])
tag[0] for tag in tags])
else:
return ''
@ -151,6 +154,7 @@ def tag(inp, chan='', db=None):
else:
return tag.__doc__
@hook.command
def untag(inp, chan='', db=None):
'.untag <nick> <tag> -- unmarks <nick> as <tag> {related: .tag, .tags, .tagged}'
@ -163,6 +167,7 @@ def untag(inp, chan='', db=None):
else:
return untag.__doc__
@hook.command
def tags(inp, chan='', db=None):
'.tags <nick>/list -- get list of tags for <nick>, or a list of tags {related: .tag, .untag, .tagged}'
@ -182,6 +187,7 @@ def tagged(inp, chan='', db=None):
return get_nicks_by_tagset(db, chan, inp)
def distance(lat1, lon1, lat2, lon2):
deg_to_rad = math.pi / 180
lat1 *= deg_to_rad
@ -189,17 +195,18 @@ def distance(lat1, lon1, lat2, lon2):
lon1 *= deg_to_rad
lon2 *= deg_to_rad
R = 6371 # km
d = math.acos(math.sin(lat1)*math.sin(lat2) +
math.cos(lat1)*math.cos(lat2) *
math.cos(lon2-lon1)) * R
R = 6371 # km
d = math.acos(math.sin(lat1) * math.sin(lat2) +
math.cos(lat1) * math.cos(lat2) *
math.cos(lon2 - lon1)) * R
return d
@hook.command(autohelp=False)
def near(inp, nick='', chan='', db=None):
try:
loc = db.execute("select lat, lon from location where chan=? and nick=lower(?)", (chan, nick)).fetchone()
loc = db.execute("select lat, lon from location where chan=? and nick=lower(?)",
(chan, nick)).fetchone()
except db.OperationError:
loc = None
@ -210,10 +217,9 @@ def near(inp, nick='', chan='', db=None):
db.create_function('distance', 4, distance)
nearby = db.execute("select nick, distance(lat, lon, ?, ?) as dist from location where chan=?"
" and nick != lower(?) order by dist limit 20", (lat, lon, chan, nick)).fetchall()
" and nick != lower(?) order by dist limit 20", (lat, lon, chan, nick)).fetchall()
out = '(km) '
last_dist = 10
while nearby and len(out) < 200:
nick, dist = nearby.pop(0)
out += '%s:%.0f ' % (munge(nick, 1), dist)

View File

@ -9,8 +9,8 @@ from util import hook, timesince
def db_init(db):
"check to see that our db has the tell table and return a dbection."
db.execute("create table if not exists tell"
"(user_to, user_from, message, chan, time,"
"primary key(user_to, message))")
"(user_to, user_from, message, chan, time,"
"primary key(user_to, message))")
db.commit()
return db
@ -18,8 +18,8 @@ def db_init(db):
def get_tells(db, user_to):
return db.execute("select user_from, message, time, chan from tell where"
" user_to=lower(?) order by time",
(user_to.lower(),)).fetchall()
" user_to=lower(?) order by time",
(user_to.lower(),)).fetchall()
@hook.singlethread
@ -42,7 +42,7 @@ def tellinput(paraml, input=None, db=None, bot=None):
reply += " (+%d more, .showtells to view)" % (len(tells) - 1)
db.execute("delete from tell where user_to=lower(?) and message=?",
(input.nick, message))
(input.nick, message))
db.commit()
input.notice(reply)
@ -65,7 +65,7 @@ def showtells(inp, nick='', chan='', notice=None, db=None):
notice("%s said %s ago in %s: %s" % (user_from, past, chan, message))
db.execute("delete from tell where user_to=lower(?)",
(nick,))
(nick,))
db.commit()
@ -91,13 +91,13 @@ def tell(inp, nick='', chan='', db=None):
db_init(db)
if db.execute("select count() from tell where user_to=?",
(user_to,)).fetchone()[0] >= 5:
(user_to,)).fetchone()[0] >= 5:
return "That person has too many things queued."
try:
db.execute("insert into tell(user_to, user_from, message, chan,"
"time) values(?,?,?,?,?)", (user_to, user_from, message,
chan, time.time()))
"time) values(?,?,?,?,?)", (user_to, user_from, message,
chan, time.time()))
db.commit()
except db.IntegrityError:
return "Message has already been queued."

View File

@ -40,13 +40,14 @@ def unescape(text):
def goog_trans(text, slang, tlang):
url = 'https://www.googleapis.com/language/translate/v2'
parsed = http.get_json(url, key=api_key, q=text, source=slang, target=tlang)
parsed = http.get_json(
url, key=api_key, q=text, source=slang, target=tlang)
if not 200 <= parsed['responseStatus'] < 300:
raise IOError('error with the translation server: %d: %s' % (
parsed['responseStatus'], parsed['responseDetails']))
parsed['responseStatus'], parsed['responseDetails']))
if not slang:
return unescape('(%(detectedSourceLanguage)s) %(translatedText)s' %
(parsed['responseData']['data']['translations'][0]))
(parsed['responseData']['data']['translations'][0]))
return unescape('%(translatedText)s' % parsed['responseData']['data']['translations'][0])
@ -66,8 +67,8 @@ def match_language(fragment):
@hook.command
def translate(inp, bot=None):
'.translate [source language [target language]] <sentence> -- translates' \
' <sentence> from source language (default autodetect) to target' \
' language (default English) using Google Translate'
' <sentence> from source language (default autodetect) to target' \
' language (default English) using Google Translate'
if not hasapikey(bot):
return None
@ -141,6 +142,7 @@ def babelext(inp, bot=None):
return out
def hasapikey(bot):
api_key = bot.config.get("api_keys", {}).get("googletranslate", None)
return api_key

View File

@ -5,7 +5,6 @@ modified by rmmh 2010, 2013
import datetime
from lxml import etree
from util import hook, http, timesince
@ -31,7 +30,8 @@ def get_episodes_for_series(seriesname):
series_id = series_id[0]
try:
series = http.get_xml(base_url + '%s/series/%s/all/en.xml' % (api_key, series_id))
series = http.get_xml(base_url + '%s/series/%s/all/en.xml' %
(api_key, series_id))
except http.URLError:
res["error"] = "error contacting thetvdb.com"
return res
@ -97,12 +97,13 @@ def tv_next(inp):
(episode_air_date, airdate, episode_desc) = ep_info
if airdate > today:
next_eps = ['%s (%s) (%s)' % (episode_air_date, timesince.timeuntil(datetime.datetime.strptime(episode_air_date, "%Y-%m-%d")), episode_desc)]
next_eps = ['%s (%s) (%s)' % (episode_air_date, timesince.timeuntil(
datetime.datetime.strptime(episode_air_date, "%Y-%m-%d")), episode_desc)]
elif airdate == today:
next_eps = ['Today (%s)' % episode_desc] + next_eps
else:
#we're iterating in reverse order with newest episodes last
#so, as soon as we're past today, break out of loop
# we're iterating in reverse order with newest episodes last
# so, as soon as we're past today, break out of loop
break
if not next_eps:
@ -140,8 +141,8 @@ def tv_last(inp):
(episode_air_date, airdate, episode_desc) = ep_info
if airdate < today:
#iterating in reverse order, so the first episode encountered
#before today was the most recently aired
# iterating in reverse order, so the first episode encountered
# before today was the most recently aired
prev_ep = '%s (%s)' % (episode_air_date, episode_desc)
break

View File

@ -5,14 +5,15 @@ from urllib import quote
from util import hook, http
@hook.api_key('twitter')
@hook.command
def twitter(inp, api_key=None):
".twitter <user>/<user> <n>/<id>/#<search>/#<search> <n> -- " \
"get <user>'s last/<n>th tweet/get tweet <id>/do <search>/get <n>th <search> result"
"get <user>'s last/<n>th tweet/get tweet <id>/do <search>/get <n>th <search> result"
if not isinstance(api_key, dict) or any(key not in api_key for key in
('consumer', 'consumer_secret', 'access', 'access_secret')):
('consumer', 'consumer_secret', 'access', 'access_secret')):
return "error: api keys not set"
getting_id = False
@ -44,13 +45,13 @@ def twitter(inp, api_key=None):
tweet = http.get_json(request_url, oauth=True, oauth_keys=api_key)
except http.HTTPError, e:
errors = {400: 'bad request (ratelimited?)',
401: 'unauthorized',
403: 'forbidden',
404: 'invalid user/id',
500: 'twitter is broken',
502: 'twitter is down ("getting upgraded")',
503: 'twitter is overloaded (lol, RoR)',
410: 'twitter shut off api v1.' }
401: 'unauthorized',
403: 'forbidden',
404: 'invalid user/id',
500: 'twitter is broken',
502: 'twitter is down ("getting upgraded")',
503: 'twitter is overloaded (lol, RoR)',
410: 'twitter shut off api v1.'}
if e.code == 404:
return 'error: invalid ' + ['username', 'tweet id'][getting_id]
if e.code in errors:
@ -75,11 +76,13 @@ def twitter(inp, api_key=None):
screen_name = tweet["user"]["screen_name"]
time = tweet["created_at"]
time = strftime('%Y-%m-%d %H:%M:%S', strptime(time, '%a %b %d %H:%M:%S +0000 %Y'))
time = strftime('%Y-%m-%d %H:%M:%S',
strptime(time, '%a %b %d %H:%M:%S +0000 %Y'))
return "%s \x02%s\x02: %s" % (time, screen_name, text)
@hook.api_key('twitter')
@hook.regex(r'https?://twitter.com/(#!/)?([_0-9a-zA-Z]+)/status/(\d+)')
def show_tweet(match, api_key=None):
return twitter(match.group(3),api_key)
return twitter(match.group(3), api_key)

View File

@ -1,5 +1,4 @@
import math
import re
import time
from util import hook, urlnorm, timesince
@ -12,22 +11,21 @@ ignored_urls = [urlnorm.normalize("http://google.com")]
def db_init(db):
db.execute("create table if not exists urlhistory"
"(chan, url, nick, time)")
"(chan, url, nick, time)")
db.commit()
def insert_history(db, chan, url, nick):
now = time.time()
db.execute("insert into urlhistory(chan, url, nick, time) "
"values(?,?,?,?)", (chan, url, nick, time.time()))
"values(?,?,?,?)", (chan, url, nick, time.time()))
db.commit()
def get_history(db, chan, url):
db.execute("delete from urlhistory where time < ?",
(time.time() - expiration_period,))
(time.time() - expiration_period,))
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):
@ -60,7 +58,7 @@ def format_reply(history):
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,
hour_span, nicklist(history), last)
hour_span, nicklist(history), last)
@hook.regex(r'([a-zA-Z]+://|www\.)[^ ]+')

View File

@ -22,7 +22,7 @@ def _hook_add(func, add, name=''):
n_args -= 1
if n_args != 1:
err = '%ss must take 1 non-keyword argument (%s)' % (name,
func.__name__)
func.__name__)
raise ValueError(err)
args = []
@ -41,7 +41,7 @@ def _hook_add(func, add, name=''):
def sieve(func):
if func.func_code.co_argcount != 5:
raise ValueError(
'sieves must take 5 arguments: (bot, input, func, type, args)')
'sieves must take 5 arguments: (bot, input, func, type, args)')
_hook_add(func, ['sieve', (func,)])
return func

View File

@ -10,7 +10,7 @@ import urllib
import urllib2
import urlparse
from hashlib import sha1
from hashlib import sha1
from urllib import quote, quote_plus as _quote_plus
from urllib2 import HTTPError, URLError
@ -69,14 +69,16 @@ def open(url, query_params=None, user_agent=None, referer=None, post_data=None,
nonce = oauth_nonce()
timestamp = oauth_timestamp()
api_url, req_data = string.split(url, "?")
unsigned_request = oauth_unsigned_request(nonce, timestamp, req_data, oauth_keys['consumer'], oauth_keys['access'])
signature = oauth_sign_request("GET", api_url, req_data, unsigned_request, oauth_keys['consumer_secret'], oauth_keys['access_secret'])
header = oauth_build_header(nonce, signature, timestamp, oauth_keys['consumer'], oauth_keys['access'])
unsigned_request = oauth_unsigned_request(
nonce, timestamp, req_data, oauth_keys['consumer'], oauth_keys['access'])
signature = oauth_sign_request("GET", api_url, req_data, unsigned_request, oauth_keys[
'consumer_secret'], oauth_keys['access_secret'])
header = oauth_build_header(
nonce, signature, timestamp, oauth_keys['consumer'], oauth_keys['access'])
request.add_header('Authorization', header)
if cookies:
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar))
else:
@ -91,7 +93,7 @@ def prepare_url(url, queries):
query = dict(urlparse.parse_qsl(query))
query.update(queries)
query = urllib.urlencode(dict((to_utf8(key), to_utf8(value))
for key, value in query.iteritems()))
for key, value in query.iteritems()))
url = urlparse.urlunsplit((scheme, netloc, path, query, fragment))
@ -108,48 +110,53 @@ def to_utf8(s):
def quote_plus(s):
return _quote_plus(to_utf8(s))
def oauth_nonce():
return ''.join([str(random.randint(0, 9)) for i in range(8)])
def oauth_timestamp():
return str(int(time.time()))
def oauth_unsigned_request(nonce, timestamp, req, consumer, token):
d = { 'oauth_consumer_key':consumer,
'oauth_nonce':nonce,
'oauth_signature_method':'HMAC-SHA1',
'oauth_timestamp':timestamp,
'oauth_token':token,
'oauth_version':'1.0' }
k,v = string.split(req, "=")
def oauth_unsigned_request(nonce, timestamp, req, consumer, token):
d = {'oauth_consumer_key': consumer,
'oauth_nonce': nonce,
'oauth_signature_method': 'HMAC-SHA1',
'oauth_timestamp': timestamp,
'oauth_token': token,
'oauth_version': '1.0'}
k, v = string.split(req, "=")
d[k] = v
unsigned_req = ''
for x in sorted(d, key=lambda key: key):
unsigned_req += x + "=" + d[x] + "&"
unsigned_req = quote(unsigned_req[:-1])
return unsigned_req
def oauth_build_header(nonce, signature, timestamp, consumer, token):
d = { 'oauth_consumer_key':consumer,
'oauth_nonce':nonce,
'oauth_signature':signature,
'oauth_signature_method':'HMAC-SHA1',
'oauth_timestamp':timestamp,
'oauth_token':token,
'oauth_version':'1.0' }
header='OAuth '
def oauth_build_header(nonce, signature, timestamp, consumer, token):
d = {'oauth_consumer_key': consumer,
'oauth_nonce': nonce,
'oauth_signature': signature,
'oauth_signature_method': 'HMAC-SHA1',
'oauth_timestamp': timestamp,
'oauth_token': token,
'oauth_version': '1.0'}
header = 'OAuth '
for x in sorted(d, key=lambda key: key):
header += x + '="' + d[x] + '", '
return header[:-1]
def oauth_sign_request(method, url, params, unsigned_request, consumer_secret, token_secret):
key = consumer_secret + "&" + token_secret
@ -158,9 +165,10 @@ def oauth_sign_request(method, url, params, unsigned_request, consumer_secret, t
hash = hmac.new(key, base, sha1)
signature = quote(binascii.b2a_base64(hash.digest())[:-1])
return signature
def unescape(s):
if not s.strip():
return s

View File

@ -22,4 +22,4 @@ def validate(inp):
errorcount = info['x-w3c-validator-errors']
warningcount = info['x-w3c-validator-warnings']
return "%s was found to be %s with %s errors and %s warnings." \
" see: %s" % (inp, status, errorcount, warningcount, url)
" see: %s" % (inp, status, errorcount, warningcount, url)

View File

@ -1,23 +1,21 @@
"weather, thanks to wunderground"
import math
from util import hook, http
@hook.api_key('wunderground')
@hook.command(autohelp=False)
def weather(inp, chan='', nick='', reply=None, db=None, api_key=None):
".weather <location> [dontsave] -- gets weather data from Wunderground "\
"http://wunderground.com/weather/api"
"http://wunderground.com/weather/api"
if not api_key:
return None
# this database is used by other plugins interested in user's locations,
# like .near in tag.py
db.execute("create table if not exists location(chan, nick, loc, lat, lon, primary key(chan, nick))")
db.execute(
"create table if not exists location(chan, nick, loc, lat, lon, primary key(chan, nick))")
loc = inp
@ -25,10 +23,10 @@ def weather(inp, chan='', nick='', reply=None, db=None, api_key=None):
if dontsave:
loc = loc[:-9].strip().lower()
if not loc: # blank line
loc = db.execute("select loc from location where chan=? and nick=lower(?)",
(chan, nick)).fetchone()
loc = db.execute(
"select loc from location where chan=? and nick=lower(?)",
(chan, nick)).fetchone()
if not loc:
try:
# grab from old-style weather database
@ -104,10 +102,10 @@ def weather(inp, chan='', nick='', reply=None, db=None, api_key=None):
info['l_c'] = sf['low']['celsius']
info['humid'] = obs['relative_humidity']
info['wind'] = 'Wind: {mph}mph/{kph}kph' \
.format(mph=obs['wind_mph'], kph=obs['wind_kph'])
reply('{city}: {weather}, {t_f}F/{t_c}C' \
'(H:{h_f}F/{h_c}C L:{l_f}F/{l_c}C)' \
', Humidity: {humid}, {wind}'.format(**info))
.format(mph=obs['wind_mph'], kph=obs['wind_kph'])
reply('{city}: {weather}, {t_f}F/{t_c}C'
'(H:{h_f}F/{h_c}C L:{l_f}F/{l_c}C)'
', Humidity: {humid}, {wind}'.format(**info))
lat = float(obs['display_location']['latitude'])
lon = float(obs['display_location']['longitude'])
@ -116,5 +114,3 @@ def weather(inp, chan='', nick='', reply=None, db=None, api_key=None):
db.execute("insert or replace into location(chan, nick, loc, lat, lon) "
"values (?, ?, ?, ?,?)", (chan, nick.lower(), inp, lat, lon))
db.commit()

View File

@ -16,7 +16,7 @@ paren_re = re.compile('\s*\(.*\)$')
@hook.command
def wiki(inp):
'''.w/.wiki <phrase> -- gets first sentence of wikipedia ''' \
'''article on <phrase>'''
'''article on <phrase>'''
x = http.get_xml(search_url, search=inp)
@ -31,7 +31,7 @@ def wiki(inp):
def extract(item):
return [item.find(ns + x).text for x in
('Text', 'Description', 'Url')]
('Text', 'Description', 'Url')]
title, desc, url = extract(items[0])

View File

@ -1,6 +1,7 @@
from util import hook, http
from random import choice
@hook.api_key('yahoo')
@hook.command
def answer(inp, api_key=None):
@ -9,10 +10,10 @@ def answer(inp, api_key=None):
url = "http://answers.yahooapis.com/AnswersService/V1/questionSearch"
result = http.get_json(url,
query=inp,
search_in="question",
output="json",
appid=api_key)
query=inp,
search_in="question",
output="json",
appid=api_key)
questions = result.get("all", {}).get("questions", [])
answered = filter(lambda x: x.get("ChosenAnswer", ""), questions)
@ -25,4 +26,3 @@ def answer(inp, api_key=None):
response = "%s -- %s" % (link, answer)
return " ".join(response.split())

View File

@ -39,17 +39,17 @@ def get_video_description(vid_id):
if 'rating' in j:
out += ' - rated \x02%.2f/5.0\x02 (%d)' % (j['rating'],
j['ratingCount'])
j['ratingCount'])
# The use of str.decode() prevents UnicodeDecodeError with some locales
# See http://stackoverflow.com/questions/4082645/
if 'viewCount' in j:
out += ' - \x02%s\x02 views' % locale.format('%d',
j['viewCount'], 1).decode(locale.getlocale()[1])
j['viewCount'], 1).decode(locale.getlocale()[1])
upload_time = time.strptime(j['uploaded'], "%Y-%m-%dT%H:%M:%S.000Z")
out += ' - \x02%s\x02 on \x02%s\x02' % (j['uploader'],
time.strftime("%Y.%m.%d", upload_time))
time.strftime("%Y.%m.%d", upload_time))
if 'contentRating' in j:
out += ' - \x034NSFW\x02'