From 478557f3ad0f5359179942ea84a032dcb773e235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AE=D1=80=D0=B8=D0=B9=20=D0=A7=D0=B5=D1=80=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE?= Date: Wed, 19 Aug 2026 15:07:17 +0300 Subject: [PATCH] first commit --- README.md | 341 +++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 10 ++ 2 files changed, 351 insertions(+) create mode 100644 README.md create mode 100644 requirements.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..9aa78cf --- /dev/null +++ b/README.md @@ -0,0 +1,341 @@ +# Hockey Stat2TV / UI Builder — BUILD 2026.07.20.13 + +## Базы данных + +Проект использует две удалённые PostgreSQL-базы: + +```text +WFL_DATABASE_URL → только чтение аккаунтов WFL для авторизации +HOCKEY_DATABASE_URL → все хоккейные данные и рабочие сессии +``` + +Локальная SQLite отключена. Файл `data/hockey.sqlite3` не создаётся и не +используется. Если `HOCKEY_DATABASE_URL` отсутствует, указывает не на +PostgreSQL или сервер недоступен, приложение прекращает запуск. + +## Настройка + +1. Создайте отдельную PostgreSQL-базу `hockey` рядом с WFL либо используйте уже + подготовленную удалённую базу. +2. Скопируйте `.env.example` в `.env`. +3. Укажите реальные строки подключения: + +```env +HOCKEY_AUTH_MODE=wfl +WFL_DATABASE_URL=postgresql+psycopg://postgres:password@localhost:5432/wfl_db +HOCKEY_DATABASE_URL=postgresql+psycopg://postgres:password@localhost:5432/hockey +HOCKEY_COOKIE_SECURE=false +``` + +Подробная настройка прав: `REMOTE_DATABASE.md`. + +## Запуск + +```powershell +START.bat +``` + +Перед запуском интерфейса скрипт проверяет удалённую базу. При успешном +соединении выводится: + +```text +[Hockey DB] PostgreSQL connection OK: server:5432/hockey +``` + +Проверка из браузера после запуска: + +```text +http://127.0.0.1:8000/api/hockey/database/status +``` + +Ответ содержит безопасные сведения о подключении без логина и пароля: + +```json +{ + "ok": true, + "backend": "postgresql", + "host": "server", + "port": 5432, + "database": "hockey", + "remote_only": true +} +``` + +## Что хранится в удалённой hockey-базе + +- турниры, расписание и матчи; +- счёт, периоды, ОТ/Б и арены; +- команды, игроки, тренеры, судьи и страны; +- составы и назначения судей; +- события и удаления; +- сезонная и турнирная статистика; +- `powerplay`, `rank`, `shots` и доступность необязательных ресурсов; +- операторские и веб-сессии; +- кэш полученных XML/JSON и история синхронизации. + +Stat2TV остаётся внешним источником XML/JSON, а не базой приложения. + +## Автоматическая схема + +При первом запуске на пустой базе приложение создаёт таблицы автоматически. +При обновлении сборки оно добавляет отсутствующие неключевые поля. Пользователю +`hockey_app` необходимы права `CREATE`, `ALTER`, `SELECT`, `INSERT`, `UPDATE`, +`DELETE` и права на sequences в схеме базы. + +## Интерфейс + +Сборка включает загрузку матчей Stat2TV, отдельную информационную вкладку «Расписание», события, play-by-play, карты бросков, +матчевую и сезонную статистику, турнирные таблицы, большинство, рейтинг, +справочники игроков/тренеров/судей/стран, операторские события и vMix JSON. + +## Расписание команд + +Вкладка «Расписание» содержит два режима: + +- «Матчи дня» — информационные карточки всех матчей выбранной лиги на текущую дату; +- «Матчи команд» — полный календарь команд текущего открытого матча: левая команда слева, правая справа. + +В командном режиме доступны фильтры по статусу, месту проведения и сортировке. Очные матчи выбранных команд выделяются золотой рамкой и подписью «Очная встреча». Карточки остаются информационными и не открывают другой матч. + +## Управление периодом и буллитами + +В шапке выбранного матча доступен ручной выбор текущего периода. Состояние сохраняется в хоккейной PostgreSQL-базе. + +Для турниров со стадией `regular` после вкладки «Игра» появляется вкладка «Буллиты». В ней можно выбрать основную серию на 3 или 5 попыток, назначать игроков обеих команд, отмечать гол/промах и при равном счёте добавлять дополнительные серии по одной попытке каждой команде. + +## BUILD 2026.07.20.7 + +- Выпадающий список текущего периода больше не закрывается при обновлении таймера и фоновой синхронизации. +- В регулярном чемпионате доступны три периода, один овертайм, буллиты и завершение матча. +- В плей-офф буллиты скрыты и запрещены на сервере. +- Для плей-офф поддерживается неограниченная последовательность овертаймов: после выбора текущего овертайма автоматически появляется следующий. +- Старое значение `ot` в плей-офф автоматически преобразуется в `ot1`. + + +## BUILD 2026.07.20.7 + +Во вкладке «Буллиты» добавлен независимый быстрый поиск для левой и правой команды. Поиск фильтрует состав по номеру, фамилии и имени. + + +## BUILD 2026.07.20.8 — таймер и численные составы + +В общих настройках Stat2TV добавлен раздел «Таймер матча»: + +- длительность обычного периода; +- длительность овертайма регулярного чемпионата; +- длительность каждого овертайма плей-офф; +- автоматический сброс основного таймера при смене периода. + +При смене периода сбрасывается только основной таймер. Активные удаления и журнал удалений сохраняются. Для нового матча используется длительность обычного периода. + +Добавлен раздел «Удаления и численные составы»: + +- базовый состав для основного времени, овертайма регулярки и овертайма плей-офф; +- минимальное количество полевых игроков; +- отдельный режим подписи для каждой фазы: `PP`, только состав (`5×4`, `4×3`) или `PP + состав`; +- настраиваемые подписи большинства и меньшинства; +- опциональное отображение `PK`. + +По умолчанию основное время отображает `PP`, овертайм регулярки — фактический состав `4×3`, овертайм плей-офф — `PP`. Текущее численное соотношение и подписи также доступны в `scoreboard.json` и `penalties.json`. + +## BUILD 2026.07.20.9 — видимые настройки таймеров + +В административном окне «Настройки» появилась отдельная вкладка **«Таймеры и составы»**. В ней можно менять длительность обычного периода, овертайма регулярного чемпионата и каждого овертайма плей-офф, автоматический сброс времени при смене периода, базовые численные составы и правила подписей PP/PK. Значения сохраняются через общий `/api/hockey/settings` и применяются без перезапуска. + + +## BUILD 2026.07.20.10 — двуязычная матрица численных составов + +В разделе **Шестерёнка → Таймеры и составы** добавлены отдельные RU/EN-подписи +для каждого численного состояния основного времени, овертайма регулярного +чемпионата и овертайма плей-офф. + +Овертайм регулярки теперь учитывает совпадающие удаления без взаимного +погашения: одно удаление — 4×3, два удаления одной команды — 5×3, по одному +у каждой команды — 4×4, по два — 5×5. + + +## BUILD 2026.07.20.11 — мгновенное отображение численного состава + +- Подготовленное удаление учитывается в численном составе сразу после выбора игрока/команды, нарушения и длительности. +- Запуск таймера удаления больше не требуется для появления `5×4`, `4×4`, `5×3`, `4×3` и настроенной RU/EN-подписи в верхнем счёте. +- Незавершённые заготовки без команды, нарушения или длительности в расчёт не попадают. +- Ответ сохранения таймеров немедленно передаётся в шапку матча без ожидания фонового опроса. + +## BUILD 2026.07.20.12 — конструктор vMix JSON + +Из проекта Golf перенесён переносимый модуль настроек vMix и адаптирован к хоккейным данным. + +Откройте **Шестерёнка → vMix JSON**. В разделе доступны: + +- отдельные JSON-пресеты для верхнего счёта, информации о матче, составов, судей, удалений, событий и полного матча; +- включение и перестановка колонок, изменение имени выходного поля и источника данных; +- вычисляемые колонки и формулы из библиотеки vMix; +- дополнительные объединяемые источники (`joins`); +- просмотр доступных полей выбранного хоккейного источника; +- предварительный просмотр результата для постоянного персонального канала vMix; +- импорт настроек из JSON или ZIP и экспорт текущих пресетов. + +Адрес пользовательского JSON формируется для постоянного канала аккаунта и языка: + +```text +/vmix/hockey/channel/{channel}/{language}/custom/{key}.json +``` + +Поддерживаемые источники: `info`, `scoreboard`, `home_lineup`, `away_lineup`, +`officials`, `penalties`, `events`, `full_match`. + +Чтобы получить рабочую ссылку и список полей, сначала откройте матч. Канал создаётся +один раз для WFL-аккаунта и затем сохраняет тот же ключ при входе с другого браузера, +перезагрузке страницы и выборе нового матча. Настройки vMix хранятся в +`settings/vmix_json.json` отдельно от подключения Stat2TV. При импорте +гольф-проектов старые endpoint-адреса автоматически заменяются хоккейными, а +неподдерживаемые источники переводятся на `scoreboard` без удаления колонок. + + + +## BUILD 2026.07.20.13 — постоянные персональные каналы vMix + +- Ссылки vMix больше не зависят от временной операторской сессии. +- Для каждого WFL-аккаунта создаётся один постоянный случайный ключ канала. +- При выборе нового матча обновляется привязка канала, но URL в проекте vMix не меняется. +- Пользователь может переключать только канал своего аккаунта; чужой канал нельзя изменить через API. +- Логин не публикуется в URL и не используется как секрет. +- Для отдельных студий рекомендуется создать отдельные WFL-аккаунты: один аккаунт = один постоянный канал. +- Старые адреса `/vmix/hockey/session/...` оставлены как совместимые алиасы, чтобы существующие проекты не перестали читать данные. + +Новый рекомендуемый формат: + +```text +/vmix/hockey/channel/{channel}/{language}/custom/{key}.json +``` + +## vMix Agent Bridge (build 2026.08.11.4) + +Новая схема подключения не требует логина внутри agent и не скачивает `.vmix` проект. Готовый Windows x64 agent находится в `agent/agent.exe`. + +- agent регистрирует постоянный Device ID через `/ws/hockey-agent`; +- вошедший WFL-пользователь видит устройства в панели **vMix Agent** и прикрепляет своё; +- на аккаунт можно сохранить несколько устройств, но только одно является активным эфирным; +- при выборе следующего матча активный agent получает новый `assignment_id` + `match_id` без перезапуска vMix; +- после reconnect pairing и текущий матч восстанавливаются с сервера; +- команды vMix защищены проверкой текущих `assignment_id` и `match_id`; +- build `2026.08.11.4` добавляет первый реальный канал команд: тестовый `SetText` из web с ожиданием `command.ack` от agent и ответа локального vMix. + +Подробности запуска: `agent/README.md`. + + +## Mapping Editor / Agent 1.3.0 — build 2026.08.12.1 + +- Agent 1.3.0 автоматически инвентаризирует текущий vMix: Inputs, key/number/type и GT-поля. +- Сервер сохраняет fingerprint и последнюю структуру проекта в PostgreSQL. +- Admin получил раздел `Настройки → Mapping`: создание профиля из активного Agent, редактирование связей, обновление структуры и удаление профиля. +- Оператор не может менять mapping; в панели vMix Agent он только видит активный профиль и его версию. +- Mapping привязан к fingerprint графического проекта, а не к матчу или устройству. +- При изменении mapping сервер немедленно отправляет `mapping.assigned` всем Agent с той же структурой vMix. + + +## Tournament drawer / schedule fallback — build 2026.08.12.2 + +- Исправлена grid-разметка вкладки «Все турниры»: summary больше не сжимается длинным списком, список скроллится только внутри drawer. +- Автоматический fallback расписания теперь после tournament-scoped файлов проверяет полный набор Stat2TV endpoint-форм, включая варианты с `tournament` и `date` query-параметрами. +- Источник `online.khl.ru` намеренно не скрапится: официальный сайт блокирует автоматические запросы и запрещает автоматизированное извлечение без разрешения. + +## Build 2026.08.17.1 — Visual Mapping Editor + +Mapping теперь настраивается визуально: admin выбирает vMix Input, затем конкретное GT-поле и связывает его с человеческим источником данных текущего матча. В редакторе одновременно показываются понятное название источника, его живое значение и технический data_key. Для связанного текстового/графического поля доступен безопасный тест через выбранный online Agent. + + +## Build 2026.08.17.2 — Context Variables + SQL Data Sources + +Mapping Editor больше не зависит от захардкоженного списка data_key. В PostgreSQL добавлены: + +- `hockey_mapping_context_variables` — определения системных и пользовательских идентификаторов; +- `hockey_mapping_context_values` — значения с изоляцией по account/session/match; +- `hockey_mapping_sql_sources` — admin-managed read-only SQL SELECT источники. + +В `Настройки → Mapping` доступны вкладки `Связи vMix`, `Переменные`, `SQL источники`. Колонки SQL автоматически становятся ключами `source.column`, а текущие значения выбранного матча сразу видны в Visual Mapping Editor. SQL выполняется в read-only транзакции с коротким statement timeout на PostgreSQL. + + +### Build 2026.08.17.3 +Разделы `Переменные` и `SQL источники` вынесены прямо в верхнее меню Настроек рядом с Mapping. Загрузка Mapping API стала отказоустойчивой: ошибка одного endpoint не скрывает остальные разделы. + +### Build 2026.08.17.5 + +- SQL Data Source с несколькими строками теперь доступен в Mapping как полноценная таблица. +- Можно выбрать конкретную строку и конкретный столбец без изменения SQL-запроса. +- Ячейки получают внутренний адрес `source.row.N.column`; старый `source.column` сохранён и означает первую строку. +- Каталог Mapping читает до 250 строк каждого включённого SQL-источника в read-only режиме. +- В табличном picker есть поиск строки по любому значению. +- vMix Inputs сортируются по номеру Input, затем по названию. +- Добавлен быстрый поиск Input по номеру, названию, key и типу. + +### Build 2026.08.17.6 + +- Mapping: для SQL-источника добавлен явный селектор `Источник → строка → столбец` с живым значением выбранной ячейки. +- Выбранную SQL-ячейку можно напрямую связать с текущим Text/Source полем vMix; технический ключ формируется автоматически. +- Кнопка `Тест` переименована в `Тест поля`, чтобы было понятно, что она отправляет только одну связь. +- Добавлена кнопка `Применить Input`, отправляющая все настроенные поля текущего Input, включая SQL-ячейки, одним batch-запросом. +- Кнопка общего применения переименована в `Применить весь Mapping`. + + +### Build 2026.08.17.7 +- Исправлен SQL Preview в Mapping: кнопка «Проверить SQL» больше не заменяет несохранённый запрос дефолтным SELECT. +- Черновик формы SQL (код, название, категория, описание, SQL, enabled, sort order) сохраняется при Preview и при ошибке выполнения. + + +### Build 2026.08.17.11 — game date fallback from match details + +- Если расписание выбранного матча не содержит дату, `game_date` заполняется из детальной карточки Stat2TV/KHL. +- Поддерживается локализованный формат вида `16 августа 2026, Вс 13:00:00`; в PostgreSQL он сохраняется как настоящий `DATE` (`2026-08-16`). +- Время `13:00` также извлекается из этой же строки, если отдельное поле времени отсутствует. +- Пустой date/time из последующего refresh расписания больше не стирает значение, уже восстановленное из карточки матча. +- Если в расписании дата есть, она остаётся приоритетной и detail fallback её не перезаписывает. + +## Build 2026.08.17.12 — game_date recovery + +- Localized KHL/Stat2TV dates such as `16 августа 2026, Вс` are normalized and stored in `hockey_games.game_date` as a real DATE (`2026-08-16`). +- Schedule upsert now recovers date/time from `start_datetime_raw` if parsed date/time are missing. +- Detail-card save performs a final recovery from the persisted raw datetime before commit. +- Startup backfill repairs existing rows where `game_date IS NULL` but `start_datetime_raw` contains a usable date. +- Unicode NBSP/thin spaces are normalized before date parsing. + +## Build 2026.08.17.13 — SQL Auto Refresh → vMix + +- SQL Data Source can now enable **Автообновление в vMix** and configure a refresh interval from 1 to 3600 seconds. +- Auto refresh runs server-side, so the Mapping admin page does not need to stay open. +- Only Mapping fields linked to the due SQL source are evaluated/sent. +- vMix commands are deduplicated: unchanged values are not sent again. +- Recommended: clocks = 1 s; live statistics = 2–5 s; standings/non-live data = 10–60 s or manual. +- PostgreSQL time formats such as `TO_CHAR(NOW(), 'HH24:MI:SS')` no longer produce false context parameters (`:MI`, `:SS`). PostgreSQL casts such as `value::text` are also ignored by the context-parameter parser. +- SQL help now includes current-time and timezone examples. + + +## Build 2026.08.17.14 +- SQL Source preview no longer hides rows after the first 8. +- Preview renders all rows returned by the server (up to 250) inside a scrollable table with a sticky header. + + +## Build 2026.08.17.15 — series Mapping +- SQL table picker in Mapping now has a real 230–430 px result grid and scroll; rows are no longer visually squeezed below the controls. +- Linked SQL table cells expose `Автосвязать столбец`: one seed such as `Name1.Text ← roster.row.1.fio` expands to sequential GT fields and SQL rows. +- Added `Размножить строку`: configure all columns of one roster row once (for example number + fio), then clone that row pattern across the remaining SQL rows. +- Sequence detection is generic: it detects the strongest numeric token in GT field names rather than requiring a hard-coded `PlayerN` naming convention. +- A confirmation preview shows generated links before they are written into the unsaved Mapping profile. + + +## Build 2026.08.17.16 — Mapping field filters + fast vMix batch + +- vMix Input fields in Mapping are split into three selectors: `Text` (`.Text`), `Image` (`.Source`) and `Color` (`.Color`). +- Added `Скрывать связанные` toggle for large GT titles. +- Mapping field kind now preserves `color` as a separate UI type while runtime uses the existing vMix text-value command path. +- New Agent 1.4.0 supports `vmix.batch`: the server sends the whole resolved Mapping in one WebSocket frame and receives one batch ACK. +- Agent executes independent local vMix HTTP commands with a small worker pool and a reusable keep-alive HTTP client. +- Server automatically falls back to legacy one-command-at-a-time transport for Agent < 1.4.0. +- Empty Mapping values now keep `Value=` in the vMix request, so generated empty roster rows can clear old title text. +- Match switch, language switch, full Mapping apply and `Применить Input` use batch transport when Agent 1.4.0 is connected. + +## Нормализованная статистика — build 30 + +Добавлено отдельное SQL-хранение матчевой статистики команд, сезонной статистики игроков/команд, строк standings и powerplay/rank. Исходный RAW Stat2TV сохраняется. Подробности: `NORMALIZED_STATISTICS_DB.md`. + +Проверка: `GET /api/hockey/database/statistics-status?tournament_id=`. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4a3b816 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +fastapi>=0.115,<1.0 +uvicorn[standard]>=0.30,<1.0 +httpx>=0.27,<1.0 +SQLAlchemy>=2.0,<3.0 +psycopg[binary]>=3.2,<4.0 +python-dotenv>=1.0,<2.0 + +requests>=2.32,<3.0 +beautifulsoup4>=4.12,<5.0 +curl_cffi>=0.7,<1.0