From 6752ca480822c2610c56e641f3847c294407a6e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AE=D1=80=D0=B8=D0=B9=20=D0=A7=D0=B5=D1=80=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE?= Date: Sat, 1 Nov 2025 12:40:02 +0300 Subject: [PATCH] =?UTF-8?q?host=20pro,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B2=20=D1=82=D0=B5=D0=BB=D0=B5=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D0=BC=D0=BC=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BE=20=D1=81=D1=82=D0=B0=D1=82=D1=83=D1=81?= =?UTF-8?q?=D0=B5=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=BE=D0=B2=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=20=D0=B2=205=20=D0=BC=D0=B8=D0=BD=D1=83?= =?UTF-8?q?=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- get_data.py | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/get_data.py b/get_data.py index 28a32e5..df47a3c 100644 --- a/get_data.py +++ b/get_data.py @@ -354,6 +354,11 @@ def results_consumer(): game["data"]["result"]["game"]["fullScore"] = payload["result"][ "fullScore" ] + game["data"]["result"]["game"]["score"] = payload["result"][ + "teams" + ][0]["total"]["points"] + ":" + payload["result"][ + "teams" + ][1]["total"]["points"] for team in game["data"]["result"]["teams"]: if team["teamNumber"] != 0: box_team = [ @@ -579,6 +584,112 @@ def extract_game_datetime(game_item: dict) -> datetime | None: except Exception: return None +def build_pretty_status_message(): + """ + Собирает одно красивое сообщение про текущее состояние онлайна. + Если game ещё нет — шлём хотя бы статусы источников. + """ + lines = [] + lines.append(f"🏀 {LEAGUE.upper()} • {TEAM}") + lines.append(f"📌 Game ID: {GAME_ID}") + lines.append(f"🕒 {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}") + + # сначала попробуем собрать нормальный game + game_wrap = latest_data.get("game") + has_game = False + if game_wrap: + game_data = game_wrap.get("data") or game_wrap + result = game_data.get("result") or {} + game_info = result.get("game") or {} + + + team1_name = game_data["team1"]["name"] + team2_name = game_data["team2"]["name"] + + score_now = game_info.get("score") or "" + full_score = game_info.get("fullScore") or "" + + lines.append(f"👥 {team1_name} vs {team2_name}") + if score_now: + lines.append(f"🔢 Score: {score_now}") + + if isinstance(full_score, str) and full_score: + quarters = full_score.split(",") + q_text = " | ".join( + f"Q{i+1} {q}" for i, q in enumerate(quarters) if q + ) + if q_text: + lines.append(f"🧱 By quarters: {q_text}") + + has_game = True + + # live-status отдельно + ls = latest_data.get("live-status", {}) + ls_raw = ls.get("data") or {} + ls_status = ( + ls_raw.get("status") + or ls_raw.get("gameStatus") + or ls_raw.get("state") + or "—" + ) + lines.append(f"🟢 LIVE status: {ls_status}") + + # добавим блок по источникам — это как раз “состояние запросов” + sort_order = ["game", "live-status", "box-score", "play-by-play"] + keys = [k for k in sort_order if k in latest_data] + sorted( + [k for k in latest_data if k not in sort_order] + ) + src_lines = [] + for k in keys: + d = latest_data.get(k) or {} + ts = d.get("ts", "—") + dat = d.get("data") + if isinstance(dat, dict) and "status" in dat: + st = dat["status"] + else: + st = dat + src_lines.append(f"• {k}: {st} ({ts})") + + if src_lines: + lines.append("📡 Sources:") + lines.extend(src_lines) + + # даже если game не успел — мы всё равно что-то вернём + return "\n".join(lines) + + +def status_broadcaster(): + """ + Если матч live — сразу шлём статус. + Потом — раз в 5 минут. + Если матч не live — ждём и проверяем снова. + """ + INTERVAL = 300 # 5 минут + last_text = None + first_live_sent = False + + while not stop_event.is_set(): + # если игра не идёт — спим по чуть-чуть и крутимся + if STATUS not in ("live", "live_soon"): + first_live_sent = False # чтобы при новом лайве снова сразу отправить + time.sleep(5) + continue + + # сюда попадаем только если live + text = build_pretty_status_message() + if text and text != last_text: + logger.info(text) + last_text = text + first_live_sent = True + + # после первого лайва ждём 5 минут, а до него — 10 секунд + wait_sec = INTERVAL if first_live_sent else 10 + for _ in range(wait_sec): + if stop_event.is_set(): + break + time.sleep(1) + + @asynccontextmanager async def lifespan(app: FastAPI): @@ -627,6 +738,12 @@ async def lifespan(app: FastAPI): daemon=True, ) thread_result_consumer.start() + + thread_status_broadcaster = threading.Thread( + target=status_broadcaster, + daemon=True, + ) + thread_status_broadcaster.start() # 5. Подготовим онлайн и офлайн наборы (как у тебя) threads_live = [ @@ -754,10 +871,11 @@ async def lifespan(app: FastAPI): yield # -------- shutdown -------- - stop_event.set() # завершить consumer + stop_event.set() stop_live_threads() stop_offline_threads() thread_result_consumer.join(timeout=1) + thread_status_broadcaster.join(timeout=1) app = FastAPI(lifespan=lifespan)