Renaming: vollstaendigen Episoden-Ordner als Namen nutzen, wenn Quelle keinen SxxExx-Token hat

User-Report (Desktop-Log): "Kreuzfahrt ins Glück" — 25 Folgen "bet_kig_01_hdt.mkv" (obfuskiert,
KEIN SxxExx-Token) landeten roh in der Library, obwohl der Episoden-Ordner
"Kreuzfahrt.ins.Glueck.01.Hochzeitsreise.nach.Burma.2007.German.720p.HDTV.x264-BET" bereits der
saubere Name ist (Episode als "01" statt S01E01).

Ursache (vorbestehend, nicht v1.7.178/179): buildAutoRenameBaseName gibt null zurueck, sobald die
QUELLE keinen SxxExx-Token hat — das "Folge 01"-Nummernformat wurde nie unterstuetzt.

Fix: Fallback in decideAutoRenameBaseName — fehlt der Quell-Episode-Token und kann normal kein
Name abgeleitet werden, aber ein folderCandidate ist ein VOLLSTAENDIGER Scene-Release-Ordner
(Scene-Gruppe UND Aufloesung ODER Codec, kein reiner Season-Ordner), wird dieser Ordnername
direkt verwendet (note "folder-as-is"). Greift NUR ohne Quell-Episode-Token -> Mega-Direct
(mit Quell-Token) bleibt no-target. Aufloesung ODER Codec (nicht nur Aufloesung) deckt
DVDRip/XviD ohne 720p ab (Advisor-Punkt). Bonus/Sample werden vorher gefiltert.

Verifiziert: tsc 6, 682 Tests gruen (+3: Kreuzfahrt real, DVDRip-nur-Codec, Mega-Direct-bleibt-
no-target), Build gruen. Advisor + reproduzierter Diagnose-Test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sucukdeluxe 2026-06-04 02:32:29 +02:00
parent e9c6a6bcae
commit dc271e08ff
3 changed files with 86 additions and 1 deletions

View File

@ -1422,7 +1422,7 @@ export function buildAutoRenameBaseNameFromFoldersWithOptions(
* clean target base name to rename to, or a skip with the reason (the caller * 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). */ * logs and falls back to KEEPING the current name raw-keep is the floor). */
export type AutoRenameNameDecision = 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 }; | { kind: "skip"; reason: "no-target" | "source-better" | "token-loss" | "token-mismatch"; targetBaseName?: string; sourceEpisodeToken?: string; targetEpisodeToken?: string };
export function decideAutoRenameBaseName( export function decideAutoRenameBaseName(
@ -1510,6 +1510,27 @@ export function decideAutoRenameBaseName(
} }
if (!targetBaseName) { 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: "skip", reason: "no-target" };
} }
return { kind: "rename", baseName: targetBaseName, note }; return { kind: "rename", baseName: targetBaseName, note };

View File

@ -219,3 +219,32 @@ einbinden → Unterstrich-Gruppen erkannt → sauberer Ordner gewinnt → ideale
VOLLSTAENDIGEN Quellnamen (Serie+Episode+Aufloesung+Codec) durch einen, der die Serien-Identitaet VOLLSTAENDIGEN Quellnamen (Serie+Episode+Aufloesung+Codec) durch einen, der die Serien-Identitaet
verliert" wuerde KUENFTIGE unbekannte Gruppen-Formate abfangen — riskanter Eingriff in Guard A, verliert" wuerde KUENFTIGE unbekannte Gruppen-Formate abfangen — riskanter Eingriff in Guard A,
nur mit Tests + auf User-Wunsch. 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.

View File

@ -128,6 +128,41 @@ describe("decideAutoRenameBaseName (shared naming decision — used by auto-rena
expect(decision.kind).toBe("rename"); expect(decision.kind).toBe("rename");
expect(decision.kind === "rename" && decision.baseName).toBe(epFolder); 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", () => { describe("hasMeaningfulSeriesPrefix", () => {