From 8d0c110415825d9e3a2e180621694d0d506ad779 Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Wed, 4 Mar 2026 14:13:14 +0100 Subject: [PATCH] Release v1.6.7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add proactive disk-busy detection: lower STREAM_HIGH_WATER_MARK from 2 MB to 512 KB so backpressure triggers sooner, and monitor stream.writableLength to show "Warte auf Festplatte" after 300 ms of undrained writes — before actual backpressure hits. Co-Authored-By: Claude Opus 4.6 --- package.json | 2 +- src/main/constants.ts | 3 ++- src/main/download-manager.ts | 37 +++++++++++++++++++++++++++++++++--- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 45def15..2cdd33f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "real-debrid-downloader", - "version": "1.6.6", + "version": "1.6.7", "description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)", "main": "build/main/main/main.js", "author": "Sucukdeluxe", diff --git a/src/main/constants.ts b/src/main/constants.ts index 8d1ffc5..a4b5a95 100644 --- a/src/main/constants.ts +++ b/src/main/constants.ts @@ -19,7 +19,8 @@ export const CHUNK_SIZE = 512 * 1024; export const WRITE_BUFFER_SIZE = 512 * 1024; // 512 KB write buffer (JDownloader: 500 KB) export const WRITE_FLUSH_TIMEOUT_MS = 2000; // 2s flush timeout export const ALLOCATION_UNIT_SIZE = 4096; // 4 KB NTFS alignment -export const STREAM_HIGH_WATER_MARK = 2 * 1024 * 1024; // 2 MB stream buffer (JDownloader: Java NIO FileChannel default ~8 MB) +export const STREAM_HIGH_WATER_MARK = 512 * 1024; // 512 KB stream buffer — lower than before (2 MB) so backpressure triggers sooner when disk is slow +export const DISK_BUSY_THRESHOLD_MS = 300; // Show "Warte auf Festplatte" if writableLength > 0 for this long export const SAMPLE_DIR_NAMES = new Set(["sample", "samples"]); export const SAMPLE_VIDEO_EXTENSIONS = new Set([".mkv", ".mp4", ".avi", ".mov", ".wmv", ".m4v", ".ts", ".m2ts", ".webm"]); diff --git a/src/main/download-manager.ts b/src/main/download-manager.ts index 731b790..342a06c 100644 --- a/src/main/download-manager.ts +++ b/src/main/download-manager.ts @@ -19,7 +19,7 @@ import { StartConflictResolutionResult, UiSnapshot } from "../shared/types"; -import { REQUEST_RETRIES, SAMPLE_VIDEO_EXTENSIONS, SPEED_WINDOW_SECONDS, WRITE_BUFFER_SIZE, WRITE_FLUSH_TIMEOUT_MS, ALLOCATION_UNIT_SIZE, STREAM_HIGH_WATER_MARK } from "./constants"; +import { REQUEST_RETRIES, SAMPLE_VIDEO_EXTENSIONS, SPEED_WINDOW_SECONDS, WRITE_BUFFER_SIZE, WRITE_FLUSH_TIMEOUT_MS, ALLOCATION_UNIT_SIZE, STREAM_HIGH_WATER_MARK, DISK_BUSY_THRESHOLD_MS } from "./constants"; import { cleanupCancelledPackageArtifactsAsync } from "./cleanup"; import { DebridService, MegaWebUnrestrictor, checkRapidgatorOnline } from "./debrid"; import { clearExtractResumeState, collectArchiveCleanupTargets, extractPackageArchives, findArchiveCandidates } from "./extractor"; @@ -4984,6 +4984,7 @@ export class DownloadManager extends EventEmitter { const stallTimeoutMs = getDownloadStallTimeoutMs(); const drainTimeoutMs = Math.max(30000, Math.min(300000, stallTimeoutMs > 0 ? stallTimeoutMs * 12 : 120000)); let lastDiskBusyEmitAt = 0; + let diskBusySince = 0; // timestamp when writableLength first became > 0 const waitDrain = (): Promise => new Promise((resolve, reject) => { if (active.abortController.signal.aborted) { @@ -5221,6 +5222,29 @@ export class DownloadManager extends EventEmitter { await alignedFlush(false); } + // Proactive disk-busy detection: if the stream's internal buffer + // hasn't drained for DISK_BUSY_THRESHOLD_MS, the OS write calls are + // lagging — typically because the physical disk can't keep up. Show + // "Warte auf Festplatte" immediately instead of waiting for full + // backpressure (stream.write returning false). + if (stream.writableLength > 0) { + if (diskBusySince === 0) diskBusySince = nowMs(); + const busyMs = nowMs() - diskBusySince; + if (busyMs >= DISK_BUSY_THRESHOLD_MS && item.status !== "paused" && !this.session.paused) { + const nowTick = nowMs(); + if (nowTick - lastDiskBusyEmitAt >= 1200) { + item.status = "downloading"; + item.speedBps = 0; + item.fullStatus = `Warte auf Festplatte (${providerLabel(item.provider)})`; + item.updatedAt = nowTick; + this.emitState(); + lastDiskBusyEmitAt = nowTick; + } + } + } else { + diskBusySince = 0; + } + written += buffer.length; windowBytes += buffer.length; this.session.totalDownloadedBytes += buffer.length; @@ -5249,10 +5273,17 @@ export class DownloadManager extends EventEmitter { } item.status = "downloading"; - item.speedBps = Math.max(0, Math.floor(speed)); item.downloadedBytes = written; item.progressPercent = item.totalBytes ? Math.max(0, Math.min(100, Math.floor((written / item.totalBytes) * 100))) : 0; - item.fullStatus = `Download läuft (${providerLabel(item.provider)})`; + // Keep "Warte auf Festplatte" label if disk is busy; otherwise show normal status + const diskBusy = diskBusySince > 0 && nowMs() - diskBusySince >= DISK_BUSY_THRESHOLD_MS; + if (diskBusy) { + item.speedBps = 0; + item.fullStatus = `Warte auf Festplatte (${providerLabel(item.provider)})`; + } else { + item.speedBps = Math.max(0, Math.floor(speed)); + item.fullStatus = `Download läuft (${providerLabel(item.provider)})`; + } const nowTick = nowMs(); if (nowTick - lastUiEmitAt >= uiUpdateIntervalMs) { item.updatedAt = nowTick;