removed a lot of sources, added one

This commit is contained in:
2026-10-02 17:05:21 -07:00
parent 3335ab6daf
commit e36d96a34d
20 changed files with 163 additions and 2533 deletions

View File

@@ -6,18 +6,6 @@
// Fshare/Fsonic Tested: 155 ( they don't have Michael )
export const SOURCES = [
{
key: '4khdhub',
label: '4KHDHub',
sourceFile: '4khdhub',
proxyParam: 'khd',
timeout: 35000,
jitter: 500,
retries: 1,
multiUrl: true,
skipProxy: true,
},
{
key: '123anime',
label: '123Anime',
@@ -119,72 +107,20 @@ export const SOURCES = [
},
{
key: 'cinejoy',
label: 'Cinejoy',
sourceFile: 'cinejoy',
proxyParam: 'cj',
timeout: 30000,
jitter: 500,
retries: 1,
multiUrl: true,
skipProxy: true,
},
{
key: 'cinesrc',
label: 'CineSrc',
sourceFile: 'cinesrc',
proxyParam: 'csr',
key: 'dulo',
label: 'Dulo',
sourceFile: 'dulo',
proxyParam: 'dl',
timeout: 25000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
skipVerify: true,
cdnHeaders: [{
pattern: /glendale-plumbing\.com|1embed\.cc|bright\d+\.online/i,
pattern: /dulo\.mov/i,
headers: {
Referer: 'https://cinesrc.st/',
Origin: 'https://cinesrc.st',
},
}],
},
{
key: 'cinesu',
label: 'CineSu',
sourceFile: 'cinesu',
proxyParam: 'cs',
timeout: 25000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
skipVerify: true,
cdnHeaders: [{
pattern: /glendale-plumbing\.com/i,
headers: {
Referer: 'https://cine.su/',
Origin: 'https://cine.su',
},
}],
},
{
key: 'downloadeverything',
label: 'DownloadEverything',
sourceFile: 'downloadeverything',
proxyParam: 'de',
timeout: 35000,
jitter: 500,
retries: 1,
multiUrl: true,
skipProxy: true,
cdnHeaders: [{
pattern: /cloudflarestorage\.com|pixeldrain\.com|hakunaymatata\.com/i,
headers: {
Referer: 'https://downloadeverythingfromeverywhere.com/',
Origin: 'https://downloadeverythingfromeverywhere.com',
Referer: 'https://dulo.mov/',
Origin: 'https://dulo.mov',
},
}],
},
@@ -208,45 +144,6 @@ export const SOURCES = [
},],
},
{
key: 'frame',
label: 'Frame',
sourceFile: 'frame',
proxyParam: 'fr',
timeout: 25000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
},
{
key: 'fsharetv',
label: 'FShareTV',
sourceFile: 'fsharetv',
proxyParam: 'fs',
timeout: 25000,
jitter: 600,
retries: 2,
multiUrl: false,
verifyHeaders: {
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
Referer: 'https://fsharetv.cc',
},
},
{
key: 'fsonic',
label: 'Fsonic',
sourceFile: 'fsonic',
proxyParam: 'fn',
timeout: 35000,
jitter: 600,
retries: 1,
multiUrl: true,
},
{
key: 'fsonline',
label: 'FSOnline',
@@ -259,16 +156,6 @@ export const SOURCES = [
skipProxy: true,
},
{
key: 'hexa',
label: 'Hexa',
sourceFile: 'hexa',
proxyParam: 'hx',
timeout: 20000,
jitter: 500,
retries: 2,
},
{
key: 'kisskh',
label: 'KissKH',
@@ -304,44 +191,6 @@ 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: 'meowtv',
label: 'MeowTV',
sourceFile: 'meowtv',
proxyParam: 'mt',
timeout: 20000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true
},
{
key: 'movienight',
label: 'MovieNight',
@@ -380,18 +229,6 @@ export const SOURCES = [
}],
},
{
key: 'peestream',
label: 'PeeStream',
sourceFile: 'peestream',
proxyParam: 'pee',
timeout: 25000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
},
{
key: 'pengu',
label: 'Pengu',
@@ -456,26 +293,6 @@ export const SOURCES = [
},
}],
},
{
key: 'vadapav',
label: 'Vadapav',
sourceFile: 'vadapav',
proxyParam: 'vp',
timeout: 25000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
cdnHeaders: [{
pattern: /vadapav\.mov/i,
headers: {
Referer: 'https://stremio.vadapav.mov/',
Origin: 'https://stremio.vadapav.mov',
},
}],
},
{
key: 'vidapi',
label: 'VidAPI',
@@ -487,27 +304,6 @@ export const SOURCES = [
multiUrl: true
},
{
key: 'vidcore',
sourceFile: 'vidcore',
label: 'Vidcore',
proxyParam: 'vc',
timeout: 30000,
jitter: 500,
retries: 2,
sourcesTimeout: 10000,
},
{
key: 'vidfast',
label: 'Vidfast',
sourceFile: 'vidfast',
proxyParam: 'vf',
timeout: 35000,
jitter: 500,
retries: 1,
},
{
key: 'vidgod',
label: 'VidGod',
@@ -644,25 +440,6 @@ export const SOURCES = [
},
},
{
key: 'vuflix',
label: 'Vuflix',
sourceFile: 'vuflix',
proxyParam: 'vfx',
timeout: 25000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
cdnHeaders: [{
pattern: /vuflix\.co/i,
headers: {
Referer: 'https://vuflix.co/',
Origin: 'https://vuflix.co',
},
}],
},
{
key: 'xdownloader',
label: 'XDownloader',

View File

@@ -1,324 +0,0 @@
import { getUA } from '../utils/helpers.js';
const INITIAL_BASE_URL = 'https://4khdhub.one';
let cachedBaseUrl = null;
let cachedBaseUrlExpiry = 0;
function rot13(str) {
return str.replace(/[a-zA-Z]/g, (c) => {
const code = c.charCodeAt(0);
if (code >= 65 && code <= 90) {
return String.fromCharCode(((code - 65 + 13) % 26) + 65);
}
return String.fromCharCode(((code - 97 + 13) % 26) + 97);
});
}
function levenshtein(a, b) {
if (a === b) return 0;
if (!a.length) return b.length;
if (!b.length) return a.length;
const la = a.length;
const lb = b.length;
const d = Array.from({ length: la + 1 }, () => new Array(lb + 1).fill(0));
for (let i = 0; i <= la; i++) d[i][0] = i;
for (let j = 0; j <= lb; j++) d[0][j] = j;
for (let i = 1; i <= la; i++) {
for (let j = 1; j <= lb; j++) {
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
}
}
return d[la][lb];
}
async function getBaseUrl(ua) {
if (cachedBaseUrl && Date.now() < cachedBaseUrlExpiry) {
return cachedBaseUrl;
}
let currentUrl = INITIAL_BASE_URL;
for (let i = 0; i < 10; i++) {
try {
const res = await fetch(currentUrl, {
method: 'HEAD',
headers: { 'User-Agent': ua },
redirect: 'manual',
signal: AbortSignal.timeout(10000),
});
if (res.status >= 300 && res.status < 400) {
const location = res.headers.get('location');
if (location) {
currentUrl = new URL(location, currentUrl).toString();
continue;
}
}
break;
} catch {
break;
}
}
const parsed = new URL(currentUrl);
cachedBaseUrl = `${parsed.protocol}//${parsed.host}`;
cachedBaseUrlExpiry = Date.now() + 3600000;
return cachedBaseUrl;
}
async function resolveMetadata(sdk, id, isTv) {
const apiKey = sdk?.tmdbApiKey || process.env.TMDB_API_KEY;
if (!apiKey) return null;
const type = isTv ? 'tv' : 'movie';
try {
const res = await fetch(`https://api.themoviedb.org/3/${type}/${id}?api_key=${apiKey}`, {
signal: AbortSignal.timeout(8000),
});
if (!res.ok) return null;
const data = await res.json();
const title = isTv ? data.name : data.title;
const releaseDate = isTv ? data.first_air_date : data.release_date;
const year = releaseDate ? parseInt(releaseDate.split('-')[0], 10) : null;
return { title, year };
} catch {
return null;
}
}
function sanitizeStreamUrl(rawUrl) {
try {
const parsed = new URL(rawUrl);
parsed.pathname = parsed.pathname.replaceAll('::', '%3A%3A');
return parsed.toString();
} catch {
return rawUrl.replaceAll('::', '%3A%3A');
}
}
async function validateStreamUrl(url, ua) {
try {
const res = await fetch(url, {
headers: {
'User-Agent': ua,
Range: 'bytes=0-1024',
},
signal: AbortSignal.timeout(4000),
});
const contentType = (res.headers.get('content-type') || '').toLowerCase();
const isSuccess = (res.status >= 200 && res.status < 300) || res.status === 206;
const isHtmlOrJsonError = contentType.includes('text/html') || contentType.includes('application/json');
if (!isSuccess || isHtmlOrJsonError) return false;
return true;
} catch {
return true;
}
}
async function resolveRedirectUrl(redirectUrl, ua) {
try {
const res = await fetch(redirectUrl, {
headers: { 'User-Agent': ua },
signal: AbortSignal.timeout(15000),
});
if (!res.ok) return null;
const html = await res.text();
let nextUrl = '';
const downloadMatch = html.match(/<a id="download" href="(.*?)"/);
if (downloadMatch) {
nextUrl = downloadMatch[1];
} else {
const varMatch = html.match(/var url = '(.*?)';/);
if (varMatch) {
nextUrl = varMatch[1];
}
}
if (!nextUrl) {
const match = html.match(/'o','(.*?)'/);
if (!match) return null;
const rawData = match[1];
const step1 = Buffer.from(rawData, 'base64').toString('utf8');
const step2 = Buffer.from(step1, 'base64').toString('utf8');
const step3 = rot13(step2);
const step4 = Buffer.from(step3, 'base64').toString('utf8');
const data = JSON.parse(step4);
return Buffer.from(data.o, 'base64').toString('utf8');
}
const interRes = await fetch(nextUrl, {
headers: { 'User-Agent': ua },
signal: AbortSignal.timeout(15000),
});
if (!interRes.ok) return null;
const interHtml = await interRes.text();
const finalMatch = interHtml.match(/<a href="([^"]+)"[^>]*class="[^"]*btn-success/);
if (finalMatch) {
return finalMatch[1];
}
return null;
} catch {
return null;
}
}
async function extractSourceResults(itemHtml, ua) {
const sizeMatch = itemHtml.match(/([\d.]+ ?[GM]B)/);
const sizeStr = sizeMatch ? sizeMatch[1] : null;
const heightMatch = itemHtml.match(/\d{3,}p/);
const heightStr = heightMatch ? heightMatch[0] : null;
const fileTitleMatch = itemHtml.match(/class="(?:file-title|episode-file-title)"[^>]*>([^<]+)/);
const fileTitle = fileTitleMatch ? fileTitleMatch[1].trim() : 'Unknown';
const displayParts = [fileTitle];
if (heightStr) displayParts.push(heightStr);
if (sizeStr) displayParts.push(sizeStr);
let hubCloudUrl = null;
let hubDriveUrl = null;
const linkRegex = /<a\s+[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi;
let match;
while ((match = linkRegex.exec(itemHtml)) !== null) {
const href = match[1];
const text = match[2];
if (text.includes('HubCloud') && !hubCloudUrl) {
hubCloudUrl = href;
} else if (text.includes('HubDrive') && !hubDriveUrl) {
hubDriveUrl = href;
}
}
const redirectUrl = hubCloudUrl || hubDriveUrl;
if (!redirectUrl) return null;
const resolvedUrl = await resolveRedirectUrl(redirectUrl, ua);
if (!resolvedUrl) return null;
const safeUrl = sanitizeStreamUrl(resolvedUrl);
const isValid = await validateStreamUrl(safeUrl, ua);
if (!isValid) return null;
return {
url: safeUrl,
label: displayParts.join(' · '),
headers: {
'User-Agent': ua,
},
};
}
export async function getStream({ id, s, e, sdk }) {
const isTv = Boolean(s && e);
const ua = getUA();
const meta = await resolveMetadata(sdk, id, isTv);
if (!meta?.title) return null;
const baseUrl = await getBaseUrl(ua);
const searchUrl = `${baseUrl}/?s=${encodeURIComponent(meta.title)}`;
const searchRes = await fetch(searchUrl, {
headers: { 'User-Agent': ua },
signal: AbortSignal.timeout(15000),
});
if (!searchRes.ok) return null;
const searchHtml = await searchRes.text();
const cardRegex = /<a\s+([^>]*\bclass="[^"]*movie-card[^"]*"[^>]*)>([\s\S]*?)<\/a>/gi;
const formatFilter = isTv ? 'Series' : 'Movies';
let targetPageUrl = null;
let cardMatch;
while ((cardMatch = cardRegex.exec(searchHtml)) !== null) {
const attributes = cardMatch[1];
const inner = cardMatch[2];
const hrefMatch = attributes.match(/href="([^"]+)"/);
if (!hrefMatch) continue;
const href = hrefMatch[1];
const formatMatches = [...inner.matchAll(/class="movie-card-format"[^>]*>([\s\S]*?)<\//gi)];
const formatTexts = formatMatches.map(m => m[1].trim());
if (!formatTexts.some(t => t.includes(formatFilter))) continue;
if (meta.year != null) {
const metaMatch = inner.match(/class="movie-card-meta"[^>]*>([\s\S]*?)<\//i);
const yearMatch = metaMatch ? metaMatch[1].match(/\d{4}/) : null;
if (yearMatch) {
const cardYear = parseInt(yearMatch[0], 10);
if (Math.abs(cardYear - meta.year) > 1) continue;
}
}
const titleMatch = inner.match(/class="movie-card-title"[^>]*>([\s\S]*?)<\//i);
let cardTitle = titleMatch ? titleMatch[1] : '';
cardTitle = cardTitle.replace(/\[.*?\]/g, '').trim();
const diff = levenshtein(cardTitle.toLowerCase(), meta.title.toLowerCase());
const isMatch = diff < 5 || (cardTitle.toLowerCase().includes(meta.title.toLowerCase()) && diff < 16);
if (!isMatch) continue;
targetPageUrl = new URL(href, baseUrl).toString();
break;
}
if (!targetPageUrl) return null;
const pageRes = await fetch(targetPageUrl, {
headers: { 'User-Agent': ua },
signal: AbortSignal.timeout(15000),
});
if (!pageRes.ok) return null;
const pageHtml = await pageRes.text();
const matchedHtmlBlocks = [];
if (isTv) {
const seasonStr = String(s).padStart(2, '0');
const episodeStr = String(e).padStart(2, '0');
const epItemRegex = /class="[^"]*episode-item[^"]*"[^>]*>([\s\S]*?)(?=(?:class="[^"]*episode-item"|<\/main>|$))/gi;
let epMatch;
while ((epMatch = epItemRegex.exec(pageHtml)) !== null) {
const epBlock = epMatch[1];
const titleMatch = epBlock.match(/class="episode-title"[^>]*>([\s\S]*?)<\//i);
const titleText = titleMatch ? titleMatch[1] : '';
if (!titleText.includes(`S${seasonStr}`)) continue;
const dlItemRegex = /class="[^"]*episode-download-item[^"]*"[^>]*>([\s\S]*?)(?=(?:class="[^"]*episode-download-item"|<\/div>\s*<\/div>|$))/gi;
let dlMatch;
while ((dlMatch = dlItemRegex.exec(epBlock)) !== null) {
const dlBlock = dlMatch[1];
if (dlBlock.includes(`Episode-${episodeStr}`)) {
matchedHtmlBlocks.push(dlBlock);
}
}
}
} else {
const dlItemRegex = /class="[^"]*download-item[^"]*"[^>]*>([\s\S]*?)(?=(?:class="[^"]*download-item"|<\/main>|$))/gi;
let dlMatch;
while ((dlMatch = dlItemRegex.exec(pageHtml)) !== null) {
matchedHtmlBlocks.push(dlMatch[1]);
}
}
if (matchedHtmlBlocks.length === 0) return null;
const results = await Promise.all(matchedHtmlBlocks.map((block) => extractSourceResults(block, ua)));
const allUrls = results.filter(Boolean);
if (allUrls.length === 0) return null;
return {
url: allUrls[0].url,
allUrls,
headers: allUrls[0].headers,
};
}

File diff suppressed because one or more lines are too long

View File

@@ -1,212 +0,0 @@
import { USER_AGENT } from '../utils/helpers.js';
const _sInit = [23, 27, 30, 31, 86, 28, 19, 86, 9, 18, 19, 21, 26, 27, 86, 120, 114, 120, 116, 86, 9, 18, 19, 21, 26, 27, 122, 89, 25, 23];
const _vParam = `_v=${(_sInit[15] ^ 0x5a)}${(_sInit[16] ^ 0x5a)}${(_sInit[17] ^ 0x5a)}${(_sInit[18] ^ 0x5a)}`;
const nD = '4860ac8bfddb';
const aD = '224eff10e662e9635c9f671cf46351dcd69af42b1edd56f5e5fa21751f44b9c8';
const Ls = [17, 91, 203, 44, 8, 177, 62, 239, 119, 3, 154, 81, 28, 210, 101, 7];
const wa = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
const SERVERS = [
{ id: 'NIGHT', endpoint: '/server/night' },
{ id: 'EMP', endpoint: '/server/emp' },
{ id: 'MAIN', endpoint: '/server/vidsrc' }
];
let cachedToken = null;
let tokenExpiry = 0;
function ab(e) {
let t = e >>> 0;
t ^= t >>> 16;
t = Math.imul(t, 2146121005) >>> 0;
t ^= t >>> 15;
t = Math.imul(t, 2221713035) >>> 0;
return (t ^ (t >>> 16)) >>> 0;
}
function sD(e) {
const t = new TextEncoder().encode(aD);
const r = Math.max(32, Math.min(128, e + 17));
const n = new Uint8Array(r);
let a = 2166136261;
for (let s = 0; s < r; s += 1) {
a ^= t[s % t.length] ?? s;
a = ab((a + Ls[s % Ls.length] + ((2654435761 * s) >>> 0)) >>> 0);
n[s] = a & 255;
}
return n;
}
function iD(e) {
let t = '';
for (let r = 0; r < e.length; r += 3) {
const n = e[r];
const a = e[r + 1];
const s = e[r + 2];
t += wa[n >>> 2];
t += wa[((3 & n) << 4) | ((a ?? 0) >>> 4)];
if (a === undefined) break;
t += wa[((15 & a) << 2) | ((s ?? 0) >>> 6)];
if (s === undefined) break;
t += wa[63 & s];
}
return t;
}
function generateCinesrcDirectHlsUrl(id, s, e) {
const isTv = s != null && e != null;
const tmdbId = Math.floor(Number(id));
const season = isTv ? Math.floor(Number(s || 1)) : 0;
const episode = isTv ? Math.floor(Number(e || 1)) : 0;
const str = `${nD}:${isTv ? 's' : 'm'}:${tmdbId}:${season}:${episode}`;
const a = new TextEncoder().encode(str);
const sArr = sD(a.length);
const i = new Uint8Array(a.length + 2);
i[0] = a.length & 255;
i[1] = (a.length >>> 8) & 255;
let o = (2654435769 ^ a.length) >>> 0;
for (let l = 0; l < a.length; l += 1) {
o = ab((o + sArr[l % sArr.length] + Ls[l % Ls.length] + l) >>> 0);
i[l + 2] = (a[l] ^ (255 & o)) ^ sArr[(7 * l + 3) % sArr.length];
}
return `https://glendale-plumbing.com/c/v1/${iD(i)}/master.m3u8`;
}
async function fetchBright67Subtitles(id, season, episode) {
let url = `https://subs.bright67.online/search?id=${id}`;
if (season != null && episode != null) {
url += `&season=${season}&episode=${episode}`;
}
try {
const res = await fetch(url, {
headers: {
'User-Agent': USER_AGENT,
'Referer': 'https://cinesrc.st/'
},
signal: AbortSignal.timeout(4000)
});
if (!res.ok) return [];
const data = await res.json();
if (!Array.isArray(data)) return [];
return data.slice(0, 15).map(s => ({
label: s.display || s.languageName || s.language || 'English',
language: s.language || 'en',
file: s.url || s.r2Url,
type: (s.url || s.r2Url || '').endsWith('.vtt') ? 'vtt' : 'srt'
}));
} catch {
return [];
}
}
async function fetchInternalToken() {
if (cachedToken && Date.now() < tokenExpiry) return cachedToken;
try {
const res = await fetch('https://1embed.cc/api/token', {
headers: {
'User-Agent': USER_AGENT,
'Referer': 'https://1embed.cc/',
'Accept': 'application/json, text/plain, */*'
},
signal: AbortSignal.timeout(4000)
});
if (res.ok) {
const data = await res.json();
if (data?.token) {
cachedToken = data.token;
tokenExpiry = Date.now() + 1800 * 1000;
return cachedToken;
}
}
} catch { }
return '';
}
export async function getStream(args) {
const { id, s, e, clientIP } = args;
const isTv = s != null && e != null;
const isMovie = !isTv;
const allUrls = [];
const [subtitles, directHlsUrl] = await Promise.all([
fetchBright67Subtitles(id, isMovie ? undefined : s, isMovie ? undefined : e),
Promise.resolve(generateCinesrcDirectHlsUrl(id, s, e))
]);
const masterUrlWithMark = `${directHlsUrl}?${_vParam}`;
allUrls.push({
url: masterUrlWithMark,
server: 'CineSrc (Direct Master)',
quality: 'Auto',
type: 'hls',
headers: {
'User-Agent': USER_AGENT,
'Referer': 'https://cinesrc.st/',
'Origin': 'https://cinesrc.st',
...(clientIP && { 'X-Forwarded-For': clientIP })
},
subtitles: subtitles.length ? subtitles : undefined
});
const token = await fetchInternalToken();
await Promise.allSettled(
SERVERS.map(async (server) => {
const query = isTv
? `id=${id}?type=tv&s=${s || 1}&e=${e || 1}`
: `id=${id}?type=movie`;
const stParam = token ? `&_st=${token}` : '';
const targetUrl = `https://1embed.cc${server.endpoint}/${query}${stParam}`;
const headers = {
'User-Agent': USER_AGENT,
'Referer': 'https://cinesrc.st/',
'Accept': 'application/json, text/plain, */*',
...(token && { 'X-Stream-Token': token }),
...(clientIP && { 'X-Forwarded-For': clientIP })
};
const res = await fetch(targetUrl, { headers, signal: AbortSignal.timeout(5000) }).catch(() => null);
if (res && res.ok) {
try {
const data = await res.json();
if (data && data.success !== false) {
const streamUrl = data.streams?.proxy_m3u8 || data.streams?.raw_m3u8 || data.streams?.m3u8 || data.streamUrl;
if (streamUrl && typeof streamUrl === 'string') {
const urlWithMark = streamUrl.includes('?') ? `${streamUrl}&${_vParam}` : `${streamUrl}?${_vParam}`;
allUrls.push({
url: urlWithMark,
server: `CineSrc (${data.selectedSource || data.provider || server.id})`,
quality: 'Auto',
type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
headers: {
'User-Agent': USER_AGENT,
'Referer': 'https://cinesrc.st/',
'Origin': 'https://cinesrc.st'
},
subtitles: subtitles.length ? subtitles : undefined
});
}
}
} catch { }
}
})
);
return allUrls.length ? { allUrls } : null;
}
export async function getSources() {
return ['CineSrc (Direct Master)', 'CineSrc (NIGHT)', 'CineSrc (EMP)', 'CineSrc (MAIN)'];
}

View File

@@ -1,148 +0,0 @@
import { USER_AGENT } from '../utils/helpers.js';
const BASE_DOMAIN = 'https://glendale-plumbing.com';
const REFERER = 'https://cine.su/';
const nD = '4860ac8bfddb';
const aD = '224eff10e662e9635c9f671cf46351dcd69af42b1edd56f5e5fa21751f44b9c8';
const Ls = [17, 91, 203, 44, 8, 177, 62, 239, 119, 3, 154, 81, 28, 210, 101, 7];
const wa = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
function ab(e) {
let t = e >>> 0;
t ^= t >>> 16;
t = Math.imul(t, 2146121005) >>> 0;
t ^= t >>> 15;
t = Math.imul(t, 2221713035) >>> 0;
return (t ^ (t >>> 16)) >>> 0;
}
function sD(e) {
const t = new TextEncoder().encode(aD);
const r = Math.max(32, Math.min(128, e + 17));
const n = new Uint8Array(r);
let a = 2166136261;
for (let s = 0; s < r; s += 1) {
a ^= t[s % t.length] ?? s;
a = ab((a + Ls[s % Ls.length] + ((2654435761 * s) >>> 0)) >>> 0);
n[s] = a & 255;
}
return n;
}
function iD(e) {
let t = '';
for (let r = 0; r < e.length; r += 3) {
const n = e[r];
const a = e[r + 1];
const s = e[r + 2];
t += wa[n >>> 2];
t += wa[((3 & n) << 4) | ((a ?? 0) >>> 4)];
if (a === undefined) break;
t += wa[((15 & a) << 2) | ((s ?? 0) >>> 6)];
if (s === undefined) break;
t += wa[63 & s];
}
return t;
}
function generateMasterUrl(id, s, e) {
const isTv = s != null && e != null;
const tmdbId = Math.floor(Number(id));
const season = isTv ? Math.floor(Number(s || 1)) : 0;
const episode = isTv ? Math.floor(Number(e || 1)) : 0;
const str = `${nD}:${isTv ? 's' : 'm'}:${tmdbId}:${season}:${episode}`;
const a = new TextEncoder().encode(str);
const sArr = sD(a.length);
const i = new Uint8Array(a.length + 2);
i[0] = a.length & 255;
i[1] = (a.length >>> 8) & 255;
let o = (2654435769 ^ a.length) >>> 0;
for (let l = 0; l < a.length; l += 1) {
o = ab((o + sArr[l % sArr.length] + Ls[l % Ls.length] + l) >>> 0);
i[l + 2] = (a[l] ^ (255 & o)) ^ sArr[(7 * l + 3) % sArr.length];
}
return `${BASE_DOMAIN}/c/v1/${iD(i)}/master.m3u8`;
}
function parsePlaylist(m3u8Text) {
const qualities = [];
const subtitles = [];
const subRegex = /#EXT-X-MEDIA:TYPE=SUBTITLES,[^\n]*NAME="([^"]*)"[^\n]*LANGUAGE="([^"]*)"[^\n]*URI="([^"]*)"/g;
let match;
while ((match = subRegex.exec(m3u8Text)) !== null) {
let uri = match[3];
if (uri.startsWith('/')) uri = `${BASE_DOMAIN}${uri}`;
subtitles.push({ label: match[1], language: match[2], file: uri, type: 'vtt' });
}
const streamRegex = /#EXT-X-STREAM-INF:[^\n]*RESOLUTION=\d+x(\d+)[^\n]*\r?\n([^\n#][^\n]*)/g;
while ((match = streamRegex.exec(m3u8Text)) !== null) {
let streamPath = match[2].trim();
if (streamPath.startsWith('/')) streamPath = `${BASE_DOMAIN}${streamPath}`;
qualities.push({ quality: `${match[1]}p`, url: streamPath });
}
return { qualities, subtitles };
}
export async function getStream(args) {
const { id, s, e, clientIP } = args;
const rawMasterUrl = generateMasterUrl(id, s, e);
const headers = {
'User-Agent': USER_AGENT,
'Referer': REFERER,
'Origin': 'https://cine.su',
...(clientIP && { 'X-Forwarded-For': clientIP })
};
try {
const res = await fetch(rawMasterUrl, {
headers,
signal: AbortSignal.timeout(5000)
});
if (res.ok) {
const text = await res.text();
const { qualities, subtitles } = parsePlaylist(text);
if (qualities.length) {
const allUrls = [{
url: rawMasterUrl,
server: 'CineSu (Auto)',
quality: 'Auto',
type: 'hls',
headers,
subtitles: subtitles.length ? subtitles : undefined
}];
for (const q of qualities) {
allUrls.push({
url: q.url,
server: `CineSu (${q.quality})`,
quality: q.quality,
type: 'hls',
headers,
subtitles: subtitles.length ? subtitles : undefined
});
}
return { allUrls };
}
}
} catch { }
return {
allUrls: [{
url: rawMasterUrl,
server: 'CineSu',
quality: 'Auto',
type: 'hls',
headers
}]
};
}

View File

@@ -1,338 +0,0 @@
import { getUA } from '../utils/helpers.js';
const SLAVE_URL = 'https://slave.downloadeverythingfromeverywhere.com/';
const REFERER = 'https://downloadeverythingfromeverywhere.com/';
const ORIGIN = 'https://downloadeverythingfromeverywhere.com';
const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36';
function extractJsonObjects(text) {
const objects = [];
let depth = 0;
let start = -1;
let inString = false;
let escape = false;
for (let i = 0; i < text.length; i++) {
const char = text[i];
if (escape) {
escape = false;
continue;
}
if (char === '\\') {
escape = true;
continue;
}
if (char === '"') {
inString = !inString;
continue;
}
if (!inString) {
if (char === '{') {
if (depth === 0) start = i;
depth++;
} else if (char === '}') {
depth--;
if (depth === 0 && start !== -1) {
const jsonStr = text.substring(start, i + 1);
try {
objects.push(JSON.parse(jsonStr));
} catch { }
start = -1;
}
}
}
}
return objects;
}
async function resolveDetails(sdk, id, isTv) {
const apiKey = sdk?.tmdbApiKey || process.env.TMDB_API_KEY;
if (!apiKey) return null;
const type = isTv ? 'tv' : 'movie';
try {
const res = await fetch(`https://api.themoviedb.org/3/${type}/${id}?api_key=${apiKey}&append_to_response=external_ids`, {
signal: AbortSignal.timeout(6000),
});
if (!res.ok) return null;
const data = await res.json();
const title = isTv ? data.name : data.title;
const releaseDate = isTv ? data.first_air_date : data.release_date;
const year = releaseDate ? parseInt(releaseDate.split('-')[0], 10) : null;
const imdbId = data.imdb_id || data.external_ids?.imdb_id || null;
return { title, year, imdbId };
} catch {
return null;
}
}
async function resolveHubCloud(hubUrl, ua) {
try {
const res1 = await fetch(hubUrl, {
headers: {
'User-Agent': ua,
Referer: REFERER,
},
signal: AbortSignal.timeout(8000),
});
const html = await res1.text();
const hubPhpMatch = html.match(/https?:\/\/[^\s"<>]+\/hubcloud\.php\?[^\s"<>]+/i);
if (!hubPhpMatch) return null;
const phpUrl = hubPhpMatch[0];
const phpRes = await fetch(phpUrl, {
headers: {
'User-Agent': ua,
Referer: hubUrl,
},
signal: AbortSignal.timeout(8000),
});
const phpBody = await phpRes.text();
const r2Match = phpBody.match(/https?:\/\/[a-zA-Z0-9.\-_]+\.r2\.cloudflarestorage\.com\/[^\s"<>]+/i);
if (r2Match) {
return r2Match[0].replaceAll('&amp;', '&');
}
const pixelMatch = phpBody.match(/https?:\/\/pixel\.hubcloud\.[a-z]+\/\?id=[^\s"<>]+/i);
if (pixelMatch) {
return pixelMatch[0];
}
} catch { }
return null;
}
async function resolveClicknUpload(clicknUrl, ua) {
try {
const res1 = await fetch(clicknUrl, {
headers: {
'User-Agent': ua,
Referer: REFERER,
},
signal: AbortSignal.timeout(8000),
});
const body1 = await res1.text();
const formMatch1 = body1.match(/<form[^>]+method=["']POST["'][^>]*>([\s\S]*?)<\/form>/i);
if (!formMatch1) return null;
const inputMatches1 = [...formMatch1[1].matchAll(/<input[^>]+name=["']([^"']+)["'][^>]+value=["']([^"']*)["']/gi)];
const params1 = new URLSearchParams();
for (const m of inputMatches1) {
params1.set(m[1], m[2]);
}
params1.set('method_free', 'Slow Download');
const rawCookies = res1.headers.getSetCookie?.() || [res1.headers.get('set-cookie')].filter(Boolean);
const cookieHeader = rawCookies.join('; ');
const res2 = await fetch(clicknUrl, {
method: 'POST',
headers: {
'User-Agent': ua,
Referer: clicknUrl,
'Content-Type': 'application/x-www-form-urlencoded',
...(cookieHeader ? { Cookie: cookieHeader } : {}),
},
body: params1.toString(),
signal: AbortSignal.timeout(8000),
});
const body2 = await res2.text();
const formMatch2 = body2.match(/<form[^>]+method=["']POST["'][^>]*>([\s\S]*?)<\/form>/i);
if (!formMatch2) return null;
const inputMatches2 = [...formMatch2[1].matchAll(/<input[^>]+name=["']([^"']+)["'][^>]+value=["']([^"']*)["']/gi)];
const params2 = new URLSearchParams();
for (const m of inputMatches2) {
params2.set(m[1], m[2]);
}
params2.set('down_script', '1');
await new Promise(r => setTimeout(r, 4500));
const res3 = await fetch(clicknUrl, {
method: 'POST',
headers: {
'User-Agent': ua,
Referer: clicknUrl,
'Content-Type': 'application/x-www-form-urlencoded',
...(cookieHeader ? { Cookie: cookieHeader } : {}),
},
body: params2.toString(),
signal: AbortSignal.timeout(8000),
});
const body3 = await res3.text();
const directMatch = body3.match(/https?:\/\/[a-zA-Z0-9.\-_:]+\/d\/[a-zA-Z0-9_\-\/]+/i) ||
body3.match(/window\.open\(["'](https?:\/\/[^"']+)["']\)/i);
if (directMatch) {
const found = directMatch[1] || directMatch[0];
if (found.includes('clicknupload.') && !found.includes('/d/')) {
return null;
}
return found;
}
} catch { }
return null;
}
async function resolveItem(item, fallbackTitle, ua) {
const rawUrl = String(item.url || '').trim();
if (!rawUrl) return null;
if (
rawUrl.includes('111477.xyz') ||
rawUrl.includes('vadapav.mov') ||
rawUrl.includes('driveseed.org') ||
rawUrl.includes('new3.gdflix.io') ||
rawUrl.includes('rapidrar.cr') ||
rawUrl.includes('megaup.net') ||
rawUrl.includes('telegram.dog') ||
rawUrl.includes('t.me')
) {
return null;
}
let directStreamUrl = null;
let provider = item.site || 'DownloadEverything';
let streamHeaders = { 'User-Agent': ua };
try {
if (rawUrl.includes('hakunaymatata.com')) {
directStreamUrl = rawUrl;
provider = 'Moviebox';
streamHeaders = { 'User-Agent': 'Lavf/60.16.100' };
} else if (rawUrl.includes('pixeldrain.dev') || rawUrl.includes('pixeldrain.com')) {
const m = rawUrl.match(/pixeldrain\.(?:dev|com)\/(?:u|l)\/([a-zA-Z0-9_-]+)/);
if (m) {
directStreamUrl = `https://pixeldrain.com/api/file/${m[1]}`;
provider = 'Pixeldrain';
}
} else if (rawUrl.includes('hubcloud.') || rawUrl.includes('vcloud.zip')) {
directStreamUrl = await resolveHubCloud(rawUrl, ua);
if (directStreamUrl) {
provider = 'HubCloud';
}
} else if (rawUrl.includes('clicknupload.')) {
directStreamUrl = await resolveClicknUpload(rawUrl, ua);
if (directStreamUrl) {
provider = 'ClicknUpload';
}
} else if (
/\.(?:mp4|mkv)(?:\?|$)/i.test(rawUrl) &&
!rawUrl.includes('111477.xyz') &&
!rawUrl.includes('vadapav.mov') &&
!rawUrl.includes('.cyou/res/')
) {
try {
const check = await fetch(rawUrl, {
method: 'HEAD',
headers: { 'User-Agent': ua },
signal: AbortSignal.timeout(2000),
});
if (check.status === 200 || check.status === 206 || (check.status >= 300 && check.status < 400)) {
directStreamUrl = rawUrl;
provider = item.site || 'DirectStream';
}
} catch { }
}
} catch { }
if (!directStreamUrl) return null;
const tags = Array.isArray(item.tags) ? item.tags.map(String) : [];
const qualityMatch = tags.find(t => /2160p|4k|1080p|720p|480p/i.test(t)) || '1080p';
const rawTitle = item.name || item.release || fallbackTitle;
return {
url: directStreamUrl,
label: `[${provider}] ${rawTitle} (${qualityMatch})`,
headers: streamHeaders,
};
}
export async function getStream({ id, s, e, sdk }) {
const isTv = Boolean(s && e);
const mediaType = isTv ? 'series' : 'movie';
const ua = USER_AGENT;
const details = await resolveDetails(sdk, id, isTv);
const title = details?.title || String(id);
const tmdbId = parseInt(id, 10);
const payload = {
mode: mediaType,
title,
...(details?.year ? { year: String(details.year) } : {}),
...(tmdbId ? { tmdb_id: tmdbId } : {}),
...(details?.imdbId ? { imdb_id: details.imdbId } : {}),
...(isTv && s != null ? { season: Number(s) } : {}),
...(isTv && e != null ? { episode: Number(e) } : {}),
};
const res = await fetch(SLAVE_URL, {
method: 'POST',
headers: {
'User-Agent': ua,
Origin: ORIGIN,
Referer: REFERER,
'Content-Type': 'application/json',
Accept: 'application/x-ndjson',
'x-defe-manual': '1',
'sec-ch-ua': '"Microsoft Edge";v="153", "Not_A Brand";v="8", "Chromium";v="153"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-site',
},
body: JSON.stringify(payload),
signal: AbortSignal.timeout(16000),
});
if (!res.ok) return null;
let fullText = '';
if (res.body?.getReader) {
const reader = res.body.getReader();
const decoder = new TextDecoder();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
fullText += decoder.decode(value, { stream: true });
}
} catch { }
} else {
fullText = await res.text();
}
const objects = extractJsonObjects(fullText);
const candidateItems = [];
for (const parsed of objects) {
if (parsed?.t === 'hit' && Array.isArray(parsed.links)) {
const site = parsed.site || 'DownloadEverything';
for (const l of parsed.links) {
if (l && typeof l === 'object') {
candidateItems.push({ site, ...l });
}
}
}
}
const resolved = await Promise.all(candidateItems.map(item => resolveItem(item, title, ua)));
const allUrls = resolved.filter(Boolean);
if (allUrls.length === 0) return null;
return {
url: allUrls[0].url,
allUrls,
headers: allUrls[0].headers,
};
}

150
src/sources/dulo.js Normal file
View File

@@ -0,0 +1,150 @@
import { getUA } from '../utils/helpers.js';
const BASE_URL = 'https://dulo.mov';
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function resolveDetails(sdk, id, isTv) {
const apiKey = sdk?.tmdbApiKey || process.env.TMDB_API_KEY;
if (!apiKey) return null;
const type = isTv ? 'tv' : 'movie';
try {
const res = await fetch(`https://api.themoviedb.org/3/${type}/${id}?api_key=${apiKey}`, {
signal: AbortSignal.timeout(6000),
});
if (!res.ok) return null;
const data = await res.json();
const title = isTv ? data.name : data.title;
const releaseDate = isTv ? data.first_air_date : data.release_date;
const year = releaseDate ? releaseDate.split('-')[0] : '';
const runtime = isTv ? (data.episode_run_time?.[0] || 24) : (data.runtime || 90);
return { title, year, runtime };
} catch {
return null;
}
}
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({ id, s, e, sdk }) {
const isTv = Boolean(s && e);
const mediaType = isTv ? 'tv' : 'movie';
const ua = getUA();
const details = await resolveDetails(sdk, id, isTv);
const title = details?.title || '';
const year = details?.year || '';
const runtime = details?.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,
label: src.label || 'Dulo',
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,
allUrls,
headers: allUrls[0].headers,
};
}

View File

@@ -1,88 +0,0 @@
import { USER_AGENT, fetchJson } from '../utils/helpers.js';
const BASE_URL = 'https://api.peestream.in';
const PROVIDERS = [
{ id: 'vaplayer', name: 'FRAME Zephyr' },
{ id: 'castle', name: 'FRAME Atlas' },
{ id: 'hera', name: 'FRAME Luna' },
{ id: 'multivid', name: 'FRAME Volt' },
{ id: 'netmirror', name: 'FRAME Echo' },
{ id: 'vidsuper-castle', name: 'FRAME Rift' },
{ id: 'vidsuper-vixsrc', name: 'FRAME Quill' }
];
async function fetchProviderStreams(provider, type, id, s, e) {
try {
const queryParams = new URLSearchParams({
q: String(id),
type,
provider: provider.id
});
if (type === 'tv') {
queryParams.set('season', String(s));
queryParams.set('episode', String(e));
}
const url = `${BASE_URL}/api/search?${queryParams.toString()}`;
const data = await fetchJson(url, {
headers: {
'User-Agent': USER_AGENT,
'Accept': 'application/json',
'Referer': 'https://peestream.in/'
},
signal: AbortSignal.timeout(12000)
});
if (!data || !Array.isArray(data.results) || !data.results.length) return [];
const streams = [];
for (const result of data.results) {
for (const stream of result.streams || []) {
if (!stream || !stream.url) continue;
streams.push({
url: stream.url,
server: provider.name,
quality: stream.quality || 'Auto',
type: stream.type === 'm3u8' || stream.url.includes('.m3u8') ? 'hls' : 'mp4',
headers: stream.headers || {
'User-Agent': USER_AGENT
}
});
}
}
return streams;
} catch {
return [];
}
}
export async function getStream(args) {
const { id, s, e, server } = args;
const isTv = s != null && e != null;
const type = isTv ? 'tv' : 'movie';
let targets = PROVIDERS;
if (server && server !== 'all') {
const clean = server.toLowerCase().replace('frame ', '').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(p, type, id, s, e))
);
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 => p.name);
}

View File

@@ -1,44 +0,0 @@
import { fetchText, fetchJson, USER_AGENT, getTmdbInfo } from '../utils/helpers.js';
const BASE_URL = 'https://fsharetv.cc';
const HEADERS = { 'User-Agent': USER_AGENT, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9', 'Referer': `${BASE_URL}/` };
const API_HEADERS = { ...HEADERS, 'Accept': 'application/json, */*; q=0.01', 'X-Requested-With': 'XMLHttpRequest' };
export async function getStream({ id, s }) {
if (s != null) return null;
try {
const info = await getTmdbInfo(id, 'movie');
if (!info?.imdbId) return null;
const html = await fetchText(`${BASE_URL}/movie/${info.imdbId}`, { headers: HEADERS, signal: AbortSignal.timeout(8000) });
let watchPath = null;
const match = html.match(/href="(\/w\/[^"]+)"/);
if (match) watchPath = match[1];
if (!watchPath) return null;
const watchHtml = await fetchText(`${BASE_URL}${watchPath}`, { headers: HEADERS, signal: AbortSignal.timeout(8000) });
let sourceId = null;
const sidMatch = watchHtml.match(/(?:source_id|file_id|setSource)[\s=:\('"]+([^'"\)]+)/i);
if (sidMatch) sourceId = sidMatch[1];
if (!sourceId) return null;
const json = await fetchJson(`${BASE_URL}/api/file/${sourceId}/source?trailer=Png81APqcxU&type=watch`, { headers: { ...API_HEADERS, 'Referer': `${BASE_URL}${watchPath}` }, signal: AbortSignal.timeout(8000) });
if (json.status !== 'ok') return null;
const groups = [];
if (Array.isArray(json.data?.file?.sources)) groups.push(json.data.file.sources);
if (Array.isArray(json.data?.file?.alternatives)) json.data.file.alternatives.forEach(g => Array.isArray(g) && groups.push(g));
const out = [], seen = new Set();
for (const group of groups) {
for (const item of group.filter(st => st?.src).sort((a, b) => parseInt(b.quality) - parseInt(a.quality))) {
const url = item.src.startsWith('http') ? item.src : `${BASE_URL}${item.src}`;
if (seen.has(url)) continue;
seen.add(url);
out.push({ url, quality: parseInt(item.quality) || 0, label: item.label || null });
}
}
out.sort((a, b) => b.quality - a.quality);
return out.length ? { allUrls: out.map(u => ({ url: u.url, headers: HEADERS, skipProxy: false })) } : null;
} catch { return null; }
}
export async function getSources(args) {
const stream = await getStream(args);
return stream?.allUrls ? stream.allUrls.map(u => u.url) : [];
}

View File

@@ -1,49 +0,0 @@
import { fetchText, fetchJson, USER_AGENT, getTmdbInfo } from '../utils/helpers.js';
const BASE_URL = 'https://www.fsonic.net';
const FSHARE_BASE = 'https://fsharetv.co';
const HEADERS = { 'User-Agent': USER_AGENT, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9' };
export async function getStream({ id, s, sdk }) {
const tmdbApiKey = sdk?.tmdbApiKey || null;
if (!tmdbApiKey) return null;
if (s != null) return null;
try {
const info = await getTmdbInfo(tmdbApiKey, id, 'movie');
if (!info?.titles?.length) return null;
let watchSlug = null;
for (const title of info.titles) {
try {
const html = await fetchText(`${BASE_URL}/movie/search/${encodeURIComponent(title)}`, { headers: HEADERS, signal: AbortSignal.timeout(8000) });
let idx = 0, found = null;
const yearStr = String(info.year);
while ((idx = html.indexOf('href="/watch/', idx)) !== -1) {
const start = idx + 6;
const end = html.indexOf('"', start);
const link = html.slice(start, end);
if (!found) found = link;
if (link.includes(yearStr)) { found = link; break; }
idx = end;
}
if (found) { watchSlug = found; break; }
} catch { }
}
if (!watchSlug) return null;
const wHtml = await fetchText(`${BASE_URL}${watchSlug}`, { headers: HEADERS, signal: AbortSignal.timeout(8000) });
let token = null, trailer = null;
const match = wHtml.match(/init\('([^']+)',\s*(?:'[^']*',\s*)?'([^']+)'/);
if (match) { token = match[1]; trailer = match[2]; }
if (!token) return null;
const json = await fetchJson(`${BASE_URL}/api/source/${token}?trailer=${trailer}&type=watch`, { headers: { ...HEADERS, 'Accept': 'application/json, text/plain, */*', 'Referer': `${BASE_URL}${watchSlug}` }, signal: AbortSignal.timeout(8000) });
if (json.status !== 'ok') return null;
const allGroups = [];
if (json.data?.file?.sources?.length) allGroups.push(json.data.file.sources);
if (json.data?.file?.alternatives) for (const g of json.data.file.alternatives) if (g?.length) allGroups.push(g);
const urls = new Set();
for (const group of allGroups) {
const best = [...group].filter(st => st?.src).sort((a, b) => parseInt(b.quality) - parseInt(a.quality))[0];
if (best) urls.add(best.src.startsWith('http') ? best.src : `${FSHARE_BASE}${best.src}`);
}
return urls.size ? { allUrls: [...urls].map(url => ({ url, headers: { ...HEADERS, 'Referer': `${FSHARE_BASE}/` }, skipProxy: false })) } : null;
} catch { return null; }
}

View File

@@ -1,82 +0,0 @@
import crypto from 'node:crypto';
import { fetchJson, fetchText, USER_AGENT } from '../utils/helpers.js';
const API_BASE = 'https://enc-dec.app/api';
const DOMAINS = ['hexa.su', 'flixer.su'];
async function getChallengeToken() {
try {
const data = await fetchJson(`${API_BASE}/enc-hexa`, { signal: AbortSignal.timeout(6000) });
return data?.status === 200 ? data.result.token : null;
} catch { return null; }
}
export async function getStream({ id, s, e, server }) {
try {
const apiKey = crypto.randomBytes(32).toString('hex');
const capToken = await getChallengeToken();
if (!capToken) return null;
const isTv = s != null && e != null;
let decrypted = null;
for (const domain of DOMAINS) {
try {
const url = isTv
? `https://theemoviedb.${domain}/api/tmdb/tv/${id}/season/${s}/episode/${e}/images`
: `https://theemoviedb.${domain}/api/tmdb/movie/${id}/images`;
const encrypted = await fetchText(url, {
headers: {
'User-Agent': USER_AGENT,
'Referer': `https://${domain}/`,
'Accept': 'text/plain',
'X-Fingerprint-Lite': 'e9136c41504646444',
'X-Api-Key': apiKey,
'X-Cap-Token': capToken
},
signal: AbortSignal.timeout(10000)
});
if (!encrypted) continue;
const decData = await fetchJson(`${API_BASE}/dec-hexa`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: encrypted, key: apiKey }),
signal: AbortSignal.timeout(8000)
});
if (decData?.status === 200 && decData.result?.sources?.length) {
decrypted = decData.result;
break;
}
} catch { continue; }
}
if (!decrypted?.sources?.length) return null;
let sources = decrypted.sources.map(src => ({
url: src.url,
server: `Hexa - ${src.name || src.server || 'Server'}`,
type: src.url.includes('.m3u8') ? 'hls' : 'mp4',
quality: src.quality || 'Auto',
subtitles: (decrypted.subtitles || []).map(sub => ({
url: sub.url,
lang: sub.label || sub.lang || 'Unknown'
})),
skipProxy: false
}));
if (server && server !== 'all') {
const cleanName = server.replace('Hexa - ', '');
sources = sources.filter(u => u.server.includes(cleanName));
}
return sources.length ? { allUrls: sources } : null;
} catch { return null; }
}
export async function getSources() {
return ['Hexa'];
}

View File

@@ -1,125 +0,0 @@
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})`);
}

View File

@@ -1,142 +0,0 @@
import { fetchJson, USER_AGENT } from '../utils/helpers.js';
const API_BASE = 'https://api.meowtv.ru';
const REFERER = 'https://meowtv.ru/';
const ENC_DEC_API = 'https://enc-dec.app/api/dec-meowtv';
const BASE_HEADERS = {
'User-Agent': USER_AGENT,
'Accept': 'application/json',
'Referer': REFERER,
'Origin': 'https://meowtv.ru',
'Accept-Language': 'en-US,en;q=0.9'
};
const SERVERS = [
'dcloud', 'acme', 'tcloud', 'ipcloud', 'turkce', 'hindiv3'
];
const TIMEOUT_MS = 15000;
export const VERIFY_HEADERS = { 'User-Agent': USER_AGENT, 'Referer': REFERER, 'Origin': 'https://meowtv.ru' };
let cachedTicket = null;
let ticketExpiry = 0;
/**
* Fetches a stream ticket or returns a cached valid ticket.
*/
async function getTicket(forceRefresh = false) {
const now = Date.now();
if (!forceRefresh && cachedTicket && now < ticketExpiry - 10000) {
return cachedTicket;
}
try {
const res = await fetchJson(`${API_BASE}/streams/ticket`, {
method: 'POST',
headers: {
...BASE_HEADERS,
'Content-Type': 'application/json'
},
body: JSON.stringify({})
});
if (res?.ticket) {
cachedTicket = res.ticket;
ticketExpiry = typeof res.exp === 'number' ? res.exp : now + 60000;
return cachedTicket;
}
} catch {
}
return null;
}
async function decryptPayload(payload) {
try {
const response = await fetchJson(ENC_DEC_API, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data: payload })
});
if (response?.status !== 200 || !response?.result) {
return null;
}
return typeof response.result === 'string' ? JSON.parse(response.result) : response.result;
} catch (e) {
return null;
}
}
export async function getStream({ id, s, e, server }) {
try {
const isTv = !!s;
let targets = SERVERS;
if (server && server !== 'all') {
const cleanName = server.replace('MeowTV - ', '');
targets = SERVERS.includes(cleanName) ? [cleanName] : [targets[0]];
}
const ticket = await getTicket();
const requestHeaders = {
...BASE_HEADERS,
...(ticket ? { 'x-stream-ticket': ticket } : {})
};
const results = await Promise.all(targets.map(async srv => {
try {
return await Promise.race([
(async () => {
const path = isTv
? `/streams/tv/${id}/${s}/${e}?s=${encodeURIComponent(srv)}`
: `/streams/movie/${id}?s=${encodeURIComponent(srv)}`;
const payload = await fetchJson(`${API_BASE}${path}`, {
headers: requestHeaders
});
if (!payload) return null;
const data = await decryptPayload(payload);
if (!data) return null;
const urls = [];
if (data?.url?.startsWith('http')) {
urls.push({
url: data.url,
server: `MeowTV - ${srv}`,
});
}
if (Array.isArray(data?.streams)) {
for (const stream of data.streams) {
if (stream?.url?.startsWith('http')) {
urls.push({
url: stream.url,
server: `MeowTV - ${srv} (${stream.language || 'Unknown'})`,
});
}
}
}
return urls;
})(),
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout exceeded')), TIMEOUT_MS))
]);
} catch (err) {
return null;
}
}));
const allUrls = results.filter(Boolean).flat();
return allUrls.length ? { allUrls } : null;
} catch (e) {
return null;
}
}
export async function getSources() {
return SERVERS.map(s => `MeowTV - ${s}`);
}

View File

@@ -1,122 +0,0 @@
import { USER_AGENT, fetchJson, getTmdbInfo } from '../utils/helpers.js';
const BASE_URL = 'https://providers.peestream.in';
export async function getStream(args) {
const { id, s, e, server, tmdbApiKey } = args;
const isTv = s != null && e != null;
const type = isTv ? 'tv' : 'movie';
let title = args.title || '';
let releaseYear = args.year || '';
let imdbId = args.imdbId || '';
if (!title) {
try {
const info = await getTmdbInfo(id, type, s, tmdbApiKey);
if (info) {
title = info.title || '';
if (info.year) releaseYear = info.year;
if (info.imdbId) imdbId = info.imdbId;
}
} catch { }
}
const queryParams = new URLSearchParams({
type,
tmdbId: String(id),
title: title || String(id)
});
if (releaseYear) queryParams.set('releaseYear', String(releaseYear));
if (imdbId) queryParams.set('imdbId', String(imdbId));
if (isTv) {
queryParams.set('season', String(s));
queryParams.set('episode', String(e));
}
const allUrls = [];
try {
const scrapeUrl = `${BASE_URL}/scrape?${queryParams.toString()}`;
const res = await fetch(scrapeUrl, {
headers: {
'User-Agent': USER_AGENT,
'Accept': 'text/event-stream',
'Referer': `${BASE_URL}/`
},
signal: AbortSignal.timeout(15000)
});
if (res.ok) {
const text = await res.text();
const events = text.split('\n\n');
for (const ev of events) {
if (ev.includes('event: completed')) {
const dataMatch = ev.match(/data:\s*(.+)/);
if (dataMatch) {
try {
const parsed = JSON.parse(dataMatch[1].trim());
const stream = parsed.stream;
const streamUrl = stream?.playlist || stream?.url || stream?.file;
if (streamUrl) {
allUrls.push({
url: streamUrl,
server: `PeeStream - ${parsed.sourceId || 'Poseidon'}`,
quality: 'Auto',
type: stream.type === 'hls' || streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
headers: stream.headers || {
'User-Agent': USER_AGENT
}
});
}
} catch { }
}
}
}
}
} catch { }
if (!allUrls.length) {
try {
const searchUrl = `${BASE_URL}/api/search?q=${encodeURIComponent(title || id)}&type=${type}&tmdbId=${id}${isTv ? `&season=${s}&episode=${e}` : ''}`;
const data = await fetchJson(searchUrl, {
headers: {
'User-Agent': USER_AGENT,
'Accept': 'application/json',
'Referer': `${BASE_URL}/`
},
signal: AbortSignal.timeout(10000)
});
if (data && Array.isArray(data.results)) {
for (const result of data.results) {
const pName = result.providerName || result.provider || 'PeeStream';
for (const stream of result.streams || []) {
if (!stream || !stream.url) continue;
allUrls.push({
url: stream.url,
server: `PeeStream - ${stream.name || pName}`,
quality: stream.quality || 'Auto',
type: stream.type === 'm3u8' || stream.url.includes('.m3u8') ? 'hls' : 'mp4',
headers: stream.headers || {
'User-Agent': USER_AGENT
}
});
}
}
}
} catch { }
}
if (server && server !== 'all') {
const clean = server.toLowerCase().replace('peestream - ', '');
const filtered = allUrls.filter(u => u.server.toLowerCase().includes(clean));
if (filtered.length) return { allUrls: filtered };
}
return allUrls.length ? { allUrls } : null;
}
export async function getSources() {
return ['PeeStream - vaplayer'];
}

View File

@@ -49,9 +49,9 @@ export async function getStream({ id, s, e, sdk }) {
'User-Agent': ua,
Referer: `${BASE_URL}/`,
Origin: BASE_URL,
Accept: 'application/x-ndjson, text/plain, */*',
Accept: 'text/event-stream, application/x-ndjson, text/plain, */*',
},
signal: AbortSignal.timeout(18000),
signal: AbortSignal.timeout(90000),
});
if (!res.ok) return null;
@@ -89,7 +89,9 @@ export async function getStream({ id, s, e, sdk }) {
for (const line of lines) {
try {
const item = JSON.parse(line);
const raw = line.startsWith('data:') ? line.slice(5).trim() : line;
if (!raw || raw === '[DONE]') continue;
const item = JSON.parse(raw);
const streamUrl = String(item?.url || '').trim();
if (!streamUrl || !streamUrl.startsWith('http') || seenUrls.has(streamUrl)) continue;

View File

@@ -1,85 +0,0 @@
import { getUA } from '../utils/helpers.js';
const ADDON_BASE = 'https://stremio.vadapav.mov';
async function resolveImdbId(sdk, id, isTv) {
const apiKey = sdk?.tmdbApiKey || process.env.TMDB_API_KEY;
if (!apiKey) return null;
const type = isTv ? 'tv' : 'movie';
try {
const res = await fetch(`https://api.themoviedb.org/3/${type}/${id}?api_key=${apiKey}&append_to_response=external_ids`, {
signal: AbortSignal.timeout(6000),
});
if (!res.ok) return null;
const data = await res.json();
return data.imdb_id || data.external_ids?.imdb_id || null;
} catch {
return null;
}
}
export async function getStream({ id, s, e, sdk }) {
const isTv = Boolean(s && e);
const ua = getUA();
const imdbId = await resolveImdbId(sdk, id, isTv);
const targetIds = [];
if (imdbId && imdbId.startsWith('tt')) {
targetIds.push(imdbId);
}
targetIds.push(`tmdb:${id}`);
const seenUrls = new Set();
const allUrls = [];
const defaultHeaders = {
'User-Agent': ua,
Accept: 'application/json, text/plain, */*',
};
for (const targetId of targetIds) {
const streamPath = isTv
? `${ADDON_BASE}/stream/series/${targetId}:${s}:${e}.json`
: `${ADDON_BASE}/stream/movie/${targetId}.json`;
try {
const res = await fetch(streamPath, {
headers: defaultHeaders,
signal: AbortSignal.timeout(12000),
});
if (!res.ok) continue;
const data = await res.json();
if (Array.isArray(data?.streams) && data.streams.length > 0) {
for (const item of data.streams) {
if (!item || typeof item !== 'object') continue;
const url = String(item.url || '').trim();
if (!url || !url.startsWith('http') || seenUrls.has(url)) continue;
seenUrls.add(url);
const rawTitle = item.title ? String(item.title).trim() : '';
const rawName = item.name ? String(item.name).trim() : 'vadapav.mov';
const label = rawTitle || rawName;
allUrls.push({
url,
label,
headers: defaultHeaders,
});
}
if (allUrls.length > 0) break;
}
} catch { }
}
if (allUrls.length === 0) return null;
return {
url: allUrls[0].url,
allUrls,
headers: allUrls[0].headers,
};
}

View File

@@ -1,43 +0,0 @@
import { fetchJson, fetchText, USER_AGENT } from '../utils/helpers.js';
const API_BASE = 'https://enc-dec.app/api';
const HEADERS = { 'User-Agent': USER_AGENT, 'Referer': 'https://vidcore.net/', 'X-Requested-With': 'XMLHttpRequest' };
async function getDynamicServers(id, s, e) {
try {
const html = await fetchText(s != null && e != null ? `https://vidcore.net/tv/${id}/${s}/${e}/` : `https://vidcore.net/movie/${id}/`, { headers: HEADERS });
const match = html.match(/\\"(?:en|token)\\":\\"(.*?)\\"/) || html.match(/"(?:en|token)":"(.*?)"/);
if (!match?.[1]) return null;
const encData = await fetchJson(`${API_BASE}/enc-vidcore?text=${encodeURIComponent(match[1])}`);
if (!encData?.result) return null;
const { servers: serversUrl, stream: streamUrl, token } = encData.result;
const reqHeaders = { ...HEADERS, 'X-CSRF-Token': token };
const serversEncrypted = await fetchText(serversUrl, { method: 'POST', headers: reqHeaders });
const decData = await fetchJson(`${API_BASE}/dec-vidcore`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: serversEncrypted }) });
return decData?.result ? { servers: decData.result, streamUrl, reqHeaders } : null;
} catch { return null; }
}
export async function getStream({ id, s, e }) {
const data = await getDynamicServers(id, s, e);
if (!data?.servers?.length) return null;
for (const srv of data.servers) {
try {
const streamEncrypted = await fetchText(`${data.streamUrl}/${srv.data}`, { method: 'POST', headers: data.reqHeaders });
const decData = await fetchJson(`${API_BASE}/dec-vidcore`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: streamEncrypted }) });
const url = decData?.result?.url;
if (url) {
const r = await fetch(url, { headers: { ...HEADERS, 'Range': 'bytes=0-511' }, signal: AbortSignal.timeout(5000) });
if (r.ok || r.status === 206) return { url, subtitles: (decData.result.captions || []).map(c => ({ url: c.file, lang: c.label || 'Unknown' })), headers: { ...HEADERS, 'Origin': 'https://vidcore.net' }, server: srv.name };
}
} catch { }
}
return null;
}
export async function getSources(args) {
const data = await getDynamicServers(args.id, args.s, args.e);
return data?.servers ? data.servers.map(s => s.name) : [];
}

View File

@@ -1,53 +0,0 @@
import { fetchJson, fetchText, USER_AGENT } from '../utils/helpers.js';
const API_BASE = 'https://enc-dec.app/api';
const DOMAIN = 'https://vidfast.vc';
const HEADERS = { 'User-Agent': USER_AGENT, 'Referer': `${DOMAIN}/`, 'X-Requested-With': 'XMLHttpRequest' };
async function getVidfastMeta(id, s, e) {
try {
const embedUrl = s != null && e != null ? `${DOMAIN}/tv/${id}/${s}/${e}/` : `${DOMAIN}/movie/${id}/`;
const html = await fetchText(embedUrl, { headers: { 'User-Agent': USER_AGENT } });
const match = html.match(/\\"(?:en|token)\\":\\"(.*?)\\"/) || html.match(/"(?:en|token)":"(.*?)"/);
if (!match?.[1]) return null;
const encData = await fetchJson(`${API_BASE}/enc-vidfast?text=${encodeURIComponent(match[1])}`);
if (encData.status !== 200 || !encData.result) return null;
const { servers: serversUrl, stream: streamUrl, token } = encData.result;
const reqHeaders = { ...HEADERS, 'X-CSRF-Token': token };
const serversEncrypted = await fetchText(serversUrl, { method: 'POST', headers: reqHeaders });
const decServersData = await fetchJson(`${API_BASE}/dec-vidfast`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: serversEncrypted }) });
if (decServersData.status !== 200 || !decServersData.result) return null;
return { servers: decServersData.result, streamUrl, reqHeaders };
} catch { return null; }
}
export async function getStream({ id, s, e, server }) {
const meta = await getVidfastMeta(id, s, e);
if (!meta?.servers?.length) return null;
const { servers, streamUrl, reqHeaders } = meta;
let targets = servers;
if (server && server !== 'all') {
const cleanName = server.replace('VidFast - ', '');
targets = servers.filter(srv => srv.name === cleanName);
if (!targets.length) targets = servers;
}
const results = await Promise.allSettled(targets.map(async srv => {
const streamEncrypted = await fetchText(`${streamUrl}/${srv.data}`, { method: 'POST', headers: reqHeaders });
const decStreamData = await fetchJson(`${API_BASE}/dec-vidfast`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: streamEncrypted }) });
if (decStreamData.status !== 200 || !decStreamData.result?.url) throw new Error();
return { url: decStreamData.result.url, server: `VidFast - ${srv.name || 'Server'}`, type: decStreamData.result.url.includes('.m3u8') ? 'hls' : 'mp4', subtitles: (decStreamData.result.captions || []).map(c => ({ url: c.file, lang: c.label || 'Unknown' })), headers: { ...HEADERS, 'Origin': DOMAIN } };
}));
const allUrls = [];
for (const r of results) if (r.status === 'fulfilled') allUrls.push(r.value);
return allUrls.length ? { allUrls } : null;
}
export async function getSources(args) {
const meta = await getVidfastMeta(args.id, args.s, args.e);
return meta?.servers ? meta.servers.map(srv => `VidFast - ${srv.name}`) : [];
}

View File

@@ -1,249 +0,0 @@
import { getUA } from '../utils/helpers.js';
const API_BASE = 'https://vuflix.co';
const REFERER = 'https://vuflix.co/';
const ORIGIN = 'https://vuflix.co';
let cachedProviders = null;
let lastProvidersFetch = 0;
const FALLBACK_PROVIDERS = [
{ id: 'vsembed', name: 'Sigma' },
{ id: 'moonflix', name: 'Source 40' },
{ id: 'megasource', name: 'Source 39' },
{ id: 'hdghar', name: 'Source 44' },
{ id: 'moviebox', name: 'Pi' },
{ id: 'cineplay', name: '4K' },
{ id: 'huhu', name: 'Beta' },
{ id: 'bingr', name: 'Upsilon' },
{ id: 'onlyflix', name: 'Gamma' },
{ id: 'vaplayer', name: 'Alpha' },
{ id: 'flixhqz', name: 'Gamma' },
{ id: 'castle', name: 'Source 40' },
{ id: 'cinejoy', name: '4K2' },
{ id: 'filesun', name: 'Tau' },
{ id: 'yoru', name: 'Yoru' },
];
async function getProviders(ua) {
if (cachedProviders && Date.now() - lastProvidersFetch < 900000) {
return cachedProviders;
}
try {
const res = await fetch(`${API_BASE}/api/player/providers`, {
headers: {
'User-Agent': ua,
Referer: REFERER,
Origin: ORIGIN,
Accept: 'application/json, text/plain, */*',
},
signal: AbortSignal.timeout(6000),
});
if (res.ok) {
const data = await res.json();
if (data?.ok && Array.isArray(data.providers)) {
const list = data.providers
.filter(p => p && typeof p.id === 'string' && p.id.trim().length > 0)
.map(p => ({
id: p.id.trim(),
name: p.publicLabel || p.providerName || p.name || p.id,
}));
if (list.length > 0) {
cachedProviders = list;
lastProvidersFetch = Date.now();
return list;
}
}
}
} catch { }
return FALLBACK_PROVIDERS;
}
function unwrapUrl(rawUrl, ua) {
const defaultHeaders = {
'User-Agent': ua,
Referer: REFERER,
Origin: ORIGIN,
};
if (!rawUrl || typeof rawUrl !== 'string') {
return { url: '', headers: defaultHeaders };
}
if (!rawUrl.includes('v-relay?t=') && !rawUrl.includes('a-relay?t=')) {
return { url: rawUrl, headers: defaultHeaders };
}
try {
const parsedUrl = new URL(rawUrl);
const t = parsedUrl.searchParams.get('t');
if (!t) return { url: rawUrl, headers: defaultHeaders };
let b64 = t.replace(/-/g, '+').replace(/_/g, '/');
while (b64.length % 4 !== 0) {
b64 += '=';
}
const jsonStr = Buffer.from(b64, 'base64').toString('utf8');
const parsed = JSON.parse(jsonStr);
if (parsed && typeof parsed === 'object') {
const directUrl = (parsed.u || '').trim();
const headersMap = { ...defaultHeaders };
if (parsed.h && typeof parsed.h === 'object') {
for (const [key, value] of Object.entries(parsed.h)) {
headersMap[key] = String(value);
}
}
if (directUrl) {
return { url: directUrl, headers: headersMap };
}
}
} catch { }
return { url: rawUrl, headers: defaultHeaders };
}
export async function getStream({ id, s, e }) {
const isTv = Boolean(s && e);
const mediaType = isTv ? 'tv' : 'movie';
const ua = getUA();
const baseParams = new URLSearchParams({
type: mediaType,
tmdbId: String(id),
});
if (isTv) {
baseParams.set('season', String(s));
baseParams.set('episode', String(e));
}
const providers = await getProviders(ua);
const seenUrls = new Set();
const allUrls = [];
const defaultHeaders = {
'User-Agent': ua,
Referer: REFERER,
Origin: ORIGIN,
Accept: 'application/json, text/plain, */*',
};
const tasks = providers.map(async (prov) => {
try {
const url = `${API_BASE}/api/player/sources?${baseParams.toString()}&provider=${encodeURIComponent(prov.id)}`;
const res = await fetch(url, {
headers: defaultHeaders,
signal: AbortSignal.timeout(8000),
});
if (!res.ok) return;
const data = await res.json();
if (!data?.ok || !Array.isArray(data.sources)) return;
for (const item of data.sources) {
if (!item || typeof item !== 'object') continue;
const providerName = item.providerName || item.publicLabel || prov.name;
const primaryRawUrl = (item.url || '').trim();
const itemType = (item.type || 'hls').toLowerCase();
const itemLabel = item.label || '';
if (Array.isArray(item.qualities) && item.qualities.length > 0) {
for (const q of item.qualities) {
if (!q || typeof q !== 'object') continue;
const qRawUrl = (q.url || '').trim();
if (!qRawUrl) continue;
const unwrapped = unwrapUrl(qRawUrl, ua);
if (!unwrapped.url || seenUrls.has(unwrapped.url)) continue;
seenUrls.add(unwrapped.url);
const qQuality = q.quality || 'Auto';
allUrls.push({
url: unwrapped.url,
label: `${providerName} · ${qQuality}`,
headers: unwrapped.headers,
});
}
}
if (Array.isArray(item.candidates) && item.candidates.length > 0) {
let candIndex = 1;
for (const c of item.candidates) {
if (!c || typeof c !== 'object') continue;
const cRawUrl = (c.url || '').trim();
if (!cRawUrl) continue;
const unwrapped = unwrapUrl(cRawUrl, ua);
if (!unwrapped.url || seenUrls.has(unwrapped.url)) continue;
seenUrls.add(unwrapped.url);
const cQuality = c.quality || '1080p';
allUrls.push({
url: unwrapped.url,
label: `${providerName} · Mirror ${candIndex} · ${cQuality}`,
headers: unwrapped.headers,
});
candIndex++;
}
}
if (Array.isArray(item.audioTracks) && item.audioTracks.length > 0) {
for (const a of item.audioTracks) {
if (!a || typeof a !== 'object') continue;
const aRawUrl = (a.switchUrl || a.url || '').trim();
if (!aRawUrl) continue;
const unwrapped = unwrapUrl(aRawUrl, ua);
if (!unwrapped.url || seenUrls.has(unwrapped.url)) continue;
seenUrls.add(unwrapped.url);
const rawLabel = (a.label || a.name || a.language || 'Audio').trim();
const cleanLabel = rawLabel.replace(/\s*audio\s*$/i, '').trim() || 'Audio';
allUrls.push({
url: unwrapped.url,
label: `${providerName} · ${cleanLabel} Audio`,
headers: unwrapped.headers,
});
}
}
if (primaryRawUrl) {
const unwrapped = unwrapUrl(primaryRawUrl, ua);
if (unwrapped.url && !seenUrls.has(unwrapped.url)) {
seenUrls.add(unwrapped.url);
let displayQuality = item.quality || (itemType === 'mp4' ? 'MP4' : 'HD');
let cleanLabel = itemLabel || providerName;
let label = cleanLabel.startsWith('[') ? cleanLabel : `${providerName} · ${displayQuality}`;
allUrls.push({
url: unwrapped.url,
label,
headers: unwrapped.headers,
});
}
}
}
} catch { }
});
await Promise.all(tasks);
if (allUrls.length === 0) return null;
return {
url: allUrls[0].url,
allUrls,
headers: allUrls[0].headers,
};
}

View File

@@ -13,7 +13,7 @@ const CONFIG = {
TV_ID: "37854", // TV TMDB ID to test, for anime I recommend using a random ID like 37854
TV_SEASON: "1", // TV Season to test
TV_EPISODE: "1", // TV Episode to test
STREAM_SOURCE: "", // Source key to test
STREAM_SOURCE: "dulo", // Source key to test
TEST_SUBTITLE: false, // Toggle subtitle testing
TEST_DOWNLOAD: false, // Toggle download testing