# AE Anons - Автономный генератор спортивных анонсов в After Effects

AE Anons Logo

[![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