Release v1.6.20
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b8bbc9c32f
commit
729aa30253
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "1.6.19",
|
"version": "1.6.20",
|
||||||
"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",
|
||||||
|
|||||||
@ -4191,7 +4191,11 @@ export class DownloadManager extends EventEmitter {
|
|||||||
return;
|
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 backoffMultiplier = Math.min(this.consecutiveReconnects, 5);
|
||||||
const waitMs = this.settings.reconnectWaitSeconds * 1000 * backoffMultiplier;
|
const waitMs = this.settings.reconnectWaitSeconds * 1000 * backoffMultiplier;
|
||||||
const maxWaitMs = this.settings.reconnectWaitSeconds * 2 * 1000;
|
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)) {
|
if (responseText && responseText !== "Unbekannter Fehler" && !/(^|\b)http\s*\d{3}\b/i.test(responseText)) {
|
||||||
lastError = `HTTP ${response.status}: ${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) {
|
if (attempt < maxAttempts) {
|
||||||
item.retries += 1;
|
item.retries += 1;
|
||||||
item.fullStatus = `Serverfehler ${response.status}, retry ${attempt}/${retryDisplayLimit}`;
|
item.fullStatus = `Serverfehler ${response.status}, retry ${attempt}/${retryDisplayLimit}`;
|
||||||
@ -5048,6 +5048,10 @@ export class DownloadManager extends EventEmitter {
|
|||||||
await sleep(retryDelayWithJitter(attempt, 250));
|
await sleep(retryDelayWithJitter(attempt, 250));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (this.settings.autoReconnect && [429, 503].includes(response.status)) {
|
||||||
|
this.requestReconnect(`HTTP ${response.status}`);
|
||||||
|
throw new Error(lastError);
|
||||||
|
}
|
||||||
throw new Error(lastError);
|
throw new Error(lastError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -466,7 +466,7 @@ export function classifyExtractionError(errorText: string): ExtractErrorCategory
|
|||||||
|
|
||||||
function isExtractAbortError(errorText: string): boolean {
|
function isExtractAbortError(errorText: string): boolean {
|
||||||
const text = String(errorText || "").toLowerCase();
|
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[] {
|
export function archiveFilenamePasswords(archiveName: string): string[] {
|
||||||
@ -872,10 +872,17 @@ function resolveJvmExtractorRootCandidates(): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let cachedJvmLayout: JvmExtractorLayout | null | undefined;
|
let cachedJvmLayout: JvmExtractorLayout | null | undefined;
|
||||||
|
let cachedJvmLayoutNullSince = 0;
|
||||||
|
const JVM_LAYOUT_NULL_TTL_MS = 5 * 60 * 1000;
|
||||||
|
|
||||||
function resolveJvmExtractorLayout(): JvmExtractorLayout | null {
|
function resolveJvmExtractorLayout(): JvmExtractorLayout | null {
|
||||||
if (cachedJvmLayout !== undefined) {
|
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 javaCandidates = resolveJavaCommandCandidates();
|
||||||
const javaCommand = javaCandidates.find((candidate) => {
|
const javaCommand = javaCandidates.find((candidate) => {
|
||||||
@ -908,6 +915,7 @@ function resolveJvmExtractorLayout(): JvmExtractorLayout | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cachedJvmLayout = null;
|
cachedJvmLayout = null;
|
||||||
|
cachedJvmLayoutNullSince = Date.now();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1958,9 +1966,12 @@ export async function extractPackageArchives(options: ExtractOptions): Promise<{
|
|||||||
let noExtractorEncountered = false;
|
let noExtractorEncountered = false;
|
||||||
|
|
||||||
const extractSingleArchive = async (archivePath: string): Promise<void> => {
|
const extractSingleArchive = async (archivePath: string): Promise<void> => {
|
||||||
if (options.signal?.aborted || noExtractorEncountered) {
|
if (options.signal?.aborted) {
|
||||||
throw new Error("aborted:extract");
|
throw new Error("aborted:extract");
|
||||||
}
|
}
|
||||||
|
if (noExtractorEncountered) {
|
||||||
|
throw new Error("noextractor:skipped");
|
||||||
|
}
|
||||||
const archiveName = path.basename(archivePath);
|
const archiveName = path.basename(archivePath);
|
||||||
const archiveResumeKey = archiveNameKey(archiveName);
|
const archiveResumeKey = archiveNameKey(archiveName);
|
||||||
const archiveStartedAt = Date.now();
|
const archiveStartedAt = Date.now();
|
||||||
@ -2057,11 +2068,11 @@ export async function extractPackageArchives(options: ExtractOptions): Promise<{
|
|||||||
emitProgress(extracted + failed, archiveName, "extracting", archivePercent, Date.now() - archiveStartedAt);
|
emitProgress(extracted + failed, archiveName, "extracting", archivePercent, Date.now() - archiveStartedAt);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
failed += 1;
|
|
||||||
const errorText = String(error);
|
const errorText = String(error);
|
||||||
if (isExtractAbortError(errorText)) {
|
if (isExtractAbortError(errorText)) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
failed += 1;
|
||||||
lastError = errorText;
|
lastError = errorText;
|
||||||
const errorCategory = classifyExtractionError(errorText);
|
const errorCategory = classifyExtractionError(errorText);
|
||||||
logger.error(`Entpack-Fehler ${path.basename(archivePath)} [${errorCategory}]: ${errorText}`);
|
logger.error(`Entpack-Fehler ${path.basename(archivePath)} [${errorCategory}]: ${errorText}`);
|
||||||
|
|||||||
@ -97,6 +97,7 @@ const providerLabels: Record<DebridProvider, string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function formatDateTime(ts: number): string {
|
function formatDateTime(ts: number): string {
|
||||||
|
if (!ts) return "";
|
||||||
const d = new Date(ts);
|
const d = new Date(ts);
|
||||||
const dd = String(d.getDate()).padStart(2, "0");
|
const dd = String(d.getDate()).padStart(2, "0");
|
||||||
const mm = String(d.getMonth() + 1).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 active = collectorTabsRef.current.find((t) => t.id === activeId) ?? collectorTabsRef.current[0];
|
||||||
const rawText = active?.text ?? "";
|
const rawText = active?.text ?? "";
|
||||||
const persisted = await persistDraftSettings();
|
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 });
|
const result = await window.rd.addLinks({ rawText, packageName: persisted.packageName });
|
||||||
if (result.addedLinks > 0) {
|
if (result.addedLinks > 0) {
|
||||||
showToast(`${result.addedPackages} Paket(e), ${result.addedLinks} Link(s) hinzugefügt`);
|
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();
|
const files = await window.rd.pickContainers();
|
||||||
if (files.length === 0) { return; }
|
if (files.length === 0) { return; }
|
||||||
await persistDraftSettings();
|
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);
|
const result = await window.rd.addContainers(files);
|
||||||
if (result.addedLinks > 0) {
|
if (result.addedLinks > 0) {
|
||||||
showToast(`DLC importiert: ${result.addedPackages} Paket(e), ${result.addedLinks} Link(s)`);
|
showToast(`DLC importiert: ${result.addedPackages} Paket(e), ${result.addedLinks} Link(s)`);
|
||||||
@ -1209,7 +1210,7 @@ export function App(): ReactElement {
|
|||||||
if (dlc.length > 0) {
|
if (dlc.length > 0) {
|
||||||
await performQuickAction(async () => {
|
await performQuickAction(async () => {
|
||||||
await persistDraftSettings();
|
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);
|
const result = await window.rd.addContainers(dlc);
|
||||||
if (result.addedLinks > 0) {
|
if (result.addedLinks > 0) {
|
||||||
showToast(`Drag-and-Drop: ${result.addedPackages} Paket(e), ${result.addedLinks} Link(s)`);
|
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.speedBps !== b.speedBps
|
||||||
|| a.retries !== b.retries
|
|| a.retries !== b.retries
|
||||||
|| a.provider !== b.provider
|
|| a.provider !== b.provider
|
||||||
|| a.fullStatus !== b.fullStatus) {
|
|| a.fullStatus !== b.fullStatus
|
||||||
|
|| a.onlineStatus !== b.onlineStatus) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user