diff --git a/src/main/download-manager.ts b/src/main/download-manager.ts index 3bae838..2172bb2 100644 --- a/src/main/download-manager.ts +++ b/src/main/download-manager.ts @@ -1422,7 +1422,7 @@ export function buildAutoRenameBaseNameFromFoldersWithOptions( * clean target base name to rename to, or a skip with the reason (the caller * logs and falls back to KEEPING the current name — raw-keep is the floor). */ export type AutoRenameNameDecision = - | { kind: "rename"; baseName: string; note?: "token-inserted" | "token-applyToken" | "folder-override"; sourceEpisodeToken?: string; targetEpisodeToken?: string } + | { kind: "rename"; baseName: string; note?: "token-inserted" | "token-applyToken" | "folder-override" | "folder-as-is"; sourceEpisodeToken?: string; targetEpisodeToken?: string } | { kind: "skip"; reason: "no-target" | "source-better" | "token-loss" | "token-mismatch"; targetBaseName?: string; sourceEpisodeToken?: string; targetEpisodeToken?: string }; export function decideAutoRenameBaseName( @@ -1510,6 +1510,27 @@ export function decideAutoRenameBaseName( } if (!targetBaseName) { + // Fallback "Junk-Quellname + sauberer Release-Ordner": hat die QUELLE keinen Episode-Token + // (z.B. obfuskiertes "bet_kig_01_hdt") und kann normal kein Name abgeleitet werden, aber EIN + // folderCandidate IST bereits ein VOLLSTAENDIGER Scene-Release-Ordner (Scene-Gruppe UND + // Aufloesung ODER Codec, KEIN reiner Season-Ordner), dann diesen Ordnernamen direkt verwenden. + // Deckt das "Folge 01"-Nummern-Format ab (Episode als "01" statt S01E01), z.B. + // "Kreuzfahrt.ins.Glueck.01.Hochzeitsreise.nach.Burma.2007.German.720p.HDTV.x264-BET". + // Greift NUR ohne Quell-Episode-Token → schliesst sich mit dem Fabrikations-Guard oben aus + // (Mega-Direct hat einen Quell-Token und kommt nie hierher). + if (!extractEpisodeToken(sourceBaseName)) { + const RESOLUTION_RE = /\b(?:480|540|576|720|1080|1440|2160|4320)[pi]\b/i; + const CODEC_RE = /\b(?:x264|x265|x266|h\.?264|h\.?265|h\.?266|hevc|avc|vvc|av1|xvid|divx)\b/i; + for (const folderName of folderCandidates) { + const f = sanitizeFilename(String(folderName || "").trim()); + if (!f) { + continue; + } + if (hasSceneGroupSuffix(f) && (RESOLUTION_RE.test(f) || CODEC_RE.test(f)) && !SCENE_SEASON_ONLY_RE.test(f)) { + return { kind: "rename", baseName: f, note: "folder-as-is" }; + } + } + } return { kind: "skip", reason: "no-target" }; } return { kind: "rename", baseName: targetBaseName, note }; diff --git a/tasks/lessons.md b/tasks/lessons.md index f3e8a26..27c0074 100644 --- a/tasks/lessons.md +++ b/tasks/lessons.md @@ -219,3 +219,32 @@ einbinden → Unterstrich-Gruppen erkannt → sauberer Ordner gewinnt → ideale VOLLSTAENDIGEN Quellnamen (Serie+Episode+Aufloesung+Codec) durch einen, der die Serien-Identitaet verliert" wuerde KUENFTIGE unbekannte Gruppen-Formate abfangen — riskanter Eingriff in Guard A, nur mit Tests + auf User-Wunsch. + +## 2026-06-03 (3) — Renaming-Klasse „Junk-Quellname + sauberer Release-Ordner" (Folge-Nummer statt SxxExx) + +**Symptom (Log 18-18):** „Kreuzfahrt ins Glück" — 25 Folgen `bet_kig_01_hdt.mkv` (obfuskiert, KEIN +SxxExx-Token) im sauberen Episoden-Ordner `Kreuzfahrt.ins.Glueck.01.Hochzeitsreise.nach.Burma.2007. +German.720p.HDTV.x264-BET` (Episode als bloße „01"). Auto-Rename: „kein Zielname" → 25× roh in die +Library. Diesmal SICHTBAR als 25 [WARN] (vorher 0 WARN) — das Log zeigt die Klasse direkt. + +**Ursache (reproduziert):** `buildAutoRenameBaseName` gibt null zurück, sobald die QUELLE keinen +SxxExx-Token hat (Z.1288) — egal wie sauber der Ordner ist. Das „Folge 01"-Nummernformat (kein +S01E01) wurde nie unterstuetzt. VORBESTEHEND, nicht meine v1.7.178/179. + +**Fix:** Fallback in decideAutoRenameBaseName — wenn kein Zielname UND Quelle hat keinen +Episode-Token, den ersten folderCandidate nehmen, der ein VOLLSTAENDIGER Scene-Release-Ordner ist: +`hasSceneGroupSuffix(f) && (RESOLUTION_RE.test(f) || CODEC_RE.test(f)) && !SCENE_SEASON_ONLY_RE.test(f)`. +Greift NUR ohne Quell-Episode-Token → schliesst sich mit dem Fabrikations-Guard aus (Mega-Direct hat +Quell-Token → unerreicht). note:"folder-as-is". + +**Advisor-Punkt (wichtig):** NICHT nur Aufloesung pruefen — alte deutsche TV-Serien gibt es als +DVDRip/XviD OHNE 720p-Token. `RESOLUTION_RE ODER CODEC_RE` → sonst die naechste Runde. Pin-Test: +DVDRip-Variante (kein 720p, nur x264). + +**Edge (Advisor):** Bonus/Sample muss VOR diesem Fallback gefiltert werden (sonst kriegt ein +Featurette/Sample im Episoden-Ordner den Episodennamen). Bestaetigt: Auto-Rename-Loop (Sample-Size + +BONUS_FILENAME_RE) und Collect filtern beide vor der Namensherleitung → gedeckt. + +**Meta:** 3. „anderes Format" in Folge — diese Klasse (Junk-Quelle + sauberer Ordner) ist die +groesste verbleibende. Scene-Naming hat aber einen langen Schwanz: ehrlich „diese Klasse ist +abgedeckt", nicht „jetzt 100%". Das Desktop-Log liefert jede neue Klasse sofort. diff --git a/tests/auto-rename.test.ts b/tests/auto-rename.test.ts index 81b7b82..94934fa 100644 --- a/tests/auto-rename.test.ts +++ b/tests/auto-rename.test.ts @@ -128,6 +128,41 @@ describe("decideAutoRenameBaseName (shared naming decision — used by auto-rena expect(decision.kind).toBe("rename"); expect(decision.kind === "rename" && decision.baseName).toBe(epFolder); }); + + it("uses the complete per-episode folder when the SOURCE has no SxxExx token (bare 'Folge 01' format)", () => { + // User-Report: "Kreuzfahrt ins Glück" — Datei "bet_kig_01_hdt.mkv" (kein SxxExx-Token), + // Episoden-Ordner nummeriert mit "01" statt S01E01. Frueher "kein Zielname" -> roh in die + // Library. Jetzt: der vollstaendige Release-Ordnername wird direkt verwendet. + const folders = [ + "Kreuzfahrt.ins.Glueck.01.Hochzeitsreise.nach.Burma.2007.German.720p.HDTV.x264-BET", + "kig.hdtv.7p-001", + "Kreuzfahrt ins Glück S01" + ]; + const decision = decideAutoRenameBaseName(folders, "bet_kig_01_hdt.mkv", "bet_kig_01_hdt", folders[0], folders[2]); + expect(decision.kind).toBe("rename"); + expect(decision.kind === "rename" && decision.baseName).toBe(folders[0]); + }); + + it("complete-folder fallback fires on CODEC alone (no resolution token — DVDRip/XviD class)", () => { + const folders = [ + "Kreuzfahrt.ins.Glueck.01.Hochzeitsreise.nach.Burma.2007.German.DVDRip.x264-BET", + "Kreuzfahrt ins Glück S01" + ]; + const decision = decideAutoRenameBaseName(folders, "bet_kig_01.mkv", "bet_kig_01", folders[0], folders[1]); + expect(decision.kind).toBe("rename"); + expect(decision.kind === "rename" && decision.baseName).toBe(folders[0]); + }); + + it("complete-folder fallback does NOT fire when the source HAS an episode token (generic pack stays no-target)", () => { + const decision = decideAutoRenameBaseName( + ["Mega-Direct-Pack"], + "Direct.Show.S01E01.German.1080p.WEB.x264-DIRECT.mkv", + "Direct.Show.S01E01.German.1080p.WEB.x264-DIRECT", + "Mega-Direct-Pack", + "Mega-Direct-Pack" + ); + expect(decision.kind).toBe("skip"); + }); }); describe("hasMeaningfulSeriesPrefix", () => {