From 0993cfa89621356438cba477754b6003595ab96b Mon Sep 17 00:00:00 2001 From: shafat-96 Date: Fri, 16 Jan 2026 19:03:57 +0600 Subject: [PATCH] fix --- embedHandler.js | 143 ++++++++++++++++++++++-------------------------- 1 file changed, 66 insertions(+), 77 deletions(-) diff --git a/embedHandler.js b/embedHandler.js index bf292f1..8b52eb3 100644 --- a/embedHandler.js +++ b/embedHandler.js @@ -1,126 +1,115 @@ const axios = require("axios"); -const cheerio = require("cheerio"); const MEGACLOUD_URL = "https://megacloud.blog"; -const KEY_URL = "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 KEY_URL = + "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 = "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; -/** 🔹 Extract nonce from HTML */ -function extractNonce(html) { - const match48 = html.match(/\b[a-zA-Z0-9]{48}\b/); - if (match48) return match48[0]; +/* ---------------- NONCE ---------------- */ - 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/ ); - if (match3x16) return match3x16.slice(1, 4).join(""); + if (m3x16) return m3x16.slice(1).join(""); return null; } -/** 🔹 Cache + fetch decryption key */ +/* ---------------- KEY ---------------- */ + async function fetchKey() { if (cachedKey) return cachedKey; - try { - const { data } = await axios.get(KEY_URL, { headers: { "User-Agent": UA } }); - cachedKey = data?.mega; - if (!cachedKey) throw new Error("Missing key in JSON"); - return cachedKey; - } catch (err) { - console.error("Failed to fetch key:", err.message); - return null; - } + + const { data } = await axios.get(KEY_URL, { + headers: { "User-Agent": UA }, + }); + + if (!data?.mega) throw new Error("Mega key missing"); + cachedKey = data.mega; + return cachedKey; } -/** 🔹 Call remote Google Script to 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)}`; +/* ---------------- DECRYPT ---------------- */ - const { data } = await axios.get(fullUrl); - const match = data.match(/"file":"(.*?)"/); - if (!match) throw new Error("Decrypted file not found"); - return match[1].replace(/\\\//g, "/"); +async function decrypt(encrypted, nonce, key) { + const url = + `${DECODE_URL}?encrypted_data=${encodeURIComponent(encrypted)}` + + `&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) { try { const headers = { Accept: "*/*", "X-Requested-With": "XMLHttpRequest", - // Use domain as referer for proper CORS Referer: `${new URL(embedUrl).origin}/`, "User-Agent": UA, }; - // Fetch embed HTML + /* Fetch embed page */ 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); if (!nonce) throw new Error("Nonce not found"); - // Build API URL dynamically - const urlParts = new URL(embedUrl).pathname.split("/").filter(Boolean); - // 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}`; + /* Extract ID from URL (correct way) */ + const id = embedUrl.split("/").pop().split("?")[0]; - // Fetch JSON - const { data: response } = await axios.get(apiUrl, { headers }); - if (!response || !response.sources) - throw new Error("No sources in API response"); + const apiUrl = + `${MEGACLOUD_URL}/embed-2/v3/e-1/getSources` + + `?id=${id}&_k=${nonce}`; - let sources = response.sources; - const tracks = response.tracks || []; - let m3u8Url; + const { data } = await axios.get(apiUrl, { headers }); + if (!data?.sources?.length) throw new Error("No sources"); - // 🔸 If sources is array and contains HLS directly - if (Array.isArray(sources) && sources.length && sources[0].file) { - m3u8Url = sources[0].file; - } - // 🔸 Encrypted string or empty array - else { + const tracks = (data.tracks || []).filter(t => + ["captions", "subtitles"].includes((t.kind || "").toLowerCase()) + ); + + let file = data.sources[0].file; + + /* Direct HLS */ + if (!file.includes(".m3u8")) { const key = await fetchKey(); - if (!key) throw new Error("No key available"); - - m3u8Url = await decryptWithGoogleScript(sources, nonce, key); + file = await decrypt(file, nonce, key); } return { - sources: [{ file: m3u8Url, type: "hls" }], - tracks: tracks.filter((t) => - ["captions", "subtitles"].includes((t.kind || "").toLowerCase()) - ), - t: response.t || 0, - server: response.server || 0, - intro: response.intro || null, - outro: response.outro || null, + sources: [{ file, type: "hls" }], + tracks, + t: data.t ?? 0, + server: data.server ?? 0, + intro: data.intro ?? null, + outro: data.outro ?? null, }; } catch (err) { - console.error("❌ MegaCloud extraction failed:", err.message); - return { - sources: [], - tracks: [], - t: 0, - server: 0, - }; + console.error("❌ MegaCloud failed:", err.message); + return { sources: [], tracks: [] }; } } -/** 🔹 Wrapper */ -async function handleEmbed(embedUrl) { - return await extract(embedUrl); -} +/* ---------------- EXPORT ---------------- */ -module.exports = { extract, handleEmbed }; +module.exports = { + extract, + handleEmbed: extract, +};