Compare commits
2 Commits
cf06adbfab
...
834ba36d74
| Author | SHA1 | Date | |
|---|---|---|---|
| 834ba36d74 | |||
| 95be10629e |
362
get_data.py
362
get_data.py
@@ -95,6 +95,12 @@ GAME_TODAY = False # флаг: игра сегодня
|
|||||||
GAME_SOON = False # флаг: игра сегодня и скоро (<1 часа)
|
GAME_SOON = False # флаг: игра сегодня и скоро (<1 часа)
|
||||||
OFFLINE_SWITCH_AT = None # timestamp, когда надо уйти в оффлайн
|
OFFLINE_SWITCH_AT = None # timestamp, когда надо уйти в оффлайн
|
||||||
OFFLINE_DELAY_SEC = 600 # 10 минут
|
OFFLINE_DELAY_SEC = 600 # 10 минут
|
||||||
|
SLEEP_NOTICE_SENT = False # 👈 чтобы не слать уведомление повторно
|
||||||
|
# --- preload lock ---
|
||||||
|
PRELOAD_LOCK = False # когда True — consumer будет принимать только preloaded game
|
||||||
|
PRELOADED_GAME_ID = None # ID матча, который мы держим «тёплым»
|
||||||
|
PRELOAD_HOLD_UNTIL = None # timestamp, до какого момента держим (T-1:15)
|
||||||
|
|
||||||
|
|
||||||
# общая очередь
|
# общая очередь
|
||||||
results_q = queue.Queue()
|
results_q = queue.Queue()
|
||||||
@@ -137,6 +143,7 @@ def start_offline_threads(season, game_id):
|
|||||||
return
|
return
|
||||||
|
|
||||||
stop_live_threads()
|
stop_live_threads()
|
||||||
|
stop_offline_threads()
|
||||||
logger.info("[threads] switching to OFFLINE mode ...")
|
logger.info("[threads] switching to OFFLINE mode ...")
|
||||||
# 🔹 очищаем latest_data безопасно, чтобы не ломать структуру
|
# 🔹 очищаем latest_data безопасно, чтобы не ломать структуру
|
||||||
keep_keys = {
|
keep_keys = {
|
||||||
@@ -165,6 +172,34 @@ def start_offline_threads(season, game_id):
|
|||||||
),
|
),
|
||||||
daemon=True,
|
daemon=True,
|
||||||
),
|
),
|
||||||
|
threading.Thread(
|
||||||
|
target=get_data_from_API,
|
||||||
|
args=(
|
||||||
|
"pregame-full-stats",
|
||||||
|
URLS["pregame-full-stats"].format(
|
||||||
|
host=HOST, league=LEAGUE, season=season, game_id=game_id, lang=LANG
|
||||||
|
),
|
||||||
|
600,
|
||||||
|
stop_event_offline,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
daemon=True,
|
||||||
|
),
|
||||||
|
threading.Thread(
|
||||||
|
target=get_data_from_API,
|
||||||
|
args=(
|
||||||
|
"actual-standings",
|
||||||
|
URLS["actual-standings"].format(
|
||||||
|
host=HOST, league=LEAGUE, season=season, lang=LANG
|
||||||
|
),
|
||||||
|
600,
|
||||||
|
stop_event_offline,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
daemon=True,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
for t in threads_offline:
|
for t in threads_offline:
|
||||||
t.start()
|
t.start()
|
||||||
@@ -300,6 +335,7 @@ def stop_live_threads():
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.info("[threads] LIVE threads stopped")
|
logger.info("[threads] LIVE threads stopped")
|
||||||
|
CURRENT_THREADS_MODE = None # 👈 сбрасываем режим
|
||||||
|
|
||||||
|
|
||||||
def stop_offline_threads():
|
def stop_offline_threads():
|
||||||
@@ -311,6 +347,7 @@ def stop_offline_threads():
|
|||||||
for t in threads_offline:
|
for t in threads_offline:
|
||||||
t.join(timeout=1)
|
t.join(timeout=1)
|
||||||
threads_offline = []
|
threads_offline = []
|
||||||
|
CURRENT_THREADS_MODE = None # 👈 сбрасываем режим
|
||||||
logger.info("[threads] OFFLINE threads stopped")
|
logger.info("[threads] OFFLINE threads stopped")
|
||||||
|
|
||||||
|
|
||||||
@@ -429,8 +466,17 @@ def results_consumer():
|
|||||||
incoming_status = payload.get("status") # может быть None
|
incoming_status = payload.get("status") # может быть None
|
||||||
# print(source, incoming_status)
|
# print(source, incoming_status)
|
||||||
if source == "game":
|
if source == "game":
|
||||||
# обработка ТОЛЬКО в спец-ветке ниже
|
# принимаем ТОЛЬКО тот game_id, который держим в PRELOAD_LOCK
|
||||||
pass
|
try:
|
||||||
|
if PRELOAD_LOCK:
|
||||||
|
incoming_gid = extract_game_id_from_payload(payload)
|
||||||
|
if not incoming_gid or str(incoming_gid) != str(PRELOADED_GAME_ID):
|
||||||
|
logger.debug(
|
||||||
|
f"results_consumer: skip game (gid={incoming_gid}) due to PRELOAD_LOCK; keep {PRELOADED_GAME_ID}"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
except Exception as _e:
|
||||||
|
logger.debug(f"results_consumer: preload lock check error: {_e}")
|
||||||
else:
|
else:
|
||||||
latest_data[source] = {
|
latest_data[source] = {
|
||||||
"ts": msg["ts"],
|
"ts": msg["ts"],
|
||||||
@@ -735,8 +781,9 @@ def build_pretty_status_message():
|
|||||||
Если game ещё нет — шлём хотя бы статусы источников.
|
Если game ещё нет — шлём хотя бы статусы источников.
|
||||||
"""
|
"""
|
||||||
lines = []
|
lines = []
|
||||||
|
cgid = get_cached_game_id()
|
||||||
lines.append(f"🏀 <b>{LEAGUE.upper()}</b> • {TEAM}")
|
lines.append(f"🏀 <b>{LEAGUE.upper()}</b> • {TEAM}")
|
||||||
lines.append(f"📌 Game ID: <code>{GAME_ID}</code>")
|
lines.append(f"📌 Game ID: <code>{cgid or GAME_ID}</code>")
|
||||||
lines.append(f"🕒 {GAME_START_DT}")
|
lines.append(f"🕒 {GAME_START_DT}")
|
||||||
|
|
||||||
# сначала попробуем собрать нормальный game
|
# сначала попробуем собрать нормальный game
|
||||||
@@ -869,42 +916,233 @@ def status_broadcaster():
|
|||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_cached_game_id() -> str | None:
|
||||||
|
game = latest_data.get("game")
|
||||||
|
if not game:
|
||||||
|
return None
|
||||||
|
payload = game.get("data", game)
|
||||||
|
if not isinstance(payload, dict):
|
||||||
|
return None
|
||||||
|
# структура может быть {"data":{"result":{...}}} или {"result":{...}}
|
||||||
|
result = (
|
||||||
|
payload.get("data", {}).get("result")
|
||||||
|
if "data" in payload else payload.get("result")
|
||||||
|
)
|
||||||
|
if not isinstance(result, dict):
|
||||||
|
return None
|
||||||
|
g = result.get("game")
|
||||||
|
if isinstance(g, dict):
|
||||||
|
return g.get("id")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def extract_game_id_from_payload(payload: dict) -> str | None:
|
||||||
|
if not isinstance(payload, dict):
|
||||||
|
return None
|
||||||
|
root = payload.get("data") if isinstance(payload.get("data"), dict) else payload
|
||||||
|
res = root.get("result") if isinstance(root.get("result"), dict) else None
|
||||||
|
if not isinstance(res, dict):
|
||||||
|
return None
|
||||||
|
g = res.get("game")
|
||||||
|
if isinstance(g, dict):
|
||||||
|
return g.get("id")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def start_offline_prevgame(season, prev_game_id: str):
|
||||||
|
"""
|
||||||
|
Специальный оффлайн для ПРЕДЫДУЩЕЙ игры:
|
||||||
|
- гасит любые текущие треды
|
||||||
|
- запускает только 'game' для prev_game_id
|
||||||
|
- НЕ останавливается после первого 'ok' (stop_after_success=False)
|
||||||
|
"""
|
||||||
|
global threads_offline, CURRENT_THREADS_MODE, stop_event_offline, latest_data
|
||||||
|
|
||||||
|
# всегда переключаемся чисто
|
||||||
|
stop_live_threads()
|
||||||
|
stop_offline_threads()
|
||||||
|
|
||||||
|
logger.info("[threads] switching to OFFLINE mode (previous game) ...")
|
||||||
|
|
||||||
|
# оставим только полезные ключи
|
||||||
|
keep_keys = {"game", "pregame", "pregame-full-stats", "actual-standings", "calendar"}
|
||||||
|
for key in list(latest_data.keys()):
|
||||||
|
if key not in keep_keys:
|
||||||
|
del latest_data[key]
|
||||||
|
|
||||||
|
stop_event_offline.clear()
|
||||||
|
threads_offline = [
|
||||||
|
threading.Thread(
|
||||||
|
target=get_data_from_API,
|
||||||
|
args=(
|
||||||
|
"game",
|
||||||
|
URLS["game"].format(host=HOST, game_id=prev_game_id, lang=LANG),
|
||||||
|
300, # редкий опрос
|
||||||
|
stop_event_offline,
|
||||||
|
False, # stop_when_live
|
||||||
|
False, # ✅ stop_after_success=False (держим тред)
|
||||||
|
),
|
||||||
|
daemon=True,
|
||||||
|
),
|
||||||
|
threading.Thread(
|
||||||
|
target=get_data_from_API,
|
||||||
|
args=(
|
||||||
|
"pregame-full-stats",
|
||||||
|
URLS["pregame-full-stats"].format(
|
||||||
|
host=HOST, league=LEAGUE, season=season, game_id=prev_game_id, lang=LANG
|
||||||
|
),
|
||||||
|
600,
|
||||||
|
stop_event_offline,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
daemon=True,
|
||||||
|
),
|
||||||
|
threading.Thread(
|
||||||
|
target=get_data_from_API,
|
||||||
|
args=(
|
||||||
|
"actual-standings",
|
||||||
|
URLS["actual-standings"].format(
|
||||||
|
host=HOST, league=LEAGUE, season=season, lang=LANG
|
||||||
|
),
|
||||||
|
600,
|
||||||
|
stop_event_offline,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
daemon=True,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
for t in threads_offline:
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
CURRENT_THREADS_MODE = "offline"
|
||||||
|
logger.info(f"[threads] OFFLINE prev-game thread started for {prev_game_id}")
|
||||||
|
|
||||||
|
|
||||||
def start_prestart_watcher(game_dt: datetime | None):
|
def start_prestart_watcher(game_dt: datetime | None):
|
||||||
"""
|
"""
|
||||||
Следит за временем начала игры.
|
Логика на день игры:
|
||||||
Как только до матча остаётся <= 1ч10м — включает live-треды.
|
1) Немедленно подгружаем ДАННЫЕ ПРОШЛОГО МАТЧА (один раз, оффлайн-поток 'game'),
|
||||||
Работает только для "игра сегодня".
|
чтобы программа имела данные до старта.
|
||||||
|
2) Ровно за 1:15 до начала — СБРАСЫВАЕМ эти данные (останавливаем оффлайн, чистим latest_data).
|
||||||
|
3) Ровно за 1:10 до начала — ВКЛЮЧАЕМ LIVE-треды.
|
||||||
"""
|
"""
|
||||||
if not game_dt:
|
if not game_dt:
|
||||||
return # нечего ждать
|
return
|
||||||
|
|
||||||
|
# разовое уведомление о "спячке"
|
||||||
|
global SLEEP_NOTICE_SENT, STATUS, SEASON, GAME_ID
|
||||||
|
now = datetime.now()
|
||||||
|
if not SLEEP_NOTICE_SENT and game_dt > now:
|
||||||
|
logger.info(
|
||||||
|
"🛌 Тред ушёл в спячку до начала игры.\n"
|
||||||
|
f"⏰ Матч начинается сегодня в {game_dt.strftime('%H:%M')}."
|
||||||
|
)
|
||||||
|
SLEEP_NOTICE_SENT = True
|
||||||
|
|
||||||
def _runner():
|
def _runner():
|
||||||
|
from datetime import time as dtime # для резервного парсинга времени
|
||||||
global STATUS
|
global STATUS
|
||||||
# за сколько включать live
|
|
||||||
lead = timedelta(hours=1, minutes=10)
|
|
||||||
switch_at = game_dt - lead
|
|
||||||
|
|
||||||
|
PRELOAD_LEAD = timedelta(hours=1, minutes=15) # T-1:15 → сброс
|
||||||
|
LIVE_LEAD = timedelta(hours=1, minutes=10) # T-1:10 → live
|
||||||
|
RESET_AT = game_dt - PRELOAD_LEAD
|
||||||
|
LIVE_AT = game_dt - LIVE_LEAD
|
||||||
|
PRELOAD_MAXWAIT_SEC = 180 # ждём до 3 мин готовности full game при предзагрузке
|
||||||
|
|
||||||
|
did_preload = False
|
||||||
|
did_reset = False
|
||||||
|
did_live = False
|
||||||
|
|
||||||
|
# --- вспомогательное: поиск предыдущей игры команды ДО сегодняшнего матча ---
|
||||||
|
def _find_prev_game_id(calendar_json: dict, cutoff_dt: datetime) -> tuple[str | None, datetime | None]:
|
||||||
|
items = get_items(calendar_json) or []
|
||||||
|
prev_id, prev_dt = None, None
|
||||||
|
team_norm = (TEAM or "").strip().casefold()
|
||||||
|
for g in reversed(items):
|
||||||
|
try:
|
||||||
|
t1 = (g["team1"]["name"] or "").strip().casefold()
|
||||||
|
t2 = (g["team2"]["name"] or "").strip().casefold()
|
||||||
|
if team_norm not in (t1, t2):
|
||||||
|
continue
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
gdt = extract_game_datetime(g)
|
||||||
|
if not gdt:
|
||||||
|
try:
|
||||||
|
gd = datetime.strptime(g["game"]["localDate"], "%d.%m.%Y").date()
|
||||||
|
gdt = datetime.combine(gd, dtime(0, 0))
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
if gdt < cutoff_dt:
|
||||||
|
prev_id, prev_dt = g["game"]["id"], gdt
|
||||||
|
break
|
||||||
|
return prev_id, prev_dt
|
||||||
|
|
||||||
|
# --- Шаг 1: сразу включаем оффлайн по ПРЕДЫДУЩЕЙ игре и держим до T-1:15 ---
|
||||||
|
try:
|
||||||
|
now = datetime.now()
|
||||||
|
if now < RESET_AT:
|
||||||
|
calendar_resp = requests.get(
|
||||||
|
URLS["calendar"].format(host=HOST, league=LEAGUE, season=SEASON, lang=LANG),
|
||||||
|
timeout=6
|
||||||
|
).json()
|
||||||
|
prev_game_id, prev_game_dt = _find_prev_game_id(calendar_resp, game_dt)
|
||||||
|
if prev_game_id and str(prev_game_id) != str(GAME_ID):
|
||||||
|
logger.info(f"[preload] старт оффлайна по предыдущей игре {prev_game_id} ({prev_game_dt})")
|
||||||
|
|
||||||
|
# включаем «замок», чтобы consumer принимал только старую игру
|
||||||
|
globals()["PRELOAD_LOCK"] = True
|
||||||
|
globals()["PRELOADED_GAME_ID"] = str(prev_game_id)
|
||||||
|
globals()["PRELOAD_HOLD_UNTIL"] = RESET_AT.timestamp()
|
||||||
|
|
||||||
|
# поднимаем один оффлайн-тред по старой игре (без stop_after_success)
|
||||||
|
start_offline_prevgame(SEASON, prev_game_id)
|
||||||
|
did_preload = True
|
||||||
|
else:
|
||||||
|
logger.warning("[preload] предыдущая игра не найдена — пропускаем")
|
||||||
|
else:
|
||||||
|
logger.info("[preload] уже поздно для предзагрузки (прошло T-1:15) — пропуск")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"[preload] ошибка предзагрузки прошлой игры: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Основной цикл ожидания контрольных моментов ---
|
||||||
while not stop_event.is_set():
|
while not stop_event.is_set():
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
|
|
||||||
# если игра уже live/finished — не мешаем
|
# если матч уже в другом конечном состоянии — выходим
|
||||||
if STATUS in ("live", "finished", "finished_wait", "finished_today"):
|
if STATUS in ("live", "finished", "finished_wait", "finished_today"):
|
||||||
break
|
break
|
||||||
|
|
||||||
# если время подошло — включаем live и выходим
|
# Шаг 2: ровно T-1:15 — сбрасываем предзагруженные данные
|
||||||
if now >= switch_at:
|
if not did_reset and now >= RESET_AT:
|
||||||
|
logger.info(f"[reset] {now:%H:%M:%S} → T-1:15: сбрасываем предзагруженные данные")
|
||||||
|
try:
|
||||||
|
stop_offline_threads() # на всякий
|
||||||
|
latest_data.clear() # полный сброс кэша
|
||||||
|
# снять замок предзагрузки
|
||||||
|
globals()["PRELOAD_LOCK"] = False
|
||||||
|
globals()["PRELOADED_GAME_ID"] = None
|
||||||
|
globals()["PRELOAD_HOLD_UNTIL"] = None
|
||||||
|
|
||||||
|
logger.info("[reset] latest_data очищен; ждём T-1:10 для запуска live")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"[reset] ошибка при очистке: {e}")
|
||||||
|
did_reset = True
|
||||||
|
|
||||||
|
# Шаг 3: T-1:10 — включаем live-треды
|
||||||
|
if not did_live and now >= LIVE_AT:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"[prestart] it's {now}, game at {game_dt}, enabling LIVE threads (1h10m rule)"
|
f"[prestart] {now:%H:%M:%S}, игра в {game_dt:%H:%M}, включаем LIVE threads по правилу T-1:10"
|
||||||
)
|
)
|
||||||
STATUS = "live_soon"
|
STATUS = "live_soon"
|
||||||
# сначала гасим оффлайн, если он крутится
|
stop_offline_threads() # на всякий случай
|
||||||
stop_offline_threads()
|
|
||||||
# а потом включаем live
|
|
||||||
start_live_threads(SEASON, GAME_ID)
|
start_live_threads(SEASON, GAME_ID)
|
||||||
|
did_live = True
|
||||||
break
|
break
|
||||||
|
|
||||||
# иначе спим немного и проверяем снова
|
time.sleep(15)
|
||||||
time.sleep(30) # можно 15–60 сек
|
|
||||||
|
|
||||||
t = threading.Thread(target=_runner, daemon=True)
|
t = threading.Thread(target=_runner, daemon=True)
|
||||||
t.start()
|
t.start()
|
||||||
@@ -986,10 +1224,10 @@ async def lifespan(app: FastAPI):
|
|||||||
start_live_threads(SEASON, GAME_ID)
|
start_live_threads(SEASON, GAME_ID)
|
||||||
else:
|
else:
|
||||||
STATUS = "today_not_started"
|
STATUS = "today_not_started"
|
||||||
start_offline_threads(SEASON, GAME_ID)
|
# start_offline_threads(SEASON, GAME_ID)
|
||||||
else:
|
else:
|
||||||
STATUS = "today_not_started"
|
STATUS = "today_not_started"
|
||||||
start_offline_threads(SEASON, GAME_ID)
|
# start_offline_threads(SEASON, GAME_ID)
|
||||||
|
|
||||||
elif cal_status == "Online":
|
elif cal_status == "Online":
|
||||||
STATUS = "live"
|
STATUS = "live"
|
||||||
@@ -1063,16 +1301,54 @@ async def top_team2():
|
|||||||
return await top_sorted_team(data)
|
return await top_sorted_team(data)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/started_team1")
|
def _b(v) -> bool:
|
||||||
async def started_team1():
|
if isinstance(v, bool): return v
|
||||||
data = await team("team1")
|
if isinstance(v, (int, float)): return v != 0
|
||||||
return await started_team(data)
|
if isinstance(v, str): return v.strip().lower() in ("1","true","yes","on")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _placeholders(n=5):
|
||||||
|
return [{"NameGFX":"", "Name1GFX":"", "Name2GFX":"", "isOnCourt":False, "num":"", } for _ in range(n)]
|
||||||
|
|
||||||
|
@app.get("/started_team1")
|
||||||
|
async def started_team1(sort_by: str = None):
|
||||||
|
data = await team("team1")
|
||||||
|
players = await started_team(data) or []
|
||||||
|
|
||||||
|
# нормализуем флаги
|
||||||
|
for p in players:
|
||||||
|
p["isStart"] = _b(p.get("isStart", False))
|
||||||
|
p["isOnCourt"] = _b(p.get("isOnCourt", False))
|
||||||
|
|
||||||
|
if sort_by and sort_by.strip().lower() == "isstart":
|
||||||
|
starters = [p for p in players if p["isStart"]]
|
||||||
|
return starters[:5] if starters else _placeholders(5)
|
||||||
|
|
||||||
|
if sort_by and sort_by.strip().lower() == "isoncourt":
|
||||||
|
on_court = [p for p in players if p["isOnCourt"]]
|
||||||
|
return on_court[:5] if on_court else _placeholders(5)
|
||||||
|
|
||||||
|
# дефолт — без фильтра, как раньше
|
||||||
|
return players
|
||||||
|
|
||||||
@app.get("/started_team2")
|
@app.get("/started_team2")
|
||||||
async def started_team2():
|
async def started_team2(sort_by: str = None):
|
||||||
data = await team("team2")
|
data = await team("team2")
|
||||||
return await started_team(data)
|
players = await started_team(data) or []
|
||||||
|
|
||||||
|
for p in players:
|
||||||
|
p["isStart"] = _b(p.get("isStart", False))
|
||||||
|
p["isOnCourt"] = _b(p.get("isOnCourt", False))
|
||||||
|
|
||||||
|
if sort_by and sort_by.strip().lower() == "isstart":
|
||||||
|
starters = [p for p in players if p["isStart"]]
|
||||||
|
return starters[:5] if starters else _placeholders(5)
|
||||||
|
|
||||||
|
if sort_by and sort_by.strip().lower() == "isoncourt":
|
||||||
|
on_court = [p for p in players if p["isOnCourt"]]
|
||||||
|
return on_court[:5] if on_court else _placeholders(5)
|
||||||
|
|
||||||
|
return players
|
||||||
|
|
||||||
|
|
||||||
@app.get("/game")
|
@app.get("/game")
|
||||||
@@ -1108,10 +1384,14 @@ async def status(request: Request):
|
|||||||
sorted_keys = [k for k in sort_order if k in latest_data] + sorted(
|
sorted_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]
|
[k for k in latest_data if k not in sort_order]
|
||||||
)
|
)
|
||||||
|
cached_game_id = get_cached_game_id() or GAME_ID
|
||||||
|
note = ""
|
||||||
|
if cached_game_id and GAME_ID and str(cached_game_id) != str(GAME_ID):
|
||||||
|
note = f' <span style="color:#ffb84d;">(предзагружены данные прошлой игры)</span>'
|
||||||
data = {
|
data = {
|
||||||
"league": LEAGUE,
|
"league": LEAGUE,
|
||||||
"team": TEAM,
|
"team": TEAM,
|
||||||
"game_id": GAME_ID,
|
"game_id": cached_game_id,
|
||||||
"game_status": STATUS,
|
"game_status": STATUS,
|
||||||
"statuses": [
|
"statuses": [
|
||||||
{
|
{
|
||||||
@@ -1139,7 +1419,7 @@ async def status(request: Request):
|
|||||||
league=LEAGUE,
|
league=LEAGUE,
|
||||||
season=SEASON,
|
season=SEASON,
|
||||||
lang=LANG,
|
lang=LANG,
|
||||||
game_id=GAME_ID,
|
game_id=cached_game_id,
|
||||||
),
|
),
|
||||||
"color": color_for_status(
|
"color": color_for_status(
|
||||||
latest_data[item]["data"]["status"]
|
latest_data[item]["data"]["status"]
|
||||||
@@ -1223,7 +1503,7 @@ async def status(request: Request):
|
|||||||
<div class="header-info">
|
<div class="header-info">
|
||||||
<p><b>League:</b> {LEAGUE}</p>
|
<p><b>League:</b> {LEAGUE}</p>
|
||||||
<p><b>Team:</b> {TEAM}</p>
|
<p><b>Team:</b> {TEAM}</p>
|
||||||
<p><b>Game ID:</b> {GAME_ID}</p>
|
<p><b>Game ID:</b> {cached_game_id}{note}</p>
|
||||||
<p><b>Game Status:</b> <span class="{gs_class}">{gs_text}</span></p>
|
<p><b>Game Status:</b> <span class="{gs_class}">{gs_text}</span></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1851,15 +2131,15 @@ async def team(who: str):
|
|||||||
|
|
||||||
|
|
||||||
async def started_team(data):
|
async def started_team(data):
|
||||||
started_team = sorted(
|
# started_team = sorted(
|
||||||
(
|
# (
|
||||||
p
|
# p
|
||||||
for p in data
|
# for p in data
|
||||||
if p.get("startRole") == "Player" and p.get("isOnCourt") is True
|
# if p.get("startRole") == "Player" and p.get("isStart") is True
|
||||||
),
|
# ),
|
||||||
key=lambda x: int(x.get("num") or 0),
|
# key=lambda x: int(x.get("num") or 0),
|
||||||
)
|
# )
|
||||||
return started_team
|
return data
|
||||||
|
|
||||||
|
|
||||||
def add_new_team_stat(
|
def add_new_team_stat(
|
||||||
@@ -2353,6 +2633,8 @@ async def info():
|
|||||||
data = latest_data["game"]["data"]["result"]
|
data = latest_data["game"]["data"]["result"]
|
||||||
team1_name = data["team1"]["name"]
|
team1_name = data["team1"]["name"]
|
||||||
team2_name = data["team2"]["name"]
|
team2_name = data["team2"]["name"]
|
||||||
|
team1_name_short = data["team1"]["abcName"]
|
||||||
|
team2_name_short = data["team2"]["abcName"]
|
||||||
team1_logo = data["team1"]["logo"]
|
team1_logo = data["team1"]["logo"]
|
||||||
team2_logo = data["team2"]["logo"]
|
team2_logo = data["team2"]["logo"]
|
||||||
arena = data["arena"]["name"]
|
arena = data["arena"]["name"]
|
||||||
@@ -2375,6 +2657,8 @@ async def info():
|
|||||||
{
|
{
|
||||||
"team1": team1_name,
|
"team1": team1_name,
|
||||||
"team2": team2_name,
|
"team2": team2_name,
|
||||||
|
"team1_short": team1_name_short,
|
||||||
|
"team2_short": team2_name_short,
|
||||||
"logo1": team1_logo,
|
"logo1": team1_logo,
|
||||||
"logo2": team2_logo,
|
"logo2": team2_logo,
|
||||||
"arena": arena,
|
"arena": arena,
|
||||||
|
|||||||
Reference in New Issue
Block a user