- 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>
Bug fixed: When a folder already contained the same episode token as
the source file (e.g. Show.S01E05.720p-4sf + s01e05.mkv), the episode
was inserted a second time producing Show.S01E05.720p.S01E05-4sf.
Root cause: The replace produced an identical string, the equality check
fell through to the suffix-insert branch which added the token again.
Fix: Use regex.test() first, then always apply the replacement when
an episode pattern exists in the folder name.
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>