Release v1.4.30 with startup and UI race-condition fixes
Build and Release / build (push) Has been cancelled

This commit is contained in:
Sucukdeluxe
2026-02-28 22:33:19 +01:00
parent eda9754d30
commit 6ae687f3ab
10 changed files with 235 additions and 52 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ import { RealDebridClient, UnrestrictedLink } from "./realdebrid";
import { compactErrorText, filenameFromUrl, looksLikeOpaqueFilename, sleep } from "./utils";
const API_TIMEOUT_MS = 30000;
const DEBRID_USER_AGENT = "RD-Node-Downloader/1.4.29";
const DEBRID_USER_AGENT = "RD-Node-Downloader/1.4.30";
const RAPIDGATOR_SCAN_MAX_BYTES = 512 * 1024;
const BEST_DEBRID_API_BASE = "https://bestdebrid.com/api/v1";
+30 -7
View File
@@ -343,6 +343,13 @@ function isNoExtractorError(errorText: string): boolean {
return String(errorText || "").toLowerCase().includes("nicht gefunden");
}
function isUnsupportedArchiveFormatError(errorText: string): boolean {
const text = String(errorText || "").toLowerCase();
return text.includes("kein rar-archiv")
|| text.includes("not a rar archive")
|| text.includes("is not a rar archive");
}
function isUnsupportedExtractorSwitchError(errorText: string): boolean {
const text = String(errorText || "").toLowerCase();
return text.includes("unknown switch")
@@ -705,17 +712,26 @@ async function runExternalExtract(
}
function isZipSafetyGuardError(error: unknown): boolean {
const text = String(error || "").toLowerCase();
return text.includes("path traversal")
|| text.includes("zip-eintrag verdächtig groß")
|| text.includes("zip-eintrag verdaechtig gross");
}
function isZipInternalLimitError(error: unknown): boolean {
const text = String(error || "").toLowerCase();
return text.includes("zip-eintrag zu groß")
|| text.includes("zip-eintrag komprimiert zu groß")
|| text.includes("zip-eintrag ohne sichere groessenangabe")
|| text.includes("path traversal");
|| text.includes("zip-eintrag ohne sichere groessenangabe");
}
function shouldFallbackToExternalZip(error: unknown): boolean {
if (isZipSafetyGuardError(error)) {
return false;
}
if (isZipInternalLimitError(error)) {
return true;
}
const text = String(error || "").toLowerCase();
if (text.includes("aborted:extract") || text.includes("extract_aborted")) {
return false;
@@ -1190,11 +1206,18 @@ export async function extractPackageArchives(options: ExtractOptions): Promise<{
if (!shouldFallbackToExternalZip(error)) {
throw error;
}
const usedPassword = await runExternalExtract(archivePath, options.targetDir, options.conflictMode, passwordCandidates, (value) => {
archivePercent = Math.max(archivePercent, value);
emitProgress(extracted + failed, archiveName, "extracting", archivePercent, Date.now() - archiveStartedAt);
}, options.signal);
passwordCandidates = prioritizePassword(passwordCandidates, usedPassword);
try {
const usedPassword = await runExternalExtract(archivePath, options.targetDir, options.conflictMode, passwordCandidates, (value) => {
archivePercent = Math.max(archivePercent, value);
emitProgress(extracted + failed, archiveName, "extracting", archivePercent, Date.now() - archiveStartedAt);
}, options.signal);
passwordCandidates = prioritizePassword(passwordCandidates, usedPassword);
} catch (externalError) {
if (isNoExtractorError(String(externalError)) || isUnsupportedArchiveFormatError(String(externalError))) {
throw error;
}
throw externalError;
}
}
}
} else {
+2 -1
View File
@@ -34,7 +34,8 @@ function validateStringArray(value: unknown, name: string): string[] {
/* ── Single Instance Lock ───────────────────────────────────────── */
const gotLock = app.requestSingleInstanceLock();
if (!gotLock) {
app.quit();
app.exit(0);
process.exit(0);
}
/* ── Unhandled error protection ─────────────────────────────────── */
+1 -1
View File
@@ -1,7 +1,7 @@
import { API_BASE_URL, REQUEST_RETRIES } from "./constants";
import { compactErrorText, sleep } from "./utils";
const DEBRID_USER_AGENT = "RD-Node-Downloader/1.4.29";
const DEBRID_USER_AGENT = "RD-Node-Downloader/1.4.30";
export interface UnrestrictedLink {
fileName: string;
-3
View File
@@ -59,9 +59,6 @@ function normalizeBandwidthSchedules(raw: unknown): BandwidthScheduleEntry[] {
function normalizeAbsoluteDir(value: unknown, fallback: string): string {
const text = asText(value);
if (/^\/[\s\S]+/.test(text)) {
return text.replace(/\\/g, "/");
}
if (!text || !path.isAbsolute(text)) {
return path.resolve(fallback);
}