## ADDED Requirements

### Requirement: Отображаемое имя торрента из контекста

При добавлении загрузки в qBittorrent система SHALL выводить из контекста
загрузки человекочитаемое отображаемое имя и передавать его в qBittorrent
(параметр `rename` API `/torrents/add`), чтобы задача в списке qBit не
показывалась безликим `dn` magnet-ссылки.

Имя SHALL быть коротким читаемым ярлыком (название, опционально режиссёр и
год; для сериала — номер сезона, если он определён), а не куском сырого
контекста. Имя SHALL очищаться от управляющих символов и переводов строк и
SHALL обрезаться по ограничению длины.

Вывод имени SHALL выполняться синхронно перед отдачей источника в
qBittorrent (параметр `rename` действует только в момент добавления).

Отображаемое имя SHALL влиять только на отображение в qBittorrent и SHALL
NOT влиять на пути файлов на диске, распознавание или раскладку — реальные
пути система по-прежнему читает из qBit API.

#### Scenario: Имя из контекста передаётся в qBittorrent

- **WHEN** загрузку добавляют с непустым контекстом, из которого удалось
  получить имя
- **THEN** система передаёт это имя в qBittorrent в параметре `rename`
- **AND** имя — короткий читаемый ярлык вида «название (режиссёр, год)»,
  где режиссёр и год опциональны

#### Scenario: Контекст пуст или имя не получено

- **WHEN** контекста нет либо ни один способ вывода не дал непустого имени
- **THEN** система добавляет загрузку без параметра `rename`
- **AND** qBittorrent оставляет собственное имя (из `dn`/торрента)

### Requirement: Вывод имени через LLM со структурированным выводом

Система SHALL строить отображаемое имя с помощью LLM (структурированный
JSON-вывод), извлекая из контекста тип (movie/series), название, год,
режиссёра и (для сериала) номер сезона. Год и режиссёр — опциональные поля.

Название SHALL быть на русском языке для российского контента и на
английском (оригинальном) — для остального.

Система SHALL предпринять ограниченное число попыток получить от LLM валидный
результат (корректный JSON с непустым названием); бюджет попыток —
`[llm].max_retries` (по умолчанию 3). Транспортные ретраи провайдера LLM
(сетевые сбои, 429, 5xx) в этот счёт не входят.

Недоступность или ошибка LLM SHALL NOT прерывать приём загрузки: система
переходит к алгоритмическому фолбеку.

#### Scenario: LLM возвращает структурированное имя

- **WHEN** LLM по контексту возвращает валидный JSON с непустым названием
- **THEN** система формирует отображаемое имя из его полей (название, год,
  для сериала — сезон)

#### Scenario: Российский контент — название на русском

- **WHEN** контент распознан как российский
- **THEN** в отображаемом имени используется русское название

#### Scenario: Исчерпан бюджет попыток LLM

- **WHEN** LLM за отведённые попытки (`[llm].max_retries`) не вернул валидный
  результат либо недоступен
- **THEN** система не прерывает приём и переходит к алгоритмическому фолбеку

### Requirement: Алгоритмический фолбек вывода имени без сети

При неудаче LLM система SHALL выводить имя алгоритмически, без сетевых
запросов: брать первую содержательную строку контекста (без ссылок, команд
бота и UI-мусора), отсекать технические характеристики, очищать и обрезать
по длине.

Если и фолбек не дал непустого имени, система SHALL добавить загрузку без
параметра `rename`.

#### Scenario: Фолбек извлекает имя из контекста

- **WHEN** LLM недоступен или исчерпал попытки, а контекст содержательный
- **THEN** система берёт первую содержательную строку контекста, отсекает
  технические характеристики и использует результат как отображаемое имя
- **AND** при этом не делается ни одного сетевого запроса

#### Scenario: Фолбек тоже пуст

- **WHEN** ни LLM, ни алгоритмический фолбек не дали непустого имени
- **THEN** система добавляет загрузку без параметра `rename`
