Compare commits
2 Commits
28d21c400f
...
f2115d356e
| Author | SHA1 | Date | |
|---|---|---|---|
| f2115d356e | |||
| 7d6c97ffc4 |
230
README.md
Normal file
230
README.md
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
# ⚽ Match Management & vMix Integration System
|
||||||
|
|
||||||
|
Полноценная система управления футбольными матчами с live-обновлением,
|
||||||
|
парсингом данных и интеграцией с vMix.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 📌 Описание
|
||||||
|
|
||||||
|
Проект состоит из нескольких ключевых частей:
|
||||||
|
|
||||||
|
- FastAPI сервер (админка + API)
|
||||||
|
- Scheduler (live-обновления матчей)
|
||||||
|
- Парсеры (игры, расписание, таблица)
|
||||||
|
- PostgreSQL база данных
|
||||||
|
- WebSocket сервер для vMix
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 🧱 Архитектура системы
|
||||||
|
|
||||||
|
┌──────────────┐
|
||||||
|
│ Scheduler │
|
||||||
|
│ │
|
||||||
|
│ matches_loop │
|
||||||
|
│ standings │
|
||||||
|
└──────┬───────┘
|
||||||
|
│
|
||||||
|
┌──────────────┼──────────────┐
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
live_match_worker parser_game parser_standings
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Database
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
FastAPI
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
vMix
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 🗄 Структура базы данных
|
||||||
|
|
||||||
|
## Таблица: matches
|
||||||
|
|
||||||
|
Поле Тип Описание
|
||||||
|
------------- ----------- ----------------------
|
||||||
|
id int ID матча
|
||||||
|
external_id text ID матча на сайте
|
||||||
|
match_date timestamp дата и время
|
||||||
|
status text статус матча
|
||||||
|
home_score int счет хозяев
|
||||||
|
away_score int счет гостей
|
||||||
|
updated_at timestamp последнее обновление
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Таблица: standings
|
||||||
|
|
||||||
|
Поле Тип Описание
|
||||||
|
---------- ----- ----------
|
||||||
|
team_id int команда
|
||||||
|
position int позиция
|
||||||
|
points int очки
|
||||||
|
played int сыграно
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Таблица: match_lineup_players
|
||||||
|
|
||||||
|
- составы команд
|
||||||
|
- старт + запас
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Таблица: match_events
|
||||||
|
|
||||||
|
- события матча (голы, карточки и т.д.)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 🔄 Основные процессы
|
||||||
|
|
||||||
|
## 1. Scheduler
|
||||||
|
|
||||||
|
Работает как отдельный процесс:
|
||||||
|
|
||||||
|
### Каждую минуту:
|
||||||
|
|
||||||
|
- ищет матчи на сегодня
|
||||||
|
- запускает worker за 1 минуту до начала
|
||||||
|
|
||||||
|
### Worker:
|
||||||
|
|
||||||
|
- раз в минуту:
|
||||||
|
- парсит сайт
|
||||||
|
- обновляет счет и статус
|
||||||
|
- останавливается при finished
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## 2. Обновление турнирной таблицы
|
||||||
|
|
||||||
|
- вызывается `parser_standings`
|
||||||
|
- обновляет standings в БД
|
||||||
|
- запускается раз в минуту
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## 3. FastAPI
|
||||||
|
|
||||||
|
Обеспечивает:
|
||||||
|
|
||||||
|
- админку
|
||||||
|
- API для vMix
|
||||||
|
- WebSocket соединения
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 📡 API Endpoints
|
||||||
|
|
||||||
|
## Основные
|
||||||
|
|
||||||
|
### Матчи
|
||||||
|
|
||||||
|
- GET /admin/matches
|
||||||
|
- GET /admin/session/{session_token}
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
### vMix
|
||||||
|
|
||||||
|
- GET /vmix/session/{session_token}/info
|
||||||
|
- GET /vmix/session/{session_token}/standings
|
||||||
|
- GET /vmix/session/{session_token}/schedule
|
||||||
|
- GET /vmix/session/{session_token}/scoreboard
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
|
||||||
|
/ws/vmix-client
|
||||||
|
|
||||||
|
Функции: - регистрация клиентов - heartbeat - отправка команд
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ⚙️ Запуск проекта
|
||||||
|
|
||||||
|
## 1. Установка
|
||||||
|
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## 2. Настройка БД
|
||||||
|
|
||||||
|
Отредактировать:
|
||||||
|
|
||||||
|
db.py
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## 3. Запуск
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
uvicorn app:app --reload
|
||||||
|
|
||||||
|
### Scheduler
|
||||||
|
|
||||||
|
python scheduler.py
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ❗ ВАЖНО
|
||||||
|
|
||||||
|
Scheduler должен запускаться отдельно.
|
||||||
|
|
||||||
|
НЕЛЬЗЯ:
|
||||||
|
|
||||||
|
run_scheduler()
|
||||||
|
|
||||||
|
внутри FastAPI.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 🔧 Что нужно реализовать
|
||||||
|
|
||||||
|
## fetch_match_live_data()
|
||||||
|
|
||||||
|
def fetch_match_live_data(match_row):
|
||||||
|
return {
|
||||||
|
"status": "live",
|
||||||
|
"home_score": 1,
|
||||||
|
"away_score": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 🚀 Рекомендации
|
||||||
|
|
||||||
|
- запускать scheduler отдельно
|
||||||
|
- использовать 1 worker для API
|
||||||
|
- добавить логирование
|
||||||
|
- обрабатывать ошибки парсинга
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 📌 Dev режим
|
||||||
|
|
||||||
|
uvicorn app:app --reload
|
||||||
|
python scheduler.py
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 🧠 Production
|
||||||
|
|
||||||
|
- API отдельно
|
||||||
|
- Scheduler отдельно
|
||||||
|
- supervisor / systemd
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# 📬 Контакты
|
||||||
|
|
||||||
|
Для доработок и улучшений --- пиши 👍
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
# WFL auth + idle session timeout
|
|
||||||
|
|
||||||
Этот набор добавляет:
|
|
||||||
- страницу `/login`
|
|
||||||
- `HttpOnly` cookie `auth_token`
|
|
||||||
- серверную проверку всех `/admin/*`
|
|
||||||
- автоматический logout после 2 часов бездействия
|
|
||||||
- rolling session timeout
|
|
||||||
- logout кнопку
|
|
||||||
- обработку `401` для AJAX/fetch
|
|
||||||
|
|
||||||
## Что заменить в проекте
|
|
||||||
|
|
||||||
Скопируй файлы в свой проект:
|
|
||||||
- `app.py` -> заменить текущий
|
|
||||||
- `repositories/auth_repository.py` -> новый файл
|
|
||||||
- `services/auth_service.py` -> новый файл
|
|
||||||
- `templates/login.html` -> новый файл
|
|
||||||
- `templates/matches.html` -> заменить
|
|
||||||
- `templates/match_workspace.html` -> заменить
|
|
||||||
|
|
||||||
## SQL
|
|
||||||
|
|
||||||
Выполни файл:
|
|
||||||
- `sql/001_auth.sql`
|
|
||||||
|
|
||||||
## Первый админ
|
|
||||||
|
|
||||||
1. Запусти:
|
|
||||||
`python scripts/create_admin.py`
|
|
||||||
2. Скопируй выведенный SQL
|
|
||||||
3. Выполни его в PostgreSQL
|
|
||||||
|
|
||||||
## Важно
|
|
||||||
|
|
||||||
В `app.py` cookie сейчас создаётся так:
|
|
||||||
- `secure=False`
|
|
||||||
|
|
||||||
Для production под HTTPS поменяй на:
|
|
||||||
- `secure=True`
|
|
||||||
|
|
||||||
## Что не трогалось
|
|
||||||
|
|
||||||
Твои `match_sessions` оставлены как рабочие сессии матча.
|
|
||||||
Пользовательская авторизация вынесена отдельно в `admin_users` и `auth_sessions`.
|
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Редактирование тренера</title>
|
<title>Редактирование тренера</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115;
|
--bg: #0f1115;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Тренеры</title>
|
<title>Тренеры</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115;
|
--bg: #0f1115;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>База</title>
|
<title>База</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115;
|
--bg: #0f1115;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Редактирование игрока</title>
|
<title>Редактирование игрока</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115;
|
--bg: #0f1115;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Игроки</title>
|
<title>Игроки</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115;
|
--bg: #0f1115;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Редактирование судьи</title>
|
<title>Редактирование судьи</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115; --panel: #171a21; --panel-2: #1d222b; --border: #2b3240;
|
--bg: #0f1115; --panel: #171a21; --panel-2: #1d222b; --border: #2b3240;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Судьи</title>
|
<title>Судьи</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115; --panel: #171a21; --panel-2: #1d222b; --border: #2b3240;
|
--bg: #0f1115; --panel: #171a21; --panel-2: #1d222b; --border: #2b3240;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Редактирование стадиона</title>
|
<title>Редактирование стадиона</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115;
|
--bg: #0f1115;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Стадионы</title>
|
<title>Стадионы</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115; --panel: #171a21; --panel-2: #1d222b; --border: #2b3240;
|
--bg: #0f1115; --panel: #171a21; --panel-2: #1d222b; --border: #2b3240;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Редактирование команды</title>
|
<title>Редактирование команды</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115; --panel: #171a21; --panel-2: #1d222b; --border: #2b3240;
|
--bg: #0f1115; --panel: #171a21; --panel-2: #1d222b; --border: #2b3240;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Команды</title>
|
<title>Команды</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115; --panel: #171a21; --panel-2: #1d222b; --border: #2b3240;
|
--bg: #0f1115; --panel: #171a21; --panel-2: #1d222b; --border: #2b3240;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<meta http-equiv="Expires" content="0" />
|
<meta http-equiv="Expires" content="0" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Загрузка проекта vMix</title>
|
<title>Загрузка проекта vMix</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<link rel="stylesheet" href="/static/styles.css?v=20260421_1" />
|
<link rel="stylesheet" href="/static/styles.css?v=20260421_1" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, max-age=0">
|
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, max-age=0">
|
||||||
<meta http-equiv="Pragma" content="no-cache">
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
<meta http-equiv="Expires" content="0">
|
<meta http-equiv="Expires" content="0">
|
||||||
<title>Вход</title>
|
<title>Вход в управлялку vMix под ЖФЛ</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #000000;
|
--bg: #000000;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
|||||||
<meta http-equiv="Pragma" content="no-cache" />
|
<meta http-equiv="Pragma" content="no-cache" />
|
||||||
<meta http-equiv="Expires" content="0" />
|
<meta http-equiv="Expires" content="0" />
|
||||||
<title>ЖФЛ Управление vMix</title>
|
<title>ЖФЛ Управление vMix</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<link rel="stylesheet" href="/static/styles.css?v=20260421_4">
|
<link rel="stylesheet" href="/static/styles.css?v=20260421_4">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
<meta http-equiv="Pragma" content="no-cache">
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
<meta http-equiv="Expires" content="0">
|
<meta http-equiv="Expires" content="0">
|
||||||
<title>Выбор матча</title>
|
<title>Выбор матча</title>
|
||||||
|
<link rel="icon" href="/static/smith.ico" type="image/x-icon">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1115;
|
--bg: #0f1115;
|
||||||
|
|||||||
BIN
templates/smith.ico
Normal file
BIN
templates/smith.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
Reference in New Issue
Block a user