Release v1.6.20

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sucukdeluxe 2026-03-04 18:09:13 +01:00
parent b8bbc9c32f
commit 729aa30253
4 changed files with 31 additions and 14 deletions

View File

@ -1,6 +1,6 @@
{
"name": "real-debrid-downloader",
"version": "1.6.19",
"version": "1.6.20",
"description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)",
"main": "build/main/main/main.js",
"author": "Sucukdeluxe",

View File

@ -4191,7 +4191,11 @@ export class DownloadManager extends EventEmitter {
return;
}
this.consecutiveReconnects += 1;
// Only increment when not already inside an active reconnect window to avoid
// inflating the backoff counter when multiple parallel downloads hit 429/503.
if (this.session.reconnectUntil <= nowMs()) {
this.consecutiveReconnects += 1;
}
const backoffMultiplier = Math.min(this.consecutiveReconnects, 5);
const waitMs = this.settings.reconnectWaitSeconds * 1000 * backoffMultiplier;
const maxWaitMs = this.settings.reconnectWaitSeconds * 2 * 1000;
@ -5037,10 +5041,6 @@ export class DownloadManager extends EventEmitter {
if (responseText && responseText !== "Unbekannter Fehler" && !/(^|\b)http\s*\d{3}\b/i.test(responseText)) {
lastError = `HTTP ${response.status}: ${responseText}`;
}
if (this.settings.autoReconnect && [429, 503].includes(response.status)) {
this.requestReconnect(`HTTP ${response.status}`);
throw new Error(lastError);
}
if (attempt < maxAttempts) {
item.retries += 1;
item.fullStatus = `Serverfehler ${response.status}, retry ${attempt}/${retryDisplayLimit}`;
@ -5048,6 +5048,10 @@ export class DownloadManager extends EventEmitter {
await sleep(retryDelayWithJitter(attempt, 250));
continue;
}
if (this.settings.autoReconnect && [429, 503].includes(response.status)) {
this.requestReconnect(`HTTP ${response.status}`);
throw new Error(lastError);
}
throw new Error(lastError);
}

View File

@ -466,7 +466,7 @@ export function classifyExtractionError(errorText: string): ExtractErrorCategory
function isExtractAbortError(errorText: string): boolean {
const text = String(errorText || "").toLowerCase();
return text.includes("aborted:extract") || text.includes("extract_aborted");
return text.includes("aborted:extract") || text.includes("extract_aborted") || text.includes("noextractor:skipped");
}
export function archiveFilenamePasswords(archiveName: string): string[] {
@ -872,10 +872,17 @@ function resolveJvmExtractorRootCandidates(): string[] {
}
let cachedJvmLayout: JvmExtractorLayout | null | undefined;
let cachedJvmLayoutNullSince = 0;
const JVM_LAYOUT_NULL_TTL_MS = 5 * 60 * 1000;
function resolveJvmExtractorLayout(): JvmExtractorLayout | null {
if (cachedJvmLayout !== undefined) {
return cachedJvmLayout;
// Don't cache null permanently — retry after TTL in case Java was installed
if (cachedJvmLayout === null && Date.now() - cachedJvmLayoutNullSince > JVM_LAYOUT_NULL_TTL_MS) {
cachedJvmLayout = undefined;
} else {
return cachedJvmLayout;
}
}
const javaCandidates = resolveJavaCommandCandidates();
const javaCommand = javaCandidates.find((candidate) => {
@ -908,6 +915,7 @@ function resolveJvmExtractorLayout(): JvmExtractorLayout | null {
}
cachedJvmLayout = null;
cachedJvmLayoutNullSince = Date.now();
return null;
}
@ -1958,9 +1966,12 @@ export async function extractPackageArchives(options: ExtractOptions): Promise<{
let noExtractorEncountered = false;
const extractSingleArchive = async (archivePath: string): Promise<void> => {
if (options.signal?.aborted || noExtractorEncountered) {
if (options.signal?.aborted) {
throw new Error("aborted:extract");
}
if (noExtractorEncountered) {
throw new Error("noextractor:skipped");
}
const archiveName = path.basename(archivePath);
const archiveResumeKey = archiveNameKey(archiveName);
const archiveStartedAt = Date.now();
@ -2057,11 +2068,11 @@ export async function extractPackageArchives(options: ExtractOptions): Promise<{
emitProgress(extracted + failed, archiveName, "extracting", archivePercent, Date.now() - archiveStartedAt);
}
} catch (error) {
failed += 1;
const errorText = String(error);
if (isExtractAbortError(errorText)) {
throw error;
}
failed += 1;
lastError = errorText;
const errorCategory = classifyExtractionError(errorText);
logger.error(`Entpack-Fehler ${path.basename(archivePath)} [${errorCategory}]: ${errorText}`);

View File

@ -97,6 +97,7 @@ const providerLabels: Record<DebridProvider, string> = {
};
function formatDateTime(ts: number): string {
if (!ts) return "";
const d = new Date(ts);
const dd = String(d.getDate()).padStart(2, "0");
const mm = String(d.getMonth() + 1).padStart(2, "0");
@ -1163,7 +1164,7 @@ export function App(): ReactElement {
const active = collectorTabsRef.current.find((t) => t.id === activeId) ?? collectorTabsRef.current[0];
const rawText = active?.text ?? "";
const persisted = await persistDraftSettings();
const existingIds = new Set(Object.keys(snapshot.session.packages));
const existingIds = new Set(Object.keys(snapshotRef.current.session.packages));
const result = await window.rd.addLinks({ rawText, packageName: persisted.packageName });
if (result.addedLinks > 0) {
showToast(`${result.addedPackages} Paket(e), ${result.addedLinks} Link(s) hinzugefügt`);
@ -1182,7 +1183,7 @@ export function App(): ReactElement {
const files = await window.rd.pickContainers();
if (files.length === 0) { return; }
await persistDraftSettings();
const existingIds = new Set(Object.keys(snapshot.session.packages));
const existingIds = new Set(Object.keys(snapshotRef.current.session.packages));
const result = await window.rd.addContainers(files);
if (result.addedLinks > 0) {
showToast(`DLC importiert: ${result.addedPackages} Paket(e), ${result.addedLinks} Link(s)`);
@ -1209,7 +1210,7 @@ export function App(): ReactElement {
if (dlc.length > 0) {
await performQuickAction(async () => {
await persistDraftSettings();
const existingIds = new Set(Object.keys(snapshot.session.packages));
const existingIds = new Set(Object.keys(snapshotRef.current.session.packages));
const result = await window.rd.addContainers(dlc);
if (result.addedLinks > 0) {
showToast(`Drag-and-Drop: ${result.addedPackages} Paket(e), ${result.addedLinks} Link(s)`);
@ -3408,7 +3409,8 @@ const PackageCard = memo(function PackageCard({ pkg, items, packageSpeed, isFirs
|| a.speedBps !== b.speedBps
|| a.retries !== b.retries
|| a.provider !== b.provider
|| a.fullStatus !== b.fullStatus) {
|| a.fullStatus !== b.fullStatus
|| a.onlineStatus !== b.onlineStatus) {
return false;
}
}