Switch Mega web fallback to real debrideur form flow and bump to 1.1.20
Some checks are pending
Build and Release / build (push) Waiting to run
Some checks are pending
Build and Release / build (push) Waiting to run
This commit is contained in:
parent
0e898733d6
commit
b1b8ed4180
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "real-debrid-downloader",
|
||||
"version": "1.1.19",
|
||||
"version": "1.1.20",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "real-debrid-downloader",
|
||||
"version": "1.1.19",
|
||||
"version": "1.1.20",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"adm-zip": "^0.5.16",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "real-debrid-downloader",
|
||||
"version": "1.1.19",
|
||||
"version": "1.1.20",
|
||||
"description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)",
|
||||
"main": "build/main/main/main.js",
|
||||
"author": "Sucukdeluxe",
|
||||
|
||||
139
scripts/mega_web_generate_download_test.mjs
Normal file
139
scripts/mega_web_generate_download_test.mjs
Normal file
@ -0,0 +1,139 @@
|
||||
const LOGIN = process.env.MEGA_LOGIN || "";
|
||||
const PASSWORD = process.env.MEGA_PASSWORD || "";
|
||||
|
||||
const LINKS = [
|
||||
"https://rapidgator.net/file/90b5397dfc3e1a0e561db7d6b89d5604/scnb-rrw7-S08E01.part1.rar.html",
|
||||
"https://rapidgator.net/file/8ddf856dc833310c5cae9db82caf9682/scnb-rrw7-S08E01.part2.rar.html",
|
||||
"https://rapidgator.net/file/440eed67d266476866332ae224c3fad5/scnb-rrw7-S08E01.part3.rar.html"
|
||||
];
|
||||
|
||||
if (!LOGIN || !PASSWORD) {
|
||||
throw new Error("Set MEGA_LOGIN and MEGA_PASSWORD env vars");
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function cookieFrom(headers) {
|
||||
const raw = headers.get("set-cookie") || "";
|
||||
return raw.split(",").map((x) => x.split(";")[0].trim()).filter(Boolean).join("; ");
|
||||
}
|
||||
|
||||
function parseDebridCodes(html) {
|
||||
const re = /processDebrid\((\d+),'([^']+)',0\)/g;
|
||||
const out = [];
|
||||
let m;
|
||||
while ((m = re.exec(html)) !== null) {
|
||||
out.push({ id: Number(m[1]), code: m[2] });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
async function resolveCode(cookie, code) {
|
||||
for (let attempt = 1; attempt <= 50; attempt += 1) {
|
||||
const res = await fetch("https://www.mega-debrid.eu/index.php?ajax=debrid&json", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "Mozilla/5.0",
|
||||
Cookie: cookie,
|
||||
Referer: "https://www.mega-debrid.eu/index.php?page=debrideur&lang=de"
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
code,
|
||||
autodl: "0"
|
||||
})
|
||||
});
|
||||
const text = (await res.text()).trim();
|
||||
if (text === "reload") {
|
||||
await sleep(800);
|
||||
continue;
|
||||
}
|
||||
if (text === "false") {
|
||||
return { ok: false, reason: "false" };
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(text);
|
||||
if (parsed?.link) {
|
||||
return { ok: true, link: String(parsed.link), text: String(parsed.text || "") };
|
||||
}
|
||||
return { ok: false, reason: text };
|
||||
} catch {
|
||||
return { ok: false, reason: text };
|
||||
}
|
||||
}
|
||||
return { ok: false, reason: "timeout" };
|
||||
}
|
||||
|
||||
async function probeDownload(url) {
|
||||
const res = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Range: "bytes=0-4095",
|
||||
"User-Agent": "Mozilla/5.0"
|
||||
},
|
||||
redirect: "manual"
|
||||
});
|
||||
return {
|
||||
status: res.status,
|
||||
location: res.headers.get("location") || "",
|
||||
contentType: res.headers.get("content-type") || "",
|
||||
contentLength: res.headers.get("content-length") || ""
|
||||
};
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const loginRes = await fetch("https://www.mega-debrid.eu/index.php?form=login", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "Mozilla/5.0"
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
login: LOGIN,
|
||||
password: PASSWORD,
|
||||
remember: "on"
|
||||
}),
|
||||
redirect: "manual"
|
||||
});
|
||||
|
||||
const cookie = cookieFrom(loginRes.headers);
|
||||
console.log("login", loginRes.status, loginRes.headers.get("location") || "");
|
||||
|
||||
const debridRes = await fetch("https://www.mega-debrid.eu/index.php?form=debrid", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "Mozilla/5.0",
|
||||
Cookie: cookie,
|
||||
Referer: "https://www.mega-debrid.eu/index.php?page=debrideur&lang=de"
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
links: LINKS.join("\n"),
|
||||
password: "",
|
||||
showLinks: "1"
|
||||
})
|
||||
});
|
||||
|
||||
const html = await debridRes.text();
|
||||
const codes = parseDebridCodes(html);
|
||||
console.log("codes", codes.length);
|
||||
if (codes.length === 0) {
|
||||
throw new Error("No processDebrid codes found");
|
||||
}
|
||||
|
||||
for (let i = 0; i < Math.min(3, codes.length); i += 1) {
|
||||
const c = codes[i];
|
||||
const resolved = await resolveCode(cookie, c.code);
|
||||
if (!resolved.ok) {
|
||||
console.log(`[FAIL] code ${c.code}: ${resolved.reason}`);
|
||||
continue;
|
||||
}
|
||||
console.log(`[OK] code ${c.code} -> ${resolved.link}`);
|
||||
const probe = await probeDownload(resolved.link);
|
||||
console.log(` probe status=${probe.status} type=${probe.contentType} len=${probe.contentLength} loc=${probe.location}`);
|
||||
}
|
||||
}
|
||||
|
||||
await main();
|
||||
@ -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.19";
|
||||
export const APP_VERSION = "1.1.20";
|
||||
export const API_BASE_URL = "https://api.real-debrid.com/rest/1.0";
|
||||
|
||||
export const DCRYPT_UPLOAD_URL = "https://dcrypt.it/decrypt/upload";
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { BrowserWindow } from "electron";
|
||||
import { UnrestrictedLink } from "./realdebrid";
|
||||
import { compactErrorText, filenameFromUrl, sleep } from "./utils";
|
||||
|
||||
@ -7,18 +6,83 @@ type MegaCredentials = {
|
||||
password: string;
|
||||
};
|
||||
|
||||
type MegaWebResult = {
|
||||
directUrl: string;
|
||||
fileName: string;
|
||||
type CodeEntry = {
|
||||
code: string;
|
||||
linkHint: string;
|
||||
};
|
||||
|
||||
export class MegaWebFallback {
|
||||
private browser: BrowserWindow | null = null;
|
||||
const LOGIN_URL = "https://www.mega-debrid.eu/index.php?form=login";
|
||||
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";
|
||||
|
||||
function normalizeLink(link: string): string {
|
||||
return link.trim().toLowerCase();
|
||||
}
|
||||
|
||||
function parseSetCookie(raw: string): string {
|
||||
return raw
|
||||
.split(",")
|
||||
.map((chunk) => chunk.split(";")[0].trim())
|
||||
.filter(Boolean)
|
||||
.join("; ");
|
||||
}
|
||||
|
||||
function parseCodes(html: string): CodeEntry[] {
|
||||
const entries: CodeEntry[] = [];
|
||||
const cardRegex = /<div[^>]*class=['"][^'"]*acp-box[^'"]*['"][^>]*>[\s\S]*?<\/div>/gi;
|
||||
let cardMatch: RegExpExecArray | null;
|
||||
while ((cardMatch = cardRegex.exec(html)) !== null) {
|
||||
const block = cardMatch[0];
|
||||
const linkTitle = (block.match(/<h3>\s*Link:\s*([^<]+)<\/h3>/i)?.[1] || "").trim();
|
||||
const code = block.match(/processDebrid\(\d+,'([^']+)',0\)/i)?.[1] || "";
|
||||
if (!code) {
|
||||
continue;
|
||||
}
|
||||
entries.push({ code, linkHint: normalizeLink(linkTitle) });
|
||||
}
|
||||
|
||||
if (entries.length === 0) {
|
||||
const fallbackRegex = /processDebrid\(\d+,'([^']+)',0\)/gi;
|
||||
let m: RegExpExecArray | null;
|
||||
while ((m = fallbackRegex.exec(html)) !== null) {
|
||||
entries.push({ code: m[1], linkHint: "" });
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
function pickCode(entries: CodeEntry[], link: string): string {
|
||||
if (entries.length === 0) {
|
||||
return "";
|
||||
}
|
||||
const target = normalizeLink(link);
|
||||
const match = entries.find((entry) => entry.linkHint && entry.linkHint.includes(target));
|
||||
return (match?.code || entries[0].code || "").trim();
|
||||
}
|
||||
|
||||
function parseDebridJson(text: string): { link: string; text: string } | null {
|
||||
try {
|
||||
const parsed = JSON.parse(text) as { link?: string; text?: string };
|
||||
return {
|
||||
link: String(parsed.link || ""),
|
||||
text: String(parsed.text || "")
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export class MegaWebFallback {
|
||||
private queue: Promise<unknown> = Promise.resolve();
|
||||
|
||||
private getCredentials: () => MegaCredentials;
|
||||
|
||||
private cookie = "";
|
||||
|
||||
private cookieSetAt = 0;
|
||||
|
||||
public constructor(getCredentials: () => MegaCredentials) {
|
||||
this.getCredentials = getCredentials;
|
||||
}
|
||||
@ -30,20 +94,29 @@ export class MegaWebFallback {
|
||||
return null;
|
||||
}
|
||||
|
||||
const browser = await this.ensureBrowser();
|
||||
const authOk = await this.login(browser, creds.login, creds.password);
|
||||
if (!authOk) {
|
||||
throw new Error("Mega-Web-Login fehlgeschlagen");
|
||||
if (!this.cookie || Date.now() - this.cookieSetAt > 20 * 60 * 1000) {
|
||||
await this.login(creds.login, creds.password);
|
||||
}
|
||||
|
||||
const data = await this.generateLink(browser, link);
|
||||
if (!data?.directUrl) {
|
||||
throw new Error("Mega-Web konnte keinen Downloadlink erzeugen");
|
||||
const generated = await this.generate(link);
|
||||
if (!generated) {
|
||||
this.cookie = "";
|
||||
await this.login(creds.login, creds.password);
|
||||
const retry = await this.generate(link);
|
||||
if (!retry) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
directUrl: retry.directUrl,
|
||||
fileName: retry.fileName || filenameFromUrl(link),
|
||||
fileSize: null,
|
||||
retriesUsed: 0
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
directUrl: data.directUrl,
|
||||
fileName: data.fileName || filenameFromUrl(link),
|
||||
directUrl: generated.directUrl,
|
||||
fileName: generated.fileName || filenameFromUrl(link),
|
||||
fileSize: null,
|
||||
retriesUsed: 0
|
||||
};
|
||||
@ -56,112 +129,106 @@ export class MegaWebFallback {
|
||||
return run;
|
||||
}
|
||||
|
||||
private async ensureBrowser(): Promise<BrowserWindow> {
|
||||
if (this.browser && !this.browser.isDestroyed()) {
|
||||
return this.browser;
|
||||
}
|
||||
this.browser = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
sandbox: true,
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
partition: "persist:mega-web"
|
||||
}
|
||||
private async login(login: string, password: string): Promise<void> {
|
||||
const response = await fetch(LOGIN_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "Mozilla/5.0"
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
login,
|
||||
password,
|
||||
remember: "on"
|
||||
}),
|
||||
redirect: "manual"
|
||||
});
|
||||
return this.browser;
|
||||
|
||||
const cookie = parseSetCookie(response.headers.get("set-cookie") || "");
|
||||
if (!cookie) {
|
||||
throw new Error("Mega-Web Login liefert kein Session-Cookie");
|
||||
}
|
||||
this.cookie = cookie;
|
||||
this.cookieSetAt = Date.now();
|
||||
}
|
||||
|
||||
private async login(browser: BrowserWindow, login: string, password: string): Promise<boolean> {
|
||||
await browser.loadURL("https://www.mega-debrid.eu/index.php?page=login&lang=en");
|
||||
await sleep(600);
|
||||
const result = await browser.webContents.executeJavaScript(`(async () => {
|
||||
const hasLogout = Boolean(document.querySelector('a[href*="logout"], a[href*="debrideur"], a[href*="debrid"]'));
|
||||
if (hasLogout) return { ok: true };
|
||||
const form = document.querySelector('#formulaire_login') || document.querySelector('form[action*="form=login"]') || document.querySelector('form');
|
||||
if (!form) return { ok: false, reason: 'Login-Form nicht gefunden' };
|
||||
const loginInput = form.querySelector('input[name="login"], #user_login');
|
||||
const passInput = form.querySelector('input[name="password"], #user_password');
|
||||
if (!loginInput || !passInput) return { ok: false, reason: 'Login-Felder fehlen' };
|
||||
loginInput.value = ${JSON.stringify(login)};
|
||||
passInput.value = ${JSON.stringify(password)};
|
||||
const submit = form.querySelector('button[type="submit"], input[type="submit"], #user_submit');
|
||||
if (submit) { submit.click(); } else { form.submit(); }
|
||||
return { ok: true };
|
||||
})();`, true);
|
||||
if (!result?.ok) {
|
||||
return false;
|
||||
private async generate(link: string): Promise<{ directUrl: string; fileName: string } | null> {
|
||||
const page = await fetch(DEBRID_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "Mozilla/5.0",
|
||||
Cookie: this.cookie,
|
||||
Referer: DEBRID_REFERER
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
links: link,
|
||||
password: "",
|
||||
showLinks: "1"
|
||||
})
|
||||
});
|
||||
|
||||
const html = await page.text();
|
||||
const code = pickCode(parseCodes(html), link);
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (let i = 0; i < 30; i += 1) {
|
||||
await sleep(350);
|
||||
const url = browser.webContents.getURL();
|
||||
if (url.includes("page=debrideur") || url.includes("page=debrid")) {
|
||||
return true;
|
||||
}
|
||||
const logged = await browser.webContents.executeJavaScript(
|
||||
"Boolean(document.querySelector('a[href*=\"debrideur\"], a[href*=\"debrid\"], a[href*=\"logout\"]'))",
|
||||
true
|
||||
).catch(() => false);
|
||||
if (logged) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async generateLink(browser: BrowserWindow, link: string): Promise<MegaWebResult | null> {
|
||||
await browser.loadURL("https://www.mega-debrid.eu/index.php?page=debrideur&lang=de");
|
||||
await sleep(800);
|
||||
|
||||
const start = await browser.webContents.executeJavaScript(`(async () => {
|
||||
const textarea = document.querySelector('textarea');
|
||||
if (!textarea) return { ok: false, reason: 'Textarea fehlt' };
|
||||
textarea.value = ${JSON.stringify(link)};
|
||||
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
const controls = Array.from(document.querySelectorAll('button, input[type="submit"], a.btn'));
|
||||
const trigger = controls.find((el) => {
|
||||
const text = (el.textContent || el.value || '').toLowerCase();
|
||||
return text.includes('erzeugen') || text.includes('generate') || text.includes('générer') || text.includes('downloadlink');
|
||||
for (let attempt = 1; attempt <= 60; attempt += 1) {
|
||||
const res = await fetch(DEBRID_AJAX_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": "Mozilla/5.0",
|
||||
Cookie: this.cookie,
|
||||
Referer: DEBRID_REFERER
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
code,
|
||||
autodl: "0"
|
||||
})
|
||||
});
|
||||
if (!trigger) return { ok: false, reason: 'Generate-Button fehlt' };
|
||||
trigger.click();
|
||||
return { ok: true };
|
||||
})();`, true);
|
||||
|
||||
if (!start?.ok) {
|
||||
throw new Error(start?.reason || "Mega-Web konnte Request nicht starten");
|
||||
}
|
||||
const text = (await res.text()).trim();
|
||||
if (text === "reload") {
|
||||
await sleep(650);
|
||||
continue;
|
||||
}
|
||||
if (text === "false") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const linkHash = link.toLowerCase();
|
||||
for (let i = 0; i < 80; i += 1) {
|
||||
await sleep(500);
|
||||
const result = await browser.webContents.executeJavaScript(`(() => {
|
||||
const cards = Array.from(document.querySelectorAll('.acp-box.card, .acp-box, .card'));
|
||||
for (const card of cards) {
|
||||
const title = (card.querySelector('.title')?.textContent || '').trim();
|
||||
const href = card.querySelector('a[href*="unrestrict.link/download/file/"]')?.getAttribute('href') || '';
|
||||
const fileName = (card.querySelector('.filename')?.textContent || '').trim();
|
||||
if (!href) continue;
|
||||
const lowTitle = title.toLowerCase();
|
||||
if (lowTitle.includes(${JSON.stringify(linkHash)}) || lowTitle.includes(${JSON.stringify(link.toLowerCase())}) || !title) {
|
||||
return { directUrl: href, fileName };
|
||||
}
|
||||
const parsed = parseDebridJson(text);
|
||||
if (!parsed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!parsed.link) {
|
||||
if (/hoster does not respond correctly|could not be done for this moment/i.test(parsed.text || "")) {
|
||||
await sleep(1200);
|
||||
continue;
|
||||
}
|
||||
return null;
|
||||
})();`, true).catch(() => null);
|
||||
if (result?.directUrl) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const fromText = parsed.text
|
||||
.replace(/<[^>]*>/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
|
||||
const nameMatch = fromText.match(/([\w .\-\[\]\(\)]+\.(?:rar|r\d{2}|zip|7z|mkv|mp4|avi|mp3|flac))/i);
|
||||
const fileName = (nameMatch?.[1] || filenameFromUrl(link)).trim();
|
||||
return {
|
||||
directUrl: parsed.link,
|
||||
fileName
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this.browser && !this.browser.isDestroyed()) {
|
||||
this.browser.destroy();
|
||||
}
|
||||
this.browser = null;
|
||||
this.cookie = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user