Last active
November 26, 2022 13:42
-
-
Save randerzander/97bf2030f284d74feb67fa071dde7135 to your computer and use it in GitHub Desktop.
Terminal UI for displaying live college or nfl game status
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Game { | |
height: 3; | |
width: 50%; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from time import monotonic | |
from textual.app import App, ComposeResult | |
from textual.containers import Container | |
from textual.reactive import reactive | |
from textual.widgets import Button, Header, Footer, Static | |
import requests, json | |
class Game(Static): | |
def __init__(self, game) -> None: | |
t1 = game["competitors"][0] | |
t2 = game["competitors"][1] | |
title = f"{game['name'].replace(' at ', ' @ ')}: " | |
title = title + f"{game['fullStatus']['type']['detail']}" | |
# map team UID to team name for xreferincing who has the ball | |
possession = { | |
t1["uid"].split(":")[-1]: t1["name"], | |
t2["uid"].split(":")[-1]: t2["name"], | |
} | |
# ugly logic for prepending team name w/ "<>" if they have possession of the ball | |
t1_has_ball = "" | |
t2_has_ball = "" | |
has_ball = "" | |
if "possession" in game["situation"]: | |
pos = game["situation"]["possession"] | |
has_ball = possession[pos] | |
if t1["name"] == has_ball: | |
t1_has_ball = "<> " | |
elif t2["name"] == has_ball: | |
t2_has_ball = "<> " | |
desc = f"{t1_has_ball}{t1['abbreviation']}: {t1['score']}, " | |
desc = desc + f"{t2_has_ball}{t2['abbreviation']}: {t2['score']}\n" | |
self._title = title | |
self._desc = desc | |
super().__init__() | |
def compose(self) -> ComposeResult: | |
yield Static(self._title, id="title") | |
yield Static(self._desc, id="desc") | |
class FootballApp(App): | |
CSS_PATH = "football.css" | |
BINDINGS = [("u", "update_games", "Update")] | |
def action_update_games(self) -> None: | |
self.load_games() | |
def compose(self) -> ComposeResult: | |
yield Container(id="games") | |
def load_games(self): | |
league = "college-football" | |
url = "https://site.web.api.espn.com/apis/v2/scoreboard/header?sport=football&league=LEAGUE®ion=us&lang=en&contentorigin=espn&buyWindow=1m&showAirings=buy%2Clive%2Creplay&showZipLookup=true&tz=America%2FNew_York" | |
doc = json.loads(requests.get(url.replace("LEAGUE", league)).text) | |
games = doc["sports"][0]["leagues"][0]["events"] | |
# remove existing displayed game entries | |
[game.remove() for game in self.query("Game")] | |
# filter for only active games | |
for game in [game for game in games if game["status"] == "in"]: | |
self.query_one("#games", Container).mount(Game(game)) | |
print(f"Loaded {len(games)}") | |
if __name__ == "__main__": | |
app = FootballApp() | |
app.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment