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