From dcfcbb0958a9f7ea477d1f946410d7af5014f3ac 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: Fri, 24 Oct 2025 18:12:26 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D1=82?= =?UTF-8?q?=D1=83=D1=80=D0=BD=D0=B8=D1=80=D0=BD=D0=BE=D0=B9=20=D1=82=D0=B0?= =?UTF-8?q?=D0=B1=D0=BB=D0=B8=D1=86=D1=8B=20=D1=80=D0=B0=D0=B7=20=D0=B2=20?= =?UTF-8?q?10=20=D0=BC=D0=B8=D0=BD=D1=83=D1=82=20=D1=81=20=D1=81=D0=BE?= =?UTF-8?q?=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=B2=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=B3=D1=80=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- get_data.py | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/get_data.py b/get_data.py index d26226e..f7b1ebe 100644 --- a/get_data.py +++ b/get_data.py @@ -28,6 +28,7 @@ import time import json import argparse import logging +import pandas as pd import logging.config import threading import concurrent.futures @@ -40,6 +41,7 @@ from zoneinfo import ZoneInfo from typing import Any, Dict, List import tempfile from pathlib import Path +from threading import Event, Lock import requests @@ -78,11 +80,13 @@ URL_GAME = "https://{host}/api/abc/games/game?Id={game_id}&lang={lang}" URL_BOX_SCORE = "https://{host}/api/abc/games/box-score?Id={game_id}&lang={lang}" URL_PLAY_BY_PLAY = "https://{host}/api/abc/games/play-by-play?Id={game_id}&lang={lang}" URL_LIVE_STATUS = "https://{host}/api/abc/games/live-status?Id={game_id}&lang={lang}" +URL_STANDINGS = "https://{host}/api/abc/comps/actual-standings?tag={league}&season={season}&lang={lang}" # Интервалы опроса STATUS_CHECK_INTERVAL_SEC = 60 # проверять "онлайн?" раз в минуту ONLINE_FETCH_INTERVAL_SEC = 1 # когда матч онлайн, дергать три запроса каждую секунду POLL_INTERVAL_OFFLINE_SEC = 300 # резервный интервал сна при ошибках/до старта +TIMEOUT_DATA_OFF = 600 TELEGRAM_BOT_TOKEN = "7639240596:AAH0YtdQoWZSC-_R_EW4wKAHHNLIA0F_ARY" # TELEGRAM_CHAT_ID = 228977654 @@ -1499,6 +1503,76 @@ def status_online_func(merged: dict, *, out_dir: str = "static") -> None: return None +def Standing_func(league, season, lang, stop_event: threading.Event, out_dir: str = "static") -> None: + logger.info("START making json for standings") + while not stop_event.is_set(): + try: + url = URL_STANDINGS.format(host=HOST, league=league, season=season, lang=lang) + data_standings = fetch_json(url) + + if data_standings and "items" in data_standings and data_standings["items"]: + standings_temp = data_standings["items"] + for item in standings_temp: + if "standings" in item and item["standings"] != []: + standings_temp = item["standings"] + df = pd.json_normalize(standings_temp) + del df["scores"] + if not df["totalWin"].isna().all(): + df["w_l"] = ( + df["totalWin"].astype(str) + + " / " + + df["totalDefeat"].astype(str) + ) + df["procent"] = df.apply( + lambda row: ( + 0 + if row["w_l"] == "0 / 0" + or row["totalGames"] == 0 + or pd.isna(row["totalWin"]) + else round( + row["totalWin"] * 100 / row["totalGames"] + + 0.000005 + ) + ), + axis=1, + ) + df["plus_minus"] = ( + df["totalGoalPlus"] - df["totalGoalMinus"] + ) + filepath = os.path.join( + out_dir, + f"standings_{league}_{item['comp']['name'].replace(' ', '_')}.json", + ) + + + df.to_json( + filepath, + orient="records", + force_ascii=False, + indent=4, + ) + logger.info("Standings data saved successfully.") + elif "playoffPairs" in item and item["playoffPairs"] != []: + standings_temp = item["playoffPairs"] + df = pd.json_normalize(standings_temp) + filepath = os.path.join( + out_dir, + f"standings_{league}_{item['comp']['name'].replace(' ', '_')}.json", + ) + df.to_json( + filepath, + orient="records", + force_ascii=False, + indent=4, + ) + logger.info("Standings data saved successfully.") + except Exception as e: + logger.warning(f"Ошибка в турнирном положении: {e}") + + stop_event.wait(TIMEOUT_DATA_OFF) + + + # ========================== # ---- ДОМЕННАЯ ЛОГИКА # ========================== @@ -1903,6 +1977,10 @@ def main(): # 1) Узнать последний сезон season = get_last_season_or_die(league, args.lang) + + + + # 2) Получить расписание для команды team_games = get_team_schedule_or_die(league, season, team, args.lang) @@ -1972,6 +2050,17 @@ def main(): daemon=True, ) rollover_thread.start() + + # 1.1) турнирная таблица + threads = [ + threading.Thread( + target=Standing_func, + args=(league, season, args.lang, stop_event), + name="standings",)] + + for t in threads: + t.start() + logger.debug(f"Поток {t.name} запущен.") # Держим главный поток живым try: @@ -1979,6 +2068,10 @@ def main(): time.sleep(1) except KeyboardInterrupt: logger.info("Завершение по Ctrl+C…") + stop_event.set() + for t in threads: + t.join() + logger.debug(f"Поток {t.name} завершён.") finally: stop_event.set() monitor_mgr.stop()