diff --git a/feeds/mlb-feed/__pycache__/main.cpython-314.pyc b/feeds/mlb-feed/__pycache__/main.cpython-314.pyc new file mode 100644 index 000000000..ef0a03575 Binary files /dev/null and b/feeds/mlb-feed/__pycache__/main.cpython-314.pyc differ diff --git a/feeds/mlb-feed/concerto-mlb.service.txt b/feeds/mlb-feed/concerto-mlb.service.txt new file mode 100644 index 000000000..f4662cd7f --- /dev/null +++ b/feeds/mlb-feed/concerto-mlb.service.txt @@ -0,0 +1,13 @@ +[Unit] +Description=Concerto MLB Feed +After=network.target + +[Service] +Type=simple +WorkingDirectory=/path/to/python-mlb-feed +ExecStart=/path/to/python-mlb-feed/start.sh +Restart=always +User=YOUR_USERNAME + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/feeds/mlb-feed/main.py b/feeds/mlb-feed/main.py new file mode 100644 index 000000000..520dcbae7 --- /dev/null +++ b/feeds/mlb-feed/main.py @@ -0,0 +1,91 @@ +from typing import Dict, List +from fastapi import FastAPI +import requests +import datetime + +app = FastAPI() + + +MLB_SCHEDULE_URL = "https://statsapi.mlb.com/api/v1/schedule" + + +def format_game_line(game: dict) -> str: + teams = game.get("teams", {}) + away = teams.get("away", {}) + home = teams.get("home", {}) + + away_team = away.get("team", {}).get("name", "Away") + home_team = home.get("team", {}).get("name", "Home") + + away_score = away.get("score") + home_score = home.get("score") + + status = game.get("status", {}) + detailed_state = status.get("detailedState", "Scheduled") + abstract_state = status.get("abstractGameState", "Preview") + + game_datetime = game.get("gameDate") + display_time = "TBD" + + if game_datetime: + try: + dt = datetime.datetime.fromisoformat(game_datetime.replace("Z", "+00:00")) + display_time = dt.astimezone().strftime("%I:%M %p").lstrip("0") + except ValueError: + pass + + if abstract_state == "Final": + return f"FINAL: {away_team} {away_score}, {home_team} {home_score}" + elif abstract_state == "Live": + return f"LIVE: {away_team} {away_score}, {home_team} {home_score} ({detailed_state})" + else: + return f"{display_time}: {away_team} at {home_team}" + + +def get_mlb_games() -> List[str]: + today = datetime.datetime.now().strftime("%Y-%m-%d") + + response = requests.get( + MLB_SCHEDULE_URL, + params={ + "sportId": 1, + "date": today, + "hydrate": "linescore,team,flags", + }, + timeout=20, + ) + + data = response.json() + dates = data.get("dates", []) + if not dates: + return ["No MLB games scheduled today."] + + games = dates[0].get("games", []) + if not games: + return ["No MLB games scheduled today."] + + lines = [format_game_line(game) for game in games[:12]] + return lines + + +@app.get("/mlb.json") +def read_mlb_scores() -> List[Dict[str, str]] | Dict[str, str]: + now = datetime.datetime.now() + start = now.replace(hour=0, minute=0, second=0, microsecond=0) + end = now.replace(hour=23, minute=59, second=59, microsecond=999999) + + try: + game_lines = get_mlb_games() + except Exception as e: + return {"Error": "Response Failed", "info": str(e)} + + html = " | ".join(game_lines) + + return [{ + "name": "MLB Scores", + "type": "RichText", + "render_as": "html", + "start_time": start.strftime("%Y-%m-%dT%H:%M:%SZ"), + "end_time": end.strftime("%Y-%m-%dT%H:%M:%SZ"), + "text": html + }] \ No newline at end of file diff --git a/feeds/mlb-feed/requirements.txt b/feeds/mlb-feed/requirements.txt new file mode 100644 index 000000000..b07ade6ba --- /dev/null +++ b/feeds/mlb-feed/requirements.txt @@ -0,0 +1,2 @@ +fastapi[standard] +requests \ No newline at end of file diff --git a/feeds/mlb-feed/start.sh b/feeds/mlb-feed/start.sh new file mode 100644 index 000000000..3d35bb6b9 --- /dev/null +++ b/feeds/mlb-feed/start.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +. .venv/bin/activate +fastapi run --host 0.0.0.0 --port 43679 +deactivate \ No newline at end of file