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()