didier/functions/football.py

192 lines
6.1 KiB
Python
Raw Normal View History

2021-08-19 21:12:29 +02:00
from typing import Optional
2021-01-25 00:16:38 +01:00
from attr import dataclass, field
2021-08-19 20:35:22 +02:00
from datetime import datetime
from enum import Enum
2021-01-25 00:16:38 +01:00
from functions.timeFormatters import fromString
from functions.scrapers.sporza import getJPLMatches, getJPLTable
2021-09-03 18:53:05 +02:00
from functions.stringFormatters import leading_zero
2021-08-19 20:35:22 +02:00
import re
from requests import get
2021-01-25 00:16:38 +01:00
import tabulate
class Status(Enum):
AfterToday = "--:--"
NotStarted = "--:--"
2021-08-19 21:12:29 +02:00
Postponed = "--:--"
2021-01-25 00:16:38 +01:00
Over = "Einde"
HalfTime = "Rust"
@dataclass
class Match:
"""
Class representing a football match between two teams
"""
matchDict: dict
home: str = field(init=False)
homeScore: int = 0
away: str = field(init=False)
awayScore: int = 0
2021-08-19 21:12:29 +02:00
start: Optional[datetime] = field(init=False)
2021-01-25 00:16:38 +01:00
date: str = field(init=False)
weekDay: str = field(init=False)
status: Status = field(init=False)
def __attrs_post_init__(self):
"""
Parse class attributes out of a dictionary returned from an API request
"""
# The API isn't public, so every single game state is differently formatted
self.status = self._get_status(self.matchDict[Navigation.Status.value])
2021-01-25 00:16:38 +01:00
self.home = self.matchDict[Navigation.HomeTeam.value][Navigation.Name.value]
self.away = self.matchDict[Navigation.AwayTeam.value][Navigation.Name.value]
if self._has_started():
2021-01-25 00:16:38 +01:00
self.homeScore = self.matchDict[Navigation.HomeScore.value]
self.awayScore = self.matchDict[Navigation.AwayScore.value]
2021-08-19 21:12:29 +02:00
if "startDateTime" in self.matchDict:
self.start = fromString(self.matchDict["startDateTime"], formatString="%Y-%m-%dT%H:%M:%S.%f%z")
else:
self.start = None
self.date = self.start.strftime("%d/%m") if self.start is not None else "Uitgesteld"
self.weekDay = self._get_weekday() if self.start is not None else "??"
2021-01-25 00:16:38 +01:00
def _get_status(self, status: str):
2021-01-25 00:16:38 +01:00
"""
Gets the string representation for the status of this match
"""
# LiveTime only exists if the status is live
# Avoids KeyErrors
if status.lower() == "live":
# Half time
if Navigation.LiveMatchPhase.value in self.matchDict and \
2021-01-27 21:53:56 +01:00
self.matchDict[Navigation.LiveMatchPhase.value] == Navigation.HalfTime.value:
2021-01-25 00:16:38 +01:00
return Status.HalfTime.value
# Current time
return self.matchDict[Navigation.LiveTime.value]
# If no special status, pull it out of this dict
statusses: dict = {
"after_today": Status.AfterToday.value,
"not_started": Status.NotStarted.value,
2021-08-19 21:12:29 +02:00
"postponed": Status.Postponed.value,
2021-01-25 00:16:38 +01:00
"end": Status.Over.value
}
return statusses[status.lower()]
def _get_weekday(self):
2021-01-25 00:16:38 +01:00
"""
Gets the day of the week this match is played on
"""
day = self.start.weekday()
days = ["Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"]
return days[day]
def get_info(self):
2021-01-25 00:16:38 +01:00
"""
Returns a list of all the info of this class in order to create a table
"""
return [self.weekDay, self.date, self.home, self._get_score(), self.away, self.status]
2021-01-25 00:16:38 +01:00
def _get_score(self):
2021-01-25 00:16:38 +01:00
"""
Returns a string representing the scoreboard
"""
2021-08-19 21:12:29 +02:00
if self.start is None:
return "??"
2021-01-25 00:16:38 +01:00
# No score to show yet, show time when the match starts
if not self._has_started():
2021-09-03 18:53:05 +02:00
return "{}:{}".format(leading_zero(str(self.start.hour)), leading_zero(str(self.start.minute)))
2021-01-25 00:16:38 +01:00
return "{} - {}".format(self.homeScore, self.awayScore)
def _has_started(self):
2021-08-19 21:12:29 +02:00
return self.status not in [Status.AfterToday.value, Status.NotStarted.value, Status.Postponed.value]
2021-01-25 00:16:38 +01:00
class Navigation(Enum):
"""
Enum to navigate through the matchdict,
seeing as the API is private the keys of the dict could change every now and then
so this makes sure a key only has to be changed once.
"""
AwayTeam = "awayTeam"
HomeTeam = "homeTeam"
AwayScore = "awayScore"
HomeScore = "homeScore"
LiveTime = "liveTime"
LiveMatchPhase = "liveMatchPhase"
HalfTime = "HALF_TIME"
Status = "status"
Name = "name"
def get_matches(matchweek: int):
2021-01-25 00:16:38 +01:00
"""
2021-01-26 21:58:49 +01:00
Function that constructs the list of matches for a given matchweek
2021-01-25 00:16:38 +01:00
"""
current_day = getJPLMatches(matchweek)
# API request failed
if current_day is None:
2021-01-26 21:58:49 +01:00
return "Er ging iets fout. Probeer het later opnieuw."
2021-01-25 00:16:38 +01:00
matches = list(map(Match, current_day))
matches = list(map(lambda x: x.get_info(), matches))
2021-01-25 00:16:38 +01:00
header = "Jupiler Pro League - Speeldag {}".format(matchweek)
table = tabulate.tabulate(matches, headers=["Dag", "Datum", "Thuis", "Stand", "Uit", "Tijd"])
return "```{}\n\n{}```".format(header, table)
2021-01-26 21:58:49 +01:00
def get_table():
2021-01-26 21:58:49 +01:00
"""
Function that constructs the current table of the JPL
"""
rows = getJPLTable()
if rows is None:
return "Er ging iets fout. Probeer het later opnieuw."
2021-01-26 22:00:20 +01:00
# Format every row to work for Tabulate
formatted = [_format_row(row) for row in rows]
2021-01-26 21:58:49 +01:00
header = "Jupiler Pro League Klassement"
table = tabulate.tabulate(formatted, headers=["#", "Ploeg", "Punten", "M", "M+", "M-", "M=", "D+", "D-", "D+/-"])
2021-01-26 21:58:49 +01:00
return "```{}\n\n{}```".format(header, table)
def _format_row(row):
2021-01-26 21:58:49 +01:00
"""
Function that formats a row into a list for Tabulate to use
"""
2021-10-18 18:39:02 +02:00
tds = row.find_all("td")
tds.pop(1) # Relegation icon
tds.pop(1) # Copy of team name
scoresArray = list([td.renderContents().decode("utf-8") for td in tds])[:9]
2021-01-26 22:00:20 +01:00
2021-01-26 21:58:49 +01:00
# Insert the team name into the list
scoresArray.insert(1, row.find_all("a")[0].renderContents().decode("utf-8").split("<!--")[0])
2021-01-26 22:00:20 +01:00
2021-01-26 21:58:49 +01:00
return scoresArray
2021-08-19 20:35:22 +02:00
def get_jpl_code() -> int:
editions = get("https://api.sporza.be/web/soccer/competitions/48").json()["editions"]
newest_edition = editions[0]["_links"]["self"]["href"]
phase = get(newest_edition).json()["phases"][0]
phase_url = phase["_links"]["self"]["href"]
r = re.compile(r"\d+$")
match = re.search(r, phase_url)
return int(match[0])