добавлены Судьи, поправлены Ход игры и События игры на офлайн матч
This commit is contained in:
302
PlayTypeID.json
Normal file
302
PlayTypeID.json
Normal file
@@ -0,0 +1,302 @@
|
||||
[
|
||||
{
|
||||
"PlayTypeID": 0,
|
||||
"PlayInfoSite": "-",
|
||||
"PlayInfo": "Пустое событие"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 1,
|
||||
"PlayInfoSite": "1 очко",
|
||||
"PlayInfo": "Штрафной бросок - попадание"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 2,
|
||||
"PlayInfoSite": "2 очка",
|
||||
"PlayInfo": "2х очковый бросок - попадание"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 3,
|
||||
"PlayInfoSite": "3 очка",
|
||||
"PlayInfo": "3х очковый бросок - попадание"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 4,
|
||||
"PlayInfoSite": "Мимо 1 очко",
|
||||
"PlayInfo": "Штрафной бросок - промах"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 5,
|
||||
"PlayInfoSite": "Мимо 2 очка",
|
||||
"PlayInfo": "2х очковый бросок - промах"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 6,
|
||||
"PlayInfoSite": "Мимо 3 очка",
|
||||
"PlayInfo": "3х очковый бросок - промах"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 7,
|
||||
"PlayInfoSite": "Замена",
|
||||
"PlayInfo": "Замена игроков"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 8,
|
||||
"PlayInfoSite": "Выход",
|
||||
"PlayInfo": "Выход на площадку"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 9,
|
||||
"PlayInfoSite": "Уход",
|
||||
"PlayInfo": "Ушел с площадки"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 10,
|
||||
"PlayInfoSite": "Потеря",
|
||||
"PlayInfo": "Потеря"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 11,
|
||||
"PlayInfoSite": "Пас-потеря",
|
||||
"PlayInfo": "Потеря мяча при передаче"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 12,
|
||||
"PlayInfoSite": "Пробежка",
|
||||
"PlayInfo": "Пробежка"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 13,
|
||||
"PlayInfoSite": "Заступ в аут",
|
||||
"PlayInfo": "Заступ в аут"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 14,
|
||||
"PlayInfoSite": "Зона",
|
||||
"PlayInfo": "Зона"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 15,
|
||||
"PlayInfoSite": "Двойное ведение",
|
||||
"PlayInfo": "Двойное ведение"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 16,
|
||||
"PlayInfoSite": "3 секунды",
|
||||
"PlayInfo": "3 секунды"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 17,
|
||||
"PlayInfoSite": "5 секунд",
|
||||
"PlayInfo": "5 секунд"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 18,
|
||||
"PlayInfoSite": "8 секунд",
|
||||
"PlayInfo": "8 секунд"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 19,
|
||||
"PlayInfoSite": "24 секунды",
|
||||
"PlayInfo": "24 секунды"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 20,
|
||||
"PlayInfoSite": "Потеря мяча",
|
||||
"PlayInfo": "Потеря мяча"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 21,
|
||||
"PlayInfoSite": "Начало четверти",
|
||||
"PlayInfo": "Начало четверти?"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 22,
|
||||
"PlayInfoSite": "",
|
||||
"PlayInfo": "Окончание четверти?"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 23,
|
||||
"PlayInfoSite": "Тайм-аут",
|
||||
"PlayInfo": "Тайм-аут"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 24,
|
||||
"PlayInfoSite": "",
|
||||
"PlayInfo": "неизвестно"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 25,
|
||||
"PlayInfoSite": "Пас",
|
||||
"PlayInfo": "Передача"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 26,
|
||||
"PlayInfoSite": "Перехват",
|
||||
"PlayInfo": "Перехват"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 27,
|
||||
"PlayInfoSite": "Блокшот",
|
||||
"PlayInfo": "Блокшот"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 28,
|
||||
"PlayInfoSite": "Подбор",
|
||||
"PlayInfo": "Подбор"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 29,
|
||||
"PlayInfoSite": "Быстрый отрыв",
|
||||
"PlayInfo": "Быстрый отрыв"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 30,
|
||||
"PlayInfoSite": "Бросок сверху",
|
||||
"PlayInfo": "Тип броска"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 31,
|
||||
"PlayInfoSite": "В прыжке",
|
||||
"PlayInfo": "Тип броска"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 32,
|
||||
"PlayInfoSite": "В проходе",
|
||||
"PlayInfo": "Тип броска"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 33,
|
||||
"PlayInfoSite": "Добивание",
|
||||
"PlayInfo": "Тип броска"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 34,
|
||||
"PlayInfoSite": "Навес",
|
||||
"PlayInfo": "Тип броска"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 35,
|
||||
"PlayInfoSite": "Бросок крюком",
|
||||
"PlayInfo": "Тип броска"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 40,
|
||||
"PlayInfoSite": "Фол P",
|
||||
"PlayInfo": "Фол персональный"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 41,
|
||||
"PlayInfoSite": "Фол U",
|
||||
"PlayInfo": "Фол неспортивный"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 42,
|
||||
"PlayInfoSite": "Фол T",
|
||||
"PlayInfo": "Фол технический"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 43,
|
||||
"PlayInfoSite": "Фол D",
|
||||
"PlayInfo": "Фол дисквалифицирующий"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 44,
|
||||
"PlayInfoSite": "Фол C",
|
||||
"PlayInfo": "Фол технический главному тренеру за его личное неспортивное поведение"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 45,
|
||||
"PlayInfoSite": "Фол В",
|
||||
"PlayInfo": "Фол технический главному тренеру по любой другой причине"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 47,
|
||||
"PlayInfoSite": "В нападении",
|
||||
"PlayInfo": "Тип фола"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 50,
|
||||
"PlayInfoSite": "Вбрасывание",
|
||||
"PlayInfo": "Тип фола"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 51,
|
||||
"PlayInfoSite": "1 бросок",
|
||||
"PlayInfo": "Назначение 1го штрафного броска"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 52,
|
||||
"PlayInfoSite": "2 броска",
|
||||
"PlayInfo": "Назначение 2х штрафных бросков"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 53,
|
||||
"PlayInfoSite": "3 броска",
|
||||
"PlayInfo": "Назначение 3х штрафных бросков"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 54,
|
||||
"PlayInfoSite": "Компенсация",
|
||||
"PlayInfo": "Обоюдное пробивание штрафных"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 59,
|
||||
"PlayInfoSite": "",
|
||||
"PlayInfo": "пробел для сайта"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 60,
|
||||
"PlayInfoSite": "Разминка команд",
|
||||
"PlayInfo": "Разминка команд"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 61,
|
||||
"PlayInfoSite": "Представление команд",
|
||||
"PlayInfo": "Представление команд"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 62,
|
||||
"PlayInfoSite": "Менее 3 минут до начала игры",
|
||||
"PlayInfo": "Менее 3 минут до начала игры"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 63,
|
||||
"PlayInfoSite": "Игра сейчас начнется",
|
||||
"PlayInfo": "Игра сейчас начнется"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 69,
|
||||
"PlayInfoSite": "Видеопросмотр",
|
||||
"PlayInfo": "Видеопросмотр?"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 70,
|
||||
"PlayInfoSite": "",
|
||||
"PlayInfo": "Возможно остановка игры?"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 71,
|
||||
"PlayInfoSite": "",
|
||||
"PlayInfo": "Возможно возобновление игры?"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 72,
|
||||
"PlayInfoSite": "Видеопросмотр",
|
||||
"PlayInfo": "Видеопросмотр?"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 73,
|
||||
"PlayInfoSite": "Старт видеотрансляции",
|
||||
"PlayInfo": "Старт видеотрансляции"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 74,
|
||||
"PlayInfoSite": "Конец видеотрансляции",
|
||||
"PlayInfo": "Конец видеотрансляции"
|
||||
},
|
||||
{
|
||||
"PlayTypeID": 100,
|
||||
"PlayInfoSite": "Матч завершен",
|
||||
"PlayInfo": "Матч завершен"
|
||||
}
|
||||
]
|
||||
185
get_data_new.py
185
get_data_new.py
@@ -10,6 +10,7 @@ from datetime import datetime, timedelta, timezone
|
||||
from zoneinfo import ZoneInfo
|
||||
from typing import Any, Dict, List, Tuple, Optional
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
import requests
|
||||
from requests.adapters import HTTPAdapter
|
||||
@@ -549,7 +550,7 @@ def poll_game_live(
|
||||
if game_finished:
|
||||
break
|
||||
|
||||
time.sleep(0.2)
|
||||
time.sleep(1)
|
||||
|
||||
# вторая точка выхода по stop_event после sleep
|
||||
if stop_event.is_set():
|
||||
@@ -652,6 +653,8 @@ def render_loop(stop_event: threading.Event, out_name: str = "game") -> None:
|
||||
Json_Team_Generation(state, who="team1")
|
||||
Json_Team_Generation(state, who="team2")
|
||||
Scores_Quarter(state)
|
||||
Referee(state)
|
||||
Play_By_Play(state)
|
||||
|
||||
# live_status отдельно, + общий state в <out_name>.json
|
||||
atomic_write_json([state["result"]["live_status"]], "live_status")
|
||||
@@ -761,7 +764,7 @@ def Referee(merged: dict, *, out_dir: str = "static") -> None:
|
||||
else len(desired_order)
|
||||
),
|
||||
)
|
||||
out_path = "referee.json"
|
||||
out_path = "referee"
|
||||
atomic_write_json(referees, out_path)
|
||||
logging.info("Сохранил payload: {out_path}")
|
||||
|
||||
@@ -769,6 +772,172 @@ def Referee(merged: dict, *, out_dir: str = "static") -> None:
|
||||
logger.error(f"Ошибка в Referee потоке: {e}", exc_info=True)
|
||||
|
||||
|
||||
def Play_By_Play(data: dict) -> None:
|
||||
"""
|
||||
Поток, обновляющий JSON-файл с последовательностью бросков в матче.
|
||||
"""
|
||||
logger.info("START making json for play-by-play")
|
||||
|
||||
try:
|
||||
game_data = data["result"] if "result" in data else data
|
||||
|
||||
if not game_data:
|
||||
logger.debug("game_online_data отсутствует")
|
||||
return
|
||||
|
||||
teams = game_data["teams"]
|
||||
team1_data = next((i for i in teams if i.get("teamNumber") == 1), None)
|
||||
team2_data = next((i for i in teams if i.get("teamNumber") == 2), None)
|
||||
|
||||
if not team1_data or not team2_data:
|
||||
logger.warning("Не удалось получить команды из game_online_data")
|
||||
return
|
||||
team1_name = game_data["team1"]["name"]
|
||||
team2_name = game_data["team2"]["name"]
|
||||
team1_startnum = [
|
||||
p["startNum"]
|
||||
for p in team1_data.get("starts", [])
|
||||
if p.get("startRole") == "Player"
|
||||
]
|
||||
team2_startnum = [
|
||||
p["startNum"]
|
||||
for p in team2_data.get("starts", [])
|
||||
if p.get("startRole") == "Player"
|
||||
]
|
||||
|
||||
plays = game_data.get("plays", [])
|
||||
if not plays:
|
||||
logger.debug("нет данных в play-by-play")
|
||||
return
|
||||
|
||||
# Получение текущего времени игры
|
||||
json_live_status = data["result"]["live_status"] if "result" in data and "live_status" in data["result"] else None
|
||||
last_event = plays[-1]
|
||||
|
||||
# if not json_live_status or json_live_status.get("message") == "Not Found":
|
||||
if json_live_status is None:
|
||||
period = last_event.get("period", 1)
|
||||
second = 0
|
||||
else:
|
||||
period = (json_live_status or {}).get("result", {}).get("period", 1)
|
||||
second = (json_live_status or {}).get("result", {}).get("second", 0)
|
||||
|
||||
# Создание DataFrame из событий
|
||||
df = pd.DataFrame(plays[::-1])
|
||||
|
||||
# Преобразование для лиги 3x3
|
||||
# if "3x3" in LEAGUE:
|
||||
# df["play"].replace({2: 1, 3: 2}, inplace=True)
|
||||
|
||||
df_goals = df[df["play"].isin([1, 2, 3])].copy()
|
||||
if df_goals.empty:
|
||||
logger.debug("нет данных о голах в play-by-play")
|
||||
return
|
||||
|
||||
# Расчёты по очкам и времени
|
||||
df_goals["score1"] = (
|
||||
df_goals["startNum"].isin(team1_startnum) * df_goals["play"]
|
||||
)
|
||||
df_goals["score2"] = (
|
||||
df_goals["startNum"].isin(team2_startnum) * df_goals["play"]
|
||||
)
|
||||
|
||||
df_goals["score_sum1"] = df_goals["score1"].fillna(0).cumsum()
|
||||
df_goals["score_sum2"] = df_goals["score2"].fillna(0).cumsum()
|
||||
|
||||
df_goals["new_sec"] = (
|
||||
pd.to_numeric(df_goals["sec"], errors="coerce").fillna(0).astype(int)
|
||||
// 10
|
||||
)
|
||||
df_goals["time_now"] = (600 if period < 5 else 300) - second
|
||||
df_goals["quar"] = period - df_goals["period"]
|
||||
|
||||
df_goals["diff_time"] = np.where(
|
||||
df_goals["quar"] == 0,
|
||||
df_goals["time_now"] - df_goals["new_sec"],
|
||||
(600 * df_goals["quar"] - df_goals["new_sec"]) + df_goals["time_now"],
|
||||
)
|
||||
|
||||
df_goals["diff_time_str"] = df_goals["diff_time"].apply(
|
||||
lambda x: (
|
||||
f"{x // 60}:{str(x % 60).zfill(2)}" if isinstance(x, int) else x
|
||||
)
|
||||
)
|
||||
|
||||
# Текстовые поля
|
||||
def generate_text(row, with_time=False, is_rus=False):
|
||||
s1, s2 = int(row["score_sum1"]), int(row["score_sum2"])
|
||||
team = (
|
||||
team1_name
|
||||
if not pd.isna(row["score1"]) and row["score1"] != 0
|
||||
else team2_name
|
||||
)
|
||||
|
||||
# ✅ Правильный порядок счёта в зависимости от команды
|
||||
if team == team1_name:
|
||||
score = f"{s1}-{s2}"
|
||||
else:
|
||||
score = f"{s2}-{s1}"
|
||||
|
||||
time_str = (
|
||||
f" за {row['diff_time_str']}"
|
||||
if is_rus
|
||||
else f" in last {row['diff_time_str']}"
|
||||
)
|
||||
prefix = "рывок" if is_rus else "run"
|
||||
|
||||
return f"{team} {score} {prefix}{time_str if with_time else ''}"
|
||||
|
||||
df_goals["text_rus"] = df_goals.apply(
|
||||
lambda r: generate_text(r, is_rus=True, with_time=False), axis=1
|
||||
)
|
||||
df_goals["text_time_rus"] = df_goals.apply(
|
||||
lambda r: generate_text(r, is_rus=True, with_time=True), axis=1
|
||||
)
|
||||
df_goals["text"] = df_goals.apply(
|
||||
lambda r: generate_text(r, is_rus=False, with_time=False), axis=1
|
||||
)
|
||||
df_goals["text_time"] = df_goals.apply(
|
||||
lambda r: generate_text(r, is_rus=False, with_time=True), axis=1
|
||||
)
|
||||
|
||||
df_goals["team"] = df_goals["score1"].apply(
|
||||
lambda x: team1_name if not pd.isna(x) and x != 0 else team2_name
|
||||
)
|
||||
|
||||
# Удаление лишнего
|
||||
drop_cols = [
|
||||
"children",
|
||||
"start",
|
||||
"stop",
|
||||
"hl",
|
||||
"sort",
|
||||
"startNum",
|
||||
"zone",
|
||||
"x",
|
||||
"y",
|
||||
]
|
||||
df_goals.drop(columns=drop_cols, inplace=True, errors="ignore")
|
||||
|
||||
# Порядок колонок
|
||||
main_cols = ["text", "text_time"]
|
||||
all_cols = main_cols + [
|
||||
col for col in df_goals.columns if col not in main_cols
|
||||
]
|
||||
df_goals = df_goals[all_cols]
|
||||
|
||||
# Сохранение JSON
|
||||
directory = "static"
|
||||
os.makedirs(directory, exist_ok=True)
|
||||
filepath = os.path.join(directory, "play_by_play.json")
|
||||
|
||||
df_goals.to_json(filepath, orient="records", force_ascii=False, indent=4)
|
||||
logger.debug("Успешно положил данные об play-by-play в файл")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка в Play_By_Play: {e}", exc_info=True)
|
||||
|
||||
|
||||
|
||||
def render_once_after_game(
|
||||
session: requests.Session,
|
||||
league: str,
|
||||
@@ -808,6 +977,7 @@ def render_once_after_game(
|
||||
Json_Team_Generation(state, who="team2")
|
||||
Scores_Quarter(state)
|
||||
Referee(state)
|
||||
Play_By_Play(state)
|
||||
|
||||
# === 4. live_status и общий state ===
|
||||
atomic_write_json(state["result"], out_name)
|
||||
@@ -817,6 +987,7 @@ def render_once_after_game(
|
||||
except Exception as ex:
|
||||
logger.exception(f"[RENDER_ONCE] error while building final state: {ex}")
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 7. Постобработка статистики для вывода
|
||||
# ============================================================================
|
||||
@@ -1446,7 +1617,9 @@ def Standing_func(
|
||||
|
||||
# когда мы последний раз успешно обновили standings
|
||||
last_call_ts = 0
|
||||
json_seasons = fetch_api_data(session, "seasons", host=HOST, league=league, lang=lang)
|
||||
json_seasons = fetch_api_data(
|
||||
session, "seasons", host=HOST, league=league, lang=lang
|
||||
)
|
||||
season = json_seasons[0]["season"]
|
||||
|
||||
# как часто вообще можно дёргать standings
|
||||
@@ -1549,7 +1722,7 @@ def Standing_func(
|
||||
filename = f"standings_{league}_{comp_name}"
|
||||
atomic_write_json(standings_payload, filename, out_dir)
|
||||
logger.info(
|
||||
f"[STANDINGS_THREAD] saved {filename}.json ({len(standings_payload)} rows)"
|
||||
f"[STANDINGS_THREAD] сохранил {filename}.json"
|
||||
)
|
||||
|
||||
# 2) плейофф-пары (playoffPairs)
|
||||
@@ -1757,8 +1930,8 @@ def main():
|
||||
standings_thread.join()
|
||||
logger.info("[MAIN] standings thread stopped, shutdown complete")
|
||||
|
||||
# идём на новую итерацию while True
|
||||
# (новая сессия / новый stop_event создаются в начале цикла)
|
||||
# идём на новую итерацию while True
|
||||
# (новая сессия / новый stop_event создаются в начале цикла)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
|
||||
45
visual.py
45
visual.py
@@ -615,9 +615,7 @@ if isinstance(cached_game_online, dict):
|
||||
col5_2.metric("Fouls", foulsB)
|
||||
|
||||
|
||||
if isinstance(cached_game_online, dict) and (
|
||||
cached_game_online.get("plays") or []
|
||||
):
|
||||
if isinstance(cached_game_online, dict) and (cached_game_online.get("plays") or []):
|
||||
col_1_col = [f"col_1_{i}" for i in range(1, period_max + 1)]
|
||||
col_2_col = [f"col_2_{i}" for i in range(1, period_max + 1)]
|
||||
count_q = 0
|
||||
@@ -1868,8 +1866,7 @@ try:
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
play_type_id = []
|
||||
|
||||
teams_section = ((cached_game_online or {}).get("result") or {}).get("teams") or {}
|
||||
|
||||
teams_section = cached_game_online.get("teams") or {}
|
||||
# Если teams_section — список (например, [{"starts": [...]}, {...}])
|
||||
if isinstance(teams_section, list):
|
||||
if len(teams_section) >= 2:
|
||||
@@ -1882,6 +1879,7 @@ if isinstance(teams_section, list):
|
||||
else:
|
||||
starts1 = []
|
||||
starts2 = []
|
||||
|
||||
# Если teams_section — словарь (обычно {"1": {...}, "2": {...}})
|
||||
elif isinstance(teams_section, dict):
|
||||
starts1 = (teams_section.get(1) or teams_section.get("1") or {}).get("starts") or []
|
||||
@@ -1927,8 +1925,43 @@ def get_event_time(row):
|
||||
return None
|
||||
|
||||
|
||||
teams_section = cached_game_online.get("teams") or {}
|
||||
|
||||
# Если teams_section — список (например, [{"starts": [...]}, {...}])
|
||||
if isinstance(teams_section, list):
|
||||
if len(teams_section) >= 2:
|
||||
starts1 = next(
|
||||
(t.get("starts") for t in teams_section if t["teamNumber"] == 1), None
|
||||
)
|
||||
starts2 = next(
|
||||
(t.get("starts") for t in teams_section if t["teamNumber"] == 2), None
|
||||
)
|
||||
else:
|
||||
starts1 = []
|
||||
starts2 = []
|
||||
# Если teams_section — словарь (обычно {"1": {...}, "2": {...}})
|
||||
elif isinstance(teams_section, dict):
|
||||
starts1 = (teams_section.get(1) or teams_section.get("1") or {}).get("starts") or []
|
||||
starts2 = (teams_section.get(2) or teams_section.get("2") or {}).get("starts") or []
|
||||
else:
|
||||
starts1 = []
|
||||
starts2 = []
|
||||
|
||||
teams_temp = sorted(
|
||||
[x for x in starts1 if isinstance(x, dict)], key=lambda x: x.get("playerNumber", 0)
|
||||
) + sorted(
|
||||
[x for x in starts2 if isinstance(x, dict)], key=lambda x: x.get("playerNumber", 0)
|
||||
)
|
||||
|
||||
list_fullname = [None] + [
|
||||
f"({x.get('displayNumber')}) {x.get('firstName','')} {x.get('lastName','')}".strip()
|
||||
for x in teams_temp
|
||||
if x.get("startRole") == "Player"
|
||||
]
|
||||
|
||||
|
||||
with tab_pbp:
|
||||
plays = ((cached_game_online or {}).get("result") or {}).get("plays") or []
|
||||
# plays = ((cached_game_online or {}).get("result") or {}).get("plays") or []
|
||||
if plays:
|
||||
temp_data_pbp = pd.DataFrame(plays)
|
||||
col1_pbp, col2_pbp = tab_pbp.columns((3, 4))
|
||||
|
||||
Reference in New Issue
Block a user