diff --git a/PlayTypeID.json b/PlayTypeID.json deleted file mode 100644 index 3d2d516..0000000 --- a/PlayTypeID.json +++ /dev/null @@ -1,302 +0,0 @@ -[ - { - "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": "Матч завершен" - } -] diff --git a/Replace PERM.bat b/Replace PERM.bat deleted file mode 100644 index 91a9d10..0000000 --- a/Replace PERM.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -REM 1. vmix_url_replace.exe -"%~dp0vmix_url_replace.exe" --file "D:\extGFX\VTB.vmix" --url "https://per.tvstart.ru/app/static/per_" - -REM 2. vMix -start "" "D:\extGFX\VTB.vmix" diff --git a/Replace UNICS.bat b/Replace UNICS.bat deleted file mode 100644 index eb3f39a..0000000 --- a/Replace UNICS.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -REM 1. vmix_url_replace.exe -"%~dp0vmix_url_replace.exe" --file "D:\extGFX\VTB.vmix" --url "https://kaz.tvstart.ru/app/static/kaz_" - -REM 2. vMix -start "" "D:\extGFX\VTB.vmix" diff --git a/match_id.json b/match_id.json deleted file mode 100644 index 664d14f..0000000 --- a/match_id.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "10.10.1.180": {"host": "", "tag": "vtb", "root": 1, "team": "cska"}, - "10.10.35.21": {"host": "gfx", "tag": "vtb", "root": 1, "team": "Lokomotiv Kuban"}, - "10.10.35.22": {"host": "krd", "tag": "vtb", "root": 1, "team": "Lokomotiv Kuban1"}, - "10.10.35.23": {"host": "ekb", "tag": "vtb", "root": 1, "team": "uralmash1"}, - "10.10.35.24": {"host": "per", "tag": "vtb", "root": 1, "team": "betcity parma1"}, - "10.10.35.25": {"host": "sar", "tag": "vtb", "root": 1, "team": "avtodor1"}, - "10.10.35.26": {"host": "spb", "tag": "vtb", "root": 1, "team": "zenit1"}, - "10.10.35.27": {"host": "sam", "tag": "vtb", "root": 1, "team": "samara1"}, - "10.10.35.28": {"host": "msk1", "tag": "vtb", "root": 1, "team": "mba-mai1"}, - "10.10.35.29": {"host": "msk2", "tag": "vtb", "root": 1, "team": "Pari Nizhny Novgorod1"}, - "10.10.35.30": {"host": "kaz", "tag": "vtb", "root": 1, "team": "unics1"} -} \ No newline at end of file diff --git a/run.bat b/run.bat deleted file mode 100644 index 3cb4520..0000000 --- a/run.bat +++ /dev/null @@ -1,7 +0,0 @@ -::Скрипт запуска отображения данных в RFB - -chcp 65001 -@echo off >nul - -echo запускаю софт -streamlit run visual.py \ No newline at end of file diff --git a/visual_GPT1.py b/visual_GPT1.py deleted file mode 100644 index 94dae06..0000000 --- a/visual_GPT1.py +++ /dev/null @@ -1,1106 +0,0 @@ -import os -import json -import socket -import platform -import numpy as np -import pandas as pd -import streamlit as st -import sys -from streamlit_autorefresh import st_autorefresh - -st.set_page_config( - page_title="Баскетбол", - page_icon="🏀", - layout="wide", - initial_sidebar_state="expanded", - menu_items={"About": "версия 1.8 22.01.2025"}, -) -REMOVE_PADDING_FROM_SIDES = """ - -""" - -st.markdown(REMOVE_PADDING_FROM_SIDES, unsafe_allow_html=True) -st_autorefresh() - - -# Функции для стилизации -def highlight_max(data): - # Преобразуем данные к числовому типу, заменяя некорректные значения на NaN - numeric_data = pd.to_numeric(data, errors="coerce") - max_value = numeric_data.max() if pd.notna(numeric_data.max()) else None - return [ - "background-color: green" if pd.notna(v) and v == max_value and v > 0 else "" - for v in numeric_data - ] - - -def color_win(s): - return [ - ( - "background-color: ForestGreen" - if v == True - else "background-color: #FF4B4B" if v == False else None - ) - for v in s - ] - - -def highlight_grey(s): - return ["background-color: grey"] * len(s) if s.foul == 5 else [""] * len(s) - - -def highlight_foul(s): - return [ - ( - "background-color: orange" - if v == 4 - else "background-color: red" if v == 5 else "" - ) - for v in s - ] - - -def load_json_data(filepath): - """ - Загружает данные из JSON файла и кэширует их. - Возвращает None, если файл не удается прочитать. - """ - try: - with open(filepath, "r", encoding="utf-8") as file: - return json.load(file) - except (json.JSONDecodeError, FileNotFoundError): - return None - - -# Функция для обработки данных одной команды -def process_team_data(team_json, columns_to_include): - team_data = pd.json_normalize(team_json) - - # Оставляем только нужные колонки - team_data = team_data[:12][columns_to_include] - - # Обработка height и weight - for column in ["height", "weight"]: - if column in team_data.columns: - team_data[column] = team_data[column].apply( - lambda value: "" if value == 0 else value - ) - - return team_data - - -def process_player_data(team_json, player_index): - team_data = pd.json_normalize(team_json) - player_data = team_data.iloc[player_index] - season_total = { - "name": "Season Total", - "game_count": str(player_data["TGameCount"]), - "start_count": str(player_data["TStartCount"]), - "pts": str(player_data["TPoints"]), - "pt-2": str(player_data["TShots2"]), - "pt-3": str(player_data["TShots3"]), - "pt-1": str(player_data["TShots1"]), - "fg": str(player_data["TShots23"]), - "ast": str(player_data["TAssist"]), - "stl": str(player_data["TSteal"]), - "blk": str(player_data["TBlocks"]), - "dreb": str(player_data["TDefRebound"]), - "oreb": str(player_data["TOffRebound"]), - "reb": str(player_data["TRebound"]), - # "to": str(player_data["TTurnover"]), - # "foul": str(player_data["TFoul"]), - "fouled": str(player_data["TOpponentFoul"]), - "dunk": str(player_data["TDunk"]), - "time": str(player_data["TPlayedTime"]), - } - season_avg = { - "name": "Season Average", - "game_count": "", - "start_count": "", - "pts": str(player_data["AvgPoints"]), - "pt-2": str(player_data["Shot2Percent"]), - "pt-3": str(player_data["Shot3Percent"]), - "pt-1": str(player_data["Shot1Percent"]), - "fg": str(player_data["Shot23Percent"]), - "ast": str(player_data["AvgAssist"]), - "stl": str(player_data["AvgSteal"]), - "blk": str(player_data["AvgBlocks"]), - "dreb": str(player_data["AvgDefRebound"]), - "oreb": str(player_data["AvgOffRebound"]), - "reb": str(player_data["AvgRebound"]), - # "to": str(player_data["AvgTurnover"]), - # "foul": str(player_data["AvgFoul"]), - "fouled": str(player_data["AvgOpponentFoul"]), - "dunk": str(player_data["AvgDunk"]), - "time": str(player_data["AvgPlayedTime"]), - } - career_total = { - "name": "Career Total", - "game_count": str(player_data["CareerTGameCount"]), - "start_count": str(player_data["CareerTStartCount"]), - "pts": str(player_data["CareerTPoints"]), - "pt-2": str(player_data["CareerTShots2"]), - "pt-3": str(player_data["CareerTShots3"]), - "pt-1": str(player_data["CareerTShots1"]), - "fg": str(player_data["CareerTShots23"]), - "ast": str(player_data["CareerTAssist"]), - "stl": str(player_data["CareerTSteal"]), - "blk": str(player_data["CareerTBlocks"]), - "dreb": str(player_data["CareerTDefRebound"]), - "oreb": str(player_data["CareerTOffRebound"]), - "reb": str(player_data["CareerTRebound"]), - # "to": str(player_data["CareerTTurnover"]), - # "foul": str(player_data["CareerTFoul"]), - "fouled": str(player_data["CareerTOpponentFoul"]), - "dunk": str(player_data["CareerTDunk"]), - "time": str(player_data["CareerTPlayedTime"]), - } - - return [season_total, season_avg, career_total], player_data - - -config = { - "flag": st.column_config.ImageColumn("flag"), - "roleShort": st.column_config.TextColumn("R", width=27), - "num": st.column_config.TextColumn("#", width=27), - "NameGFX": st.column_config.TextColumn(width=170), - "isOn": st.column_config.TextColumn("🏀", width=27), - "pts": st.column_config.NumberColumn("PTS", width=27), - "pt-2": st.column_config.TextColumn("2-PT", width=45), - "pt-3": st.column_config.TextColumn("3-PT", width=45), - "pt-1": st.column_config.TextColumn("FT", width=45), - "fg": st.column_config.TextColumn("FG", width=45), - "ast": st.column_config.NumberColumn("AS", width=27), - "stl": st.column_config.NumberColumn("ST", width=27), - "blk": st.column_config.NumberColumn("BL", width=27), - "blkVic": st.column_config.NumberColumn("BV", width=27), - "dreb": st.column_config.NumberColumn("DR", width=27), - "oreb": st.column_config.NumberColumn("OR", width=27), - "reb": st.column_config.NumberColumn("R", width=27), - "to": st.column_config.NumberColumn("TO", width=27), - "foul": st.column_config.NumberColumn("F", width=27), - "fouled": st.column_config.NumberColumn("Fed", width=27), - "plusMinus": st.column_config.NumberColumn("+/-", width=27), - "dunk": st.column_config.NumberColumn("DUNK", width=27), - "kpi": st.column_config.NumberColumn("KPI", width=27), - "time": st.column_config.TextColumn("TIME"), - "game_count": st.column_config.TextColumn("G", width=27), - "start_count": st.column_config.TextColumn("S", width=27), - "q_pts": st.column_config.TextColumn("PTS", width=27), - "q_ast": st.column_config.TextColumn("AS", width=27), - "q_stl": st.column_config.TextColumn("ST", width=27), - "q_blk": st.column_config.TextColumn("BL", width=27), - "q_reb": st.column_config.TextColumn("R", width=27), - "q_rnk": st.column_config.TextColumn("KPI", width=27), - "q_f": st.column_config.TextColumn("F", width=27), - "q_f_on": st.column_config.TextColumn("Fed", width=27), - "q_to": st.column_config.TextColumn("TO", width=27), - "q_time": st.column_config.TextColumn("TIME"), - "q_pt2": st.column_config.TextColumn("2-PT", width=45), - "q_pt3": st.column_config.TextColumn("3-PT", width=45), - "q_pt23": st.column_config.TextColumn("FG", width=45), - "q_ft": st.column_config.TextColumn("FT", width=45), -} -config_season = { - "flag": st.column_config.ImageColumn("flag"), - "roleShort": st.column_config.TextColumn("R", width=27), - "num": st.column_config.TextColumn("#", width=27), - "NameGFX": st.column_config.TextColumn(width=170), - "isOn": st.column_config.TextColumn("🏀", width=27), - "pts": st.column_config.TextColumn("PTS", width=40), - "pt-2": st.column_config.TextColumn("2-PT", width=60), - "pt-3": st.column_config.TextColumn("3-PT", width=60), - "pt-1": st.column_config.TextColumn("FT", width=60), - "fg": st.column_config.TextColumn("FG", width=60), - "ast": st.column_config.TextColumn("AS", width=40), - "stl": st.column_config.TextColumn("ST", width=40), - "blk": st.column_config.TextColumn("BL", width=40), - "blkVic": st.column_config.TextColumn("BV", width=40), - "dreb": st.column_config.TextColumn("DR", width=40), - "oreb": st.column_config.TextColumn("OR", width=40), - "reb": st.column_config.TextColumn("R", width=40), - "to": st.column_config.TextColumn("TO", width=40), - "foul": st.column_config.TextColumn("F", width=40), - "fouled": st.column_config.TextColumn("Fed", width=40), - "plusMinus": st.column_config.TextColumn("+/-", width=40), - "dunk": st.column_config.TextColumn("DUNK", width=40), - "kpi": st.column_config.TextColumn("KPI", width=40), - "time": st.column_config.TextColumn("TIME"), - "game_count": st.column_config.TextColumn("G", width=40), - "start_count": st.column_config.TextColumn("S", width=40), -} - -if "player1" not in st.session_state: - st.session_state.player1 = None -if "player2" not in st.session_state: - st.session_state.player2 = None - - -myhost = platform.node() -if sys.platform.startswith("win"): # было: if platform == "win32": - FOLDER_JSON = "JSON" -else: - FOLDER_JSON = "static" - -def get_ip_address(): - try: - # Попытка получить IP-адрес с использованием внешнего сервиса - # Может потребоваться подключение к интернету - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.connect(("8.8.8.8", 80)) - ip_address = s.getsockname()[0] - except socket.error: - # Если не удалось получить IP-адрес через внешний сервис, - # используем метод для локального получения IP - ip_address = socket.gethostbyname(socket.gethostname()) - return ip_address - - -def load_data_from_json(filepath): - directory = FOLDER_JSON - os.makedirs(directory, exist_ok=True) - filepath_full = os.path.join(directory, f"{filepath}.json") - - ip = get_ip_address() - host = ip_check.get(ip, {}).get("host") or "" # безопаснее - - # Ключ в session_state: <имя файла> без префикса _ - # Пример: static/abc_game_online.json -> game_online - base = os.path.basename(filepath_full).replace(".json","") - key = base.replace(f"{host}_", "", 1) - - temp = load_json_data(filepath_full) # None, если нет файла/парсинга - st.session_state[key] = temp # ключ гарантированно создаётся - -try: - with open("match_id.json", "r", encoding="utf-8") as f: - ip_check = json.load(f) -except (FileNotFoundError, json.JSONDecodeError): - ip_check = {} - -ip_address = get_ip_address() -prefix = ip_check.get(ip_address, {}).get("host") - - -load_data_from_json(f"{prefix}_game_online") -cached_game_online = st.session_state.get("game_online") - -load_data_from_json(f"{prefix}_team1") -cached_team1 = st.session_state.get("team1") - -load_data_from_json(f"{prefix}_team2") -cached_team2 = st.session_state.get("team2") - -load_data_from_json(f"{prefix}_referee") -cached_referee = st.session_state.get("referee") - -# standings — может не быть тега/файла -league_tag = None -if isinstance(cached_game_online, dict): - league_tag = ((cached_game_online.get("result") or {}).get("league") or {}).get("tag") -if league_tag: - load_data_from_json(f"{prefix}_standings_{league_tag}") -cached_standings = st.session_state.get(f"standings_{league_tag}") if league_tag else None - -load_data_from_json(f"{prefix}_scores_quarter") -cached_scores_quarter = st.session_state.get("scores_quarter") - -load_data_from_json(f"{prefix}_play_by_play") -cached_play_by_play = st.session_state.get("play_by_play") - -load_data_from_json(f"{prefix}_team_stats") -cached_team_stats = st.session_state.get("team_stats") - -load_data_from_json(f"{prefix}_scores") -cached_scores = st.session_state.get("scores") or [] # важно! - -load_data_from_json(f"{prefix}_live_status") -cached_live_status = st.session_state.get("live_status") - -load_data_from_json(f"{prefix}_schedule") -cached_schedule = st.session_state.get("schedule") - -# st.session_state -def ensure_state(key: str, default=None): - # Инициализирует ключ один раз и возвращает значение - return st.session_state.setdefault(key, default) - - -period_max = 0 -if isinstance(cached_play_by_play, list) and isinstance(cached_game_online, dict): - plays = (cached_game_online.get("result") or {}).get("plays") or [] - if plays: - df_data_pbp = pd.DataFrame(cached_play_by_play) - if not df_data_pbp.empty and "period" in df_data_pbp.columns: - period_max = int(df_data_pbp.iloc[0]["period"]) - count_quarter = [ - f"Четверть {i}" if i < 5 else f"Овертайм {i-4}" - for i in range(1, period_max + 1) - ] - - for i in range(1, period_max + 1): - key_team1 = f"team1_{i}" - key_team2 = f"team2_{i}" - load_data_from_json(key_team1) - load_data_from_json(key_team2) - _q1 = st.session_state.get(key_team1) # может быть None — это ок - _q2 = st.session_state.get(key_team2) - - -timeout1 = [] -timeout2 = [] - -if isinstance(cached_game_online, dict): - result = cached_game_online.get("result") or {} - plays = result.get("plays") or [] - - timeout1, timeout2 = [], [] - for event in plays: - if isinstance(event, dict) and event.get("play") == 23: - if event.get("startNum") == 1: - timeout1.append(event) - elif event.get("startNum") == 2: - timeout2.append(event) - - col1, col4, col2, col5, col3 = st.columns([1, 5, 3, 5, 1]) - - t1 = (result.get("team1") or {}) - t2 = (result.get("team2") or {}) - if t1.get("logo"): - col1.image(t1["logo"], width=100) - team1_name = t1.get("name") or "" - team2_name = t2.get("name") or "" - if team1_name or team2_name: - col2.markdown( - f"

{team1_name} — {team2_name}

", - unsafe_allow_html=True, - ) - if t2.get("logo"): - col3.image(t2["logo"], width=100) - - col4_1, col4_2, col4_3 = col4.columns((1, 1, 1)) - col5_1, col5_2, col5_3 = col5.columns((1, 1, 1)) - - # Points метрики безопасно - val1 = val2 = None - if isinstance(cached_team_stats, list) and len(cached_team_stats) > 0: - v1 = cached_team_stats[0].get("val1") - v2 = cached_team_stats[0].get("val2") - if v1 is not None and v2 is not None: - val1, val2 = int(v1), int(v2) - delta_color_1 = "off" if val1 == val2 else "normal" - col4_1.metric("Points", v1, val1 - val2, delta_color_1) - col5_3.metric("Points", v2, val2 - val1, delta_color_1) - - col4_3.metric("TimeOuts", len(timeout1)) - col5_1.metric("TimeOuts", len(timeout2)) - - if isinstance(cached_live_status, list) and cached_live_status: - foulsA = (cached_live_status[0] or {}).get("foulsA") - foulsB = (cached_live_status[0] or {}).get("foulsB") - if foulsA is not None: - col4_2.metric("Fouls", foulsA) - if foulsB is not None: - col5_2.metric("Fouls", foulsB) - - -if isinstance(cached_game_online, dict) and ((cached_game_online.get("result") or {}).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 - - score_by_quarter_1 = [x.get("score1") for x in cached_scores if isinstance(x, dict) and x.get("score1") not in ("", None)] - score_by_quarter_2 = [x.get("score2") for x in cached_scores if isinstance(x, dict) and x.get("score2") not in ("", None)] - - if score_by_quarter_1: - col_1_col = col4.columns([1 for _ in range(len(score_by_quarter_1))]) - col_2_col = col5.columns([1 for _ in range(len(score_by_quarter_2))]) - - for q1, q2, col1_i, col2_i in zip(score_by_quarter_1, score_by_quarter_2, col_1_col, col_2_col): - count_q += 1 - name_q = f"OT{count_q-4}" if count_q > 4 else f"Q{count_q}" - try: - delta_color = "off" if int(q1) == int(q2) else "normal" - col1_i.metric(name_q, q1, int(q1) - int(q2), delta_color, border=True) - col2_i.metric(name_q, q2, int(q2) - int(q1), delta_color, border=True) - except (ValueError, TypeError): - # если кривые данные в JSON, просто пропустим - pass - - - -( - tab_temp_1, - tab_temp_2, - tab_temp_3, - tab_temp_4, - tab_temp_5, - tab_temp_6, - tab_pbp, - tab_temp_7, - tab_temp_8, - tab_schedule, -) = st.tabs( - [ - "Игроки", - "Команды", - "Судьи", - "Турнирная таблица", - "Статистика четвертей", - "Ход игры", - "События игры", - "Статистика по четвертям", - "Milestones", - "Прошедшие/будущие матчи", - ] -) - - -def check_milestone(value, milestone_type, name, num, where): - milestone_checks = { - "PTS": "point", - "AST": "assist", - "BLK": "block", - "REB": "rebound", - "DREB": "defensive rebound", - "OREB": "offensive rebound", - "STL": "steal", - "GAMES": "game", - } - if milestone_type == "GAMES": - list_data = [*range(50, 5100, 50)] - if int(value) % 100 in [49, 99]: - diff = [l - int(value) for l in list_data] - positive_numbers = [num for num in diff if num > -1] - count = 0 - for i in diff: - count += 1 - if i == min(positive_numbers): - break - full_word = [ - word - for w, word in milestone_checks.items() - if w.lower() == milestone_type.lower() - ][0] - # print(positive_numbers) - if min(positive_numbers) != 0: - word = full_word if min(positive_numbers) == 1 else f"{full_word}s" - if where == "season": - where = "in this season" - elif where == "league": - where = "in career VTB" - string_value = f"{name} needs {min(positive_numbers)} {word} to reach {list_data[count-1]} {full_word}s {where}" - else: - string_value = "" - return { - "NameGFX": f"{name} ({num})", - "type": milestone_type.upper(), - "value": value, - "string_value": string_value, - } - else: - list_data = [*range(100, 5100, 100)] - if (int(value) % 100) >= 90 or (int(value) % 1000) in list_data: - diff = [l - int(value) for l in list_data] - positive_numbers = [num for num in diff if num > -1] - count = 0 - for i in diff: - count += 1 - if i == min(positive_numbers): - break - # print(positive_numbers) - full_word = [ - word - for w, word in milestone_checks.items() - if w.lower() == milestone_type.lower() - ][0] - # print(positive_numbers) - if min(positive_numbers) != 0: - word = full_word if min(positive_numbers) == 1 else f"{full_word}s" - if where == "season": - where = "in this season" - elif where == "league": - where = "in career VTB" - string_value = f"{name} needs {min(positive_numbers)} {word} to reach {list_data[count-1]} {full_word}s {where}" - else: - string_value = "" - return { - "NameGFX": f"{name} ({num})", - "type": milestone_type.upper(), - "value": value, - "string_value": string_value, - } - return None - - -def milestones(data): - new_data_season = [] - new_data_career = [] - for d in data: - if d["startRole"] == "Player": - milestone_checks = { - "PTS": d["TPoints"], - "AST": d["TAssist"], - "BLK": d["TBlocks"], - "REB": d["TRebound"], - "DREB": d["TDefRebound"], - "OREB": d["TOffRebound"], - "STL": d["TSteal"], - "GAMES": d["TGameCount"], - } - milestone_career_checks = { - "PTS": d["CareerTPoints"], - "AST": d["CareerTAssist"], - "BLK": d["CareerTBlocks"], - "REB": d["CareerTRebound"], - "DREB": d["CareerTDefRebound"], - "OREB": d["CareerTOffRebound"], - "STL": d["CareerTSteal"], - "GAMES": d["CareerTGameCount"], - } - for milestone_type, value in milestone_checks.items(): - milestone_data = check_milestone( - value, milestone_type, d["NameGFX"], d["num"], "season" - ) - if milestone_data: - new_data_season.append(milestone_data) - for milestone_type_car, value_car in milestone_career_checks.items(): - milestone_data_car = check_milestone( - value_car, milestone_type_car, d["NameGFX"], d["num"], "league" - ) - if milestone_data_car: - new_data_career.append(milestone_data_car) - return new_data_season, new_data_career - - -columns_game = [ - "num", - # "roleShort", - "NameGFX", - "isOn", - # "flag", - "pts", - "pt-2", - "pt-3", - "pt-1", - "fg", - "ast", - "stl", - "blk", - "blkVic", - "dreb", - "oreb", - "reb", - "to", - "foul", - "fouled", - "plusMinus", - "dunk", - "kpi", - "time", -] -if cached_team1 and cached_team2: - team1_data = process_team_data(cached_team1, columns_game) - team2_data = process_team_data(cached_team2, columns_game) - - - # Стилизация данных - team1_styled = ( - team1_data.style.apply(highlight_grey, axis=1) - .apply(highlight_foul, subset="foul") - .apply(highlight_max, subset="pts") - ) - team2_styled = ( - team2_data.style.apply(highlight_grey, axis=1) - .apply(highlight_foul, subset="foul") - .apply(highlight_max, subset="pts") - ) - - # Вывод данных - col_player1, col_player2 = tab_temp_1.columns((5, 5)) - event1 = col_player1.dataframe( - team1_styled, - column_config=config, - hide_index=True, - height=460, - on_select="rerun", - selection_mode=[ - "single-row", - ], - ) - event2 = col_player2.dataframe( - team2_styled, - column_config=config, - hide_index=True, - height=460, - on_select="rerun", - selection_mode=[ - "single-row", - ], - ) - - if event1.selection and event1.selection.get("rows"): - selected_index1 = event1.selection["rows"][0] - st.session_state["player1"] = ( - selected_index1 # Сохранение состояния в session_state - ) - if st.session_state["player1"] is not None: - selected_player_1, player_data_1 = process_player_data( - cached_team1, st.session_state["player1"] - ) - if player_data_1["num"]: - z, a, b, c, d, e = col_player1.columns((1, 6, 1, 1, 1, 1)) - z.metric("Номер", player_data_1["num"], border=False) - a.metric("Игрок", player_data_1["NameGFX"], border=False) - b.metric("Амплуа", player_data_1["roleShort"], border=False) - c.metric("Возраст", player_data_1["age"], border=False) - d.metric("Рост", player_data_1["height"].split()[0], border=False) - e.metric("Вес", player_data_1["weight"].split()[0], border=False) - - col_player1.dataframe( - selected_player_1, - column_config=config_season, - hide_index=True, - ) - if event2.selection and event2.selection.get("rows"): - selected_index2 = event2.selection["rows"][0] - st.session_state["player2"] = ( - selected_index2 # Сохранение состояния в session_state - ) - if st.session_state["player2"] is not None: - selected_player_2, player_data_2 = process_player_data( - cached_team2, st.session_state["player2"] - ) - if player_data_2["num"]: - z, a, b, c, d, e = col_player2.columns((1, 6, 1, 1, 1, 1)) - z.metric("Номер", player_data_2["num"], border=False) - a.metric("Игрок", player_data_2["NameGFX"], border=False) - b.metric("Амплуа", player_data_2["roleShort"], border=False) - c.metric("Возраст", player_data_2["age"], border=False) - d.metric("Рост", player_data_2["height"].split()[0], border=False) - e.metric("Вес", player_data_2["weight"].split()[0], border=False) - - col_player2.dataframe( - selected_player_2, - column_config=config_season, - hide_index=True, - ) - - -if isinstance(cached_team_stats, list) and len(cached_team_stats) >= 34: - cached_team_stats_new = [ - cached_team_stats[0], - *cached_team_stats[25:29], - cached_team_stats[7], - cached_team_stats[33], - *cached_team_stats[9:11], - *cached_team_stats[15:17], - ] - tab_temp_2.table(cached_team_stats_new) - -if isinstance(cached_referee, (list, pd.DataFrame)): - tab_temp_3.dataframe(cached_referee, height=600, column_config={"flag": st.column_config.ImageColumn("flag")}) - - -column_config_ref = { - "flag": st.column_config.ImageColumn( - "flag", - ), -} - -if cached_referee: - tab_temp_3.dataframe(cached_referee, height=600, column_config=column_config_ref) - - -def highlight_teams(s): - try: - if s.iloc[0] in ( - cached_game_online["result"]["team1"]["teamId"], - cached_game_online["result"]["team2"]["teamId"], - ): - return ["background-color: #FF4B4B"] * len(s) - else: - return [""] * len(s) - except NameError: - return [""] * len(s) - - -if cached_standings: - df_st = pd.json_normalize(cached_standings) - def highlight_teams(s): - try: - t1 = ((cached_game_online or {}).get("result") or {}).get("team1", {}).get("teamId") - t2 = ((cached_game_online or {}).get("result") or {}).get("team2", {}).get("teamId") - if s.iloc[0] in (t1, t2): - return ["background-color: #FF4B4B"] * len(s) - except Exception: - pass - return [""] * len(s) - styled = df_st.style.apply(highlight_teams, axis=1) - tab_temp_4.dataframe( - styled, - column_config={"logo": st.column_config.ImageColumn("logo")}, - hide_index=True, - height=610, - ) - - -if isinstance(cached_scores_quarter, list) and len(cached_scores_quarter) >= 2: - column_config = {} - for quarter in ["Q1", "Q2", "Q3", "Q4", "OT1", "OT2", "OT3", "OT4"]: - column_name = f"score_avg{quarter}" - column_config[column_name] = st.column_config.NumberColumn(column_name, format="%.1f") - - columns_quarters_name = ["Q1", "Q2", "Q3", "Q4"] - columns_quarters_name_ot = ["OT1", "OT2", "OT3", "OT4"] - columns_quarters = tab_temp_5.columns((1, 1, 1, 1)) - - # Основные четверти - for index, col in enumerate(columns_quarters): - q = columns_quarters_name[index] - df_col = [ - { - "team": cached_scores_quarter[0].get("team"), - "W": cached_scores_quarter[0].get(f"win{q}"), - "L": cached_scores_quarter[0].get(f"lose{q}"), - "D": cached_scores_quarter[0].get(f"draw{q}"), - "PTS": cached_scores_quarter[0].get(f"score{q}"), - "AVG": cached_scores_quarter[0].get(f"score_avg{q}"), - }, - { - "team": cached_scores_quarter[1].get("team"), - "W": cached_scores_quarter[1].get(f"win{q}"), - "L": cached_scores_quarter[1].get(f"lose{q}"), - "D": cached_scores_quarter[1].get(f"draw{q}"), - "PTS": cached_scores_quarter[1].get(f"score{q}"), - "AVG": cached_scores_quarter[1].get(f"score_avg{q}"), - }, - ] - col.write(q) - col.dataframe(df_col) - - # Овертаймы - for index, col in enumerate(columns_quarters): - q = columns_quarters_name_ot[index] - df_col = [ - { - "team": cached_scores_quarter[0].get("team"), - "W": cached_scores_quarter[0].get(f"win{q}"), - "L": cached_scores_quarter[0].get(f"lose{q}"), - "D": cached_scores_quarter[0].get(f"draw{q}"), - "PTS": cached_scores_quarter[0].get(f"score{q}"), - "AVG": cached_scores_quarter[0].get(f"score_avg{q}"), - }, - { - "team": cached_scores_quarter[1].get("team"), - "W": cached_scores_quarter[1].get(f"win{q}"), - "L": cached_scores_quarter[1].get(f"lose{q}"), - "D": cached_scores_quarter[1].get(f"draw{q}"), - "PTS": cached_scores_quarter[1].get(f"score{q}"), - "AVG": cached_scores_quarter[1].get(f"score_avg{q}"), - }, - ] - col.write(q) - col.dataframe(df_col) - - -if isinstance(cached_play_by_play, list) and isinstance(cached_game_online, dict): - plays = (cached_game_online.get("result") or {}).get("plays") or [] - if plays: - tab_temp_6.table(cached_play_by_play) - - -def schedule_selected_team(team_id, data, game_id, selected, away_team_id): - columns = [ - "game.localDate", - "team1.name", - "team1.logo", - "game.score", - "team2.logo", - "team2.name", - "game.fullScore", - "win", - ] - df_schedule_new = data.loc[ - # (data["game.id"] < game_id) - # & - ( - (data["team1.teamId"].isin([team_id])) - | (data["team2.teamId"].isin([team_id])) - ) - ] - df_schedule_new.loc[:, "game.fullScore"] = df_schedule_new[ - "game.fullScore" - ].str.split(",") - conditions = [ - (df_schedule_new["team1.teamId"] == team_id) - & (df_schedule_new["game.score1"] > df_schedule_new["game.score2"]), - (df_schedule_new["team1.teamId"] == team_id) - & (df_schedule_new["game.score1"] < df_schedule_new["game.score2"]), - (df_schedule_new["team2.teamId"] == team_id) - & (df_schedule_new["game.score2"] > df_schedule_new["game.score1"]), - (df_schedule_new["team2.teamId"] == team_id) - & (df_schedule_new["game.score2"] < df_schedule_new["game.score1"]), - ] - values = [True, False, True, False] - - df_schedule_new = df_schedule_new.copy() - df_schedule_new.loc[:, "win"] = np.select(conditions, values, default=None) - mask = pd.Series(True, index=df_schedule_new.index) - - # Проверяем каждое выбранное условие и объединяем с маской - if selected: - if "Дома" in selected: - mask &= df_schedule_new["team1.teamId"] == team_id - if "В гостях" in selected: - mask &= df_schedule_new["team2.teamId"] == team_id - if "Выигрыши" in selected: - mask &= df_schedule_new["win"] == True - if "Поражения" in selected: - mask &= df_schedule_new["win"] == False - if "Друг с другом" in selected: - mask &= df_schedule_new["team1.teamId"].isin( - [away_team_id, team_id] - ) & df_schedule_new["team2.teamId"].isin([away_team_id, team_id]) - return df_schedule_new[columns].loc[mask] - - -def get_in(d, path, default=None): - cur = d - for key in path: - if not isinstance(cur, dict): - return default - cur = cur.get(key, default) - if cur is default: - return default - return cur - -if tab_schedule: - if cached_schedule and "items" in cached_schedule: - cached_schedule = cached_schedule["items"] - pd_schedule = pd.json_normalize(cached_schedule) - - game_online = st.session_state.get("game_online") - team1_id = get_in(game_online, ["result", "team1", "teamId"]) - team1_name = get_in(game_online, ["result", "team1", "name"]) - team2_id = get_in(game_online, ["result", "team2", "teamId"]) - team2_name = get_in(game_online, ["result", "team2", "name"]) - game_id = get_in(game_online, ["result", "game", "id"]) - - - col1_schedule, col2_schedule = tab_schedule.columns((5, 5)) - options = ["Дома", "В гостях", "Выигрыши", "Поражения", "Друг с другом"] - selection1 = col1_schedule.segmented_control( - "Фильтр", options, selection_mode="multi", key="1" - ) - selection2 = col2_schedule.segmented_control( - "Фильтр", options, selection_mode="multi", key="2" - ) - - team1_data = schedule_selected_team( - team1_id, pd_schedule, game_id, selection1, team2_id - ) - team2_data = schedule_selected_team( - team2_id, pd_schedule, game_id, selection2, team1_id - ) - - def highlight_two_teams(s): - try: - if str(s.loc["team1.name"]) in ( - team1_name, - team2_name, - ) and str(s.loc["team2.name"]) in ( - team1_name, - team2_name, - ): - return ["background-color: #FF4B4B"] * len(s) - else: - return [""] * len(s) - except NameError: - return [""] * len(s) - - column_config = { - "team1.name": st.column_config.TextColumn("Команда1", width=150), - "team2.name": st.column_config.TextColumn("Команда2", width=150), - "game.score": st.column_config.TextColumn( - "Счёт", - ), - "game.localDate": st.column_config.TextColumn( - "Дата", - ), - "game.fullScore": st.column_config.Column( - "Счёт по четвертям", - ), - "team1.logo": st.column_config.ImageColumn("Лого1", width=50), - "team2.logo": st.column_config.ImageColumn("Лого2", width=50), - } - count_game_1 = len(team1_data) - count_game_2 = len(team2_data) - team1_data = team1_data.style.apply(highlight_two_teams, axis=1).apply( - color_win, subset="win" - ) - team2_data = team2_data.style.apply(highlight_two_teams, axis=1).apply( - color_win, subset="win" - ) - height1 = 38 * max(count_game_1, 10) - height2 = 38 * max(count_game_2, 10) - col1_schedule.dataframe( - team1_data, - hide_index=True, - height=int(min(height1, 1200)), - column_config=column_config, - ) - col2_schedule.dataframe( - team2_data, - hide_index=True, - height=int(min(height2, 1200)), - column_config=column_config, - ) - - -def get_play_info(play): - # Ищем в списке play_type_id элемент, у которого PlayTypeID совпадает с play - for item in play_type_id: - if item["PlayTypeID"] == play: - return item["PlayInfoSite"] - return None # Если совпадение не найдено - - -def get_player_name(start_num): - # Ищем в списке teams_temp элемент, у которого startNum совпадает с temp_data_pbp["startNum"] - for player in teams_temp: - if player["startNum"] == start_num: - return f"{player['firstName']} {player['lastName']}" - return None # Если совпадение не найдено - - -def get_event_time(row): - if row != 0: - time_str = 6000 - row - if time_str == 0: - time_str = "0:00" - else: - time_str = time_str // 10 - time_str = f"{time_str // 60}:{str(time_str % 60).zfill(2)}" - return time_str - - -# Безопасная загрузка PlayTypeID -try: - with open("PlayTypeID.json", "r", encoding="utf-8") as f: - play_type_id = json.load(f) -except (FileNotFoundError, json.JSONDecodeError): - play_type_id = [] - -teams_section = ((cached_game_online or {}).get("result") or {}).get("teams") or {} - -# Если teams_section — список (например, [{"starts": [...]}, {...}]) -if isinstance(teams_section, list): - if len(teams_section) >= 2: - starts1 = (teams_section[0] or {}).get("starts") or [] - starts2 = (teams_section[1] or {}).get("starts") or [] - elif len(teams_section) == 1: - starts1 = (teams_section[0] or {}).get("starts") or [] - starts2 = [] - 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" -] - -def get_play_info(play): - for item in play_type_id: - if isinstance(item, dict) and item.get("PlayTypeID") == play: - return item.get("PlayInfoSite") - return None - -def get_player_name(start_num): - for player in teams_temp: - if player.get("startNum") == start_num: - return f"{player.get('firstName','')} {player.get('lastName','')}".strip() - return None - -def get_event_time(row): - if isinstance(row, (int, float)) and row != 0: - time_val = 6000 - int(row) - if time_val <= 0: - return "0:00" - time_val //= 10 - return f"{time_val // 60}:{str(time_val % 60).zfill(2)}" - return None - -with tab_pbp: - 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)) - option_player = col1_pbp.selectbox("Выбрать игрока", list_fullname) - - options_pbp = ["1 очко", "2 очка", "3 очка"] - selection_pbp = col1_pbp.segmented_control("Фильтр", options_pbp, selection_mode="multi", key=3) - - if not temp_data_pbp.empty and "period" in temp_data_pbp.columns: - options_quarter = [ - (f"{i+1} четверть" if i + 1 < 5 else f"{i-3} овертайм") - for i in range(int(temp_data_pbp["period"].max())) - ] - selection_quarter = col1_pbp.segmented_control("Выбор четверти", options_quarter, selection_mode="multi", key=4) - - temp_data_pbp["info"] = temp_data_pbp["play"].map(get_play_info) - temp_data_pbp["who"] = temp_data_pbp["startNum"].map(get_player_name) - temp_data_pbp["time"] = temp_data_pbp["sec"].map(get_event_time) - - mask1 = pd.Series(True, index=temp_data_pbp.index) - - if option_player: - # безопасный поиск startNum - for x in teams_temp: - display = f"({x.get('displayNumber')}) {x.get('firstName','')} {x.get('lastName','')}".strip() - if display == option_player: - mask1 &= temp_data_pbp["startNum"] == x.get("startNum") - break - - if selection_pbp: - plays_mapping = {"1 очко": 1, "2 очка": 2, "3 очка": 3} - selected_plays = [plays_mapping[p] for p in selection_pbp if p in plays_mapping] - mask1 &= temp_data_pbp["play"].isin(selected_plays) - - if selection_quarter: - select_quart = [i+1 for i, q in enumerate(options_quarter) if q in selection_quarter] - mask1 &= temp_data_pbp["period"].isin(select_quart) - - filtered_data_pbp = temp_data_pbp[mask1] - count_pbp = len(filtered_data_pbp) - - column_pbp = ["num", "info", "who", "period", "time"] - column_config_pbp = { - "info": st.column_config.TextColumn(width="medium"), - "who": st.column_config.TextColumn(width="large"), - } - col2_pbp.dataframe( - filtered_data_pbp[column_pbp], - column_config=column_config_pbp, - hide_index=True, - height=(38 * count_pbp if count_pbp > 10 else None), - ) - else: - st.info("Данных play-by-play нет.") diff --git a/visual_back1.py b/visual_back1.py deleted file mode 100644 index b517e9f..0000000 --- a/visual_back1.py +++ /dev/null @@ -1,1601 +0,0 @@ -import os -import json -import socket -import platform -import numpy as np -import pandas as pd -import streamlit as st -import sys -from streamlit_autorefresh import st_autorefresh - -st.set_page_config( - page_title="Баскетбол", - page_icon="🏀", - layout="wide", - initial_sidebar_state="expanded", - menu_items={"About": "версия 1.8 22.01.2025"}, -) -REMOVE_PADDING_FROM_SIDES = """ - -""" - -st.markdown(REMOVE_PADDING_FROM_SIDES, unsafe_allow_html=True) -st_autorefresh() - - -# Функции для стилизации -def highlight_max(data): - # Преобразуем данные к числовому типу, заменяя некорректные значения на NaN - numeric_data = pd.to_numeric(data, errors="coerce") - max_value = numeric_data.max() if pd.notna(numeric_data.max()) else None - return [ - "background-color: green" if pd.notna(v) and v == max_value and v > 0 else "" - for v in numeric_data - ] - - -def color_win(s): - return [ - ( - "background-color: ForestGreen" - if v == True - else "background-color: #FF4B4B" if v == False else None - ) - for v in s - ] - - -def highlight_grey(s): - return ["background-color: grey"] * len(s) if s.foul == 5 else [""] * len(s) - - -def highlight_foul(s): - return [ - ( - "background-color: orange" - if v == 4 - else "background-color: red" if v == 5 else "" - ) - for v in s - ] - - -def load_json_data(filepath): - """ - Загружает данные из JSON файла и кэширует их. - Возвращает None, если файл не удается прочитать. - """ - try: - with open(filepath, "r", encoding="utf-8") as file: - return json.load(file) - except (json.JSONDecodeError, FileNotFoundError): - return None - - -def show_df(container, data, *, base_row_h=38, min_rows=12, max_h=1200, **kwargs): - # вычисляем высоту - try: - n = len(data) - except Exception: - n = 0 - h = base_row_h * max(n, min_rows) - # зажимаем в допустимый диапазон - if not isinstance(h, int): - h = int(h) - h = max(0, min(h, max_h)) - - # если высота 0 или данных мало — не передаём height вовсе - if h <= 0 or n == 0: - container.dataframe(data, **kwargs) - else: - container.dataframe(data, height=h, **kwargs) - - -# Функция для обработки данных одной команды -def process_team_data(team_json, columns_to_include): - team_data = pd.json_normalize(team_json) - - # Оставляем только нужные колонки - team_data = team_data[:12][columns_to_include] - - # Обработка height и weight - for column in ["height", "weight"]: - if column in team_data.columns: - team_data[column] = team_data[column].apply( - lambda value: "" if value == 0 else value - ) - - return team_data - - -def process_player_data(team_json, player_index): - team_data = pd.json_normalize(team_json) - player_data = team_data.iloc[player_index] - season_total = { - "name": "Season Total", - "game_count": str(player_data["TGameCount"]), - "start_count": str(player_data["TStartCount"]), - "pts": str(player_data["TPoints"]), - "pt-2": str(player_data["TShots2"]), - "pt-3": str(player_data["TShots3"]), - "pt-1": str(player_data["TShots1"]), - "fg": str(player_data["TShots23"]), - "ast": str(player_data["TAssist"]), - "stl": str(player_data["TSteal"]), - "blk": str(player_data["TBlocks"]), - "dreb": str(player_data["TDefRebound"]), - "oreb": str(player_data["TOffRebound"]), - "reb": str(player_data["TRebound"]), - # "to": str(player_data["TTurnover"]), - # "foul": str(player_data["TFoul"]), - "fouled": str(player_data["TOpponentFoul"]), - "dunk": str(player_data["TDunk"]), - "time": str(player_data["TPlayedTime"]), - } - season_avg = { - "name": "Season Average", - "game_count": "", - "start_count": "", - "pts": str(player_data["AvgPoints"]), - "pt-2": str(player_data["Shot2Percent"]), - "pt-3": str(player_data["Shot3Percent"]), - "pt-1": str(player_data["Shot1Percent"]), - "fg": str(player_data["Shot23Percent"]), - "ast": str(player_data["AvgAssist"]), - "stl": str(player_data["AvgSteal"]), - "blk": str(player_data["AvgBlocks"]), - "dreb": str(player_data["AvgDefRebound"]), - "oreb": str(player_data["AvgOffRebound"]), - "reb": str(player_data["AvgRebound"]), - # "to": str(player_data["AvgTurnover"]), - # "foul": str(player_data["AvgFoul"]), - "fouled": str(player_data["AvgOpponentFoul"]), - "dunk": str(player_data["AvgDunk"]), - "time": str(player_data["AvgPlayedTime"]), - } - career_total = { - "name": "Career Total", - "game_count": str(player_data["CareerTGameCount"]), - "start_count": str(player_data["CareerTStartCount"]), - "pts": str(player_data["CareerTPoints"]), - "pt-2": str(player_data["CareerTShots2"]), - "pt-3": str(player_data["CareerTShots3"]), - "pt-1": str(player_data["CareerTShots1"]), - "fg": str(player_data["CareerTShots23"]), - "ast": str(player_data["CareerTAssist"]), - "stl": str(player_data["CareerTSteal"]), - "blk": str(player_data["CareerTBlocks"]), - "dreb": str(player_data["CareerTDefRebound"]), - "oreb": str(player_data["CareerTOffRebound"]), - "reb": str(player_data["CareerTRebound"]), - # "to": str(player_data["CareerTTurnover"]), - # "foul": str(player_data["CareerTFoul"]), - "fouled": str(player_data["CareerTOpponentFoul"]), - "dunk": str(player_data["CareerTDunk"]), - "time": str(player_data["CareerTPlayedTime"]), - } - - return [season_total, season_avg, career_total], player_data - - -config = { - "flag": st.column_config.ImageColumn("flag"), - "roleShort": st.column_config.TextColumn("R", width=27), - "num": st.column_config.TextColumn("#", width=27), - "NameGFX": st.column_config.TextColumn(width=170), - "isOn": st.column_config.TextColumn("🏀", width=27), - "pts": st.column_config.NumberColumn("PTS", width=27), - "pt-2": st.column_config.TextColumn("2-PT", width=45), - "pt-3": st.column_config.TextColumn("3-PT", width=45), - "pt-1": st.column_config.TextColumn("FT", width=45), - "fg": st.column_config.TextColumn("FG", width=45), - "ast": st.column_config.NumberColumn("AS", width=27), - "stl": st.column_config.NumberColumn("ST", width=27), - "blk": st.column_config.NumberColumn("BL", width=27), - "blkVic": st.column_config.NumberColumn("BV", width=27), - "dreb": st.column_config.NumberColumn("DR", width=27), - "oreb": st.column_config.NumberColumn("OR", width=27), - "reb": st.column_config.NumberColumn("R", width=27), - "to": st.column_config.NumberColumn("TO", width=27), - "foul": st.column_config.NumberColumn("F", width=27), - "fouled": st.column_config.NumberColumn("Fed", width=27), - "plusMinus": st.column_config.NumberColumn("+/-", width=27), - "dunk": st.column_config.NumberColumn("DUNK", width=27), - "kpi": st.column_config.NumberColumn("KPI", width=27), - "time": st.column_config.TextColumn("TIME"), - "game_count": st.column_config.TextColumn("G", width=27), - "start_count": st.column_config.TextColumn("S", width=27), - "q_pts": st.column_config.TextColumn("PTS", width=27), - "q_ast": st.column_config.TextColumn("AS", width=27), - "q_stl": st.column_config.TextColumn("ST", width=27), - "q_blk": st.column_config.TextColumn("BL", width=27), - "q_reb": st.column_config.TextColumn("R", width=27), - "q_rnk": st.column_config.TextColumn("KPI", width=27), - "q_f": st.column_config.TextColumn("F", width=27), - "q_f_on": st.column_config.TextColumn("Fed", width=27), - "q_to": st.column_config.TextColumn("TO", width=27), - "q_time": st.column_config.TextColumn("TIME"), - "q_pt2": st.column_config.TextColumn("2-PT", width=45), - "q_pt3": st.column_config.TextColumn("3-PT", width=45), - "q_pt23": st.column_config.TextColumn("FG", width=45), - "q_ft": st.column_config.TextColumn("FT", width=45), -} -config_season = { - "flag": st.column_config.ImageColumn("flag"), - "roleShort": st.column_config.TextColumn("R", width=27), - "num": st.column_config.TextColumn("#", width=27), - "NameGFX": st.column_config.TextColumn(width=170), - "isOn": st.column_config.TextColumn("🏀", width=27), - "pts": st.column_config.TextColumn("PTS", width=40), - "pt-2": st.column_config.TextColumn("2-PT", width=60), - "pt-3": st.column_config.TextColumn("3-PT", width=60), - "pt-1": st.column_config.TextColumn("FT", width=60), - "fg": st.column_config.TextColumn("FG", width=60), - "ast": st.column_config.TextColumn("AS", width=40), - "stl": st.column_config.TextColumn("ST", width=40), - "blk": st.column_config.TextColumn("BL", width=40), - "blkVic": st.column_config.TextColumn("BV", width=40), - "dreb": st.column_config.TextColumn("DR", width=40), - "oreb": st.column_config.TextColumn("OR", width=40), - "reb": st.column_config.TextColumn("R", width=40), - "to": st.column_config.TextColumn("TO", width=40), - "foul": st.column_config.TextColumn("F", width=40), - "fouled": st.column_config.TextColumn("Fed", width=40), - "plusMinus": st.column_config.TextColumn("+/-", width=40), - "dunk": st.column_config.TextColumn("DUNK", width=40), - "kpi": st.column_config.TextColumn("KPI", width=40), - "time": st.column_config.TextColumn("TIME"), - "game_count": st.column_config.TextColumn("G", width=40), - "start_count": st.column_config.TextColumn("S", width=40), -} - -if "player1" not in st.session_state: - st.session_state.player1 = None -if "player2" not in st.session_state: - st.session_state.player2 = None - - -# myhost = platform.node() -# FOLDER_JSON = "" -# if platform == "win32": -# FOLDER_JSON = "JSON" -# else: -# FOLDER_JSON = "static" - -myhost = platform.node() -if sys.platform.startswith("win"): # было: if platform == "win32": - FOLDER_JSON = "JSON" -else: - FOLDER_JSON = "static" - -def get_ip_address(): - try: - # Попытка получить IP-адрес с использованием внешнего сервиса - # Может потребоваться подключение к интернету - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.connect(("8.8.8.8", 80)) - ip_address = s.getsockname()[0] - except socket.error: - # Если не удалось получить IP-адрес через внешний сервис, - # используем метод для локального получения IP - ip_address = socket.gethostbyname(socket.gethostname()) - return ip_address - - -def load_data_from_json2(filepath): - directory = FOLDER_JSON - os.makedirs(directory, exist_ok=True) - filepath = os.path.join(directory, f"{filepath}.json") - ip = get_ip_address() - host = ip_check.get(ip, {}).get("host") - - # st.write(filepath) - key = filepath.replace(f"static/{host}_", "").replace(".json","") # Создаём уникальный ключ на основе значения filepath - # st.write(key) - temp = load_json_data(filepath) - # st.write(temp) - if key not in st.session_state: - st.session_state[key] = temp - else: - st.session_state[key] = temp - -def load_data_from_json(filepath): - directory = FOLDER_JSON - os.makedirs(directory, exist_ok=True) - filepath_full = os.path.join(directory, f"{filepath}.json") - - ip = get_ip_address() - host = ip_check.get(ip, {}).get("host") or "" # безопаснее - - # Ключ в session_state: <имя файла> без префикса _ - # Пример: static/abc_game_online.json -> game_online - base = os.path.basename(filepath_full).replace(".json","") - key = base.replace(f"{host}_", "", 1) - - temp = load_json_data(filepath_full) # None, если нет файла/парсинга - st.session_state[key] = temp # ключ гарантированно создаётся - -try: - with open("match_id.json", "r", encoding="utf-8") as f: - ip_check = json.load(f) -except (FileNotFoundError, json.JSONDecodeError): - ip_check = {} - -ip_address = get_ip_address() -prefix = ip_check.get(ip_address, {}).get("host") - - -# load_data_from_json(f"{prefix}_game_online") -# cached_game_online = st.session_state.game_online -# # for i in cached_game_online["result"]: -# # print(i) -# # print(cached_game_online["result"]["plays"]) -# load_data_from_json(f"{prefix}_team1") -# cached_team1 = st.session_state.team1 -# load_data_from_json(f"{prefix}_team2") -# cached_team2 = st.session_state.team2 -# load_data_from_json(f"{prefix}_referee") -# cached_referee = st.session_state.referee -# try: -# load_data_from_json(f'{prefix}_standings_{cached_game_online["result"]["league"]["tag"]}') -# except TypeError: -# pass -# if cached_game_online: -# cached_standings = st.session_state[ -# f'standings_{cached_game_online["result"]["league"]["tag"]}' -# ] -# else: -# cached_standings = None -# load_data_from_json(f"{prefix}_scores_quarter") -# cached_scores_quarter = st.session_state.scores_quarter -# load_data_from_json(f"{prefix}_play_by_play") -# cached_play_by_play = st.session_state.play_by_play -# load_data_from_json(f"{prefix}_team_stats") -# cached_team_stats = st.session_state.team_stats -# load_data_from_json(f"{prefix}_scores") -# cached_scores = st.session_state.scores -# load_data_from_json(f"{prefix}_live_status") -# cached_live_status = st.session_state.live_status -# load_data_from_json(f"{prefix}_schedule") -# cached_schedule = st.session_state.schedule - -load_data_from_json(f"{prefix}_game_online") -cached_game_online = st.session_state.get("game_online") - -load_data_from_json(f"{prefix}_team1") -cached_team1 = st.session_state.get("team1") - -load_data_from_json(f"{prefix}_team2") -cached_team2 = st.session_state.get("team2") - -load_data_from_json(f"{prefix}_referee") -cached_referee = st.session_state.get("referee") - -# standings — может не быть тега/файла -league_tag = None -if isinstance(cached_game_online, dict): - league_tag = ((cached_game_online.get("result") or {}).get("league") or {}).get("tag") -if league_tag: - load_data_from_json(f"{prefix}_standings_{league_tag}") -cached_standings = st.session_state.get(f"standings_{league_tag}") if league_tag else None - -load_data_from_json(f"{prefix}_scores_quarter") -cached_scores_quarter = st.session_state.get("scores_quarter") - -load_data_from_json(f"{prefix}_play_by_play") -cached_play_by_play = st.session_state.get("play_by_play") - -load_data_from_json(f"{prefix}_team_stats") -cached_team_stats = st.session_state.get("team_stats") - -load_data_from_json(f"{prefix}_scores") -cached_scores = st.session_state.get("scores") or [] # важно! - -load_data_from_json(f"{prefix}_live_status") -cached_live_status = st.session_state.get("live_status") - -load_data_from_json(f"{prefix}_schedule") -cached_schedule = st.session_state.get("schedule") - -# st.session_state -def ensure_state(key: str, default=None): - # Инициализирует ключ один раз и возвращает значение - return st.session_state.setdefault(key, default) - -# period_max = 0 -# if cached_play_by_play and cached_game_online and cached_game_online["result"]["plays"]: -# df_data_pbp = pd.DataFrame(cached_play_by_play) -# if "play" in df_data_pbp: -# period_max = df_data_pbp.iloc[0]["period"] -# count_quarter = [ -# f"Четверть {i}" if i < 5 else f"Овертайм {i-4}" -# for i in range(1, int(period_max) + 1) -# ] - -# for i in range(period_max): -# i += 1 -# key_team1 = f"team1_{i}" -# key_team2 = f"team2_{i}" -# load_data_from_json(key_team1) -# load_data_from_json(key_team2) -# # if key_quarter_team1: -# # key_quarter_team1 = st.session_state[key_quarter_team1] - -# # if key_quarter_team2: -# # key_quarter_team2 = st.session_state[key_quarter_team2] - -# key_quarter_team1 = st.session_state.get(key_team1) # None, если ключа нет -# key_quarter_team2 = st.session_state.get(key_team2) - -period_max = 0 -if isinstance(cached_play_by_play, list) and isinstance(cached_game_online, dict): - plays = (cached_game_online.get("result") or {}).get("plays") or [] - if plays: - df_data_pbp = pd.DataFrame(cached_play_by_play) - if not df_data_pbp.empty and "period" in df_data_pbp.columns: - period_max = int(df_data_pbp.iloc[0]["period"]) - count_quarter = [ - f"Четверть {i}" if i < 5 else f"Овертайм {i-4}" - for i in range(1, period_max + 1) - ] - - for i in range(1, period_max + 1): - key_team1 = f"team1_{i}" - key_team2 = f"team2_{i}" - load_data_from_json(key_team1) - load_data_from_json(key_team2) - _q1 = st.session_state.get(key_team1) # может быть None — это ок - _q2 = st.session_state.get(key_team2) - - -timeout1 = [] -timeout2 = [] -# if cached_game_online: -# for event in cached_game_online["result"]["plays"]: -# if event["play"] == 23: -# if event["startNum"] == 1: -# timeout1.append(event) -# elif event["startNum"] == 2: -# timeout2.append(event) - -# # with st.expander(""): -# col1, col4, col2, col5, col3 = st.columns([1, 5, 3, 5, 1]) -# col1.image(cached_game_online["result"]["team1"]["logo"], width=100) -# team1_name = cached_game_online["result"]["team1"]["name"] -# team2_name = cached_game_online["result"]["team2"]["name"] -# col2.markdown( -# f"

{team1_name} — {team2_name}

", -# unsafe_allow_html=True, -# ) -# col3.image(cached_game_online["result"]["team2"]["logo"], width=100) - - -# col4_1, col4_2, col4_3 = col4.columns((1, 1, 1)) -# delta_color_1 = ( -# "off" -# if int(cached_team_stats[0]["val1"]) == int(cached_team_stats[0]["val2"]) -# else "normal" -# ) - -# col4_1.metric( -# "Points", -# cached_team_stats[0]["val1"], -# int(cached_team_stats[0]["val1"]) - int(cached_team_stats[0]["val2"]), -# delta_color_1, -# ) -# col4_3.metric("TimeOuts", len(timeout1)) - -# col5_1, col5_2, col5_3 = col5.columns((1, 1, 1)) -# col5_3.metric( -# "Points", -# cached_team_stats[0]["val2"], -# int(cached_team_stats[0]["val2"]) - int(cached_team_stats[0]["val1"]), -# delta_color_1, -# ) -# col5_1.metric("TimeOuts", len(timeout2)) -# # print(cached_live_status) -# if cached_live_status is not None: -# col4_2.metric("Fouls", cached_live_status[0]["foulsA"]) -# col5_2.metric("Fouls", cached_live_status[0]["foulsB"]) - -if isinstance(cached_game_online, dict): - result = cached_game_online.get("result") or {} - plays = result.get("plays") or [] - - timeout1, timeout2 = [], [] - for event in plays: - if isinstance(event, dict) and event.get("play") == 23: - if event.get("startNum") == 1: - timeout1.append(event) - elif event.get("startNum") == 2: - timeout2.append(event) - - col1, col4, col2, col5, col3 = st.columns([1, 5, 3, 5, 1]) - - t1 = (result.get("team1") or {}) - t2 = (result.get("team2") or {}) - if t1.get("logo"): - col1.image(t1["logo"], width=100) - team1_name = t1.get("name") or "" - team2_name = t2.get("name") or "" - if team1_name or team2_name: - col2.markdown( - f"

{team1_name} — {team2_name}

", - unsafe_allow_html=True, - ) - if t2.get("logo"): - col3.image(t2["logo"], width=100) - - col4_1, col4_2, col4_3 = col4.columns((1, 1, 1)) - col5_1, col5_2, col5_3 = col5.columns((1, 1, 1)) - - # Points метрики безопасно - val1 = val2 = None - if isinstance(cached_team_stats, list) and len(cached_team_stats) > 0: - v1 = cached_team_stats[0].get("val1") - v2 = cached_team_stats[0].get("val2") - if v1 is not None and v2 is not None: - val1, val2 = int(v1), int(v2) - delta_color_1 = "off" if val1 == val2 else "normal" - col4_1.metric("Points", v1, val1 - val2, delta_color_1) - col5_3.metric("Points", v2, val2 - val1, delta_color_1) - - col4_3.metric("TimeOuts", len(timeout1)) - col5_1.metric("TimeOuts", len(timeout2)) - - if isinstance(cached_live_status, list) and cached_live_status: - foulsA = (cached_live_status[0] or {}).get("foulsA") - foulsB = (cached_live_status[0] or {}).get("foulsB") - if foulsA is not None: - col4_2.metric("Fouls", foulsA) - if foulsB is not None: - col5_2.metric("Fouls", foulsB) - - -# if cached_game_online and cached_game_online["result"]["plays"]: -# col_1_col = [f"col_1_{i}" for i in range(1, int(period_max) + 1)] -# col_2_col = [f"col_2_{i}" for i in range(1, int(period_max) + 1)] -# count_q = 0 -# cached_scores = cached_scores or [] -# score_by_quarter_1 = [x["score1"] for x in cached_scores if x["score1"] != ""] -# score_by_quarter_2 = [x["score2"] for x in cached_scores if x["score2"] != ""] -# if score_by_quarter_1 != []: -# col_1_col = col4.columns([1 for i in range(1, len(score_by_quarter_1) + 1)]) -# col_2_col = col5.columns([1 for i in range(1, len(score_by_quarter_2) + 1)]) -# # print(score_by_quarter_1) -# for q1, q2, col1, col2 in zip( -# score_by_quarter_1, score_by_quarter_2, col_1_col, col_2_col -# ): -# count_q += 1 -# name_q = "" -# if count_q > 4: -# name_q = f"OT{count_q-4}" -# else: -# name_q = f"Q{count_q}" -# # print(q1, q2) -# delta_color = "off" if int(q1) == int(q2) else "normal" -# col1.metric(name_q, q1, int(q1) - int(q2), delta_color, border=True) -# col2.metric(name_q, q2, int(q2) - int(q1), delta_color, border=True) - -if isinstance(cached_game_online, dict) and ((cached_game_online.get("result") or {}).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 - - score_by_quarter_1 = [x.get("score1") for x in cached_scores if isinstance(x, dict) and x.get("score1") not in ("", None)] - score_by_quarter_2 = [x.get("score2") for x in cached_scores if isinstance(x, dict) and x.get("score2") not in ("", None)] - - if score_by_quarter_1: - col_1_col = col4.columns([1 for _ in range(len(score_by_quarter_1))]) - col_2_col = col5.columns([1 for _ in range(len(score_by_quarter_2))]) - - for q1, q2, col1_i, col2_i in zip(score_by_quarter_1, score_by_quarter_2, col_1_col, col_2_col): - count_q += 1 - name_q = f"OT{count_q-4}" if count_q > 4 else f"Q{count_q}" - try: - delta_color = "off" if int(q1) == int(q2) else "normal" - col1_i.metric(name_q, q1, int(q1) - int(q2), delta_color, border=True) - col2_i.metric(name_q, q2, int(q2) - int(q1), delta_color, border=True) - except (ValueError, TypeError): - # если кривые данные в JSON, просто пропустим - pass - - - -( - tab_temp_1, - tab_temp_2, - tab_temp_3, - tab_temp_4, - tab_temp_5, - tab_temp_6, - tab_pbp, - tab_temp_7, - tab_temp_8, - tab_schedule, -) = st.tabs( - [ - "Игроки", - "Команды", - "Судьи", - "Турнирная таблица", - "Статистика четвертей", - "Ход игры", - "События игры", - "Статистика по четвертям", - "Milestones", - "Прошедшие/будущие матчи", - ] -) - - -def check_milestone(value, milestone_type, name, num, where): - milestone_checks = { - "PTS": "point", - "AST": "assist", - "BLK": "block", - "REB": "rebound", - "DREB": "defensive rebound", - "OREB": "offensive rebound", - "STL": "steal", - "GAMES": "game", - } - if milestone_type == "GAMES": - list_data = [*range(50, 5100, 50)] - if int(value) % 100 in [49, 99]: - diff = [l - int(value) for l in list_data] - positive_numbers = [num for num in diff if num > -1] - count = 0 - for i in diff: - count += 1 - if i == min(positive_numbers): - break - full_word = [ - word - for w, word in milestone_checks.items() - if w.lower() == milestone_type.lower() - ][0] - # print(positive_numbers) - if min(positive_numbers) != 0: - word = full_word if min(positive_numbers) == 1 else f"{full_word}s" - if where == "season": - where = "in this season" - elif where == "league": - where = "in career VTB" - string_value = f"{name} needs {min(positive_numbers)} {word} to reach {list_data[count-1]} {full_word}s {where}" - else: - string_value = "" - return { - "NameGFX": f"{name} ({num})", - "type": milestone_type.upper(), - "value": value, - "string_value": string_value, - } - else: - list_data = [*range(100, 5100, 100)] - if (int(value) % 100) >= 90 or (int(value) % 1000) in list_data: - diff = [l - int(value) for l in list_data] - positive_numbers = [num for num in diff if num > -1] - count = 0 - for i in diff: - count += 1 - if i == min(positive_numbers): - break - # print(positive_numbers) - full_word = [ - word - for w, word in milestone_checks.items() - if w.lower() == milestone_type.lower() - ][0] - # print(positive_numbers) - if min(positive_numbers) != 0: - word = full_word if min(positive_numbers) == 1 else f"{full_word}s" - if where == "season": - where = "in this season" - elif where == "league": - where = "in career VTB" - string_value = f"{name} needs {min(positive_numbers)} {word} to reach {list_data[count-1]} {full_word}s {where}" - else: - string_value = "" - return { - "NameGFX": f"{name} ({num})", - "type": milestone_type.upper(), - "value": value, - "string_value": string_value, - } - return None - - -def milestones(data): - new_data_season = [] - new_data_career = [] - for d in data: - if d["startRole"] == "Player": - milestone_checks = { - "PTS": d["TPoints"], - "AST": d["TAssist"], - "BLK": d["TBlocks"], - "REB": d["TRebound"], - "DREB": d["TDefRebound"], - "OREB": d["TOffRebound"], - "STL": d["TSteal"], - "GAMES": d["TGameCount"], - } - milestone_career_checks = { - "PTS": d["CareerTPoints"], - "AST": d["CareerTAssist"], - "BLK": d["CareerTBlocks"], - "REB": d["CareerTRebound"], - "DREB": d["CareerTDefRebound"], - "OREB": d["CareerTOffRebound"], - "STL": d["CareerTSteal"], - "GAMES": d["CareerTGameCount"], - } - for milestone_type, value in milestone_checks.items(): - milestone_data = check_milestone( - value, milestone_type, d["NameGFX"], d["num"], "season" - ) - if milestone_data: - new_data_season.append(milestone_data) - for milestone_type_car, value_car in milestone_career_checks.items(): - milestone_data_car = check_milestone( - value_car, milestone_type_car, d["NameGFX"], d["num"], "league" - ) - if milestone_data_car: - new_data_career.append(milestone_data_car) - return new_data_season, new_data_career - - -columns_game = [ - "num", - # "roleShort", - "NameGFX", - "isOn", - # "flag", - "pts", - "pt-2", - "pt-3", - "pt-1", - "fg", - "ast", - "stl", - "blk", - "blkVic", - "dreb", - "oreb", - "reb", - "to", - "foul", - "fouled", - "plusMinus", - "dunk", - "kpi", - "time", -] -# print(cached_team1) -if cached_team1 and cached_team2: - team1_data = process_team_data(cached_team1, columns_game) - team2_data = process_team_data(cached_team2, columns_game) - - # team1_data["pts"] = pd.to_numeric(team1_data["pts"], errors="coerce") - # team2_data["pts"] = pd.to_numeric(team2_data["pts"], errors="coerce") - # team1_data["ast"] = pd.to_numeric(team1_data["ast"], errors="coerce") - # team2_data["ast"] = pd.to_numeric(team2_data["ast"], errors="coerce") - # team1_data["stl"] = pd.to_numeric(team1_data["stl"], errors="coerce") - # team2_data["stl"] = pd.to_numeric(team2_data["stl"], errors="coerce") - # team1_data["blk"] = pd.to_numeric(team1_data["blk"], errors="coerce") - # team2_data["blk"] = pd.to_numeric(team2_data["blk"], errors="coerce") - # team1_data["blkVic"] = pd.to_numeric(team1_data["blkVic"], errors="coerce") - # team2_data["blkVic"] = pd.to_numeric(team2_data["blkVic"], errors="coerce") - # team1_data["dreb"] = pd.to_numeric(team1_data["dreb"], errors="coerce") - # team2_data["dreb"] = pd.to_numeric(team2_data["dreb"], errors="coerce") - # team1_data["oreb"] = pd.to_numeric(team1_data["oreb"], errors="coerce") - # team2_data["oreb"] = pd.to_numeric(team2_data["oreb"], errors="coerce") - # team1_data["reb"] = pd.to_numeric(team1_data["reb"], errors="coerce") - # team2_data["reb"] = pd.to_numeric(team2_data["reb"], errors="coerce") - # team1_data["to"] = pd.to_numeric(team1_data["to"], errors="coerce") - # team2_data["to"] = pd.to_numeric(team2_data["to"], errors="coerce") - # team1_data["foul"] = pd.to_numeric(team1_data["foul"], errors="coerce") - # team2_data["foul"] = pd.to_numeric(team2_data["foul"], errors="coerce") - # team1_data["fouled"] = pd.to_numeric(team1_data["fouled"], errors="coerce") - # team2_data["fouled"] = pd.to_numeric(team2_data["fouled"], errors="coerce") - # team1_data["plusMinus"] = pd.to_numeric(team1_data["plusMinus"], errors="coerce") - # team2_data["plusMinus"] = pd.to_numeric(team2_data["plusMinus"], errors="coerce") - # team1_data["dunk"] = pd.to_numeric(team1_data["dunk"], errors="coerce") - # team2_data["dunk"] = pd.to_numeric(team2_data["dunk"], errors="coerce") - # team1_data["kpi"] = pd.to_numeric(team1_data["kpi"], errors="coerce") - # team2_data["kpi"] = pd.to_numeric(team2_data["kpi"], errors="coerce") - - # Стилизация данных - team1_styled = ( - team1_data.style.apply(highlight_grey, axis=1) - .apply(highlight_foul, subset="foul") - .apply(highlight_max, subset="pts") - ) - team2_styled = ( - team2_data.style.apply(highlight_grey, axis=1) - .apply(highlight_foul, subset="foul") - .apply(highlight_max, subset="pts") - ) - - # Вывод данных - col_player1, col_player2 = tab_temp_1.columns((5, 5)) - event1 = col_player1.dataframe( - team1_styled, - column_config=config, - hide_index=True, - height=460, - on_select="rerun", - selection_mode=[ - "single-row", - ], - ) - event2 = col_player2.dataframe( - team2_styled, - column_config=config, - hide_index=True, - height=460, - on_select="rerun", - selection_mode=[ - "single-row", - ], - ) - - # if event1.selection["rows"]: - # player_index = event1.selection["rows"][0] - # selected_player_1 = process_player_data(cached_team1, player_index) - # col_player1.dataframe( - # selected_player_1, - # column_config=config_season, - # hide_index=True, - # ) - # if event2.selection["rows"]: - # player_index = event2.selection["rows"][0] - # selected_player_2 = process_player_data(cached_team2, player_index) - # col_player2.dataframe( - # selected_player_2, - # column_config=config_season, - # hide_index=True, - # ) - if event1.selection and event1.selection.get("rows"): - selected_index1 = event1.selection["rows"][0] - st.session_state["player1"] = ( - selected_index1 # Сохранение состояния в session_state - ) - if st.session_state["player1"] is not None: - selected_player_1, player_data_1 = process_player_data( - cached_team1, st.session_state["player1"] - ) - if player_data_1["num"]: - z, a, b, c, d, e = col_player1.columns((1, 6, 1, 1, 1, 1)) - z.metric("Номер", player_data_1["num"], border=False) - a.metric("Игрок", player_data_1["NameGFX"], border=False) - b.metric("Амплуа", player_data_1["roleShort"], border=False) - c.metric("Возраст", player_data_1["age"], border=False) - d.metric("Рост", player_data_1["height"].split()[0], border=False) - e.metric("Вес", player_data_1["weight"].split()[0], border=False) - - col_player1.dataframe( - selected_player_1, - column_config=config_season, - hide_index=True, - ) - if event2.selection and event2.selection.get("rows"): - selected_index2 = event2.selection["rows"][0] - st.session_state["player2"] = ( - selected_index2 # Сохранение состояния в session_state - ) - if st.session_state["player2"] is not None: - selected_player_2, player_data_2 = process_player_data( - cached_team2, st.session_state["player2"] - ) - if player_data_2["num"]: - z, a, b, c, d, e = col_player2.columns((1, 6, 1, 1, 1, 1)) - z.metric("Номер", player_data_2["num"], border=False) - a.metric("Игрок", player_data_2["NameGFX"], border=False) - b.metric("Амплуа", player_data_2["roleShort"], border=False) - c.metric("Возраст", player_data_2["age"], border=False) - d.metric("Рост", player_data_2["height"].split()[0], border=False) - e.metric("Вес", player_data_2["weight"].split()[0], border=False) - - col_player2.dataframe( - selected_player_2, - column_config=config_season, - hide_index=True, - ) - - # if event2.selection and event2.selection.get("rows"): - # selected_index2 = event2.selection["rows"][0] - # st.session_state["player2"] = ( - # selected_index2 # Сохранение состояния в session_state - # ) - # selected_player_2, player_data_2 = process_player_data( - # cached_team2, selected_index2 - # ) - # st.session_state["player2_data"] = selected_player_2 - # if st.session_state["player2_data"]: - # col_player2.dataframe( - # st.session_state["player2_data"], - # column_config=config_season, - # hide_index=True, - # ) - - -# if cached_team_stats: -# cached_team_stats_new = [ -# cached_team_stats[0], -# *cached_team_stats[25:29], # Распаковка элементов среза -# cached_team_stats[7], -# cached_team_stats[33], -# *cached_team_stats[9:11], # Распаковка элементов среза -# *cached_team_stats[15:17], # Распаковка элементов среза -# ] - -# tab_temp_2.table( -# cached_team_stats_new, -# ) - -if isinstance(cached_team_stats, list) and len(cached_team_stats) >= 34: - cached_team_stats_new = [ - cached_team_stats[0], - *cached_team_stats[25:29], - cached_team_stats[7], - cached_team_stats[33], - *cached_team_stats[9:11], - *cached_team_stats[15:17], - ] - tab_temp_2.table(cached_team_stats_new) - -if isinstance(cached_referee, (list, pd.DataFrame)): - tab_temp_3.dataframe(cached_referee, height=600, column_config={"flag": st.column_config.ImageColumn("flag")}) - - -column_config_ref = { - "flag": st.column_config.ImageColumn( - "flag", - ), -} - -if cached_referee: - tab_temp_3.dataframe(cached_referee, height=600, column_config=column_config_ref) - - -def highlight_teams(s): - try: - if s.iloc[0] in ( - cached_game_online["result"]["team1"]["teamId"], - cached_game_online["result"]["team2"]["teamId"], - ): - return ["background-color: #FF4B4B"] * len(s) - else: - return [""] * len(s) - except NameError: - return [""] * len(s) - - -# if cached_standings: -# df_st = pd.json_normalize(cached_standings) -# cached_standings = df_st.style.apply(highlight_teams, axis=1) -# tab_temp_4.dataframe( -# cached_standings, -# column_config={ -# "logo": st.column_config.ImageColumn( -# "logo", -# ), -# }, -# hide_index=True, -# height=610, -# ) - -if cached_standings: - df_st = pd.json_normalize(cached_standings) - def highlight_teams(s): - try: - t1 = ((cached_game_online or {}).get("result") or {}).get("team1", {}).get("teamId") - t2 = ((cached_game_online or {}).get("result") or {}).get("team2", {}).get("teamId") - if s.iloc[0] in (t1, t2): - return ["background-color: #FF4B4B"] * len(s) - except Exception: - pass - return [""] * len(s) - styled = df_st.style.apply(highlight_teams, axis=1) - tab_temp_4.dataframe( - styled, - column_config={"logo": st.column_config.ImageColumn("logo")}, - hide_index=True, - height=610, - ) - - -# if cached_scores_quarter: -# column_config = {} - -# for quarter in ["Q1", "Q2", "Q3", "Q4", "OT1", "OT2", "OT3", "OT4"]: -# column_name = f"score_avg{quarter}" -# column_config[column_name] = st.column_config.NumberColumn( -# column_name, format="%.1f" -# ) -# columns_quarters_name = ["Q1", "Q2", "Q3", "Q4"] -# columns_quarters_name_ot = ["OT1", "OT2", "OT3", "OT4"] -# columns_quarters = tab_temp_5.columns((1, 1, 1, 1)) -# for index, col in enumerate(columns_quarters): -# df_col = [ -# { -# "team": cached_scores_quarter[0]["team"], -# "W": cached_scores_quarter[0][f"win{columns_quarters_name[index]}"], -# "L": cached_scores_quarter[0][f"lose{columns_quarters_name[index]}"], -# "D": cached_scores_quarter[0][f"draw{columns_quarters_name[index]}"], -# "PTS": cached_scores_quarter[0][f"score{columns_quarters_name[index]}"], -# "AVG": cached_scores_quarter[0][ -# f"score_avg{columns_quarters_name[index]}" -# ], -# }, -# { -# "team": cached_scores_quarter[1]["team"], -# "W": cached_scores_quarter[1][f"win{columns_quarters_name[index]}"], -# "L": cached_scores_quarter[1][f"lose{columns_quarters_name[index]}"], -# "D": cached_scores_quarter[1][f"draw{columns_quarters_name[index]}"], -# "PTS": cached_scores_quarter[1][f"score{columns_quarters_name[index]}"], -# "AVG": cached_scores_quarter[1][ -# f"score_avg{columns_quarters_name[index]}" -# ], -# }, -# ] -# col.write(columns_quarters_name[index]) -# col.dataframe(df_col) -# for index, col in enumerate(columns_quarters): -# df_col = [ -# { -# "team": cached_scores_quarter[0]["team"], -# "W": cached_scores_quarter[0][f"win{columns_quarters_name_ot[index]}"], -# "L": cached_scores_quarter[0][f"lose{columns_quarters_name_ot[index]}"], -# "D": cached_scores_quarter[0][f"draw{columns_quarters_name_ot[index]}"], -# "PTS": cached_scores_quarter[0][ -# f"score{columns_quarters_name_ot[index]}" -# ], -# "AVG": cached_scores_quarter[0][ -# f"score_avg{columns_quarters_name_ot[index]}" -# ], -# }, -# { -# "team": cached_scores_quarter[1]["team"], -# "W": cached_scores_quarter[1][f"win{columns_quarters_name_ot[index]}"], -# "L": cached_scores_quarter[1][f"lose{columns_quarters_name_ot[index]}"], -# "D": cached_scores_quarter[1][f"draw{columns_quarters_name_ot[index]}"], -# "PTS": cached_scores_quarter[1][ -# f"score{columns_quarters_name_ot[index]}" -# ], -# "AVG": cached_scores_quarter[1][ -# f"score_avg{columns_quarters_name_ot[index]}" -# ], -# }, -# ] -# col.write(columns_quarters_name_ot[index]) -# col.dataframe(df_col) - -if isinstance(cached_scores_quarter, list) and len(cached_scores_quarter) >= 2: - column_config = {} - for quarter in ["Q1", "Q2", "Q3", "Q4", "OT1", "OT2", "OT3", "OT4"]: - column_name = f"score_avg{quarter}" - column_config[column_name] = st.column_config.NumberColumn(column_name, format="%.1f") - - columns_quarters_name = ["Q1", "Q2", "Q3", "Q4"] - columns_quarters_name_ot = ["OT1", "OT2", "OT3", "OT4"] - columns_quarters = tab_temp_5.columns((1, 1, 1, 1)) - - # Основные четверти - for index, col in enumerate(columns_quarters): - q = columns_quarters_name[index] - df_col = [ - { - "team": cached_scores_quarter[0].get("team"), - "W": cached_scores_quarter[0].get(f"win{q}"), - "L": cached_scores_quarter[0].get(f"lose{q}"), - "D": cached_scores_quarter[0].get(f"draw{q}"), - "PTS": cached_scores_quarter[0].get(f"score{q}"), - "AVG": cached_scores_quarter[0].get(f"score_avg{q}"), - }, - { - "team": cached_scores_quarter[1].get("team"), - "W": cached_scores_quarter[1].get(f"win{q}"), - "L": cached_scores_quarter[1].get(f"lose{q}"), - "D": cached_scores_quarter[1].get(f"draw{q}"), - "PTS": cached_scores_quarter[1].get(f"score{q}"), - "AVG": cached_scores_quarter[1].get(f"score_avg{q}"), - }, - ] - col.write(q) - col.dataframe(df_col) - - # Овертаймы - for index, col in enumerate(columns_quarters): - q = columns_quarters_name_ot[index] - df_col = [ - { - "team": cached_scores_quarter[0].get("team"), - "W": cached_scores_quarter[0].get(f"win{q}"), - "L": cached_scores_quarter[0].get(f"lose{q}"), - "D": cached_scores_quarter[0].get(f"draw{q}"), - "PTS": cached_scores_quarter[0].get(f"score{q}"), - "AVG": cached_scores_quarter[0].get(f"score_avg{q}"), - }, - { - "team": cached_scores_quarter[1].get("team"), - "W": cached_scores_quarter[1].get(f"win{q}"), - "L": cached_scores_quarter[1].get(f"lose{q}"), - "D": cached_scores_quarter[1].get(f"draw{q}"), - "PTS": cached_scores_quarter[1].get(f"score{q}"), - "AVG": cached_scores_quarter[1].get(f"score_avg{q}"), - }, - ] - col.write(q) - col.dataframe(df_col) - - -# if cached_play_by_play and isinstance(cached_game_online, dict): -# plays = cached_game_online.get("result", {}).get("plays") -# if plays: -# tab_temp_6.table(cached_play_by_play) - -if isinstance(cached_play_by_play, list) and isinstance(cached_game_online, dict): - plays = (cached_game_online.get("result") or {}).get("plays") or [] - if plays: - tab_temp_6.table(cached_play_by_play) - - -# print(cached_game_online["result"]["plays"]) - -# if cached_game_online and cached_game_online["result"]["plays"]: -# columns_quarter = tab_temp_7.tabs(count_quarter) -# columns_quarter_for_st = [ -# "num", -# "NameGFX", -# "q_pts", -# "q_pt2", -# "q_pt3", -# "q_ft", -# "q_pt23", -# "q_ast", -# "q_stl", -# "q_blk", -# "q_reb", -# "q_to", -# "q_f", -# "q_f_on", -# "q_rnk", -# "q_time", -# ] -# for i in range(period_max): -# col_quarter1, col_quarter2 = columns_quarter[i].columns((5, 5)) -# key_quarter_team1 = f"team1_{i+1}" -# load_data_from_json(key_quarter_team1) -# key_quarter_team1 = st.session_state[key_quarter_team1] -# # print(key_quarter_team1) -# df_team1 = pd.DataFrame(key_quarter_team1) -# count_players_1 = len(df_team1) -# col_quarter1.dataframe( -# df_team1[columns_quarter_for_st].style.apply(highlight_max, subset="q_pts"), -# column_config=config, -# hide_index=True, -# height=38 * count_players_1 if count_players_1 > 10 else None, -# ) - -# key_quarter_team2 = f"team2_{i+1}" -# load_data_from_json(key_quarter_team2) -# key_quarter_team2 = st.session_state[key_quarter_team2] -# df_team2 = pd.DataFrame(key_quarter_team2) -# count_players_2 = len(df_team2) -# col_quarter2.dataframe( -# df_team2[columns_quarter_for_st].style.apply(highlight_max, subset="q_pts"), -# column_config=config, -# hide_index=True, -# height=38 * count_players_2 if count_players_2 > 10 else None, -# ) - -# if cached_team1 and cached_team2: -# data_team_season_1, data_team_career_1 = milestones(cached_team1) -# data_team_season_2, data_team_career_2 = milestones(cached_team2) - -# tab7_col1, tab7_col2 = tab_temp_8.columns((5, 5)) -# tab7_col1.dataframe(data_team_season_1) -# tab7_col2.dataframe(data_team_season_2) -# tab7_col1.dataframe(data_team_career_1) -# tab7_col2.dataframe(data_team_career_2) - - -def schedule_selected_team(team_id, data, game_id, selected, away_team_id): - columns = [ - "game.localDate", - "team1.name", - "team1.logo", - "game.score", - "team2.logo", - "team2.name", - "game.fullScore", - "win", - ] - df_schedule_new = data.loc[ - # (data["game.id"] < game_id) - # & - ( - (data["team1.teamId"].isin([team_id])) - | (data["team2.teamId"].isin([team_id])) - ) - ] - df_schedule_new.loc[:, "game.fullScore"] = df_schedule_new[ - "game.fullScore" - ].str.split(",") - conditions = [ - (df_schedule_new["team1.teamId"] == team_id) - & (df_schedule_new["game.score1"] > df_schedule_new["game.score2"]), - (df_schedule_new["team1.teamId"] == team_id) - & (df_schedule_new["game.score1"] < df_schedule_new["game.score2"]), - (df_schedule_new["team2.teamId"] == team_id) - & (df_schedule_new["game.score2"] > df_schedule_new["game.score1"]), - (df_schedule_new["team2.teamId"] == team_id) - & (df_schedule_new["game.score2"] < df_schedule_new["game.score1"]), - ] - values = [True, False, True, False] - - df_schedule_new = df_schedule_new.copy() - df_schedule_new.loc[:, "win"] = np.select(conditions, values, default=None) - mask = pd.Series(True, index=df_schedule_new.index) - - # Проверяем каждое выбранное условие и объединяем с маской - if selected: - if "Дома" in selected: - mask &= df_schedule_new["team1.teamId"] == team_id - if "В гостях" in selected: - mask &= df_schedule_new["team2.teamId"] == team_id - if "Выигрыши" in selected: - mask &= df_schedule_new["win"] == True - if "Поражения" in selected: - mask &= df_schedule_new["win"] == False - if "Друг с другом" in selected: - mask &= df_schedule_new["team1.teamId"].isin( - [away_team_id, team_id] - ) & df_schedule_new["team2.teamId"].isin([away_team_id, team_id]) - # print(selected) - return df_schedule_new[columns].loc[mask] - - -def get_in(d, path, default=None): - cur = d - for key in path: - if not isinstance(cur, dict): - return default - cur = cur.get(key, default) - if cur is default: - return default - return cur - -if tab_schedule: - if cached_schedule and "items" in cached_schedule: - cached_schedule = cached_schedule["items"] - pd_schedule = pd.json_normalize(cached_schedule) - - # team1_id = st.session_state["game_online"]["result"]["team1"]["teamId"] - # team1_name = st.session_state["game_online"]["result"]["team1"]["name"] - - # team2_id = st.session_state["game_online"]["result"]["team2"]["teamId"] - # team2_name = st.session_state["game_online"]["result"]["team2"]["name"] - - # game_id = st.session_state["game_online"]["result"]["game"]["id"] - - game_online = st.session_state.get("game_online") - team1_id = get_in(game_online, ["result", "team1", "teamId"]) - team1_name = get_in(game_online, ["result", "team1", "name"]) - team2_id = get_in(game_online, ["result", "team2", "teamId"]) - team2_name = get_in(game_online, ["result", "team2", "name"]) - game_id = get_in(game_online, ["result", "game", "id"]) - - - col1_schedule, col2_schedule = tab_schedule.columns((5, 5)) - options = ["Дома", "В гостях", "Выигрыши", "Поражения", "Друг с другом"] - selection1 = col1_schedule.segmented_control( - "Фильтр", options, selection_mode="multi", key="1" - ) - selection2 = col2_schedule.segmented_control( - "Фильтр", options, selection_mode="multi", key="2" - ) - - team1_data = schedule_selected_team( - team1_id, pd_schedule, game_id, selection1, team2_id - ) - team2_data = schedule_selected_team( - team2_id, pd_schedule, game_id, selection2, team1_id - ) - - def highlight_two_teams(s): - try: - if str(s.loc["team1.name"]) in ( - team1_name, - team2_name, - ) and str(s.loc["team2.name"]) in ( - team1_name, - team2_name, - ): - return ["background-color: #FF4B4B"] * len(s) - else: - return [""] * len(s) - except NameError: - return [""] * len(s) - - column_config = { - "team1.name": st.column_config.TextColumn("Команда1", width=150), - "team2.name": st.column_config.TextColumn("Команда2", width=150), - "game.score": st.column_config.TextColumn( - "Счёт", - ), - "game.localDate": st.column_config.TextColumn( - "Дата", - ), - "game.fullScore": st.column_config.Column( - "Счёт по четвертям", - ), - "team1.logo": st.column_config.ImageColumn("Лого1", width=50), - "team2.logo": st.column_config.ImageColumn("Лого2", width=50), - } - count_game_1 = len(team1_data) - count_game_2 = len(team2_data) - team1_data = team1_data.style.apply(highlight_two_teams, axis=1).apply( - color_win, subset="win" - ) - team2_data = team2_data.style.apply(highlight_two_teams, axis=1).apply( - color_win, subset="win" - ) - height1 = 38 * max(count_game_1, 10) - height2 = 38 * max(count_game_2, 10) - col1_schedule.dataframe( - team1_data, - hide_index=True, - height=int(min(height1, 1200)), - column_config=column_config, - ) - col2_schedule.dataframe( - team2_data, - hide_index=True, - height=int(min(height2, 1200)), - column_config=column_config, - ) - -# with open("PlayTypeID.json", "r", encoding="utf-8") as f: -# play_type_id = json.load(f) -# # print(play_type_id) - -# teams_data = cached_game_online["result"]["teams"] -# teams_temp = sorted( -# teams_data[1]["starts"], key=lambda x: x["playerNumber"], reverse=False -# ) + sorted(teams_data[2]["starts"], key=lambda x: x["playerNumber"], reverse=False) -# # print(teams_temp) -# list_fullname = [None] + [ -# f"({x['displayNumber']}) {x['firstName']} {x['lastName']}" -# for x in teams_temp -# if x["startRole"] == "Player" -# ] - - -def get_play_info(play): - # Ищем в списке play_type_id элемент, у которого PlayTypeID совпадает с play - for item in play_type_id: - if item["PlayTypeID"] == play: - return item["PlayInfoSite"] - return None # Если совпадение не найдено - - -def get_player_name(start_num): - # Ищем в списке teams_temp элемент, у которого startNum совпадает с temp_data_pbp["startNum"] - for player in teams_temp: - if player["startNum"] == start_num: - return f"{player['firstName']} {player['lastName']}" - return None # Если совпадение не найдено - - -def get_event_time(row): - if row != 0: - time_str = 6000 - row - if time_str == 0: - time_str = "0:00" - else: - time_str = time_str // 10 - time_str = f"{time_str // 60}:{str(time_str % 60).zfill(2)}" - return time_str - - -# with tab_pbp: -# temp_data_pbp = pd.DataFrame(cached_game_online["result"]["plays"]) -# col1_pbp, col2_pbp = tab_pbp.columns((3, 4)) -# option_player = col1_pbp.selectbox( -# "Выбрать игрока", -# list_fullname, -# ) - -# options_pbp = ["1 очко", "2 очка", "3 очка"] -# selection_pbp = col1_pbp.segmented_control( -# "Фильтр", options_pbp, selection_mode="multi", key=3 -# ) -# if not temp_data_pbp.empty: -# options_quarter = [ -# (f"{i+1} четверть" if i + 1 < 5 else f"{i-3} овертайм") -# for i in range(max(temp_data_pbp["period"])) -# ] -# selection_quarter = col1_pbp.segmented_control( -# "Выбор четверти", options_quarter, selection_mode="multi", key=4 -# ) -# temp_data_pbp["info"] = temp_data_pbp["play"].map(get_play_info) -# temp_data_pbp["who"] = temp_data_pbp["startNum"].map(get_player_name) -# temp_data_pbp["time"] = temp_data_pbp["sec"].map(get_event_time) - -# # Инициализируем маску фильтрации (все строки по умолчанию) -# mask1 = pd.Series(True, index=temp_data_pbp.index) - -# if option_player: -# start_number = [ -# x["startNum"] -# for x in teams_temp -# if f"({x['displayNumber']}) {x['firstName']} {x['lastName']}" -# == option_player -# ][0] -# mask1 &= temp_data_pbp["startNum"] == start_number - -# # Фильтрация по типу очков -# if selection_pbp: -# plays_mapping = {"1 очко": 1, "2 очка": 2, "3 очка": 3} -# selected_plays = [plays_mapping[play] for play in selection_pbp] -# mask1 &= temp_data_pbp["play"].isin(selected_plays) - -# # Фильтрация по четверти -# if selection_quarter: -# select_quart = [ -# index + 1 -# for index, quarter in enumerate(options_quarter) -# if quarter in selection_quarter -# ] -# mask1 &= temp_data_pbp["period"].isin(select_quart) - -# # Применяем маску фильтрации -# filtered_data_pbp = temp_data_pbp[mask1] - -# count_pbp = len(filtered_data_pbp) -# column_pbp = [ -# "num", -# "info", -# "who", -# "period", -# "time", -# ] -# column_config_pbp = { -# "info": st.column_config.TextColumn(width="medium"), -# "who": st.column_config.TextColumn(width="large"), -# } -# col2_pbp.dataframe( -# filtered_data_pbp[column_pbp], -# column_config=column_config_pbp, -# hide_index=True, -# height=(38 * count_pbp if count_pbp > 10 else None), -# ) - -# Безопасная загрузка PlayTypeID -try: - with open("PlayTypeID.json", "r", encoding="utf-8") as f: - play_type_id = json.load(f) -except (FileNotFoundError, json.JSONDecodeError): - play_type_id = [] - -# Безопасное получение команд и игроков -# teams_section = ((cached_game_online or {}).get("result") or {}).get("teams") or {} -# starts1 = (teams_section.get(1) or {}).get("starts") or [] -# starts2 = (teams_section.get(2) or {}).get("starts") or [] - -teams_section = ((cached_game_online or {}).get("result") or {}).get("teams") or {} - -# Если teams_section — список (например, [{"starts": [...]}, {...}]) -if isinstance(teams_section, list): - if len(teams_section) >= 2: - starts1 = (teams_section[0] or {}).get("starts") or [] - starts2 = (teams_section[1] or {}).get("starts") or [] - elif len(teams_section) == 1: - starts1 = (teams_section[0] or {}).get("starts") or [] - starts2 = [] - 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" -] - -def get_play_info(play): - for item in play_type_id: - if isinstance(item, dict) and item.get("PlayTypeID") == play: - return item.get("PlayInfoSite") - return None - -def get_player_name(start_num): - for player in teams_temp: - if player.get("startNum") == start_num: - return f"{player.get('firstName','')} {player.get('lastName','')}".strip() - return None - -def get_event_time(row): - if isinstance(row, (int, float)) and row != 0: - time_val = 6000 - int(row) - if time_val <= 0: - return "0:00" - time_val //= 10 - return f"{time_val // 60}:{str(time_val % 60).zfill(2)}" - return None - -with tab_pbp: - 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)) - option_player = col1_pbp.selectbox("Выбрать игрока", list_fullname) - - options_pbp = ["1 очко", "2 очка", "3 очка"] - selection_pbp = col1_pbp.segmented_control("Фильтр", options_pbp, selection_mode="multi", key=3) - - if not temp_data_pbp.empty and "period" in temp_data_pbp.columns: - options_quarter = [ - (f"{i+1} четверть" if i + 1 < 5 else f"{i-3} овертайм") - for i in range(int(temp_data_pbp["period"].max())) - ] - selection_quarter = col1_pbp.segmented_control("Выбор четверти", options_quarter, selection_mode="multi", key=4) - - temp_data_pbp["info"] = temp_data_pbp["play"].map(get_play_info) - temp_data_pbp["who"] = temp_data_pbp["startNum"].map(get_player_name) - temp_data_pbp["time"] = temp_data_pbp["sec"].map(get_event_time) - - mask1 = pd.Series(True, index=temp_data_pbp.index) - - if option_player: - # безопасный поиск startNum - for x in teams_temp: - display = f"({x.get('displayNumber')}) {x.get('firstName','')} {x.get('lastName','')}".strip() - if display == option_player: - mask1 &= temp_data_pbp["startNum"] == x.get("startNum") - break - - if selection_pbp: - plays_mapping = {"1 очко": 1, "2 очка": 2, "3 очка": 3} - selected_plays = [plays_mapping[p] for p in selection_pbp if p in plays_mapping] - mask1 &= temp_data_pbp["play"].isin(selected_plays) - - if selection_quarter: - select_quart = [i+1 for i, q in enumerate(options_quarter) if q in selection_quarter] - mask1 &= temp_data_pbp["period"].isin(select_quart) - - filtered_data_pbp = temp_data_pbp[mask1] - count_pbp = len(filtered_data_pbp) - - column_pbp = ["num", "info", "who", "period", "time"] - column_config_pbp = { - "info": st.column_config.TextColumn(width="medium"), - "who": st.column_config.TextColumn(width="large"), - } - col2_pbp.dataframe( - filtered_data_pbp[column_pbp], - column_config=column_config_pbp, - hide_index=True, - height=(38 * count_pbp if count_pbp > 10 else None), - ) - else: - st.info("Данных play-by-play нет.") diff --git a/vmix_url_replace.py b/vmix_url_replace.py deleted file mode 100644 index f339e95..0000000 --- a/vmix_url_replace.py +++ /dev/null @@ -1,79 +0,0 @@ -import os -import shutil -import argparse -import xml.etree.ElementTree as ET -from urllib.parse import urlparse, unquote - -def localname(tag: str) -> str: - return tag.split('}', 1)[-1].lower() - -def extract_filename(u: str) -> str: - s = (u or "").strip() - if not s: - return "" - p = urlparse(s) - path = p.path if p.scheme else s - path = path.replace("\\", "/") - name = path.split("/")[-1] - return unquote(name) - -def replace_urls_in_vmix(xml_path: str, prefix_url: str) -> int: - if not os.path.isfile(xml_path): - raise FileNotFoundError(f"Файл не найден: {xml_path}") - - backup_path = xml_path + ".bak" - shutil.copy2(xml_path, backup_path) - - tree = ET.parse(xml_path) - root = tree.getroot() - - replaced = 0 - for node in root.iter(): - if localname(node.tag).startswith("datasource") and node.get("friendlyName") == "JSON": - for sub in node.iter(): - if localname(sub.tag) == "url": - old = (sub.text or "").strip() - # ✅ проверка: если уже новый URL — пропускаем - if old.startswith(prefix_url): - print(f"Пропускаем — уже новый URL: {old}") - continue - tail = extract_filename(old) - if not tail: - continue - new_full = prefix_url + tail - if old != new_full: - print(f"{old} -> {new_full}") - sub.text = new_full - replaced += 1 - - # сохраняем без XML декларации - tree.write(xml_path, encoding="utf-8", xml_declaration=False) - return replaced - - -def main(): - parser = argparse.ArgumentParser( - description="Заменяет в datasource[friendlyName=JSON] на PREFIX + имя файла." - ) - parser.add_argument("--file", "-f", required=True, help="Путь к .vmix файлу") - parser.add_argument("--url", "-u", required=False, help="Префикс нового URL (например, https://gfx.tvstart.ru/app/static/gfx_)") - parser.add_argument("--pause", action="store_true", help="Ожидать Enter в конце (удобно при запуске двойным кликом)") - args = parser.parse_args() - - prefix = args.url or input("Введите префикс нового URL (например, https://gfx.tvstart.ru/app/static/gfx_): ").strip() - if not prefix: - print("Префикс пустой — ничего не сделано.") - return - - try: - count = replace_urls_in_vmix(args.file, prefix) - print(f"Готово. Заменено тегов : {count}") - print(f"Резервная копия: {args.file}.bak") - except Exception as e: - print("Ошибка:", e) - - if args.pause: - input("Нажмите Enter для выхода...") - -if __name__ == "__main__": - main()