mirror of
https://github.com/Inside4ndroid/TMDB-Embed-API.git
synced 2026-10-22 09:35:11 +00:00
- 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.
133 lines
4.7 KiB
JavaScript
133 lines
4.7 KiB
JavaScript
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 }; |