Release v1.6.19
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a263e3eb2c
commit
b8bbc9c32f
@@ -1437,6 +1437,21 @@ export class DownloadManager extends EventEmitter {
|
||||
|
||||
this.persistSoon();
|
||||
this.emitState(true);
|
||||
|
||||
// Fix async race: processItem catch with "package_toggle" overwrites fullStatus
|
||||
// after we already set it to "Wartet". Re-fix on next microtask.
|
||||
const pkgItemIds = [...pkg.itemIds];
|
||||
queueMicrotask(() => {
|
||||
for (const iid of pkgItemIds) {
|
||||
const it = this.session.items[iid];
|
||||
if (it && it.status === "queued" && it.fullStatus === "Paket gestoppt") {
|
||||
it.fullStatus = "Wartet";
|
||||
it.updatedAt = nowMs();
|
||||
}
|
||||
}
|
||||
this.emitState(true);
|
||||
});
|
||||
|
||||
return { skipped: true, overwritten: false };
|
||||
}
|
||||
|
||||
@@ -2472,8 +2487,8 @@ export class DownloadManager extends EventEmitter {
|
||||
|
||||
const active = this.activeTasks.get(itemId);
|
||||
if (active) {
|
||||
active.abortReason = "cancel";
|
||||
active.abortController.abort("cancel");
|
||||
active.abortReason = "reset";
|
||||
active.abortController.abort("reset");
|
||||
}
|
||||
|
||||
// Delete partial download file
|
||||
@@ -2540,8 +2555,8 @@ export class DownloadManager extends EventEmitter {
|
||||
|
||||
const active = this.activeTasks.get(itemId);
|
||||
if (active) {
|
||||
active.abortReason = "cancel";
|
||||
active.abortController.abort("cancel");
|
||||
active.abortReason = "reset";
|
||||
active.abortController.abort("reset");
|
||||
}
|
||||
|
||||
const targetPath = String(item.targetPath || "").trim();
|
||||
@@ -2552,7 +2567,6 @@ export class DownloadManager extends EventEmitter {
|
||||
|
||||
this.dropItemContribution(itemId);
|
||||
this.runOutcomes.delete(itemId);
|
||||
this.runItemIds.delete(itemId);
|
||||
this.retryAfterByItem.delete(itemId);
|
||||
this.retryStateByItem.delete(itemId);
|
||||
|
||||
@@ -2570,6 +2584,13 @@ export class DownloadManager extends EventEmitter {
|
||||
item.fullStatus = "Wartet";
|
||||
item.onlineStatus = undefined;
|
||||
item.updatedAt = nowMs();
|
||||
|
||||
// Re-add to runItemIds if session is running so outcome is tracked in summary
|
||||
if (this.session.running) {
|
||||
this.runItemIds.add(itemId);
|
||||
} else {
|
||||
this.runItemIds.delete(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset parent package status if it was completed/failed (now has queued items again)
|
||||
@@ -4678,6 +4699,9 @@ export class DownloadManager extends EventEmitter {
|
||||
genericErrorRetries: Number(active.genericErrorRetries || 0),
|
||||
unrestrictRetries: Number(active.unrestrictRetries || 0)
|
||||
});
|
||||
} else if (reason === "reset") {
|
||||
// Item was reset externally by resetItems/resetPackage — state already set, do nothing
|
||||
this.retryStateByItem.delete(item.id);
|
||||
} else if (reason === "package_toggle") {
|
||||
item.status = "queued";
|
||||
item.speedBps = 0;
|
||||
|
||||
+6
-1
@@ -130,7 +130,7 @@ function createTray(): void {
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ label: "Anzeigen", click: () => { mainWindow?.show(); mainWindow?.focus(); } },
|
||||
{ type: "separator" },
|
||||
{ label: "Start", click: () => { controller.start(); } },
|
||||
{ label: "Start", click: () => { void controller.start().catch((err) => logger.warn(`Tray Start Fehler: ${String(err)}`)); } },
|
||||
{ label: "Stop", click: () => { controller.stop(); } },
|
||||
{ type: "separator" },
|
||||
{ label: "Beenden", click: () => { app.quit(); } }
|
||||
@@ -453,6 +453,11 @@ function registerIpcHandlers(): void {
|
||||
return { restored: false, message: "Abgebrochen" };
|
||||
}
|
||||
const filePath = result.filePaths[0];
|
||||
const stat = await fs.promises.stat(filePath);
|
||||
const BACKUP_MAX_BYTES = 50 * 1024 * 1024;
|
||||
if (stat.size > BACKUP_MAX_BYTES) {
|
||||
return { restored: false, message: `Backup-Datei zu groß (max 50 MB, Datei hat ${(stat.size / 1024 / 1024).toFixed(1)} MB)` };
|
||||
}
|
||||
const json = await fs.promises.readFile(filePath, "utf8");
|
||||
return controller.importBackup(json);
|
||||
});
|
||||
|
||||
+21
-6
@@ -449,8 +449,13 @@ export function saveSettings(paths: StoragePaths, settings: AppSettings): void {
|
||||
const persisted = sanitizeCredentialPersistence(normalizeSettings(settings));
|
||||
const payload = JSON.stringify(persisted, null, 2);
|
||||
const tempPath = `${paths.configFile}.tmp`;
|
||||
fs.writeFileSync(tempPath, payload, "utf8");
|
||||
syncRenameWithExdevFallback(tempPath, paths.configFile);
|
||||
try {
|
||||
fs.writeFileSync(tempPath, payload, "utf8");
|
||||
syncRenameWithExdevFallback(tempPath, paths.configFile);
|
||||
} catch (error) {
|
||||
try { fs.rmSync(tempPath, { force: true }); } catch { /* ignore */ }
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
let asyncSettingsSaveRunning = false;
|
||||
@@ -553,8 +558,13 @@ export function saveSession(paths: StoragePaths, session: SessionState): void {
|
||||
}
|
||||
const payload = JSON.stringify({ ...session, updatedAt: Date.now() });
|
||||
const tempPath = sessionTempPath(paths.sessionFile, "sync");
|
||||
fs.writeFileSync(tempPath, payload, "utf8");
|
||||
syncRenameWithExdevFallback(tempPath, paths.sessionFile);
|
||||
try {
|
||||
fs.writeFileSync(tempPath, payload, "utf8");
|
||||
syncRenameWithExdevFallback(tempPath, paths.sessionFile);
|
||||
} catch (error) {
|
||||
try { fs.rmSync(tempPath, { force: true }); } catch { /* ignore */ }
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
let asyncSaveRunning = false;
|
||||
@@ -652,8 +662,13 @@ export function saveHistory(paths: StoragePaths, entries: HistoryEntry[]): void
|
||||
const trimmed = entries.slice(0, MAX_HISTORY_ENTRIES);
|
||||
const payload = JSON.stringify(trimmed, null, 2);
|
||||
const tempPath = `${paths.historyFile}.tmp`;
|
||||
fs.writeFileSync(tempPath, payload, "utf8");
|
||||
syncRenameWithExdevFallback(tempPath, paths.historyFile);
|
||||
try {
|
||||
fs.writeFileSync(tempPath, payload, "utf8");
|
||||
syncRenameWithExdevFallback(tempPath, paths.historyFile);
|
||||
} catch (error) {
|
||||
try { fs.rmSync(tempPath, { force: true }); } catch { /* ignore */ }
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export function addHistoryEntry(paths: StoragePaths, entry: HistoryEntry): HistoryEntry[] {
|
||||
|
||||
Reference in New Issue
Block a user