Files
jellybit/openspec/specs/recognition/spec.md
T
avandClaude dfa182a5a9 Ссылки на внешние базы в ревью (recognition)
Каждый кандидат внешней базы метаданных (TMDB/TVDB/TVMaze) теперь несёт
URL на страницу элемента — при ревью можно кликнуть и проверить матч.
URL формируется клиентом провайдера при поиске, сохраняется в БД
(metadata_candidate.url) и отображается ссылкой в веб-интерфейсе.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-29 20:09:20 +03:00

9.4 KiB
Raw Blame History

recognition Specification

Purpose

Распознавание: сопоставление загрузки с конкретным фильмом/сериалом во включённых базах метаданных. Capability описывает контракт LLM на названия, порядок и нормализацию сверки по нескольким названиям, локаль запроса к TMDB и сбор кандидатов для ручного выбора в review.

Requirements

Requirement: Сверка с базой по нескольким названиям

При сверке плана с включёнными базами метаданных система SHALL искать по нескольким названиям в порядке убывания силы ключа: сначала по original_title, затем по локализованному title, затем по provider_hint. Поиск SHALL останавливаться, как только очередной запрос дал единичный сильный матч (ровно один кандидат с совпадением названия и года). Запрос с названием, нормализованно совпадающим с уже выполненным, система SHALL пропускать, чтобы не обращаться к базе повторно с тем же ключом.

Кандидаты для ручного выбора в review система SHALL собирать из всех выполненных заходов с дедупликацией по provider:id и общим потолком.

Scenario: Иностранный фильм находится по оригинальному названию

  • GIVEN план с title «Тёмный рыцарь», original_title «The Dark Knight», год 2008
  • WHEN выполняется сверка с базой
  • THEN первый запрос идёт по «The Dark Knight»
  • AND при единичном сильном матче дальнейшие запросы (по title, provider_hint) не выполняются

Scenario: Фолбэк на локализованное название

  • GIVEN план, для которого запрос по original_title не дал единичного сильного матча
  • WHEN продолжается сверка
  • THEN выполняется запрос по локализованному title
  • AND при отсутствии матча и там — запрос по provider_hint

Scenario: Дублирующий запрос пропускается

  • GIVEN план, у которого original_title нормализованно совпадает с title
  • WHEN выполняется сверка
  • THEN база запрашивается этим названием один раз, повторный заход по title не делается

Requirement: Контракт LLM на оригинальное и локализованное названия

Промпт распознавания SHALL требовать от модели всегда заполнять и title, и original_title. Если отдельного оригинального названия нет или контент российского происхождения, модель SHALL дублировать title в original_title. При неуверенности в оригинальном названии модель SHALL дублировать title, а не выдумывать название (защита от ложного авто-матча).

Разбор ответа SHALL оставаться устойчивым к пустому original_title: пустое значение не отбраковывается и не вызывает correction-ретрай; сверка gracefully использует доступные названия.

Scenario: Российский фильм — дублирование

  • GIVEN раздача российского фильма без отдельного оригинального названия
  • WHEN модель возвращает план
  • THEN title и original_title заполнены одинаковым каноническим названием

Scenario: Пустой original_title не ломает разбор

  • GIVEN ответ модели с пустым original_title
  • WHEN план разбирается
  • THEN разбор успешен без correction-ретрая
  • AND сверка использует titleprovider_hint)

Requirement: Локаль запроса к TMDB

Запрос поиска к TMDB SHALL передавать параметр language, по умолчанию ru-RU, со значением, настраиваемым конфигом [metadata.tmdb].language. Это влияет только на локализованное поле Title/Name; поле original_title/original_name остаётся на языке оригинала, поэтому оригинальная сторона сравнения не затрагивается.

Scenario: Локализованный заголовок приходит по-русски

  • GIVEN TMDB включён, language не задан в конфиге
  • WHEN выполняется поиск фильма с русской локализацией
  • THEN запрос содержит language=ru-RU
  • AND в кандидате Title приходит на русском, а OriginalTitle — на языке оригинала

Requirement: Нормализация названий при сравнении

Нормализация названий для гейта сильного матча SHALL сводить букву ё к е, чтобы написания, различающиеся только ё/е, считались одним названием.

Scenario: «Тёмный» и «Темный» совпадают

  • GIVEN план с названием «Тёмный рыцарь» и кандидат базы «Темный рыцарь»
  • WHEN сравниваются нормализованные названия
  • THEN они считаются совпадающими

Requirement: Кандидат несёт URL для внешней проверки

Каждый кандидат внешней базы метаданных (metadata.Candidate) SHALL нести поле URL — ссылку на страницу элемента (фильма/сериала) на сайте провайдера. URL SHALL формироваться клиентом провайдера при поиске (Search) и сохраняться в таблице metadata_candidate. На странице ревью URL SHALL отображаться кликабельной ссылкой, открывающейся в новой вкладке браузера.

Формат URL для каждого провайдера:

  • TMDB: https://www.themoviedb.org/movie/{id} (фильм) или https://www.themoviedb.org/tv/{id} (сериал) — тип контента известен из запроса Query.Type
  • TVDB: https://www.thetvdb.com/dereferrer/series/{id}
  • TVMaze: https://www.tvmaze.com/shows/{id} — URL SHALL использовать нативный id TVMaze, а не внешний тег (TVDB/IMDb), чтобы ссылка вела на TVMaze-страницу

Scenario: Кандидат TMDB с корректной ссылкой

  • GIVEN TMDB найден кандидат-фильм с id 603 («Матрица»)
  • WHEN клиент TMDB формирует Candidate
  • THEN URL = https://www.themoviedb.org/movie/603

Scenario: Кандидат TVMaze с нативной ссылкой

  • GIVEN TVMaze найден сериал с id 169 («Фарго»), внешний тег — TVDB id 269613
  • WHEN клиент TVMaze формирует Candidate
  • THEN URL = https://www.tvmaze.com/shows/169
  • AND TagProvider/TagID остаются tvdb/269613 (тег папки Jellyfin не меняется)

Scenario: Ссылка в интерфейсе ревью

  • GIVEN загрузка в состоянии review с кандидатами, у которых заполнен url
  • WHEN рендерится страница ревью
  • THEN в таблице кандидатов каждый кандидат SHALL отображаться со ссылкой на внешний сайт
  • AND ссылка открывается в новой вкладке (target="_blank")
  • AND текстом ссылки служит провайдер или сокращённый url

Scenario: URL сохраняется в БД

  • GIVEN результат поиска с кандидатами
  • WHEN кандидаты сохраняются в таблицу metadata_candidate
  • THEN значение url SHALL быть записано в колонку url
  • AND при последующей загрузке данных ревью url доступен без повторной генерации