Files
AE_Anons/README.md

316 lines
23 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AE Anons - Автономный генератор спортивных анонсов в After Effects
<!-- markdownlint-disable MD033 -->
<p align="left">
<img src="assets/logo.png" alt="AE Anons Logo" width="250"/>
</p>
<!-- markdownlint-enable MD033 -->
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Rust](https://img.shields.io/badge/Rust-1.70%2B-orange.svg)](https://www.rust-lang.org/)
[![Status](https://img.shields.io/badge/status-production-green.svg)](https://git.tvstart.ru/lexx/AE_Anons)
**AE Anons** — полностью автономная (standalone) система для создания спортивных анонсов с использованием шаблонов After Effects через Nexrender. Все данные берутся из электронных таблиц Synology Office, рендеринг выполняется локально, управление заданиями происходит через встроенный веб-интерфейс с мгновенными обновлениями. Система не требует доступа в интернет — все ресурсы (иконки, стили, шрифты) встроены в бинарный файл.
## Новое в версии v0.3.0
- **WebSocket** — мгновенные обновления списка заданий (без устаревшего polling каждые 60 секунд)
- **SQLite** — хранение истории заданий и статуса апрува
- **Просмотр видео** прямо в веб-интерфейсе (по ссылке на готовый файл)
- **Апрув заданий** с копированием видео на SMB-шару (без монтирования, с поддержкой Active Directory)
- **Уведомления в реальном времени** о старте/завершении генерации, ошибках
- **Улучшенный веб-интерфейс** с кнопками апрува и иконками превью
- **Оптимизация памяти** — строки таблицы обрабатываются потоково, неиспользуемые логотипы и ассеты удаляются после генерации. Пиковое потребление памяти достигается только в момент загрузки и парсинга Excel, после чего память освобождается. Это позволяет работать с таблицами большого объёма (десятки тысяч строк) и обеспечивает стабильную работу в режиме долгоживущего сервиса.
- Полная автономность — все статические ресурсы (HTML, CSS, Font Awesome, логотип, favicon) встроены в бинарный файл.
## Обзор
AE Anons — это CLI-утилита и веб-сервер на Rust, которая выступает как **интеллектуальный генератор заданий** для [Nexrender](https://github.com/inlife/nexrender) — опенсорсного оркестратора рендеринга After Effects.
### Режимы работы
1. **Однократная обработка** (`--once` или без флагов):
- Подключение к NAS Synology
- Парсинг Excel данных
- Генерация и отправка заданий Nexrender
- Мониторинг завершения и выход
2. **Веб-сервер** (`--web`):
- Запуск веб-интерфейса на порту `:3000` (настраивается)
- Управление заданиями через браузер с WebSocket-обновлениями
- Просмотр видео и апрув готовых роликов
## Особенности
- **Полная автономность** — не требует выхода в интернет, все ресурсы встроены в бинарник
- **Интеграция с Synology** — аутентификация и загрузка файлов с NAS Synology (локальные и AD-учётные записи)
- **Экспорт офисных таблиц** — автоматическое преобразование `.osheet` в Excel
- **Гибкий парсинг данных** — динамический парсинг листов с обнаружением заголовков
- **Множественная генерация вариантов** — "Сегодня", "Завтра" и датированные версии
- **Умное управление логотипами** — автоматическое разрешение и масштабирование
- **Веб-интерфейс с WebSocket** — мгновенные обновления, просмотр видео, апрув
- **REST API** — программное управление заданиями
- **SQLite** — хранение истории и статуса апрува
- **Поддержка SMB** — копирование утверждённых видео на сетевую шару (с AD-аутентификацией)
- **Профессиональное логирование** — структурированный журнал с настройкой уровня
- **Эффективная работа с памятью** — потоковая обработка строк, своевременное удаление неиспользуемых данных (логотипы, ассеты) позволяет обрабатывать таблицы с десятками тысяч строк без утечек памяти
## Предварительные требования
- Rust 1.70 или выше
- Доступ к NAS Synology с пакетами File Station и Office (локальный или доменный пользователь)
- Экземпляр _server_ и _worker_ (не менее одного) Nexrender
- Шаблоны After Effects (формат .aep или .aepx, совместимые с версией AE на worker)
- (Для апрува) Доступ к SMB-шаре с правами на запись
## Установка
git clone https://git.example.com/team/ae_anons.git
cd ae_anons
cargo build --release
cp .env.example .env
# отредактируйте .env согласно вашей инфраструктуре
## Конфигурация
Все настройки задаются через переменные окружения в файле `.env`.
### Основные переменные
| Переменная | Обязательна | Описание |
|-------------------------|-------------|---------------------------------------------------------------------------------|
| `NAS_FQDN` | Да | URL Synology NAS (*) |
| `NAS_USER` | Да | Имя пользователя (локального или доменного, например `DOMAIN\username`) |
| `NAS_PASS` | Да | Пароль |
| `NAS_FILE` | Да | Путь к `.osheet` файлу на NAS (например, `/Team Folder/schedule.osheet`) |
| `NEXRENDER_API_URL` | Да | API Nexrender (например, `http://nexrender:3050/api/v1/jobs`) |
| `OUTPUT_FOLDER` | Да | Папка, куда Nexrender сохраняет готовые видео (локальный путь) |
| `TEMPLATE_DOUBLE_SRC` | Да | Путь к AEP-шаблону для двух команд (например, `file:///templates/double.aepx`) |
| `TEMPLATE_SINGLE_SRC` | Да | Путь к AEP-шаблону для одной команды |
| `TEMPLATE_COMPOSITION` | Да | Имя композиции в проекте AE |
| `TEMPLATE_OUTPUT_MODULE`| Да | Имя модуля вывода в AE |
| `TEMPLATE_OUTPUT_EXT` | Да | Расширение выходного файла (например, `mp4`) |
| `WEB_PORT` | Нет | Порт веб-сервера (по умолчанию 3000) |
| `RUST_LOG` | Нет | Уровень логирования (info, debug, trace) |
| `SMB_UPLOAD_URL` | Да(**) | SMB-URL для апрува (например, `smb://storage/approved`) |
| `SMB_USERNAME` | Да(**) | Имя пользователя для SMB (локальный или `DOMAIN\user`) |
| `SMB_PASSWORD` | Да(**) | Пароль для SMB |
| `DATABASE_URL` | Нет | Путь к SQLite БД (по умолчанию `sqlite:ae_anons.db`) |
> (*) — для `NAS_FQDN` можно указывать протокол `http://` или `https://`. Безопаснее `https`, хотя для локальной сети допустим и `http`. Если NAS доступен по стандартному HTTPS-порту 443, протокол можно опустить (например, `nas.company.local`). Иначе указывайте полный URL с портом: `https://nas.company.local:5001` или `http://nas.local:5000`.
>
> (**) — обязательно, если используется функция апрува (веб-режим). В режиме `--once` апрув не требуется.
### Пример файла `.env`
# Synology NAS
NAS_FQDN="https://nas.company.local:5001"
NAS_USER="DOMAIN\\service_account"
NAS_PASS="strongpassword"
NAS_FILE="/Team Folder/Anonsy/sport.osheet"
# Nexrender
NEXRENDER_API_URL="http://render-01:3050/api/v1/jobs"
OUTPUT_FOLDER="/mnt/nexrender/output"
# After Effects Templates
TEMPLATE_DOUBLE_SRC="file:///mnt/templates/double_team.aepx"
TEMPLATE_SINGLE_SRC="file:///mnt/templates/single_team.aepx"
TEMPLATE_COMPOSITION="main"
TEMPLATE_OUTPUT_MODULE="h264"
TEMPLATE_OUTPUT_EXT="mp4"
# Web server
WEB_PORT="3000"
RUST_LOG="info"
# SMB для апрува (AD-совместимо)
SMB_UPLOAD_URL="smb://storage.company.local/approved_videos"
SMB_USERNAME="DOMAIN\\service_account"
SMB_PASSWORD="strongpassword"
# Database
DATABASE_URL="sqlite:/var/lib/ae_anons/ae_anons.db"
> **Примечание об аутентификации:**
> Synology API и SMB-библиотека `smb` поддерживают как локальных пользователей NAS, так и доменных (Active Directory). Для доменных пользователей используйте формат `DOMAIN\username` (обратный слеш необходимо экранировать в `.env` как `\\`). Проверено на Synology DSM 7.x и Samba AD.
## Использование
### Однократная обработка (cron или ручной запуск)
./target/release/ae_anons --once
### Веб-сервер (интерактивный режим)
./target/release/ae_anons --web
После запуска откройте браузер: `http://localhost:3000`
## Веб-интерфейс
- **Главная страница** — таблица всех заданий с полями: UID, имя файла, статус, превью (иконка видео), кнопка апрува, дата создания.
- **Обновления в реальном времени** через WebSocket — статусы заданий меняются мгновенно без перезагрузки страницы.
- **Кнопка «Generate»** — запускает парсинг таблицы Synology и создание новых заданий. Во время генерации кнопка блокируется, при завершении приходит уведомление.
- **Кнопка «Cleanup»** — удаляет из Nexrender задания со статусом finished/error.
- **Кнопка «Stop all»** — останавливает все активные (queued/started/processing) задания.
- **Просмотр видео** — клик по иконке видео открывает готовый файл в новой вкладке (поддерживается любой браузерный просмотр MP4).
- **Апрув** — клик по ✅ копирует видео на SMB-шару (путь из `SMB_UPLOAD_URL`) и помечает задание как approved. Повторный апрув невозможен.
### API эндпоинты
- `GET /api/jobs` — список всех заданий (из SQLite)
- `POST /api/generate` — запуск генерации
- `POST /api/cleanup` — очистка завершённых
- `POST /api/jobs/stop-all` — остановка активных
- `GET /api/status` — статус сервера
- `GET /api/video/:uid` — просмотр видеофайла
- `POST /api/approve/:uid` — апрув (копирование на SMB)
- `WS /ws` — WebSocket для получения событий (`JobUpdated`, `GenerationStarted`, `GenerationFinished`, `Error`)
## Уровни логирования
`RUST_LOG=debug ./ae_anons --web`
- **error** — только критические ошибки
- **warn** — предупреждения
- **info** — стандартная информация (по умолчанию)
- **debug** — детали API-вызовов, парсинга, SMB-операций
- **trace** — максимальная детализация
## Структура электронной таблицы
Файл Excel должен содержать следующие листы со специфичными структурами:
### Лист "SPORT"
Связывает названия видов спорта с соответствующими видео пакетами.
| SPORT | LINK |
|----------------|---------------------------------------------|
| Без оформления | \\server\share\path\to\null.mov |
| Футбол | \\server\share\path\to\football_pack.mov |
| Волейбол | \\server\share\path\to\volleyball_pack.mov |
### Лист "TEAMS"
Сопоставляет имена команд с их видами спорта и логотипами. Колонка SPORT заполняется из выпадающего списка (заполнена из листа SPORT).
Если несколько команд в одном виде спорта имеют одинаковые названия, но разные логотипы, используется разделитель хеш # для уникальной идентификации.
| TEAM | SPORT | LINK |
|-------------------|-----------|---------------------------------------------------|
| Галатасарай#Turki | Футбол | \\server\share\path\to\galatasaray_football.png |
| Галатасарай | Волейбол | \\server\share\path\to\galatasaray_volleyball.png |
| Галатасарай#UCL | Волейбол | \\server\share\path\to\galatasaray_ucl.png |
| Сомбатей##400 | Футбол | \\server\share\path\to\szombathely.png |
### Лист "CHANELL"
Сопоставляет названия каналов с их логотипами. Поля заполняются вручную без выпадающих списков.
| CHANELL | LINK |
|---------|-----------------------------------------|
| КАНАЛ | \\server\share\path\to\channel_logo.png |
| TRIUMPH | \\server\share\path\to\triumph_logo.png |
### Лист "Start"
Основной источник данных для генерации анонсов. Большинство полей заполняются из выпадающих списков, основанных на других листах.
Обязательные колонки: DATA, TIME, CHANELL, SPORT, LEAGUE, TEAM A, TEAM B
**Примечания:**
- Колонка LEAGUE обязательна для заполнения, но не имеет выпадающего списка. Проверка орфографии и опечаток отсутствует!
- Колонка DATA должна содержать дату в формате `ДД.ММ.ГГГГ` (например, `28.2.2026`).
| STATE | TRIPPLE | DATA | TIME | SPORT | LEAGUE | CHANELL | TEAM A | TEAM B |
|-------|---------|-----------|-------|---------|---------------------------|---------|-----------------|------------------|
| TRUE | TRUE | 27.2.2026 | 23:40 | Футбол | Чемпионат Португалии | START | Спортинг#ll#550 | Эшторил#ll#550 |
| FALSE | TRUE | 28.2.2026 | 12:55 | Волейбол| Чемпионат Турции. Женщины | TRIUMPH | Бешикташ | Галатасарай#Turki|
### Формат имен команд
Имена команд поддерживают два типа разделителей хэш #:
1. **Первый хеш**: Уникальный идентификатор для команд с одинаковыми названиями в одном виде спорта, или одинаковым названием в разных видах спорта.
2. **Второй хеш**: Целевой размер в пикселях для масштабирования логотипа
Формат: `DisplayName#UniqueID#TargetSize`
Примеры:
- `Галатасарай#Turki` - только уникальный идентификатор
- `Сомбатей##400` - только целевой размер (обратите внимание на двойной хеш)
- `Спортинг#ll#550` - оба идентификатор и целевой размер
## Выходные файлы
Рендеренные видео сохраняются в `OUTPUT_FOLDER` по шаблону:
`YYYYMMDD_Sport_League_TeamA_TeamB_Channel[_Variant].mp4`
При апруве файл копируется в SMB-шару с тем же именем.
## Рабочий процесс (веб-режим)
1. Пользователь заполняет таблицу Synology Office.
2. Нажимает «Generate» в веб-интерфейсе.
3. Сервер аутентифицируется на NAS, скачивает и парсит Excel.
4. Генерирует задания Nexrender, сохраняет их в SQLite и отправляет в Nexrender.
5. WebSocket уведомляет клиент о новых заданиях.
6. Nexrender рендерит видео, статус задания обновляется (периодический опрос или webhook).
7. Когда видео готово, пользователь видит иконку превью, может посмотреть видео и нажать апрув.
8. При апруве видео копируется на SMB-шару, задание помечается как approved.
## Требования к шаблонам After Effects
Не изменились — все слои `DATA`, `TIME_H`, `TIME_M`, `LEAGUE`, `SPORT`, `TEAMS`, `TEAM_A_LOGO`, `TEAM_B_LOGO`, `CHANELL`, `TOP` должны присутствовать согласно типу шаблона (DOUBLE/SINGLE). Поддержка масштабирования логотипов через выражения After Effects — осталась.
## Устранение неисправностей
### WebSocket не работает
- Проверьте, что браузер поддерживает WebSocket (все современные поддерживают).
- При использовании прокси (nginx) необходимо настроить Upgrade заголовки.
### Ошибка аутентификации на NAS для доменного пользователя
- Убедитесь, что в `.env` указано `DOMAIN\\username` (двойной обратный слеш).
- Проверьте, что NAS настроен на приём доменных учётных записей (DSM → Домен/LDAP).
### Ошибка SMB подключения
- Проверьте доступность шары: `smbclient -U DOMAIN/username -L //storage/`
- Убедитесь, что в URL используется `smb://` протокол, путь без лишних слешей.
- Время на сервере и клиенте должно быть синхронизировано (SMB требует этого).
### БД SQLite блокирована
- При конкурентных запросах SQLite может выдавать `database is locked`. Для веб-сервера с одним процессом это маловероятно. Если возникает — используйте `sqlite://:memory:` для тестов или настройте WAL-режим.
### Высокое потребление памяти
- Система спроектирована так, чтобы минимизировать удержание данных. Если вы наблюдаете рост памяти, убедитесь, что вы используете последнюю версию. При работе с очень большими таблицами (сотни тысяч строк) может потребоваться увеличить лимит строк в `processor.rs` (константа 10000).
## Разработка
Все статические ресурсы (HTML, CSS, шрифты Font Awesome, логотип, favicon) встроены в бинарник с помощью `include_str!` и `include_bytes!`. Для разработки можно редактировать файлы в `src/static/`, но при сборке они компилируются внутрь исполняемого файла.
### Сборка для production
cargo build --release
strip target/release/ae_anons # уменьшает размер
Итоговый бинарник можно переносить на любой Linux-сервер без дополнительных зависимостей (кроме libc и openssl, если не используется статическая сборка).
## Лицензия
**AE Anons** — MIT
**Nexrender** — MIT
**Font Awesome Free** — CC BY 4.0 (иконки) и SIL OFL 1.1 (шрифты)
---
Made with 🦀 Rust and ☕ coffee