This commit is contained in:
shafat420
2025-06-18 00:15:32 +06:00
parent 63ac812298
commit 2520c427dc
4 changed files with 158 additions and 58404 deletions

View File

@@ -1,110 +1,147 @@
const { spawn } = require('child_process'); const axios = require('axios');
const path = require('path'); const crypto = require('node:crypto');
const fs = require('fs').promises;
class EmbedSource {
class EmbedSource { constructor(file, sourceType) {
constructor(file, sourceType) { this.file = file;
this.file = file; this.type = sourceType;
this.type = sourceType; }
} }
}
class Track {
class Track { constructor(file, label, kind, isDefault = false) {
constructor(file, label, kind, isDefault = false) { this.file = file;
this.file = file; this.label = label;
this.label = label; this.kind = kind;
this.kind = kind; if (isDefault) {
if (isDefault) { this.default = isDefault;
this.default = isDefault; }
} }
} }
}
class EmbedSources {
class EmbedSources { constructor(sources = [], tracks = [], t = 0, server = 1, intro = null, outro = null) {
constructor(sources = [], tracks = [], t = 0, server = 1, intro = null, outro = null) { this.sources = sources;
this.sources = sources; this.tracks = tracks;
this.tracks = tracks; this.t = t;
this.t = t; this.server = server;
this.server = server; if (intro) this.intro = intro;
if (intro) this.intro = intro; if (outro) this.outro = outro;
if (outro) this.outro = outro; }
} }
}
// Constants for Megacloud
const findRabbitScript = async () => { const MEGACLOUD_URL = 'https://megacloud.blog';
const possiblePaths = [ const KEY_URL = 'https://raw.githubusercontent.com/yogesh-hacker/MegacloudKeys/refs/heads/main/keys.json';
path.join(__dirname, 'sources', 'rabbit.ts'),
path.join(__dirname, 'sources', 'rabbit.js'), // --- OpenSSL-compatible key+IV derivation (same algorithm used by Megacloud)
path.join(__dirname, 'rabbit.js'), function opensslKeyIv(password, salt, keyLen = 32, ivLen = 16) {
path.join(process.cwd(), 'rabbit.js') let d = Buffer.alloc(0);
]; let prev = Buffer.alloc(0);
for (const p of possiblePaths) { while (d.length < keyLen + ivLen) {
try { const hash = crypto.createHash('md5');
await fs.access(p); hash.update(Buffer.concat([prev, password, salt]));
return p; prev = hash.digest();
} catch (error) { d = Buffer.concat([d, prev]);
continue; }
}
} return {
throw new Error('rabbit.js not found in any expected locations'); key: d.subarray(0, keyLen),
}; iv: d.subarray(keyLen, keyLen + ivLen),
};
const handleEmbed = async (embedUrl, referrer) => { }
return new Promise(async (resolve, reject) => {
try { // --- Decrypt OpenSSL AES-CBC encoded Base64 payloads
const rabbitPath = await findRabbitScript(); function decryptOpenSSL(encBase64, password) {
const childProcess = spawn('node', [ try {
rabbitPath, const data = Buffer.from(encBase64, 'base64');
`--embed-url=${embedUrl}`, if (data.subarray(0, 8).toString() !== 'Salted__') return null;
`--referrer=${referrer}`
]); const salt = data.subarray(8, 16);
const { key, iv } = opensslKeyIv(Buffer.from(password, 'utf8'), salt);
let outputData = ''; const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
let errorData = ''; const decrypted = Buffer.concat([
decipher.update(data.subarray(16)),
childProcess.stdout.on('data', (data) => { decipher.final(),
outputData += data.toString(); ]);
}); return decrypted.toString('utf-8');
} catch (err) {
childProcess.stderr.on('data', (data) => { console.error('Decryption error:', err.message);
errorData += data.toString(); return null;
}); }
}
childProcess.on('close', (code) => {
if (code !== 0) { // --- Helpers
reject(new Error(`Process exited with code ${code}: ${errorData}`)); function extractId(url) {
return; return url.split('/').pop().split('?')[0];
} }
try { async function getDecryptionKey() {
const parsedOutput = JSON.parse(outputData.trim()); try {
const embedSources = new EmbedSources( const res = await axios.get(KEY_URL);
parsedOutput.sources.map(s => new EmbedSource(s.file, s.type)), return typeof res.data === 'string' ? JSON.parse(res.data).mega : res.data?.mega;
parsedOutput.tracks.map(t => new Track(t.file, t.label, t.kind, t.default)), } catch (e) {
parsedOutput.t, console.error('Failed to fetch key:', e.message);
parsedOutput.server, return null;
parsedOutput.intro, }
parsedOutput.outro }
);
resolve(embedSources); const handleEmbed = async (embedUrl, referrer = 'https://megacloud.blog') => {
} catch (error) { try {
reject(error); if (!embedUrl) throw new Error('embedUrl is required');
}
}); const id = extractId(embedUrl);
const apiUrl = `${MEGACLOUD_URL}/embed-2/v2/e-1/getSources?id=${id}`;
childProcess.on('error', (error) => {
reject(error); const headers = {
}); Referer: referrer || embedUrl,
} catch (error) { Origin: 'https://megacloud.blog/',
reject(error); 'User-Agent': 'Mozilla/5.0',
} };
});
}; const { data } = await axios.get(apiUrl, { headers });
if (!data?.sources) throw new Error('No sources field in response');
module.exports = {
handleEmbed, // Parse/Decrypt sources array
EmbedSource, let rawSources;
Track, if (typeof data.sources === 'string') {
EmbedSources try {
rawSources = JSON.parse(data.sources);
} catch (_) {
const key = await getDecryptionKey();
if (!key) throw new Error('Failed to fetch decryption key');
const decrypted = decryptOpenSSL(data.sources, key);
if (!decrypted) throw new Error('Decryption failed');
rawSources = JSON.parse(decrypted);
}
} else if (Array.isArray(data.sources)) {
rawSources = data.sources;
} else {
throw new Error('Unexpected sources format');
}
if (!rawSources.length) throw new Error('No valid sources found');
const sources = rawSources.map((s) => new EmbedSource(s.file, s.type || s.quality || 'unknown'));
const tracks = (data.tracks || []).map((t) => new Track(t.file, t.label, t.kind, t.default));
return new EmbedSources(
sources,
tracks,
data.t ?? 0,
'megacloud',
data.intro ?? null,
data.outro ?? null
);
} catch (error) {
throw error;
}
};
module.exports = {
handleEmbed,
EmbedSource,
Track,
EmbedSources
}; };

8
package-lock.json generated
View File

@@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"axios": "^1.6.2", "axios": "^1.6.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"crypto": "^1.0.1",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"express": "^4.18.2" "express": "^4.18.2"
}, },
@@ -269,6 +270,13 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.",
"license": "ISC"
},
"node_modules/debug": { "node_modules/debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",

View File

@@ -12,12 +12,13 @@
"vercel-build": "echo hello" "vercel-build": "echo hello"
}, },
"dependencies": { "dependencies": {
"express": "^4.18.2",
"axios": "^1.6.2", "axios": "^1.6.2",
"cors": "^2.8.5",
"crypto": "^1.0.1",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"cors": "^2.8.5" "express": "^4.18.2"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.0.2" "nodemon": "^3.0.2"
} }
} }

File diff suppressed because one or more lines are too long