From 3de4ba3e90a13b7ae52fca0b43d1f1a43f7a135f Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Mon, 9 Mar 2026 05:33:09 +0100 Subject: [PATCH] Fix final post-process requeue stall --- src/main/download-manager.ts | 12 ++++- src/renderer/App.tsx | 2 +- tests/download-manager.test.ts | 98 ++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/main/download-manager.ts b/src/main/download-manager.ts index ee5bb28..34278c9 100644 --- a/src/main/download-manager.ts +++ b/src/main/download-manager.ts @@ -4989,6 +4989,14 @@ export class DownloadManager extends EventEmitter { }); } + private shouldCollapseQuickPostProcessRequeue(packageId: string): boolean { + const pkg = this.session.packages[packageId]; + if (!pkg) { + return true; + } + return !this.areAllPackageItemRefsFinished(pkg); + } + private async findFullExtractArchiveSet(pkg: PackageEntry, completedItems: DownloadItem[]): Promise> { const relevant = new Set(); if (!pkg.outputDir || completedItems.length === 0) { @@ -5499,7 +5507,9 @@ export class DownloadManager extends EventEmitter { // rounds when many small archive parts complete in rapid // succession (e.g. 15-20 × 101 MB parts per episode). if (roundMs < 2000 && this.hybridExtractRequeue.has(packageId)) { - this.hybridExtractRequeue.delete(packageId); + if (this.shouldCollapseQuickPostProcessRequeue(packageId)) { + this.hybridExtractRequeue.delete(packageId); + } } } while (this.hybridExtractRequeue.has(packageId)); } finally { diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 09fc65a..e0785c2 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -5538,7 +5538,7 @@ export function App(): ReactElement { void window.rd.openItemLog(id).catch(() => {}); } setContextMenu(null); - }}>Item-Log öffnen{multi ? ` (${selectedItemIds.length})` : ""} + }}>Item-Log öffnen{multi ? ` (${selectedItemIds.length})` : ""} )}
{hasPackages && !contextMenu.itemId && ( diff --git a/tests/download-manager.test.ts b/tests/download-manager.test.ts index 5250753..0c34588 100644 --- a/tests/download-manager.test.ts +++ b/tests/download-manager.test.ts @@ -129,6 +129,104 @@ describe("download manager", () => { expect(historyEntries[0]?.downloadedBytes).toBe(90 * 1024 * 1024); }); + it("keeps the quick post-process requeue once the final package items are finished", () => { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-postprocess-final-")); + tempDirs.push(root); + + const session = emptySession(); + const packageId = "postprocess-final-pkg"; + const firstItemId = "postprocess-final-item-1"; + const secondItemId = "postprocess-final-item-2"; + const createdAt = Date.now() - 20_000; + const packageOutputDir = path.join(root, "downloads", "PostProcess Final Round"); + const packageExtractDir = path.join(root, "extract", "PostProcess Final Round"); + fs.mkdirSync(packageOutputDir, { recursive: true }); + fs.mkdirSync(packageExtractDir, { recursive: true }); + fs.writeFileSync(path.join(packageOutputDir, "final-1.rar"), Buffer.alloc(100, 1)); + + session.packageOrder = [packageId]; + session.packages[packageId] = { + id: packageId, + name: "PostProcess Final Round", + outputDir: packageOutputDir, + extractDir: packageExtractDir, + status: "downloading", + itemIds: [firstItemId, secondItemId], + cancelled: false, + enabled: true, + createdAt, + updatedAt: createdAt + }; + session.items[firstItemId] = { + id: firstItemId, + packageId, + url: "https://example.com/final-1.rar", + provider: "realdebrid", + status: "completed", + retries: 0, + speedBps: 0, + downloadedBytes: 100, + totalBytes: 100, + progressPercent: 100, + fileName: "final-1.rar", + targetPath: path.join(packageOutputDir, "final-1.rar"), + resumable: true, + attempts: 1, + lastError: "", + fullStatus: "Entpackt - Done (<1s)", + createdAt, + updatedAt: createdAt + }; + session.items[secondItemId] = { + id: secondItemId, + packageId, + url: "https://example.com/final-2.rar", + provider: "realdebrid", + status: "downloading", + retries: 0, + speedBps: 0, + downloadedBytes: 90, + totalBytes: 100, + progressPercent: 90, + fileName: "final-2.rar", + targetPath: path.join(packageOutputDir, "final-2.rar"), + resumable: true, + attempts: 1, + lastError: "", + fullStatus: "Download läuft", + createdAt, + updatedAt: createdAt + }; + + const manager = new DownloadManager( + { + ...defaultSettings(), + token: "rd-token", + outputDir: path.join(root, "downloads"), + extractDir: path.join(root, "extract"), + autoExtract: true, + hybridExtract: true + }, + session, + createStoragePaths(path.join(root, "state")) + ); + + expect((manager as any).shouldCollapseQuickPostProcessRequeue(packageId)).toBe(true); + + const item = (manager as any).session.items[secondItemId]; + item.status = "completed"; + item.downloadedBytes = item.totalBytes; + item.progressPercent = 100; + item.fullStatus = "Entpacken - Ausstehend"; + item.updatedAt = Date.now(); + + expect((manager as any).session.items[firstItemId].status).toBe("completed"); + expect((manager as any).session.items[secondItemId].status).toBe("completed"); + expect((manager as any).session.packages[packageId].itemIds).toEqual([firstItemId, secondItemId]); + + expect((manager as any).shouldCollapseQuickPostProcessRequeue(packageId)).toBe(false); + }); + function createCompletedArchiveSession(root: string, packageName: string, extractedFileName: string): { session: ReturnType; packageId: string;