Compare commits
No commits in common. "4d2f11a96df8d3e6dcffd5bd7fd54a8343849e81" and "7be2d2e14839a79bff6142f759e5d6263862e778" have entirely different histories.
4d2f11a96d
...
7be2d2e148
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "1.7.141",
|
"version": "1.7.140",
|
||||||
"description": "Desktop downloader",
|
"description": "Desktop downloader",
|
||||||
"main": "build/main/main/main.js",
|
"main": "build/main/main/main.js",
|
||||||
"author": "Sucukdeluxe",
|
"author": "Sucukdeluxe",
|
||||||
|
|||||||
@ -142,30 +142,7 @@ function setDebridLinkKeyCooldownState(
|
|||||||
clearDebridLinkKeyCooldownState(keyId);
|
clearDebridLinkKeyCooldownState(keyId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Cooldown set: max-wins. When 8 parallel items hit floodDetected on the
|
debridLinkKeyCooldowns.set(keyId, Date.now() + Math.max(1000, Math.floor(cooldownMs)));
|
||||||
// same key, each computes its own retry-after and calls setDebridLinkKey
|
|
||||||
// CooldownState. Without max-wins, the LAST setter could shorten the
|
|
||||||
// cooldown (e.g. one item got a 1h Retry-After header, another got the
|
|
||||||
// default 2 min — without max-wins the 2 min would overwrite the 1h).
|
|
||||||
// Quota and rate_limit categories take priority over generic temporary
|
|
||||||
// cooldowns regardless of duration to preserve the more-specific signal.
|
|
||||||
const newUntil = Date.now() + Math.max(1000, Math.floor(cooldownMs));
|
|
||||||
const existingUntil = Number(debridLinkKeyCooldowns.get(keyId) || 0);
|
|
||||||
const existingDetail = debridLinkKeyCooldownDetails.get(keyId);
|
|
||||||
const newIsStrongCategory = category === "rate_limit" || category === "quota" || category === "invalid";
|
|
||||||
const existingIsStrongCategory = existingDetail
|
|
||||||
? (existingDetail.category === "rate_limit" || existingDetail.category === "quota" || existingDetail.category === "invalid")
|
|
||||||
: false;
|
|
||||||
// Keep existing if it's still active and either lasts longer or has a stronger category
|
|
||||||
if (existingUntil > Date.now()) {
|
|
||||||
if (existingUntil >= newUntil && (!newIsStrongCategory || existingIsStrongCategory)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (existingIsStrongCategory && !newIsStrongCategory) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debridLinkKeyCooldowns.set(keyId, newUntil);
|
|
||||||
debridLinkKeyCooldownDetails.set(keyId, { message, category });
|
debridLinkKeyCooldownDetails.set(keyId, { message, category });
|
||||||
setDebridLinkKeyRuntimeStatus(keyId, mapDebridLinkCooldownCategoryToRuntimeState(category), message);
|
setDebridLinkKeyRuntimeStatus(keyId, mapDebridLinkCooldownCategoryToRuntimeState(category), message);
|
||||||
}
|
}
|
||||||
@ -2705,32 +2682,13 @@ class DebridLinkClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isRetryableErrorText(errorText) || /debrid-link.*(json|html)/i.test(errorText)) {
|
if (isRetryableErrorText(errorText) || /debrid-link.*(json|html)/i.test(errorText)) {
|
||||||
// Distinguish a single transient transport error (timeout, network blip,
|
|
||||||
// ECONNRESET) from a real API/server problem. Single timeouts shouldn't
|
|
||||||
// park a key for 2 full minutes — that just delays parallel work for
|
|
||||||
// no reason. Use a short 15s cooldown for transport, full 2min only
|
|
||||||
// for things that look like server-side faults (5xx HTML pages, etc).
|
|
||||||
const isTransport = /timeout|network|fetch failed|aborted|econnreset|enotfound|etimedout|socket/i.test(errorText)
|
|
||||||
&& !(error instanceof DebridLinkApiError);
|
|
||||||
return {
|
return {
|
||||||
fatal: false,
|
fatal: false,
|
||||||
cooldownMs: isTransport ? 15_000 : DEBRID_LINK_KEY_COOLDOWN_MS,
|
cooldownMs: DEBRID_LINK_KEY_COOLDOWN_MS,
|
||||||
message: errorText || "temporärer Transportfehler"
|
message: errorText || "temporärer Transportfehler"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP 200 with success:false but no recognizable error code: don't kill
|
|
||||||
// the item permanently. Treat as a temporary blip — same key can be tried
|
|
||||||
// again after a short cooldown, or another key picked up.
|
|
||||||
if (errorText && /success.*false|kein.*json|empty.*response/i.test(errorText)) {
|
|
||||||
return {
|
|
||||||
fatal: false,
|
|
||||||
cooldownMs: 30_000,
|
|
||||||
message: errorText,
|
|
||||||
category: "temporary"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fatal: true,
|
fatal: true,
|
||||||
cooldownMs: 0,
|
cooldownMs: 0,
|
||||||
|
|||||||
@ -8687,21 +8687,12 @@ export class DownloadManager extends EventEmitter {
|
|||||||
active.unrestrictRetries += 1;
|
active.unrestrictRetries += 1;
|
||||||
item.retries += 1;
|
item.retries += 1;
|
||||||
const failureProvider = this.getProviderFailureKeyForItem(item);
|
const failureProvider = this.getProviderFailureKeyForItem(item);
|
||||||
// Debrid-Link manages its own per-key cooldowns in debrid.ts. The
|
this.recordProviderFailure(failureProvider);
|
||||||
// provider-wide circuit breaker would double-block all Debrid-Link
|
if (isProviderBusyUnrestrictError(errorText) || isTemporaryUnrestrictError(errorText)) {
|
||||||
// keys when only one key (or a transient transport hiccup) failed.
|
const busyCooldownMs = isTemporaryUnrestrictError(errorText)
|
||||||
// Skip recordProviderFailure / applyProviderBusyBackoff entirely
|
? Math.min(180000, 20000 + Number(active.unrestrictRetries || 0) * 10000)
|
||||||
// for any Debrid-Link-flavoured error message, not just the
|
: Math.min(60000, 12000 + Number(active.unrestrictRetries || 0) * 3000);
|
||||||
// debrid_link_cooldown sentinel that's caught above.
|
this.applyProviderBusyBackoff(failureProvider, busyCooldownMs);
|
||||||
const isDebridLinkError = /debrid-link|debrid_link/i.test(errorText) || failureProvider === "debridlink";
|
|
||||||
if (!isDebridLinkError) {
|
|
||||||
this.recordProviderFailure(failureProvider);
|
|
||||||
if (isProviderBusyUnrestrictError(errorText) || isTemporaryUnrestrictError(errorText)) {
|
|
||||||
const busyCooldownMs = isTemporaryUnrestrictError(errorText)
|
|
||||||
? Math.min(180000, 20000 + Number(active.unrestrictRetries || 0) * 10000)
|
|
||||||
: Math.min(60000, 12000 + Number(active.unrestrictRetries || 0) * 3000);
|
|
||||||
this.applyProviderBusyBackoff(failureProvider, busyCooldownMs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Escalating backoff: 5s, 7.5s, 11s, 17s, 25s, 38s, ... up to 120s
|
// Escalating backoff: 5s, 7.5s, 11s, 17s, 25s, 38s, ... up to 120s
|
||||||
let unrestrictDelayMs = Math.min(120000, Math.floor(5000 * Math.pow(1.5, active.unrestrictRetries - 1)));
|
let unrestrictDelayMs = Math.min(120000, Math.floor(5000 * Math.pow(1.5, active.unrestrictRetries - 1)));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user