Единый источник полей отображаемого имени и один рендер полного ярлыка на всех путях (старт и «Обновить имя»/авто-перелив). Раньше старт давал полный «Название (режиссёр, год). Сезон 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>
58 lines
1.7 KiB
Go
58 lines
1.7 KiB
Go
package httpapi
|
||
|
||
import (
|
||
"git.vakhrushev.me/av/jellybit/internal/layout"
|
||
"git.vakhrushev.me/av/jellybit/internal/recognize"
|
||
)
|
||
|
||
// fileRow — строка виджета «файл источника → раскладка», общего для экранов
|
||
// ревью и просмотра загрузки. Целевой путь берётся из превью (единая логика
|
||
// internal/layout), а не вычисляется в шаблоне.
|
||
type fileRow struct {
|
||
Src string
|
||
Dst string // целевой путь; пусто — файл не раскладывается
|
||
RoleLabel string
|
||
Linked bool
|
||
Ignored bool
|
||
}
|
||
|
||
// buildFileRows сшивает файлы плана с целевыми путями из превью раскладки.
|
||
func buildFileRows(plan recognize.Plan, preview []layout.Link) []fileRow {
|
||
dstBySrc := make(map[string]string, len(preview))
|
||
for _, l := range preview {
|
||
dstBySrc[l.Src] = l.Dst
|
||
}
|
||
rows := make([]fileRow, 0, len(plan.Files))
|
||
for _, f := range plan.Files {
|
||
dst := dstBySrc[f.Src]
|
||
rows = append(rows, fileRow{
|
||
Src: f.Src,
|
||
Dst: dst,
|
||
RoleLabel: roleLabel(string(f.Role)),
|
||
Linked: dst != "",
|
||
Ignored: f.Role == "ignore",
|
||
})
|
||
}
|
||
return rows
|
||
}
|
||
|
||
// roleLabel — человекочитаемая роль файла раскладки.
|
||
func roleLabel(role string) string {
|
||
switch role {
|
||
case "episode":
|
||
return "эпизод"
|
||
case "main", "movie":
|
||
return "фильм"
|
||
case "subtitle":
|
||
return "субтитры"
|
||
case "extra":
|
||
return "допматериал"
|
||
case "sample":
|
||
return "семпл"
|
||
case "ignore":
|
||
return "игнор"
|
||
default:
|
||
return role
|
||
}
|
||
}
|