From c4aefb61750d7e7a7a125b2e1e5bfbfeb00bd21a Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Tue, 3 Mar 2026 23:17:37 +0100 Subject: [PATCH] Release v1.5.78 Co-Authored-By: Claude Opus 4.6 --- package.json | 2 +- src/main/download-manager.ts | 4 ++-- src/renderer/App.tsx | 35 +++++++++++++++-------------------- src/renderer/styles.css | 6 +++--- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 40061d0..d6bcdbb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "real-debrid-downloader", - "version": "1.5.77", + "version": "1.5.78", "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 fd1b08e..7e32388 100644 --- a/src/main/download-manager.ts +++ b/src/main/download-manager.ts @@ -5216,7 +5216,7 @@ export class DownloadManager extends EventEmitter { let allMissingExistOnDisk = true; for (const part of missingParts) { try { - const stat = fs.statSync(part); + const stat = await fs.promises.stat(part); if (stat.size < 10240) { allMissingExistOnDisk = false; break; @@ -5466,7 +5466,7 @@ export class DownloadManager extends EventEmitter { continue; } try { - const stat = fs.statSync(item.targetPath); + const stat = await fs.promises.stat(item.targetPath); // Require file to be either ≥50% of expected size or at least 10 KB to avoid // recovering tiny error-response files (e.g. 9-byte "Forbidden" pages). const minSize = item.totalBytes && item.totalBytes > 0 diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index aa65b63..987033f 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -69,9 +69,10 @@ const emptySnapshot = (): UiSnapshot => ({ cleanupMode: "none", extractConflictMode: "overwrite", removeLinkFilesAfterExtract: false, removeSamplesAfterExtract: false, enableIntegrityCheck: true, autoResumeOnStart: true, autoReconnect: false, reconnectWaitSeconds: 45, completedCleanupPolicy: "never", - maxParallel: 4, retryLimit: 0, speedLimitEnabled: false, speedLimitKbps: 0, speedLimitMode: "global", + maxParallel: 4, maxParallelExtract: 2, retryLimit: 0, speedLimitEnabled: false, speedLimitKbps: 0, speedLimitMode: "global", updateRepo: "", autoUpdateCheck: true, clipboardWatch: false, minimizeToTray: false, - theme: "dark", collapseNewPackages: true, bandwidthSchedules: [] + theme: "dark", collapseNewPackages: true, autoSkipExtracted: false, confirmDeleteSelection: true, + bandwidthSchedules: [], totalDownloadedAllTime: 0 }, session: { version: 2, packageOrder: [], packages: {}, items: {}, runStartedAt: 0, @@ -144,7 +145,7 @@ const BandwidthChart = memo(function BandwidthChart({ items, running, paused, sp const canvasRef = useRef(null); const containerRef = useRef(null); const lastUpdateRef = useRef(0); - const [, forceUpdate] = useState(0); + const animationFrameRef = useRef(0); const drawChart = useCallback(() => { @@ -268,13 +269,10 @@ const BandwidthChart = memo(function BandwidthChart({ items, running, paused, sp useEffect(() => { const interval = setInterval(() => { - const now = Date.now(); - if (now - lastUpdateRef.current >= 250) { - forceUpdate((n) => n + 1); - } + drawChart(); }, 250); return () => clearInterval(interval); - }, []); + }, [drawChart]); useEffect(() => { const now = Date.now(); @@ -313,7 +311,7 @@ const BandwidthChart = memo(function BandwidthChart({ items, running, paused, sp useEffect(() => { drawChart(); - }); + }, [drawChart, items, paused]); return (
@@ -466,6 +464,8 @@ export function App(): ReactElement { const settingsDirtyRef = useRef(false); const settingsDraftRevisionRef = useRef(0); const latestStateRef = useRef(null); + const snapshotRef = useRef(snapshot); + snapshotRef.current = snapshot; const stateFlushTimerRef = useRef | null>(null); const toastTimerRef = useRef | null>(null); const [dragOver, setDragOver] = useState(false); @@ -1649,13 +1649,11 @@ export function App(): ReactElement { }, [contextMenu]); const executeDeleteSelection = useCallback((ids: Set): void => { - setSnapshot((prev) => { - for (const id of ids) { - if (prev.session.items[id]) void window.rd.removeItem(id); - else if (prev.session.packages[id]) void window.rd.cancelPackage(id); - } - return prev; - }); + const current = snapshotRef.current; + for (const id of ids) { + if (current.session.items[id]) void window.rd.removeItem(id); + else if (current.session.packages[id]) void window.rd.cancelPackage(id); + } setSelectedIds(new Set()); }, []); @@ -1752,10 +1750,7 @@ export function App(): ReactElement { if (!e.shiftKey && e.key.toLowerCase() === "o") { e.preventDefault(); setOpenMenu(null); - void window.rd.pickContainers().then(async (files) => { - if (files.length === 0) { return; } - await window.rd.addContainers(files); - }).catch(() => undefined); + void onImportDlc(); return; } } diff --git a/src/renderer/styles.css b/src/renderer/styles.css index 4f2c638..be068bb 100644 --- a/src/renderer/styles.css +++ b/src/renderer/styles.css @@ -577,7 +577,7 @@ body, .pkg-column-header { display: grid; - grid-template-columns: 1fr 90px 170px 140px 130px 180px 100px; + grid-template-columns: 1fr 170px 90px 140px 130px 180px 100px; gap: 8px; padding: 5px 12px; background: var(--card); @@ -612,7 +612,7 @@ body, .pkg-columns { display: grid; - grid-template-columns: 1fr 90px 170px 140px 130px 180px 100px; + grid-template-columns: 1fr 170px 90px 140px 130px 180px 100px; gap: 8px; align-items: center; min-width: 0; @@ -1284,7 +1284,7 @@ td { .item-row { display: grid; - grid-template-columns: 1fr 90px 170px 140px 130px 180px 100px; + grid-template-columns: 1fr 170px 90px 140px 130px 180px 100px; gap: 8px; align-items: center; margin: 0 -12px;