Last active
February 6, 2022 04:34
-
-
Save jparise/f3142c58d3478ff1b236ee061f541724 to your computer and use it in GitHub Desktop.
Olympic Medal Standings for Vestaboard
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
#!/usr/bin/env python3 | |
"""Olympic Medal Standings for Vestaboard""" | |
# pip install beautifulsoup4 vesta | |
import argparse | |
import logging | |
import time | |
from collections import namedtuple | |
from typing import List | |
import requests | |
import vesta | |
from bs4 import BeautifulSoup | |
Team = namedtuple("Row", "country gold silver bronze total") | |
def get_standings(limit=5): | |
resp = requests.get( | |
"https://olympics.com/beijing-2022/olympic-games/en/results/all-sports/medal-standings.htm" | |
) | |
soup = BeautifulSoup(resp.text, "html.parser") | |
table = soup.find("table", id="medal-standing-table") | |
for row in table.find_all("tr", limit=limit + 1)[1:]: | |
cells = row.find_all("td") | |
yield Team( | |
country=cells[1].div["country"], | |
gold=int(cells[2].text.strip()), | |
silver=int(cells[3].text.strip()), | |
bronze=int(cells[4].text.strip()), | |
total=int(cells[5].text.strip()), | |
) | |
def render(standings) -> List[List[int]]: | |
chars = [ | |
vesta.encode_row(" {65} {69} {64} T "), | |
] | |
for i, team in enumerate(standings, start=1): | |
chars.append( | |
vesta.encode_row( | |
f" {i} {team.country:5} " | |
f"{team.gold:2} {team.silver:2} {team.bronze:2} {team.total:3}" | |
) | |
) | |
return chars | |
def main(args): | |
logging.basicConfig( | |
format="%(asctime)s %(levelname)s %(message)s", | |
level=logging.INFO, | |
) | |
client = vesta.Client(args.key, args.secret) | |
last = None | |
while True: | |
logging.info("Fetching latest standings") | |
try: | |
standings = tuple(get_standings()) | |
except IOError as e: | |
logging.error(e) | |
time.sleep(60) | |
continue | |
if standings != last: | |
logging.info( | |
"Publishing updated standings: %s", | |
" ".join(team.country for team in standings), | |
) | |
chars = render(standings) | |
if args.pprint: | |
vesta.pprint(chars) | |
try: | |
client.post_message(args.sub, chars) | |
except IOError as e: | |
logging.error(e) | |
time.sleep(60) | |
continue | |
last = standings | |
time.sleep(args.interval) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser(description=__doc__) | |
parser.add_argument("--key", required=True, help="API key") | |
parser.add_argument("--secret", required=True, help="API secret") | |
parser.add_argument("--sub", required=True, help="subscription ID") | |
parser.add_argument("--pprint", action="store_true", help="print the board") | |
parser.add_argument( | |
"--interval", type=int, default=10 * 60, help="update interval (seconds)" | |
) | |
args = parser.parse_args() | |
main(args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment