nemubot/modules/worldcup.py

221 lines
7.2 KiB
Python

# coding=utf-8
"""The 2014 football worldcup module"""
from datetime import datetime, timezone
import json
import re
from urllib.parse import quote
from urllib.request import urlopen
from nemubot.exception import IRCException
from nemubot.hooks import hook
from nemubot.tools.xmlparser.node import ModuleState
nemubotversion = 3.4
from more import Response
API_URL="http://worldcup.sfg.io/%s"
def load(context):
from nemubot.event import ModuleEvent
add_event(ModuleEvent(func=lambda url: urlopen(url, timeout=10).read().decode(), func_data=API_URL % "matches/current?by_date=DESC", call=current_match_new_action, interval=30))
def help_full ():
return "!worldcup: do something."
def start_watch(msg):
global DATAS
w = ModuleState("watch")
w["server"] = msg.server
w["channel"] = msg.channel
w["proprio"] = msg.nick
w["start"] = datetime.now(timezone.utc)
DATAS.addChild(w)
save()
raise IRCException("This channel is now watching world cup events!")
@hook("cmd_hook", "watch_worldcup")
def cmd_watch(msg):
global DATAS
# Get current state
node = None
for n in DATAS.getChilds():
if n["server"] == msg.server and n["channel"] == msg.channel:
node = n
break
if len(msg.cmds) >= 2:
if msg.cmds[1] == "stop" and node is not None:
DATAS.delChild(node)
save()
raise IRCException("This channel will not anymore receives world cup events.")
elif msg.cmds[1] == "start" and node is None:
start_watch(msg)
else:
raise IRCException("Use only start or stop as first argument")
else:
if node is None:
start_watch(msg)
else:
DATAS.delChild(node)
save()
raise IRCException("This channel will not anymore receives world cup events.")
def current_match_new_action(match_str, osef):
global DATAS
add_event(ModuleEvent(func=lambda url: urlopen(url).read().decode(), func_data=API_URL % "matches/current?by_date=DESC", call=current_match_new_action, interval=30))
matches = json.loads(match_str)
for match in matches:
if is_valid(match):
events = sort_events(match["home_team"], match["away_team"], match["home_team_events"], match["away_team_events"])
msg = "Match %s vs. %s ; score %s - %s" % (match["home_team"]["country"], match["away_team"]["country"], match["home_team"]["goals"], match["away_team"]["goals"])
if len(events) > 0:
msg += " ; à la " + txt_event(events[0])
for n in DATAS.getChilds():
send_response(n["server"], Response(msg, channel=n["channel"]))
def is_int(s):
try:
int(s)
return True
except ValueError:
return False
def sort_events(teamA, teamB, eventA, eventB):
res = []
for e in eventA:
e["team"] = teamA
res.append(e)
for e in eventB:
e["team"] = teamB
res.append(e)
return sorted(res, key=lambda evt: int(evt["time"][0:2]), reverse=True)
def detail_event(evt):
if evt == "yellow-card":
return "carton jaune pour"
elif evt == "yellow-card-second":
return "second carton jaune pour"
elif evt == "red-card":
return "carton rouge pour"
elif evt == "substitution-in" or evt == "substitution-in halftime":
return "joueur entrant :"
elif evt == "substitution-out" or evt == "substitution-out halftime":
return "joueur sortant :"
elif evt == "goal":
return "but de"
elif evt == "goal-own":
return "but contre son camp de"
elif evt == "goal-penalty":
return "but (pénalty) de"
return evt + " par"
def txt_event(e):
return "%se minutes : %s %s (%s)" % (e["time"], detail_event(e["type_of_event"]), e["player"], e["team"]["code"])
def prettify(match):
matchdate_local = datetime.strptime(match["datetime"].replace(':', ''), "%Y-%m-%dT%H%M%S.%f%z")
matchdate = matchdate_local - (matchdate_local.utcoffset() - datetime.timedelta(hours=2))
if match["status"] == "future":
return ["Match à venir (%s) le %s : %s vs. %s" % (match["match_number"], matchdate.strftime("%A %d à %H:%M"), match["home_team"]["country"], match["away_team"]["country"])]
else:
msgs = list()
msg = ""
if match["status"] == "completed":
msg += "Match (%s) du %s terminé : " % (match["match_number"], matchdate.strftime("%A %d à %H:%M"))
else:
msg += "Match en cours (%s) depuis %d minutes : " % (match["match_number"], (datetime.now(matchdate.tzinfo) - matchdate_local).seconds / 60)
msg += "%s %d - %d %s" % (match["home_team"]["country"], match["home_team"]["goals"], match["away_team"]["goals"], match["away_team"]["country"])
events = sort_events(match["home_team"], match["away_team"], match["home_team_events"], match["away_team_events"])
if len(events) > 0:
msg += " ; dernière action, à la " + txt_event(events[0])
msgs.append(msg)
for e in events[1:]:
msgs.append("À la " + txt_event(e))
else:
msgs.append(msg)
return msgs
def is_valid(match):
return isinstance(match, dict) and (
isinstance(match.get('home_team'), dict) and
'goals' in match.get('home_team')
) and (
isinstance(match.get('away_team'), dict) and
'goals' in match.get('away_team')
) or isinstance(match.get('group_id'), int)
def get_match(url, matchid):
allm = get_matches(url)
for m in allm:
if int(m["match_number"]) == matchid:
return [ m ]
def get_matches(url):
try:
raw = urlopen(url)
except:
raise IRCException("requête invalide")
matches = json.loads(raw.read().decode())
for match in matches:
if is_valid(match):
yield match
@hook("cmd_hook", "worldcup")
def cmd_worldcup(msg):
res = Response(channel=msg.channel, nomore="No more match to display", count=" (%d more matches)")
nb = len(msg.cmds)
url = None
if nb == 2:
if msg.cmds[1] == "today" or msg.cmds[1] == "aujourd'hui":
url = "matches/today?by_date=ASC"
elif msg.cmds[1] == "tomorrow" or msg.cmds[1] == "demain":
url = "matches/tomorrow?by_date=ASC"
elif msg.cmds[1] == "all" or msg.cmds[1] == "tout" or msg.cmds[1] == "tous":
url = "matches/"
elif len(msg.cmds[1]) == 3:
url = "matches/country?fifa_code=%s&by_date=DESC" % msg.cmds[1]
elif is_int(msg.cmds[1]):
url = int(msg.cmds[1])
else:
raise IRCException("unrecognized request; choose between 'today', 'tomorrow', a FIFA country code or a match identifier")
if url is None:
url = "matches/current?by_date=ASC"
res.nomore = "There is no match currently"
if isinstance(url, int):
matches = get_match(API_URL % "matches/", url)
else:
matches = [m for m in get_matches(API_URL % url)]
for match in matches:
if len(matches) == 1:
res.count = " (%d more actions)"
for m in prettify(match):
res.append_message(m)
else:
res.append_message(prettify(match)[0])
return res