mirror of
https://gitlab.com/vyla-entertainment/sdk.git
synced 2026-11-13 21:57:27 -05:00
135 lines
4.0 KiB
JavaScript
135 lines
4.0 KiB
JavaScript
import { getTmdbMetadata, getUA, resolveTmdbKey } from '../utils/helpers.js';
|
|
|
|
const BASE_URL = 'https://dulo.mov';
|
|
|
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
async function fetchSource(url, headers) {
|
|
try {
|
|
const res = await fetch(url, {
|
|
headers,
|
|
signal: AbortSignal.timeout(8000),
|
|
});
|
|
if (!res.ok) return null;
|
|
return await res.json();
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function getStream(args) {
|
|
const { id, s, e, sdk } = args || {};
|
|
const isTv = s != null && e != null;
|
|
const mediaType = isTv ? 'tv' : 'movie';
|
|
const apiKey = resolveTmdbKey(args, sdk);
|
|
const ua = getUA();
|
|
|
|
const meta = await getTmdbMetadata(id, isTv, apiKey);
|
|
const title = meta?.title || '';
|
|
const year = meta?.year || '';
|
|
const runtime = meta?.runtime || '';
|
|
|
|
const referer = isTv
|
|
? `${BASE_URL}/watch/tv/${id}/${s}/${e}`
|
|
: `${BASE_URL}/watch/movie/${id}`;
|
|
|
|
const defaultHeaders = {
|
|
'User-Agent': ua,
|
|
Referer: referer,
|
|
Origin: BASE_URL,
|
|
Accept: '*/*',
|
|
'Sec-Fetch-Dest': 'empty',
|
|
'Sec-Fetch-Mode': 'cors',
|
|
'Sec-Fetch-Site': 'same-origin',
|
|
};
|
|
|
|
const baseParams = new URLSearchParams({
|
|
tmdbId: String(id),
|
|
type: mediaType,
|
|
});
|
|
|
|
const additionalParams = new URLSearchParams({
|
|
tmdbId: String(id),
|
|
type: mediaType,
|
|
progressive: 'true',
|
|
});
|
|
|
|
if (title) additionalParams.set('title', title);
|
|
if (year) additionalParams.set('year', String(year));
|
|
if (runtime) additionalParams.set('runtime', String(runtime));
|
|
|
|
if (isTv) {
|
|
baseParams.set('season', String(s));
|
|
baseParams.set('episode', String(e));
|
|
additionalParams.set('season', String(s));
|
|
additionalParams.set('episode', String(e));
|
|
}
|
|
|
|
const endpoints = [
|
|
`${BASE_URL}/api/sources?${baseParams.toString()}`,
|
|
`${BASE_URL}/api/sources/willow?${baseParams.toString()}`,
|
|
`${BASE_URL}/api/sources/additional?${additionalParams.toString()}`,
|
|
];
|
|
|
|
const seenUrls = new Set();
|
|
const allUrls = [];
|
|
|
|
let pendingUrls = [...endpoints];
|
|
const maxPollTime = Date.now() + 16000;
|
|
|
|
while (pendingUrls.length > 0 && Date.now() < maxPollTime) {
|
|
const results = await Promise.all(
|
|
pendingUrls.map(url => fetchSource(url, defaultHeaders))
|
|
);
|
|
|
|
const nextPending = [];
|
|
|
|
results.forEach((data, index) => {
|
|
if (!data) return;
|
|
|
|
if (Array.isArray(data.sources) && data.sources.length > 0) {
|
|
for (const src of data.sources) {
|
|
let streamUrl = String(src?.url || '').trim();
|
|
if (!streamUrl) continue;
|
|
|
|
if (streamUrl.startsWith('/')) {
|
|
streamUrl = `${BASE_URL}${streamUrl}`;
|
|
}
|
|
|
|
if (!streamUrl.startsWith('http') || seenUrls.has(streamUrl)) continue;
|
|
seenUrls.add(streamUrl);
|
|
|
|
allUrls.push({
|
|
url: streamUrl,
|
|
server: src.label || 'Dulo',
|
|
label: src.label || 'Dulo',
|
|
quality: 'Auto',
|
|
type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
|
|
headers: {
|
|
'User-Agent': ua,
|
|
Referer: referer,
|
|
},
|
|
captions: Array.isArray(src.captions) ? src.captions : [],
|
|
});
|
|
}
|
|
}
|
|
|
|
if (data.pending) {
|
|
nextPending.push(pendingUrls[index]);
|
|
}
|
|
});
|
|
|
|
pendingUrls = nextPending;
|
|
if (pendingUrls.length > 0) {
|
|
await sleep(1500);
|
|
}
|
|
}
|
|
|
|
if (allUrls.length === 0) return null;
|
|
|
|
return {
|
|
url: allUrls[0].url,
|
|
headers: allUrls[0].headers,
|
|
allUrls,
|
|
};
|
|
} |