- New "Jetzt entpacken" right-click option: triggers extraction for
completed packages regardless of paused/stopped state
- Fix 5-10s freeze when pressing Start after Pause: recoverRetryableItems
was calling fs.stat on every item (474+); now only checks failed/completed
- Full IPC pipeline: extractNow in manager, controller, preload, renderer
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WinRAR doesn't support \?\ prefix (interprets it as UNC network path).
Replace with subst drive mapping: maps targetDir to a short drive letter
(Z:, Y:, etc.) before extraction, then removes mapping after. This keeps
total paths under 260 chars even when archives contain deep internal
directory structures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add longPathForWindows() helper that prefixes extract target directories
with \?\ on Windows, bypassing the 260-char MAX_PATH limit. Applied to
both WinRAR/UnRAR and 7z arguments. Fixes "Die Syntax für den
Dateinamen, Verzeichnisnamen" errors when archive internal directories
create deeply nested output paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Right-click packages with extraction errors shows "Extraktion
wiederholen" option to manually retry
- Increase WinRAR error text from 240 to 500 chars for better
diagnostics in logs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- triggerPendingExtractions() now runs when unpausing, so packages
with extraction errors are automatically retried
- executeDeleteSelection no longer depends on snapshot objects
(prevents unnecessary re-renders with large queues)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Session counter now uses sessionDownloadedBytes (in-memory counter)
instead of summing completed items. Removing packages after extraction
no longer resets the session total.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Save settings every 30s during active downloads (not just session)
- Force settings save on shutdown and run finish
- Preserve live totalDownloadedAllTime when user saves settings
(app-controller's stale copy no longer overwrites the counter)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pause button is now one-way (orange glow when paused, disabled when
already paused). Start button resumes from pause.
- Fix hybrid extraction attempting incomplete multi-part archives when
paused: disk-fallback now blocks any non-terminal item status, not
just downloading/validating/integrity_check.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Dynamic left padding based on measured label width (no more cut-off numbers)
- Speed history ref lifted to App so chart data survives tab switches
- Pause button uses optimistic UI update for instant visual feedback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Track totalDownloadedAllTime in settings (persists across restarts)
- Track sessionDownloadedBytes for current app session
- Status bar shows both: Session + Gesamt
- Statistics section shows Heruntergeladen (Session) + (Gesamt)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Track packageId in speed events so package speed uses same 3-second
window as global speed (fixes mismatch between package and status bar)
- Add packageSpeedBps to UiSnapshot, computed from speed events
- Context menu delete actions now respect confirmDeleteSelection setting
- Progress bar visible even when package is collapsed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix Ctrl+Click: mousedown no longer immediately adds item, preventing
onClick from toggling it back off. Drag-select still works via mouseenter.
- Delete key removes selected items/packages with JDownloader-style
confirmation dialog showing count and remaining items.
- "Nicht mehr anzeigen" checkbox disables future confirmations.
- New setting "Vor dem Löschen bestätigen" under Allgemein.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dead link detection:
- Mega-Web: parse hoster error messages (hosterNotAvailable, etc.) from HTML
and throw specific error instead of returning null
- MegaDebridClient: stop retrying on permanent hoster errors
- download-manager: isPermanentLinkError() immediately fails items with dead
links instead of retrying forever
Extraction race condition:
- package_done cleanup policy checked if all items were "completed" (downloaded)
but not if they were "extracted" — removing the package before the last
episode could be extracted
- Both applyCompletedCleanupPolicy and applyPackageDoneCleanup now guard
against premature removal when autoExtract is enabled
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- HTTP 200 on resume: detect server ignoring Range header, write in truncate mode
instead of appending (prevents doubled/corrupted files)
- HTTP 416 without Content-Range: assume complete if >1MB exists instead of
deleting potentially multi-GB finished files
- Stream handle leak: explicit destroy() after finally to prevent fd exhaustion
- Drain timeout: don't abort controller on disk backpressure, let inner retry
loop handle it instead of escalating to full stall pipeline
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Provider circuit breaker: track consecutive failures per provider with
escalating cooldowns (30s/60s/120s/300s), auto-invalidate Mega-Debrid
session on cooldown
- Escalating backoff: retry delays now scale up to 120s (was 30s max),
unrestrict backoff exponential instead of linear 15s cap
- Shelve logic: after 15 consecutive failures, item pauses 5 min with
counter halving for gradual recovery
- Periodic soft-reset: every 10 min, reset stale retry counters (>10 min
queued) and old provider failures (>15 min), acts like mini-restart
- Mega-Debrid queue timeout: 90s wait limit in runExclusive to prevent
cascade blocking behind stuck calls
- Provider-cooldown-aware retry delays: items wait for provider cooldown
instead of retrying against broken service
- Fix: reconnect/package_toggle now persist retry counters (previously
lost on interruption, defeating shelve logic)
- Mega-Debrid generate: tighter timeouts, progressive reload backoff,
hoster retry limit (5x max)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Left half (blue) shows download progress, right half (green) shows
extraction progress. When no extraction is active, full bar is blue.
Full bar = 50% blue (all downloaded) + 50% green (all extracted).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Active packages are now sorted by completed item count (descending),
then by downloaded bytes, so packages with real download progress
appear above packages still in link resolution phase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Packages with items in downloading/validating/extracting/integrity_check
state are always shown at the top regardless of sort order (A-Z or Z-A).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show current aggregate speed (all active downloads) in the stats bar
next to Pakete/Dateien/Gesamt. Only visible while session is running.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Some hosters return tiny error responses (e.g. 9 bytes) with HTTP 200.
- downloadToFile: detect files <512 B, log content, delete and throw for retry
- Post-download: catch <512 B files even when totalBytes is unknown
- Logs the error-page content for debugging
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix .z001/.z002 split zip volumes not deleted after extraction
(regex matched only 2-digit, now matches 2-3 digit volumes)
- Make extract progress file writes atomic (write to .tmp then rename)
to prevent corruption on crash during extraction
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keep existing good filename when debrid API returns "download.bin"
or opaque name. Only overwrite item.fileName if the resolved name
is actually better (not opaque, not download.bin).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When post-processing runs, detect items in idle states (queued/paused)
whose target file already exists on disk with non-zero size, and
auto-recover them to "completed" status. This ensures allDone becomes
true, triggering final extraction with archive cleanup (delete mode).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add disk-fallback to findReadyArchiveSets: when all archive parts
physically exist on disk with non-zero size and none are actively
downloading/validating, consider the archive ready for extraction.
This fixes episodes being skipped when a download item's status
was not updated to "completed" despite the file being fully written.
Also improve debug server: raise log limit to 10000 lines,
add grep filter, add /session endpoint for raw session data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Starts an HTTP server on port 9868 (configurable via debug_port.txt)
when debug_token.txt exists in the app runtime directory. Provides
/health, /log, /status, and /items endpoints for live monitoring.
Token-based auth required.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The validating-stuck timeout (45s) was shorter than the unrestrict
timeout (60s), causing items to be endlessly aborted and retried
before the debrid API call could complete. Now uses unrestrict
timeout + 15s buffer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Convert all sync FS ops (existsSync, readdirSync, statSync, writeFileSync,
rmSync, renameSync) to async equivalents across download-manager, extractor,
cleanup, storage, and logger to prevent UI freezes
- Replace linear retry delays with exponential backoff + jitter to prevent
retry storms with many parallel downloads
- Deduplicate resolveArchiveItems into single shared function
- Replace Array.shift() O(N) in bandwidth chart with slice-based trimming
- Make logger rotation async in the async flush path
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Don't clear extraction resume state during hybrid mode (skipPostCleanup)
- Mark ALL completed items as "Entpackt" after successful hybrid extraction
to prevent full extraction from re-extracting already-extracted archives
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previous fix used pathKey-based maps which failed due to path resolution
mismatches on Windows. New approach matches items to archives using
filename regex patterns directly (e.g. prefix.part\d+.rar), which is
robust regardless of path casing/resolution.
Also marks items as "Entpackt" immediately when their archive finishes
instead of waiting for all archives to complete, so completed episodes
show correct status while later episodes are still extracting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- togglePause: clear retry delays and abort stuck tasks on unpause so
Pause/Start actually recovers stuck downloads
- Fix retry display showing Number.MAX_SAFE_INTEGER instead of "inf"
for unrestrict and generic error retries
- Fix extraction status applied to ALL items in package instead of only
the items belonging to the currently extracting archive
- Make persistNow always async and item-completion stat async to reduce
UI freezes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace Readable.fromWeb() + pipeline with ReadableStream.getReader() loop
- Collect chunks in memory, verify size, then write to disk in one shot
- Add Accept-Encoding: identity to prevent content encoding issues
- Eliminates stream conversion bugs that caused file corruption on some servers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Patch latest.yml during release to use actual filenames (spaces) instead of electron-builder's dashed names
- Add download size validation before SHA512 check to catch incomplete downloads
- Retry download on integrity mismatch (up to 3 passes) with API refresh
- Re-resolve digest from latest.yml on each retry pass
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Parse <filename> tags from DLC XML for proper file names instead of
deriving from opaque URLs (fixes download.bin display)
- Optimistic UI removal for package/item delete (instant feedback)
- Show app version in header ("Multi Debrid Downloader vX.X.X")
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Local DLC decryption no longer throws on invalid PKCS7 padding
- Instead tries to parse the decrypted data as-is (Node.js base64
decoder is lenient with trailing garbage bytes)
- This fixes large DLCs that previously failed locally and then
hit dcrypt.it's 413 size limit on both endpoints
- Empty decryption result returns [] instead of throwing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Handle 413 from paste endpoint (not just upload)
- Show clear German error "DLC-Datei zu groß für dcrypt.it" when both
endpoints reject the file due to size
- Add tests for dual-413 and upload-413+paste-500 scenarios
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use DLC filename as package name in dcrypt fallback instead of
inferring from individual URLs (fixes mangled package names)
- Add paste endpoint fallback when dcrypt upload returns 413
- Split decryptDlcViaDcrypt into tryDcryptUpload/tryDcryptPaste
- Add DCRYPT_PASTE_URL constant
- Expand container tests for 413 fallback and dual-failure scenarios
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- AllDebrid: add HTML response detection to unrestrictLink
- Cleanup: skip symlinks/junctions in all directory traversals
- Blob URL: increase revoke delay from 0ms to 60s
- Extractor: per-package progress file to prevent collision
- ADD_CONTAINERS: reject path traversal and relative paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Items extracted during hybrid extraction now show "Entpackt" instead of "Fertig"
- Only items belonging to the extracted archive set get status updates during hybrid extraction
- Final extraction preserves "Entpackt" status from prior hybrid passes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements hybrid extraction: when a package has multiple episodes with
multi-part archives, completed archive sets are extracted immediately
while the rest of the package continues downloading. Uses the existing
hybridExtract setting (already in UI/types/storage).
Key changes:
- Export findArchiveCandidates/pathSetKey from extractor.ts
- Add onlyArchives/skipPostCleanup options to ExtractOptions
- Add findReadyArchiveSets to identify complete archive sets
- Add runHybridExtraction for incremental extraction passes
- Requeue logic in runPackagePostProcessing for new completions
- Resume state preserved across hybrid passes (no premature clear)
- Guard against extracting incomplete multi-part archives
- Correct abort/toggle handling during hybrid extraction
- Package toggle now also aborts active post-processing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Cache itemCount as class property instead of O(n) Object.keys().length on every emit/persist/UI update
- Eliminate redundant iteration: hasQueuedItems now delegates to findNextQueuedItem
- Remove expensive cloneSession from getSnapshot (IPC serialization handles the copy)
- Increase speed events compaction threshold (50 → 200) to reduce array reallocations
- Time-based UI emit throttling instead of per-percent progress checks
- Avoid Array.from allocation in global stall watchdog
- Optimize markQueuedAsReconnectWait to iterate only run items instead of all items
- Cache pathKey computation in claimTargetPath loop (avoid path.resolve per iteration)
- Use packageOrder.length instead of Object.keys(packages).length in getStats
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The "type": "module" in package.json caused tsup to emit .cjs files instead
of .js, breaking the electron-builder entry point check. Using .mts extension
for vite config achieves ESM for Vite without affecting the rest of the package.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 30s fetch timeouts to ALL API calls (Real-Debrid, BestDebrid, AllDebrid, Mega-Web)
- Fix race condition in concurrent worker indexing (runWithConcurrency)
- Guard JSON.parse in RealDebrid response with try-catch
- Add try-catch to fs.mkdirSync in download pipeline (handles permission denied)
- Convert MD5/SHA1 hashing to streaming (prevents OOM on large files)
- Add error handling for hash manifest file reading
- Prevent infinite hangs on unresponsive API endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Convert session persistence to async during downloads (prevents 50-200ms UI freezes)
- Avoid unnecessary Buffer.from() copy on Uint8Array chunks (zero-copy when possible)
- Cache effective speed limit for 2s (eliminates Date object creation per chunk)
- Replace O(n) speed event shift() with pointer-based pruning
- Throttle speed event pruning to every 1.5s instead of per chunk
- Optimize refreshPackageStatus to single-loop counting (was 4 separate filter passes)
- Fix global stall watchdog race condition (re-check abort state before aborting)
- Add coalescing for async session saves (prevents write storms)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add multi-threaded extraction via WinRAR -mt flag (uses all CPU cores)
- Fix -idq flag suppressing progress output, replaced with -idc
- Fix extraction timeout for multi-part archives (now calculates total size across all parts)
- Raise extraction timeout cap from 40min to 2h for large archives (40GB+)
- Add natural episode sorting (E1, E2, E10 instead of E1, E10, E2)
- Add split archive support (.zip.001, .7z.001) with proper cleanup
- Add write-stream drain timeout to prevent download freezes on backpressure
- Fix regex global-state bug in progress percentage parsing
- Optimize speed event pruning (every 1.5s instead of every chunk)
- Add performance flag fallback for older WinRAR versions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix extraction status display after restart (shows "Entpacken ausstehend" instead of stale status)
- Fix Start button to trigger pending extractions for already-downloaded packages
- Fix extraction resume when archives already cleaned (recognizes completed state from resume file)
- Reduce update download connection timeout from 8min to 30s per candidate for faster fallback
- Add logging for update download candidates and failures
- Show manual download URL on update failure
- Sequential extraction preserved (one package at a time via queue)
- Extraction properly cancelled on shutdown, resumes on restart
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>