Release v1.6.8
- Fix "Fertig" status on completed items: session recovery no longer resets "Entpacken - Ausstehend" to "Fertig (size)" — respects autoExtract setting - Extraction continues during pause instead of being aborted - Hybrid extraction recovery on start/resume: triggerPendingExtractions and recoverPostProcessingOnStartup now handle partial packages with hybridExtract - Move Up/Down buttons: optimistic UI update so packages move instantly Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8d0c110415
commit
97c5bfaa7d
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "real-debrid-downloader",
|
||||
"version": "1.6.7",
|
||||
"version": "1.6.8",
|
||||
"description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)",
|
||||
"main": "build/main/main/main.js",
|
||||
"author": "Sucukdeluxe",
|
||||
|
||||
@ -3042,9 +3042,9 @@ export class DownloadManager extends EventEmitter {
|
||||
const wasPaused = this.session.paused;
|
||||
this.session.paused = !this.session.paused;
|
||||
|
||||
// When pausing: abort active extractions so they don't continue during pause
|
||||
if (!wasPaused && this.session.paused) {
|
||||
this.abortPostProcessing("pause");
|
||||
// Do NOT abort extraction on pause — extraction works on already-downloaded
|
||||
// files and should continue while downloads are paused.
|
||||
this.speedEvents = [];
|
||||
this.speedBytesLastWindow = 0;
|
||||
this.speedBytesPerPackage.clear();
|
||||
@ -3129,8 +3129,13 @@ export class DownloadManager extends EventEmitter {
|
||||
}
|
||||
if (item.status === "completed") {
|
||||
const statusText = (item.fullStatus || "").trim();
|
||||
if (statusText && !isExtractedLabel(statusText) && !/^Fertig\b/i.test(statusText)) {
|
||||
item.fullStatus = `Fertig (${humanSize(item.downloadedBytes)})`;
|
||||
// Preserve extraction-related statuses (Ausstehend, Warten auf Parts, etc.)
|
||||
if (/^Entpacken\b/i.test(statusText) || isExtractedLabel(statusText) || /^Fertig\b/i.test(statusText)) {
|
||||
// keep as-is
|
||||
} else if (statusText) {
|
||||
item.fullStatus = this.settings.autoExtract
|
||||
? "Entpacken - Ausstehend"
|
||||
: `Fertig (${humanSize(item.downloadedBytes)})`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3601,7 +3606,27 @@ export class DownloadManager extends EventEmitter {
|
||||
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) {
|
||||
const allDone = success + failed + cancelled >= items.length;
|
||||
|
||||
// Hybrid extraction recovery: not all items done, but some completed
|
||||
// with pending extraction status → re-label and trigger post-processing
|
||||
// so extraction picks up where it left off.
|
||||
if (!allDone && this.settings.autoExtract && this.settings.hybridExtract && success > 0 && failed === 0) {
|
||||
const needsExtraction = items.some((item) => item.status === "completed" && !isExtractedLabel(item.fullStatus));
|
||||
if (needsExtraction) {
|
||||
for (const item of items) {
|
||||
if (item.status === "completed" && !isExtractedLabel(item.fullStatus)) {
|
||||
item.fullStatus = "Entpacken - Ausstehend";
|
||||
item.updatedAt = nowMs();
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
// Don't trigger extraction here — it will be triggered when the
|
||||
// session starts via triggerPendingExtractions or item completions.
|
||||
}
|
||||
}
|
||||
|
||||
if (!allDone) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3663,15 +3688,14 @@ export class DownloadManager extends EventEmitter {
|
||||
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 || cancelled > 0 || success === 0) {
|
||||
continue;
|
||||
}
|
||||
const allDone = success + failed + cancelled >= items.length;
|
||||
|
||||
// Full extraction: all items done, no failures
|
||||
if (allDone && failed === 0 && cancelled === 0 && success > 0) {
|
||||
const needsExtraction = items.some((item) =>
|
||||
item.status === "completed" && !isExtractedLabel(item.fullStatus)
|
||||
);
|
||||
if (!needsExtraction) {
|
||||
continue;
|
||||
}
|
||||
if (needsExtraction) {
|
||||
pkg.status = "queued";
|
||||
pkg.updatedAt = nowMs();
|
||||
for (const item of items) {
|
||||
@ -3683,6 +3707,26 @@ export class DownloadManager extends EventEmitter {
|
||||
logger.info(`Entpacken via Start ausgelöst: pkg=${pkg.name}`);
|
||||
void this.runPackagePostProcessing(packageId).catch((err) => logger.warn(`runPackagePostProcessing Fehler (triggerPending): ${compactErrorText(err)}`));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hybrid extraction: not all items done, but some completed and no failures
|
||||
if (!allDone && this.settings.hybridExtract && success > 0 && failed === 0) {
|
||||
const needsExtraction = items.some((item) =>
|
||||
item.status === "completed" && !isExtractedLabel(item.fullStatus)
|
||||
);
|
||||
if (needsExtraction) {
|
||||
for (const item of items) {
|
||||
if (item.status === "completed" && !isExtractedLabel(item.fullStatus)) {
|
||||
item.fullStatus = "Entpacken - Ausstehend";
|
||||
item.updatedAt = nowMs();
|
||||
}
|
||||
}
|
||||
logger.info(`Hybrid-Entpacken via Start ausgelöst: pkg=${pkg.name}, completed=${success}/${items.length}`);
|
||||
void this.runPackagePostProcessing(packageId).catch((err) => logger.warn(`runPackagePostProcessing Fehler (triggerPendingHybrid): ${compactErrorText(err)}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public retryExtraction(packageId: string): void {
|
||||
|
||||
@ -1498,10 +1498,21 @@ export function App(): ReactElement {
|
||||
pendingPackageOrderRef.current = [...order];
|
||||
pendingPackageOrderAtRef.current = Date.now();
|
||||
packageOrderRef.current = [...order];
|
||||
// Optimistic UI update — apply the new order immediately so the user
|
||||
// sees the change without waiting for the backend round-trip.
|
||||
setSnapshot((prev) => {
|
||||
if (!prev) return prev;
|
||||
return { ...prev, session: { ...prev.session, packageOrder: [...order] } };
|
||||
});
|
||||
void window.rd.reorderPackages(order).catch((error) => {
|
||||
pendingPackageOrderRef.current = null;
|
||||
pendingPackageOrderAtRef.current = 0;
|
||||
packageOrderRef.current = serverPackageOrderRef.current;
|
||||
// Rollback: restore original order from server
|
||||
setSnapshot((prev) => {
|
||||
if (!prev) return prev;
|
||||
return { ...prev, session: { ...prev.session, packageOrder: serverPackageOrderRef.current } };
|
||||
});
|
||||
showToast(`Sortierung fehlgeschlagen: ${String(error)}`, 2400);
|
||||
});
|
||||
}, [selectedIds, snapshot.session.packages, showToast]);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user