mirror of
https://gitlab.com/vyla-entertainment/sdk.git
synced 2026-11-09 19:57:23 -05:00
added cinesu & pstream, removed vidrift & vidsync
This commit is contained in:
@@ -115,6 +115,26 @@ export const SOURCES = [
|
||||
skipProxy: true,
|
||||
},
|
||||
|
||||
{
|
||||
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: 'flaxmovies',
|
||||
label: 'FlaxMovies',
|
||||
@@ -303,6 +323,17 @@ export const SOURCES = [
|
||||
disabled: false, // Enabled, but only returns streams when a manifest is provided
|
||||
},
|
||||
|
||||
{
|
||||
key: 'pstream',
|
||||
label: 'PStream',
|
||||
sourceFile: 'pstream',
|
||||
proxyParam: 'ps',
|
||||
timeout: 35000,
|
||||
jitter: 500,
|
||||
retries: 1,
|
||||
multiUrl: true,
|
||||
},
|
||||
|
||||
{
|
||||
key: 'nova',
|
||||
label: 'Nova',
|
||||
@@ -456,19 +487,6 @@ export const SOURCES = [
|
||||
skipProxy: true,
|
||||
},
|
||||
|
||||
{
|
||||
key: 'vidrift',
|
||||
label: 'VidRift',
|
||||
sourceFile: 'vidrift',
|
||||
proxyParam: 'vr',
|
||||
timeout: 20000,
|
||||
jitter: 500,
|
||||
retries: 2,
|
||||
multiUrl: true,
|
||||
skipProxy: true,
|
||||
disabled: true, // Temporarily disabled because their site is down, embed website does not load
|
||||
},
|
||||
|
||||
{
|
||||
key: 'vidrock',
|
||||
label: 'VidRock',
|
||||
@@ -489,17 +507,6 @@ export const SOURCES = [
|
||||
},],
|
||||
},
|
||||
|
||||
{
|
||||
key: 'vidsync',
|
||||
label: 'VidSync',
|
||||
sourceFile: 'vidsync',
|
||||
proxyParam: 'vs',
|
||||
timeout: 20000,
|
||||
retries: 2,
|
||||
multiUrl: true,
|
||||
disabled: true, // Temporarily disabled due to enc dec issues
|
||||
},
|
||||
|
||||
{
|
||||
key: 'vidup',
|
||||
label: 'VidUp',
|
||||
|
||||
148
src/sources/cinesu.js
Normal file
148
src/sources/cinesu.js
Normal file
@@ -0,0 +1,148 @@
|
||||
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
|
||||
}]
|
||||
};
|
||||
}
|
||||
68
src/sources/pstream.js
Normal file
68
src/sources/pstream.js
Normal file
@@ -0,0 +1,68 @@
|
||||
import { USER_AGENT } from '../utils/helpers.js';
|
||||
|
||||
async function safeImport(moduleName) {
|
||||
try {
|
||||
return await import(`./${moduleName}.js`);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStream(args) {
|
||||
const { id, s, e, clientIP, sdk } = args;
|
||||
const isTv = s != null && e != null;
|
||||
const type = isTv ? 'tv' : 'movie';
|
||||
const allUrls = [];
|
||||
|
||||
const providers = [
|
||||
{ name: 'CineSu', key: 'cinesu', fnName: 'fetchCineSuStreams' },
|
||||
{ name: 'ZxcStream', key: 'zxcstream', fnName: 'fetchZxcStreams' },
|
||||
{ name: 'VidFast', key: 'vidfast', fnName: 'fetchVidFastStreams' },
|
||||
{ name: '1Embed', key: '1embed', fnName: 'fetchOneEmbedStreams' },
|
||||
];
|
||||
|
||||
await Promise.all(
|
||||
providers.map(async ({ name, key, fnName }) => {
|
||||
try {
|
||||
let streamResult = null;
|
||||
|
||||
if (sdk) {
|
||||
try {
|
||||
streamResult = await sdk.getStream(key, id, s, e, clientIP);
|
||||
} catch { }
|
||||
}
|
||||
|
||||
if (!streamResult) {
|
||||
const mod = await safeImport(key);
|
||||
if (mod) {
|
||||
if (typeof mod.getStream === 'function') {
|
||||
streamResult = await mod.getStream(args);
|
||||
} else if (typeof mod[fnName] === 'function') {
|
||||
const raw = await mod[fnName]({ type, id, season: s, episode: e });
|
||||
if (Array.isArray(raw)) {
|
||||
streamResult = { allUrls: raw };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!streamResult) return;
|
||||
|
||||
const streams = streamResult.allUrls || (streamResult.url ? [streamResult] : []);
|
||||
for (const item of streams) {
|
||||
allUrls.push({
|
||||
url: item.url,
|
||||
server: `FlyStream (${item.source || item.server || name})`,
|
||||
quality: item.quality || 'Auto',
|
||||
type: item.type || item.format || (item.url?.includes('.m3u8') ? 'hls' : 'mp4'),
|
||||
headers: item.headers || {
|
||||
'User-Agent': USER_AGENT,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch { }
|
||||
})
|
||||
);
|
||||
|
||||
return allUrls.length ? { allUrls } : null;
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const BASE = "https://embed.vidrift.in";
|
||||
|
||||
const DEFAULT_HEADERS = {
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "en-US,en;q=0.9",
|
||||
"Cache-Control": "no-cache",
|
||||
"Pragma": "no-cache",
|
||||
"Referer": `${BASE}/`,
|
||||
"Origin": BASE,
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0"
|
||||
};
|
||||
|
||||
function decodeStreams(encodedStr) {
|
||||
try {
|
||||
const base64Str = encodedStr.replace(/-/g, '+').replace(/_/g, '/');
|
||||
|
||||
const binaryStr = typeof atob === 'function'
|
||||
? atob(base64Str)
|
||||
: Buffer.from(base64Str, 'base64').toString('binary');
|
||||
|
||||
const bytes = new Uint8Array(binaryStr.length);
|
||||
for (let i = 0; i < binaryStr.length; i++) {
|
||||
bytes[i] = binaryStr.charCodeAt(i);
|
||||
}
|
||||
|
||||
const key = bytes[0];
|
||||
let decodedStr = '';
|
||||
for (let i = 1; i < bytes.length; i++) {
|
||||
decodedStr += String.fromCharCode(bytes[i] ^ key);
|
||||
}
|
||||
|
||||
return JSON.parse(decodedStr);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStream(args) {
|
||||
const { id, s, e, server: serverName } = args;
|
||||
const type = s != null && e != null ? "tv" : "movie";
|
||||
|
||||
const endpoint = type === "tv"
|
||||
? `${BASE}/embed/tv/${id}/${s}/${e}`
|
||||
: `${BASE}/embed/movie/${id}`;
|
||||
|
||||
try {
|
||||
const res = await fetch(endpoint, {
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
"Accept": "text/html",
|
||||
},
|
||||
signal: AbortSignal.timeout(10000)
|
||||
});
|
||||
|
||||
if (!res.ok) return null;
|
||||
|
||||
const html = await res.text();
|
||||
|
||||
const match = html.match(/var\s+_s\s*=\s*['"]([^'"]+)['"]/);
|
||||
if (!match) return null;
|
||||
|
||||
const encodedStreams = match[1];
|
||||
const streamsData = decodeStreams(encodedStreams);
|
||||
|
||||
if (!Array.isArray(streamsData) || !streamsData.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const allUrls = streamsData.map((stream, index) => ({
|
||||
url: stream.url.startsWith("http")
|
||||
? stream.url
|
||||
: `${BASE}${stream.url}`,
|
||||
server: stream.label || `VidRift - Server ${index + 1}`,
|
||||
type: "hls",
|
||||
headers: DEFAULT_HEADERS
|
||||
}));
|
||||
|
||||
if (serverName && serverName !== "all") {
|
||||
const filtered = allUrls.filter(x => x.server === serverName);
|
||||
return filtered.length ? { allUrls: filtered } : null;
|
||||
}
|
||||
|
||||
return { allUrls };
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSources(args) {
|
||||
const res = await getStream(args);
|
||||
if (!res?.allUrls) return ["VidRift - Server 1"];
|
||||
return res.allUrls.map(x => x.server);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { fetchJson, fetchText, USER_AGENT, getTmdbInfo } from '../utils/helpers.js';
|
||||
|
||||
const API_BASE = "https://enc-dec.app/api";
|
||||
const DOMAIN = "https://vidsync.xyz";
|
||||
const HEADERS = { "Accept": "*/*", "Origin": DOMAIN, "Referer": `${DOMAIN}/`, "User-Agent": USER_AGENT, "X-Requested-With": "XMLHttpRequest" };
|
||||
const SERVERS = ["cinevault", "cinedub", "cinebox", "cineflix", "cinevip", "cinecloud", "cine4k"];
|
||||
|
||||
export async function getStream({ id, s, e, server }) {
|
||||
try {
|
||||
const isTv = s != null && e != null;
|
||||
const type = isTv ? 'tv' : 'movie';
|
||||
const info = await getTmdbInfo(id, type);
|
||||
if (!info?.titles?.length) return null;
|
||||
const turnstileJson = await fetchJson(`${API_BASE}/enc-vidsync`, { signal: AbortSignal.timeout(5000) });
|
||||
if (turnstileJson.status !== 200 || !turnstileJson.result?.token) return null;
|
||||
const turnstileToken = turnstileJson.result.token;
|
||||
let targets = SERVERS;
|
||||
if (server && server !== 'all') {
|
||||
const clean = server.replace('VidSync - ', '');
|
||||
targets = SERVERS.includes(clean) ? [clean] : SERVERS;
|
||||
}
|
||||
const encTitle = encodeURIComponent(info.titles[0]).replace(/%20/g, '+');
|
||||
const results = await Promise.allSettled(targets.map(async srv => {
|
||||
let url = `${DOMAIN}/api/stream/fetch?title=${encTitle}&type=${type}&releaseYear=${info.year}&mediaId=${id}&serverName=${srv}`;
|
||||
if (isTv) url += `&season=${s}&episode=${e}`;
|
||||
const encryptedText = await fetchText(url, { headers: { ...HEADERS, "X-Cf-Turnstile": turnstileToken }, signal: AbortSignal.timeout(10000) });
|
||||
const decJson = await fetchJson(`${API_BASE}/dec-vidsync`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: encryptedText, id: String(id) }), signal: AbortSignal.timeout(10000) });
|
||||
if (decJson.status !== 200 || !decJson.result) throw new Error();
|
||||
const streams = Array.isArray(decJson.result) ? decJson.result : [decJson.result];
|
||||
return streams.map(st => ({ url: st.url || st.file, server: `VidSync - ${srv}`, quality: st.quality || "Auto", type: (st.url || st.file || "").includes(".m3u8") ? "hls" : "mp4", headers: { ...HEADERS, "Origin": DOMAIN }, skipProxy: false, skipVerify: true, skipHlsCheck: true }));
|
||||
}));
|
||||
const allUrls = [];
|
||||
for (const r of results) if (r.status === 'fulfilled') allUrls.push(...r.value);
|
||||
return allUrls.length ? { allUrls } : null;
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
export async function getSources() { return SERVERS.map(s => `VidSync - ${s}`); }
|
||||
Reference in New Issue
Block a user