mirror of
https://gitlab.com/vyla-entertainment/sdk.git
synced 2026-11-09 19:57:23 -05:00
Fixed Vidzee, Added Luna, and Rivestream
This commit is contained in:
@@ -230,6 +230,32 @@ export const SOURCES = [
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
key: 'luna-sub',
|
||||
label: 'Luna (Sub)',
|
||||
sourceFile: 'luna',
|
||||
proxyParam: 'lusub',
|
||||
subtype: 'sub',
|
||||
timeout: 25000,
|
||||
jitter: 500,
|
||||
retries: 2,
|
||||
multiUrl: true,
|
||||
skipProxy: true,
|
||||
},
|
||||
|
||||
{
|
||||
key: 'luna-dub',
|
||||
label: 'Luna (Dub)',
|
||||
sourceFile: 'luna',
|
||||
proxyParam: 'ludub',
|
||||
subtype: 'dub',
|
||||
timeout: 25000,
|
||||
jitter: 500,
|
||||
retries: 2,
|
||||
multiUrl: true,
|
||||
skipProxy: true,
|
||||
},
|
||||
|
||||
{
|
||||
key: 'mapple',
|
||||
label: 'Mapple',
|
||||
@@ -288,6 +314,17 @@ export const SOURCES = [
|
||||
skipProxy: true
|
||||
},
|
||||
|
||||
{
|
||||
key: 'rivestream',
|
||||
label: 'RiveStream',
|
||||
sourceFile: 'rivestream',
|
||||
proxyParam: 'rs',
|
||||
timeout: 30000,
|
||||
jitter: 500,
|
||||
retries: 2,
|
||||
multiUrl: true,
|
||||
},
|
||||
|
||||
{
|
||||
key: 'vidapi',
|
||||
label: 'VidAPI',
|
||||
@@ -478,7 +515,6 @@ export const SOURCES = [
|
||||
Referer: 'https://player.vidzee.wtf',
|
||||
Origin: 'https://player.vidzee.wtf',
|
||||
},
|
||||
disabled: true // Disabled temporarily due to decryption issues
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
125
src/sources/luna.js
Normal file
125
src/sources/luna.js
Normal file
@@ -0,0 +1,125 @@
|
||||
import { USER_AGENT, fetchText, getTmdbInfo, tmdbToAnilist } from '../utils/helpers.js';
|
||||
|
||||
const ACTION_FETCH_SOURCES = 'afb0491c5516f9fff5fcb464d627638df76062f8';
|
||||
const WATCH_URL = 'https://luna-stream.me/anime/watch/21/gogoanime/1';
|
||||
|
||||
const PROVIDERS = [
|
||||
{ id: 'megaplay', name: 'Helios' },
|
||||
{ id: 'anibd', name: 'Nova' },
|
||||
{ id: 'pahe', name: 'Polaris' },
|
||||
{ id: 'gogoanime', name: 'Quasar' },
|
||||
{ id: 'zoro', name: 'Zenith' },
|
||||
{ id: 'animepahe', name: 'Vega' },
|
||||
{ id: 'animekai', name: 'Cosmos' },
|
||||
{ id: 'crysoline', name: 'CrysOline' },
|
||||
{ id: 'orion', name: 'Orion' },
|
||||
{ id: 'pulsar', name: 'Pulsar' }
|
||||
];
|
||||
|
||||
function parseRscResponse(text) {
|
||||
for (const line of text.split('\n')) {
|
||||
if (line.startsWith('1:')) {
|
||||
try {
|
||||
return JSON.parse(line.slice(2));
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function cleanUrl(rawUrl) {
|
||||
if (!rawUrl) return '';
|
||||
return rawUrl.replace(/^https:\/\/api\.luna-stream\.mehttps:\/\/api\.luna-stream\.me/, 'https://api.luna-stream.me');
|
||||
}
|
||||
|
||||
async function fetchProviderStreams(anilistId, epNum, provider, subtype) {
|
||||
try {
|
||||
const text = await fetchText(WATCH_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'User-Agent': USER_AGENT,
|
||||
'Next-Action': ACTION_FETCH_SOURCES,
|
||||
'Content-Type': 'text/plain;charset=UTF-8',
|
||||
'Accept': 'text/x-component',
|
||||
'Referer': WATCH_URL,
|
||||
'Origin': 'https://luna-stream.me'
|
||||
},
|
||||
body: JSON.stringify([anilistId, provider.id, String(epNum), epNum, subtype, null]),
|
||||
signal: AbortSignal.timeout(10000)
|
||||
});
|
||||
|
||||
if (!text) return [];
|
||||
|
||||
const parsed = parseRscResponse(text);
|
||||
if (!parsed || !Array.isArray(parsed.sources)) return [];
|
||||
|
||||
const streams = [];
|
||||
for (const s of parsed.sources) {
|
||||
if (!s || !s.url) continue;
|
||||
|
||||
const url = cleanUrl(s.url);
|
||||
const format = String(s.type || '').toLowerCase();
|
||||
const isM3U8 = format === 'hls' || format === 'm3u8' || url.includes('.m3u8') || url.includes('.txt');
|
||||
|
||||
streams.push({
|
||||
url,
|
||||
server: `Luna (${provider.name})`,
|
||||
quality: String(s.quality || 'Auto'),
|
||||
type: isM3U8 ? 'hls' : 'mp4',
|
||||
headers: {
|
||||
'User-Agent': USER_AGENT,
|
||||
'Referer': 'https://luna-stream.me/'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return streams;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStream(args) {
|
||||
const { id, s, e, ep, audio, server, tmdbApiKey } = args;
|
||||
const isTv = s != null && e != null;
|
||||
const mediaType = isTv ? 'tv' : 'movie';
|
||||
|
||||
let anilistId = null;
|
||||
try {
|
||||
const info = await getTmdbInfo(tmdbApiKey, id, mediaType, s);
|
||||
anilistId = await tmdbToAnilist(id, mediaType, s, info?.titles || [], info?.year);
|
||||
} catch { }
|
||||
|
||||
if (!anilistId) {
|
||||
anilistId = Number(id);
|
||||
}
|
||||
|
||||
if (!anilistId || isNaN(anilistId)) return null;
|
||||
|
||||
const epNum = Number(e || ep || 1);
|
||||
const resolvedSubtype = audio === 'dub' ? 'dub' : 'sub';
|
||||
|
||||
let targets = PROVIDERS;
|
||||
if (server && server !== 'all') {
|
||||
const clean = server.toLowerCase().replace('luna (', '').replace(')', '').replace('luna', '').trim();
|
||||
targets = PROVIDERS.filter(p => p.id.toLowerCase() === clean || p.name.toLowerCase().includes(clean));
|
||||
if (!targets.length) targets = PROVIDERS;
|
||||
}
|
||||
|
||||
const settled = await Promise.allSettled(
|
||||
targets.map(p => fetchProviderStreams(anilistId, epNum, p, resolvedSubtype))
|
||||
);
|
||||
|
||||
const allUrls = [];
|
||||
for (const r of settled) {
|
||||
if (r.status === 'fulfilled' && Array.isArray(r.value)) {
|
||||
allUrls.push(...r.value);
|
||||
}
|
||||
}
|
||||
|
||||
return allUrls.length ? { allUrls } : null;
|
||||
}
|
||||
|
||||
export async function getSources() {
|
||||
return PROVIDERS.map(p => `Luna (${p.name})`);
|
||||
}
|
||||
179
src/sources/rivestream.js
Normal file
179
src/sources/rivestream.js
Normal file
@@ -0,0 +1,179 @@
|
||||
// im being salty
|
||||
|
||||
import { USER_AGENT, fetchJson } from '../utils/helpers.js';
|
||||
|
||||
const C_ARRAY = [
|
||||
'4Z7lUo', 'gwIVSMD', 'PLmz2elE2v', 'Z4OFV0', 'SZ6RZq6Zc', 'zhJEFYxrz8', 'FOm7b0', 'axHS3q4KDq', 'o9zuXQ', '4Aebt',
|
||||
'wgjjWwKKx', 'rY4VIxqSN', 'kfjbnSo', '2DyrFA1M', 'YUixDM9B', 'JQvgEj0', 'mcuFx6JIek', 'eoTKe26gL', 'qaI9EVO1rB', '0xl33btZL',
|
||||
'1fszuAU', 'a7jnHzst6P', 'wQuJkX', 'cBNhTJlEOf', 'KNcFWhDvgT', 'XipDGjST', 'PCZJlbHoyt', '2AYnMZkqd', 'HIpJh', 'KH0C3iztrG',
|
||||
'W81hjts92', 'rJhAT', 'NON7LKoMQ', 'NMdY3nsKzI', 't4En5v', 'Qq5cOQ9H', 'Y9nwrp', 'VX5FYVfsf', 'cE5SJG', 'x1vj1',
|
||||
'HegbLe', 'zJ3nmt4OA', 'gt7rxW57dq', 'clIE9b', 'jyJ9g', 'B5jXjMCSx', 'cOzZBZTV', 'FTXGy', 'Dfh1q1', 'ny9jqZ2POI',
|
||||
'X2NnMn', 'MBtoyD', 'qz4Ilys7wB', '68lbOMye', '3YUJnmxp', '1fv5Imona', 'PlfvvXD7mA', 'ZarKfHCaPR', 'owORnX', 'dQP1YU',
|
||||
'dVdkx', 'qgiK0E', 'cx9wQ', '5F9bGa', '7UjkKrp', 'Yvhrj', 'wYXez5Dg3', 'pG4GMU', 'MwMAu', 'rFRD5wlM'
|
||||
];
|
||||
|
||||
const DEFAULT_SERVICES = [
|
||||
'apex', 'pulse', 'solstice', 'quasar', 'horizon', 'primevids',
|
||||
'flowcast', 'asiacloud', 'citadel', 'hindicast', 'guru'
|
||||
];
|
||||
|
||||
function generateRiveSecretKey(e) {
|
||||
if (e === undefined || e === null) return 'rive';
|
||||
try {
|
||||
let t, n;
|
||||
const r = String(e);
|
||||
if (isNaN(Number(e))) {
|
||||
const sum = r.split('').reduce((acc, ch) => acc + ch.charCodeAt(0), 0);
|
||||
t = C_ARRAY[sum % C_ARRAY.length] || Buffer.from(r).toString('base64');
|
||||
n = Math.floor((sum % r.length) / 2);
|
||||
} else {
|
||||
const i = Number(e);
|
||||
t = C_ARRAY[i % C_ARRAY.length] || Buffer.from(r).toString('base64');
|
||||
n = Math.floor((i % r.length) / 2);
|
||||
}
|
||||
const i = r.slice(0, n) + t + r.slice(n);
|
||||
const o = (function (str) {
|
||||
const t = String(str);
|
||||
let n = 3735928559 ^ t.length;
|
||||
for (let e = 0; e < t.length; e++) {
|
||||
const r = t.charCodeAt(e);
|
||||
const rXor = (131 * e + 89 ^ (r << (e % 5))) & 255;
|
||||
const r2 = r ^ rXor;
|
||||
n = (((n << 7) | (n >>> 25)) >>> 0) ^ r2;
|
||||
const idx = (65535 & n) * 60205;
|
||||
const o2 = ((n >>> 16) * 60205) << 16;
|
||||
n = (idx + o2) >>> 0;
|
||||
n ^= n >>> 11;
|
||||
}
|
||||
n ^= n >>> 15;
|
||||
n = ((65535 & n) * 49842 + (((n >>> 16) * 49842) << 16)) >>> 0;
|
||||
n ^= n >>> 13;
|
||||
n = ((65535 & n) * 40503 + (((n >>> 16) * 40503) << 16)) >>> 0;
|
||||
n ^= n >>> 16;
|
||||
n = ((65535 & n) * 10196 + (((n >>> 16) * 10196) << 16)) >>> 0;
|
||||
return ((n ^= n >>> 15)).toString(16).padStart(8, '0');
|
||||
})(
|
||||
(function (str) {
|
||||
const s = String(str);
|
||||
let t = 0;
|
||||
for (let n = 0; n < s.length; n++) {
|
||||
const r = s.charCodeAt(n);
|
||||
const i = (((t = (r + (t << 6) + (t << 16) - t) >>> 0) << (n % 5)) | (t >>> (32 - (n % 5)))) >>> 0;
|
||||
t ^= (i ^ ((r << (n % 7)) | (r >>> (8 - (n % 7))))) >>> 0;
|
||||
t = (t + ((t >>> 11) ^ (t << 3))) >>> 0;
|
||||
}
|
||||
t ^= t >>> 15;
|
||||
t = ((65535 & t) * 49842 + ((((t >>> 16) * 49842) & 65535) << 16)) >>> 0;
|
||||
t ^= t >>> 13;
|
||||
t = ((65535 & t) * 40503 + ((((t >>> 16) * 40503) & 65535) << 16)) >>> 0;
|
||||
return ((t ^= t >>> 16)).toString(16).padStart(8, '0');
|
||||
})(i)
|
||||
);
|
||||
return Buffer.from(o, 'utf-8').toString('base64');
|
||||
} catch {
|
||||
return 'topSecret';
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchRiveServices() {
|
||||
try {
|
||||
const secretKey = generateRiveSecretKey();
|
||||
const url = `https://www.rivestream.app/api/backendfetch?requestID=VideoProviderServices&secretKey=${encodeURIComponent(secretKey)}`;
|
||||
const res = await fetchJson(url, {
|
||||
headers: {
|
||||
'User-Agent': USER_AGENT,
|
||||
'Referer': 'https://www.rivestream.app/',
|
||||
'Accept': 'application/json, text/plain, */*'
|
||||
},
|
||||
signal: AbortSignal.timeout(6000)
|
||||
});
|
||||
return Array.isArray(res?.data) && res.data.length ? res.data : DEFAULT_SERVICES;
|
||||
} catch {
|
||||
return DEFAULT_SERVICES;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchServiceStreams(service, isMovie, id, s, e, secretKey, referer) {
|
||||
try {
|
||||
const cb = (service === 'primevids' || service === 'citadel')
|
||||
? `&cb=${Math.floor(Date.now() / 3e6)}`
|
||||
: '';
|
||||
|
||||
const reqID = isMovie ? 'movieVideoProvider' : 'tvVideoProvider';
|
||||
const params = isMovie
|
||||
? `requestID=${reqID}&id=${encodeURIComponent(id)}&service=${service}${cb}&secretKey=${encodeURIComponent(secretKey)}`
|
||||
: `requestID=${reqID}&id=${encodeURIComponent(id)}&season=${encodeURIComponent(s)}&episode=${encodeURIComponent(e)}&service=${service}${cb}&secretKey=${encodeURIComponent(secretKey)}`;
|
||||
|
||||
const url = `https://www.rivestream.app/api/backendfetch?${params}`;
|
||||
const res = await fetchJson(url, {
|
||||
headers: {
|
||||
'User-Agent': USER_AGENT,
|
||||
'Referer': referer,
|
||||
'Accept': 'application/json, text/plain, */*'
|
||||
},
|
||||
signal: AbortSignal.timeout(10000)
|
||||
});
|
||||
|
||||
if (!res?.data?.sources || !Array.isArray(res.data.sources)) return [];
|
||||
|
||||
const streams = [];
|
||||
for (const item of res.data.sources) {
|
||||
if (!item || !item.url) continue;
|
||||
|
||||
const format = String(item.format || '').toLowerCase();
|
||||
const urlStr = String(item.url || '').toLowerCase();
|
||||
const isM3U8 = format === 'hls' || format === 'm3u8' || urlStr.includes('.m3u8') || urlStr.includes('.txt');
|
||||
|
||||
streams.push({
|
||||
url: item.url,
|
||||
server: `Rive (${item.source || service})`,
|
||||
quality: String(item.quality || 'Auto'),
|
||||
type: isM3U8 ? 'hls' : 'mp4',
|
||||
headers: {
|
||||
'User-Agent': USER_AGENT,
|
||||
'Referer': referer
|
||||
}
|
||||
});
|
||||
}
|
||||
return streams;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStream(args) {
|
||||
const { id, s, e, server } = args;
|
||||
const isTv = s != null && e != null;
|
||||
const isMovie = !isTv;
|
||||
|
||||
const secretKey = generateRiveSecretKey(id);
|
||||
const referer = isMovie
|
||||
? `https://www.rivestream.app/watch?type=movie&id=${id}`
|
||||
: `https://www.rivestream.app/watch?type=tv&id=${id}&season=${s}&episode=${e}`;
|
||||
|
||||
let services = await fetchRiveServices();
|
||||
|
||||
if (server && server !== 'all') {
|
||||
const clean = server.toLowerCase().replace('rive (', '').replace(')', '').replace('rive', '').trim();
|
||||
services = services.filter(srv => srv.toLowerCase().includes(clean));
|
||||
if (!services.length) services = await fetchRiveServices();
|
||||
}
|
||||
|
||||
const settled = await Promise.allSettled(
|
||||
services.map(srv => fetchServiceStreams(srv, isMovie, id, s, e, secretKey, referer))
|
||||
);
|
||||
|
||||
const allUrls = [];
|
||||
for (const r of settled) {
|
||||
if (r.status === 'fulfilled' && Array.isArray(r.value)) {
|
||||
allUrls.push(...r.value);
|
||||
}
|
||||
}
|
||||
|
||||
return allUrls.length ? { allUrls } : null;
|
||||
}
|
||||
|
||||
export async function getSources() {
|
||||
const services = await fetchRiveServices();
|
||||
return services.map(s => `Rive (${s})`);
|
||||
}
|
||||
@@ -1,106 +1,184 @@
|
||||
// i can't fix this, i'll wait for someone else to fix this lol
|
||||
import { USER_AGENT, fetchJson } from '../utils/helpers.js';
|
||||
|
||||
import crypto from 'node:crypto';
|
||||
import { fetchJson, USER_AGENT } from '../utils/helpers.js';
|
||||
|
||||
const CORE_URL = 'https://core.vidzee.wtf';
|
||||
const BASE_URL = 'https://core.vidzee.wtf';
|
||||
const PLAYER_URL = 'https://player.vidzee.wtf';
|
||||
const KEY = 'c4a8f1d7e2b9a6c3d0f5e8a1b7c4d9e2';
|
||||
const SERVICES = ['dcloud', 'ipcloud', 'tik', 'v6:Hindi', '3AHindi'];
|
||||
const WASM_B64 = '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';
|
||||
|
||||
function decryptAes(encryptedBase64) {
|
||||
const keyBuf = Buffer.from(KEY, 'utf8');
|
||||
const ciphertext = Buffer.from(encryptedBase64, 'base64');
|
||||
let wasmInstanceCache = null;
|
||||
|
||||
async function getWasmInstance() {
|
||||
if (wasmInstanceCache) return wasmInstanceCache;
|
||||
try {
|
||||
const decipher = crypto.createDecipheriv('aes-256-ecb', keyBuf, null);
|
||||
decipher.setAutoPadding(true);
|
||||
let dec = decipher.update(ciphertext);
|
||||
dec = Buffer.concat([dec, decipher.final()]);
|
||||
const text = dec.toString('utf8');
|
||||
if (text.startsWith('http') || text.includes('{')) return text;
|
||||
} catch { }
|
||||
const wasmBuffer = Buffer.from(WASM_B64, 'base64');
|
||||
const wasmModule = await WebAssembly.compile(wasmBuffer);
|
||||
|
||||
let memory;
|
||||
let exports;
|
||||
|
||||
const env = {
|
||||
abort() {
|
||||
throw new Error('WASM abort');
|
||||
}
|
||||
};
|
||||
|
||||
const res = await WebAssembly.instantiate(wasmModule, { env });
|
||||
exports = res.exports;
|
||||
memory = exports.memory;
|
||||
|
||||
const refMap = new Map();
|
||||
function pin(ptr) {
|
||||
if (ptr) {
|
||||
const count = refMap.get(ptr);
|
||||
if (count) refMap.set(ptr, count + 1);
|
||||
else refMap.set(exports.__pin(ptr), 1);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
function unpin(ptr) {
|
||||
if (ptr) {
|
||||
const count = refMap.get(ptr);
|
||||
if (count === 1) {
|
||||
exports.__unpin(ptr);
|
||||
refMap.delete(ptr);
|
||||
} else if (count) {
|
||||
refMap.set(ptr, count - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wasmInstanceCache = {
|
||||
decrypt(encryptedBytes, keyStr) {
|
||||
let dataPtr = 0;
|
||||
let keyPtr = 0;
|
||||
try {
|
||||
const len = encryptedBytes.length;
|
||||
const pinPtr = exports.__pin(exports.__new(len, 1)) >>> 0;
|
||||
dataPtr = exports.__new(12, 6) >>> 0;
|
||||
|
||||
const view = new DataView(memory.buffer);
|
||||
view.setUint32(dataPtr, pinPtr, true);
|
||||
view.setUint32(dataPtr + 4, pinPtr, true);
|
||||
view.setUint32(dataPtr + 8, len, true);
|
||||
new Uint8Array(memory.buffer, pinPtr, len).set(encryptedBytes);
|
||||
exports.__unpin(pinPtr);
|
||||
|
||||
pin(dataPtr);
|
||||
|
||||
const kLen = keyStr.length;
|
||||
keyPtr = exports.__new(kLen << 1, 2) >>> 0;
|
||||
const u16View = new Uint16Array(memory.buffer);
|
||||
for (let i = 0; i < kLen; i++) {
|
||||
u16View[(keyPtr >>> 1) + i] = keyStr.charCodeAt(i);
|
||||
}
|
||||
|
||||
const resPtr = exports.decrypt(dataPtr, keyPtr) >>> 0;
|
||||
if (!resPtr) return new Uint8Array(0);
|
||||
|
||||
const resView = new DataView(memory.buffer);
|
||||
const outPtr = resView.getUint32(resPtr + 4, true);
|
||||
const outLen = resView.getUint32(resPtr + 8, true);
|
||||
return new Uint8Array(memory.buffer, outPtr, outLen).slice();
|
||||
} finally {
|
||||
unpin(dataPtr);
|
||||
}
|
||||
}
|
||||
};
|
||||
return wasmInstanceCache;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function requestEndpoint(url, headers) {
|
||||
try {
|
||||
const iv = Buffer.alloc(16, 0);
|
||||
const decipher = crypto.createDecipheriv('aes-256-cbc', keyBuf, iv);
|
||||
decipher.setAutoPadding(true);
|
||||
let dec = decipher.update(ciphertext);
|
||||
dec = Buffer.concat([dec, decipher.final()]);
|
||||
const text = dec.toString('utf8');
|
||||
if (text.startsWith('http') || text.includes('{')) return text;
|
||||
} catch { }
|
||||
return await fetchJson(url, {
|
||||
headers,
|
||||
signal: AbortSignal.timeout(6000)
|
||||
});
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const iv = ciphertext.subarray(0, 16);
|
||||
const data = ciphertext.subarray(16);
|
||||
const decipher = crypto.createDecipheriv('aes-256-cbc', keyBuf, iv);
|
||||
decipher.setAutoPadding(true);
|
||||
let dec = decipher.update(data);
|
||||
dec = Buffer.concat([dec, decipher.final()]);
|
||||
const text = dec.toString('utf8');
|
||||
if (text.startsWith('http') || text.includes('{')) return text;
|
||||
} catch { }
|
||||
async function resolveServiceStream(service, isMovie, id, s, e, headers) {
|
||||
const directEndpoint = isMovie
|
||||
? `${BASE_URL}/streams/movie/${id}?s=${service}`
|
||||
: `${BASE_URL}/streams/tv/${id}/${s || 1}/${e || 1}?s=${service}`;
|
||||
|
||||
let res = await requestEndpoint(directEndpoint, headers);
|
||||
|
||||
if (!res || !res.url) {
|
||||
const encEndpoint = `${directEndpoint}&e=1`;
|
||||
const encRes = await requestEndpoint(encEndpoint, headers);
|
||||
|
||||
if (encRes && encRes.c) {
|
||||
const instance = await getWasmInstance();
|
||||
if (instance) {
|
||||
const encryptedBytes = new Uint8Array(Buffer.from(encRes.c, 'base64'));
|
||||
const decryptedBytes = instance.decrypt(encryptedBytes, 'player.vidzee.wtf');
|
||||
if (decryptedBytes.length > 0) {
|
||||
const str = new TextDecoder().decode(decryptedBytes);
|
||||
try {
|
||||
res = JSON.parse(str);
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res && res.url) {
|
||||
const format = res.url.includes('.m3u8') ? 'hls' : 'mp4';
|
||||
return {
|
||||
url: res.url,
|
||||
server: `VidZee (${service})`,
|
||||
quality: res.language || 'Auto',
|
||||
type: format,
|
||||
headers: {
|
||||
'User-Agent': USER_AGENT,
|
||||
'Referer': `${PLAYER_URL}/`,
|
||||
'Origin': PLAYER_URL,
|
||||
...(res.headers || {})
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function getStream({ id, s, e, clientIP }) {
|
||||
export async function getStream(args) {
|
||||
const { id, s, e, server, clientIP } = args;
|
||||
const isTv = s != null && e != null;
|
||||
const isMovie = !isTv;
|
||||
|
||||
const headers = {
|
||||
'User-Agent': USER_AGENT,
|
||||
'Accept': 'application/json',
|
||||
'Referer': PLAYER_URL,
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'Referer': `${PLAYER_URL}/`,
|
||||
'Origin': PLAYER_URL,
|
||||
...(clientIP && { 'X-Forwarded-For': clientIP })
|
||||
};
|
||||
|
||||
try {
|
||||
const isTv = s != null && e != null;
|
||||
const servers = ['tik', 'ipcloud', 'v6:Hindi'];
|
||||
const results = [];
|
||||
|
||||
for (const sr of servers) {
|
||||
try {
|
||||
const url = isTv
|
||||
? `${CORE_URL}/streams/tv/${id}/${s}/${e}?s=${encodeURIComponent(sr)}&e=${e}`
|
||||
: `${CORE_URL}/streams/movie/${id}?s=${encodeURIComponent(sr)}&e=1`;
|
||||
|
||||
const data = await fetchJson(url, { headers, signal: AbortSignal.timeout(6000) });
|
||||
|
||||
if (data && data.c) {
|
||||
const decryptedText = decryptAes(data.c);
|
||||
if (decryptedText) {
|
||||
let streamUrl = decryptedText;
|
||||
let extraHeaders = {};
|
||||
|
||||
if (decryptedText.startsWith('{')) {
|
||||
try {
|
||||
const parsed = JSON.parse(decryptedText);
|
||||
streamUrl = parsed.url || parsed.link || parsed.file;
|
||||
if (parsed.headers) extraHeaders = parsed.headers;
|
||||
} catch { }
|
||||
}
|
||||
|
||||
if (streamUrl && streamUrl.startsWith('http')) {
|
||||
results.push({
|
||||
url: streamUrl,
|
||||
server: `VidZee - ${sr}`,
|
||||
skipHlsCheck: true,
|
||||
headers: {
|
||||
'User-Agent': USER_AGENT,
|
||||
'Referer': PLAYER_URL,
|
||||
'Origin': PLAYER_URL,
|
||||
...extraHeaders
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
}
|
||||
}
|
||||
|
||||
return results.length ? { allUrls: results } : null;
|
||||
} catch {
|
||||
return null;
|
||||
let targets = SERVICES;
|
||||
if (server && server !== 'all') {
|
||||
const clean = server.toLowerCase().replace('vidzee (', '').replace(')', '').replace('vidzee', '').trim();
|
||||
targets = SERVICES.filter(srv => srv.toLowerCase().includes(clean));
|
||||
if (!targets.length) targets = SERVICES;
|
||||
}
|
||||
|
||||
const settled = await Promise.allSettled(
|
||||
targets.map(service => resolveServiceStream(service, isMovie, id, s, e, headers))
|
||||
);
|
||||
|
||||
const allUrls = [];
|
||||
for (const r of settled) {
|
||||
if (r.status === 'fulfilled' && r.value) {
|
||||
allUrls.push(r.value);
|
||||
}
|
||||
}
|
||||
|
||||
return allUrls.length ? { allUrls } : null;
|
||||
}
|
||||
|
||||
export async function getSources() {
|
||||
return SERVICES.map(s => `VidZee (${s})`);
|
||||
}
|
||||
Reference in New Issue
Block a user