X-Git-Url: https://jfr.im/git/z_archive/twitter.git/blobdiff_plain/d8ac8b7264bd351654d10bdb8a0806dae5b31d47..de072195b64f3535375f1a20b25f457586a29125:/twitter/ircbot.py diff --git a/twitter/ircbot.py b/twitter/ircbot.py index c5363ea..e882ba7 100644 --- a/twitter/ircbot.py +++ b/twitter/ircbot.py @@ -24,14 +24,9 @@ email: password: If no config file is given "twitterbot.ini" will be used by default. - """ -# TODO add delimiter if first word isn't "is" or "was" -# TODO handle newlines -# TODO handle quotes - -BOT_VERSION = "TwitterBot 0.2.1 (mike.verdone.ca/twitter)" +BOT_VERSION = "TwitterBot 1.0 (http://mike.verdone.ca/twitter)" IRC_BOLD = chr(0x02) IRC_ITALIC = chr(0x16) @@ -41,11 +36,13 @@ IRC_REGULAR = chr(0x0f) import sys import time from dateutil.parser import parse -from ConfigParser import ConfigParser +from ConfigParser import SafeConfigParser from heapq import heappop, heappush import traceback +import os.path from api import Twitter, TwitterError +from util import htmlentitydecode try: import irclib @@ -85,19 +82,17 @@ class Scheduler(object): now = time.time() task = heappop(self.task_heap) wait = task.next - now + task.next = now + task.delta + heappush(self.task_heap, task) if (wait > 0): time.sleep(wait) task() - task.next = now + task.delta - heappush(self.task_heap, task) debug("tasks: " + str(self.task_heap)) def run_forever(self): - try: - while True: - self.next_task() - except KeyboardInterrupt: - pass + while True: + self.next_task() + class TwitterBot(object): def __init__(self, configFilename): @@ -124,22 +119,28 @@ class TwitterBot(object): traceback.print_exc(file=sys.stderr) return + nextLastUpdate = self.lastUpdate for update in updates: crt = parse(update['created_at']).utctimetuple() if (crt > self.lastUpdate): - text = ( - update['text'] - .replace('\n', ' ') - .replace(""", "\"") - .replace('&', '&')) - self.privmsg_channel( - "=^_^= %s%s%s %s" %( - IRC_BOLD, update['user']['screen_name'], - IRC_BOLD, text)) - self.lastUpdate = crt + text = (htmlentitydecode( + update['text'].replace('\n', ' ')) + .encode('utf-8', 'replace')) + + # Skip updates beginning with @ + # TODO This would be better if we only ignored messages + # to people who are not on our following list. + if not text.startswith("@"): + self.privmsg_channel( + u"=^_^= %s%s%s %s" %( + IRC_BOLD, update['user']['screen_name'], + IRC_BOLD, text.decode('utf-8'))) + + nextLastUpdate = crt else: break - + self.lastUpdate = nextLastUpdate + def process_events(self): debug("In process_events") self.irc.process_once() @@ -176,7 +177,7 @@ class TwitterBot(object): def privmsg_channel(self, msg): return self.ircServer.privmsg( - self.config.get('irc', 'channel'), msg) + self.config.get('irc', 'channel'), msg.encode('utf-8')) def follow(self, conn, evt, name): userNick = evt.source().split('!')[0] @@ -224,27 +225,57 @@ class TwitterBot(object): self.config.getint('irc', 'port'), self.config.get('irc', 'nick')) self.ircServer.join(self.config.get('irc', 'channel')) - try: - self.sched.run_forever() - except KeyboardInterrupt: - pass + + while True: + try: + self.sched.run_forever() + except KeyboardInterrupt: + break + except TwitterError: + # twitter.com is probably down because it sucks. ignore the fault and keep going + pass def load_config(filename): defaults = dict(server=dict(port=6667, nick="twitterbot")) - cp = ConfigParser(defaults) + cp = SafeConfigParser(defaults) cp.read((filename,)) + + # attempt to read these properties-- they are required + cp.get('twitter', 'email'), + cp.get('twitter', 'password') + cp.get('irc', 'server') + cp.getint('irc', 'port') + cp.get('irc', 'nick') + cp.get('irc', 'channel') + return cp + +# Howdy, hacker!! You've found the secret Twitter business model!! +# +# 1. provide awesome status-update service +# 2. buy a lot of new hardware to keep it running +# 3. ??? +# 4. profit! +# +# I'm just kidding... :3 + + def main(): configFilename = "twitterbot.ini" if (sys.argv[1:]): configFilename = sys.argv[1] + try: + if not os.path.exists(configFilename): + raise Exception() load_config(configFilename) - except: - print >> sys.stderr, "Error loading ini file %s" %( + except Exception, e: + print >> sys.stderr, "Error while loading ini file %s" %( configFilename) - print __doc__ + print >> sys.stderr, e + print >> sys.stderr, __doc__ sys.exit(1) + bot = TwitterBot(configFilename) return bot.run()