display_name: слоистое разрешение полей + сохранение режиссёра из контекста
Единый источник полей отображаемого имени и один рендер полного ярлыка на всех путях (старт и «Обновить имя»/авто-перелив). Раньше старт давал полный «Название (режиссёр, год). Сезон N» но выбрасывал структуру, а перелив по распознаванию — усечённый «Title (Year)». - Слоистое разрешение скаляров имени: override → recognition(+match) → новый базовый слой «контекст» (download.parsed_context, JSON naming.Fields). - naming: публичные Fields/Label/Derive, вынесен единый рендер; удалён FormatTitleYear. Сводка сезонов вынесена в recognize.SeasonSummary. - Режиссёр из метабазы (решение A2): TMDB/TVDB credits через опциональный metadata.DirectorProvider; авто-матч кладёт в plan.Director, ручной выбор кандидата тянет credits и пиннит ovrDirector. Метабаза бьёт контекст. - refreshDisplayNameLocked строит полный ярлык из эффективных полей; инфо-панель ревью показывает загруженного режиссёра. - Миграция 0011_parsed_context + ER-схема. Всё косметика: на пути/раскладку не влияет, приём/вывод имени не валятся (best-effort). Закрывает беклог-задачу «Кнопка „Обновить имя“: полный формат ярлыка». OpenSpec: archive/2026-07-11-field-resolution-display-name (ingest, recognition, metadata-match, review). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -173,14 +173,19 @@ type Infohash struct {
|
||||
|
||||
// Download — строка таблицы download.
|
||||
type Download struct {
|
||||
ID string `db:"id"` // ULID (lowercase), публичный ключ домена
|
||||
SourceType SourceType `db:"source_type"`
|
||||
SourceRef string `db:"source_ref"`
|
||||
DisplayName string `db:"display_name"` // имя раздачи (rename в qBittorrent), заголовок в веб-UI
|
||||
Context string `db:"context"`
|
||||
State State `db:"state"`
|
||||
ErrorCode sql.NullString `db:"error_code"`
|
||||
ErrorMsg sql.NullString `db:"error_msg"`
|
||||
ID string `db:"id"` // ULID (lowercase), публичный ключ домена
|
||||
SourceType SourceType `db:"source_type"`
|
||||
SourceRef string `db:"source_ref"`
|
||||
DisplayName string `db:"display_name"` // имя раздачи (rename в qBittorrent), заголовок в веб-UI
|
||||
Context string `db:"context"`
|
||||
// ParsedContext — извлечённая на шаге добавления структура имени (naming, JSON:
|
||||
// type/title/original_title/year/director/season). Базовый (наименее
|
||||
// доверенный) слой источника полей display_name; пусто, пока не выведена.
|
||||
// Косметика: на пути/раскладку не влияет.
|
||||
ParsedContext string `db:"parsed_context"`
|
||||
State State `db:"state"`
|
||||
ErrorCode sql.NullString `db:"error_code"`
|
||||
ErrorMsg sql.NullString `db:"error_msg"`
|
||||
// SourceMissCount — счётчик подряд идущих тиков сверки без раздачи в
|
||||
// qBittorrent (дебаунс пропажи источника, см. state-reconciliation).
|
||||
SourceMissCount int `db:"source_miss_count"`
|
||||
@@ -806,6 +811,19 @@ WHERE id = ?`, name, FormatTime(Now()), id); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetParsedContext сохраняет извлечённую из контекста структуру имени (JSON) —
|
||||
// базовый слой источника display_name (см. capability ingest). Косметика: FSM не
|
||||
// двигает, на пути/раскладку не влияет. Пустой json допустим (нечего сохранять).
|
||||
func (s *Store) SetParsedContext(ctx context.Context, id, jsonStr string) error {
|
||||
if _, err := s.DB.ExecContext(ctx, `
|
||||
UPDATE download
|
||||
SET parsed_context = ?, updated_at = ?
|
||||
WHERE id = ?`, jsonStr, FormatTime(Now()), id); err != nil {
|
||||
return fmt.Errorf("set parsed context %s: %w", id, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setState выполняет UPDATE состояния. reviveOK=true — вызов из гарда
|
||||
// (ActivateIfNoOtherActive), которому переход терминал→активное разрешён;
|
||||
// иначе предикат в UPDATE не даёт молча оживить терминальную задачу.
|
||||
|
||||
Reference in New Issue
Block a user