Files
jellybit/docs/research/tvdb-search-translations.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

7.2 KiB
Raw Blame History

Переводы в ответе поиска TheTVDB v4

Клиент TVDB (internal/metadata/tvdb.go) берёт локализованное название кандидата из ответа /search. Здесь записано, откуда взята форма этого ответа и чего в ней не подтверждено.

Провенанс — и он слабый. Всё ниже сверено по публичной документации TheTVDB API v4, файл docs/swagger.yml репозитория thetvdb/v4-api, поле info.version = 4.7.10 (прочитано 2026-08-07). Живым прогоном не подтверждено ни одно наблюдение: CLAUDE.md → «Запреты» запрещает ходить в боевые метабазы из отладочных прогонов и расходовать лимиты ключа. Всё дальнейшее — условие, а не замер. Оракул, который это закроет, написан и ждёт человека:

TVDB_API_KEY=… go test ./internal/metadata/ -run Integration -v

Он печатает Title и OriginalTitle первых кандидатов.

Параметр language у /search — фильтр, а не селектор перевода

Дословно из swagger, параметр language эндпоинта /search:

Restrict results to a specific primary language. Should include the 3 character language code.

То есть он сужает выдачу по основному языку записи, а не выбирает, на каком языке вернуть название. Форум TheTVDB подтверждает направление: маршруты /search не возвращают записи, которых нет на указанном языке.

Следствие для нас: передача language=rus отсекла бы ровно те записи, ради которых заводилась задача, — у Ne Zha основной язык zho. Поэтому запрос поиска параметром языка не параметризуется, а локаль работает только на стороне разбора ответа. Это заказано спекой (openspec/specs/metadata-match/, требование «Локализованное название кандидата TVDB»).

Расхождение с TMDB намеренное: у TMDB language — именно селектор локализованного поля, и там он в запрос уходит.

Поля SearchResult, относящиеся к названию

Из схемы SearchResult того же swagger:

Поле Тип по схеме Что берём
name string primary name записи — идёт в Candidate.OriginalTitle и служит фолбэком для Title
translations TranslationSimple карта «код языка → название»; из неё берём Candidate.Title
name_translated string не используем
overviews, overview_translated описания не используем
primary_language string не используем
translationsWithLang массив строк не используем

TranslationSimple в самом файле swagger описан как открытая карта (свободные ключи со строковыми значениями); полного текста этой схемы вычитать не удалось — документ в местах чтения обрывался. Форма «карта кода языка в строку» принята по описанию поля и по обсуждениям в трекере thetvdb/v4-api, где встречаются фрагменты вида "translations": {"eng": "…"}. Это самое слабое место записки: если реальная форма иная (список объектов, двухбуквенные ключи), разбор молча уйдёт в фолбэк.

Почему не name_translated. Семантика поля в документации не описана вовсе — не сказано ни на каком языке оно приходит, ни от чего зависит. Правдоподобно, что заполняет его поисковый индекс при заданном фильтре language, которого мы не шлём. Взять его в фолбэк значило бы получить название на неизвестном языке молча; карта translations самодостаточна.

Что известно про вырожденные значения

В трекере thetvdb/v4-api есть подтверждённый случай, когда name приезжает пустой строкой при непустом блоке переводов (issue про "name":"" must not be empty). Отсюда два следствия для разбора, оба заказаны спекой:

  • пустая строка в этих полях реальна, поэтому пустота значения перевода проверяется после обрезки пробелов;
  • блок переводов может нести ключ с пустым значением — это не «перевод есть».

Как мы защищаемся от того, что запись неверна

Наблюдение не подтверждено, поэтому разбор устроен так, чтобы ошибка записки стоила как можно меньше:

  • блок переводов разбирается отдельно от остального ответа и его негодная форма гасится в фолбэк: косметическое поле не получает права уронить выдачу поиска целиком;
  • ключ ищется регистронезависимо;
  • если в выдаче не разобрался ни один блок переводов, клиент пишет строку DEBUG. Это единственный сигнал, отличающий «форма ответа не та, что здесь записана» от штатного «перевода на этот язык нет»: без него неверное предположение жило бы в бою неограниченно долго при зелёном гейте.

Условие пересмотра

Записка протухает от смены версии API TheTVDB (сегодня v4, swagger 4.7.10) и от любого ручного прогона интеграционного теста: первый же живой ответ обязан заменить здесь предположения на наблюдения, а слова «живым прогоном не подтверждено» — на дату и результат прогона.