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

6.4 KiB
Raw Blame History

Why

Глобальная настройка [general].language правит только промпт LLM и клиент TMDB; до клиента TVDB она не доезжает вовсе. TVDB отдаёт primary name — название на языке оригинала, — и оно попадает в карточку ревью и в имя папки Jellyfin как есть: у movie 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.
  • Разбор ответа /search дополняется картой translations (код языка → название). Candidate.Title берётся из translations[код], при отсутствии перевода — из primary name (молчаливой пустоты быть не должно).
  • Candidate.OriginalTitle заполняется primary name.
  • Параметр language в запрос /search НЕ добавляется. По swagger TVDB v4 4.7.10 этот параметр — фильтр («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.goTVDBConfig.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 → раздел «Вопросы».