This commit is contained in:
shafat-96
2026-01-16 19:03:57 +06:00
parent c47c397903
commit 0993cfa896

View File

@@ -1,126 +1,115 @@
const axios = require("axios"); const axios = require("axios");
const cheerio = require("cheerio");
const MEGACLOUD_URL = "https://megacloud.blog"; const MEGACLOUD_URL = "https://megacloud.blog";
const KEY_URL = "https://raw.githubusercontent.com/yogesh-hacker/MegacloudKeys/refs/heads/main/keys.json"; const KEY_URL =
const DECODE_URL = "https://script.google.com/macros/s/AKfycbx-yHTwupis_JD0lNzoOnxYcEYeXmJZrg7JeMxYnEZnLBy5V0--UxEvP-y9txHyy1TX9Q/exec"; "https://raw.githubusercontent.com/yogesh-hacker/MegacloudKeys/refs/heads/main/keys.json";
const DECODE_URL =
"https://script.google.com/macros/s/AKfycbx-yHTwupis_JD0lNzoOnxYcEYeXmJZrg7JeMxYnEZnLBy5V0--UxEvP-y9txHyy1TX9Q/exec";
const UA = const UA =
"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36"; "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36";
let cachedKey = null; let cachedKey = null;
/** 🔹 Extract nonce from HTML */ /* ---------------- NONCE ---------------- */
function extractNonce(html) {
const match48 = html.match(/\b[a-zA-Z0-9]{48}\b/);
if (match48) return match48[0];
const match3x16 = html.match( function extractNonce(html) {
const m48 = html.match(/\b[a-zA-Z0-9]{48}\b/);
if (m48) return m48[0];
const m3x16 = html.match(
/\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b/ /\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b/
); );
if (match3x16) return match3x16.slice(1, 4).join(""); if (m3x16) return m3x16.slice(1).join("");
return null; return null;
} }
/** 🔹 Cache + fetch decryption key */ /* ---------------- KEY ---------------- */
async function fetchKey() { async function fetchKey() {
if (cachedKey) return cachedKey; if (cachedKey) return cachedKey;
try {
const { data } = await axios.get(KEY_URL, { headers: { "User-Agent": UA } }); const { data } = await axios.get(KEY_URL, {
cachedKey = data?.mega; headers: { "User-Agent": UA },
if (!cachedKey) throw new Error("Missing key in JSON"); });
if (!data?.mega) throw new Error("Mega key missing");
cachedKey = data.mega;
return cachedKey; return cachedKey;
} catch (err) {
console.error("Failed to fetch key:", err.message);
return null;
}
} }
/** 🔹 Call remote Google Script to decrypt */ /* ---------------- DECRYPT ---------------- */
async function decryptWithGoogleScript(encryptedData, nonce, key) {
const fullUrl = `${DECODE_URL}?encrypted_data=${encodeURIComponent(
typeof encryptedData === "string" ? encryptedData : JSON.stringify(encryptedData)
)}&nonce=${encodeURIComponent(nonce)}&secret=${encodeURIComponent(key)}`;
const { data } = await axios.get(fullUrl); async function decrypt(encrypted, nonce, key) {
const match = data.match(/"file":"(.*?)"/); const url =
if (!match) throw new Error("Decrypted file not found"); `${DECODE_URL}?encrypted_data=${encodeURIComponent(encrypted)}` +
return match[1].replace(/\\\//g, "/"); `&nonce=${encodeURIComponent(nonce)}` +
`&secret=${encodeURIComponent(key)}`;
const { data } = await axios.get(url);
const m = data?.match(/"file":"(.*?)"/);
if (!m) throw new Error("Decryption failed");
return m[1].replace(/\\\//g, "/");
} }
/** 🔹 Main extractor */ /* ---------------- MAIN ---------------- */
async function extract(embedUrl) { async function extract(embedUrl) {
try { try {
const headers = { const headers = {
Accept: "*/*", Accept: "*/*",
"X-Requested-With": "XMLHttpRequest", "X-Requested-With": "XMLHttpRequest",
// Use domain as referer for proper CORS
Referer: `${new URL(embedUrl).origin}/`, Referer: `${new URL(embedUrl).origin}/`,
"User-Agent": UA, "User-Agent": UA,
}; };
// Fetch embed HTML /* Fetch embed page */
const { data: html } = await axios.get(embedUrl, { headers }); const { data: html } = await axios.get(embedUrl, { headers });
const $ = cheerio.load(html);
// Extract file ID
const fileId = $("#megacloud-player").attr("data-id");
if (!fileId) throw new Error("data-id not found");
// Extract nonce
const nonce = extractNonce(html); const nonce = extractNonce(html);
if (!nonce) throw new Error("Nonce not found"); if (!nonce) throw new Error("Nonce not found");
// Build API URL dynamically /* Extract ID from URL (correct way) */
const urlParts = new URL(embedUrl).pathname.split("/").filter(Boolean); const id = embedUrl.split("/").pop().split("?")[0];
// Always use v3 endpoint as it returns correct JSON even when embed URL contains v2
const apiUrl = `${MEGACLOUD_URL}/embed-2/v3/e-1/getSources?id=${fileId}&_k=${nonce}`;
// Fetch JSON const apiUrl =
const { data: response } = await axios.get(apiUrl, { headers }); `${MEGACLOUD_URL}/embed-2/v3/e-1/getSources` +
if (!response || !response.sources) `?id=${id}&_k=${nonce}`;
throw new Error("No sources in API response");
let sources = response.sources; const { data } = await axios.get(apiUrl, { headers });
const tracks = response.tracks || []; if (!data?.sources?.length) throw new Error("No sources");
let m3u8Url;
// 🔸 If sources is array and contains HLS directly const tracks = (data.tracks || []).filter(t =>
if (Array.isArray(sources) && sources.length && sources[0].file) { ["captions", "subtitles"].includes((t.kind || "").toLowerCase())
m3u8Url = sources[0].file; );
}
// 🔸 Encrypted string or empty array let file = data.sources[0].file;
else {
/* Direct HLS */
if (!file.includes(".m3u8")) {
const key = await fetchKey(); const key = await fetchKey();
if (!key) throw new Error("No key available"); file = await decrypt(file, nonce, key);
m3u8Url = await decryptWithGoogleScript(sources, nonce, key);
} }
return { return {
sources: [{ file: m3u8Url, type: "hls" }], sources: [{ file, type: "hls" }],
tracks: tracks.filter((t) => tracks,
["captions", "subtitles"].includes((t.kind || "").toLowerCase()) t: data.t ?? 0,
), server: data.server ?? 0,
t: response.t || 0, intro: data.intro ?? null,
server: response.server || 0, outro: data.outro ?? null,
intro: response.intro || null,
outro: response.outro || null,
}; };
} catch (err) { } catch (err) {
console.error("❌ MegaCloud extraction failed:", err.message); console.error("❌ MegaCloud failed:", err.message);
return { return { sources: [], tracks: [] };
sources: [], }
tracks: [], }
t: 0,
server: 0, /* ---------------- EXPORT ---------------- */
module.exports = {
extract,
handleEmbed: extract,
}; };
}
}
/** 🔹 Wrapper */
async function handleEmbed(embedUrl) {
return await extract(embedUrl);
}
module.exports = { extract, handleEmbed };