Release v1.6.27

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sucukdeluxe 2026-03-04 20:34:50 +01:00
parent 55b00bf884
commit 9a00304a93
4 changed files with 32 additions and 12 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "real-debrid-downloader", "name": "real-debrid-downloader",
"version": "1.6.26", "version": "1.6.27",
"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

@ -1710,8 +1710,8 @@ export class DownloadManager extends EventEmitter {
item.lastError = "Datei nicht gefunden auf Rapidgator"; item.lastError = "Datei nicht gefunden auf Rapidgator";
item.onlineStatus = "offline"; item.onlineStatus = "offline";
item.updatedAt = nowMs(); item.updatedAt = nowMs();
if (this.runItemIds.has(itemId)) { if (this.runItemIds.has(item.id)) {
this.recordRunOutcome(itemId, "failed"); this.recordRunOutcome(item.id, "failed");
} }
// Refresh package status since item was set to failed // Refresh package status since item was set to failed
const pkg = this.session.packages[item.packageId]; const pkg = this.session.packages[item.packageId];
@ -2575,6 +2575,10 @@ export class DownloadManager extends EventEmitter {
if (postProcessController && !postProcessController.signal.aborted) { if (postProcessController && !postProcessController.signal.aborted) {
postProcessController.abort("reset"); postProcessController.abort("reset");
} }
this.packagePostProcessAbortControllers.delete(packageId);
this.packagePostProcessTasks.delete(packageId);
this.hybridExtractRequeue.delete(packageId);
this.runCompletedPackages.delete(packageId);
// 3. Clean up extraction progress manifest (.rd_extract_progress.json) // 3. Clean up extraction progress manifest (.rd_extract_progress.json)
if (pkg.outputDir) { if (pkg.outputDir) {
@ -3418,7 +3422,9 @@ export class DownloadManager extends EventEmitter {
if (this.settings.autoExtract) { if (this.settings.autoExtract) {
const allExtracted = pkg.itemIds.every((id) => { const allExtracted = pkg.itemIds.every((id) => {
const item = this.session.items[id]; const item = this.session.items[id];
return !item || isExtractedLabel(item.fullStatus || ""); if (!item) return true;
if (item.status === "failed" || item.status === "cancelled") return true;
return isExtractedLabel(item.fullStatus || "");
}); });
if (!allExtracted) continue; if (!allExtracted) continue;
} }
@ -4927,6 +4933,7 @@ export class DownloadManager extends EventEmitter {
} }
} }
this.releaseTargetPath(item.id); this.releaseTargetPath(item.id);
this.dropItemContribution(item.id);
this.queueRetry(item, active, 300, "Netzwerkfehler erkannt, frischer Retry"); this.queueRetry(item, active, 300, "Netzwerkfehler erkannt, frischer Retry");
item.lastError = ""; item.lastError = "";
item.downloadedBytes = 0; item.downloadedBytes = 0;
@ -6373,11 +6380,12 @@ export class DownloadManager extends EventEmitter {
} }
const status = entry.fullStatus || ""; const status = entry.fullStatus || "";
if (/^Entpacken\b/i.test(status)) { if (/^Entpacken\b/i.test(status)) {
if (result.extracted > 0 && result.failed === 0) { if (result.failed > 0) {
entry.fullStatus = formatExtractDone(nowMs() - hybridExtractStartMs);
} else {
entry.fullStatus = "Entpacken - Error"; entry.fullStatus = "Entpacken - Error";
} else if (result.extracted > 0) {
entry.fullStatus = formatExtractDone(nowMs() - hybridExtractStartMs);
} }
// extracted === 0 && failed === 0: keep current status (no archives to process)
entry.updatedAt = updatedAt; entry.updatedAt = updatedAt;
} }
} }
@ -6690,7 +6698,9 @@ export class DownloadManager extends EventEmitter {
const timeoutReason = `Entpacken Timeout nach ${Math.ceil(extractTimeoutMs / 1000)}s`; const timeoutReason = `Entpacken Timeout nach ${Math.ceil(extractTimeoutMs / 1000)}s`;
logger.error(`Post-Processing Entpacken Timeout: pkg=${pkg.name}`); logger.error(`Post-Processing Entpacken Timeout: pkg=${pkg.name}`);
for (const entry of completedItems) { for (const entry of completedItems) {
entry.fullStatus = `Entpack-Fehler: ${timeoutReason}`; if (!isExtractedLabel(entry.fullStatus)) {
entry.fullStatus = `Entpack-Fehler: ${timeoutReason}`;
}
entry.updatedAt = nowMs(); entry.updatedAt = nowMs();
} }
pkg.status = "failed"; pkg.status = "failed";
@ -6713,7 +6723,9 @@ export class DownloadManager extends EventEmitter {
const reason = compactErrorText(error); const reason = compactErrorText(error);
logger.error(`Post-Processing Entpacken Exception: pkg=${pkg.name}, reason=${reason}`); logger.error(`Post-Processing Entpacken Exception: pkg=${pkg.name}, reason=${reason}`);
for (const entry of completedItems) { for (const entry of completedItems) {
entry.fullStatus = `Entpack-Fehler: ${reason}`; if (!isExtractedLabel(entry.fullStatus)) {
entry.fullStatus = `Entpack-Fehler: ${reason}`;
}
entry.updatedAt = nowMs(); entry.updatedAt = nowMs();
} }
pkg.status = "failed"; pkg.status = "failed";

View File

@ -424,9 +424,12 @@ async function writeExtractResumeState(packageDir: string, completedArchives: Se
.map((name) => archiveNameKey(name)) .map((name) => archiveNameKey(name))
.sort((a, b) => a.localeCompare(b)) .sort((a, b) => a.localeCompare(b))
}; };
const tmpPath = progressPath + ".tmp"; const tmpPath = progressPath + "." + Date.now() + "." + Math.random().toString(36).slice(2, 8) + ".tmp";
await fs.promises.writeFile(tmpPath, JSON.stringify(payload, null, 2), "utf8"); await fs.promises.writeFile(tmpPath, JSON.stringify(payload, null, 2), "utf8");
await fs.promises.rename(tmpPath, progressPath); await fs.promises.rename(tmpPath, progressPath).catch(async () => {
// rename may fail if another writer renamed tmpPath first (parallel workers)
await fs.promises.rm(tmpPath, { force: true }).catch(() => {});
});
} catch (error) { } catch (error) {
logger.warn(`ExtractResumeState schreiben fehlgeschlagen: ${String(error)}`); logger.warn(`ExtractResumeState schreiben fehlgeschlagen: ${String(error)}`);
} }
@ -896,6 +899,8 @@ function resolveJvmExtractorLayout(): JvmExtractorLayout | null {
}) || ""; }) || "";
if (!javaCommand) { if (!javaCommand) {
cachedJvmLayout = null;
cachedJvmLayoutNullSince = Date.now();
return null; return null;
} }

View File

@ -482,6 +482,7 @@ export function App(): ReactElement {
tabRef.current = tab; tabRef.current = tab;
const stateFlushTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); const stateFlushTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const toastTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); const toastTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const onImportDlcRef = useRef<() => Promise<void>>(() => Promise.resolve());
const [dragOver, setDragOver] = useState(false); const [dragOver, setDragOver] = useState(false);
const [editingPackageId, setEditingPackageId] = useState<string | null>(null); const [editingPackageId, setEditingPackageId] = useState<string | null>(null);
const [editingName, setEditingName] = useState(""); const [editingName, setEditingName] = useState("");
@ -1199,6 +1200,8 @@ export function App(): ReactElement {
}); });
}; };
onImportDlcRef.current = onImportDlc;
const onDrop = async (event: DragEvent<HTMLElement>): Promise<void> => { const onDrop = async (event: DragEvent<HTMLElement>): Promise<void> => {
event.preventDefault(); event.preventDefault();
dragDepthRef.current = 0; dragDepthRef.current = 0;
@ -1929,7 +1932,7 @@ export function App(): ReactElement {
if (inInput) return; if (inInput) return;
e.preventDefault(); e.preventDefault();
setOpenMenu(null); setOpenMenu(null);
void onImportDlc(); void onImportDlcRef.current();
return; return;
} }
if (!e.shiftKey && e.key.toLowerCase() === "a") { if (!e.shiftKey && e.key.toLowerCase() === "a") {