Fix: Mega-Debrid "Kein Server fuer diesen Hoster" (Tageslimit) -> schnell scheitern + rotieren

User-Report: Account 1 am Tageslimit liefert "Kein Server fuer diesen Hoster verfuegbar".
Bisher lief das durch die volle Web-Retry-Maschine (generate->null -> re-Login -> 3x
REQUEST_RETRIES) und fraß ~40s des GETEILTEN 60s-Unrestrict-Budgets -> der funktionierende
naechste Account (FabelDavid) lief in den Timeout (aborted:debrid -> als fatal klassifiziert,
"abgebrochen (fataler Fehler)" im Rotations-Verlauf), obwohl er gehen wuerde.

Fix (3 Teile, gemeinsame MEGA_DEBRID_NO_SERVER_RE):
1. mega-web-fallback generate(): die "Kein Server"-Meldung wird surfacet (throw) statt
   null zurueckzugeben -> kein re-Login + erneutes Pollen.
2. unrestrictViaWeb: bricht bei der Meldung ab (kein 3x-REQUEST_RETRIES) -> sofortige
   Retries sind zwecklos (Limit bleibt) und verbrennen das geteilte Rotations-Budget.
3. classifyAccountFailure: erkennt die Meldung -> quota-Cooldown (2 min) -> naechster
   Account, mit echter Meldung im Log statt generischem "Antwort leer".

So scheitert der limitierte Account schnell (1 Versuch) und der naechste Account bekommt
das volle Budget zum Aufloesen.

Tests: mega-web-fallback (throw + ajaxCalls=1) + debrid-Rotation (acc1 Limit -> acc2,
calls=2). 645 Tests gruen, tsc 9, Build sauber.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sucukdeluxe
2026-05-31 19:23:49 +02:00
co-authored by Claude Opus 4.8
parent 1e5cd3012b
commit 9d8351c017
4 changed files with 104 additions and 2 deletions
+17 -2
View File
@@ -6,6 +6,7 @@ import { APP_VERSION, REQUEST_RETRIES } from "./constants";
import { logger } from "./logger";
import { logAccountRotation } from "./account-rotation-log";
import { RealDebridClient, UnrestrictedLink } from "./realdebrid";
import { MEGA_DEBRID_NO_SERVER_RE } from "./mega-web-fallback";
import { isMegaFileUrl, resolveMegaFilename } from "./mega-public-api";
import { compactErrorText, filenameFromUrl, looksLikeOpaqueFilename, sleep } from "./utils";
@@ -1866,8 +1867,11 @@ class MegaDebridClient {
if (!lastError) {
lastError = "Mega-Web Antwort leer";
}
// Don't retry permanent hoster errors (dead link, file removed, etc.)
if (/permanent ungültig|hosternotavailable|file.?not.?found|file.?unavailable|link.?is.?dead/i.test(lastError)) {
// Don't retry permanent hoster errors (dead link, file removed, etc.) — and
// don't hammer a "Kein Server für diesen Hoster" (account hoster quota) message:
// immediate retries are futile (the limit persists) and waste the shared
// rotation budget, so break and let the rotation move to the next account.
if (/permanent ungültig|hosternotavailable|file.?not.?found|file.?unavailable|link.?is.?dead/i.test(lastError) || MEGA_DEBRID_NO_SERVER_RE.test(lastError)) {
break;
}
if (attempt < REQUEST_RETRIES) {
@@ -2085,6 +2089,17 @@ class MegaDebridClient {
};
}
// "Kein Server für diesen Hoster verfügbar" = Account-Tageslimit für diesen
// Hoster erschöpft (oder Hoster kurz nicht bedient). Quota-Cooldown, nächster Account.
if (MEGA_DEBRID_NO_SERVER_RE.test(errorText)) {
return {
fatal: false,
cooldownMs: MEGA_DEBRID_ACCOUNT_COOLDOWN_MS,
message: "Kein Server fuer diesen Hoster (Tageslimit/Hoster nicht verfuegbar)",
category: "quota"
};
}
// Rate limit
if (/rate.?limit|too.?many|429/i.test(errorText)) {
return {
+18
View File
@@ -16,6 +16,15 @@ const DEBRID_URL = "https://www.mega-debrid.eu/index.php?form=debrid";
const DEBRID_AJAX_URL = "https://www.mega-debrid.eu/index.php?ajax=debrid&json";
const DEBRID_REFERER = "https://www.mega-debrid.eu/index.php?page=debrideur&lang=de";
/**
* Mega-Debrid-Antwort "Kein Server für diesen Hoster verfügbar". Kommt zurück, wenn
* das Tageslimit DIESES Accounts für den Hoster erschöpft ist (oder der Hoster kurz
* nicht bedient wird). KEIN Session-/Leer-Fall — der Account soll schnell scheitern,
* damit die Multi-Account-Rotation sofort zum nächsten (nicht limitierten) Account
* wechselt, statt re-Login + Retry-Sturm das geteilte Unrestrict-Budget zu fressen.
*/
export const MEGA_DEBRID_NO_SERVER_RE = /kein server f(?:ü|u)r diesen hoster|no server (?:is )?available for this host|aucun serveur disponible/i;
function normalizeLink(link: string): string {
return link.trim().toLowerCase();
}
@@ -395,6 +404,15 @@ export class MegaWebFallback {
await sleepWithSignal(1200, signal);
continue;
}
const serverMsg = (parsed.text || "").replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
// "Kein Server für diesen Hoster verfügbar" = Account-Tageslimit erschöpft.
// Surface die Meldung statt null zurückzugeben — sonst re-loggt unrestrict()
// ein + pollt erneut (Retry-Sturm), was bei einem limitierten Account zwecklos
// ist und das geteilte Rotations-Budget verbrennt. So scheitert der Account
// schnell und die Rotation nutzt den nächsten Account.
if (serverMsg && MEGA_DEBRID_NO_SERVER_RE.test(serverMsg)) {
throw new Error(`Mega-Web: ${serverMsg}`);
}
return null;
}