#!/usr/bin/env python # Rugby score announcing bot # Copyright (C) 2008 Michael Gorven # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from ircbot import SingleServerIRCBot from irclib import nm_to_n, nm_to_h, irc_lower, ip_numstr_to_quad, ip_quad_to_numstr from threading import Timer from BeautifulSoup import BeautifulSoup from urllib2 import urlopen import re class RugbyBot(SingleServerIRCBot): def __init__(self, channels, nickname, servers, password): SingleServerIRCBot.__init__(self, servers, nickname, nickname) self.channellist = channels self.password = password self.games = {} self.scores = {} t = Timer(30, self.update) t.start() def on_nicknameinuse(self, connection, event): connection.nick(connection.get_nickname() + "_") def on_welcome(self, connection, event): connection.privmsg('NickServ', 'IDENTIFY %s' % self.password) def on_privnotice(self, connection, event): message = event.arguments()[0] if event.source() is not None and event.source().startswith('NickServ') and ('accepted' in message or 'identified' in message): for channel in channels: connection.join(channel) def on_pubmsg(self, connection, event): message = event.arguments()[0].split(":", 1) if len(message) > 1 and irc_lower(message[0]) == irc_lower(self.connection.get_nickname()): self.do_command(event, message[1].strip()) def on_privmsg(self, connection, event): self.do_command(event, event.arguments()[0].strip()) def do_command(self, event, command): print 'Handling command: %s' % command nick = nm_to_n(event.source()) target = nm_to_n(event.target()) connection = self.connection if target[0] == '#': respondto = target prefix = nick + ': ' else: respondto = nick prefix = '' arguments = command.split(' ') if command == 'disconnect': self.disconnect() elif command == 'die': self.die() elif command == 'help': connection.privmsg(respondto, prefix + 'Commands: follow , stop ') elif arguments[0] == 'leave': if len(arguments) > 1: channel = arguments[1] elif respondto[0] == '#': channel = respondto else: self.connection.privmsg(respondto, prefix + 'Channel not specified') return self.connection.part(channel) self._remove_subscription(channel) elif arguments[0] == 'join': if len(arguments) < 2 or arguments[1][0] is not '#': self.connection.privmsg(respondto, prefix + 'Please specify channel') else: self.connection.join(arguments[1]) elif arguments[0] == 'list': fixtures = self._getfixtures() for fixture in fixtures: self.connection.privmsg(respondto, prefix + '%s: %s' % fixture) elif arguments[0] == 'follow': if len(arguments) < 2: connection.privmsg(respondto, prefix + 'Please specify a game ID to follow') else: try: gameid = int(arguments[1]) except ValueError: connection.privmsg(respondto, prefix + 'Invalid game ID') return if self._add_subscription(respondto, gameid) is False: self.connection.privmsg(respondto, prefix + "That isn't a current game") else: connection.privmsg(respondto, prefix + 'Now following game %s' % (str(gameid))) elif arguments[0] == 'stop': if len(arguments) < 2: connection.privmsg(respondto, prefix + 'Please specify a game ID to stop following') else: if arguments[1] == 'all': self._remove_subscription(respondto) self.connection.privmsg(respondto, prefix + 'Not following any games anymore') else: try: gameid = int(arguments[1]) except ValueError: connection.privmsg(respondto, prefix + 'Invalid game ID') return if not self.games.has_key(gameid): connection.privmsg(respondto, prefix + 'Not following that game') elif respondto not in self.games[gameid]: connection.privmsg(respondto, prefix + 'Not following that game in here') else: self._remove_subscription(respondto, gameid) connection.privmsg(respondto, prefix + 'Not following game %s anymore' % (gameid)) else: self.respond(nick, target, 'Invalid command') print self.games def _add_subscription(self, recipient, game): if self.games.has_key(game): self.games[game].append(recipient) else: score = self._getscore(game) if score is None: return False self.games[game] = [recipient] def _remove_subscription(self, recipient, game=None): if game == None: for game, channels in self.games.items(): self._remove_subscription(recipient, game) else: if self.games.has_key(game) and recipient in self.games[game]: self.games[game].remove(recipient) if len(self.games[game]) == 0: del self.games[game] def _getscore(self, id): try: scoref = urlopen('http://www.supersport.co.za/rugby/live.aspx?id=%s&type=reload' % id) soup = BeautifulSoup(scoref.read()) scoref.close() score = soup.b.contents[0] status = soup.td.contents[2] if score == ' vs ': return None else: return (score, status) except: return False def _getfixtures(self): try: livef = urlopen('file:///tmp/page.html') soup = BeautifulSoup(livef.read()) livef.close() fixturelist = [] fixtures = soup.findAll('table', width='940')[0].tr.td for table in fixtures.findAll('table', attrs={'class': 'fixtures_results'}): if table.findPreviousSibling() is not None and table.findPreviousSibling().tr.td.contents[1].find('Rugby') != -1: for row in table.findAll('tr'): name = row.findAll('td')[0].contents[0].strip() id = int(re.search("id=(\d*)'", row.findAll('td')[2].a['onclick']).groups()[0]) fixturelist.append((id, name,)) break print fixturelist return fixturelist except: return None def update(self): for game, targets in self.games.items(): score = self._getscore(game) if score is not False: message = score[0] + ' (' + score[0] + ')' print message if not self.scores.has_key(game) or not self.scores[game] == message: for target in targets: self.connection.privmsg(target, message) self.scores[game] = message if score[1] == 'Full Time': del self.games[game] del self.scores[game] t = Timer(30, self.update) t.start() if __name__ == '__main__': servers = [('irc.example.com', 6667)] channels = ['#channel'] bot = RugbyBot(channels, 'nick', servers, 'password') bot.start()