Fix: Mega-Debrid-Account sperrt sich nicht mehr dauerhaft selbst (Self-Cooldown bis Neustart)

Ein gesunder Mega-Debrid-Account konnte sich dauerhaft "bis Neustart" sperren,
ohne sich von selbst zu erholen — genau das vom Nutzer beobachtete Verhalten
("das Tool setzt sich selbst Cooldowns"). Zwei Ursachen, beide behoben:

1) Falsche Einstufung eines HOSTER-Problems als ACCOUNT-Limit:
   classifyAccountFailure hat den hoster-spezifischen Fehler "Kein Server fuer
   diesen Hoster" (MEGA_DEBRID_NO_SERVER_RE — Mega-Debrid hat fuer EINEN Hoster,
   z.B. Rapidgator, gerade keinen Server) mit limitSignal=true markiert. Dieses
   Signal speist den "bis Neustart"-Streak (3x -> Dauer-Park). Bei einer
   Warteschlange voller Links desselben (kurzzeitig nicht bedienbaren) Hosters
   kletterte der Streak hoch und parkte einen kerngesunden Account — der sich
   dann ueber die Rotation auf ALLE Accounts ausbreitete. Fix: limitSignal aus
   dem No-Server-Zweig entfernt (der 120s-Cooldown bleibt). Hoster-Verfuegbarkeit
   ist kein Account-Gesundheitssignal. Der echte Tageslimit-Pfad (leere Antwort)
   bleibt unveraendert.

2) "Bis Neustart"-Park hatte keine Ablaufzeit (until = MAX_SAFE_INTEGER) und
   konnte daher NIE von selbst aufgehen — auch nicht, nachdem Mega-Debrid wieder
   Server hatte oder das Tageslimit um Mitternacht zuruecksetzt. Nur ein Neustart
   half. Fix: Der Park laeuft jetzt zum naechsten Tagesreset (lokale Mitternacht,
   mind. 120s) ab und heilt sich damit garantiert innerhalb von <=24h selbst —
   egal welcher Zweig ihn ausgeloest hat. Texte entsprechend von "bis Neustart
   gesperrt" auf "bis zum Tagesreset gesperrt" angepasst (Main + Renderer
   konsistent).

Tests: (a) ein geparkter Account ist nach dem Tagesreset wieder frei statt
dauerhaft gesperrt (rot ohne Fix: MAX_SAFE_INTEGER laeuft nie ab); (b) ein
"no server"-Fehler liefert kein limitSignal mehr (rot ohne Fix), waehrend die
echte leere Antwort weiterhin als Limit zaehlt. 86 Debrid-Tests gruen.
This commit is contained in:
Sucukdeluxe
2026-06-17 05:47:52 +02:00
parent 68f50eaa5e
commit 76b3f99476
3 changed files with 41 additions and 19 deletions
+20 -9
View File
@@ -349,14 +349,26 @@ export function primeMegaDebridRuntimeCooldownForTests(accountId: string, cooldo
setMegaDebridAccountCooldownState(accountId, cooldownMs, message, "temporary");
}
export function primeMegaDebridUntilRestartForTests(accountId: string, message = "Tageslimit (Test) — bis Neustart gesperrt"): void {
export function primeMegaDebridUntilRestartForTests(accountId: string, message = "Tageslimit (Test) — bis zum Tagesreset gesperrt"): void {
setMegaDebridAccountCooldownState(accountId, 0, message, "quota", true);
}
export function classifyMegaDebridAccountFailureForTests(
error: unknown
): { fatal: boolean; cooldownMs: number; message: string; category: MegaDebridCooldownCategory; limitSignal?: boolean } {
return MegaDebridClient.classifyAccountFailure(error);
}
function clearMegaDebridAccountCooldownState(accountId: string): void {
megaDebridAccountCooldowns.delete(accountId);
}
function megaDebridDailyParkExpiry(now: number): number {
const midnight = new Date(now);
midnight.setHours(24, 0, 0, 0);
return Math.max(midnight.getTime(), now + MEGA_DEBRID_ACCOUNT_COOLDOWN_MS);
}
function setMegaDebridAccountCooldownState(
accountId: string,
cooldownMs: number,
@@ -366,7 +378,7 @@ function setMegaDebridAccountCooldownState(
): void {
if (untilRestart) {
megaDebridAccountCooldowns.set(accountId, {
until: Number.MAX_SAFE_INTEGER,
until: megaDebridDailyParkExpiry(Date.now()),
message,
category,
untilRestart: true
@@ -1987,7 +1999,7 @@ class MegaDebridClient {
? "Neustart"
: new Date(accountCooldownState.until).toLocaleTimeString();
const reasonText = accountCooldownState.untilRestart
? "Tageslimit erreicht — bis Neustart gesperrt"
? "Tageslimit erreicht — bis zum Tagesreset gesperrt"
: `Cooldown bis ${untilStr}`;
logger.info(`Mega-Debrid${accountLabel}: uebersprungen (${reasonText}), pruefe naechsten Account`);
logAccountRotation("INFO", providerName, rotationLabel, "SKIP_COOLDOWN", {
@@ -2086,7 +2098,7 @@ class MegaDebridClient {
const streak = recordMegaDebridEmptyResponseStreak(cooldownKey);
if (streak >= MEGA_DEBRID_EMPTY_STREAK_UNTIL_RESTART) {
parkUntilRestart = true;
parkMessage = `Tageslimit erreicht (${streak}x kein Server/leere Antwort) — bis Neustart gesperrt`;
parkMessage = `Tageslimit erreicht (${streak}x kein Server/leere Antwort) — bis zum Tagesreset gesperrt`;
}
} else {
clearMegaDebridEmptyResponseStreak(cooldownKey);
@@ -2109,7 +2121,7 @@ class MegaDebridClient {
throw new Error(`Mega-Debrid${accountLabel}: ${failure.message}`);
}
const cooldownInfo = parkUntilRestart
? ", bis Neustart gesperrt"
? ", bis zum Tagesreset gesperrt"
: failure.cooldownMs > 0
? `, Cooldown ${Math.ceil(failure.cooldownMs / 1000)}s`
: "";
@@ -2146,14 +2158,14 @@ class MegaDebridClient {
throw new Error(`mega_debrid_cooldown:${retryMs}:${cooldownFailures.join(" | ")}`);
}
if (parkedUntilRestartSeen) {
throw new Error(`Mega-Debrid: Alle Accounts am Tageslimit (bis Neustart gesperrt)${cooldownFailures.length > 0 ? ` | ${cooldownFailures.join(" | ")}` : ""}`);
throw new Error(`Mega-Debrid: Alle Accounts am Tageslimit (bis zum Tagesreset gesperrt)${cooldownFailures.length > 0 ? ` | ${cooldownFailures.join(" | ")}` : ""}`);
}
throw new Error("Mega-Debrid: Kein aktiver Account verfuegbar");
}
throw new Error(failures.join(" | ") || "Mega-Debrid: Kein aktiver Account verfuegbar");
}
private static classifyAccountFailure(
static classifyAccountFailure(
error: unknown
): { fatal: boolean; cooldownMs: number; message: string; category: MegaDebridCooldownCategory; limitSignal?: boolean } {
const errorText = compactErrorText(error).replace(/^Error:\s*/i, "");
@@ -2206,8 +2218,7 @@ class MegaDebridClient {
fatal: false,
cooldownMs: MEGA_DEBRID_ACCOUNT_COOLDOWN_MS,
message: "Kein Server fuer diesen Hoster (Tageslimit/Hoster nicht verfuegbar)",
category: "quota",
limitSignal: true
category: "quota"
};
}
+3 -3
View File
@@ -1159,13 +1159,13 @@ function formatCheckedAgo(checkedAt: number): string {
}
function rotationEventText(ev: { event: string; cooldownSec?: number; next?: string; reason?: string }): string {
const untilRestart = /bis Neustart gesperrt/i.test(ev.reason || "");
const untilRestart = /bis zum Tagesreset gesperrt/i.test(ev.reason || "");
switch (ev.event) {
case "OK": return "erfolgreich";
case "FAILED": {
if (untilRestart) {
const nx = ev.next && ev.next !== "ENDE" ? `${ev.next}` : "";
return `Tageslimit erreicht, bis Neustart gesperrt${nx}`;
return `Tageslimit erreicht, bis zum Tagesreset gesperrt${nx}`;
}
const cd = ev.cooldownSec ? `, Cooldown ${ev.cooldownSec}s` : "";
const nx = ev.next && ev.next !== "ENDE" ? `${ev.next}` : "";
@@ -1176,7 +1176,7 @@ function rotationEventText(ev: { event: string; cooldownSec?: number; next?: str
const cd = ev.cooldownSec ? `, Cooldown ${ev.cooldownSec}s` : "";
return `Timeout/Abbruch${cd} → nächster Account beim Retry`;
}
case "SKIP_COOLDOWN": return untilRestart ? "übersprungen (bis Neustart gesperrt)" : "übersprungen (Cooldown aktiv)";
case "SKIP_COOLDOWN": return untilRestart ? "übersprungen (bis zum Tagesreset gesperrt)" : "übersprungen (Cooldown aktiv)";
case "SKIP_DISABLED": return "übersprungen (deaktiviert)";
case "SKIP_DAILY_LIMIT": return "übersprungen (Tageslimit erreicht)";
case "SKIP_HOST_COOLDOWN": return "übersprungen (Host-Cooldown)";