# 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)

Автоматизированная система для создания спортивных анонсов с использованием шаблонов After Effects через Nexrender, с данными из электронных таблиц Synology Office.

## Новое в версии v0.2.6

- Сортировка заданий по дате и времени события (самые ранние — первыми)
- Сортировка по варианту (оригинал → today → tomorrow)
- Последовательная отправка для гарантированного порядка в очереди
- Исправлена нормализация дефисов (2 и более дефиса подряд → 1)
- Исправлен SINGLE шаблон (убран несуществующий слой TEAMS)
- Добавлена поддержка кеширования ассетов (cache: true/false)
- Логотипы команд не кешируются, логотипы каналов и видео-паки кешируются

## Обзор

AE Anons — это CLI-утилита и веб-сервер на Rust, которая выступает как **интеллектуальный генератор заданий**
для [Nexrender](https://github.com/inlife/nexrender) — опенсорсного оркестратора рендеринга
After Effects (лицензия MIT).

### Режимы работы

1. **Однократная обработка** (`--once` или без флагов):
   - Подключение к NAS Synology
   - Парсинг Excel данных
   - Генерация и отправка заданий Nexrender
   - Мониторинг завершения и выход

2. **Веб-сервер** (`--web`):
   - Запуск веб-интерфейса на порту `:3000`
   - Управление заданиями через браузер
   - Автообновление статуса каждую минуту

## Особенности

- **Интеграция с Synology**: Аутентификация и загрузка файлов с NAS Synology
- **Экспорт офисных таблиц**: Автоматическое преобразование файлов .osheet в формат Excel
- **Гибкий парсинг данных**: Динамический парсинг листов с обнаружением заголовков
- **Множественная генерация вариантов**: Создание "Сегодня", "Завтра" и датированных версий
- **Умное управление логотипами**: Автоматическое разрешение и масштабирование логотипов
- **Веб-интерфейс**: Удобное управление и мониторинг заданий
- **REST API**: Программный доступ к управлению заданиями
- **Профессиональное логирование**: Структурированный журнал с настройкой уровня

## Предварительные требования

- Rust 1.70 или выше
- Доступ к NAS Synology с пакетами File Station и Office
- Экземпляр _server_ и _worker_(не менее одного) Nexrender
- Шаблоны After Effects (формат Adobe After Effects 2024 .aepx)

## Установка

### 1. Клонирование репозитория

```bash
git clone https://git.tvstart.ru/lexx/AE_Anons.git
cd ae_anons
```

### 2. Сборка проекта

```bash
cargo build --release
```

### 3. Настройка окружения

Скопируйте пример конфигурации и заполните своими данными:

```bash
cp .env.example .env
```

Затем отредактируйте файл .env:

См. раздел Конфигурация для подробной информации.

## Использование

### Однократная обработка

```bash
# Запуск с настройками по умолчанию
./target/release/ae_anons

# Явно указать однократный режим
./target/release/ae_anons --once

# С отладочным логированием
RUST_LOG=debug ./target/release/ae_anons
```

### Веб-сервер

```bash
# Запуск веб-интерфейса на порту по умолчанию (3000)
./target/release/ae_anons --web

# Или с указанием другого порта через .env файл
# WEB_PORT=8080 ./target/release/ae_anons --web

```

## Веб-интерфейс

После запуска веб-сервера откройте браузер:

- Главная страница: <http://localhost:3000>

- API эндпоинты:
  - `GET /api/jobs` - список всех заданий
  - `POST /api/generate` - запуск генерации
  - `POST /api/cleanup` - очистка завершённых
  - `POST /api/jobs/stop-all` - остановка активных
  - `GET /api/status` - статус сервера
  
## Уровни логирования

Управляйте детализацией вывода через переменную окружения `RUST_LOG`:

- **error** - Только критические ошибки
- **warn** - Предупреждения и ошибки  
- **info** - Общие операционные сообщения (по умолчанию)
- **debug** - Детальная информация о процессе обработки
- **trace** - Полное отладочное логирование с деталями API вызовов

```bash
RUST_LOG=debug cargo run
```

## Конфигурация

### Переменные окружения

| Переменная              | Обязательна | Описание                                             |
|-------------------------|-------------|------------------------------------------------------|
| `NAS_FQDN`              | Да          | URL NAS Synology с протоколом и портом               |
| `NAS_USER`              | Да          | Имя пользователя учетной записи Synology             |
| `NAS_PASS`              | Да          | Пароль учетной записи Synology                       |
| `NAS_FILE`              | Да          | Полный путь к файлу .osheet на NAS                   |
| `NEXRENDER_API_URL`     | Да          | Конечная точка API сервера Nexrender                 |
| `OUTPUT_FOLDER`         | Да          | Сетевой путь для рендеренных видео                   |
| `TEMPLATE_DOUBLE_SRC`   | Да          | Путь к AEP-шаблону для двух команд                   |
| `TEMPLATE_SINGLE_SRC`   | Да          | Путь к AEP-шаблону для одной команды                 |
| `TEMPLATE_COMPOSITION`  | Да          | Имя композиции в проекте AE (например, `main`)       |
| `TEMPLATE_OUTPUT_MODULE`| Да          | Имя модуля вывода в AE (например, `h264`)            |
| `TEMPLATE_OUTPUT_EXT`   | Да          | Расширение выходного файла (например, `mp4`)         |
| `WEB_PORT`              | Нет         | Порт для веб-сервера (по умолчанию: 3000)            |
| `RUST_LOG`              | Нет         | Уровень детализации логирования (по умолчанию: info) |

### Пример файла `.env`

```env
# Synology NAS
NAS_FQDN="https://your-nas.example.com"
NAS_USER="your_username"
NAS_PASS="your_password"
NAS_FILE="/Team Folder/path/to/file.osheet"

# Logging
RUST_LOG="info"

# Web Server
WEB_PORT="3000"

# Nexrender
NEXRENDER_API_URL="http://nexrender-server:3050/api/v1/jobs"
OUTPUT_FOLDER="/path/to/output"

# After Effects Templates
TEMPLATE_DOUBLE_SRC="file:///path/to/double_team_template.aepx"
TEMPLATE_SINGLE_SRC="file:///path/to/single_team_template.aepx"
TEMPLATE_COMPOSITION="main"
TEMPLATE_OUTPUT_MODULE="h264"
TEMPLATE_OUTPUT_EXT="mp4"
```

## Структура электронной таблицы

Файл 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. **Первый хеш**: Уникальный идентификатор для команд с одинаковыми названиями в одном виде спорта, или одинаковым названием в разных видах спорта.
Примеры:

- `Динамо#Футбол`, `Динамо#Волейбол` - Одно название разный вид спорта
- `Спартак#ЖенскийФ`, `Спартак#МужскойФ` Одно название _разный_ вид спорта

1. **Второй хеш**: Целевой размер в пикселях для масштабирования логотипа

Формат: `DisplayName#UniqueID#TargetSize`

Примеры:

- `Галатасарай#Turki` - только уникальный идентификатор
- `Сомбатей##400` - только целевой размер (обратите внимание на двойной хеш)
- `Спортинг#ll#550` - оба идентификатор и целевой размер

**Важно**: Обрабатывается **только второй хеш** для масштабирования логотипа. Если уникальный идентификатор не требуется, используйте двойной хеш ## перед целевым размером.

## Выходные файлы

### Рендеренные видео

Рендерные видео сохраняются в `OUTPUT_FOLDER` по следующему шаблону именования:

```shell
YYYYMMDD_Sport_League_TeamA_TeamB_Channel[_Variant].mp4
```

Имена файлов транслитерируются в латиницу.
**Примеры:**

- `20260228_Volleyball_Championship-Turkey-Women_Beşiktaş_Galatasaray_TRIUMPH.mp4`
- `20260228_Volleyball_Championship-Turkey-Women_Beşiktaş_Galatasaray_TRIUMPH_Today.mp4`
- `20260228_Volleyball_Championship-Turkey-Women_Beşiktaş_Galatasaray_TRIUMPH_Tomorrow.mp4`

## Рабочий процесс

1. **Аутентификация**: Подключение к NAS Synology с использованием предоставленных учетных данных
2. **Получение файла**: Поиск и экспорт указанного файла .osheet в Excel
3. **Парсинг данных**: Чтение всех листов и структурирование данных
4. **Разрешение ресурсов**: Сопоставление видов спорта, команд и каналов с визуальными элементами
5. **Генерация заданий**: Создание заданий Nexrender для каждой активной строки с вариантами
6. **Очистка**: Удаление завершенных/неудачных заданий из предыдущих запусков
7. **Отправка**: Отправка заданий на API Nexrender
8. **Мониторинг**: Слежение за прогрессом выполнения до завершения
9. **Завершение сеанса**: Закрытие сессии Synology

## Требования к шаблонам After Effects

Шаблоны должны быть предварительно настроены на узлах рендеринга со следующими именами слоёв.

### Файлы шаблонов

Настраиваются через переменные окружения:

| Переменная              | Назначение                          | Пример значения                    |
|-------------------------|-------------------------------------|------------------------------------|
| `TEMPLATE_DOUBLE_SRC`   | Шаблон для матчей с двумя командами | `file:///path/to/double.aepx`      |
| `TEMPLATE_SINGLE_SRC`   | Шаблон для анонсов с одной командой | `file:///path/to/single.aepx`      |
| `TEMPLATE_COMPOSITION`  | Имя главной композиции              | `main`                             |
| `TEMPLATE_OUTPUT_MODULE`| Имя модуля вывода                   | `h264`                             |
| `TEMPLATE_OUTPUT_EXT`   | Расширение выходного файла          | `mp4`                              |

### Обязательные слои в шаблонах

#### Текстовые слои

| Имя слоя  | Шаблон DOUBLE | Шаблон SINGLE | Описание                                        |
|-----------|:-------------:|:-------------:|-------------------------------------------------|
| `DATA`    | ✅            | ✅            | Отображение даты (автоматически подстраивается) |
| `TIME_H`  | ✅            | ❌            | Часы (отдельный слой)                           |
| `TIME_M`  | ✅            | ❌            | Минуты (отдельный слой)                         |
| `TIME`    | ❌            | ✅            | Полное время (единый слой)                      |
| `LEAGUE`  | ✅            | ✅            | Название лиги/турнира                           |
| `SPORT`   | ✅            | ✅            | Категория спорта                                |
| `TEAMS`   | ✅            | ✅            | Скомбинированные имена команд                   |

#### Слои с изображениями

| Имя слоя       | Шаблон DOUBLE | Шаблон SINGLE | Описание                    |
|----------------|:-------------:|:-------------:|-----------------------------|
| `TEAM_A_LOGO`  | ✅            | ✅            | Логотип команды A           |
| `TEAM_B_LOGO`  | ✅            | ❌            | Логотип команды B           |
| `CHANELL`      | ✅            | ✅            | Логотип канала (две буквы L)|

#### Видео слои

| Имя слоя  | Шаблон DOUBLE | Шаблон SINGLE | Описание                   |
|-----------|:-------------:|:-------------:|----------------------------|
| `TOP`     | ✅            | ✅            | Наложение видео оформления |

### Особенности шаблонов

#### Шаблон DOUBLE (две команды)

Используется когда в строке Excel заполнены оба поля `TEAM A` и `TEAM B`.

Обязательные слои:

- Все текстовые слои с `TIME_H` и `TIME_M` вместо `TIME`
- Оба логотипа команд: `TEAM_A_LOGO` и `TEAM_B_LOGO`

#### Шаблон SINGLE (одна команда)

Используется когда заполнено только одно поле команды.

Обязательные слои:

- Текстовый слой `TIME` вместо `TIME_H` и `TIME_M`
- Только логотип `TEAM_A_LOGO`

### Автоматические корректировки

AE Anons автоматически применяет следующие настройки к слоям:

#### Слой DATA

В зависимости от отображаемого текста и типа шаблона:

| Текст      | Шаблон   | Font Size | Anchor Point |
|------------|----------|-----------|--------------|
| "сегодня"  | DOUBLE   | 105       | [0, 5]       |
| "завтра"   | DOUBLE   | 115       | [0, 25]      |
| дата (<6)  | DOUBLE   | 120       | [0, 20]      |

#### Слои TIME_H, TIME_M, TIME

Корректировка Anchor Point в зависимости от длины текста:

| Условие           | Anchor Point |
|-------------------|--------------|
| 1 символ          | [60, 0]      |
| 2 символа, <20    | [20, 0]      |

#### Слой LEAGUE

Если длина текста превышает 16 символов, размер шрифта уменьшается до 73.

#### Слой TEAMS

Если суммарная длина имён команд ≥ 32 символов, размер шрифта уменьшается до 55.

#### Логотипы (TEAM_A_LOGO, TEAM_B_LOGO)

Если в имени команды указан целевой размер через `#` (например, `Спортинг##550`), применяется выражение масштабирования:

```javascript
if (width > height) {
    max_size = width;
} else {
    max_size = height;
}
var real_size = 550 / max_size * 100;
[real_size, real_size]
```

### Пример структуры слоёв в After Effects

Ниже представлен рекомендуемый порядок слоёв в композиции. Порядок важен для правильного наложения элементов.

```text
📁 main (композиция)
├── 🎬 TOP (видео слой)                    # Видео-оверлей (обязательный)
├── 📝 TEAMS (текстовый слой)              # Имена команд (обязательный)
├── 📝 LEAGUE (текстовый слой)             # Название лиги (обязательный)
├── 📝 SPORT (текстовый слой)              # Вид спорта (обязательный)
├── 📝 DATA (текстовый слой)               # Дата (обязательный)
├── 📝 TIME (текстовый слой)               # Время (только SINGLE)
├── 📝 TIME_H (текстовый слой)             # Часы (только DOUBLE)
├── 📝 TIME_M (текстовый слой)             # Минуты (только DOUBLE)
├── 🖼️ CHANELL (слой изображения)          # Логотип канала (обязательный)
├── 🖼️ TEAM_A_LOGO (слой изображения)      # Логотип команды A (обязательный)
├── 🖼️ TEAM_B_LOGO (слой изображения)      # Логотип команды B (только DOUBLE)
└── 🖼️ BOTTOM (слой изображения)           # Фоновый слой (опционально)
```

### Формат проекта и совместимость с After Effects

**Поддерживаемые форматы проектов:**

- `.aep` — стандартный бинарный формат After Effects (рекомендуется)
- `.aepx` — XML-формат проекта (поддерживается с AE CC 2015)

**Совместимость версий After Effects:**

| Версия After Effects | Поддерживаемые форматы | Особенности                                     |
|----------------------|------------------------|-------------------------------------------------|
| CS 5.5               | `.aep`                 | Базовая поддержка                               |
| CC / CC 2014         | `.aep`                 | Полная поддержка                                |
| CC 2015 - CC 2019    | `.aep`, `.aepx`        | Добавлена поддержка XML формата `.aepx`         |
| CC 2020 - CC 2022    | `.aep`, `.aepx`        | Рекомендуется использовать `.aep`               |
| CC 2023 и новее      | `.aep`, `.aepx`        | **Требуется настройка Output Module** (см. ниже)|

> **⚠️ Важно для After Effects 2023+:**
>
> В версиях After Effects 2023 и новее критически важно настроить **Output Module** в шаблоне проекта. Бинарный файл рендеринга (`aerender`) не будет обрабатывать композицию без явно указанного модуля вывода, даже если в проекте используется модуль по умолчанию.
>
> AE Anons автоматически решает эту проблему, используя параметры `TEMPLATE_OUTPUT_MODULE` и `TEMPLATE_OUTPUT_EXT` из `.env` файла. Убедитесь, что эти значения соответствуют настройкам вашего шаблона.

### Настройки композиции

| Параметр                  | Переменная окружения     | Пример значения | Описание                                    |
|---------------------------|--------------------------|-----------------|---------------------------------------------|
| Имя композиции            | `TEMPLATE_COMPOSITION`   | `main`          | Имя главной композиции в проекте AE         |
| Выходной модуль           | `TEMPLATE_OUTPUT_MODULE` | `h264`          | Имя модуля вывода в AE                      |
| Расширение выходного файла| `TEMPLATE_OUTPUT_EXT`    | `mp4`           | Расширение выходного файла                  |

**Рекомендации по выбору формата:**

1. Используйте `.aep` для максимальной совместимости со всеми версиями AE
2. Версия After Effects на worker-машине должна быть не ниже версии, в которой создан проект
3. Для AE 2023+ убедитесь, что в шаблоне настроен Output Module с именем, указанным в `TEMPLATE_OUTPUT_MODULE`

**Источники:**

- [Nexrender - Tested with After Effects versions](https://github.com/inlife/nexrender#tested-with)
- [Adobe Aerender documentation](https://helpx.adobe.com/after-effects/using/automated-rendering-network-rendering.html)

## Устранение неисправностей

### Частые проблемы

#### Ошибка подключения к NAS

- Проверьте, что `NAS_FQDN` включает протокол и порт (например, `https://nas.example.com:5001`)
- Проверьте сетевую связность с NAS
- Убедитесь, что сервисы File Station и Office включены

#### Файл не найден

- Убедитесь, что путь в `NAS_FILE` точно соответствует пути в Synology Drive
- Путь должен начинаться с `/Team Folder/` для рабочих папок
- Проверьте права доступа к файлу для учетной записи сервиса

#### Ошибка отправки задания Nexrender

- Подтвердите доступность сервера Nexrender
- Убедитесь, что `NEXRENDER_API_URL` правильный
- Проверьте существование файлов шаблонов на узлах рендеринга

### Режим отладки

Включите подробное логирование для детального анализа:

```bash
RUST_LOG=debug ./target/release/ae_anons
```

Это выведет:

- Детали API запросов/ответов
- Информацию о парсинге листов
- Детали создания заданий
- Процесс разрешения ресурсов

## Возможные ограничения по производительности

- **Большие таблицы**: Ограничение обработки до 10,000 строк на лист
- **Задержка сети**: Загрузка файлов с NAS может занимать время для больших файлов
- **Параллельные задания**: Nexrender управляет очередью заданий внутренне

## Примечания по безопасности

- Храните учетные данные только в файле `.env` (исключен из git)
- Используйте специальные аккаунты с минимально необходимыми правами
- Сессии Synology завершаются после выполнения
- HTTPS рекомендуется для подключений NAS в продакшене

## Разработка

### Структура кода

```shell
ae_anons/
├── .gitignore
├── .env.example
├── Cargo.toml
├── LICENSE
├── README.md
├── assets/
│   └── logo.png
└── src/
    ├── main.rs           # Точка входа, CLI
    ├── config.rs         # Конфигурация из .env
    ├── nexrender.rs      # Модели заданий Nexrender
    ├── synology.rs       # Клиент Synology API
    ├── processor.rs      # Логика обработки
    ├── web.rs            # Веб-сервер и API
    └── static/
        ├── index.html    # Веб-интерфейс
        └── style.css     # Стили
```

## Зависимости

### Основные зависимости

| Crate              | Версия  | Назначение                              |
|--------------------|---------|-----------------------------------------|
| reqwest            | 0.12    | HTTP клиент для коммуникации с API      |
| serde / serde_json | 1.0     | Сериализация и десериализация JSON      |
| calamine           | 0.26    | Парсинг файлов Excel (.xlsx, .xls)      |
| chrono             | 0.4     | Обработка дат и времени                 |
| tokio              | 1.0     | Асинхронная среда выполнения            |
| dotenv             | 0.15    | Загрузка конфигурации из .env файла     |
| log / env_logger   | 0.4/0.11| Система логирования с уровнями          |
| thiserror          | 2.0     | Эргономичные определения типов ошибок   |
| anyhow             | 1.0     | Упрощённая обработка ошибок             |
| regex              | 1.11    | Регулярные выражения                    |
| urlencoding        | 2.1     | Кодирование URL для API запросов        |
| bytes              | 1.9     | Работа с байтовыми данными              |
| futures            | 0.3     | Асинхронные примитивы                   |

### Веб-сервер и CLI

| Crate              | Версия | Назначение                              |
|--------------------|--------|-----------------------------------------|
| axum               | 0.8    | Веб-фреймворк для REST API              |
| tower              | 0.5    | Промежуточное ПО для веб-сервера        |
| tower-http         | 0.6    |HTTP утилиты (CORS, статика, трассировка)|
| askama             | 0.15   | Шаблонизация (опционально)              |
| clap               | 4.5    | Парсинг аргументов командной строки     |

### Платформозависимые зависимости

| Crate              | Версия | Платформа | Назначение                       |
|--------------------|--------|-----------|----------------------------------|
| openssl            | 0.10   | Linux     | Криптография для HTTPS (vendored)|

## 🙏 Благодарности

### Nexrender

Особая благодарность проекту **[Nexrender](https://github.com/inlife/nexrender)**
([@inlife](https://github.com/inlife) и контрибьюторам) за создание надёжной платформы
для автоматизации After Effects.

### Font Awesome Free 6.4.0

Веб-интерфейс использует иконки и шрифты **Font Awesome Free**:

- **Иконки**: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
- **Шрифты**: [SIL OFL 1.1](https://scripts.sil.org/OFL)

© 2023 Fonticons, Inc. — <https://fontawesome.com>

## Лицензия

**AE Anons** — [License](LICENSE)  
**Nexrender** — [MIT License](https://github.com/inlife/nexrender/blob/master/LICENSE)

Обе лицензии MIT обеспечивают полную свободу использования и модификации кода.

**Разрешается:**

- ✅ Использовать в коммерческих целях
- ✅ Изменять исходный код
- ✅ Распространять копии
- ✅ Использовать приватно

**Требуется:**

- Сохранять копирайт и текст лицензии

## Поддержка

Для вопросов и запросов функций обращайтесь:

- <a.barabanov@tvstart.ru>
- [README.md](https://git.tvstart.ru/lexx/AE_Anons)

## История изменений

### v0.2.6 (текущая)

- Сортировка заданий по дате и времени события (самые ранние — первыми)
- Сортировка по варианту (оригинал → today → tomorrow)
- Последовательная отправка для гарантированного порядка в очереди
- Исправлена нормализация дефисов (2 и более дефиса подряд → 1)
- Исправлен SINGLE шаблон (убран несуществующий слой TEAMS)
- Добавлена поддержка кеширования ассетов (cache: true/false)
- Логотипы команд не кешируются, логотипы каналов и видео-паки кешируются

### v0.2.5

- Оптимизация памяти: очистка неиспользуемых логотипов
- Групповая отправка заданий по 3 для сохранения порядка
- Добавлен UID в логи отправки

### v0.2.4

- Полностью автономный режим (встроенный Font Awesome)
- Добавлен favicon
- Все статические ресурсы встроены в бинарник

### v0.2.3

- Веб-интерфейс с настраиваемым портом (WEB_PORT)
- Тёмная/светлая тема с автоопределением ОС
- Сортировка по всем колонкам в интерфейсе
- Фильтрация по имени файла/UID
- Остановка всех активных заданий
- Автообновление каждые 60 секунд
- Улучшенное debug-логирование
- Исправлена обработка UNC/SMB путей

### v0.2.2

- Исправлено отображение имён выходных файлов в веб-интерфейсе
- Улучшена цветовая схема
- Добавлена сортировка по всем колонкам
- Вынесены стили в отдельный CSS файл

### v0.2.0

- Добавлен веб-интерфейс для управления заданиями
- Реализован REST API
- Добавлена поддержка тёмной/светлой темы
- Автообновление статуса заданий
- Возможность остановки всех активных заданий

### v0.1.1

- Оптимизирована работа с памятью
- Убрана функция создания .json

### v0.1.0

- Первый выпуск
- Интеграция с Synology Office
- Базовая генерация заданий Nexrender
- Парсинг Excel с динамическим обнаружением листов

---

Made with 🦀 Rust and ☕ coffee
