- локаль из [general].language применяется при разборе ответа /search, а в запрос не уходит: параметр language у TVDB — фильтр выдачи, а не селектор перевода (ADR-2026-08-07) - Title берётся из блока translations с тотальным фолбэком на primary name, OriginalTitle — из primary name; форма ответа сверена по документации и живым прогоном не подтверждена (docs/research) - неожиданная форма ответа даёт WARN: признак — отсутствие во всей выдаче ключей языка ожидаемого вида, а не неудача разбора блока
7.2 KiB
Переводы в ответе поиска 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) и от любого ручного прогона интеграционного теста: первый же живой ответ обязан заменить здесь предположения на наблюдения, а слова «живым прогоном не подтверждено» — на дату и результат прогона.