perf(ui): calm large-queue live updates
Throttle visible download snapshots at 500 ms from 250 queue items, align speed visualizations to the same cadence, preserve small-queue responsiveness, and retain the stronger protection for very large queues.
This commit is contained in:
@@ -4,6 +4,14 @@ All notable changes to Multi-Debrid Downloader are documented in this file.
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2.0.44] - 2026-08-17
|
||||||
|
|
||||||
|
### Live updates
|
||||||
|
|
||||||
|
- Reduced visible download, remaining-volume, speed, ETA, and availability refresh churn for queues with 250 or more items by using a calm 500 ms cadence.
|
||||||
|
- Updated live speed sparklines and the bandwidth chart to redraw every 500 ms instead of every 250 ms.
|
||||||
|
- Kept small queues responsive and retained the stronger 700 ms protection for queues with 1,500 or more items.
|
||||||
|
|
||||||
## [2.0.43] - 2026-08-16
|
## [2.0.43] - 2026-08-16
|
||||||
|
|
||||||
### Product identity
|
### Product identity
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "multi-debrid-downloader",
|
"name": "multi-debrid-downloader",
|
||||||
"version": "2.0.43",
|
"version": "2.0.44",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "multi-debrid-downloader",
|
"name": "multi-debrid-downloader",
|
||||||
"version": "2.0.43",
|
"version": "2.0.44",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"adm-zip": "0.6.0",
|
"adm-zip": "0.6.0",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "multi-debrid-downloader",
|
"name": "multi-debrid-downloader",
|
||||||
"version": "2.0.43",
|
"version": "2.0.44",
|
||||||
"description": "Desktop downloader",
|
"description": "Desktop downloader",
|
||||||
"main": "build/main/main/main.js",
|
"main": "build/main/main/main.js",
|
||||||
"author": "Sucukdeluxe",
|
"author": "Sucukdeluxe",
|
||||||
|
|||||||
@@ -6551,11 +6551,9 @@ export class DownloadManager extends EventEmitter {
|
|||||||
const emitDelay = this.session.running
|
const emitDelay = this.session.running
|
||||||
? itemCount >= 1500
|
? itemCount >= 1500
|
||||||
? 700
|
? 700
|
||||||
: itemCount >= 700
|
: itemCount >= 250
|
||||||
? 500
|
? 500
|
||||||
: itemCount >= 250
|
: 150
|
||||||
? 300
|
|
||||||
: 150
|
|
||||||
: 200;
|
: 200;
|
||||||
this.stateEmitTimer = setTimeout(() => {
|
this.stateEmitTimer = setTimeout(() => {
|
||||||
this.stateEmitTimer = null;
|
this.stateEmitTimer = null;
|
||||||
@@ -10568,12 +10566,10 @@ export class DownloadManager extends EventEmitter {
|
|||||||
let lastLoggedPercent = -1;
|
let lastLoggedPercent = -1;
|
||||||
const itemCount = this.itemCount;
|
const itemCount = this.itemCount;
|
||||||
const uiUpdateIntervalMs = itemCount >= 1500
|
const uiUpdateIntervalMs = itemCount >= 1500
|
||||||
? 500
|
? 700
|
||||||
: itemCount >= 700
|
: itemCount >= 250
|
||||||
? 350
|
? 500
|
||||||
: itemCount >= 250
|
: 120;
|
||||||
? 220
|
|
||||||
: 120;
|
|
||||||
let lastUiEmitAt = 0;
|
let lastUiEmitAt = 0;
|
||||||
const stallTimeoutMs = getDownloadStallTimeoutMs();
|
const stallTimeoutMs = getDownloadStallTimeoutMs();
|
||||||
const drainTimeoutMs = Math.max(30000, Math.min(300000, stallTimeoutMs > 0 ? stallTimeoutMs * 12 : 120000));
|
const drainTimeoutMs = Math.max(30000, Math.min(300000, stallTimeoutMs > 0 ? stallTimeoutMs * 12 : 120000));
|
||||||
|
|||||||
@@ -880,7 +880,7 @@ const historyRetentionLabels: Record<RendererSettings["historyRetentionMode"], s
|
|||||||
const AUTO_RENDER_PACKAGE_LIMIT = 260;
|
const AUTO_RENDER_PACKAGE_LIMIT = 260;
|
||||||
|
|
||||||
export function getSnapshotRenderDelay(itemCount: number, running: boolean, activeTab: MainView): number {
|
export function getSnapshotRenderDelay(itemCount: number, running: boolean, activeTab: MainView): number {
|
||||||
let delay = itemCount >= 700 ? 0 : itemCount >= 250 ? 50 : 100;
|
let delay = itemCount >= 250 ? 0 : 100;
|
||||||
if (!running) delay = Math.min(delay, 200);
|
if (!running) delay = Math.min(delay, 200);
|
||||||
if (activeTab !== "downloads") delay = Math.max(delay, 800);
|
if (activeTab !== "downloads") delay = Math.max(delay, 800);
|
||||||
return delay;
|
return delay;
|
||||||
@@ -1272,7 +1272,7 @@ const BandwidthChart = memo(function BandwidthChart({ running, paused, speedHist
|
|||||||
const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
drawChart();
|
drawChart();
|
||||||
}, reducedMotion ? 1000 : 250);
|
}, reducedMotion ? 1000 : 500);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [drawChart, running, paused]);
|
}, [drawChart, running, paused]);
|
||||||
|
|
||||||
@@ -1374,7 +1374,7 @@ const DownloadSpeedSparkline = memo(function DownloadSpeedSparkline({ speedBps,
|
|||||||
draw();
|
draw();
|
||||||
};
|
};
|
||||||
|
|
||||||
const id = window.setInterval(tick, 250);
|
const id = window.setInterval(tick, 500);
|
||||||
return () => window.clearInterval(id);
|
return () => window.clearInterval(id);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,10 @@ describe("desktop shell", () => {
|
|||||||
expect(getSnapshotRenderDelay(2_470, true, "statistics")).toBe(800);
|
expect(getSnapshotRenderDelay(2_470, true, "statistics")).toBe(800);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("renders medium download queues immediately after their calm half-second snapshot", () => {
|
||||||
|
expect(getSnapshotRenderDelay(661, true, "downloads")).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
it("keeps application menus mounted for animated opening and closing", () => {
|
it("keeps application menus mounted for animated opening and closing", () => {
|
||||||
const source = readFileSync(new URL("../src/renderer/App.tsx", import.meta.url), "utf8");
|
const source = readFileSync(new URL("../src/renderer/App.tsx", import.meta.url), "utf8");
|
||||||
const css = readFileSync(new URL("../src/renderer/styles.css", import.meta.url), "utf8");
|
const css = readFileSync(new URL("../src/renderer/styles.css", import.meta.url), "utf8");
|
||||||
|
|||||||
@@ -507,7 +507,7 @@ describe("bandwidth chart palette", () => {
|
|||||||
expect(chartBlock).toContain('role="img"');
|
expect(chartBlock).toContain('role="img"');
|
||||||
expect(chartBlock).toContain('aria-label="Bandbreitenverlauf der letzten 60 Sekunden"');
|
expect(chartBlock).toContain('aria-label="Bandbreitenverlauf der letzten 60 Sekunden"');
|
||||||
expect(chartBlock).toContain('window.matchMedia("(prefers-reduced-motion: reduce)")');
|
expect(chartBlock).toContain('window.matchMedia("(prefers-reduced-motion: reduce)")');
|
||||||
expect(chartBlock).toContain("reducedMotion ? 1000 : 250");
|
expect(chartBlock).toContain("reducedMotion ? 1000 : 500");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("asks for confirmation before deleting all saved download statistics", () => {
|
it("asks for confirmation before deleting all saved download statistics", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user