From 5ab179e47bacc9084eed1809b485c8e542fdb2ca 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: Tue, 28 Oct 2025 15:54:51 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BD=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8F?= =?UTF-8?q?=20Pregame=5FJSON,=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D0=B0=D1=8F?= =?UTF-8?q?=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D1=8F=D0=B5=D1=82=20Tea?= =?UTF-8?q?m=20Comparison?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- get_data_new.py | 182 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 168 insertions(+), 14 deletions(-) diff --git a/get_data_new.py b/get_data_new.py index d36b35a..ccc9692 100644 --- a/get_data_new.py +++ b/get_data_new.py @@ -36,6 +36,7 @@ TELEGRAM_CHAT_ID = -4803699526 # Глобальный лок для потокобезопасной записи JSON _write_lock = threading.Lock() +_pregame_done_for_game = {} # Карта всех ручек API, с интервалами опроса в секундах. URLS = [ @@ -495,7 +496,9 @@ def poll_game_live( with ThreadPoolExecutor(max_workers=5) as executor: while True: if stop_event.is_set(): - logger.info(f"[POLL] stop_event set -> break live poll for game {game_id}") + logger.info( + f"[POLL] stop_event set -> break live poll for game {game_id}" + ) break now = time.time() @@ -532,13 +535,17 @@ def poll_game_live( # data может быть: # {"status":"404","message":"Not found","result":None} # или {"status":"200","result":{"gameStatus":"Online", ...}} - ls_result = data.get("result") if isinstance(data, dict) else None + ls_result = ( + data.get("result") if isinstance(data, dict) else None + ) game_status = "" if isinstance(ls_result, dict): game_status = (ls_result.get("gameStatus") or "").lower() if game_status in ("resultconfirmed", "finished", "result"): - logger.info(f"[POLL] Game {game_id} finished by live-status") + logger.info( + f"[POLL] Game {game_id} finished by live-status" + ) game_finished = True except Exception as e: @@ -553,7 +560,7 @@ def poll_game_live( if game_finished: break - time.sleep(.5) + time.sleep(0.5) if stop_event.is_set(): logger.info( @@ -634,7 +641,9 @@ def build_render_state() -> dict: player["stats"] = stat # total по команде - team["total"] = box_team.get("total", {}) if isinstance(box_team, dict) else {} + team["total"] = ( + box_team.get("total", {}) if isinstance(box_team, dict) else {} + ) # периоды и общий счёт if isinstance(box_score_data["result"], dict): @@ -674,7 +683,9 @@ def render_loop(stop_event: threading.Event, out_name: str = "game") -> None: state = build_render_state() except Exception as build_err: # до тех пор, пока api_game не готов или битый — просто ждём - logger.debug(f"[RENDER_THREAD] build_render_state not ready: {build_err}") + logger.debug( + f"[RENDER_THREAD] build_render_state not ready: {build_err}" + ) time.sleep(0.2) continue @@ -1589,6 +1600,101 @@ def Team_Both_Stat(merged: dict) -> None: logger.error(f"Ошибка при обработке командной статистики: {e}", exc_info=True) +def Pregame_data_json(data: dict) -> None: + teams = [] + for data_team in (data["teamStats1"], data["teamStats2"]): + temp_team = { + "team": data_team["team"]["name"], + "games": data_team["games"], + "points": round( + (data_team["totalStats"]["points"] / data_team["games"]), 1 + ), + "points_2": round( + ( + data_team["totalStats"]["goal2"] + * 100 + / data_team["totalStats"]["shot2"] + ), + 1, + ), + "points_3": round( + ( + data_team["totalStats"]["goal3"] + * 100 + / data_team["totalStats"]["shot3"] + ), + 1, + ), + "points_23": round( + ( + data_team["totalStats"]["goal23"] + * 100 + / data_team["totalStats"]["shot23"] + ), + 1, + ), + "points_1": round( + ( + data_team["totalStats"]["goal1"] + * 100 + / data_team["totalStats"]["shot1"] + ), + 1, + ), + "assists": round( + (data_team["totalStats"]["assist"] / data_team["games"]), 1 + ), + "rebounds": round( + ( + ( + data_team["totalStats"]["defRebound"] + + data_team["totalStats"]["offRebound"] + ) + / data_team["games"] + ), + 1, + ), + "steals": round((data_team["totalStats"]["steal"] / data_team["games"]), 1), + "turnovers": round( + (data_team["totalStats"]["turnover"] / data_team["games"]), 1 + ), + "blocks": round( + (data_team["totalStats"]["blockShot"] / data_team["games"]), 1 + ), + "fouls": round((data_team["totalStats"]["foul"] / data_team["games"]), 1), + } + teams.append(temp_team) + atomic_write_json(teams, "team_comparison") + logger.info("Сохранил payload: team_comparison.json") + + +def Pregame_data(pregame_raw: dict, game_stub: dict) -> None: + """ + Обработка предматчевых данных (Pregame). + Вызывается один раз ДО начала матча, если матч сегодня. + + Вход: + pregame_raw -> ответ от /pregame (dict или None) + game_stub -> today_game["game"] из календаря (минимальная информация о матче) + """ + try: + out = { + "game": game_stub or {}, + "pregame": ( + pregame_raw.get("result") + if isinstance(pregame_raw, dict) + else pregame_raw + ), + "generatedAt": _now_iso(), + } + Pregame_data_json(out["pregame"]) + # сохраняем файл + # atomic_write_json(out["pregame"], "pregame") + # logger.info("Сохранил payload: pregame.json") + except Exception as e: + logger.error(f"Ошибка в Pregame_data: {e}", exc_info=True) + + def Scores_Quarter(merged: dict) -> None: """ Пишет счёт по четвертям и овертаймам в static/scores.json. @@ -1680,7 +1786,11 @@ def Standing_func( for item in items: comp = item.get("comp", {}) - comp_name = (comp.get("name") or "unknown_comp").replace(" ", "_").replace("|", "") + comp_name = ( + (comp.get("name") or "unknown_comp") + .replace(" ", "_") + .replace("|", "") + ) if item.get("standings"): standings_rows = item["standings"] @@ -1697,8 +1807,16 @@ def Standing_func( and "totalGoalPlus" in df.columns and "totalGoalMinus" in df.columns ): - tw = pd.to_numeric(df["totalWin"], errors="coerce").fillna(0).astype(int) - td = pd.to_numeric(df["totalDefeat"], errors="coerce").fillna(0).astype(int) + tw = ( + pd.to_numeric(df["totalWin"], errors="coerce") + .fillna(0) + .astype(int) + ) + td = ( + pd.to_numeric(df["totalDefeat"], errors="coerce") + .fillna(0) + .astype(int) + ) df["w_l"] = tw.astype(str) + " / " + td.astype(str) @@ -1723,8 +1841,16 @@ def Standing_func( df["procent"] = df.apply(calc_percent, axis=1) - tg_plus = pd.to_numeric(df["totalGoalPlus"], errors="coerce").fillna(0).astype(int) - tg_minus = pd.to_numeric(df["totalGoalMinus"], errors="coerce").fillna(0).astype(int) + tg_plus = ( + pd.to_numeric(df["totalGoalPlus"], errors="coerce") + .fillna(0) + .astype(int) + ) + tg_minus = ( + pd.to_numeric(df["totalGoalMinus"], errors="coerce") + .fillna(0) + .astype(int) + ) df["plus_minus"] = tg_plus - tg_minus @@ -1872,11 +1998,39 @@ def get_data_API( return "live_done" if phase == "upcoming": - # матч сегодня, но ещё не начался (Scheduled / NotStarted / Draft) - # не генерим финал, не спим до завтра logger.info( - f"Матч {game_id} сегодня, но ещё не начался (status={effective_status}). Ждём старт." + f"Матч {game_id} сегодня, но ещё не начался (status={effective_status}). Подготовка pregame." ) + + # дергаем pregame только один раз за матч + if not _pregame_done_for_game.get(game_id): + try: + pregame_raw = fetch_api_data( + session, + "pregame", + host=HOST, + league=league, + season=season, + game_id=game_id, + lang=lang, + ) + + Pregame_data( + pregame_raw=pregame_raw, + game_stub=today_game["game"], + ) + + _pregame_done_for_game[game_id] = True + logger.info( + f"[get_data_API] pregame данные собраны для game_id={game_id}" + ) + + except Exception as e: + logger.exception( + f"[get_data_API] ошибка при подготовке pregame для {game_id}: {e}" + ) + + # матч сегодня, ждём старта return "upcoming" if phase == "finished":