Files
TV/.build/sdk/sources/vidapi.js

115 lines
3.7 KiB
JavaScript

import { fetchJson, USER_AGENT } from '../utils/helpers.js';
const API_BASE = 'https://streamdata.vaplayer.ru/api.php';
const EMBED_ORIGIN = 'https://nextgencloudfabric.com';
export const VERIFY_HEADERS = {
'User-Agent': USER_AGENT,
'Referer': `${EMBED_ORIGIN}/`,
'Origin': EMBED_ORIGIN
};
function extractStreamUrls(obj, urls = new Set()) {
if (!obj) return urls;
if (typeof obj === 'string') {
if (obj.startsWith('http') && (obj.includes('.m3u8') || obj.includes('.mp4') || obj.includes('.mpd'))) {
urls.add(obj);
}
} else if (Array.isArray(obj)) {
for (const item of obj) extractStreamUrls(item, urls);
} else if (typeof obj === 'object') {
for (const val of Object.values(obj)) {
extractStreamUrls(val, urls);
}
}
return urls;
}
export async function getStream({ id, s, e }) {
try {
const isTv = s != null && e != null;
const type = isTv ? 'tv' : 'movie';
const url = `${API_BASE}?tmdb=${id}&type=${type}${isTv ? `&season=${s}&episode=${e}` : ''}`;
const data = await fetchJson(url, {
headers: {
'Accept': '*/*',
'Origin': EMBED_ORIGIN,
'Referer': `${EMBED_ORIGIN}/`,
'User-Agent': USER_AGENT
},
signal: AbortSignal.timeout(10000)
});
const streamUrls = Array.from(extractStreamUrls(data));
if (!streamUrls.length) return null;
let subs = [];
if (data.subtitles && Array.isArray(data.subtitles)) {
subs = data.subtitles;
} else if (data.captions && Array.isArray(data.captions)) {
subs = data.captions;
}
const subtitles = subs.map(sub => ({
url: sub.url || sub.file || sub.src,
lang: sub.display || sub.label || sub.language || sub.lang || 'Unknown'
})).filter(s => s.url);
const allUrls = streamUrls.map(streamUrl => {
let type = 'mp4';
if (streamUrl.includes('.mpd')) type = 'dash';
else if (streamUrl.includes('.m3u8')) type = 'hls';
return {
url: streamUrl,
server: 'VidAPI',
quality: 'Auto',
type,
headers: VERIFY_HEADERS,
subtitles: subtitles.length > 0 ? subtitles : undefined,
skipProxy: false
};
});
return allUrls.length ? { allUrls } : null;
} catch {
return null;
}
}
export async function getSources() {
return ['VidAPI'];
}
export async function proxyStream({ url, res, proxyUtils: { fetchUpstream, rewriteM3u8 } }) {
try {
const upstream = await fetchUpstream(url, 0, VERIFY_HEADERS);
if (!upstream) return res.end();
const ct = (upstream.headers?.['content-type'] || '').toLowerCase();
const isM3u8 = ct.includes('mpegurl') || ct.includes('m3u8') || /\.m3u8?(\?|$)/i.test(url);
if (isM3u8) {
const chunks = [];
for await (const c of upstream) chunks.push(c);
let body = Buffer.concat(chunks).toString('utf8');
res.setHeader('Content-Type', 'application/vnd.apple.mpegurl');
res.setHeader('Access-Control-Allow-Origin', '*');
return res.end(rewriteM3u8(body, url, '&va=1&tt=1'));
}
res.setHeader('Content-Type', ct || 'application/octet-stream');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Cache-Control', 'public, max-age=3600');
upstream.pipe(res);
} catch {
if (!res.headersSent) {
res.statusCode = 502;
res.end();
}
}
}