mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-30 06:18:50 +00:00
fix: stream addon selection logic with fallback for non-standard types
This commit is contained in:
parent
4c9bcbf64e
commit
77b8b59734
3 changed files with 237 additions and 133 deletions
|
|
@ -1486,10 +1486,10 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
|||
setActiveFetchingScrapers([]);
|
||||
setAddonResponseOrder([]); // Reset response order
|
||||
|
||||
// Get TMDB ID for external sources and determine the correct ID for Stremio addons
|
||||
if (__DEV__) console.log('🔍 [loadStreams] Getting TMDB ID for:', id);
|
||||
let tmdbId;
|
||||
let stremioId = id; // Default to original ID
|
||||
let stremioId = id;
|
||||
let effectiveStreamType: string = type;
|
||||
|
||||
if (id.startsWith('tmdb:')) {
|
||||
tmdbId = id.split(':')[1];
|
||||
|
|
@ -1544,56 +1544,66 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
|||
const allStremioAddons = await stremioService.getInstalledAddons();
|
||||
const localScrapers = await localScraperService.getInstalledScrapers();
|
||||
|
||||
// Map app-level "tv" type to Stremio "series" for addon capability checks
|
||||
const stremioType = type === 'tv' ? 'series' : type;
|
||||
const requestedStreamType = type;
|
||||
|
||||
// Filter Stremio addons to only include those that provide streams for this content type
|
||||
const streamAddons = allStremioAddons.filter(addon => {
|
||||
if (!addon.resources || !Array.isArray(addon.resources)) {
|
||||
return false;
|
||||
}
|
||||
const pickEligibleStreamAddons = (requestType: string) =>
|
||||
allStremioAddons.filter(addon => {
|
||||
if (!addon.resources || !Array.isArray(addon.resources)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let hasStreamResource = false;
|
||||
let supportsIdPrefix = false;
|
||||
let hasStreamResource = false;
|
||||
let supportsIdPrefix = false;
|
||||
|
||||
for (const resource of addon.resources) {
|
||||
// Check if the current element is a ResourceObject
|
||||
if (typeof resource === 'object' && resource !== null && 'name' in resource) {
|
||||
const typedResource = resource as any;
|
||||
if (typedResource.name === 'stream' &&
|
||||
Array.isArray(typedResource.types) &&
|
||||
typedResource.types.includes(stremioType)) {
|
||||
hasStreamResource = true;
|
||||
for (const resource of addon.resources) {
|
||||
if (typeof resource === 'object' && resource !== null && 'name' in resource) {
|
||||
const typedResource = resource as any;
|
||||
if (typedResource.name === 'stream' &&
|
||||
Array.isArray(typedResource.types) &&
|
||||
typedResource.types.includes(requestType)) {
|
||||
hasStreamResource = true;
|
||||
|
||||
// Check if this addon supports the ID prefix generically: any prefix must match start of id
|
||||
if (Array.isArray(typedResource.idPrefixes) && typedResource.idPrefixes.length > 0) {
|
||||
supportsIdPrefix = typedResource.idPrefixes.some((p: string) => id.startsWith(p));
|
||||
} else {
|
||||
// If no idPrefixes specified, assume it supports all prefixes
|
||||
supportsIdPrefix = true;
|
||||
if (Array.isArray(typedResource.idPrefixes) && typedResource.idPrefixes.length > 0) {
|
||||
supportsIdPrefix = typedResource.idPrefixes.some((p: string) => stremioId.startsWith(p));
|
||||
} else {
|
||||
supportsIdPrefix = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (typeof resource === 'string' && resource === 'stream' && addon.types) {
|
||||
if (Array.isArray(addon.types) && addon.types.includes(requestType)) {
|
||||
hasStreamResource = true;
|
||||
if (addon.idPrefixes && Array.isArray(addon.idPrefixes) && addon.idPrefixes.length > 0) {
|
||||
supportsIdPrefix = addon.idPrefixes.some((p: string) => stremioId.startsWith(p));
|
||||
} else {
|
||||
supportsIdPrefix = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check if the element is the simple string "stream" AND the addon has a top-level types array
|
||||
else if (typeof resource === 'string' && resource === 'stream' && addon.types) {
|
||||
if (Array.isArray(addon.types) && addon.types.includes(stremioType)) {
|
||||
hasStreamResource = true;
|
||||
// For simple string resources, check addon-level idPrefixes generically
|
||||
if (addon.idPrefixes && Array.isArray(addon.idPrefixes) && addon.idPrefixes.length > 0) {
|
||||
supportsIdPrefix = addon.idPrefixes.some((p: string) => id.startsWith(p));
|
||||
} else {
|
||||
// If no idPrefixes specified, assume it supports all prefixes
|
||||
supportsIdPrefix = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return hasStreamResource && supportsIdPrefix;
|
||||
});
|
||||
|
||||
effectiveStreamType = requestedStreamType;
|
||||
let eligibleStreamAddons = pickEligibleStreamAddons(requestedStreamType);
|
||||
|
||||
if (eligibleStreamAddons.length === 0) {
|
||||
const fallbackTypes = ['series', 'movie'].filter(t => t !== requestedStreamType);
|
||||
for (const fallbackType of fallbackTypes) {
|
||||
const fallback = pickEligibleStreamAddons(fallbackType);
|
||||
if (fallback.length > 0) {
|
||||
effectiveStreamType = fallbackType;
|
||||
eligibleStreamAddons = fallback;
|
||||
if (__DEV__) console.log(`[useMetadata.loadStreams] No addons for '${requestedStreamType}', falling back to '${fallbackType}'`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasStreamResource && supportsIdPrefix;
|
||||
});
|
||||
if (__DEV__) console.log('[useMetadata.loadStreams] Eligible stream addons:', streamAddons.map(a => a.id));
|
||||
const streamAddons = eligibleStreamAddons;
|
||||
if (__DEV__) console.log('[useMetadata.loadStreams] Eligible stream addons:', streamAddons.map(a => a.id), { requestedStreamType, effectiveStreamType });
|
||||
|
||||
// Initialize scraper statuses for tracking
|
||||
const initialStatuses: ScraperStatus[] = [];
|
||||
|
|
@ -1645,9 +1655,9 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
|||
|
||||
// Start Stremio request using the converted ID format
|
||||
if (__DEV__) console.log('🎬 [loadStreams] Using ID for Stremio addons:', stremioId);
|
||||
// Map app-level "tv" type to Stremio "series" when requesting streams
|
||||
const stremioContentType = type === 'tv' ? 'series' : type;
|
||||
processStremioSource(stremioContentType, stremioId, false);
|
||||
// Use the effective type we selected when building the eligible addon list.
|
||||
// This stays aligned with Stremio manifest filtering rules and avoids hard-mapping non-standard types.
|
||||
processStremioSource(effectiveStreamType, stremioId, false);
|
||||
|
||||
// Also extract any embedded streams from metadata (PPV-style addons)
|
||||
extractEmbeddedStreams();
|
||||
|
|
@ -1707,36 +1717,41 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
|||
const allStremioAddons = await stremioService.getInstalledAddons();
|
||||
const localScrapers = await localScraperService.getInstalledScrapers();
|
||||
|
||||
// Filter Stremio addons to only include those that provide streams for series content
|
||||
const streamAddons = allStremioAddons.filter(addon => {
|
||||
if (!addon.resources || !Array.isArray(addon.resources)) {
|
||||
// We don't yet know the final episode ID format here (it can be normalized later),
|
||||
// but we can still pre-filter by stream capability for the most likely types.
|
||||
const pickStreamCapableAddons = (requestType: string) =>
|
||||
allStremioAddons.filter(addon => {
|
||||
if (!addon.resources || !Array.isArray(addon.resources)) return false;
|
||||
|
||||
for (const resource of addon.resources) {
|
||||
if (typeof resource === 'object' && resource !== null && 'name' in resource) {
|
||||
const typedResource = resource as any;
|
||||
if (typedResource.name === 'stream' && Array.isArray(typedResource.types) && typedResource.types.includes(requestType)) {
|
||||
return true;
|
||||
}
|
||||
} else if (typeof resource === 'string' && resource === 'stream' && addon.types) {
|
||||
if (Array.isArray(addon.types) && addon.types.includes(requestType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
let hasStreamResource = false;
|
||||
|
||||
for (const resource of addon.resources) {
|
||||
// Check if the current element is a ResourceObject
|
||||
if (typeof resource === 'object' && resource !== null && 'name' in resource) {
|
||||
const typedResource = resource as any;
|
||||
if (typedResource.name === 'stream' &&
|
||||
Array.isArray(typedResource.types) &&
|
||||
typedResource.types.includes('series')) {
|
||||
hasStreamResource = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check if the element is the simple string "stream" AND the addon has a top-level types array
|
||||
else if (typeof resource === 'string' && resource === 'stream' && addon.types) {
|
||||
if (Array.isArray(addon.types) && addon.types.includes('series')) {
|
||||
hasStreamResource = true;
|
||||
break;
|
||||
}
|
||||
const requestedEpisodeType = type;
|
||||
let streamAddons = pickStreamCapableAddons(requestedEpisodeType);
|
||||
|
||||
if (streamAddons.length === 0) {
|
||||
const fallbackTypes = ['series', 'movie'].filter(t => t !== requestedEpisodeType);
|
||||
for (const fallbackType of fallbackTypes) {
|
||||
const fallback = pickStreamCapableAddons(fallbackType);
|
||||
if (fallback.length > 0) {
|
||||
streamAddons = fallback;
|
||||
if (__DEV__) console.log(`[useMetadata.loadEpisodeStreams] No addons for '${requestedEpisodeType}', falling back to '${fallbackType}'`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hasStreamResource;
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize scraper statuses for tracking
|
||||
const initialStatuses: ScraperStatus[] = [];
|
||||
|
|
@ -1923,10 +1938,8 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
|||
// Start Stremio request using the converted episode ID format
|
||||
if (__DEV__) console.log('🎬 [loadEpisodeStreams] Using episode ID for Stremio addons:', stremioEpisodeId);
|
||||
|
||||
// For collections, treat episodes as individual movies, not series
|
||||
// For other types (e.g. StreamsPPV), preserve the original type unless it's explicitly 'series' logic we want
|
||||
// Map app-level "tv" type to Stremio "series" for addon stream endpoint
|
||||
const contentType = isCollection ? 'movie' : (type === 'tv' ? 'series' : type);
|
||||
const requestedContentType = isCollection ? 'movie' : type;
|
||||
const contentType = requestedContentType;
|
||||
if (__DEV__) console.log(`🎬 [loadEpisodeStreams] Using content type: ${contentType} for ${isCollection ? 'collection' : type}`);
|
||||
|
||||
processStremioSource(contentType, stremioEpisodeId, true);
|
||||
|
|
|
|||
|
|
@ -1924,7 +1924,6 @@ const ConditionalPostHogProvider: React.FC<{ children: React.ReactNode }> = ({ c
|
|||
apiKey="phc_sk6THCtV3thEAn6cTaA9kL2cHuKDBnlYiSL40ywdS6C"
|
||||
options={{
|
||||
host: "https://us.i.posthog.com",
|
||||
autocapture: analyticsEnabled,
|
||||
// Start opted out if analytics is disabled
|
||||
defaultOptIn: analyticsEnabled,
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1250,6 +1250,49 @@ class StremioService {
|
|||
|
||||
const addons = this.getInstalledAddons();
|
||||
|
||||
// Some addons use non-standard meta types (e.g. "anime") but expect streams under the "series" endpoint.
|
||||
// We'll try the requested type first, then (if no addons match) fall back to "series".
|
||||
const pickStreamAddons = (requestType: string) =>
|
||||
addons.filter(addon => {
|
||||
if (!addon.resources || !Array.isArray(addon.resources)) {
|
||||
logger.log(`⚠️ [getStreams] Addon ${addon.id} has no valid resources array`);
|
||||
return false;
|
||||
}
|
||||
|
||||
let hasStreamResource = false;
|
||||
let supportsIdPrefix = false;
|
||||
|
||||
for (const resource of addon.resources) {
|
||||
if (typeof resource === 'object' && resource !== null && 'name' in resource) {
|
||||
const typedResource = resource as ResourceObject;
|
||||
if (typedResource.name === 'stream' &&
|
||||
Array.isArray(typedResource.types) &&
|
||||
typedResource.types.includes(requestType)) {
|
||||
hasStreamResource = true;
|
||||
|
||||
if (Array.isArray(typedResource.idPrefixes) && typedResource.idPrefixes.length > 0) {
|
||||
supportsIdPrefix = typedResource.idPrefixes.some(p => id.startsWith(p));
|
||||
} else {
|
||||
supportsIdPrefix = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (typeof resource === 'string' && resource === 'stream' && addon.types) {
|
||||
if (Array.isArray(addon.types) && addon.types.includes(requestType)) {
|
||||
hasStreamResource = true;
|
||||
if (addon.idPrefixes && Array.isArray(addon.idPrefixes) && addon.idPrefixes.length > 0) {
|
||||
supportsIdPrefix = addon.idPrefixes.some(p => id.startsWith(p));
|
||||
} else {
|
||||
supportsIdPrefix = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasStreamResource && supportsIdPrefix;
|
||||
});
|
||||
|
||||
// Check if local scrapers are enabled and execute them first
|
||||
try {
|
||||
// Load settings from AsyncStorage directly (scoped with fallback)
|
||||
|
|
@ -1396,64 +1439,109 @@ class StremioService {
|
|||
// TMDB Embed addon not found
|
||||
}
|
||||
|
||||
// Find addons that provide streams and sort them by installation order
|
||||
const streamAddons = addons
|
||||
.filter(addon => {
|
||||
if (!addon.resources || !Array.isArray(addon.resources)) {
|
||||
logger.log(`⚠️ [getStreams] Addon ${addon.id} has no valid resources array`);
|
||||
return false;
|
||||
let effectiveType = type;
|
||||
let streamAddons = pickStreamAddons(type);
|
||||
|
||||
logger.log(`🧭 [getStreams] Resolving stream addons for type='${type}' id='${id}' (matched=${streamAddons.length})`);
|
||||
|
||||
if (streamAddons.length === 0) {
|
||||
const fallbackTypes = ['series', 'movie', 'tv', 'channel'].filter(t => t !== type);
|
||||
for (const fallbackType of fallbackTypes) {
|
||||
const fallbackAddons = pickStreamAddons(fallbackType);
|
||||
if (fallbackAddons.length > 0) {
|
||||
effectiveType = fallbackType;
|
||||
streamAddons = fallbackAddons;
|
||||
logger.log(`🔁 [getStreams] No stream addons for type '${type}', falling back to '${effectiveType}' for id '${id}'`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let hasStreamResource = false;
|
||||
let supportsIdPrefix = false;
|
||||
|
||||
// Iterate through the resources array, checking each element
|
||||
for (const resource of addon.resources) {
|
||||
// Check if the current element is a ResourceObject
|
||||
if (typeof resource === 'object' && resource !== null && 'name' in resource) {
|
||||
const typedResource = resource as ResourceObject;
|
||||
if (typedResource.name === 'stream' &&
|
||||
Array.isArray(typedResource.types) &&
|
||||
typedResource.types.includes(type)) {
|
||||
hasStreamResource = true;
|
||||
|
||||
// Check if this addon supports the ID prefix (generic: any prefix that matches start of id)
|
||||
if (Array.isArray(typedResource.idPrefixes) && typedResource.idPrefixes.length > 0) {
|
||||
supportsIdPrefix = typedResource.idPrefixes.some(p => id.startsWith(p));
|
||||
} else {
|
||||
// If no idPrefixes specified, assume it supports all prefixes
|
||||
supportsIdPrefix = true;
|
||||
}
|
||||
break; // Found the stream resource object, no need to check further
|
||||
}
|
||||
}
|
||||
// Check if the element is the simple string "stream" AND the addon has a top-level types array
|
||||
else if (typeof resource === 'string' && resource === 'stream' && addon.types) {
|
||||
if (Array.isArray(addon.types) && addon.types.includes(type)) {
|
||||
hasStreamResource = true;
|
||||
// For simple string resources, check addon-level idPrefixes (generic)
|
||||
if (addon.idPrefixes && Array.isArray(addon.idPrefixes) && addon.idPrefixes.length > 0) {
|
||||
supportsIdPrefix = addon.idPrefixes.some(p => id.startsWith(p));
|
||||
} else {
|
||||
// If no idPrefixes specified, assume it supports all prefixes
|
||||
supportsIdPrefix = true;
|
||||
}
|
||||
break; // Found the simple stream resource string and type support
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const canHandleRequest = hasStreamResource && supportsIdPrefix;
|
||||
|
||||
return canHandleRequest;
|
||||
});
|
||||
|
||||
|
||||
if (effectiveType !== type) {
|
||||
logger.log(`🧭 [getStreams] Using effectiveType='${effectiveType}' (requested='${type}') for id='${id}'`);
|
||||
}
|
||||
|
||||
if (streamAddons.length === 0) {
|
||||
logger.warn('⚠️ [getStreams] No addons found that can provide streams');
|
||||
// Optionally call callback with an empty result or specific status?
|
||||
// For now, just return if no addons.
|
||||
|
||||
// Log what the URL would have been for debugging
|
||||
const encodedId = encodeURIComponent(id);
|
||||
const exampleUrl = `/stream/${effectiveType}/${encodedId}.json`;
|
||||
logger.log(`🚫 [getStreams] No stream addons matched. Would have requested: ${exampleUrl}`);
|
||||
logger.log(`🚫 [getStreams] Details: requestedType='${type}' effectiveType='${effectiveType}' id='${id}'`);
|
||||
|
||||
// Show which addons have stream capability but didn't match
|
||||
const streamCapableAddons = addons.filter(addon => {
|
||||
if (!addon.resources || !Array.isArray(addon.resources)) return false;
|
||||
return addon.resources.some(resource => {
|
||||
if (typeof resource === 'object' && resource !== null && 'name' in resource) {
|
||||
return (resource as ResourceObject).name === 'stream';
|
||||
}
|
||||
return typeof resource === 'string' && resource === 'stream';
|
||||
});
|
||||
});
|
||||
|
||||
if (streamCapableAddons.length > 0) {
|
||||
logger.log(`🚫 [getStreams] Found ${streamCapableAddons.length} stream-capable addon(s) that didn't match:`);
|
||||
|
||||
for (const addon of streamCapableAddons) {
|
||||
const streamResources = addon.resources!.filter(resource => {
|
||||
if (typeof resource === 'object' && resource !== null && 'name' in resource) {
|
||||
return (resource as ResourceObject).name === 'stream';
|
||||
}
|
||||
return typeof resource === 'string' && resource === 'stream';
|
||||
});
|
||||
|
||||
for (const resource of streamResources) {
|
||||
if (typeof resource === 'object' && resource !== null) {
|
||||
const typedResource = resource as ResourceObject;
|
||||
const types = typedResource.types || [];
|
||||
const prefixes = typedResource.idPrefixes || [];
|
||||
const typeMatch = types.includes(effectiveType);
|
||||
const prefixMatch = prefixes.length === 0 || prefixes.some(p => id.startsWith(p));
|
||||
|
||||
if (addon.url) {
|
||||
const { baseUrl, queryParams } = this.getAddonBaseURL(addon.url);
|
||||
const wouldBeUrl = queryParams
|
||||
? `${baseUrl}/stream/${effectiveType}/${encodedId}.json?${queryParams}`
|
||||
: `${baseUrl}/stream/${effectiveType}/${encodedId}.json`;
|
||||
|
||||
console.log(
|
||||
` ❌ ${addon.name} (${addon.id}):\n` +
|
||||
` types=[${types.join(',')}] typeMatch=${typeMatch}\n` +
|
||||
` prefixes=[${prefixes.join(',')}] prefixMatch=${prefixMatch}\n` +
|
||||
` url=${wouldBeUrl}`
|
||||
);
|
||||
} else {
|
||||
console.log(` ❌ ${addon.name} (${addon.id}): no URL configured`);
|
||||
}
|
||||
} else if (typeof resource === 'string' && resource === 'stream') {
|
||||
// String resource - check addon-level types and prefixes
|
||||
const addonTypes = addon.types || [];
|
||||
const addonPrefixes = addon.idPrefixes || [];
|
||||
const typeMatch = addonTypes.includes(effectiveType);
|
||||
const prefixMatch = addonPrefixes.length === 0 || addonPrefixes.some(p => id.startsWith(p));
|
||||
|
||||
if (addon.url) {
|
||||
const { baseUrl, queryParams } = this.getAddonBaseURL(addon.url);
|
||||
const wouldBeUrl = queryParams
|
||||
? `${baseUrl}/stream/${effectiveType}/${encodedId}.json?${queryParams}`
|
||||
: `${baseUrl}/stream/${effectiveType}/${encodedId}.json`;
|
||||
|
||||
console.log(
|
||||
` ❌ ${addon.name} (${addon.id}) [addon-level]:\n` +
|
||||
` types=[${addonTypes.join(',')}] typeMatch=${typeMatch}\n` +
|
||||
` prefixes=[${addonPrefixes.join(',')}] prefixMatch=${prefixMatch}\n` +
|
||||
` url=${wouldBeUrl}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.log(`🚫 [getStreams] No stream-capable addons installed`);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1470,9 +1558,11 @@ class StremioService {
|
|||
|
||||
const { baseUrl, queryParams } = this.getAddonBaseURL(addon.url);
|
||||
const encodedId = encodeURIComponent(id);
|
||||
const url = queryParams ? `${baseUrl}/stream/${type}/${encodedId}.json?${queryParams}` : `${baseUrl}/stream/${type}/${encodedId}.json`;
|
||||
const url = queryParams ? `${baseUrl}/stream/${effectiveType}/${encodedId}.json?${queryParams}` : `${baseUrl}/stream/${effectiveType}/${encodedId}.json`;
|
||||
|
||||
logger.log(`🔗 [getStreams] Requesting streams from ${addon.name} (${addon.id}) [${addon.installationId}]: ${url}`);
|
||||
logger.log(
|
||||
`🔗 [getStreams] GET ${url} (addon='${addon.name}' id='${addon.id}' install='${addon.installationId}' requestedType='${type}' effectiveType='${effectiveType}' rawId='${id}')`
|
||||
);
|
||||
|
||||
const response = await this.retryRequest(async () => {
|
||||
return await axios.get(url, safeAxiosConfig);
|
||||
|
|
@ -1517,14 +1607,16 @@ class StremioService {
|
|||
const streamPath = `/stream/${type}/${encodedId}.json`;
|
||||
const url = queryParams ? `${baseUrl}${streamPath}?${queryParams}` : `${baseUrl}${streamPath}`;
|
||||
|
||||
logger.log(`Fetching streams from URL: ${url}`);
|
||||
logger.log(
|
||||
`🔗 [fetchStreamsFromAddon] GET ${url} (addon='${addon.name}' id='${addon.id}' install='${addon.installationId}' type='${type}' rawId='${id}')`
|
||||
);
|
||||
|
||||
try {
|
||||
// Increase timeout for debrid services
|
||||
const timeout = addon.id.toLowerCase().includes('torrentio') ? 60000 : 10000;
|
||||
|
||||
const response = await this.retryRequest(async () => {
|
||||
logger.log(`Making request to ${url} with timeout ${timeout}ms`);
|
||||
logger.log(`🌐 [fetchStreamsFromAddon] Requesting ${url} (timeout=${timeout}ms)`);
|
||||
return await axios.get(url, createSafeAxiosConfig(timeout, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
|
|
|
|||
Loading…
Reference in a new issue