- три плагина слились в один `av-dev`: служебные `docs/.docs.json` и `tasks/.tasks.json` заменены на `.av-dev.toml` в корне, в гейте переехали пути трёх скриптов, вызовы скиллов переименованы по всему репозиторию - тип задачи `goal` и `ROADMAP.md` упразднены: семь целей закрыты с причинами, теги сняты, объявлена стадия `support` - метка `small`/`medium`/`large` снята из процесса — вместо «Триггеров метки» в review.md подраздел «Когда звать глубокое ревью»; следом разобран урожай doc-consistency: девять фактов сведены к одному дому
7.3 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) и от любого ручного прогона интеграционного теста: первый же живой ответ обязан заменить здесь предположения на наблюдения, а слова «живым прогоном не подтверждено» — на дату и результат прогона.