Updated sources

This commit is contained in:
2026-08-17 19:08:49 -07:00
parent e3d0d4dd1c
commit 40d258b28c
13 changed files with 387 additions and 442 deletions

View File

@@ -23,7 +23,7 @@ This project is developed and maintained by [Vyla Entertainment](https://github.
Original work and core authorship:
[@endoverdosing](https://github.com/EndOverdosing)
[@alwaysmesmerizingyou](https://gitlab.com/alwaysmesmerizingyou)
[@GavinGoGaming](https://github.com/GavinGoGaming)

View File

@@ -11,7 +11,8 @@
"email": "gavin@klash.dev"
},
{
"name": "EndOverdosing"
"name": "alwaysmesmerizingyou",
"email": "alwaysmesmerizingyou@gmail.com"
}
],
"license": "CC-BY-NC-4.0",

View File

@@ -6,17 +6,6 @@
// Fshare/Fsonic Tested: 155 ( they don't have Michael )
export const SOURCES = [
{
key: '1embed',
label: '1Embed',
sourceFile: '1embed',
proxyParam: '1e',
timeout: 20000,
jitter: 500,
retries: 2,
multiUrl: true,
},
{
key: '123anime',
label: '123Anime',
@@ -145,6 +134,18 @@ 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',
@@ -252,30 +253,15 @@ export const SOURCES = [
},
{
key: 'opstream',
label: 'OpStream',
sourceFile: 'opstream',
proxyParam: 'op',
timeout: 35000,
key: 'peestream',
label: 'PeeStream',
sourceFile: 'peestream',
proxyParam: 'pee',
timeout: 25000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
verifyHeaders: {
Referer: 'https://opstream.fun/',
Origin: 'https://opstream.fun',
},
},
{
key: 'peachify',
label: 'Peachify',
sourceFile: 'peachify',
proxyParam: 'pf',
timeout: 30000,
jitter: 500,
retries: 1,
multiUrl: true
},
{
@@ -408,7 +394,8 @@ export const SOURCES = [
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true
skipProxy: true,
disabled: true, // Temporarily disabled because their site is down, embed website does not load
},
{

View File

@@ -1,115 +0,0 @@
import { USER_AGENT } from '../utils/helpers.js';
const BASE_URL = "https://1embed.cc";
const PROVIDERS = [
{ id: "BUKE", name: "1Embed - BUKE" },
{ id: "YOTA", name: "1Embed - YOTA" },
{ id: "NEPT", name: "1Embed - NEPT" },
{ id: "AZURE", name: "1Embed - AZURE" },
{ id: "YORU", name: "1Embed - YORU" }
];
let cachedToken = null;
let tokenExpiresAt = 0;
async function getToken() {
const now = Math.floor(Date.now() / 1000);
if (cachedToken && tokenExpiresAt > now + 10) return cachedToken;
try {
const res = await fetch(`${BASE_URL}/api/token`, { headers: { "Referer": `${BASE_URL}/`, "User-Agent": USER_AGENT, "Accept": "application/json" }, signal: AbortSignal.timeout(10000) });
if (!res.ok) return null;
const data = await res.json();
cachedToken = data.token;
tokenExpiresAt = data.expiresAt;
return cachedToken;
} catch { return null; }
}
function decodeBsUrl(url) {
if (!url) return url;
let target = url;
if (url.includes('d=')) {
try {
const parts = url.split(/[?&]/);
for (const part of parts) {
if (part.startsWith('d=')) {
target = decodeURIComponent(part.substring(2));
break;
}
}
} catch { }
}
if (target.startsWith('bs_')) {
try {
const decoded = Buffer.from(target.slice(3), 'base64').toString('utf-8');
const reversed = decoded.split('').reverse().join('');
if (reversed.startsWith('http')) return reversed;
} catch { }
}
return url;
}
async function fetchProviderStream(provider, type, id, s, e, token) {
try {
const referer = type === "movie" ? `${BASE_URL}/embed/movie/${id}` : `${BASE_URL}/embed/tv/${id}/${s}/${e}`;
const payload = { type, id: String(id), provider: provider.id };
if (type === "tv") { payload.season = Number(s); payload.episode = Number(e); }
const res = await fetch(`${BASE_URL}/api/sources`, {
method: "POST",
headers: { "User-Agent": USER_AGENT, "Referer": referer, "Origin": BASE_URL, "Accept": "application/json", "Content-Type": "application/json", "x-bcine-key": token, "X-Requested-With": "XMLHttpRequest" },
body: JSON.stringify(payload),
signal: AbortSignal.timeout(15000)
});
if (!res.ok) return null;
const data = await res.json();
let rawSources = [];
if (Array.isArray(data.servers)) rawSources.push(...data.servers);
if (data.providerResults?.[provider.id]?.sources) rawSources.push(...data.providerResults[provider.id].sources);
if (data.providerResults?.[provider.id] && Array.isArray(data.providerResults[provider.id])) rawSources.push(...data.providerResults[provider.id]);
if (!rawSources.length) return null;
const results = [];
for (const src of rawSources) {
if (typeof src !== 'object' || !src) continue;
let rawUrl = src.url || src.file || src.link;
if (typeof rawUrl !== 'string') continue;
let streamUrl = decodeBsUrl(rawUrl);
if (streamUrl.startsWith('/')) streamUrl = `${BASE_URL}${streamUrl}`;
const isWorker = streamUrl.includes('omena-puu') || streamUrl.includes('nocach') || streamUrl.includes('?p=');
const isHls = src.type === 'hls' || src.type === 'm3u8' || streamUrl.includes('m3u8') || isWorker;
if (isHls && !streamUrl.includes('m3u8')) streamUrl += streamUrl.includes('?') ? '&format=.m3u8' : '?format=.m3u8';
const srcHeaders = (src.headers && typeof src.headers === 'object') ? src.headers : {};
results.push({
url: streamUrl,
server: provider.name,
quality: src.quality || src.label || src.title || "Auto",
type: isHls ? "hls" : "mp4",
headers: { "User-Agent": USER_AGENT, "Referer": referer, "Origin": BASE_URL, ...srcHeaders },
});
}
return results;
} catch {
return null;
}
}
export async function getStream(args) {
const { id, s, e, server } = args;
const type = s != null && e != null ? "tv" : "movie";
const token = await getToken();
if (!token) return null;
let targets = PROVIDERS;
if (server && server !== 'all') {
const cleanName = server.replace('1Embed - ', '').toLowerCase();
targets = PROVIDERS.filter(p => p.id.toLowerCase() === cleanName || p.name.toLowerCase().includes(cleanName));
if (!targets.length) targets = PROVIDERS;
}
const settled = await Promise.allSettled(targets.map(p => fetchProviderStream(p, type, id, s, e, token)));
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 PROVIDERS.map(p => p.name); }

View File

@@ -1,26 +1,118 @@
import { fetchJson } from '../utils/helpers.js';
import { USER_AGENT, fetchJson } from '../utils/helpers.js';
export async function getStream({ id, s, e }) {
const BASE_URL = 'https://flaxmovies.xyz';
async function getWorkerUrls(embedUrl) {
const foundUrls = [];
try {
const url = s && e
? `https://sparkling-mode-a1ed.fillatame.workers.dev/?tmdb_id=${id}&season=${s}&episode=${e}`
: `https://sparkling-mode-a1ed.fillatame.workers.dev/?tmdb_id=${id}`;
const data = await fetchJson(url, { signal: AbortSignal.timeout(15000) });
if (!data || !Array.isArray(data.streams)) return null;
const allUrls = [];
for (const stream of data.streams) {
const streamUrl = stream.url || stream.link;
if (!streamUrl) continue;
const isHls = stream.format === 'HLS' || stream.isM3U8 === true || streamUrl.includes('m3u8');
allUrls.push({
url: streamUrl,
server: stream.provider || 'FlaxMovies',
quality: stream.resolution || 'Auto',
type: isHls ? 'hls' : 'mp4'
});
const res = await fetch(embedUrl, {
headers: {
'User-Agent': USER_AGENT,
'Referer': `${BASE_URL}/`,
'Origin': BASE_URL
},
signal: AbortSignal.timeout(8000)
});
if (res.ok) {
const html = await res.text();
const directMatch = html.match(/WORKER_URL\s*[:=]\s*["'](https?:\/\/[^"']+)["']/i);
if (directMatch && directMatch[1]) {
foundUrls.push(directMatch[1].replace(/\/+$/, ''));
}
const scriptMatches = [...html.matchAll(/<script[^>]+src=["']([^"']+)["']/gi)];
for (const sm of scriptMatches) {
let scriptUrl = sm[1];
if (scriptUrl.startsWith('//')) scriptUrl = `https:${scriptUrl}`;
else if (scriptUrl.startsWith('/')) scriptUrl = `${BASE_URL}${scriptUrl}`;
else if (!scriptUrl.startsWith('http')) scriptUrl = `${BASE_URL}/${scriptUrl}`;
if (scriptUrl.includes('jsdelivr') || scriptUrl.includes('google') || scriptUrl.includes('cloudflare')) continue;
try {
const sRes = await fetch(scriptUrl, {
headers: { 'User-Agent': USER_AGENT, 'Referer': embedUrl },
signal: AbortSignal.timeout(6000)
});
if (sRes.ok) {
const sCode = await sRes.text();
const m = sCode.match(/WORKER_URL\s*[:=]\s*["'](https?:\/\/[^"']+)["']/i);
if (m && m[1]) {
const wUrl = m[1].replace(/\/+$/, '');
if (!foundUrls.includes(wUrl)) foundUrls.push(wUrl);
}
}
} catch { }
}
}
return allUrls.length ? { allUrls } : null;
} catch {
return null;
} catch { }
const defaults = ['https://freakyniki.elaxo.lol', 'https://vidlove.nabilekson.workers.dev'];
for (const d of defaults) {
if (!foundUrls.includes(d)) foundUrls.push(d);
}
return foundUrls;
}
export async function getStream(args) {
const { id, s, e, server } = args;
const isTv = s != null && e != null;
const embedUrl = isTv
? `${BASE_URL}/embed/tv/${id}/${s}/${e}`
: `${BASE_URL}/embed/movie/${id}`;
const workerUrls = await getWorkerUrls(embedUrl);
const query = isTv
? `tmdb_id=${id}&tmdbId=${id}&season=${s}&episode=${e}`
: `tmdb_id=${id}&tmdbId=${id}`;
for (const worker of workerUrls) {
try {
const url = `${worker}/?${query}`;
const data = await fetchJson(url, {
headers: {
'User-Agent': USER_AGENT,
'Referer': `${BASE_URL}/`,
'Origin': BASE_URL,
'Accept': 'application/json, text/plain, */*'
},
signal: AbortSignal.timeout(12000)
});
if (data && Array.isArray(data.streams) && data.streams.length > 0) {
let allUrls = data.streams
.filter(st => st && typeof st.url === 'string')
.map(st => {
const isHls = (st.format || '').toLowerCase().includes('hls') || st.url.includes('.m3u8');
return {
url: st.url,
server: `FlaxMovies - ${st.provider || 'Default'}`,
quality: st.resolution || 'Auto',
type: isHls ? 'hls' : 'mp4',
headers: {
'User-Agent': USER_AGENT,
'Referer': `${BASE_URL}/`,
'Origin': BASE_URL
}
};
});
if (server && server !== 'all') {
const clean = server.toLowerCase().replace('flaxmovies - ', '');
const filtered = allUrls.filter(u => u.server.toLowerCase().includes(clean));
if (filtered.length) allUrls = filtered;
}
if (allUrls.length) {
return { allUrls };
}
}
} catch { }
}
return null;
}
export async function getSources() {
return ['FlaxMovies - Airflix', 'FlaxMovies - Xpass-VIP 1'];
}

88
src/sources/frame.js Normal file
View File

@@ -0,0 +1,88 @@
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

@@ -76,13 +76,29 @@ export async function getStream(args) {
const reqMatch = html.match(/window\.__REQUEST_TOKEN__\s*=\s*"([^"]+)"/);
if (!reqMatch) return null;
const requestToken = reqMatch[1];
const initRes = await fetch(`${BASE_URL}/api/playback-init`, { method: "POST", headers: { "Content-Type": "application/json", ...PROXY_HEADERS, Referer: pageUrl }, body: JSON.stringify({ mediaId: Number(id), mediaType, requestToken }), signal: AbortSignal.timeout(10000) });
const cookies = pageRes.headers.getSetCookie();
const cookieHeader = cookies.map(c => c.split(';')[0]).join('; ');
const initHeaders = { "Content-Type": "application/json", ...PROXY_HEADERS, Referer: pageUrl };
if (cookieHeader) initHeaders.Cookie = cookieHeader;
const initRes = await fetch(`${BASE_URL}/api/playback-init`, {
method: "POST",
headers: initHeaders,
body: JSON.stringify({ mediaId: Number(id), mediaType, requestToken }),
signal: AbortSignal.timeout(10000)
});
const initData = await initRes.json();
let streamToken = initData.token;
if (initData.requiresPow && initData.pow) {
const powRes = solvePoW(initData.pow.challenge, initData.pow.difficulty);
if (powRes.found) {
const solveRes = await fetch(`${BASE_URL}/api/playback-init`, { method: "POST", headers: { "Content-Type": "application/json", ...PROXY_HEADERS, Referer: pageUrl }, body: JSON.stringify({ mediaId: Number(id), mediaType, requestToken, pow: { challengeId: initData.pow.challengeId, nonce: powRes.nonce } }), signal: AbortSignal.timeout(10000) });
const solveRes = await fetch(`${BASE_URL}/api/playback-init`, {
method: "POST",
headers: initHeaders,
body: JSON.stringify({ mediaId: Number(id), mediaType, requestToken, pow: { challengeId: initData.pow.challengeId, nonce: powRes.nonce } }),
signal: AbortSignal.timeout(10000)
});
streamToken = (await solveRes.json()).token;
}
}
@@ -96,8 +112,28 @@ export async function getStream(args) {
const allUrls = [];
for (const srv of targets) {
try {
const streamUrl = `${BASE_URL}/api/stream?mediaId=${id}&mediaType=${mediaType}&tv_slug=${tvSlug}&source=${srv.id}&apikey=mptv_sk_a8f29c4e7b3d1f&requestToken=${requestToken}&token=${streamToken}`;
const streamRes = await fetch(streamUrl, { headers: { ...PROXY_HEADERS, Referer: pageUrl }, signal: AbortSignal.timeout(8000) });
const encryptRes = await fetch(`${BASE_URL}/api/encrypt`, {
method: "POST",
headers: initHeaders,
body: JSON.stringify({
data: {
mediaId: Number(id),
mediaType,
tv_slug: tvSlug,
source: srv.id,
apikey: "mptv_sk_a8f29c4e7b3d1f"
}
}),
signal: AbortSignal.timeout(8000)
});
const encryptData = await encryptRes.json();
if (!encryptData.encrypted) continue;
const streamUrl = `${BASE_URL}/api/stream-encrypted?data=${encodeURIComponent(encryptData.encrypted)}&requestToken=${encodeURIComponent(requestToken)}&token=${encodeURIComponent(streamToken)}`;
const streamRes = await fetch(streamUrl, {
headers: { ...PROXY_HEADERS, Referer: pageUrl, ...(cookieHeader ? { Cookie: cookieHeader } : {}) },
signal: AbortSignal.timeout(8000)
});
const streamData = await streamRes.json();
if (streamData.success && streamData.data?.stream_url) {
let fileUrl = streamData.data.stream_url;

View File

@@ -13,15 +13,7 @@ const HEADERS = {
};
const SERVERS = [
'pseudo',
'lynx',
'tik',
'ipcloud',
'v4:English',
'turkce',
'v5:Hindi',
'v4:Hindi',
'v6:Hindi'
'hindiv3'
];
const TIMEOUT_MS = 15000;

View File

@@ -1,57 +0,0 @@
import { fetchJson, fetchText, getTmdbInfo, tmdbToAnilist } from '../utils/helpers.js';
const BASE_URL = "https://nekowatch.xyz";
const ANIME_JS_URL = `${BASE_URL}/js/anime.js?v=v263_fast_player_start`;
const FALLBACK_ORDER = ['kiwi', 'ally', 'bee', 'arc', 'anikoto', 'jet', 'bonk', 'moo', 'hop', 'pulsar', 'pahe'];
let providerOrderCache = null, providerOrderTs = 0;
async function getProviderOrder() {
const now = Date.now();
if (providerOrderCache && now - providerOrderTs < 1800000) return providerOrderCache;
try {
const js = await fetchText(ANIME_JS_URL, { signal: AbortSignal.timeout(6000) });
const match = js.match(/PROVIDER_ORDER\s*=\s*\[([\s\S]*?)\]/);
if (match) {
const order = [...match[1].matchAll(/['"]([a-z0-9_]+)['"]/gi)].map(m => m[1]);
if (order.length) { providerOrderCache = order; providerOrderTs = now; return order; }
}
} catch { }
return providerOrderCache || FALLBACK_ORDER;
}
export async function getStream({ id, s, e, audio }) {
try {
const info = await getTmdbInfo(id, s ? 'tv' : 'movie', s);
if (!info || !info.isAnime) return null;
const anilistId = await tmdbToAnilist(id, s ? 'tv' : 'movie', s, info.titles, info.year);
if (!anilistId) return null;
const ep = e || 1;
const audiosToTry = audio === "all" ? ["sub", "dub"] : (audio === "dub" ? ["dub", "sub"] : ["sub", "dub"]);
const providerOrder = await getProviderOrder();
for (const aud of audiosToTry) {
const results = await Promise.allSettled(providerOrder.map(p => fetchJson(`${BASE_URL}/api/anime/watch/${p}/${anilistId}/${aud}/${p}-${ep}`, { signal: AbortSignal.timeout(8000) })));
const allUrls = [], seenActual = new Set();
for (const r of results) {
if (r.status !== 'fulfilled' || !r.value) continue;
const data = r.value;
let streams = [], actual = data.attempted?.actualProvider || data.provider;
if (Array.isArray(data.streams)) streams = data.streams;
else {
for (const key of Object.keys(data)) if (data[key] && Array.isArray(data[key].streams)) { streams.push(...data[key].streams); if (!actual) actual = data[key].provider || key; }
}
if (!streams.length) continue;
if (actual) { if (seenActual.has(actual)) continue; seenActual.add(actual); }
const valid = streams.filter(st => st.type === "hls" && st.url).sort((a, b) => (b.priority || 0) - (a.priority || 0));
for (const st of valid) allUrls.push({ url: st.url, type: "hls", audio: aud, server: st.server ? `NekoWatch-${st.server}` : "NekoWatch", headers: st.referer ? { Referer: st.referer } : undefined, skipProxy: /\.workers\.dev(\/|$)/i.test(st.url) });
}
if (allUrls.length) return { allUrls };
}
return null;
} catch { return null; }
}
export async function getSources(args) {
const stream = await getStream(args);
return stream?.allUrls ? [...new Set(stream.allUrls.map(u => u.server))] : [];
}

View File

@@ -1,123 +0,0 @@
import { getTmdbInfo, USER_AGENT } from '../utils/helpers.js';
const BASE_URL = 'https://opstream.fun';
const API_BASE = `${BASE_URL}/api/resolve`;
const API_HEADERS = {
'User-Agent': USER_AGENT,
'Accept': 'application/x-ndjson; charset=utf-8',
'Referer': `${BASE_URL}/`,
'Origin': BASE_URL,
};
const STREAM_HEADERS = {
'User-Agent': USER_AGENT,
'Referer': `${BASE_URL}/`,
'Origin': BASE_URL,
};
export async function getStream({ id, s, e }) {
try {
const isTv = s != null && e != null;
const info = await getTmdbInfo(id, isTv ? 'tv' : 'movie');
if (!info?.titles?.length || !info.imdbId) return null;
const params = new URLSearchParams({
type: isTv ? 'tv' : 'movie',
tmdbId: id,
title: info.titles[0],
year: info.year || '',
imdbId: info.imdbId,
progress: '1'
});
if (isTv) {
params.append('season', s);
params.append('episode', e);
}
const res = await fetch(`${API_BASE}?${params}`, {
headers: API_HEADERS,
signal: AbortSignal.timeout(15000)
});
if (!res.ok) return null;
const text = await res.text();
const lines = text.split('\n');
let streamData = null;
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
try {
const json = JSON.parse(trimmed);
if (json.t === 'done' && json.data) {
streamData = json.data;
break;
}
} catch { continue; }
}
if (!streamData) return null;
const subtitles = (streamData.captions || []).map(c => ({
url: c.url.startsWith('http') ? c.url : `${BASE_URL}${c.url}`,
lang: c.label || 'Unknown'
}));
const allUrls = [];
if (streamData.qualities && streamData.qualities.length > 0) {
for (const q of streamData.qualities) {
let finalUrl = q.url;
if (!finalUrl.startsWith('http')) {
finalUrl = `${BASE_URL}${finalUrl}`;
}
const isDash = finalUrl.includes('.mpd');
const isHls = finalUrl.includes('.m3u8');
allUrls.push({
url: finalUrl,
server: `OpStream - ${q.label}`,
type: isDash ? 'dash' : (isHls ? 'hls' : 'mp4'),
headers: STREAM_HEADERS,
subtitles,
skipProxy: true
});
}
} else if (streamData.url) {
let finalUrl = streamData.url;
if (finalUrl.includes('?u=')) {
try {
const uParam = new URL(finalUrl, BASE_URL).searchParams.get('u');
if (uParam) finalUrl = Buffer.from(uParam, 'base64').toString('utf8');
} catch {}
} else if (!finalUrl.startsWith('http')) {
finalUrl = `${BASE_URL}${finalUrl}`;
}
const isDash = streamData.kind === 'dash' || finalUrl.includes('.mpd');
const isHls = streamData.kind === 'hls' || finalUrl.includes('.m3u8');
allUrls.push({
url: finalUrl,
server: 'OpStream',
type: isDash ? 'dash' : (isHls ? 'hls' : 'mp4'),
headers: STREAM_HEADERS,
subtitles,
skipProxy: true
});
}
if (allUrls.length === 0) return null;
return { allUrls };
} catch { return null; }
}
export async function getSources() {
return ['OpStream'];
}

View File

@@ -1,78 +0,0 @@
import { fetchJson, USER_AGENT } from '../utils/helpers.js';
const DEC_API = "https://enc-dec.app/api/dec-peachify";
const ORIGIN = "https://peachify.top";
const HEADERS = { "User-Agent": USER_AGENT, "Origin": ORIGIN, "Referer": `${ORIGIN}/` };
const SERVERS = [
{ label: "Wolf", path: "air", api: "https://usa.eat-peach.sbs" },
{ label: "Spider", path: "holly", api: "https://usa.eat-peach.sbs" },
{ label: "Iron", path: "moviebox", api: "https://uwu.eat-peach.sbs" },
{ label: "Multi", path: "multi", api: "https://usa.eat-peach.sbs" },
{ label: "Dark", path: "net", api: "https://uwu.eat-peach.sbs" },
];
export async function getStream({ id, s, e, server }) {
try {
const isTv = s != null && e != null;
const segment = isTv ? `tv/${id}/${s}/${e}` : `movie/${id}`;
let targets = SERVERS;
if (server && server !== 'all') {
const cleanName = server.replace('Peachify - ', '');
targets = SERVERS.filter(srv => srv.label === cleanName);
if (!targets.length) targets = SERVERS;
}
const settled = await Promise.allSettled(targets.map(async srv => {
const url = `${srv.api}/${srv.path}/${segment}`;
const rawData = await fetchJson(url, { headers: HEADERS, signal: AbortSignal.timeout(10000) });
if (!rawData?.data) throw new Error();
const decJson = await fetchJson(DEC_API, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: rawData.data }),
signal: AbortSignal.timeout(10000)
});
if (decJson.status !== 200 || !decJson.result) throw new Error();
const res = decJson.result;
const sources = Array.isArray(res) ? res : (res.sources || [res]);
const subs = res.subtitles || [];
return sources.map(source => {
const streamUrl = source.url || source.file || source.link;
if (!streamUrl) return null;
return {
url: streamUrl,
server: `Peachify - ${srv.label}`,
quality: source.quality || "Auto",
type: streamUrl.includes('.m3u8') ? 'hls' : 'mp4',
headers: { ...HEADERS, "Origin": ORIGIN },
subtitles: subs.map(sub => ({
url: sub.url || sub.file,
lang: sub.language || sub.lang || sub.label || 'Unknown'
})),
skipProxy: false,
skipVerify: true,
skipHlsCheck: true
};
}).filter(Boolean);
}));
const allUrls = [];
for (const r of settled) {
if (r.status === 'fulfilled' && r.value) allUrls.push(...r.value);
}
return allUrls.length ? { allUrls } : null;
} catch { return null; }
}
export async function getSources() {
return SERVERS.map(s => `Peachify - ${s.label}`);
}

122
src/sources/peestream.js Normal file
View File

@@ -0,0 +1,122 @@
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

@@ -18,7 +18,7 @@ const CONFIG = {
TEST_SUBTITLE: false, // Toggle subtitle testing
TEST_DOWNLOAD: false, // Toggle download testing
TEST_MOVIE: false, // Toggle movie testing
TEST_MOVIE: true, // Toggle movie testing
TEST_TV: true // Toggle TV testing
};