Fix: Folgen in vollstaendigem Episoden-Ordner OHNE -GROUP-Suffix werden umbenannt
Alte deutsche Dokus/Serien-Ordner ohne Gruppen-Suffix (Ordner endet auf bare Codec ".XviD", kein "-GROUP") wurden vom Auto-Rename als "kein Zielname" verworfen — die Folge landete dann ROH in der Library (z.B. "safari-fm-s04e08a.avi" statt "Fluss-Monster.S04E08a.Am.Essequibo.Teil.1.German.DOKU.SATRiP.XviD.avi"). buildAutoRenameBaseName akzeptiert jetzt zusaetzlich einen vollstaendigen Episoden- Ordner: echter SxxExx-Token IM Ordnernamen UND ein Codec-/Aufloesungs-Marker (SCENE_RESOLUTION_MARKER_RE / SCENE_CODEC_MARKER_RE, inkl. xvid/divx). Der Part- Buchstabe a/b bleibt erhalten (Ordnername dient unveraendert als Zielname), sodass Teil 1 und Teil 2 nicht kollidieren. Konservativ: ein nackter "Show.S01E01"-Ordner ohne Qualitaets-/Codec-Marker wird weiterhin nicht abgeleitet. Greift in Auto-Rename und Collect. 5 Unit- + 1 Collect-Integrationstest; v1.7.180-Fallback nutzt jetzt dieselben Module-Konstanten (DRY).
This commit is contained in:
@@ -1061,3 +1061,45 @@ describe("isBonusContent (numbered episodes are never bonus)", () => {
|
||||
expect(isBonusContent(fp, pkgDir, "Making.Of")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("complete episode folder WITHOUT group suffix (codec/resolution only)", () => {
|
||||
const hash = "c284d9d9072eaf3ac314d05f951dd115";
|
||||
|
||||
it("uses the clean folder name when it has an episode token + codec but no -GROUP (safari S04E08a)", () => {
|
||||
// Echter Bug (rename-session 2026-06-04): alte deutsche Doku ohne Gruppen-Suffix.
|
||||
// Ordner endet auf ".XviD" (kein "-GROUP") -> buildAutoRenameBaseName lieferte null ->
|
||||
// "kein Zielname" -> Datei landete roh als "safari-fm-s04e08a.avi" in der Library.
|
||||
const folder = "Fluss-Monster.S04E08a.Am.Essequibo.Teil.1.German.DOKU.SATRiP.XviD";
|
||||
const decision = decideAutoRenameBaseName([folder, hash], "safari-fm-s04e08a.avi", "safari-fm-s04e08a", hash, hash);
|
||||
expect(decision).toEqual({ kind: "rename", baseName: folder });
|
||||
});
|
||||
|
||||
it("keeps multi-part letters a/b distinct (Teil.1 vs Teil.2 do NOT collide)", () => {
|
||||
const fa = "Fluss-Monster.S04E08a.Am.Essequibo.Teil.1.German.DOKU.SATRiP.XviD";
|
||||
const fb = "Fluss-Monster.S04E08b.Am.Essequibo.Teil.2.German.DOKU.SATRiP.XviD";
|
||||
const da = decideAutoRenameBaseName([fa, hash], "safari-fm-s04e08a.avi", "safari-fm-s04e08a", hash, hash);
|
||||
const db = decideAutoRenameBaseName([fb, hash], "safari-fm-s04e08b.avi", "safari-fm-s04e08b", hash, hash);
|
||||
expect(da).toEqual({ kind: "rename", baseName: fa });
|
||||
expect(db).toEqual({ kind: "rename", baseName: fb });
|
||||
// Verschiedene Zielnamen -> keine "(2)"-Kollision beim Sammeln.
|
||||
expect((da as any).baseName).not.toBe((db as any).baseName);
|
||||
});
|
||||
|
||||
it("the previously-working group-suffix folder still works (no regression)", () => {
|
||||
const folder = "Fluss-Monster.S01E02.Auf.der.Suche.nach.dem.Killer-Wels.German.DOKU.SATRiP.XviD-SAFARi";
|
||||
const decision = decideAutoRenameBaseName([folder, hash], "safari-fm-s01e02.avi", "safari-fm-s01e02", hash, hash);
|
||||
expect(decision).toEqual({ kind: "rename", baseName: folder });
|
||||
});
|
||||
|
||||
it("does NOT use a bare episode folder WITHOUT any codec/resolution marker (stays conservative)", () => {
|
||||
// "Show.S01E01" allein (keine Qualitaets-/Codec-Info, kein -GROUP) ist mehrdeutig ->
|
||||
// weiterhin kein Ableiten (kein Over-Firing auf generische Ordner).
|
||||
const decision = decideAutoRenameBaseName(["Show.S01E01", hash], "abc-s01e01.avi", "abc-s01e01", hash, hash);
|
||||
expect(decision.kind).toBe("skip");
|
||||
});
|
||||
|
||||
it("does NOT fabricate a name from a token-LESS folder (Mega-Direct guard intact)", () => {
|
||||
const decision = decideAutoRenameBaseName(["Mega-Direct-Pack", hash], "Direct.Show.S01E01.DIRECT.mkv", "Direct.Show.S01E01.DIRECT", hash, hash);
|
||||
expect(decision.kind).toBe("skip");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9686,6 +9686,72 @@ describe("download manager", () => {
|
||||
void manager;
|
||||
}, 20000);
|
||||
|
||||
it("collect CLEANS a raw .avi whose folder is a complete episode name WITHOUT a -GROUP suffix (safari S04E08a)", async () => {
|
||||
// Echter Bug (rename-session 2026-06-04): alte deutsche Doku ohne Gruppen-Suffix
|
||||
// (Ordner endet ".XviD", kein "-GROUP"). buildAutoRenameBaseName lieferte null -> die
|
||||
// Folge landete ROH als "safari-fm-s04e08a.avi" in der Library. Der Part-Buchstabe a/b
|
||||
// muss erhalten bleiben (Teil 1 vs Teil 2 duerfen nicht kollidieren).
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-dm-"));
|
||||
tempDirs.push(root);
|
||||
|
||||
const packageName = "c284d9d9072eaf3ac314d05f951dd115";
|
||||
const outputDir = path.join(root, "downloads", packageName);
|
||||
const extractDir = path.join(root, "extract", packageName);
|
||||
const mk = (folder: string, raw: string) => {
|
||||
const epDir = path.join(extractDir, folder);
|
||||
fs.mkdirSync(epDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(epDir, raw), Buffer.alloc(4096, 8));
|
||||
};
|
||||
const folderA = "Fluss-Monster.S04E08a.Am.Essequibo.Teil.1.German.DOKU.SATRiP.XviD";
|
||||
const folderB = "Fluss-Monster.S04E08b.Am.Essequibo.Teil.2.German.DOKU.SATRiP.XviD";
|
||||
mk(folderA, "safari-fm-s04e08a.avi");
|
||||
mk(folderB, "safari-fm-s04e08b.avi");
|
||||
|
||||
const session = emptySession();
|
||||
const packageId = `${packageName}-pkg`;
|
||||
const createdAt = Date.now() - 60_000;
|
||||
session.packageOrder = [packageId];
|
||||
session.packages[packageId] = {
|
||||
id: packageId,
|
||||
name: packageName,
|
||||
outputDir,
|
||||
extractDir,
|
||||
status: "completed",
|
||||
itemIds: [],
|
||||
cancelled: false,
|
||||
enabled: true,
|
||||
createdAt,
|
||||
updatedAt: createdAt
|
||||
};
|
||||
|
||||
const mkvLibraryDir = path.join(root, "mkv-library");
|
||||
const manager = new DownloadManager(
|
||||
{
|
||||
...defaultSettings(),
|
||||
outputDir: path.join(root, "downloads"),
|
||||
extractDir: path.join(root, "extract"),
|
||||
autoExtract: true,
|
||||
autoRename4sf4sj: true,
|
||||
collectMkvToLibrary: true,
|
||||
mkvLibraryDir,
|
||||
enableIntegrityCheck: false,
|
||||
cleanupMode: "none"
|
||||
},
|
||||
session,
|
||||
createStoragePaths(path.join(root, "state"))
|
||||
);
|
||||
|
||||
await (manager as any).collectMkvFilesToLibrary(packageId, session.packages[packageId], undefined, false);
|
||||
|
||||
// Beide Folgen sauber benannt in der Library, Part a/b distinkt, KEINE rohen Namen.
|
||||
expect(fs.existsSync(path.join(mkvLibraryDir, `${folderA}.avi`))).toBe(true);
|
||||
expect(fs.existsSync(path.join(mkvLibraryDir, `${folderB}.avi`))).toBe(true);
|
||||
expect(fs.existsSync(path.join(mkvLibraryDir, "safari-fm-s04e08a.avi"))).toBe(false);
|
||||
expect(fs.existsSync(path.join(mkvLibraryDir, "safari-fm-s04e08b.avi"))).toBe(false);
|
||||
|
||||
void manager;
|
||||
}, 20000);
|
||||
|
||||
it("deferred final pass renames fresh files before collecting them (no scene names in library)", async () => {
|
||||
// Folge-Fund zu 18eada9 (verifiziert via Advisor-Gate): 18eada9 schloss den
|
||||
// "frische Datei landet unbenannt"-Bug nur fuer den HYBRID-Pfad (deferFreshFiles=true
|
||||
|
||||
Reference in New Issue
Block a user