- локаль из [general].language применяется при разборе ответа /search, а в запрос не уходит: параметр language у TVDB — фильтр выдачи, а не селектор перевода (ADR-2026-08-07) - Title берётся из блока translations с тотальным фолбэком на primary name, OriginalTitle — из primary name; форма ответа сверена по документации и живым прогоном не подтверждена (docs/research) - неожиданная форма ответа даёт WARN: признак — отсутствие во всей выдаче ключей языка ожидаемого вида, а не неудача разбора блока
79 lines
6.4 KiB
Markdown
79 lines
6.4 KiB
Markdown
## Why
|
||
|
||
Глобальная настройка `[general].language` правит только промпт LLM и клиент TMDB;
|
||
до клиента TVDB она не доезжает вовсе. TVDB отдаёт primary name — название на
|
||
языке оригинала, — и оно попадает в карточку ревью и в имя папки Jellyfin как
|
||
есть: у [movie 131155](https://www.thetvdb.com/movies/131155-) это `哪吒之魔童降世`
|
||
вместо «Нэчжа», хотя русский перевод у записи есть. Плюс `Candidate.OriginalTitle`
|
||
у TVDB не заполняется вовсе, хотя это ось сравнения при матче: сегодня TVDB
|
||
сравнивается только по одному названию из двух возможных.
|
||
|
||
## What Changes
|
||
|
||
- `TVDBConfig` получает поле `Language` — абстрактный код (`ru`|`en`) из
|
||
`cfg.ContentLanguage()`, как уже сделано для TMDB. Диалект (у TVDB это
|
||
трёхбуквенный код ISO 639-2: `rus`/`eng`) выводит сам `internal/metadata/tvdb.go`
|
||
тотальным `switch` с default-веткой — по решению 2 архивного
|
||
[design content-language-switch](../archive/2026-07-24-content-language-switch/design.md).
|
||
- Разбор ответа `/search` дополняется картой `translations` (код языка → название).
|
||
`Candidate.Title` берётся из `translations[код]`, при отсутствии перевода —
|
||
из primary `name` (молчаливой пустоты быть не должно).
|
||
- `Candidate.OriginalTitle` заполняется primary `name`.
|
||
- **Параметр `language` в запрос `/search` НЕ добавляется.** По
|
||
[swagger TVDB v4 4.7.10](https://raw.githubusercontent.com/thetvdb/v4-api/main/docs/swagger.yml)
|
||
этот параметр — фильтр («Restrict results to a specific primary language»), а не
|
||
селектор перевода: он сузил бы выдачу и отрезал именно те записи, ради которых
|
||
задача заводилась. Разбор ведётся по ответу, а не по запросу. Расхождение с
|
||
критерием приёмки задачи вынесено вопросом человеку — см. `## Открытый вопрос`.
|
||
- **Форма ответа TVDB живым API не сверялась** — только по публичной документации
|
||
(см. `docs/research/tvdb-search-translations.md`). Интеграционный тест за
|
||
env-гейтом `TVDB_API_KEY` написан, но не запускался.
|
||
|
||
Ломающих изменений нет: конфиг не меняется, новых настроек не появляется.
|
||
|
||
## Capabilities
|
||
|
||
### New Capabilities
|
||
|
||
Новых нет.
|
||
|
||
### Modified Capabilities
|
||
|
||
- `metadata-match`: требование «Локаль запроса к TMDB» получает соседа —
|
||
«Локализованное название кандидата TVDB». Обобщать существующее требование на
|
||
всех провайдеров нельзя: механика у TMDB и TVDB разная (параметр запроса против
|
||
разбора ответа), и одно требование на двоих скрыло бы эту разницу.
|
||
|
||
## Impact
|
||
|
||
- `internal/metadata/tvdb.go` — `TVDBConfig.Language`, вывод кода языка, разбор
|
||
`translations` в `tvdbSearchResp`, заполнение `Title`/`OriginalTitle`.
|
||
- `internal/metadata/tvdb_test.go` — стенд `httptest` с блоком `translations`,
|
||
табличный тест на перевод/фолбэк/`OriginalTitle`.
|
||
- `internal/metadata/integration_test.go` — интеграционный тест за `TVDB_API_KEY`
|
||
печатает `Title` и `OriginalTitle`. **Пишется, но не запускается.**
|
||
- `cmd/jellybit/serve.go` — сборка провайдера TVDB получает `Language`.
|
||
- `internal/config/config.go` — в `validate` живёт единственный перечень
|
||
потребителей кода языка («при добавлении кода синхронно расширь мапперы
|
||
`metadata.tmdbLocale` и `recognize.languageDirective`»); третий маппер
|
||
дописывается в этот перечень.
|
||
- `docs/research/tvdb-search-translations.md` — новая записка о форме ответа
|
||
`/search` с честным провенансом.
|
||
- Поведение матча: `strongMatches` сравнивает план и с `Title`, и с
|
||
`OriginalTitle`. У TVDB сегодня `OriginalTitle` пуст, поэтому сравнение идёт по
|
||
одному названию; после изменения их станет два (локализованное + оригинальное).
|
||
Логика гейта не трогается, но его **вход** меняется, и следствие двустороннее:
|
||
запись, которую отсекал иероглифический primary name, теперь может пройти по
|
||
переводу (задача уйдёт в авто вместо review) — и наоборот, две разные записи
|
||
могут совпасть с планом разными названиями, тогда единичный сильный матч
|
||
станет двумя и задача уйдёт в review вместо авто. Второе направление —
|
||
в сторону человека, то есть безопасную. Инвариант «авто-раскладка только при
|
||
подтверждённом матче» не двигается.
|
||
- Внешний контракт: TheTVDB API v4 `/search`. Живых запросов в рамках задачи не
|
||
делалось (запрет `CLAUDE.md` → «Запреты»: лимиты метабаз не расходуем).
|
||
|
||
## Открытый вопрос
|
||
|
||
Форма ответа `/search` не сверена живым API. Вопрос человеку записан в
|
||
`docs/tasks/items/tvdb-title-locale.md` → раздел «Вопросы».
|