Fix split-archive cleanup after extraction and release v1.3.7
This commit is contained in:
parent
0a99d3c584
commit
75fc582299
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "real-debrid-downloader",
|
||||
"version": "1.3.6",
|
||||
"version": "1.3.7",
|
||||
"description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)",
|
||||
"main": "build/main/main/main.js",
|
||||
"author": "Sucukdeluxe",
|
||||
|
||||
@ -245,11 +245,76 @@ function extractZipArchive(archivePath: string, targetDir: string, conflictMode:
|
||||
}
|
||||
}
|
||||
|
||||
function escapeRegex(value: string): string {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
|
||||
export function collectArchiveCleanupTargets(sourceArchivePath: string): string[] {
|
||||
const targets = new Set<string>([sourceArchivePath]);
|
||||
const dir = path.dirname(sourceArchivePath);
|
||||
const fileName = path.basename(sourceArchivePath);
|
||||
|
||||
let filesInDir: string[] = [];
|
||||
try {
|
||||
filesInDir = fs.readdirSync(dir, { withFileTypes: true })
|
||||
.filter((entry) => entry.isFile())
|
||||
.map((entry) => entry.name);
|
||||
} catch {
|
||||
return Array.from(targets);
|
||||
}
|
||||
|
||||
const addMatching = (pattern: RegExp): void => {
|
||||
for (const candidate of filesInDir) {
|
||||
if (pattern.test(candidate)) {
|
||||
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"));
|
||||
return Array.from(targets);
|
||||
}
|
||||
|
||||
if (/\.rar$/i.test(fileName)) {
|
||||
const stem = escapeRegex(fileName.replace(/\.rar$/i, ""));
|
||||
addMatching(new RegExp(`^${stem}\\.rar$`, "i"));
|
||||
addMatching(new RegExp(`^${stem}\\.r\\d{2}$`, "i"));
|
||||
return Array.from(targets);
|
||||
}
|
||||
|
||||
if (/\.zip$/i.test(fileName)) {
|
||||
const stem = escapeRegex(fileName.replace(/\.zip$/i, ""));
|
||||
addMatching(new RegExp(`^${stem}\\.zip$`, "i"));
|
||||
addMatching(new RegExp(`^${stem}\\.z\\d{2}$`, "i"));
|
||||
return Array.from(targets);
|
||||
}
|
||||
|
||||
if (/\.7z$/i.test(fileName)) {
|
||||
const stem = escapeRegex(fileName.replace(/\.7z$/i, ""));
|
||||
addMatching(new RegExp(`^${stem}\\.7z$`, "i"));
|
||||
addMatching(new RegExp(`^${stem}\\.7z\\.\\d{3}$`, "i"));
|
||||
return Array.from(targets);
|
||||
}
|
||||
|
||||
return Array.from(targets);
|
||||
}
|
||||
|
||||
function cleanupArchives(sourceFiles: string[], cleanupMode: CleanupMode): void {
|
||||
if (cleanupMode === "none") {
|
||||
return;
|
||||
}
|
||||
for (const filePath of sourceFiles) {
|
||||
|
||||
const targets = new Set<string>();
|
||||
for (const sourceFile of sourceFiles) {
|
||||
for (const target of collectArchiveCleanupTargets(sourceFile)) {
|
||||
targets.add(target);
|
||||
}
|
||||
}
|
||||
|
||||
for (const filePath of targets) {
|
||||
try {
|
||||
fs.rmSync(filePath, { force: true });
|
||||
} catch {
|
||||
|
||||
@ -3,7 +3,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import AdmZip from "adm-zip";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { buildExternalExtractArgs, extractPackageArchives } from "../src/main/extractor";
|
||||
import { buildExternalExtractArgs, collectArchiveCleanupTargets, extractPackageArchives } from "../src/main/extractor";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
@ -71,6 +71,66 @@ describe("extractor", () => {
|
||||
expect(fs.existsSync(path.join(targetDir, "release.txt"))).toBe(true);
|
||||
});
|
||||
|
||||
it("collects companion rar parts for cleanup", () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-extract-"));
|
||||
tempDirs.push(root);
|
||||
const packageDir = path.join(root, "pkg");
|
||||
fs.mkdirSync(packageDir, { recursive: true });
|
||||
|
||||
const part1 = path.join(packageDir, "show.s01e01.part01.rar");
|
||||
const part2 = path.join(packageDir, "show.s01e01.part02.rar");
|
||||
const part3 = path.join(packageDir, "show.s01e01.part03.rar");
|
||||
const other = path.join(packageDir, "other.s01e01.part01.rar");
|
||||
|
||||
fs.writeFileSync(part1, "a", "utf8");
|
||||
fs.writeFileSync(part2, "b", "utf8");
|
||||
fs.writeFileSync(part3, "c", "utf8");
|
||||
fs.writeFileSync(other, "x", "utf8");
|
||||
|
||||
const targets = new Set(collectArchiveCleanupTargets(part1));
|
||||
expect(targets.has(part1)).toBe(true);
|
||||
expect(targets.has(part2)).toBe(true);
|
||||
expect(targets.has(part3)).toBe(true);
|
||||
expect(targets.has(other)).toBe(false);
|
||||
});
|
||||
|
||||
it("deletes split zip companion parts when cleanup is enabled", async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-extract-"));
|
||||
tempDirs.push(root);
|
||||
const packageDir = path.join(root, "pkg");
|
||||
const targetDir = path.join(root, "out");
|
||||
fs.mkdirSync(packageDir, { recursive: true });
|
||||
|
||||
const zipPath = path.join(packageDir, "season.zip");
|
||||
const z01Path = path.join(packageDir, "season.z01");
|
||||
const z02Path = path.join(packageDir, "season.z02");
|
||||
const otherPath = path.join(packageDir, "other.z01");
|
||||
|
||||
const zip = new AdmZip();
|
||||
zip.addFile("episode.txt", Buffer.from("ok"));
|
||||
zip.writeZip(zipPath);
|
||||
fs.writeFileSync(z01Path, "part1", "utf8");
|
||||
fs.writeFileSync(z02Path, "part2", "utf8");
|
||||
fs.writeFileSync(otherPath, "keep", "utf8");
|
||||
|
||||
const result = await extractPackageArchives({
|
||||
packageDir,
|
||||
targetDir,
|
||||
cleanupMode: "delete",
|
||||
conflictMode: "overwrite",
|
||||
removeLinks: false,
|
||||
removeSamples: false
|
||||
});
|
||||
|
||||
expect(result.extracted).toBe(1);
|
||||
expect(result.failed).toBe(0);
|
||||
expect(fs.existsSync(zipPath)).toBe(false);
|
||||
expect(fs.existsSync(z01Path)).toBe(false);
|
||||
expect(fs.existsSync(z02Path)).toBe(false);
|
||||
expect(fs.existsSync(otherPath)).toBe(true);
|
||||
expect(fs.existsSync(path.join(targetDir, "episode.txt"))).toBe(true);
|
||||
});
|
||||
|
||||
it("treats ask conflict mode as skip in zip extraction", async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-extract-"));
|
||||
tempDirs.push(root);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user