mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
added axios response limit
This commit is contained in:
parent
181de15b93
commit
b24cd9ca66
4 changed files with 53 additions and 31 deletions
|
|
@ -5,6 +5,7 @@ import axios from 'axios';
|
|||
import { TMDBService } from './tmdbService';
|
||||
import { logger } from '../utils/logger';
|
||||
import { getCatalogDisplayName } from '../utils/catalogNameUtils';
|
||||
import { createSafeAxiosConfig } from '../utils/axiosConfig';
|
||||
|
||||
// Add a constant for storing the data source preference
|
||||
const DATA_SOURCE_KEY = 'discover_data_source';
|
||||
|
|
@ -1476,7 +1477,7 @@ class CatalogService {
|
|||
logger.warn(`Search failed for catalog in ${addon.name}:`, s.reason);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (addonResults.length === 0) {
|
||||
logger.log(`No results from ${addon.name}`);
|
||||
return;
|
||||
|
|
@ -1542,7 +1543,7 @@ class CatalogService {
|
|||
logger.warn(`Addon ${manifest.name} (${manifest.id}) has no URL, skipping search`);
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
// Extract base URL and preserve query params (same logic as stremioService.getAddonBaseURL)
|
||||
const [baseUrlPart, queryParams] = chosenUrl.split('?');
|
||||
let cleanBaseUrl = baseUrlPart.replace(/manifest\.json$/, '').replace(/\/$/, '');
|
||||
|
|
@ -1554,7 +1555,7 @@ class CatalogService {
|
|||
|
||||
const encodedCatalogId = encodeURIComponent(catalogId);
|
||||
const encodedQuery = encodeURIComponent(query);
|
||||
|
||||
|
||||
// Try path-style URL first (per Stremio protocol)
|
||||
url = `${cleanBaseUrl}/catalog/${type}/${encodedCatalogId}/search=${encodedQuery}.json`;
|
||||
|
||||
|
|
@ -1566,9 +1567,7 @@ class CatalogService {
|
|||
|
||||
logger.log(`Searching ${manifest.name} (${type}/${catalogId}):`, url);
|
||||
|
||||
const response = await axios.get<{ metas: any[] }>(url, {
|
||||
timeout: 10000, // 10 second timeout per addon
|
||||
});
|
||||
const response = await axios.get<{ metas: any[] }>(url, createSafeAxiosConfig(10000));
|
||||
|
||||
const metas = response.data?.metas || [];
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { logger } from '../utils/logger';
|
|||
import { Stream } from '../types/streams';
|
||||
import { cacheService } from './cacheService';
|
||||
import CryptoJS from 'crypto-js';
|
||||
import { safeAxiosConfig, createSafeAxiosConfig } from '../utils/axiosConfig';
|
||||
|
||||
const MAX_CONCURRENT_SCRAPERS = 5;
|
||||
const MAX_INFLIGHT_KEYS = 30;
|
||||
|
|
@ -407,13 +408,12 @@ class LocalScraperService {
|
|||
: `${repositoryUrl}/manifest.json`;
|
||||
const manifestUrl = `${baseManifestUrl}?t=${Date.now()}`;
|
||||
|
||||
const response = await axios.get(manifestUrl, {
|
||||
timeout: 10000,
|
||||
const response = await axios.get(manifestUrl, createSafeAxiosConfig(10000, {
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
'Pragma': 'no-cache'
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
if (response.data && response.data.name) {
|
||||
logger.log('[LocalScraperService] Found repository name in manifest:', response.data.name);
|
||||
|
|
@ -645,14 +645,13 @@ class LocalScraperService {
|
|||
: `${this.repositoryUrl}/manifest.json`;
|
||||
const manifestUrl = `${baseManifestUrl}?t=${Date.now()}&v=${Math.random()}`;
|
||||
|
||||
const response = await axios.get(manifestUrl, {
|
||||
timeout: 10000,
|
||||
const response = await axios.get(manifestUrl, createSafeAxiosConfig(10000, {
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
'Pragma': 'no-cache',
|
||||
'Expires': '0'
|
||||
}
|
||||
});
|
||||
}));
|
||||
const manifest: ScraperManifest = response.data;
|
||||
|
||||
// Store repository name from manifest
|
||||
|
|
@ -740,14 +739,13 @@ class LocalScraperService {
|
|||
: `${repo.url}/manifest.json`;
|
||||
const manifestUrl = `${baseManifestUrl}?t=${Date.now()}&v=${Math.random()}`;
|
||||
|
||||
const response = await axios.get(manifestUrl, {
|
||||
timeout: 10000,
|
||||
const response = await axios.get(manifestUrl, createSafeAxiosConfig(10000, {
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
'Pragma': 'no-cache',
|
||||
'Expires': '0'
|
||||
}
|
||||
});
|
||||
}));
|
||||
const manifest: ScraperManifest = response.data;
|
||||
|
||||
// Update repository name from manifest
|
||||
|
|
@ -823,14 +821,13 @@ class LocalScraperService {
|
|||
// Add cache-busting parameters to force fresh download
|
||||
const scraperUrlWithCacheBust = `${scraperUrl}?t=${Date.now()}&v=${Math.random()}`;
|
||||
|
||||
const response = await axios.get(scraperUrlWithCacheBust, {
|
||||
timeout: 15000,
|
||||
const response = await axios.get(scraperUrlWithCacheBust, createSafeAxiosConfig(15000, {
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
'Pragma': 'no-cache',
|
||||
'Expires': '0'
|
||||
}
|
||||
});
|
||||
}));
|
||||
const scraperCode = response.data;
|
||||
|
||||
// Store scraper info and code
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import EventEmitter from 'eventemitter3';
|
|||
import { localScraperService } from './pluginService';
|
||||
import { DEFAULT_SETTINGS, AppSettings } from '../hooks/useSettings';
|
||||
import { TMDBService } from './tmdbService';
|
||||
import { safeAxiosConfig, createSafeAxiosConfig } from '../utils/axiosConfig';
|
||||
|
||||
// Create an event emitter for addon changes
|
||||
export const addonEmitter = new EventEmitter();
|
||||
|
|
@ -626,7 +627,7 @@ class StremioService {
|
|||
: `${url.replace(/\/$/, '')}/manifest.json`;
|
||||
|
||||
const response = await this.retryRequest(async () => {
|
||||
return await axios.get(manifestUrl);
|
||||
return await axios.get(manifestUrl, safeAxiosConfig);
|
||||
});
|
||||
|
||||
const manifest = response.data;
|
||||
|
|
@ -878,7 +879,7 @@ class StremioService {
|
|||
// For page 1 without filters, try simple URL first (best compatibility)
|
||||
if (pageSkip === 0 && extraParts.length === 0) {
|
||||
if (__DEV__) console.log(`🔍 [getCatalog] Trying simple URL for ${manifest.name}: ${urlSimple}`);
|
||||
response = await this.retryRequest(async () => axios.get(urlSimple));
|
||||
response = await this.retryRequest(async () => axios.get(urlSimple, safeAxiosConfig));
|
||||
// Check if we got valid metas - if empty, try other styles
|
||||
if (!response?.data?.metas || response.data.metas.length === 0) {
|
||||
throw new Error('Empty response from simple URL');
|
||||
|
|
@ -890,7 +891,7 @@ class StremioService {
|
|||
try {
|
||||
// Try path-style URL (correct per protocol)
|
||||
if (__DEV__) console.log(`🔍 [getCatalog] Trying path-style URL for ${manifest.name}: ${urlPathStyle}`);
|
||||
response = await this.retryRequest(async () => axios.get(urlPathStyle));
|
||||
response = await this.retryRequest(async () => axios.get(urlPathStyle, safeAxiosConfig));
|
||||
// Check if we got valid metas - if empty, try query-style
|
||||
if (!response?.data?.metas || response.data.metas.length === 0) {
|
||||
throw new Error('Empty response from path-style URL');
|
||||
|
|
@ -899,7 +900,7 @@ class StremioService {
|
|||
try {
|
||||
// Try legacy query-style URL as last resort
|
||||
if (__DEV__) console.log(`🔍 [getCatalog] Trying query-style URL for ${manifest.name}: ${urlQueryStyle}`);
|
||||
response = await this.retryRequest(async () => axios.get(urlQueryStyle));
|
||||
response = await this.retryRequest(async () => axios.get(urlQueryStyle, safeAxiosConfig));
|
||||
} catch (e3) {
|
||||
if (__DEV__) console.log(`❌ [getCatalog] All URL styles failed for ${manifest.name}`);
|
||||
throw e3;
|
||||
|
|
@ -994,7 +995,7 @@ class StremioService {
|
|||
if (isSupported) {
|
||||
try {
|
||||
const response = await this.retryRequest(async () => {
|
||||
return await axios.get(url, { timeout: 10000 });
|
||||
return await axios.get(url, createSafeAxiosConfig(10000));
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -1025,7 +1026,7 @@ class StremioService {
|
|||
|
||||
|
||||
const response = await this.retryRequest(async () => {
|
||||
return await axios.get(url, { timeout: 10000 });
|
||||
return await axios.get(url, createSafeAxiosConfig(10000));
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -1096,7 +1097,7 @@ class StremioService {
|
|||
|
||||
|
||||
const response = await this.retryRequest(async () => {
|
||||
return await axios.get(url, { timeout: 10000 });
|
||||
return await axios.get(url, createSafeAxiosConfig(10000));
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -1412,7 +1413,7 @@ class StremioService {
|
|||
logger.log(`🔗 [getStreams] Requesting streams from ${addon.name} (${addon.id}): ${url}`);
|
||||
|
||||
const response = await this.retryRequest(async () => {
|
||||
return await axios.get(url);
|
||||
return await axios.get(url, safeAxiosConfig);
|
||||
});
|
||||
|
||||
let processedStreams: Stream[] = [];
|
||||
|
|
@ -1462,13 +1463,12 @@ class StremioService {
|
|||
|
||||
const response = await this.retryRequest(async () => {
|
||||
logger.log(`Making request to ${url} with timeout ${timeout}ms`);
|
||||
return await axios.get(url, {
|
||||
timeout,
|
||||
return await axios.get(url, createSafeAxiosConfig(timeout, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36'
|
||||
}
|
||||
});
|
||||
}));
|
||||
}, 5); // Increase retries for stream fetching
|
||||
|
||||
if (response.data && response.data.streams && Array.isArray(response.data.streams)) {
|
||||
|
|
@ -1770,7 +1770,7 @@ class StremioService {
|
|||
: `${baseUrl}/subtitles/${type}/${encodedId}.json`;
|
||||
}
|
||||
logger.log(`[getSubtitles] Fetching subtitles from ${addon.name}: ${url}`);
|
||||
const response = await this.retryRequest(async () => axios.get(url, { timeout: 10000 }));
|
||||
const response = await this.retryRequest(async () => axios.get(url, createSafeAxiosConfig(10000)));
|
||||
if (response.data && Array.isArray(response.data.subtitles)) {
|
||||
logger.log(`[getSubtitles] Got ${response.data.subtitles.length} subtitles from ${addon.name}`);
|
||||
return response.data.subtitles.map((sub: any, index: number) => ({
|
||||
|
|
@ -1910,7 +1910,7 @@ class StremioService {
|
|||
const url = `${baseUrl}/addon_catalog/${type}/${encodeURIComponent(id)}.json${queryParams ? `?${queryParams}` : ''}`;
|
||||
|
||||
logger.log(`[getAddonCatalogs] Fetching from ${addon.name}: ${url}`);
|
||||
const response = await this.retryRequest(() => axios.get(url, { timeout: 10000 }));
|
||||
const response = await this.retryRequest(() => axios.get(url, createSafeAxiosConfig(10000)));
|
||||
|
||||
if (response.data?.addons && Array.isArray(response.data.addons)) {
|
||||
results.push(...response.data.addons);
|
||||
|
|
|
|||
26
src/utils/axiosConfig.ts
Normal file
26
src/utils/axiosConfig.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
export const MAX_RESPONSE_SIZE = 10 * 1024 * 1024; // 10MB in bytes
|
||||
|
||||
/**
|
||||
* Default axios request configuration with response size limits.
|
||||
* Apply this to all axios.get() calls to prevent OOM crashes.
|
||||
*/
|
||||
export const safeAxiosConfig = {
|
||||
maxContentLength: MAX_RESPONSE_SIZE,
|
||||
maxBodyLength: MAX_RESPONSE_SIZE,
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a safe axios config with response size limits and optional timeout.
|
||||
* @param timeout - Optional timeout in milliseconds (default: 10000)
|
||||
* @param additionalConfig - Additional axios config to merge
|
||||
* @returns Axios request config with safety limits
|
||||
*/
|
||||
export const createSafeAxiosConfig = (
|
||||
timeout: number = 10000,
|
||||
additionalConfig?: Record<string, any>
|
||||
) => ({
|
||||
...safeAxiosConfig,
|
||||
timeout,
|
||||
...additionalConfig,
|
||||
});
|
||||
Loading…
Reference in a new issue