Раскладка: сходимость папки сериала (второй сезон в ту же папку)

При подтверждённом матче база папки (имя+год) наследуется от живой
папки-якоря того же (provider, provider_id) вместо печати заново из выхода
LLM — так второй/последующий сезон ложится в ТУ ЖЕ папку, а не заводит
рядом почти одинаковую. Отдельная сущность «тайтл» не вводится.

- layout: Plan.FolderBase перекрывает базу в папке и именах файлов;
  TitleFolder разбирает dst_path в папку тайтла и базу (снятие тега).
- store: LiveTitleFolders — dst_path живых ссылок того же матча.
- worker: resolveFolderBase (живость якоря — по наличию папки на диске,
  os.Lstat, а не по статусу ссылки в БД) в linkPlan и в превью ревью
  (превью=применение); рассинхрон нескольких живых папок → review из
  linking (deferred→review в графе нет).

Схема БД не менялась. Change series-folder-convergence заархивирован,
требования влиты в openspec/specs/file-layout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
av
2026-07-10 13:50:49 +03:00
co-authored by Claude Opus 4.8
parent 3f1a928000
commit 5c3ef79496
20 changed files with 1031 additions and 56 deletions
+19
View File
@@ -47,6 +47,25 @@ func TestFolderName(t *testing.T) {
}
}
func TestFolderBase(t *testing.T) {
tests := []struct {
in, want string
}{
{"Фарго (2014) [tvdbid-269613]", "Фарго (2014)"}, // текущий тег
{"Fargo (2017) [tmdbid-123]", "Fargo (2017)"}, // чужой/старый тег снимается так же
{"No Tag (2020)", "No Tag (2020)"}, // без тега — как есть
{"Bare Name", "Bare Name"}, // без года и тега
{"Weird [not a tag", "Weird [not a tag"}, // незакрытый — не трогаем
{"[tvdbid-1]", "[tvdbid-1]"}, // нет " [" с пробелом — не тег
{"Movie (2020) [edition-Director's Cut]", "Movie (2020)"}, // снимается любой хвостовой [...]
}
for _, tt := range tests {
if got := folderBase(tt.in); got != tt.want {
t.Errorf("folderBase(%q) = %q, want %q", tt.in, got, tt.want)
}
}
}
func TestEpisodeStem(t *testing.T) {
if got := episodeStem("Fargo (2015)", 2, 1, 0); got != "Fargo (2015) S02E01" {
t.Errorf("got %q", got)