Persist totalDownloadedAllTime across restarts

- 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>
This commit is contained in:
Sucukdeluxe 2026-03-02 19:29:32 +01:00
parent 549328893e
commit bc70ff94cc
3 changed files with 15 additions and 3 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "real-debrid-downloader", "name": "real-debrid-downloader",
"version": "1.5.11", "version": "1.5.12",
"description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)", "description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)",
"main": "build/main/main/main.js", "main": "build/main/main/main.js",
"author": "Sucukdeluxe", "author": "Sucukdeluxe",

View File

@ -133,6 +133,9 @@ export class AppController {
return this.settings; return this.settings;
} }
// Preserve the live totalDownloadedAllTime from the download manager
const liveSettings = this.manager.getSettings();
nextSettings.totalDownloadedAllTime = Math.max(nextSettings.totalDownloadedAllTime || 0, liveSettings.totalDownloadedAllTime || 0);
this.settings = nextSettings; this.settings = nextSettings;
saveSettings(this.storagePaths, this.settings); saveSettings(this.storagePaths, this.settings);
this.manager.setSettings(this.settings); this.manager.setSettings(this.settings);

View File

@ -23,7 +23,7 @@ import { DebridService, MegaWebUnrestrictor } from "./debrid";
import { collectArchiveCleanupTargets, extractPackageArchives, findArchiveCandidates } from "./extractor"; import { collectArchiveCleanupTargets, extractPackageArchives, findArchiveCandidates } from "./extractor";
import { validateFileAgainstManifest } from "./integrity"; import { validateFileAgainstManifest } from "./integrity";
import { logger } from "./logger"; import { logger } from "./logger";
import { StoragePaths, saveSession, saveSessionAsync } from "./storage"; import { StoragePaths, saveSession, saveSessionAsync, saveSettings } from "./storage";
import { compactErrorText, ensureDirPath, filenameFromUrl, formatEta, humanSize, looksLikeOpaqueFilename, nowMs, sanitizeFilename, sleep } from "./utils"; import { compactErrorText, ensureDirPath, filenameFromUrl, formatEta, humanSize, looksLikeOpaqueFilename, nowMs, sanitizeFilename, sleep } from "./utils";
type ActiveTask = { type ActiveTask = {
@ -735,6 +735,7 @@ export class DownloadManager extends EventEmitter {
private statsCacheAt = 0; private statsCacheAt = 0;
private lastPersistAt = 0; private lastPersistAt = 0;
private lastSettingsPersistAt = 0;
private cleanupQueue: Promise<void> = Promise.resolve(); private cleanupQueue: Promise<void> = Promise.resolve();
@ -802,6 +803,7 @@ export class DownloadManager extends EventEmitter {
} }
public setSettings(next: AppSettings): void { public setSettings(next: AppSettings): void {
next.totalDownloadedAllTime = Math.max(next.totalDownloadedAllTime || 0, this.settings.totalDownloadedAllTime || 0);
this.settings = next; this.settings = next;
this.debridService.setSettings(next); this.debridService.setSettings(next);
this.resolveExistingQueuedOpaqueFilenames(); this.resolveExistingQueuedOpaqueFilenames();
@ -2462,6 +2464,7 @@ export class DownloadManager extends EventEmitter {
this.retryAfterByItem.clear(); this.retryAfterByItem.clear();
this.nonResumableActive = 0; this.nonResumableActive = 0;
this.session.summaryText = ""; this.session.summaryText = "";
this.lastSettingsPersistAt = 0; // force settings save on shutdown
this.persistNow(); this.persistNow();
this.emitState(true); this.emitState(true);
logger.info(`Shutdown-Vorbereitung beendet: requeued=${requeuedItems}`); logger.info(`Shutdown-Vorbereitung beendet: requeued=${requeuedItems}`);
@ -2636,8 +2639,13 @@ export class DownloadManager extends EventEmitter {
} }
private persistNow(): void { private persistNow(): void {
this.lastPersistAt = nowMs(); const now = nowMs();
this.lastPersistAt = now;
void saveSessionAsync(this.storagePaths, this.session).catch((err) => logger.warn(`saveSessionAsync Fehler: ${compactErrorText(err)}`)); void saveSessionAsync(this.storagePaths, this.session).catch((err) => logger.warn(`saveSessionAsync Fehler: ${compactErrorText(err)}`));
if (now - this.lastSettingsPersistAt >= 30000) {
this.lastSettingsPersistAt = now;
try { saveSettings(this.storagePaths, this.settings); } catch (err) { logger.warn(`saveSettings Fehler: ${compactErrorText(err as Error)}`); }
}
} }
private emitState(force = false): void { private emitState(force = false): void {
@ -5405,6 +5413,7 @@ export class DownloadManager extends EventEmitter {
this.nonResumableActive = 0; this.nonResumableActive = 0;
this.lastGlobalProgressBytes = this.session.totalDownloadedBytes; this.lastGlobalProgressBytes = this.session.totalDownloadedBytes;
this.lastGlobalProgressAt = nowMs(); this.lastGlobalProgressAt = nowMs();
this.lastSettingsPersistAt = 0; // force settings save on run finish
this.persistNow(); this.persistNow();
this.emitState(); this.emitState();
} }