mirror of
https://github.com/shafat-96/anicrush-api.git
synced 2026-04-17 15:51:44 +00:00
fix
This commit is contained in:
143
embedHandler.js
143
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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user