mirror of
https://gitlab.com/vyla-entertainment/sdk.git
synced 2026-11-14 22:27:27 -05:00
added mapple, mysterious and vidqueen
This commit is contained in:
@@ -50,7 +50,7 @@ export const SOURCES = [
|
||||
Referer: 'https://play2.echovideo.ru/',
|
||||
Origin: 'https://play2.echovideo.ru',
|
||||
},
|
||||
},],
|
||||
}],
|
||||
},
|
||||
|
||||
{
|
||||
@@ -438,6 +438,24 @@ export const SOURCES = [
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
key: 'mapple',
|
||||
label: 'Mapple',
|
||||
sourceFile: 'mapple',
|
||||
proxyParam: 'mp',
|
||||
timeout: 25000,
|
||||
jitter: 500,
|
||||
retries: 2,
|
||||
multiUrl: true,
|
||||
cdnHeaders: [{
|
||||
pattern: /mapple\.fun/i,
|
||||
headers: {
|
||||
Referer: 'https://mapple.fun/',
|
||||
Origin: 'https://mapple.fun',
|
||||
},
|
||||
}],
|
||||
},
|
||||
|
||||
{
|
||||
key: 'meowtv',
|
||||
label: 'MeowTV',
|
||||
@@ -520,6 +538,24 @@ export const SOURCES = [
|
||||
}],
|
||||
},
|
||||
|
||||
{
|
||||
key: 'mysterious',
|
||||
label: 'Mysterious',
|
||||
sourceFile: 'mysterious',
|
||||
proxyParam: 'mys',
|
||||
timeout: 20000,
|
||||
jitter: 500,
|
||||
retries: 2,
|
||||
multiUrl: true,
|
||||
cdnHeaders: [{
|
||||
pattern: /speedoflight\.buzz|febbox\.com/i,
|
||||
headers: {
|
||||
Referer: 'https://atlantic.speedoflight.buzz/',
|
||||
Origin: 'https://atlantic.speedoflight.buzz',
|
||||
},
|
||||
}],
|
||||
},
|
||||
|
||||
{
|
||||
key: 'net79',
|
||||
label: 'Net79',
|
||||
@@ -709,7 +745,7 @@ export const SOURCES = [
|
||||
timeout: 25000,
|
||||
jitter: 500,
|
||||
retries: 1,
|
||||
multiUrl: true
|
||||
multiUrl: true,
|
||||
},
|
||||
|
||||
{
|
||||
@@ -849,6 +885,24 @@ export const SOURCES = [
|
||||
}],
|
||||
},
|
||||
|
||||
{
|
||||
key: 'vidqueen',
|
||||
label: 'Vidqueen',
|
||||
sourceFile: 'vidqueen',
|
||||
proxyParam: 'vq',
|
||||
timeout: 25000,
|
||||
jitter: 500,
|
||||
retries: 2,
|
||||
multiUrl: true,
|
||||
cdnHeaders: [{
|
||||
pattern: /vidqueen\.st|surrealviews\.com/i,
|
||||
headers: {
|
||||
Referer: 'https://vidqueen.st/',
|
||||
Origin: 'https://vidqueen.st',
|
||||
},
|
||||
}],
|
||||
},
|
||||
|
||||
{
|
||||
key: 'vidspark',
|
||||
label: 'VidSpark',
|
||||
@@ -875,7 +929,7 @@ export const SOURCES = [
|
||||
timeout: 35000,
|
||||
jitter: 500,
|
||||
retries: 1,
|
||||
multiUrl: true
|
||||
multiUrl: true,
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
430
src/sources/mapple.js
Normal file
430
src/sources/mapple.js
Normal file
@@ -0,0 +1,430 @@
|
||||
const BASE_URL = 'https://mapple.fun';
|
||||
const DSKTP_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36';
|
||||
const MBILE_UA = 'Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36';
|
||||
|
||||
const SERVERS = [
|
||||
{ name: 'Zeus', source: 'mapple' },
|
||||
{ name: 'Poseidon', source: 's25' },
|
||||
{ name: 'Aphrodite', source: 's6' },
|
||||
{ name: 'Hephaestus', source: 's15' },
|
||||
{ name: 'Prometheus', source: 's10' },
|
||||
{ name: 'Atlas', source: 's1' }
|
||||
];
|
||||
|
||||
const SHA256_K = new Int32Array([
|
||||
1116352408, 1899447441, 3049323471, 3921009573, 961987163, 1508970993, 2453635748, 2870763221,
|
||||
3624381080, 310598401, 607225278, 1426881987, 1925078388, 2162078206, 2614888103, 3248222580,
|
||||
3835390401, 4022224774, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
|
||||
2554220882, 2821834349, 2952996808, 3210313671, 3336571891, 3584528711, 113926993, 338241895,
|
||||
666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, 2177026350, 2456956037,
|
||||
2730485921, 2820302411, 3259730800, 3345764771, 3516065817, 3600352804, 4094571909, 275423344,
|
||||
430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779,
|
||||
1955562222, 2024104815, 2227730452, 2361852424, 2428436474, 2756734187, 3204031479, 3329325298
|
||||
]);
|
||||
|
||||
const SHA256_IS = new Int32Array([
|
||||
1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225
|
||||
]);
|
||||
|
||||
function sha256Compress(state, schedule, data, offset) {
|
||||
let i, pos, a, b, c, d, e, f, g, h, temp1, sum0, sum1, choice, majority, w15, w2;
|
||||
for (i = 0; i < 16; i++) {
|
||||
pos = offset + i * 4;
|
||||
schedule[i] = (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3];
|
||||
}
|
||||
for (i = 16; i < 64; i++) {
|
||||
w15 = schedule[i - 15];
|
||||
w2 = schedule[i - 2];
|
||||
schedule[i] = (schedule[i - 16] + (((w15 >>> 7) | (w15 << 25)) ^ ((w15 >>> 18) | (w15 << 14)) ^ (w15 >>> 3)) +
|
||||
schedule[i - 7] + (((w2 >>> 17) | (w2 << 15)) ^ ((w2 >>> 19) | (w2 << 13)) ^ (w2 >>> 10))) | 0;
|
||||
}
|
||||
a = state[0]; b = state[1]; c = state[2]; d = state[3];
|
||||
e = state[4]; f = state[5]; g = state[6]; h = state[7];
|
||||
for (i = 0; i < 64; i += 8) {
|
||||
sum1 = (((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7)));
|
||||
choice = (e & f) ^ (~e & g);
|
||||
temp1 = (h + sum1 + choice + SHA256_K[i + 0] + schedule[i + 0]) | 0;
|
||||
sum0 = (((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10)));
|
||||
majority = (a & b) ^ (a & c) ^ (b & c);
|
||||
d = (d + temp1) | 0;
|
||||
h = (temp1 + sum0 + majority) | 0;
|
||||
|
||||
sum1 = (((d >>> 6) | (d << 26)) ^ ((d >>> 11) | (d << 21)) ^ ((d >>> 25) | (d << 7)));
|
||||
choice = (d & e) ^ (~d & f);
|
||||
temp1 = (g + sum1 + choice + SHA256_K[i + 1] + schedule[i + 1]) | 0;
|
||||
sum0 = (((h >>> 2) | (h << 30)) ^ ((h >>> 13) | (h << 19)) ^ ((h >>> 22) | (h << 10)));
|
||||
majority = (h & a) ^ (h & b) ^ (a & b);
|
||||
c = (c + temp1) | 0;
|
||||
g = (temp1 + sum0 + majority) | 0;
|
||||
|
||||
sum1 = (((c >>> 6) | (c << 26)) ^ ((c >>> 11) | (c << 21)) ^ ((c >>> 25) | (c << 7)));
|
||||
choice = (c & d) ^ (~c & e);
|
||||
temp1 = (f + sum1 + choice + SHA256_K[i + 2] + schedule[i + 2]) | 0;
|
||||
sum0 = (((g >>> 2) | (g << 30)) ^ ((g >>> 13) | (g << 19)) ^ ((g >>> 22) | (g << 10)));
|
||||
majority = (g & h) ^ (g & a) ^ (h & a);
|
||||
b = (b + temp1) | 0;
|
||||
f = (temp1 + sum0 + majority) | 0;
|
||||
|
||||
sum1 = (((b >>> 6) | (b << 26)) ^ ((b >>> 11) | (b << 21)) ^ ((b >>> 25) | (b << 7)));
|
||||
choice = (b & c) ^ (~b & d);
|
||||
temp1 = (e + sum1 + choice + SHA256_K[i + 3] + schedule[i + 3]) | 0;
|
||||
sum0 = (((f >>> 2) | (f << 30)) ^ ((f >>> 13) | (f << 19)) ^ ((f >>> 22) | (f << 10)));
|
||||
majority = (f & g) ^ (f & h) ^ (g & h);
|
||||
a = (a + temp1) | 0;
|
||||
e = (temp1 + sum0 + majority) | 0;
|
||||
|
||||
sum1 = (((a >>> 6) | (a << 26)) ^ ((a >>> 11) | (a << 21)) ^ ((a >>> 25) | (a << 7)));
|
||||
choice = (a & b) ^ (~a & c);
|
||||
temp1 = (d + sum1 + choice + SHA256_K[i + 4] + schedule[i + 4]) | 0;
|
||||
sum0 = (((e >>> 2) | (e << 30)) ^ ((e >>> 13) | (e << 19)) ^ ((e >>> 22) | (e << 10)));
|
||||
majority = (e & f) ^ (e & g) ^ (f & g);
|
||||
h = (h + temp1) | 0;
|
||||
d = (temp1 + sum0 + majority) | 0;
|
||||
|
||||
sum1 = (((h >>> 6) | (h << 26)) ^ ((h >>> 11) | (h << 21)) ^ ((h >>> 25) | (h << 7)));
|
||||
choice = (h & a) ^ (~h & b);
|
||||
temp1 = (c + sum1 + choice + SHA256_K[i + 5] + schedule[i + 5]) | 0;
|
||||
sum0 = (((d >>> 2) | (d << 30)) ^ ((d >>> 13) | (d << 19)) ^ ((d >>> 22) | (d << 10)));
|
||||
majority = (d & e) ^ (d & f) ^ (e & f);
|
||||
g = (g + temp1) | 0;
|
||||
c = (temp1 + sum0 + majority) | 0;
|
||||
|
||||
sum1 = (((g >>> 6) | (g << 26)) ^ ((g >>> 11) | (g << 21)) ^ ((g >>> 25) | (g << 7)));
|
||||
choice = (g & h) ^ (~g & a);
|
||||
temp1 = (b + sum1 + choice + SHA256_K[i + 6] + schedule[i + 6]) | 0;
|
||||
sum0 = (((c >>> 2) | (c << 30)) ^ ((c >>> 13) | (c << 19)) ^ ((c >>> 22) | (c << 10)));
|
||||
majority = (c & d) ^ (c & e) ^ (d & e);
|
||||
f = (f + temp1) | 0;
|
||||
b = (temp1 + sum0 + majority) | 0;
|
||||
|
||||
sum1 = (((f >>> 6) | (f << 26)) ^ ((f >>> 11) | (f << 21)) ^ ((f >>> 25) | (f << 7)));
|
||||
choice = (f & g) ^ (~f & h);
|
||||
temp1 = (a + sum1 + choice + SHA256_K[i + 7] + schedule[i + 7]) | 0;
|
||||
sum0 = (((b >>> 2) | (b << 30)) ^ ((b >>> 13) | (b << 19)) ^ ((b >>> 22) | (b << 10)));
|
||||
majority = (b & c) ^ (b & d) ^ (c & d);
|
||||
e = (e + temp1) | 0;
|
||||
a = (temp1 + sum0 + majority) | 0;
|
||||
}
|
||||
state[0] = (state[0] + a) | 0; state[1] = (state[1] + b) | 0;
|
||||
state[2] = (state[2] + c) | 0; state[3] = (state[3] + d) | 0;
|
||||
state[4] = (state[4] + e) | 0; state[5] = (state[5] + f) | 0;
|
||||
state[6] = (state[6] + g) | 0; state[7] = (state[7] + h) | 0;
|
||||
}
|
||||
|
||||
function hasLeadingZeroBits(state, requiredBits) {
|
||||
let remaining = requiredBits;
|
||||
for (let i = 0; i < 8; i++) {
|
||||
if (remaining <= 0) return true;
|
||||
if (state[i] === 0) {
|
||||
remaining -= 32;
|
||||
continue;
|
||||
}
|
||||
return Math.clz32(state[i]) >= remaining;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function solveProofOfWork(challenge, difficulty) {
|
||||
const prefix = new TextEncoder().encode(String(challenge));
|
||||
const prefixLength = prefix.length;
|
||||
const state = new Int32Array(8);
|
||||
const midState = new Int32Array(8);
|
||||
const schedule = new Int32Array(64);
|
||||
const firstDynamicBlock = Math.floor(prefixLength / 64);
|
||||
|
||||
for (let digits = 1; digits <= 8; digits++) {
|
||||
const rangeStart = digits === 1 ? 0 : Math.pow(10, digits - 1);
|
||||
const rangeEnd = Math.min(Math.pow(10, digits), 20000000);
|
||||
const messageLength = prefixLength + digits;
|
||||
const paddedLength = Math.ceil((messageLength + 9) / 64) * 64;
|
||||
const buffer = new Uint8Array(paddedLength);
|
||||
buffer.set(prefix, 0);
|
||||
buffer[messageLength] = 128;
|
||||
const bitLength = messageLength * 8;
|
||||
buffer[paddedLength - 4] = (bitLength >>> 24) & 255;
|
||||
buffer[paddedLength - 3] = (bitLength >>> 16) & 255;
|
||||
buffer[paddedLength - 2] = (bitLength >>> 8) & 255;
|
||||
buffer[paddedLength - 1] = bitLength & 255;
|
||||
|
||||
midState.set(SHA256_IS);
|
||||
for (let block = 0; block < firstDynamicBlock; block++) {
|
||||
sha256Compress(midState, schedule, buffer, block * 64);
|
||||
}
|
||||
|
||||
for (let nonce = rangeStart; nonce < rangeEnd; nonce++) {
|
||||
let remainder = nonce;
|
||||
for (let pos = messageLength - 1; pos >= prefixLength; pos--) {
|
||||
buffer[pos] = 48 + (remainder % 10);
|
||||
remainder = (remainder / 10) | 0;
|
||||
}
|
||||
state.set(midState);
|
||||
for (let offset = firstDynamicBlock * 64; offset < paddedLength; offset += 64) {
|
||||
sha256Compress(state, schedule, buffer, offset);
|
||||
}
|
||||
if (hasLeadingZeroBits(state, difficulty)) return String(nonce);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function createCookieJar() {
|
||||
const cookies = {};
|
||||
return {
|
||||
update(response) {
|
||||
let rawCookies = [];
|
||||
try {
|
||||
if (response && response.headers && typeof response.headers.getSetCookie === 'function') {
|
||||
rawCookies = response.headers.getSetCookie() || [];
|
||||
} else if (response && response.headers) {
|
||||
const header = response.headers.get('set-cookie');
|
||||
if (header) rawCookies = [header];
|
||||
}
|
||||
} catch { }
|
||||
rawCookies.forEach((cookie) => {
|
||||
const pair = cookie.split(';')[0].split('=');
|
||||
if (pair.length >= 2) cookies[pair[0].trim()] = pair.slice(1).join('=').trim();
|
||||
});
|
||||
},
|
||||
serialize() {
|
||||
return Object.keys(cookies).map((name) => `${name}=${cookies[name]}`).join('; ');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function resolvePlaylistUrl(entry, playlistUrl) {
|
||||
if (/^https?:\/\//i.test(entry)) return entry;
|
||||
const cleanUrl = playlistUrl.split('#')[0].split('?')[0];
|
||||
if (entry.charAt(0) === '/') {
|
||||
const origin = cleanUrl.match(/^(https?:\/\/[^\/]+)/i);
|
||||
return `${origin ? origin[1] : ''}${entry}`;
|
||||
}
|
||||
return `${cleanUrl.slice(0, cleanUrl.lastIndexOf('/') + 1)}${entry}`;
|
||||
}
|
||||
|
||||
const PLAYBACK_HEADERS = {
|
||||
'User-Agent': DSKTP_UA,
|
||||
Origin: BASE_URL,
|
||||
Referer: `${BASE_URL}/`
|
||||
};
|
||||
|
||||
async function createSession(tmdbId, mediaType, tvSlug, referer, timeout = 25000) {
|
||||
try {
|
||||
const jar = createCookieJar();
|
||||
const homeRes = await fetch(`${BASE_URL}/`, {
|
||||
headers: { 'User-Agent': MBILE_UA, Accept: 'text/html' },
|
||||
signal: AbortSignal.timeout(timeout)
|
||||
});
|
||||
jar.update(homeRes);
|
||||
|
||||
const tokenRes = await fetch(`${BASE_URL}/api/ui/session`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'User-Agent': MBILE_UA,
|
||||
Accept: '*/*',
|
||||
Origin: BASE_URL,
|
||||
Referer: referer,
|
||||
'Content-Type': 'application/json',
|
||||
Cookie: jar.serialize()
|
||||
},
|
||||
body: '',
|
||||
signal: AbortSignal.timeout(timeout)
|
||||
});
|
||||
jar.update(tokenRes);
|
||||
|
||||
const tokenData = await tokenRes.json().catch(() => null);
|
||||
const requestToken = tokenData?.token;
|
||||
if (!requestToken) return null;
|
||||
|
||||
const payload = {
|
||||
mediaId: Number(tmdbId),
|
||||
mediaType,
|
||||
tv_slug: tvSlug,
|
||||
requestToken
|
||||
};
|
||||
|
||||
const initPlayback = async (body) => {
|
||||
const res = await fetch(`${BASE_URL}/api/playback-init`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'User-Agent': MBILE_UA,
|
||||
Accept: '*/*',
|
||||
Origin: BASE_URL,
|
||||
Referer: referer,
|
||||
'Content-Type': 'application/json',
|
||||
Cookie: jar.serialize()
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
signal: AbortSignal.timeout(timeout)
|
||||
});
|
||||
jar.update(res);
|
||||
return await res.json().catch(() => null);
|
||||
};
|
||||
|
||||
let result = await initPlayback(payload);
|
||||
if (result?.success && result.token) {
|
||||
return { requestToken, playbackToken: result.token, jar, referer };
|
||||
}
|
||||
|
||||
if (result?.requiresPow && result.pow) {
|
||||
const nonce = solveProofOfWork(result.pow.challenge, result.pow.difficulty || 18);
|
||||
if (nonce === null) return null;
|
||||
|
||||
result = await initPlayback({
|
||||
...payload,
|
||||
pow: { challengeId: result.pow.challengeId, nonce }
|
||||
});
|
||||
|
||||
if (result?.token) {
|
||||
return { requestToken, playbackToken: result.token, jar, referer };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function parseMasterPlaylist(playlistUrl, headers) {
|
||||
try {
|
||||
const res = await fetch(playlistUrl, {
|
||||
headers,
|
||||
signal: AbortSignal.timeout(5000)
|
||||
});
|
||||
if (!res.ok) return null;
|
||||
const text = await res.text();
|
||||
if (!text.includes('#EXT-X-STREAM-INF')) return null;
|
||||
|
||||
const lines = text.split('\n');
|
||||
const variants = [];
|
||||
let currentQuality = '1080p';
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (line.startsWith('#EXT-X-STREAM-INF')) {
|
||||
const resMatch = line.match(/RESOLUTION=\d+x(\d+)/i);
|
||||
if (resMatch) {
|
||||
currentQuality = `${resMatch[1]}p`;
|
||||
}
|
||||
} else if (line && !line.startsWith('#')) {
|
||||
const streamUrl = resolvePlaylistUrl(line, playlistUrl);
|
||||
variants.push({
|
||||
url: streamUrl,
|
||||
quality: currentQuality
|
||||
});
|
||||
currentQuality = '1080p';
|
||||
}
|
||||
}
|
||||
|
||||
return variants.length ? variants : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchServerStreams(server, tmdbId, mediaType, tvSlug, session, timeout = 25000) {
|
||||
const sourceKey = server.source || server.key;
|
||||
try {
|
||||
const encryptRes = await fetch(`${BASE_URL}/api/encrypt`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'User-Agent': MBILE_UA,
|
||||
Accept: '*/*',
|
||||
Origin: BASE_URL,
|
||||
Referer: session.referer,
|
||||
'Content-Type': 'application/json',
|
||||
Cookie: session.jar.serialize()
|
||||
},
|
||||
body: JSON.stringify({
|
||||
data: {
|
||||
mediaId: Number(tmdbId),
|
||||
mediaType,
|
||||
tv_slug: tvSlug,
|
||||
source: sourceKey
|
||||
},
|
||||
endpoint: 'stream-encrypted',
|
||||
requestToken: session.requestToken
|
||||
}),
|
||||
signal: AbortSignal.timeout(timeout)
|
||||
});
|
||||
|
||||
const encrypted = await encryptRes.json().catch(() => null);
|
||||
if (!encrypted?.url) return [];
|
||||
|
||||
const streamEndpoint = `${BASE_URL}${encrypted.url}&requestToken=${encodeURIComponent(session.requestToken)}&token=${encodeURIComponent(session.playbackToken)}`;
|
||||
const streamRes = await fetch(streamEndpoint, {
|
||||
headers: {
|
||||
'User-Agent': MBILE_UA,
|
||||
Accept: '*/*',
|
||||
Origin: BASE_URL,
|
||||
Referer: session.referer,
|
||||
Cookie: session.jar.serialize()
|
||||
},
|
||||
signal: AbortSignal.timeout(timeout)
|
||||
});
|
||||
|
||||
const streamData = await streamRes.json().catch(() => null);
|
||||
const streamUrl = streamData?.data?.stream_url;
|
||||
if (!streamUrl || String(streamUrl).includes('playback-unavailable')) return [];
|
||||
|
||||
const variants = await parseMasterPlaylist(streamUrl, PLAYBACK_HEADERS);
|
||||
if (variants && variants.length > 0) {
|
||||
return variants.map(v => ({
|
||||
url: v.url,
|
||||
quality: v.quality,
|
||||
serverName: server.name
|
||||
}));
|
||||
}
|
||||
|
||||
return [{ url: streamUrl, quality: 'Auto', serverName: server.name }];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStream(args) {
|
||||
const { id, s, e } = args || {};
|
||||
if (!id || !/^\d+$/.test(String(id))) return null;
|
||||
|
||||
const isTv = s != null && e != null;
|
||||
const type = isTv ? 'tv' : 'movie';
|
||||
const tvSlug = isTv ? `${Number(s || 1)}-${Number(e || 1)}` : '';
|
||||
const referer = isTv
|
||||
? `${BASE_URL}/tv/${id}/${Number(s || 1)}/${Number(e || 1)}`
|
||||
: `${BASE_URL}/movie/${id}`;
|
||||
|
||||
const session = await createSession(id, type, tvSlug, referer, args?.config?.timeout);
|
||||
if (!session) return null;
|
||||
|
||||
const serverPromises = SERVERS.map((server) =>
|
||||
fetchServerStreams(server, id, type, tvSlug, session, args?.config?.timeout)
|
||||
);
|
||||
|
||||
const settled = await Promise.allSettled(serverPromises);
|
||||
const allUrls = [];
|
||||
const seenUrls = new Set();
|
||||
|
||||
for (const res of settled) {
|
||||
if (res.status !== 'fulfilled' || !Array.isArray(res.value)) continue;
|
||||
for (const item of res.value) {
|
||||
if (!item.url || seenUrls.has(item.url)) continue;
|
||||
seenUrls.add(item.url);
|
||||
|
||||
allUrls.push({
|
||||
url: item.url,
|
||||
server: `Mapple - ${item.serverName}`,
|
||||
quality: item.quality || 'Auto',
|
||||
type: item.url.includes('.m3u8') ? 'hls' : 'mp4',
|
||||
headers: PLAYBACK_HEADERS
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!allUrls.length) return null;
|
||||
|
||||
return {
|
||||
url: allUrls[0].url,
|
||||
headers: allUrls[0].headers,
|
||||
allUrls
|
||||
};
|
||||
}
|
||||
113
src/sources/mysterious.js
Normal file
113
src/sources/mysterious.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import { fetchJson } from '../utils/helpers.js';
|
||||
|
||||
const BASE_URL = 'https://atlantic.speedoflight.buzz';
|
||||
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36';
|
||||
|
||||
function normalizeQuality(q) {
|
||||
if (!q) return '1080p';
|
||||
const str = String(q).trim();
|
||||
return /^\d+$/.test(str) ? `${str}p` : str;
|
||||
}
|
||||
|
||||
export async function getStream(args) {
|
||||
const { id, s, e } = args || {};
|
||||
if (!id) return null;
|
||||
|
||||
const isTv = s != null && e != null;
|
||||
const season = s || 1;
|
||||
const episode = e || 1;
|
||||
|
||||
const targetUrl = isTv
|
||||
? `${BASE_URL}/api/embed?tmdb_id=${encodeURIComponent(id)}&type=series&season=${encodeURIComponent(season)}&episode=${encodeURIComponent(episode)}`
|
||||
: `${BASE_URL}/api/embed?tmdb_id=${encodeURIComponent(id)}`;
|
||||
|
||||
try {
|
||||
const payload = await fetchJson(targetUrl, {
|
||||
headers: {
|
||||
'User-Agent': UA,
|
||||
Accept: 'application/json',
|
||||
},
|
||||
signal: AbortSignal.timeout(args?.config?.timeout || 10000),
|
||||
});
|
||||
|
||||
if (!payload || (!Array.isArray(payload.qualities) && !payload.download_url && !payload.url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const allUrls = [];
|
||||
const seenUrls = new Set();
|
||||
|
||||
if (Array.isArray(payload.qualities)) {
|
||||
for (const item of payload.qualities) {
|
||||
if (!item || !item.url || seenUrls.has(item.url)) continue;
|
||||
|
||||
const qualLabel = String(item.quality || '').trim();
|
||||
if (qualLabel.toUpperCase() === 'ORG') continue;
|
||||
|
||||
seenUrls.add(item.url);
|
||||
const quality = normalizeQuality(qualLabel || '1080p');
|
||||
const sizeText = item.sizeText ? ` (${item.sizeText})` : '';
|
||||
|
||||
const ext = item.url.split('?')[0].split('.').pop()?.toLowerCase();
|
||||
const type = ext === 'm3u8' || item.url.includes('.m3u8')
|
||||
? 'hls'
|
||||
: (ext === 'mpd' || item.url.includes('.mpd') ? 'dash' : (ext === 'mkv' ? 'mkv' : 'mp4'));
|
||||
|
||||
allUrls.push({
|
||||
url: item.url,
|
||||
server: `Mysterious - Direct ${quality}${sizeText}`,
|
||||
quality,
|
||||
type,
|
||||
skipProxy: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const directUrl = payload.download_url || payload.url;
|
||||
if (directUrl && !seenUrls.has(directUrl)) {
|
||||
seenUrls.add(directUrl);
|
||||
const qMatch = (payload.file_name || '').match(/\b(2160p|1080p|720p|480p|360p|4k)\b/i);
|
||||
const quality = qMatch ? qMatch[1].toLowerCase() : 'Auto';
|
||||
const sizeText = payload.file_size ? ` (${payload.file_size})` : '';
|
||||
const ext = directUrl.split('?')[0].split('.').pop()?.toLowerCase();
|
||||
const type = ext === 'm3u8' || directUrl.includes('.m3u8')
|
||||
? 'hls'
|
||||
: (ext === 'mpd' || directUrl.includes('.mpd') ? 'dash' : (ext === 'mkv' || (payload.file_name && payload.file_name.endsWith('.mkv')) ? 'mkv' : 'mp4'));
|
||||
|
||||
allUrls.push({
|
||||
url: directUrl,
|
||||
server: `Mysterious - Direct ${quality}${sizeText}`,
|
||||
quality,
|
||||
type,
|
||||
skipProxy: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (payload.download_url && !seenUrls.has(payload.download_url)) {
|
||||
seenUrls.add(payload.download_url);
|
||||
const qMatch = (payload.file_name || '').match(/\b(2160p|1080p|720p|480p|360p|4k)\b/i);
|
||||
const quality = qMatch ? qMatch[1].toLowerCase() : 'Auto';
|
||||
const sizeText = payload.file_size ? ` (${payload.file_size})` : '';
|
||||
const ext = payload.download_url.split('?')[0].split('.').pop()?.toLowerCase();
|
||||
const type = ext === 'm3u8' ? 'hls' : (ext === 'mpd' ? 'dash' : (ext === 'mkv' || (payload.file_name && payload.file_name.endsWith('.mkv')) ? 'mkv' : 'mp4'));
|
||||
|
||||
allUrls.push({
|
||||
url: payload.download_url,
|
||||
server: `Mysterious - Direct ${quality}${sizeText}`,
|
||||
quality,
|
||||
type,
|
||||
skipProxy: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (!allUrls.length) return null;
|
||||
|
||||
return {
|
||||
url: allUrls[0].url,
|
||||
headers: allUrls[0].headers,
|
||||
allUrls,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
138
src/sources/vidqueen.js
Normal file
138
src/sources/vidqueen.js
Normal file
@@ -0,0 +1,138 @@
|
||||
const BASE_URL = 'https://api.vidqueen.st';
|
||||
const ORIGIN = 'https://vidqueen.st';
|
||||
|
||||
const HEADERS = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/157.0.0.0 Safari/537.36',
|
||||
Accept: 'application/json',
|
||||
'Accept-Language': 'en-US,en;q=0.9',
|
||||
Origin: ORIGIN,
|
||||
Referer: `${ORIGIN}/`,
|
||||
'Sec-Fetch-Site': 'same-site',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'sec-ch-ua': '"Not-A.Brand";v="99", "Google Chrome";v="157", "Chromium";v="157"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
};
|
||||
|
||||
const PLAYBACK_HEADERS = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/157.0.0.0 Safari/537.36',
|
||||
Origin: ORIGIN,
|
||||
Referer: `${ORIGIN}/`,
|
||||
};
|
||||
|
||||
const SERVERS = [
|
||||
{ key: 's1', label: 'Bloodstone', params: 'sources=s1&hevc=1' },
|
||||
{ key: 's2', label: 'Garnet', params: 'sources=s2&hevc=1&vh=1' },
|
||||
{ key: 's3', label: 'Ruby', params: 'sources=s3&hevc=1&vh=1' },
|
||||
{ key: 's4', label: 'Obsidian', params: 'sources=s4&sw=1' },
|
||||
{ key: 's5', label: 'Jet', params: 'sources=s5&hevc=1&vh=1' },
|
||||
];
|
||||
|
||||
function normalizeQuality(q) {
|
||||
if (!q) return '1080p';
|
||||
const str = String(q).trim();
|
||||
return /^\d+$/.test(str) ? `${str}p` : str;
|
||||
}
|
||||
|
||||
export async function getStream(args) {
|
||||
const { id, s, e } = args || {};
|
||||
if (!id) return null;
|
||||
|
||||
const isTv = s != null && e != null;
|
||||
const prefix = isTv
|
||||
? `tv?id=${id}&season=${s || 1}&episode=${e || 1}&mode=json`
|
||||
: `movie?id=${id}&mode=json`;
|
||||
|
||||
const responses = await Promise.allSettled(
|
||||
SERVERS.map(async (cfg) => {
|
||||
const url = `${BASE_URL}/${prefix}&${cfg.params}`;
|
||||
const res = await fetch(url, {
|
||||
headers: HEADERS,
|
||||
signal: AbortSignal.timeout(args?.config?.timeout || 10000),
|
||||
}).catch(() => null);
|
||||
|
||||
if (!res || !res.ok) return null;
|
||||
const data = await res.json().catch(() => null);
|
||||
if (!data?.source) return null;
|
||||
|
||||
return { cfg, data };
|
||||
})
|
||||
);
|
||||
|
||||
const allUrls = [];
|
||||
const seenUrls = new Set();
|
||||
|
||||
for (const r of responses) {
|
||||
if (r.status !== 'fulfilled' || !r.value?.data?.source) continue;
|
||||
const { cfg, data } = r.value;
|
||||
const src = data.source;
|
||||
const serverLabel = src.label || cfg.label;
|
||||
|
||||
if (src.manifest && typeof src.manifest === 'string') {
|
||||
const lines = src.manifest.split('\n').map(l => l.trim());
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i].startsWith('#EXT-X-STREAM-INF')) {
|
||||
const inf = lines[i];
|
||||
const streamUrl = lines[i + 1];
|
||||
if (streamUrl && streamUrl.startsWith('http') && !seenUrls.has(streamUrl)) {
|
||||
seenUrls.add(streamUrl);
|
||||
let quality = '1080p';
|
||||
const resMatch = inf.match(/RESOLUTION=\d+x(\d+)/i);
|
||||
if (resMatch) {
|
||||
quality = `${resMatch[1]}p`;
|
||||
}
|
||||
allUrls.push({
|
||||
url: streamUrl,
|
||||
server: `Vidqueen - ${serverLabel}`,
|
||||
quality,
|
||||
type: 'hls',
|
||||
headers: PLAYBACK_HEADERS,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(src.qualities) && src.qualities.some(q => q.type === 'mp4')) {
|
||||
for (const q of src.qualities) {
|
||||
if (!q?.url || seenUrls.has(q.url)) continue;
|
||||
seenUrls.add(q.url);
|
||||
allUrls.push({
|
||||
url: q.url,
|
||||
server: `Vidqueen - ${serverLabel}`,
|
||||
quality: normalizeQuality(q.quality),
|
||||
type: 'mp4',
|
||||
headers: PLAYBACK_HEADERS,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (src.url && (!src.qualities || !src.qualities.some(q => q.type === 'mp4')) && !src.manifest) {
|
||||
if (!seenUrls.has(src.url)) {
|
||||
seenUrls.add(src.url);
|
||||
let rawQuality = '1080p';
|
||||
if (src.h) {
|
||||
rawQuality = `${src.h}p`;
|
||||
} else if (src.qualities?.[0]?.quality && src.qualities[0].quality !== 'Auto') {
|
||||
rawQuality = src.qualities[0].quality;
|
||||
}
|
||||
allUrls.push({
|
||||
url: src.url,
|
||||
server: `Vidqueen - ${serverLabel}`,
|
||||
quality: normalizeQuality(rawQuality),
|
||||
type: src.url.includes('.m3u8') ? 'hls' : 'mp4',
|
||||
headers: PLAYBACK_HEADERS,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!allUrls.length) return null;
|
||||
|
||||
return {
|
||||
url: allUrls[0].url,
|
||||
headers: allUrls[0].headers,
|
||||
allUrls,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user