Files
jellybit/docs/research/tvdb-search-translations.md
av 3bce73fc34 раскладка av-dev повышена с канона 12 до версии 5
- три плагина слились в один `av-dev`: служебные `docs/.docs.json` и
  `tasks/.tasks.json` заменены на `.av-dev.toml` в корне, в гейте переехали пути
  трёх скриптов, вызовы скиллов переименованы по всему репозиторию
- тип задачи `goal` и `ROADMAP.md` упразднены: семь целей закрыты с причинами,
  теги сняты, объявлена стадия `support`
- метка `small`/`medium`/`large` снята из процесса — вместо «Триггеров метки» в
  review.md подраздел «Когда звать глубокое ревью»; следом разобран урожай
  doc-consistency: девять фактов сведены к одному дому
2026-09-02 09:55:28 +03:00

7.3 KiB
Raw Permalink 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) и от любого ручного прогона интеграционного теста: первый же живой ответ обязан заменить здесь предположения на наблюдения, а слова «живым прогоном не подтверждено» — на дату и результат прогона.