mirror of
https://github.com/Inside4ndroid/TMDB-Embed-API.git
synced 2026-10-22 09:35:11 +00:00
Add new providers for streaming services and utility functions
- Implement StreamFlix provider for fetching movie and episode streams. - Add VaPlayer provider to retrieve streaming URLs for movies and TV shows. - Introduce ZXCStreams provider for accessing various streaming links. - Create utility functions for fetching episode counts from Cinemeta. - Develop a title matching system for improved search results. - Implement TMDB title to IMDB ID resolution for better integration with TMDB API.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const API_BASE = 'https://api.streamflix.app';
|
||||
const FIREBASE_BASE = 'https://chilflix-410be-default-rtdb.asia-southeast1.firebasedatabase.app';
|
||||
|
||||
const DATA_TTL = 30 * 60 * 1000;
|
||||
const CONFIG_TTL = 5 * 60 * 1000;
|
||||
const EPISODES_TTL = 60 * 60 * 1000;
|
||||
|
||||
let dataCache = null;
|
||||
let configCache = null;
|
||||
const episodesCache = new Map();
|
||||
|
||||
const REQUEST_HEADERS = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
|
||||
'Accept': 'application/json, */*',
|
||||
'Accept-Language': 'en-US,en;q=0.9'
|
||||
};
|
||||
|
||||
async function getData() {
|
||||
if (dataCache && Date.now() - dataCache.ts < DATA_TTL) return dataCache.items;
|
||||
console.log('[StreamFlix] fetching data.json');
|
||||
const res = await axios.get(`${API_BASE}/data.json`, { headers: REQUEST_HEADERS, timeout: 20000 });
|
||||
const items = (res.data && res.data.data) || [];
|
||||
dataCache = { items, ts: Date.now() };
|
||||
console.log(`[StreamFlix] data.json cached (${items.length} items)`);
|
||||
return items;
|
||||
}
|
||||
|
||||
async function getConfig() {
|
||||
if (configCache && Date.now() - configCache.ts < CONFIG_TTL) return configCache.config;
|
||||
const res = await axios.get(`${API_BASE}/config/config-streamflixapp.json`, { headers: REQUEST_HEADERS, timeout: 8000 });
|
||||
configCache = { config: res.data, ts: Date.now() };
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async function getEpisodes(movieKey, season) {
|
||||
const cacheKey = `${movieKey}:${season}`;
|
||||
const cached = episodesCache.get(cacheKey);
|
||||
if (cached && Date.now() - cached.ts < EPISODES_TTL) return cached.episodes;
|
||||
|
||||
const url = `${FIREBASE_BASE}/Data/${movieKey}/seasons/${season}/episodes.json`;
|
||||
const res = await axios.get(url, { headers: REQUEST_HEADERS, timeout: 10000 });
|
||||
|
||||
const raw = res.data || {};
|
||||
const episodes = {};
|
||||
for (const [k, v] of Object.entries(raw)) {
|
||||
episodes[parseInt(k, 10)] = v;
|
||||
}
|
||||
episodesCache.set(cacheKey, { episodes, ts: Date.now() });
|
||||
return episodes;
|
||||
}
|
||||
|
||||
function downloadBases(config) {
|
||||
const seen = new Set();
|
||||
const out = [];
|
||||
for (const url of config.download || []) {
|
||||
if (url && !seen.has(url)) {
|
||||
seen.add(url);
|
||||
out.push(url);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function subtitleHint(filename) {
|
||||
const f = (filename || '').toLowerCase();
|
||||
if (f.includes('esub') || f.includes('.srt') || f.includes('.ass') || f.includes('sub')) {
|
||||
return ' [Embedded Subs]';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
async function getStreamflixStreams(tmdbId, mediaType = 'movie', seasonNum = null, episodeNum = null) {
|
||||
console.log(`[StreamFlix] Fetching streams for TMDB ID: ${tmdbId}, Type: ${mediaType}`);
|
||||
|
||||
try {
|
||||
const [items, config] = await Promise.all([getData(), getConfig()]);
|
||||
|
||||
const match = items.find((item) => item.tmdb === String(tmdbId));
|
||||
if (!match) {
|
||||
console.log(`[StreamFlix] No match found for TMDB ID ${tmdbId}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
const bases = downloadBases(config);
|
||||
if (bases.length === 0) {
|
||||
console.log(`[StreamFlix] No download CDN bases in config`);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (mediaType === 'movie') {
|
||||
if (!match.movielink) return [];
|
||||
const subs = subtitleHint(match.movielink);
|
||||
return bases.map((base, i) => ({
|
||||
name: 'StreamFlix',
|
||||
title: `StreamFlix${i > 0 ? ` Mirror ${i}` : ''}${subs} | ${match.moviename}`,
|
||||
url: `${base}${match.movielink}`,
|
||||
quality: 'Auto',
|
||||
provider: 'StreamFlix',
|
||||
headers: { 'User-Agent': REQUEST_HEADERS['User-Agent'] }
|
||||
}));
|
||||
}
|
||||
|
||||
if (seasonNum === null || episodeNum === null) return [];
|
||||
|
||||
try {
|
||||
const episodes = await getEpisodes(match.moviekey, seasonNum);
|
||||
const ep = episodes[episodeNum - 1] || episodes[episodeNum];
|
||||
|
||||
if (ep && ep.link) {
|
||||
const subs = subtitleHint(ep.link);
|
||||
return bases.map((base, i) => ({
|
||||
name: 'StreamFlix',
|
||||
title: `StreamFlix${i > 0 ? ` Mirror ${i}` : ''}${subs} | ${match.moviename} S${seasonNum}E${episodeNum}${ep.name ? ` • ${ep.name}` : ''}`,
|
||||
url: `${base}${ep.link}`,
|
||||
quality: 'Auto',
|
||||
provider: 'StreamFlix',
|
||||
headers: { 'User-Agent': REQUEST_HEADERS['User-Agent'] }
|
||||
}));
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(`[StreamFlix] Firebase fetch failed: ${err.message}`);
|
||||
}
|
||||
|
||||
return [];
|
||||
} catch (err) {
|
||||
console.error(`[StreamFlix] Error: ${err.message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { getStreamflixStreams };
|
||||
Reference in New Issue
Block a user