This commit is contained in:
tapframe 2025-07-21 00:42:13 +05:30
parent da0a69ab0e
commit 9006d312b8
4 changed files with 93 additions and 8 deletions

View file

@ -29,7 +29,7 @@ async function getUHDMoviesDomain() {
try {
console.log('[UHDMovies] Fetching latest domain...');
const response = await axios.get('https://raw.githubusercontent.com/phisher98/TVVVV/refs/heads/main/domains.json', { timeout: 10000 });
const response = await axios.get('https://raw.githubusercontent.com/phisher98/TVVVV/refs/heads/main/domains.json');
if (response.data && response.data.UHDMovies) {
uhdMoviesDomain = response.data.UHDMovies;
domainCacheTimestamp = now;
@ -101,8 +101,7 @@ const axiosInstance = axios.create({
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'Cache-Control': 'max-age=0'
},
timeout: 30000
}
});
// Simple In-Memory Cache

@ -1 +1 @@
Subproject commit fa92f8cf27fc238b48697263aa48d8a2eb5a68ef
Subproject commit 6be646d6702a809b28eac63b7d04a453f756c402

View file

@ -294,6 +294,9 @@ class LocalScraperService {
// This is a simplified sandbox - in production, you'd want more security
try {
// Create a limited global context
const moduleExports = {};
const moduleObj = { exports: moduleExports };
const sandbox = {
console: {
log: (...args: any[]) => logger.log('[Scraper]', ...args),
@ -310,13 +313,41 @@ class LocalScraperService {
parseFloat,
encodeURIComponent,
decodeURIComponent,
// Add fetch for HTTP requests (using axios as polyfill)
fetch: async (url: string, options: any = {}) => {
const axiosConfig = {
url,
method: options.method || 'GET',
headers: options.headers || {},
data: options.body,
timeout: 30000
};
try {
const response = await axios(axiosConfig);
return {
ok: response.status >= 200 && response.status < 300,
status: response.status,
statusText: response.statusText,
headers: response.headers,
json: async () => response.data,
text: async () => typeof response.data === 'string' ? response.data : JSON.stringify(response.data)
};
} catch (error: any) {
throw new Error(`Fetch failed: ${error.message}`);
}
},
// Add axios for HTTP requests
axios: axios.create({
timeout: 30000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
})
}),
// Node.js compatibility
module: moduleObj,
exports: moduleExports,
global: {} // Empty global object
};
// Execute the scraper code with timeout
@ -328,7 +359,7 @@ class LocalScraperService {
try {
// Create function from code
const func = new Function('sandbox', 'params', `
const { console, setTimeout, clearTimeout, Promise, JSON, Date, Math, parseInt, parseFloat, encodeURIComponent, decodeURIComponent, axios } = sandbox;
const { console, setTimeout, clearTimeout, Promise, JSON, Date, Math, parseInt, parseFloat, encodeURIComponent, decodeURIComponent, axios, fetch, module, exports, global } = sandbox;
${code}
// Call the main function (assuming it's exported)
@ -336,6 +367,8 @@ class LocalScraperService {
return getStreams(params.tmdbId, params.mediaType, params.season, params.episode);
} else if (typeof module !== 'undefined' && module.exports && typeof module.exports.getStreams === 'function') {
return module.exports.getStreams(params.tmdbId, params.mediaType, params.season, params.episode);
} else if (typeof global !== 'undefined' && global.getStreams && typeof global.getStreams === 'function') {
return global.getStreams(params.tmdbId, params.mediaType, params.season, params.episode);
} else {
throw new Error('No getStreams function found in scraper');
}

View file

@ -4,6 +4,7 @@ import { logger } from '../utils/logger';
import EventEmitter from 'eventemitter3';
import { localScraperService } from './localScraperService';
import { DEFAULT_SETTINGS, AppSettings } from '../hooks/useSettings';
import { TMDBService } from './tmdbService';
// Create an event emitter for addon changes
export const addonEmitter = new EventEmitter();
@ -631,8 +632,60 @@ class StremioService {
if (hasScrapers) {
logger.log('🔧 [getStreams] Executing local scrapers for', type, id);
// Execute local scrapers asynchronously
localScraperService.getStreams(type, id, undefined, undefined, (streams, scraperId, scraperName, error) => {
// Map Stremio types to local scraper types
const scraperType = type === 'series' ? 'tv' : type;
// Parse the Stremio ID to extract IMDb ID and season/episode info
let tmdbId: string | null = null;
let season: number | undefined = undefined;
let episode: number | undefined = undefined;
try {
const idParts = id.split(':');
let baseImdbId: string;
// Handle different episode ID formats
if (idParts[0] === 'series') {
// Format: series:imdbId:season:episode
baseImdbId = idParts[1];
if (scraperType === 'tv' && idParts.length >= 4) {
season = parseInt(idParts[2], 10);
episode = parseInt(idParts[3], 10);
}
} else if (idParts[0].startsWith('tt')) {
// Format: imdbId:season:episode (direct IMDb ID)
baseImdbId = idParts[0];
if (scraperType === 'tv' && idParts.length >= 3) {
season = parseInt(idParts[1], 10);
episode = parseInt(idParts[2], 10);
}
} else {
// Fallback: assume first part is the ID
baseImdbId = idParts[0];
if (scraperType === 'tv' && idParts.length >= 3) {
season = parseInt(idParts[1], 10);
episode = parseInt(idParts[2], 10);
}
}
// Convert IMDb ID to TMDB ID using TMDBService
const tmdbService = TMDBService.getInstance();
const tmdbIdNumber = await tmdbService.findTMDBIdByIMDB(baseImdbId);
if (tmdbIdNumber) {
tmdbId = tmdbIdNumber.toString();
logger.log(`🔄 [getStreams] Converted IMDb ID ${baseImdbId} to TMDB ID ${tmdbId}${scraperType === 'tv' ? ` (S${season}E${episode})` : ''}`);
} else {
logger.warn(`⚠️ [getStreams] Could not convert IMDb ID ${baseImdbId} to TMDB ID`);
return; // Skip local scrapers if we can't convert the ID
}
} catch (error) {
logger.error(`❌ [getStreams] Failed to parse Stremio ID or convert to TMDB ID:`, error);
return; // Skip local scrapers if ID parsing fails
}
// Execute local scrapers asynchronously with TMDB ID
localScraperService.getStreams(scraperType, tmdbId, season, episode, (streams, scraperId, scraperName, error) => {
if (error) {
logger.error(`❌ [getStreams] Local scraper ${scraperName} failed:`, error);
if (callback) {