Files
jellybit/openspec/changes/archive/2026-08-07-tvdb-title-locale/proposal.md
T
av fdbc781197 metadata: TVDB отдаёт локализованное название и оригинал
- локаль из [general].language применяется при разборе ответа /search, а в
  запрос не уходит: параметр language у TVDB — фильтр выдачи, а не селектор
  перевода (ADR-2026-08-07)
- Title берётся из блока translations с тотальным фолбэком на primary name,
  OriginalTitle — из primary name; форма ответа сверена по документации и
  живым прогоном не подтверждена (docs/research)
- неожиданная форма ответа даёт WARN: признак — отсутствие во всей выдаче
  ключей языка ожидаемого вида, а не неудача разбора блока
2026-08-07 15:17:05 +03:00

79 lines
6.4 KiB
Markdown
Raw 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.
## 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` → раздел «Вопросы».