From ab5fcaf836120740983ebcb09f9212f9b0c61124 Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Sat, 4 Apr 2026 20:31:58 +0200 Subject: [PATCH] Clean up companion metadata files (.sfv, .nfo, .md5) with their archives collectArchiveCleanupTargets() now includes companion files (.sfv, .nfo, .md5, .sha1, .sha256, .crc, .srr) that share the same base stem as the archive parts. Previously these were left as orphans after archive cleanup. Applies to all archive types: multipart RAR, single RAR, ZIP, split ZIP, 7z, and split 7z. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/main/extractor.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/extractor.ts b/src/main/extractor.ts index 04adea4..2f684e6 100644 --- a/src/main/extractor.ts +++ b/src/main/extractor.ts @@ -438,13 +438,26 @@ export function collectArchiveCleanupTargets(sourceArchivePath: string, director } }; + // Companion metadata files (.sfv, .nfo, .md5, etc.) share the same base stem + // as the archive and should be cleaned up together with the archive parts. + const COMPANION_EXTS_RE = /\.(?:sfv|nfo|nzb|md5|sha1|sha256|crc|srr)$/i; + const addCompanions = (stemRe: string): void => { + for (const candidate of filesInDir) { + if (!COMPANION_EXTS_RE.test(candidate)) continue; + const candidateStem = candidate.replace(/\.[^.]+$/, ""); + if (new RegExp(`^${stemRe}$`, "i").test(candidateStem)) { + targets.add(path.join(dir, candidate)); + } + } + }; + const multipartRar = fileName.match(/^(.*)\.part\d+\.rar$/i); if (multipartRar) { const prefix = escapeRegex(multipartRar[1]); addMatching(new RegExp(`^${prefix}\\.part\\d+\\.rar$`, "i")); - // RAR5 recovery volumes: prefix.partN.rev AND legacy prefix.rev addMatching(new RegExp(`^${prefix}\\.part\\d+\\.rev$`, "i")); addMatching(new RegExp(`^${prefix}\\.rev$`, "i")); + addCompanions(prefix); return Array.from(targets); } @@ -453,6 +466,7 @@ export function collectArchiveCleanupTargets(sourceArchivePath: string, director addMatching(new RegExp(`^${stem}\\.rar$`, "i")); addMatching(new RegExp(`^${stem}\\.r\\d{2,3}$`, "i")); addMatching(new RegExp(`^${stem}\\.rev$`, "i")); + addCompanions(stem); return Array.from(targets); } @@ -460,6 +474,7 @@ export function collectArchiveCleanupTargets(sourceArchivePath: string, director const stem = escapeRegex(fileName.replace(/\.zip$/i, "")); addMatching(new RegExp(`^${stem}\\.zip$`, "i")); addMatching(new RegExp(`^${stem}\\.z\\d{2,3}$`, "i")); + addCompanions(stem); return Array.from(targets); } @@ -468,6 +483,7 @@ export function collectArchiveCleanupTargets(sourceArchivePath: string, director const stem = escapeRegex(splitZip[1]); addMatching(new RegExp(`^${stem}\\.zip$`, "i")); addMatching(new RegExp(`^${stem}\\.zip\\.\\d{3}$`, "i")); + addCompanions(stem); return Array.from(targets); } @@ -475,6 +491,7 @@ export function collectArchiveCleanupTargets(sourceArchivePath: string, director const stem = escapeRegex(fileName.replace(/\.7z$/i, "")); addMatching(new RegExp(`^${stem}\\.7z$`, "i")); addMatching(new RegExp(`^${stem}\\.7z\\.\\d{3}$`, "i")); + addCompanions(stem); return Array.from(targets); } @@ -483,6 +500,7 @@ export function collectArchiveCleanupTargets(sourceArchivePath: string, director const stem = escapeRegex(splitSeven[1]); addMatching(new RegExp(`^${stem}\\.7z$`, "i")); addMatching(new RegExp(`^${stem}\\.7z\\.\\d{3}$`, "i")); + addCompanions(stem); return Array.from(targets); }