import json from flask import abort, render_template, jsonify, send_from_directory from app import app from app.config import SCOREBOARD_DATA_FILE from app.games import parse_games from app.playoff import today_meta from app.bracket_view import build_bracket_view from app.playoff_cache import ( day_n as compute_day_n, fetch_series, get_bracket, parse_series_id, record_start_date_if_missing, refresh_bracket, ) from app.series_view import build_series_view from datetime import datetime from zoneinfo import ZoneInfo _EASTERN = ZoneInfo("America/New_York") @app.route("/manifest.json") def manifest(): return send_from_directory(app.static_folder, "manifest.json") @app.route("/sw.js") def service_worker(): response = send_from_directory(app.static_folder, "sw.js") response.headers["Service-Worker-Allowed"] = "/" response.headers["Cache-Control"] = "no-cache" return response @app.route("/favicon.ico") def favicon(): return send_from_directory( app.static_folder, "icon-32x32.png", mimetype="image/png" ) @app.route("/") def index(): return render_template("index.html") @app.route("/scoreboard") def get_scoreboard(): try: with open(SCOREBOARD_DATA_FILE, "r") as json_file: scoreboard_data = json.load(json_file) except FileNotFoundError: return jsonify({"error": "Failed to retrieve scoreboard data. File not found."}) except json.JSONDecodeError: return jsonify( {"error": "Failed to retrieve scoreboard data. Invalid JSON format."} ) if scoreboard_data: raw_games = scoreboard_data.get("games", []) record_start_date_if_missing(raw_games) games = parse_games(scoreboard_data) n, total = compute_day_n() meta = today_meta(raw_games, day_n=n, day_total=total) pinned = [g for g in games if g.get("Pinned")] remaining = [g for g in games if not g.get("Pinned")] return jsonify( { "meta": meta, "pinned_games": pinned, "live_games": [ g for g in remaining if g["Game State"] == "LIVE" and not g["Intermission"] ], "intermission_games": [ g for g in remaining if g["Game State"] == "LIVE" and g["Intermission"] ], "pre_games": [g for g in remaining if g["Game State"] == "PRE"], "final_games": [g for g in remaining if g["Game State"] == "FINAL"], } ) else: return jsonify({"error": "Failed to retrieve scoreboard data"}) @app.route("/series/") def series_detail(series_id): if parse_series_id(series_id) is None: abort(404) payload = fetch_series(series_id) if payload is None: abort(404) view = build_series_view(series_id, payload) return render_template("series.html", series=view) @app.route("/bracket") def bracket(): year = datetime.now(_EASTERN).year payload, fetched_at = get_bracket(year) if payload is None: payload = refresh_bracket(year) if payload is None: abort(404) view = build_bracket_view(year, payload, fetched_at=fetched_at) return render_template("bracket.html", bracket=view)