Fix: Selbst-Lahmlegung der Mega-Debrid-API beheben (1-Token-pro-Account + falscher 60-min-Cooldown)
Live aus conversion.log belegt: bei API-first + maxParallel hammerten viele parallele Umwandlungen DENSELBEN Account → Mega-Debrids 1-Token-pro-Account- Regel → "Token error, please log-in" (Token gegenseitig invalidiert). Ein einzelner generischer Null-getLink wurde dann als "Login oder Unrestrict fehlgeschlagen" geworfen → classifyAccountFailure matchte das Wort "Login" → category=invalid → 60-MINUTEN-Cooldown auf einen NACHWEISLICH funktionierenden Account (39x OK davor, klappt auch auf der Webseite). Folge: alle Accounts cooled, alle Slots haengen an Fehl-Umwandlungen (conv12/dl0), nichts laedt. Fix A (download-manager): getSerializedValidatingLimit gilt jetzt auch fuer megadebrid-api (nicht nur -web) = Anzahl nutzbarer Accounts ohne :api-Cooldown. Damit laeuft hoechstens EINE API-Umwandlung pro Account gleichzeitig (Rotation verteilt 1/Account) — respektiert die 1-Token-Regel, verhindert die Token- Kollision und gibt Download-Slots frei. Fix B (debrid): (1) generische Wurf-Meldung "Login oder Unrestrict fehlgeschlagen" -> "Linkgenerierung lieferte kein Ergebnis" (kein "Login"- Trigger mehr). (2) classifyAccountFailure: "token error"/"please log-in" -> kurzer temporary-Cooldown (15s); invalid-Branch nur noch bei ECHTEN Credential-Fehlern (bad login/incorrect password/invalid credentials/ unauthorized/forbidden/connectUser) statt losem login|auth. Ein transienter Fehler sperrt einen guten Account nicht mehr 60 min, sondern hoechstens Sekunden. Tests: API-Serialisierung 2-Acct->2-parallel + 1-Acct->1-at-a-time; kein 60-min-invalid bei Null-Ergebnis; token-error<60s. 844/844 gruen, tsc=6.
This commit is contained in:
@@ -1339,6 +1339,84 @@ describe("debrid service", () => {
|
||||
expect(getMegaDebridAccountCooldownState(`${getMegaDebridAccountId("user")}:api`)).toBeNull();
|
||||
});
|
||||
|
||||
it("does NOT slap a 60-minute 'invalid' cooldown on a working account when the API returns no result (transient)", async () => {
|
||||
const settings = {
|
||||
...defaultSettings(),
|
||||
token: "",
|
||||
bestToken: "",
|
||||
allDebridToken: "",
|
||||
megaLogin: "user",
|
||||
megaPassword: "pass",
|
||||
megaCredentials: "user:pass",
|
||||
megaDebridApiEnabled: true,
|
||||
megaDebridWebEnabled: false,
|
||||
providerPrimary: "megadebrid-api" as const,
|
||||
providerSecondary: "none" as const,
|
||||
providerTertiary: "none" as const,
|
||||
autoProviderFallback: true
|
||||
};
|
||||
|
||||
globalThis.fetch = (async (input: RequestInfo | URL): Promise<Response> => {
|
||||
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
||||
if (url.includes("action=connectUser")) {
|
||||
return new Response(JSON.stringify({ response_code: "ok", token: "tok", vip_end: Math.floor(Date.now() / 1000) + 999999 }), { status: 200, headers: { "Content-Type": "application/json" } });
|
||||
}
|
||||
if (url.includes("action=getLink")) {
|
||||
return new Response(JSON.stringify({ response_code: "ok" }), { status: 200, headers: { "Content-Type": "application/json" } });
|
||||
}
|
||||
return new Response("not-found", { status: 404 });
|
||||
}) as typeof fetch;
|
||||
|
||||
const service = new DebridService(settings);
|
||||
const err = await service.unrestrictLink("https://rapidgator.net/file/no-result.rar.html").then(() => null, (e: unknown) => e);
|
||||
expect(err).toBeTruthy();
|
||||
expect(String(err)).not.toMatch(/Login oder Unrestrict/i);
|
||||
|
||||
const cooldown = getMegaDebridAccountCooldownState(`${getMegaDebridAccountId("user")}:api`);
|
||||
if (cooldown) {
|
||||
expect(cooldown.category).not.toBe("invalid");
|
||||
expect(cooldown.remainingMs).toBeLessThan(5 * 60 * 1000);
|
||||
}
|
||||
});
|
||||
|
||||
it("treats a Mega-Debrid API 'Token error, please log-in' as a short transient cooldown, not invalid", async () => {
|
||||
const settings = {
|
||||
...defaultSettings(),
|
||||
token: "",
|
||||
bestToken: "",
|
||||
allDebridToken: "",
|
||||
megaLogin: "user",
|
||||
megaPassword: "pass",
|
||||
megaCredentials: "user:pass",
|
||||
megaDebridApiEnabled: true,
|
||||
megaDebridWebEnabled: false,
|
||||
providerPrimary: "megadebrid-api" as const,
|
||||
providerSecondary: "none" as const,
|
||||
providerTertiary: "none" as const,
|
||||
autoProviderFallback: true
|
||||
};
|
||||
|
||||
globalThis.fetch = (async (input: RequestInfo | URL): Promise<Response> => {
|
||||
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
||||
if (url.includes("action=connectUser")) {
|
||||
return new Response(JSON.stringify({ response_code: "ok", token: "tok", vip_end: Math.floor(Date.now() / 1000) + 999999 }), { status: 200, headers: { "Content-Type": "application/json" } });
|
||||
}
|
||||
if (url.includes("action=getLink")) {
|
||||
return new Response(JSON.stringify({ response_code: "error_token", response_text: "Token error, please log-in" }), { status: 200, headers: { "Content-Type": "application/json" } });
|
||||
}
|
||||
return new Response("not-found", { status: 404 });
|
||||
}) as typeof fetch;
|
||||
|
||||
const service = new DebridService(settings);
|
||||
await service.unrestrictLink("https://rapidgator.net/file/token-collision.rar.html").then(() => null, (e: unknown) => e);
|
||||
|
||||
const cooldown = getMegaDebridAccountCooldownState(`${getMegaDebridAccountId("user")}:api`);
|
||||
if (cooldown) {
|
||||
expect(cooldown.category).not.toBe("invalid");
|
||||
expect(cooldown.remainingMs).toBeLessThan(60 * 1000);
|
||||
}
|
||||
});
|
||||
|
||||
it("uses Mega Web only when it is configured as a separate fallback provider", async () => {
|
||||
const settings = {
|
||||
...defaultSettings(),
|
||||
|
||||
Reference in New Issue
Block a user