#!/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()