From 1ed13f7f88ce53f4af4bc4bae774b7e6fb61d2da Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Wed, 4 Mar 2026 18:57:18 +0100 Subject: [PATCH] Release v1.6.21 Co-Authored-By: Claude Opus 4.6 --- package.json | 2 +- src/main/app-controller.ts | 6 ++++-- src/main/download-manager.ts | 8 ++++++++ src/main/extractor.ts | 7 +++---- src/main/storage.ts | 7 +++---- src/renderer/App.tsx | 17 ++++++++++++----- 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 592ee55..368da78 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "real-debrid-downloader", - "version": "1.6.20", + "version": "1.6.21", "description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)", "main": "build/main/main/main.js", "author": "Sucukdeluxe", diff --git a/src/main/app-controller.ts b/src/main/app-controller.ts index 6a67726..e6ed2f5 100644 --- a/src/main/app-controller.ts +++ b/src/main/app-controller.ts @@ -21,7 +21,7 @@ import { parseCollectorInput } from "./link-parser"; import { configureLogger, getLogFilePath, logger } from "./logger"; import { initSessionLog, getSessionLogPath, shutdownSessionLog } from "./session-log"; import { MegaWebFallback } from "./mega-web-fallback"; -import { addHistoryEntry, clearHistory, createStoragePaths, loadHistory, loadSession, loadSettings, normalizeSettings, removeHistoryEntry, saveSession, saveSettings } from "./storage"; +import { addHistoryEntry, clearHistory, createStoragePaths, loadHistory, loadSession, loadSettings, normalizeLoadedSession, normalizeLoadedSessionTransientFields, normalizeSettings, removeHistoryEntry, saveSession, saveSettings } from "./storage"; import { abortActiveUpdateDownload, checkGitHubUpdate, installLatestUpdate } from "./update"; import { startDebugServer, stopDebugServer } from "./debug-server"; @@ -309,7 +309,9 @@ export class AppController { // Cancel any deferred persist timer so the old in-memory session // does not overwrite the restored session file on disk. this.manager.clearPersistTimer(); - const restoredSession = parsed.session as ReturnType; + const restoredSession = normalizeLoadedSessionTransientFields( + normalizeLoadedSession(parsed.session) + ); saveSession(this.storagePaths, restoredSession); return { restored: true, message: "Backup wiederhergestellt. Bitte App neustarten." }; } diff --git a/src/main/download-manager.ts b/src/main/download-manager.ts index 9fcfc22..768dbb7 100644 --- a/src/main/download-manager.ts +++ b/src/main/download-manager.ts @@ -2540,6 +2540,14 @@ export class DownloadManager extends EventEmitter { pkg.updatedAt = nowMs(); this.historyRecordedPackages.delete(packageId); + // 5. Re-add to runItemIds/runPackageIds if session is running so outcomes are tracked + if (this.session.running) { + for (const itemId of itemIds) { + this.runItemIds.add(itemId); + } + this.runPackageIds.add(packageId); + } + logger.info(`Paket "${pkg.name}" zurückgesetzt (${itemIds.length} Items)`); this.persistSoon(); this.emitState(true); diff --git a/src/main/extractor.ts b/src/main/extractor.ts index 5d7b889..3491217 100644 --- a/src/main/extractor.ts +++ b/src/main/extractor.ts @@ -1993,6 +1993,7 @@ export async function extractPackageArchives(options: ExtractOptions): Promise<{ const sig = await detectArchiveSignature(archivePath); if (!sig) { logger.info(`Generische Split-Datei übersprungen (keine Archiv-Signatur): ${archiveName}`); + extracted += 1; clearInterval(pulseTimer); return; } @@ -2200,10 +2201,8 @@ export async function extractPackageArchives(options: ExtractOptions): Promise<{ resumeCompleted.add(nestedKey); await writeExtractResumeState(options.packageDir, resumeCompleted, options.packageId); logger.info(`Nested-Entpacken erfolgreich: ${nestedName}`); - if (options.cleanupMode === "delete") { - for (const part of collectArchiveCleanupTargets(nestedArchive)) { - try { await fs.promises.unlink(part); } catch { /* ignore */ } - } + if (options.cleanupMode !== "none") { + await cleanupArchives([nestedArchive], options.cleanupMode); } } catch (nestedErr) { const errText = String(nestedErr); diff --git a/src/main/storage.ts b/src/main/storage.ts index f3ee70d..80671ec 100644 --- a/src/main/storage.ts +++ b/src/main/storage.ts @@ -188,8 +188,7 @@ function sanitizeCredentialPersistence(settings: AppSettings): AppSettings { megaLogin: "", megaPassword: "", bestToken: "", - allDebridToken: "", - archivePasswordList: "" + allDebridToken: "" }; } @@ -233,7 +232,7 @@ function readSettingsFile(filePath: string): AppSettings | null { } } -function normalizeLoadedSession(raw: unknown): SessionState { +export function normalizeLoadedSession(raw: unknown): SessionState { const fallback = emptySession(); const parsed = asRecord(raw); if (!parsed) { @@ -412,7 +411,7 @@ function sessionBackupPath(sessionFile: string): string { return `${sessionFile}.bak`; } -function normalizeLoadedSessionTransientFields(session: SessionState): SessionState { +export function normalizeLoadedSessionTransientFields(session: SessionState): SessionState { // Reset transient fields that may be stale from a previous crash const ACTIVE_STATUSES = new Set(["downloading", "validating", "extracting", "integrity_check", "paused", "reconnect_wait"]); for (const item of Object.values(session.items)) { diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 682ed58..3885c21 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -1813,9 +1813,12 @@ export function App(): ReactElement { const onKey = (e: KeyboardEvent): void => { if (e.key === "Escape") { const target = e.target as HTMLElement; - if (target.tagName !== "INPUT" && target.tagName !== "TEXTAREA") setSelectedIds(new Set()); + if (target.tagName !== "INPUT" && target.tagName !== "TEXTAREA") { + if (tabRef.current === "downloads") setSelectedIds(new Set()); + else if (tabRef.current === "history") setSelectedHistoryIds(new Set()); + } } - if (e.key === "Delete" && selectedIds.size > 0) { + if (e.key === "Delete" && tabRef.current === "downloads" && selectedIds.size > 0) { const target = e.target as HTMLElement; if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") return; e.preventDefault(); @@ -1824,7 +1827,7 @@ export function App(): ReactElement { }; const onDown = (e: MouseEvent): void => { const target = e.target as HTMLElement; - if (target.closest(".package-card") || target.closest(".ctx-menu")) return; + if (target.closest(".package-card") || target.closest(".ctx-menu") || target.closest(".modal-backdrop") || target.closest(".modal-card")) return; setSelectedIds(new Set()); }; window.addEventListener("keydown", onKey); @@ -3368,7 +3371,9 @@ const PackageCard = memo(function PackageCard({ pkg, items, packageSpeed, isFirs if (prev.pkg.updatedAt !== next.pkg.updatedAt || prev.pkg.status !== next.pkg.status || prev.pkg.enabled !== next.pkg.enabled - || prev.pkg.name !== next.pkg.name) { + || prev.pkg.name !== next.pkg.name + || prev.pkg.priority !== next.pkg.priority + || prev.pkg.createdAt !== next.pkg.createdAt) { return false; } if (prev.packageSpeed !== next.packageSpeed @@ -3410,7 +3415,9 @@ const PackageCard = memo(function PackageCard({ pkg, items, packageSpeed, isFirs || a.retries !== b.retries || a.provider !== b.provider || a.fullStatus !== b.fullStatus - || a.onlineStatus !== b.onlineStatus) { + || a.onlineStatus !== b.onlineStatus + || a.downloadedBytes !== b.downloadedBytes + || a.totalBytes !== b.totalBytes) { return false; } }