mirror of
https://gitlab.com/vyla-entertainment/sdk.git
synced 2026-11-09 19:57:23 -05:00
Add nova/mega, enable pengu with new config, provide SDK directly
This commit is contained in:
@@ -300,7 +300,29 @@ export const SOURCES = [
|
||||
retries: 1,
|
||||
multiUrl: true,
|
||||
skipProxy: true,
|
||||
disabled: true, // Temporarily disabled because they now require google auth
|
||||
disabled: false, // Enabled, but only returns streams when a manifest is provided
|
||||
},
|
||||
|
||||
{
|
||||
key: 'nova',
|
||||
label: 'Nova',
|
||||
sourceFile: 'nova',
|
||||
proxyParam: 'nv',
|
||||
timeout: 25000,
|
||||
jitter: 500,
|
||||
retries: 1,
|
||||
multiUrl: true,
|
||||
},
|
||||
|
||||
{
|
||||
key: 'megasource',
|
||||
label: 'MegaSource',
|
||||
sourceFile: 'megasource',
|
||||
proxyParam: 'mg',
|
||||
timeout: 25000,
|
||||
jitter: 500,
|
||||
retries: 1,
|
||||
multiUrl: true,
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ async function withRetry(fn, attempts = 2, delay = 300) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function probeSource(tmdbApiKey, cfg, mod) {
|
||||
export async function probeSource(sdk, cfg, mod) {
|
||||
const audio = /dub$/.test(cfg.key) ? 'dub' : 'sub';
|
||||
const streamArgs = {
|
||||
id: HEALTH_PROBE_ID,
|
||||
@@ -23,7 +23,7 @@ export async function probeSource(tmdbApiKey, cfg, mod) {
|
||||
clientIP: null,
|
||||
absoluteBase: null,
|
||||
audio,
|
||||
tmdbApiKey,
|
||||
sdk,
|
||||
config: cfg,
|
||||
};
|
||||
|
||||
|
||||
11
src/sdk.js
11
src/sdk.js
@@ -13,8 +13,11 @@ const SOURCE_MODULES = Object.fromEntries(
|
||||
);
|
||||
|
||||
export default class VylaSDK {
|
||||
constructor({ tmdbApiKey } = {}) {
|
||||
this.tmdbApiKey = tmdbApiKey;
|
||||
tmdbApiKey = null;
|
||||
penguManifest = null;
|
||||
constructor({ tmdbApiKey, penguManifest } = {}) {
|
||||
this.tmdbApiKey = tmdbApiKey || null;
|
||||
this.penguManifest = penguManifest || null;
|
||||
}
|
||||
getSources(excludeDisabled = false) {
|
||||
if (excludeDisabled) {
|
||||
@@ -43,14 +46,14 @@ export default class VylaSDK {
|
||||
if (!cfg) throw new Error(`Source with key "${key}" not found`);
|
||||
const mod = SOURCE_MODULES[key];
|
||||
if (!mod) throw new Error(`Source module for key "${key}" not found`);
|
||||
return await probeSource(this.tmdbApiKey, cfg, mod);
|
||||
return await probeSource(this, cfg, mod);
|
||||
}
|
||||
async getStream(key, id, s = null, e = null, clientIP = null) {
|
||||
const cfg = SOURCES.find(cfg => cfg.key === key);
|
||||
if (!cfg) throw new Error(`Source with key "${key}" not found`);
|
||||
const mod = SOURCE_MODULES[key];
|
||||
if (!mod) throw new Error(`Source module for key "${key}" not found`);
|
||||
const streamArgs = await createStreamArgs(cfg, this.tmdbApiKey, id, s, e, clientIP);
|
||||
const streamArgs = await createStreamArgs(cfg, this, id, s, e, clientIP);
|
||||
return await mod.getStream(streamArgs);
|
||||
}
|
||||
async getSubtitles(id, s = null, e = null) {
|
||||
|
||||
@@ -69,7 +69,9 @@ async function extractHls(embedUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function getStream({ id, s, e, audio, tmdbApiKey }) {
|
||||
export async function getStream({ id, s, e, audio, sdk }) {
|
||||
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
||||
if (!tmdbApiKey) return null;
|
||||
try {
|
||||
const info = await getTmdbInfo(tmdbApiKey, id, s ? 'tv' : 'movie', s);
|
||||
if (!info || !info.isAnime) return null;
|
||||
|
||||
@@ -4,7 +4,9 @@ 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, tmdbApiKey }) {
|
||||
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');
|
||||
|
||||
@@ -4,7 +4,9 @@ const ORIGIN = 'https://www3.fsonline.app';
|
||||
const AJAX_URL = `${ORIGIN}/wp-admin/admin-ajax.php`;
|
||||
const HEADERS = { 'User-Agent': USER_AGENT, 'Origin': ORIGIN, 'Referer': `${ORIGIN}/` };
|
||||
|
||||
export async function getStream({ id, s, e, tmdbApiKey }) {
|
||||
export async function getStream({ id, s, e, sdk }) {
|
||||
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
||||
if (!tmdbApiKey) return null;
|
||||
try {
|
||||
const isTv = s != null && e != null;
|
||||
const info = await getTmdbInfo(tmdbApiKey, id, isTv ? 'tv' : 'movie');
|
||||
|
||||
@@ -47,7 +47,9 @@ function getEpisodeIdFast(html, s, e) {
|
||||
return am ? am[1] : null;
|
||||
}
|
||||
|
||||
export async function getStream({ id, s, e, tmdbApiKey, clientIP }) {
|
||||
export async function getStream({ id, s, e, sdk, clientIP }) {
|
||||
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
||||
if (!tmdbApiKey) return null;
|
||||
try {
|
||||
const tmdbKey = tmdbApiKey;
|
||||
if (!tmdbKey) return null;
|
||||
|
||||
47
src/sources/megasource.js
Normal file
47
src/sources/megasource.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import { fetchJson } from '../utils/helpers.js';
|
||||
|
||||
const CONFIGURATION = 'W3siaWQiOiJkZWZhdWx0IiwibmFtZSI6Ik1lZ2FTb3VyY2UgZGVmYXVsdCIsInVybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS96b3JldS9tZWdhc291cmNlX3NjcmFwZXJzL3Jhdy9yZWZzL2hlYWRzL21haW4vZGVmYXVsdF9zY3JhcGVyLnB5IiwiZGVzY3JpcHRpb24iOiJEZWZhdWx0IHNjcmFwZXIgaG9zdGVkIG9uIEdpdEh1Yi4ifV0';
|
||||
const BASE_URL = `https://megasource.wasmer.app/${CONFIGURATION}`;
|
||||
|
||||
async function getImdbId(tmdbApiKey, tmdbId, s, e) {
|
||||
const key = tmdbApiKey;
|
||||
if (!key) return null;
|
||||
try {
|
||||
const url = s != null && e != null
|
||||
? `https://api.themoviedb.org/3/tv/${tmdbId}/external_ids?api_key=${key}`
|
||||
: `https://api.themoviedb.org/3/movie/${tmdbId}?api_key=${key}`;
|
||||
const res = await fetchJson(url);
|
||||
return res?.imdb_id || null;
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
export async function getStream({ id, s, e, sdk }) {
|
||||
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
||||
if (!tmdbApiKey) return null;
|
||||
try {
|
||||
const imdbId = await getImdbId(tmdbApiKey, id, s, e);
|
||||
if (!imdbId) return null;
|
||||
|
||||
const path = s != null && e != null
|
||||
? `/stream/series/${imdbId}:${s}:${e}.json`
|
||||
: `/stream/movie/${imdbId}.json`;
|
||||
|
||||
const res = await fetchJson(`${BASE_URL}${path}`);
|
||||
if (!res?.streams?.length) return null;
|
||||
|
||||
const allUrls = res.streams.map(stream => {
|
||||
if (!stream.url) return null;
|
||||
const headers = stream.behaviorHints?.proxyHeaders?.request || {};
|
||||
return {
|
||||
url: stream.url,
|
||||
server: `MegaSource - ${stream.title ? ` ${stream.title}` : ''}`,
|
||||
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
||||
skipProxy: Object.keys(headers).length > 0 && stream.behaviorHints?.notWebReady === false
|
||||
};
|
||||
}).filter(Boolean);
|
||||
|
||||
return allUrls.length ? { allUrls } : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
46
src/sources/nova.js
Normal file
46
src/sources/nova.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import { fetchJson } from '../utils/helpers.js';
|
||||
|
||||
const BASE_URL = `https://nova-streamz.vercel.app`;
|
||||
|
||||
async function getImdbId(tmdbApiKey, tmdbId, s, e) {
|
||||
const key = tmdbApiKey;
|
||||
if (!key) return null;
|
||||
try {
|
||||
const url = s != null && e != null
|
||||
? `https://api.themoviedb.org/3/tv/${tmdbId}/external_ids?api_key=${key}`
|
||||
: `https://api.themoviedb.org/3/movie/${tmdbId}?api_key=${key}`;
|
||||
const res = await fetchJson(url);
|
||||
return res?.imdb_id || null;
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
export async function getStream({ id, s, e, sdk }) {
|
||||
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
||||
if (!tmdbApiKey) return null;
|
||||
try {
|
||||
const imdbId = await getImdbId(tmdbApiKey, id, s, e);
|
||||
if (!imdbId) return null;
|
||||
|
||||
const path = s != null && e != null
|
||||
? `/stream/series/${imdbId}:${s}:${e}.json`
|
||||
: `/stream/movie/${imdbId}.json`;
|
||||
|
||||
const res = await fetchJson(`${BASE_URL}${path}`);
|
||||
if (!res?.streams?.length) return null;
|
||||
|
||||
const allUrls = res.streams.map(stream => {
|
||||
if (!stream.url) return null;
|
||||
const headers = stream.behaviorHints?.proxyHeaders?.request || {};
|
||||
return {
|
||||
url: stream.url,
|
||||
server: `Nova - ${stream.name.replace('Nova ', '') || 'Server'}${stream.title ? ` ${stream.title.split(' | ')[0] || ''}` : ''}`,
|
||||
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
||||
skipProxy: Object.keys(headers).length > 0 && stream.behaviorHints?.notWebReady === false
|
||||
};
|
||||
}).filter(Boolean);
|
||||
|
||||
return allUrls.length ? { allUrls } : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { fetchJson } from '../utils/helpers.js';
|
||||
|
||||
const PENGU_CONFIG = '%7B%22source_4khdhub%22%3A%22on%22%2C%22source_moviebox%22%3A%22on%22%2C%22source_moviesdrives%22%3A%22on%22%2C%22source_vaplayer%22%3A%22on%22%2C%22source_hdghartv%22%3A%22on%22%2C%22res_2160%22%3A%22on%22%2C%22res_1080%22%3A%22on%22%2C%22res_720%22%3A%22on%22%2C%22disable_direct%22%3A%22on%22%7D';
|
||||
const BASE_URL = `https://pengu.uk/${PENGU_CONFIG}`;
|
||||
// const PENGU_CONFIG = '%7B%22source_4khdhub%22%3A%22on%22%2C%22source_moviebox%22%3A%22on%22%2C%22source_moviesdrives%22%3A%22on%22%2C%22source_vaplayer%22%3A%22on%22%2C%22source_hdghartv%22%3A%22on%22%2C%22res_2160%22%3A%22on%22%2C%22res_1080%22%3A%22on%22%2C%22res_720%22%3A%22on%22%2C%22disable_direct%22%3A%22on%22%7D';
|
||||
// const BASE_URL = `https://pengu.uk/${PENGU_CONFIG}`;
|
||||
|
||||
async function getImdbId(tmdbApiKey, tmdbId, s, e) {
|
||||
const key = tmdbApiKey;
|
||||
@@ -15,7 +15,12 @@ async function getImdbId(tmdbApiKey, tmdbId, s, e) {
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
export async function getStream({ id, s, e, tmdbApiKey }) {
|
||||
export async function getStream({ id, s, e, sdk }) {
|
||||
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
||||
const manifest = sdk?.penguManifest || null;
|
||||
if (!tmdbApiKey || !manifest || (manifest && !manifest.endsWith('manifest.json'))) return null;
|
||||
const BASE_URL = manifest ? manifest.split('/manifest.json')[0] : null;
|
||||
if (!BASE_URL) return null;
|
||||
try {
|
||||
const imdbId = await getImdbId(tmdbApiKey, id, s, e);
|
||||
if (!imdbId) return null;
|
||||
|
||||
@@ -12,7 +12,9 @@ const SERVERS = [
|
||||
{ id: 'superflix', name: 'Raze' }
|
||||
];
|
||||
|
||||
export async function getStream({ id, s, e, server, tmdbApiKey }) {
|
||||
export async function getStream({ id, s, e, server, sdk }) {
|
||||
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
||||
if (!tmdbApiKey) return null;
|
||||
try {
|
||||
const isTv = s != null && e != null;
|
||||
const info = await getTmdbInfo(tmdbApiKey, id, isTv ? 'tv' : 'movie');
|
||||
|
||||
@@ -39,7 +39,9 @@ async function tmdbToAnilist(tmdbId, season) {
|
||||
|
||||
const SERVER_KEYS = ['hollymoviehd', 'allmovies', 'catflix', 'purstream', 'lamda', 'vidlink', 'klikxxi'];
|
||||
|
||||
export async function getStream({ id, s, e, tmdbApiKey, audio }) {
|
||||
export async function getStream({ id, s, e, sdk, audio }) {
|
||||
const tmdbApiKey = sdk?.tmdbApiKey || null;
|
||||
if (!tmdbApiKey) return null;
|
||||
if (s) {
|
||||
const k = tmdbApiKey;
|
||||
const showData = k ? await fetchJson(`https://api.themoviedb.org/3/tv/${id}?api_key=${k}`, { signal: AbortSignal.timeout(5000) }).catch(() => null) : null;
|
||||
|
||||
@@ -67,7 +67,7 @@ function cacheGet(cache, key) {
|
||||
|
||||
function cacheSet(cache, key, val, ttl) { cache.set(key, { val, ts: Date.now(), ttl }); }
|
||||
|
||||
export async function createStreamArgs(source, tmdbApiKey, id, s, e, clientIP = null) {
|
||||
export async function createStreamArgs(source, sdk, id, s, e, clientIP = null) {
|
||||
const audio = /dub$/.test(source.key) ? 'dub' : 'sub';
|
||||
return {
|
||||
id: id,
|
||||
@@ -76,7 +76,7 @@ export async function createStreamArgs(source, tmdbApiKey, id, s, e, clientIP =
|
||||
clientIP: clientIP,
|
||||
absoluteBase: '/',
|
||||
audio,
|
||||
tmdbApiKey,
|
||||
sdk,
|
||||
config: source,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import fs from "fs";
|
||||
import path from "path";
|
||||
import VylaSDK from "../src/sdk.js";
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
const CONFIG = {
|
||||
DEBUG: true, // Set to true to print outgoing requests, headers, formats, and responses
|
||||
@@ -14,13 +13,20 @@ 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: "cinejoy", // Source key to test
|
||||
STREAM_SOURCE: "pengu", // Source key to test
|
||||
|
||||
TEST_SUBTITLE: false, // Toggle subtitle testing
|
||||
TEST_DOWNLOAD: false, // Toggle download testing
|
||||
TEST_MOVIE: true, // Toggle movie testing
|
||||
TEST_TV: true // Toggle TV testing
|
||||
TEST_TV: true, // Toggle TV testing
|
||||
|
||||
EXTRA_SDK_PARAMS: { // Additional parameters for the SDK constructor
|
||||
// penguManifest: ""
|
||||
}
|
||||
};
|
||||
dotenv.config({
|
||||
debug: CONFIG.DEBUG
|
||||
});
|
||||
|
||||
// debug
|
||||
if (CONFIG.DEBUG) {
|
||||
@@ -105,7 +111,8 @@ if (CONFIG.DEBUG) {
|
||||
}
|
||||
|
||||
const sdk = new VylaSDK({
|
||||
tmdbApiKey: process.env.TMDB_API_KEY
|
||||
tmdbApiKey: process.env.TMDB_API_KEY,
|
||||
...CONFIG.EXTRA_SDK_PARAMS
|
||||
});
|
||||
|
||||
console.log("Starting...");
|
||||
|
||||
Reference in New Issue
Block a user