Harden Mega web flow and smooth download runtime
Build and Release / build (push) Has been cancelled

This commit is contained in:
Sucukdeluxe
2026-02-27 06:17:15 +01:00
parent 40bfda2ad7
commit 583d74fcc9
9 changed files with 198 additions and 61 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ import os from "node:os";
import { AppSettings } from "../shared/types";
export const APP_NAME = "Debrid Download Manager";
export const APP_VERSION = "1.1.21";
export const APP_VERSION = "1.1.22";
export const API_BASE_URL = "https://api.real-debrid.com/rest/1.0";
export const DCRYPT_UPLOAD_URL = "https://dcrypt.it/decrypt/upload";
+28 -3
View File
@@ -755,6 +755,19 @@ export class DownloadManager extends EventEmitter {
let windowBytes = 0;
let windowStarted = nowMs();
const waitDrain = (): Promise<void> => new Promise((resolve, reject) => {
const onDrain = (): void => {
stream.off("error", onError);
resolve();
};
const onError = (error: Error): void => {
stream.off("drain", onDrain);
reject(error);
};
stream.once("drain", onDrain);
stream.once("error", onError);
});
try {
const body = response.body;
if (!body) {
@@ -784,7 +797,9 @@ export class DownloadManager extends EventEmitter {
const buffer = Buffer.from(chunk);
await this.applySpeedLimit(buffer.length, windowBytes, windowStarted);
stream.write(buffer);
if (!stream.write(buffer)) {
await waitDrain();
}
written += buffer.length;
windowBytes += buffer.length;
this.session.totalDownloadedBytes += buffer.length;
@@ -806,8 +821,18 @@ export class DownloadManager extends EventEmitter {
this.emitState();
}
} finally {
await new Promise<void>((resolve) => {
stream.end(() => resolve());
await new Promise<void>((resolve, reject) => {
const onFinish = (): void => {
stream.off("error", onError);
resolve();
};
const onError = (error: Error): void => {
stream.off("finish", onFinish);
reject(error);
};
stream.once("finish", onFinish);
stream.once("error", onError);
stream.end();
});
}
+3 -2
View File
@@ -83,8 +83,9 @@ async function hashFile(filePath: string, algorithm: "crc32" | "md5" | "sha1"):
const stream = fs.createReadStream(filePath, { highWaterMark: 1024 * 1024 });
return await new Promise<string>((resolve, reject) => {
let crc = 0;
stream.on("data", (chunk: Buffer) => {
crc = crc32Buffer(chunk, crc);
stream.on("data", (chunk: string | Buffer) => {
const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
crc = crc32Buffer(buffer, crc);
});
stream.on("error", reject);
stream.on("end", () => resolve(((crc >>> 0).toString(16)).padStart(8, "0").toLowerCase()));
+32 -3
View File
@@ -20,9 +20,23 @@ function normalizeLink(link: string): string {
return link.trim().toLowerCase();
}
function parseSetCookie(raw: string): string {
function parseSetCookieFromHeaders(headers: Headers): string {
const getSetCookie = (headers as unknown as { getSetCookie?: () => string[] }).getSetCookie;
if (typeof getSetCookie === "function") {
const values = getSetCookie.call(headers)
.map((entry) => entry.split(";")[0].trim())
.filter(Boolean);
if (values.length > 0) {
return values.join("; ");
}
}
const raw = headers.get("set-cookie") || "";
if (!raw) {
return "";
}
return raw
.split(",")
.split(/,(?=[^;=]+?=)/g)
.map((chunk) => chunk.split(";")[0].trim())
.filter(Boolean)
.join("; ");
@@ -144,10 +158,25 @@ export class MegaWebFallback {
redirect: "manual"
});
const cookie = parseSetCookie(response.headers.get("set-cookie") || "");
const cookie = parseSetCookieFromHeaders(response.headers);
if (!cookie) {
throw new Error("Mega-Web Login liefert kein Session-Cookie");
}
const verify = await fetch(DEBRID_REFERER, {
method: "GET",
headers: {
"User-Agent": "Mozilla/5.0",
Cookie: cookie,
Referer: DEBRID_REFERER
}
});
const verifyHtml = await verify.text();
const hasDebridForm = /id=["']debridForm["']/i.test(verifyHtml) || /name=["']links["']/i.test(verifyHtml);
if (!hasDebridForm) {
throw new Error("Mega-Web Login ungültig oder Session blockiert");
}
this.cookie = cookie;
this.cookieSetAt = Date.now();
}