фикс 14
This commit is contained in:
831
README.md
831
README.md
@@ -1,230 +1,771 @@
|
|||||||
# ⚽ Match Management & vMix Integration System
|
# ⚽ VMIX Football Broadcast System
|
||||||
|
|
||||||
Полноценная система управления футбольными матчами с live-обновлением,
|
<p align="center">
|
||||||
парсингом данных и интеграцией с vMix.
|
<img src="https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white" alt="Python">
|
||||||
|
<img src="https://img.shields.io/badge/FastAPI-0.115+-009688?logo=fastapi&logoColor=white" alt="FastAPI">
|
||||||
|
<img src="https://img.shields.io/badge/PostgreSQL-15+-4169E1?logo=postgresql&logoColor=white" alt="PostgreSQL">
|
||||||
|
<img src="https://img.shields.io/badge/WebSocket-Realtime-7C3AED" alt="WebSocket">
|
||||||
|
<img src="https://img.shields.io/badge/vMix-Integration-FF6A00" alt="vMix">
|
||||||
|
<img src="https://img.shields.io/badge/status-active-success" alt="Status">
|
||||||
|
</p>
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
> Система управления футбольными трансляциями с интеграцией в **vMix**, админ-панелью, live-обновлением матчей, генерацией данных для графики и WebSocket-взаимодействием с операторскими клиентами.
|
||||||
|
|
||||||
# 📌 Описание
|
---
|
||||||
|
|
||||||
Проект состоит из нескольких ключевых частей:
|
## 📌 Что это за проект
|
||||||
|
|
||||||
- FastAPI сервер (админка + API)
|
Проект предназначен для подготовки и сопровождения футбольных трансляций. Он объединяет в одном приложении:
|
||||||
- Scheduler (live-обновления матчей)
|
|
||||||
- Парсеры (игры, расписание, таблица)
|
|
||||||
- PostgreSQL база данных
|
|
||||||
- WebSocket сервер для vMix
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
- администрирование матчей, команд, игроков, тренеров, судей и стадионов;
|
||||||
|
- работу с составами и формациями на матч;
|
||||||
|
- генерацию данных для эфирной графики в vMix;
|
||||||
|
- создание и выгрузку `.vmix`-проекта;
|
||||||
|
- приём и отправку команд в vMix-клиенты через WebSocket;
|
||||||
|
- фоновое отслеживание матчей и обновление live-данных;
|
||||||
|
- синхронизацию расписания, игроков, команд и турнирной таблицы.
|
||||||
|
|
||||||
# 🧱 Архитектура системы
|
По текущей структуре проект ориентирован на внутреннюю production/операторскую эксплуатацию, а не на публичный API-сервис.
|
||||||
|
|
||||||
┌──────────────┐
|
---
|
||||||
│ Scheduler │
|
|
||||||
│ │
|
|
||||||
│ matches_loop │
|
|
||||||
│ standings │
|
|
||||||
└──────┬───────┘
|
|
||||||
│
|
|
||||||
┌──────────────┼──────────────┐
|
|
||||||
│ │ │
|
|
||||||
▼ ▼ ▼
|
|
||||||
live_match_worker parser_game parser_standings
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
Database
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
FastAPI
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
vMix
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
## ✨ Основные возможности
|
||||||
|
|
||||||
# 🗄 Структура базы данных
|
### Админка и матч-центр
|
||||||
|
- авторизация администратора;
|
||||||
|
- список матчей и выбор матча для сессии;
|
||||||
|
- рабочее пространство матча;
|
||||||
|
- редактирование составов;
|
||||||
|
- редактирование формаций;
|
||||||
|
- управление судьями;
|
||||||
|
- управление событиями матча.
|
||||||
|
|
||||||
## Таблица: matches
|
### База футбольных сущностей
|
||||||
|
- игроки;
|
||||||
|
- команды;
|
||||||
|
- тренеры;
|
||||||
|
- судьи;
|
||||||
|
- стадионы;
|
||||||
|
- турнирная таблица;
|
||||||
|
- составы на матч;
|
||||||
|
- матчевые сессии для операторов.
|
||||||
|
|
||||||
Поле Тип Описание
|
### Интеграция с vMix
|
||||||
------------- ----------- ----------------------
|
- генерация `.vmix`-проекта;
|
||||||
id int ID матча
|
- формирование имени файла проекта;
|
||||||
external_id text ID матча на сайте
|
- генерация JSON-данных для графики;
|
||||||
match_date timestamp дата и время
|
- публикация команд в подключённые vMix-клиенты;
|
||||||
status text статус матча
|
- получение динамических значений из vMix API.
|
||||||
home_score int счет хозяев
|
|
||||||
away_score int счет гостей
|
|
||||||
updated_at timestamp последнее обновление
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
### Live-логика
|
||||||
|
- планировщик, который отслеживает матчи дня;
|
||||||
|
- запуск watcher-потоков перед матчем;
|
||||||
|
- опрос live-данных каждые 60 секунд;
|
||||||
|
- обновление статуса матча и счёта;
|
||||||
|
- обновление турнирной таблицы.
|
||||||
|
|
||||||
## Таблица: standings
|
### Парсинг и синхронизация
|
||||||
|
- парсинг матчей;
|
||||||
|
- парсинг игроков;
|
||||||
|
- парсинг расписания;
|
||||||
|
- парсинг таблицы;
|
||||||
|
- синхронизация сущностей в БД через сервисный слой.
|
||||||
|
|
||||||
Поле Тип Описание
|
---
|
||||||
---------- ----- ----------
|
|
||||||
team_id int команда
|
|
||||||
position int позиция
|
|
||||||
points int очки
|
|
||||||
played int сыграно
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
## 🏗 Архитектура
|
||||||
|
|
||||||
## Таблица: match_lineup_players
|
Проект построен вокруг классической схемы:
|
||||||
|
|
||||||
- составы команд
|
```text
|
||||||
- старт + запас
|
Parsers -> Services -> Repositories -> PostgreSQL
|
||||||
|
|
|
||||||
|
+-> vMix JSON / .vmix generation
|
||||||
|
+-> FastAPI admin UI
|
||||||
|
+-> WebSocket command bus
|
||||||
|
+-> Scheduler / live workers
|
||||||
|
```
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
### Слои проекта
|
||||||
|
|
||||||
## Таблица: match_events
|
#### `parsers/`
|
||||||
|
Получают данные из внешних источников. Используются для матчей, игроков, расписания, команд и таблиц.
|
||||||
|
|
||||||
- события матча (голы, карточки и т.д.)
|
#### `services/`
|
||||||
|
Содержат прикладную бизнес-логику: синхронизацию данных, авторизацию, подготовку JSON для vMix.
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
#### `repositories/`
|
||||||
|
Отвечают за доступ к PostgreSQL. Здесь собраны CRUD-операции и специализированные запросы.
|
||||||
|
|
||||||
# 🔄 Основные процессы
|
#### `templates/` + `static/`
|
||||||
|
HTML-шаблоны Jinja2, CSS, JS и статические файлы интерфейса.
|
||||||
|
|
||||||
## 1. Scheduler
|
#### `vmix/`
|
||||||
|
Логика генерации vMix-проекта и служебные функции, связанные с эфирной интеграцией.
|
||||||
|
|
||||||
Работает как отдельный процесс:
|
#### `scheduler.py`
|
||||||
|
Фоновый мониторинг матчей и обновление live-состояния.
|
||||||
|
|
||||||
### Каждую минуту:
|
#### `agent.py`
|
||||||
|
Отдельный клиент для связи между vMix и сервером через WebSocket.
|
||||||
|
|
||||||
- ищет матчи на сегодня
|
---
|
||||||
- запускает worker за 1 минуту до начала
|
|
||||||
|
|
||||||
### Worker:
|
## 📁 Структура проекта
|
||||||
|
|
||||||
- раз в минуту:
|
```text
|
||||||
- парсит сайт
|
vmix/
|
||||||
- обновляет счет и статус
|
├── app.py # Основной FastAPI сервер
|
||||||
- останавливается при finished
|
├── agent.py # WebSocket/vMix агент
|
||||||
|
├── db.py # Подключение к PostgreSQL
|
||||||
|
├── scheduler.py # Фоновый live scheduler
|
||||||
|
├── main.py # Demo/seed сценарий
|
||||||
|
├── deploy.sh # Скрипт деплоя
|
||||||
|
├── requirements.txt # Python зависимости
|
||||||
|
├── wfl.sql # Основная схема БД
|
||||||
|
│
|
||||||
|
├── parsers/
|
||||||
|
│ ├── parser_game.py # Парсинг/обновление данных матча
|
||||||
|
│ ├── parser_players.py # Парсинг игроков
|
||||||
|
│ ├── parser_schedule.py # Парсинг расписания
|
||||||
|
│ ├── parser_standings.py # Парсинг таблицы
|
||||||
|
│ └── parser_teams.py # Парсинг команд
|
||||||
|
│
|
||||||
|
├── repositories/
|
||||||
|
│ ├── audit_log_repository.py
|
||||||
|
│ ├── auth_repository.py
|
||||||
|
│ ├── coach_repository.py
|
||||||
|
│ ├── match_clock_repository.py
|
||||||
|
│ ├── match_coach_repository.py
|
||||||
|
│ ├── match_event_repository.py
|
||||||
|
│ ├── match_formation_repository.py
|
||||||
|
│ ├── match_lineup_repository.py
|
||||||
|
│ ├── match_referee_repository.py
|
||||||
|
│ ├── match_repository.py
|
||||||
|
│ ├── match_session_repository.py
|
||||||
|
│ ├── match_view_repository.py
|
||||||
|
│ ├── player_repository.py
|
||||||
|
│ ├── referee_repository.py
|
||||||
|
│ ├── stadium_repository.py
|
||||||
|
│ ├── standings_repository.py
|
||||||
|
│ ├── team_coach_repository.py
|
||||||
|
│ ├── team_repository.py
|
||||||
|
│ └── team_squad_repository.py
|
||||||
|
│
|
||||||
|
├── services/
|
||||||
|
│ ├── auth_service.py
|
||||||
|
│ ├── game_service.py
|
||||||
|
│ ├── players_service.py
|
||||||
|
│ ├── schedule_service.py
|
||||||
|
│ ├── standings_service.py
|
||||||
|
│ ├── teams_service.py
|
||||||
|
│ └── vmix_json_service.py
|
||||||
|
│
|
||||||
|
├── sql/
|
||||||
|
│ └── 001_auth.sql # Таблицы админ-пользователей и сессий
|
||||||
|
│
|
||||||
|
├── static/
|
||||||
|
│ ├── script.js
|
||||||
|
│ ├── styles.css
|
||||||
|
│ ├── smith.ico
|
||||||
|
│ └── images/
|
||||||
|
│ └── vmix_icon.png
|
||||||
|
│
|
||||||
|
├── templates/
|
||||||
|
│ ├── login.html
|
||||||
|
│ ├── matches.html
|
||||||
|
│ ├── match_workspace.html
|
||||||
|
│ ├── download_vmix.html
|
||||||
|
│ ├── admin_db_index.html
|
||||||
|
│ ├── admin_db_players.html
|
||||||
|
│ ├── admin_db_player_edit.html
|
||||||
|
│ ├── admin_db_referees.html
|
||||||
|
│ ├── admin_db_referee_edit.html
|
||||||
|
│ ├── admin_db_coaches.html
|
||||||
|
│ ├── admin_db_coach_edit.html
|
||||||
|
│ ├── admin_db_stadiums.html
|
||||||
|
│ ├── admin_db_stadium_edit.html
|
||||||
|
│ ├── admin_db_teams.html
|
||||||
|
│ └── admin_db_team_edit.html
|
||||||
|
│
|
||||||
|
└── vmix/
|
||||||
|
├── __init__.py
|
||||||
|
└── vmix_service.py # Генерация .vmix файла
|
||||||
|
```
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
---
|
||||||
|
|
||||||
## 2. Обновление турнирной таблицы
|
## 🧰 Технологии
|
||||||
|
|
||||||
- вызывается `parser_standings`
|
| Категория | Технологии |
|
||||||
- обновляет standings в БД
|
|---|---|
|
||||||
- запускается раз в минуту
|
| Backend | FastAPI |
|
||||||
|
| Валидация | Pydantic |
|
||||||
|
| Шаблоны | Jinja2 |
|
||||||
|
| База данных | PostgreSQL + psycopg2 |
|
||||||
|
| Парсинг | requests + BeautifulSoup4 |
|
||||||
|
| Realtime | WebSocket |
|
||||||
|
| Интеграция с эфиром | vMix API + XML |
|
||||||
|
| Конфигурация | python-dotenv |
|
||||||
|
| Дополнительно | numpy |
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
### Зависимости из `requirements.txt`
|
||||||
|
|
||||||
## 3. FastAPI
|
```txt
|
||||||
|
fastapi>=0.115,<1.0
|
||||||
|
uvicorn[standard]>=0.30,<1.0
|
||||||
|
pydantic>=2.0,<3.0
|
||||||
|
jinja2>=3.1,<4.0
|
||||||
|
python-multipart>=0.0.9,<1.0
|
||||||
|
requests>=2.31,<3.0
|
||||||
|
websockets>=12,<16
|
||||||
|
beautifulsoup4>=4.12,<5.0
|
||||||
|
psycopg2-binary>=2.9,<3.0
|
||||||
|
python-dotenv>=1.0,<2.0
|
||||||
|
numpy>=1.26,<3.0
|
||||||
|
```
|
||||||
|
|
||||||
Обеспечивает:
|
Также в файле указан дополнительный приватный индекс и пакет `nasio`, поэтому для полноценной установки в целевой среде может понадобиться доступ к внутреннему package registry.
|
||||||
|
|
||||||
- админку
|
---
|
||||||
- API для vMix
|
|
||||||
- WebSocket соединения
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
## 🚀 Быстрый старт
|
||||||
|
|
||||||
# 📡 API Endpoints
|
## 1. Клонирование репозитория
|
||||||
|
|
||||||
## Основные
|
```bash
|
||||||
|
git clone <YOUR_REPOSITORY_URL>
|
||||||
|
cd vmix
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Установка зависимостей
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Настройка переменных окружения
|
||||||
|
|
||||||
|
Создай файл `.env` в корне проекта:
|
||||||
|
|
||||||
|
```env
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_NAME=wfl_db
|
||||||
|
DB_USER=postgres
|
||||||
|
DB_PASSWORD=your_password
|
||||||
|
```
|
||||||
|
|
||||||
|
`db.py` загружает эти параметры через `python-dotenv` и использует их для подключения к PostgreSQL.
|
||||||
|
|
||||||
|
## 4. Инициализация базы данных
|
||||||
|
|
||||||
|
Сначала разверни основную схему:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
psql -U postgres -d wfl_db -f wfl.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
Затем создай таблицы авторизации:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
psql -U postgres -d wfl_db -f sql/001_auth.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Создание администратора
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/create_admin.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт запросит:
|
||||||
|
- `Username`
|
||||||
|
- `Password`
|
||||||
|
|
||||||
|
После этого создаст запись в таблице `admin_users`.
|
||||||
|
|
||||||
|
## 6. Запуск приложения
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uvicorn app:app --host 0.0.0.0 --port 8000 --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
После запуска приложение будет доступно по адресу:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://localhost:8000
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Авторизация
|
||||||
|
|
||||||
|
В проекте используется сессионная авторизация для админки.
|
||||||
|
|
||||||
|
### Что есть в коде
|
||||||
|
- таблица `admin_users`;
|
||||||
|
- таблица `auth_sessions`;
|
||||||
|
- проверка пароля в `services/auth_service.py`;
|
||||||
|
- cookie/session-based доступ к админским маршрутам;
|
||||||
|
- logout с отзывом сессии.
|
||||||
|
|
||||||
|
### SQL-таблицы авторизации
|
||||||
|
Файл `sql/001_auth.sql` создаёт:
|
||||||
|
- `admin_users`
|
||||||
|
- `auth_sessions`
|
||||||
|
- индексы по токену, пользователю и активности
|
||||||
|
|
||||||
|
### Скрипт создания пользователя
|
||||||
|
`python scripts/create_admin.py`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥 Интерфейс и рабочие зоны
|
||||||
|
|
||||||
|
### Основные страницы
|
||||||
|
- `/login` — вход администратора;
|
||||||
|
- `/` — редирект/входная точка;
|
||||||
|
- `/admin/matches` — список матчей для администратора;
|
||||||
|
- `/admin/session/{session_token}` — рабочее пространство матча;
|
||||||
|
- `/admin/session/{session_token}/download-vmix-page` — страница выгрузки проекта;
|
||||||
|
- `/admin/db` — индекс админского раздела БД.
|
||||||
|
|
||||||
|
### Разделы админ-БД
|
||||||
|
- игроки;
|
||||||
|
- судьи;
|
||||||
|
- тренеры;
|
||||||
|
- стадионы;
|
||||||
|
- команды.
|
||||||
|
|
||||||
|
Для каждой сущности есть минимум список и форма редактирования.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 HTTP и WebSocket API
|
||||||
|
|
||||||
|
Ниже — маршруты, которые реально определены в `app.py`.
|
||||||
|
|
||||||
|
### Аутентификация
|
||||||
|
|
||||||
|
| Метод | Маршрут | Назначение |
|
||||||
|
|---|---|---|
|
||||||
|
| GET | `/login` | страница входа |
|
||||||
|
| POST | `/login` | авторизация |
|
||||||
|
| POST | `/logout` | выход |
|
||||||
|
|
||||||
|
### Матчи и сессии
|
||||||
|
|
||||||
|
| Метод | Маршрут | Назначение |
|
||||||
|
|---|---|---|
|
||||||
|
| GET | `/admin/matches` | список матчей |
|
||||||
|
| GET | `/admin/matches/{match_id}/select` | выбор матча и создание/открытие сессии |
|
||||||
|
| GET | `/admin/session/{session_token}` | рабочее пространство матча |
|
||||||
|
| POST | `/admin/session/{session_token}/load-match-data` | загрузка/обновление данных матча |
|
||||||
|
| POST | `/admin/session/{session_token}/close` | закрытие сессии |
|
||||||
|
| GET | `/admin/session/{session_token}/download-vmix-page` | HTML-страница выгрузки vMix |
|
||||||
|
| GET | `/admin/session/{session_token}/download-vmix` | скачивание `.vmix` |
|
||||||
|
|
||||||
|
### Формации и составы
|
||||||
|
|
||||||
|
| Метод | Маршрут | Назначение |
|
||||||
|
|---|---|---|
|
||||||
|
| POST | `/admin/session/{session_token}/formations/apply` | применить preset формации к игрокам |
|
||||||
|
| POST | `/admin/session/{session_token}/formations/save` | сохранить формации |
|
||||||
|
| GET | `/admin/session/{session_token}/squad-editor-data` | получить данные редактора состава |
|
||||||
|
| POST | `/admin/session/{session_token}/squad-editor-save` | сохранить состав |
|
||||||
|
| POST | `/admin/session/{session_token}/referees/save` | сохранить судей на матч |
|
||||||
|
|
||||||
|
### События матча
|
||||||
|
|
||||||
|
| Метод | Маршрут | Назначение |
|
||||||
|
|---|---|---|
|
||||||
|
| GET | `/admin/session/{session_token}/events` | список событий |
|
||||||
|
| POST | `/admin/session/{session_token}/event` | создать событие |
|
||||||
|
| PUT | `/admin/session/{session_token}/event/{event_id}` | обновить событие |
|
||||||
|
| DELETE | `/admin/session/{session_token}/event/{event_id}` | удалить событие |
|
||||||
|
| DELETE | `/admin/session/{session_token}/events` | очистить все события |
|
||||||
|
|
||||||
|
### Справочники БД
|
||||||
|
|
||||||
|
| Метод | Маршрут | Назначение |
|
||||||
|
|---|---|---|
|
||||||
|
| GET | `/admin/db` | главная админ-БД |
|
||||||
|
| GET/POST | `/admin/db/players` / `/admin/db/players/{player_id}/edit` | список/редактирование игроков |
|
||||||
|
| GET/POST | `/admin/db/referees` / `/admin/db/referees/{referee_id}/edit` | список/редактирование судей |
|
||||||
|
| GET/POST | `/admin/db/coaches` / `/admin/db/coaches/{coach_id}/edit` | список/редактирование тренеров |
|
||||||
|
| GET/POST | `/admin/db/stadiums` / `/admin/db/stadiums/{stadium_id}/edit` | список/редактирование стадионов |
|
||||||
|
| GET/POST | `/admin/db/teams` / `/admin/db/teams/{team_id}/edit` | список/редактирование команд |
|
||||||
|
|
||||||
|
### vMix JSON endpoints
|
||||||
|
|
||||||
|
| Метод | Маршрут | Назначение |
|
||||||
|
|---|---|---|
|
||||||
|
| GET | `/vmix/session/{session_token}/home-lineup` | стартовый состав хозяев |
|
||||||
|
| GET | `/vmix/session/{session_token}/away-lineup` | стартовый состав гостей |
|
||||||
|
| GET | `/vmix/session/{session_token}/home-bench` | запасные хозяев |
|
||||||
|
| GET | `/vmix/session/{session_token}/away-bench` | запасные гостей |
|
||||||
|
| GET | `/vmix/session/{session_token}/info` | информация о матче |
|
||||||
|
| GET | `/vmix/session/{session_token}/standings` | турнирная таблица |
|
||||||
|
| GET | `/vmix/session/{session_token}/schedule` | расписание/тур |
|
||||||
|
| GET | `/vmix/session/{session_token}/home-formations` | формация хозяев |
|
||||||
|
| GET | `/vmix/session/{session_token}/away-formations` | формация гостей |
|
||||||
|
| GET | `/vmix/session/{session_token}/scoreboard` | данные для счётчика |
|
||||||
|
| GET | `/vmix/session/{session_token}/match-events` | данные по событиям матча |
|
||||||
|
|
||||||
|
### Команды для vMix-клиентов
|
||||||
|
|
||||||
|
| Метод | Маршрут | Назначение |
|
||||||
|
|---|---|---|
|
||||||
|
| POST | `/api/vmix/publish-command` | отправить команду в vMix-клиент(ы) |
|
||||||
|
| GET | `/api/vmix/clients` | список подключённых клиентов |
|
||||||
|
| WS | `/ws/vmix-client` | WebSocket-канал клиентов |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎬 Интеграция с vMix
|
||||||
|
|
||||||
|
### Что делает сервер
|
||||||
|
Сервер:
|
||||||
|
- создаёт матчевые сессии;
|
||||||
|
- готовит JSON для графики;
|
||||||
|
- собирает и отдаёт `.vmix`-проект;
|
||||||
|
- отправляет команды в подключённые клиентские агенты.
|
||||||
|
|
||||||
|
### Что делает агент `agent.py`
|
||||||
|
Агент — это отдельное приложение, которое запускается рядом с vMix и выполняет роль моста между сервером и локальным vMix API.
|
||||||
|
|
||||||
|
#### В коде агента есть:
|
||||||
|
- `VMIX_API = "http://127.0.0.1:8088/api"`
|
||||||
|
- `WS_BASE = "wss://wfl.tvstart.ru/ws/vmix-client"`
|
||||||
|
- чтение XML-ответа vMix;
|
||||||
|
- извлечение `dynamic/value1`, `dynamic/value2` и других значений;
|
||||||
|
- регистрация клиента в WebSocket;
|
||||||
|
- reconnect-логика.
|
||||||
|
|
||||||
|
### Как это работает в общем
|
||||||
|
1. Оператор открывает матч в админке.
|
||||||
|
2. Создаётся матчевая сессия с `session_token`.
|
||||||
|
3. Сервер отдаёт JSON и/или `.vmix`-файл.
|
||||||
|
4. Локальный агент подключается по WebSocket.
|
||||||
|
5. Сервер отправляет команды конкретному клиенту, группе или оператору.
|
||||||
|
6. Агент применяет команды в локальном vMix через HTTP API.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧾 Генерация JSON для графики
|
||||||
|
|
||||||
|
Логика сосредоточена в `services/vmix_json_service.py`.
|
||||||
|
|
||||||
|
### По коду видно, что сервис формирует:
|
||||||
|
- стартовые составы;
|
||||||
|
- запасных;
|
||||||
|
- информацию о матче;
|
||||||
|
- турнирную таблицу;
|
||||||
|
- расписание тура;
|
||||||
|
- формации команд;
|
||||||
|
- scoreboard-информацию;
|
||||||
|
- события матча;
|
||||||
|
- данные для показа авторов голов.
|
||||||
|
|
||||||
|
### Особенности реализации
|
||||||
|
- строятся полные имена игроков;
|
||||||
|
- добавляются суффиксы капитана и вратаря;
|
||||||
|
- формируются пути к фотографиям игроков;
|
||||||
|
- используются логотипы команд и специальные варианты логотипов для некоторых клубов;
|
||||||
|
- матчевая информация собирается SQL-запросами по сессии.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Генерация `.vmix` проекта
|
||||||
|
|
||||||
|
Файл `vmix/vmix_service.py` используется для:
|
||||||
|
- сборки бинарного содержимого vMix-проекта;
|
||||||
|
- генерации имени файла;
|
||||||
|
- выдачи файла пользователю через FastAPI.
|
||||||
|
|
||||||
|
В `app.py` для этого используются:
|
||||||
|
- `build_vmix_project_bytes`
|
||||||
|
- `build_vmix_filename`
|
||||||
|
|
||||||
|
Это означает, что оператор может открыть страницу сессии и скачать готовый `.vmix`-проект под конкретный матч.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⏱ Scheduler и live-мониторинг
|
||||||
|
|
||||||
|
`scheduler.py` — это фоновый процесс, который поднимается на старте приложения:
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.on_event("startup")
|
||||||
|
def start_scheduler():
|
||||||
|
import threading
|
||||||
|
thread = threading.Thread(target=run_scheduler, daemon=True)
|
||||||
|
thread.start()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ключевые интервалы
|
||||||
|
|
||||||
|
```python
|
||||||
|
MATCH_START_LEAD_MINUTES = 1
|
||||||
|
LIVE_MATCH_POLL_SECONDS = 60
|
||||||
|
MATCHES_LOOP_SECONDS = 60
|
||||||
|
STANDINGS_LOOP_SECONDS = 60
|
||||||
|
WORKER_ERROR_RETRY_SECONDS = 30
|
||||||
|
WORKER_MAX_ERRORS_IN_ROW = 20
|
||||||
|
```
|
||||||
|
|
||||||
|
### Что делает scheduler
|
||||||
|
- получает матчи на сегодня из БД;
|
||||||
|
- определяет, какие матчи уже пора мониторить;
|
||||||
|
- запускает отдельные worker-потоки;
|
||||||
|
- обновляет status/home_score/away_score в таблице матчей;
|
||||||
|
- вызывает обновление турнирной таблицы;
|
||||||
|
- ведёт реестр активных worker'ов.
|
||||||
|
|
||||||
|
### Источник live-данных
|
||||||
|
По текущему коду live-страница матча запрашивается с:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://wfl.rfs.ru/match/{match_id}
|
||||||
|
```
|
||||||
|
|
||||||
|
HTML разбирается через BeautifulSoup.
|
||||||
|
|
||||||
|
### Важное замечание
|
||||||
|
В `fetch_match_live_data()` есть незавершённая часть: функция частично реализована и в конце всё ещё содержит `NotImplementedError`. То есть scheduler уже встроен, но live-парсинг требует аккуратной доработки, чтобы считать его полностью production-ready.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗄 Репозитории и доменные сущности
|
||||||
|
|
||||||
|
По составу `repositories/` проект работает со следующими сущностями:
|
||||||
|
|
||||||
|
### Пользователи и аудит
|
||||||
|
- `auth_repository.py`
|
||||||
|
- `audit_log_repository.py`
|
||||||
|
|
||||||
### Матчи
|
### Матчи
|
||||||
|
- `match_repository.py`
|
||||||
|
- `match_session_repository.py`
|
||||||
|
- `match_view_repository.py`
|
||||||
|
- `match_clock_repository.py`
|
||||||
|
- `match_event_repository.py`
|
||||||
|
|
||||||
- GET /admin/matches
|
### Составы и формации
|
||||||
- GET /admin/session/{session_token}
|
- `match_lineup_repository.py`
|
||||||
|
- `match_formation_repository.py`
|
||||||
|
- `team_squad_repository.py`
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
### Официальные лица и стадионы
|
||||||
|
- `referee_repository.py`
|
||||||
|
- `match_referee_repository.py`
|
||||||
|
- `coach_repository.py`
|
||||||
|
- `match_coach_repository.py`
|
||||||
|
- `team_coach_repository.py`
|
||||||
|
- `stadium_repository.py`
|
||||||
|
|
||||||
### vMix
|
### Команды, игроки, таблица
|
||||||
|
- `team_repository.py`
|
||||||
|
- `player_repository.py`
|
||||||
|
- `standings_repository.py`
|
||||||
|
|
||||||
- GET /vmix/session/{session_token}/info
|
Это хороший признак разделённой архитектуры: доступ к данным отделён от HTTP-слоя и от прикладной логики.
|
||||||
- GET /vmix/session/{session_token}/standings
|
|
||||||
- GET /vmix/session/{session_token}/schedule
|
|
||||||
- GET /vmix/session/{session_token}/scoreboard
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
---
|
||||||
|
|
||||||
### WebSocket
|
## 🔄 Сервисы синхронизации
|
||||||
|
|
||||||
/ws/vmix-client
|
В `services/` есть отдельные сервисы:
|
||||||
|
|
||||||
Функции: - регистрация клиентов - heartbeat - отправка команд
|
- `teams_service.py`
|
||||||
|
- `schedule_service.py`
|
||||||
|
- `players_service.py`
|
||||||
|
- `standings_service.py`
|
||||||
|
- `game_service.py`
|
||||||
|
- `auth_service.py`
|
||||||
|
- `vmix_json_service.py`
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
### Demo-режим
|
||||||
|
`main.py` показывает, как можно программно наполнить систему тестовыми данными:
|
||||||
|
|
||||||
# ⚙️ Запуск проекта
|
- создаются 2 команды;
|
||||||
|
- создаётся матч;
|
||||||
|
- добавляются игроки;
|
||||||
|
- заполняется турнирная таблица.
|
||||||
|
|
||||||
## 1. Установка
|
Запуск:
|
||||||
|
|
||||||
pip install -r requirements.txt
|
```bash
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
Это удобно для первичной проверки БД и шаблонного сценария разработки.
|
||||||
|
|
||||||
## 2. Настройка БД
|
---
|
||||||
|
|
||||||
Отредактировать:
|
## 🧪 Полезные команды
|
||||||
|
|
||||||
db.py
|
### Проверка подключения к БД
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
```bash
|
||||||
|
python db.py
|
||||||
|
```
|
||||||
|
|
||||||
## 3. Запуск
|
### Создание администратора
|
||||||
|
|
||||||
### API
|
```bash
|
||||||
|
python scripts/create_admin.py
|
||||||
|
```
|
||||||
|
|
||||||
uvicorn app:app --reload
|
### Demo-наполнение
|
||||||
|
|
||||||
### Scheduler
|
```bash
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
python scheduler.py
|
### Запуск сервера
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
```bash
|
||||||
|
uvicorn app:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
# ❗ ВАЖНО
|
---
|
||||||
|
|
||||||
Scheduler должен запускаться отдельно.
|
## 🖼 Скриншоты
|
||||||
|
|
||||||
НЕЛЬЗЯ:
|
Ниже заготовки под реальные скриншоты интерфейса. Когда будут реальные изображения, просто положи их в репозиторий и обнови пути.
|
||||||
|
|
||||||
run_scheduler()
|
```md
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
```
|
||||||
|
|
||||||
внутри FastAPI.
|
---
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
## ⚠️ Ограничения и важные замечания
|
||||||
|
|
||||||
# 🔧 Что нужно реализовать
|
### 1. Документация OpenAPI отключена
|
||||||
|
В `app.py` явно выключены:
|
||||||
|
- `/docs`
|
||||||
|
- `/redoc`
|
||||||
|
- `/openapi.json`
|
||||||
|
|
||||||
## fetch_match_live_data()
|
Это нормально для внутреннего production-режима, но неудобно для внешних интеграций.
|
||||||
|
|
||||||
def fetch_match_live_data(match_row):
|
### 2. Live scheduler требует доработки
|
||||||
return {
|
`fetch_match_live_data()` ещё не завершена до конца и сейчас выглядит как заготовка с частичной логикой.
|
||||||
"status": "live",
|
|
||||||
"home_score": 1,
|
|
||||||
"away_score": 0
|
|
||||||
}
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
### 3. Есть Windows-специфичные элементы
|
||||||
|
В JSON-сервисе и агенте встречаются Windows-пути и логика работы с иконкой консоли. Это значит, что часть инфраструктуры ориентирована на Windows-машину оператора.
|
||||||
|
|
||||||
# 🚀 Рекомендации
|
### 4. Есть внешняя зависимость от приватного Python registry
|
||||||
|
В `requirements.txt` указан `--extra-index-url`, поэтому разворачивание в другой среде может потребовать доступов.
|
||||||
|
|
||||||
- запускать scheduler отдельно
|
### 5. Есть жёстко заданные интеграционные значения
|
||||||
- использовать 1 worker для API
|
Например:
|
||||||
- добавить логирование
|
- `http://127.0.0.1:8088/api`
|
||||||
- обрабатывать ошибки парсинга
|
- `wss://wfl.tvstart.ru/ws/vmix-client`
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
Для production лучше вынести их в `.env`.
|
||||||
|
|
||||||
# 📌 Dev режим
|
---
|
||||||
|
|
||||||
uvicorn app:app --reload
|
## 🔮 Что можно улучшить
|
||||||
python scheduler.py
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
### Инфраструктура
|
||||||
|
- добавить Dockerfile и `docker-compose.yml`;
|
||||||
|
- вынести конфигурацию целиком в `.env`;
|
||||||
|
- добавить healthcheck и monitoring;
|
||||||
|
- настроить CI/CD.
|
||||||
|
|
||||||
# 🧠 Production
|
### Backend
|
||||||
|
- включить структурированное логирование;
|
||||||
|
- покрыть ключевые места тестами;
|
||||||
|
- заменить часть threading-логики на более управляемый background orchestration;
|
||||||
|
- валидацию live-парсеров сделать устойчивее.
|
||||||
|
|
||||||
- API отдельно
|
### Безопасность
|
||||||
- Scheduler отдельно
|
- ограничить rate limit для логина;
|
||||||
- supervisor / systemd
|
- добавить CSRF-защиту, если нужна;
|
||||||
|
- вынести секреты и URL в окружение;
|
||||||
|
- расширить аудит действий администратора.
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
### API и DX
|
||||||
|
- вернуть внутреннюю OpenAPI-документацию под флагом окружения;
|
||||||
|
- добавить Postman/Insomnia collection;
|
||||||
|
- оформить контракт JSON-ответов для графики.
|
||||||
|
|
||||||
# 📬 Контакты
|
### UI/UX
|
||||||
|
- добавить больше навигации в админке;
|
||||||
|
- улучшить визуальный статус live-сессий;
|
||||||
|
- добавить быстрые действия в матч-центре.
|
||||||
|
|
||||||
Для доработок и улучшений --- пиши 👍
|
---
|
||||||
|
|
||||||
|
## 🛠 Пример локального сценария запуска
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. установить зависимости
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 2. создать .env
|
||||||
|
cp .env.example .env # если появится шаблон
|
||||||
|
|
||||||
|
# 3. поднять БД и применить SQL
|
||||||
|
psql -U postgres -d wfl_db -f wfl.sql
|
||||||
|
psql -U postgres -d wfl_db -f sql/001_auth.sql
|
||||||
|
|
||||||
|
# 4. создать администратора
|
||||||
|
python scripts/create_admin.py
|
||||||
|
|
||||||
|
# 5. при необходимости заполнить демо-данными
|
||||||
|
python main.py
|
||||||
|
|
||||||
|
# 6. запустить сервер
|
||||||
|
uvicorn app:app --host 0.0.0.0 --port 8000 --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤝 Вклад в проект
|
||||||
|
|
||||||
|
Если проект будет развиваться дальше, рекомендуется принять минимальные правила contribution:
|
||||||
|
|
||||||
|
1. отдельная ветка на каждую фичу;
|
||||||
|
2. PR с описанием изменений;
|
||||||
|
3. проверка SQL-миграций перед merge;
|
||||||
|
4. ручная проверка vMix-сценария и матчевого workflow.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📄 Лицензия
|
||||||
|
|
||||||
|
В текущем архиве лицензия отдельно не обнаружена.
|
||||||
|
|
||||||
|
Если проект внутренний — можно оставить private/internal use only.
|
||||||
|
Если репозиторий будет публичным — добавь подходящую лицензию, например MIT, Apache-2.0 или другую нужную команде.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 👨💻 Итог
|
||||||
|
|
||||||
|
Этот проект — это не просто CRUD-приложение, а полноценный операторский инструмент для футбольной трансляции:
|
||||||
|
|
||||||
|
- FastAPI-сервер с HTML-интерфейсом;
|
||||||
|
- PostgreSQL как основной источник данных;
|
||||||
|
- сессионная админ-авторизация;
|
||||||
|
- матчевые рабочие сессии;
|
||||||
|
- составы, формации, события и судьи;
|
||||||
|
- JSON и `.vmix` для эфирной графики;
|
||||||
|
- WebSocket-мост для операторских клиентов;
|
||||||
|
- scheduler для live-матчей и обновления данных.
|
||||||
|
|
||||||
|
Если нужно, следующим сообщением я могу так же сделать ещё и:
|
||||||
|
|
||||||
|
- `README_EN.md` на английском;
|
||||||
|
- `docs/API.md` с описанием всех маршрутов;
|
||||||
|
- `docker-compose.yml` для локального запуска;
|
||||||
|
- `.env.example`;
|
||||||
|
- более «маркетинговую» GitHub-версию с centered hero, anchors и navigation block.
|
||||||
|
|||||||
BIN
static/smith.ico
BIN
static/smith.ico
Binary file not shown.
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 4.2 KiB |
BIN
static/smith_full.ico
Normal file
BIN
static/smith_full.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
Reference in New Issue
Block a user