Backfill extracted archive cleanup on startup in v1.3.8
This commit is contained in:
parent
75fc582299
commit
da51e03cef
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "real-debrid-downloader",
|
||||
"version": "1.3.7",
|
||||
"version": "1.3.8",
|
||||
"description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)",
|
||||
"main": "build/main/main/main.js",
|
||||
"author": "Sucukdeluxe",
|
||||
|
||||
@ -7,7 +7,7 @@ import { AppSettings, DownloadItem, DownloadStats, DownloadSummary, DownloadStat
|
||||
import { REQUEST_RETRIES } from "./constants";
|
||||
import { cleanupCancelledPackageArtifactsAsync } from "./cleanup";
|
||||
import { DebridService, MegaWebUnrestrictor } from "./debrid";
|
||||
import { extractPackageArchives } from "./extractor";
|
||||
import { collectArchiveCleanupTargets, extractPackageArchives } from "./extractor";
|
||||
import { validateFileAgainstManifest } from "./integrity";
|
||||
import { logger } from "./logger";
|
||||
import { StoragePaths, saveSession } from "./storage";
|
||||
@ -179,12 +179,14 @@ export class DownloadManager extends EventEmitter {
|
||||
this.normalizeSessionStatuses();
|
||||
this.recoverPostProcessingOnStartup();
|
||||
this.resolveExistingQueuedOpaqueFilenames();
|
||||
this.cleanupExistingExtractedArchives();
|
||||
}
|
||||
|
||||
public setSettings(next: AppSettings): void {
|
||||
this.settings = next;
|
||||
this.debridService.setSettings(next);
|
||||
this.resolveExistingQueuedOpaqueFilenames();
|
||||
this.cleanupExistingExtractedArchives();
|
||||
this.emitState();
|
||||
}
|
||||
|
||||
@ -580,6 +582,77 @@ export class DownloadManager extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
private cleanupExistingExtractedArchives(): void {
|
||||
if (this.settings.cleanupMode === "none") {
|
||||
return;
|
||||
}
|
||||
|
||||
const cleanupTargetsByPackage = new Map<string, Set<string>>();
|
||||
for (const packageId of this.session.packageOrder) {
|
||||
const pkg = this.session.packages[packageId];
|
||||
if (!pkg || pkg.cancelled || pkg.status !== "completed") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const items = pkg.itemIds
|
||||
.map((itemId) => this.session.items[itemId])
|
||||
.filter(Boolean) as DownloadItem[];
|
||||
if (items.length === 0 || !items.every((item) => item.status === "completed")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const extractedItems = items.filter((item) => item.fullStatus === "Entpackt");
|
||||
if (extractedItems.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const packageTargets = cleanupTargetsByPackage.get(packageId) ?? new Set<string>();
|
||||
for (const item of extractedItems) {
|
||||
const targetPath = String(item.targetPath || "").trim();
|
||||
if (!targetPath) {
|
||||
continue;
|
||||
}
|
||||
for (const cleanupTarget of collectArchiveCleanupTargets(targetPath)) {
|
||||
packageTargets.add(cleanupTarget);
|
||||
}
|
||||
}
|
||||
if (packageTargets.size > 0) {
|
||||
cleanupTargetsByPackage.set(packageId, packageTargets);
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanupTargetsByPackage.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cleanupQueue = this.cleanupQueue
|
||||
.then(async () => {
|
||||
for (const [packageId, targets] of cleanupTargetsByPackage.entries()) {
|
||||
const pkg = this.session.packages[packageId];
|
||||
if (!pkg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let removed = 0;
|
||||
for (const targetPath of targets) {
|
||||
try {
|
||||
await fs.promises.rm(targetPath, { force: true });
|
||||
removed += 1;
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (removed > 0) {
|
||||
logger.info(`Nachtraegliches Archive-Cleanup fuer ${pkg.name}: ${removed} Datei(en) geloescht`);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.warn(`Nachtraegliches Archive-Cleanup fehlgeschlagen: ${compactErrorText(error)}`);
|
||||
});
|
||||
}
|
||||
|
||||
public cancelPackage(packageId: string): void {
|
||||
const pkg = this.session.packages[packageId];
|
||||
if (!pkg) {
|
||||
|
||||
@ -821,6 +821,76 @@ describe("download manager", () => {
|
||||
expect(snapshot.canStart).toBe(true);
|
||||
});
|
||||
|
||||
it("cleans leftover split archives on startup for already extracted packages", async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-dm-"));
|
||||
tempDirs.push(root);
|
||||
|
||||
const packageDir = path.join(root, "downloads", "legacy");
|
||||
fs.mkdirSync(packageDir, { recursive: true });
|
||||
const part1 = path.join(packageDir, "legacy.release.part01.rar");
|
||||
const part2 = path.join(packageDir, "legacy.release.part02.rar");
|
||||
const part3 = path.join(packageDir, "legacy.release.part03.rar");
|
||||
const keep = path.join(packageDir, "keep.txt");
|
||||
fs.writeFileSync(part2, "part2", "utf8");
|
||||
fs.writeFileSync(part3, "part3", "utf8");
|
||||
fs.writeFileSync(keep, "keep", "utf8");
|
||||
|
||||
const session = emptySession();
|
||||
const packageId = "legacy-pkg";
|
||||
const itemId = "legacy-item";
|
||||
const createdAt = Date.now() - 20_000;
|
||||
|
||||
session.packageOrder = [packageId];
|
||||
session.packages[packageId] = {
|
||||
id: packageId,
|
||||
name: "legacy",
|
||||
outputDir: packageDir,
|
||||
extractDir: path.join(root, "extract", "legacy"),
|
||||
status: "completed",
|
||||
itemIds: [itemId],
|
||||
cancelled: false,
|
||||
enabled: true,
|
||||
createdAt,
|
||||
updatedAt: createdAt
|
||||
};
|
||||
session.items[itemId] = {
|
||||
id: itemId,
|
||||
packageId,
|
||||
url: "https://dummy/legacy",
|
||||
provider: "realdebrid",
|
||||
status: "completed",
|
||||
retries: 0,
|
||||
speedBps: 0,
|
||||
downloadedBytes: 123,
|
||||
totalBytes: 123,
|
||||
progressPercent: 100,
|
||||
fileName: path.basename(part1),
|
||||
targetPath: part1,
|
||||
resumable: true,
|
||||
attempts: 1,
|
||||
lastError: "",
|
||||
fullStatus: "Entpackt",
|
||||
createdAt,
|
||||
updatedAt: createdAt
|
||||
};
|
||||
|
||||
new DownloadManager(
|
||||
{
|
||||
...defaultSettings(),
|
||||
token: "rd-token",
|
||||
outputDir: path.join(root, "downloads"),
|
||||
extractDir: path.join(root, "extract"),
|
||||
autoExtract: true,
|
||||
cleanupMode: "delete"
|
||||
},
|
||||
session,
|
||||
createStoragePaths(path.join(root, "state"))
|
||||
);
|
||||
|
||||
await waitFor(() => !fs.existsSync(part2) && !fs.existsSync(part3), 5000);
|
||||
expect(fs.existsSync(keep)).toBe(true);
|
||||
});
|
||||
|
||||
it("resets run counters and reconnect state on start", async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-dm-"));
|
||||
tempDirs.push(root);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user