From 21dbf46f8162bc38c00eefbb0370714bf47f0729 Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Tue, 3 Mar 2026 22:13:58 +0100 Subject: [PATCH] Release v1.5.74 - Fix hybrid extract not using maxParallelExtract setting (was hardcoded to 1) - Fix "Warten auf Parts" label shown for items whose downloads are already complete - Update hybrid extract progress handler to support parallel archive tracking Co-Authored-By: Claude Opus 4.6 --- package.json | 2 +- src/main/download-manager.ts | 104 ++++++++++++++++++----------------- 2 files changed, 56 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index 3359a1b..571eced 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "real-debrid-downloader", - "version": "1.5.73", + "version": "1.5.74", "description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)", "main": "build/main/main/main.js", "author": "Sucukdeluxe", diff --git a/src/main/download-manager.ts b/src/main/download-manager.ts index 26e25ff..b0ebab5 100644 --- a/src/main/download-manager.ts +++ b/src/main/download-manager.ts @@ -5306,48 +5306,22 @@ export class DownloadManager extends EventEmitter { const resolveArchiveItems = (archiveName: string): DownloadItem[] => resolveArchiveItemsFromList(archiveName, hybridItems); - // Only update the items currently being extracted, not all hybrid items at once - let currentArchiveItems: DownloadItem[] = []; - const updateExtractingStatus = (text: string): void => { - const normalized = String(text || ""); - if (hybridLastStatusText === normalized) { - return; - } - hybridLastStatusText = normalized; - const updatedAt = nowMs(); - for (const entry of currentArchiveItems) { - if (isExtractedLabel(entry.fullStatus)) { - continue; - } - if (entry.fullStatus === normalized) { - continue; - } - entry.fullStatus = normalized; - entry.updatedAt = updatedAt; - } - }; - - let hybridLastStatusText = ""; + // Track multiple active archives for parallel hybrid extraction + const activeHybridArchiveMap = new Map(); let hybridLastEmitAt = 0; - let lastHybridArchiveName = ""; - const emitHybridStatus = (text: string, force = false): void => { - updateExtractingStatus(text); - const now = nowMs(); - if (!force && now - hybridLastEmitAt < EXTRACT_PROGRESS_EMIT_INTERVAL_MS) { - return; - } - hybridLastEmitAt = now; - this.emitState(); - }; // Mark hybrid items as pending, others as waiting for parts + // If all items are completed, no item should show "Warten auf Parts" const hybridItemIds = new Set(hybridItems.map((item) => item.id)); + const allDownloaded = completedItems.length >= items.length; for (const entry of completedItems) { if (isExtractedLabel(entry.fullStatus)) { continue; } if (hybridItemIds.has(entry.id)) { entry.fullStatus = "Entpacken - Ausstehend"; + } else if (allDownloaded) { + entry.fullStatus = "Entpacken - Ausstehend"; } else { entry.fullStatus = "Entpacken - Warten auf Parts"; } @@ -5369,33 +5343,65 @@ export class DownloadManager extends EventEmitter { skipPostCleanup: true, packageId, hybridMode: true, + maxParallel: this.settings.maxParallelExtract || 2, onProgress: (progress) => { if (progress.phase === "done") { - return; - } - // When a new archive starts, mark the previous archive's items as done - if (progress.archiveName && progress.archiveName !== lastHybridArchiveName) { - if (lastHybridArchiveName && currentArchiveItems.length > 0) { + // Mark all remaining active archives as done + for (const [, archItems] of activeHybridArchiveMap) { const doneAt = nowMs(); - for (const entry of currentArchiveItems) { + for (const entry of archItems) { if (!isExtractedLabel(entry.fullStatus)) { entry.fullStatus = "Entpackt - Done"; entry.updatedAt = doneAt; } } } - lastHybridArchiveName = progress.archiveName; - const resolved = resolveArchiveItems(progress.archiveName); - currentArchiveItems = resolved; + activeHybridArchiveMap.clear(); + return; + } + + if (progress.archiveName) { + // Resolve items for this archive if not yet tracked + if (!activeHybridArchiveMap.has(progress.archiveName)) { + activeHybridArchiveMap.set(progress.archiveName, resolveArchiveItems(progress.archiveName)); + } + const archItems = activeHybridArchiveMap.get(progress.archiveName)!; + + // If archive is at 100%, mark its items as done and remove from active + if (Number(progress.archivePercent ?? 0) >= 100) { + const doneAt = nowMs(); + for (const entry of archItems) { + if (!isExtractedLabel(entry.fullStatus)) { + entry.fullStatus = "Entpackt - Done"; + entry.updatedAt = doneAt; + } + } + activeHybridArchiveMap.delete(progress.archiveName); + } else { + // Update this archive's items with current progress + const archive = ` · ${progress.archiveName}`; + const elapsed = progress.elapsedMs && progress.elapsedMs >= 1000 + ? ` · ${Math.floor(progress.elapsedMs / 1000)}s` + : ""; + const activeArchive = Number(progress.archivePercent ?? 0) > 0 ? 1 : 0; + const currentDisplay = Math.max(0, Math.min(progress.total, progress.current + activeArchive)); + const label = `Entpacken ${progress.percent}% (${currentDisplay}/${progress.total})${archive}${elapsed}`; + const updatedAt = nowMs(); + for (const entry of archItems) { + if (!isExtractedLabel(entry.fullStatus)) { + entry.fullStatus = label; + entry.updatedAt = updatedAt; + } + } + } + } + + // Throttled emit + const now = nowMs(); + if (now - hybridLastEmitAt >= EXTRACT_PROGRESS_EMIT_INTERVAL_MS) { + hybridLastEmitAt = now; + this.emitState(); } - const archive = progress.archiveName ? ` · ${progress.archiveName}` : ""; - const elapsed = progress.elapsedMs && progress.elapsedMs >= 1000 - ? ` · ${Math.floor(progress.elapsedMs / 1000)}s` - : ""; - const activeArchive = Number(progress.archivePercent ?? 0) > 0 ? 1 : 0; - const currentDisplay = Math.max(0, Math.min(progress.total, progress.current + activeArchive)); - const label = `Entpacken ${progress.percent}% (${currentDisplay}/${progress.total})${archive}${elapsed}`; - emitHybridStatus(label); } });