Release v1.4.9 with extraction resume fix and faster update downloads

- Fix extraction status display after restart (shows "Entpacken ausstehend" instead of stale status)
- Fix Start button to trigger pending extractions for already-downloaded packages
- Fix extraction resume when archives already cleaned (recognizes completed state from resume file)
- Reduce update download connection timeout from 8min to 30s per candidate for faster fallback
- Add logging for update download candidates and failures
- Show manual download URL on update failure
- Sequential extraction preserved (one package at a time via queue)
- Extraction properly cancelled on shutdown, resumes on restart

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sucukdeluxe
2026-02-27 19:47:53 +01:00
co-authored by Claude Opus 4.6
parent 333a912d67
commit e1286e02af
4 changed files with 77 additions and 4 deletions
+52
View File
@@ -969,6 +969,8 @@ export class DownloadManager extends EventEmitter {
this.emitState(true);
}
this.triggerPendingExtractions();
const runItems = Object.values(this.session.items)
.filter((item) => {
if (item.status !== "queued" && item.status !== "reconnect_wait") {
@@ -1420,6 +1422,15 @@ export class DownloadManager extends EventEmitter {
const needsPostProcess = pkg.status !== "completed"
|| items.some((item) => item.status === "completed" && !isExtractedLabel(item.fullStatus));
if (needsPostProcess) {
pkg.status = "queued";
pkg.updatedAt = nowMs();
for (const item of items) {
if (item.status === "completed" && !isExtractedLabel(item.fullStatus)) {
item.fullStatus = "Entpacken ausstehend";
item.updatedAt = nowMs();
}
}
changed = true;
void this.runPackagePostProcessing(packageId);
} else if (pkg.status !== "completed") {
pkg.status = "completed";
@@ -1443,6 +1454,47 @@ export class DownloadManager extends EventEmitter {
}
}
private triggerPendingExtractions(): void {
if (!this.settings.autoExtract) {
return;
}
for (const packageId of this.session.packageOrder) {
const pkg = this.session.packages[packageId];
if (!pkg || pkg.cancelled || !pkg.enabled) {
continue;
}
if (this.packagePostProcessTasks.has(packageId)) {
continue;
}
const items = pkg.itemIds.map((id) => this.session.items[id]).filter(Boolean) as DownloadItem[];
if (items.length === 0) {
continue;
}
const success = items.filter((item) => item.status === "completed").length;
const failed = items.filter((item) => item.status === "failed").length;
const cancelled = items.filter((item) => item.status === "cancelled").length;
if (success + failed + cancelled < items.length || failed > 0 || success === 0) {
continue;
}
const needsExtraction = items.some((item) =>
item.status === "completed" && !isExtractedLabel(item.fullStatus)
);
if (!needsExtraction) {
continue;
}
pkg.status = "queued";
pkg.updatedAt = nowMs();
for (const item of items) {
if (item.status === "completed" && !isExtractedLabel(item.fullStatus)) {
item.fullStatus = "Entpacken ausstehend";
item.updatedAt = nowMs();
}
}
logger.info(`Entpacken via Start ausgelöst: pkg=${pkg.name}`);
void this.runPackagePostProcessing(packageId);
}
}
private removePackageFromSession(packageId: string, itemIds: string[]): void {
for (const itemId of itemIds) {
delete this.session.items[itemId];