mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-20 16:22:04 +00:00
embed stream fetch critical bug fix
This commit is contained in:
parent
ff2bca18a5
commit
b4b8648e25
2 changed files with 75 additions and 25 deletions
|
|
@ -1364,7 +1364,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract embedded streams from metadata videos (used by PPV-style addons)
|
// Extract embedded streams from metadata videos (used by PPV-style addons)
|
||||||
const extractEmbeddedStreams = useCallback(() => {
|
const extractEmbeddedStreams = useCallback((episodeIdOverride?: string) => {
|
||||||
if (!metadata?.videos) return;
|
if (!metadata?.videos) return;
|
||||||
|
|
||||||
// Check if any video has embedded streams
|
// Check if any video has embedded streams
|
||||||
|
|
@ -1378,11 +1378,11 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
const addonId = (metadata as any).addonId || 'embedded';
|
const addonId = (metadata as any).addonId || 'embedded';
|
||||||
const addonName = (metadata as any).addonName || metadata.name || 'Embedded Streams';
|
const addonName = (metadata as any).addonName || metadata.name || 'Embedded Streams';
|
||||||
|
|
||||||
// Extract all streams from videos
|
// 1. Extract all streams for groupedStreams (legacy/movies behavior, or flat list)
|
||||||
const embeddedStreams: Stream[] = [];
|
const allEmbeddedStreams: Stream[] = [];
|
||||||
for (const video of videosWithStreams) {
|
for (const video of videosWithStreams) {
|
||||||
for (const stream of video.streams) {
|
for (const stream of video.streams) {
|
||||||
embeddedStreams.push({
|
allEmbeddedStreams.push({
|
||||||
...stream,
|
...stream,
|
||||||
name: stream.name || stream.title || video.title,
|
name: stream.name || stream.title || video.title,
|
||||||
title: stream.title || video.title,
|
title: stream.title || video.title,
|
||||||
|
|
@ -1392,15 +1392,15 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (embeddedStreams.length > 0) {
|
if (allEmbeddedStreams.length > 0) {
|
||||||
if (__DEV__) console.log(`✅ [extractEmbeddedStreams] Found ${embeddedStreams.length} embedded streams from ${addonName}`);
|
if (__DEV__) console.log(`✅ [extractEmbeddedStreams] Found ${allEmbeddedStreams.length} embedded streams from ${addonName}`);
|
||||||
|
|
||||||
// Add to grouped streams
|
// Add to grouped streams
|
||||||
setGroupedStreams(prevStreams => ({
|
setGroupedStreams(prevStreams => ({
|
||||||
...prevStreams,
|
...prevStreams,
|
||||||
[addonId]: {
|
[addonId]: {
|
||||||
addonName,
|
addonName,
|
||||||
streams: embeddedStreams,
|
streams: allEmbeddedStreams,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -1412,10 +1412,44 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
return prevOrder;
|
return prevOrder;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mark loading as complete since we have streams
|
// If we are not waiting for episode streams, we can stop loading
|
||||||
setLoadingStreams(false);
|
if (!loadingEpisodeStreams) {
|
||||||
|
setLoadingStreams(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [metadata]);
|
|
||||||
|
// 2. Extract streams specifically for the selected episode
|
||||||
|
const episodeToUse = episodeIdOverride || selectedEpisode;
|
||||||
|
if (episodeToUse) {
|
||||||
|
const episodeVideo = videosWithStreams.find(
|
||||||
|
v => v.id === episodeToUse ||
|
||||||
|
v.id === episodeToUse.split(':').pop() || // Handle cases where ID might have prefix
|
||||||
|
(v.season === 0 && v.episode === 1 && videosWithStreams.length === 1) // Single item PPV edge case
|
||||||
|
);
|
||||||
|
|
||||||
|
if (episodeVideo && episodeVideo.streams && episodeVideo.streams.length > 0) {
|
||||||
|
if (__DEV__) console.log(`✅ [extractEmbeddedStreams] Found embedded streams for episode ${episodeToUse}`);
|
||||||
|
|
||||||
|
const episodeStreamsList: Stream[] = episodeVideo.streams.map((stream: any) => ({
|
||||||
|
...stream,
|
||||||
|
name: stream.name || stream.title || episodeVideo.title,
|
||||||
|
title: stream.title || episodeVideo.title,
|
||||||
|
addonId,
|
||||||
|
addonName,
|
||||||
|
}));
|
||||||
|
|
||||||
|
setEpisodeStreams(prevStreams => ({
|
||||||
|
...prevStreams,
|
||||||
|
[addonId]: {
|
||||||
|
addonName,
|
||||||
|
streams: episodeStreamsList,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
setLoadingEpisodeStreams(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [metadata, selectedEpisode, loadingEpisodeStreams]);
|
||||||
|
|
||||||
const loadStreams = async () => {
|
const loadStreams = async () => {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
@ -1822,11 +1856,24 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
if (__DEV__) console.log('✅ [loadEpisodeStreams] Converted to TMDB ID:', tmdbId);
|
if (__DEV__) console.log('✅ [loadEpisodeStreams] Converted to TMDB ID:', tmdbId);
|
||||||
|
|
||||||
// Ensure consistent format
|
// Ensure consistent format
|
||||||
stremioEpisodeId = `${id}:${seasonNum}:${episodeNum}`;
|
// Ensure consistent format or fallback to episodeId if parsing failed
|
||||||
|
// This handles cases where 'tt' is used for a unique episode ID directly
|
||||||
|
if (!seasonNum && !episodeNum) {
|
||||||
|
stremioEpisodeId = episodeId;
|
||||||
|
} else {
|
||||||
|
stremioEpisodeId = `${id}:${seasonNum}:${episodeNum}`;
|
||||||
|
}
|
||||||
if (__DEV__) console.log('🔧 [loadEpisodeStreams] Normalized episode ID for addons:', stremioEpisodeId);
|
if (__DEV__) console.log('🔧 [loadEpisodeStreams] Normalized episode ID for addons:', stremioEpisodeId);
|
||||||
} else {
|
} else {
|
||||||
tmdbId = id;
|
tmdbId = id;
|
||||||
stremioEpisodeId = `${id}:${seasonNum}:${episodeNum}`;
|
// If season/episode parsing failed (empty strings), use the raw episode ID
|
||||||
|
// This handles custom IDs like "ppv-event-name" that don't follow "id:s:e" format
|
||||||
|
if (!seasonNum && !episodeNum) {
|
||||||
|
// Remove 'series:' prefix if present to be safe, though parsing logic above usually handles it
|
||||||
|
stremioEpisodeId = episodeId.replace(/^series:/, '');
|
||||||
|
} else {
|
||||||
|
stremioEpisodeId = `${id}:${seasonNum}:${episodeNum}`;
|
||||||
|
}
|
||||||
if (__DEV__) console.log('ℹ️ [loadEpisodeStreams] Using ID as both TMDB and Stremio ID:', tmdbId);
|
if (__DEV__) console.log('ℹ️ [loadEpisodeStreams] Using ID as both TMDB and Stremio ID:', tmdbId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1840,11 +1887,16 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
if (__DEV__) console.log('🎬 [loadEpisodeStreams] Using episode ID for Stremio addons:', stremioEpisodeId);
|
if (__DEV__) console.log('🎬 [loadEpisodeStreams] Using episode ID for Stremio addons:', stremioEpisodeId);
|
||||||
|
|
||||||
// For collections, treat episodes as individual movies, not series
|
// For collections, treat episodes as individual movies, not series
|
||||||
const contentType = isCollection ? 'movie' : 'series';
|
// For other types (e.g. StreamsPPV), preserve the original type unless it's explicitly 'series' logic we want
|
||||||
if (__DEV__) console.log(`🎬 [loadEpisodeStreams] Using content type: ${contentType} for ${isCollection ? 'collection' : 'series'}`);
|
const contentType = isCollection ? 'movie' : type;
|
||||||
|
if (__DEV__) console.log(`🎬 [loadEpisodeStreams] Using content type: ${contentType} for ${isCollection ? 'collection' : type}`);
|
||||||
|
|
||||||
processStremioSource(contentType, stremioEpisodeId, true);
|
processStremioSource(contentType, stremioEpisodeId, true);
|
||||||
|
|
||||||
|
// Also extract any embedded streams from metadata for this episode
|
||||||
|
// Also extract any embedded streams from metadata for this episode
|
||||||
|
extractEmbeddedStreams(episodeId);
|
||||||
|
|
||||||
// Monitor scraper completion status instead of using fixed timeout
|
// Monitor scraper completion status instead of using fixed timeout
|
||||||
const checkEpisodeScrapersCompletion = () => {
|
const checkEpisodeScrapersCompletion = () => {
|
||||||
setScraperStatuses(currentStatuses => {
|
setScraperStatuses(currentStatuses => {
|
||||||
|
|
|
||||||
|
|
@ -357,7 +357,7 @@ export const useStreamsScreen = () => {
|
||||||
async (stream: Stream, options?: { headers?: Record<string, string> }) => {
|
async (stream: Stream, options?: { headers?: Record<string, string> }) => {
|
||||||
const finalHeaders = filterHeadersForVidrock(options?.headers || (stream.headers as any));
|
const finalHeaders = filterHeadersForVidrock(options?.headers || (stream.headers as any));
|
||||||
|
|
||||||
const streamsToPass = type === 'series' || (type === 'other' && selectedEpisode) ? episodeStreams : groupedStreams;
|
const streamsToPass = selectedEpisode ? episodeStreams : groupedStreams;
|
||||||
const streamName = stream.name || stream.title || 'Unnamed Stream';
|
const streamName = stream.name || stream.title || 'Unnamed Stream';
|
||||||
const streamProvider = stream.addonId || stream.addonName || stream.name;
|
const streamProvider = stream.addonId || stream.addonName || stream.name;
|
||||||
|
|
||||||
|
|
@ -545,8 +545,7 @@ export const useStreamsScreen = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isMounted.current) return;
|
if (!isMounted.current) return;
|
||||||
|
|
||||||
const currentStreamsData =
|
const currentStreamsData = selectedEpisode ? episodeStreams : groupedStreams;
|
||||||
metadata?.videos && metadata.videos.length > 1 && selectedEpisode ? episodeStreams : groupedStreams;
|
|
||||||
|
|
||||||
const providersWithStreams = Object.entries(currentStreamsData)
|
const providersWithStreams = Object.entries(currentStreamsData)
|
||||||
.filter(([_, data]) => data.streams && data.streams.length > 0)
|
.filter(([_, data]) => data.streams && data.streams.length > 0)
|
||||||
|
|
@ -592,8 +591,7 @@ export const useStreamsScreen = () => {
|
||||||
const isSpecialFilter = selectedProvider === 'all' || selectedProvider === 'grouped-plugins';
|
const isSpecialFilter = selectedProvider === 'all' || selectedProvider === 'grouped-plugins';
|
||||||
if (isSpecialFilter) return;
|
if (isSpecialFilter) return;
|
||||||
|
|
||||||
const currentStreamsData =
|
const currentStreamsData = selectedEpisode ? episodeStreams : groupedStreams;
|
||||||
metadata?.videos && metadata.videos.length > 1 && selectedEpisode ? episodeStreams : groupedStreams;
|
|
||||||
const hasStreamsForProvider =
|
const hasStreamsForProvider =
|
||||||
currentStreamsData[selectedProvider] &&
|
currentStreamsData[selectedProvider] &&
|
||||||
currentStreamsData[selectedProvider].streams &&
|
currentStreamsData[selectedProvider].streams &&
|
||||||
|
|
@ -675,8 +673,7 @@ export const useStreamsScreen = () => {
|
||||||
// Autoplay effect
|
// Autoplay effect
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (settings.autoplayBestStream && !autoplayTriggered && isAutoplayWaiting) {
|
if (settings.autoplayBestStream && !autoplayTriggered && isAutoplayWaiting) {
|
||||||
const streams =
|
const streams = selectedEpisode ? episodeStreams : groupedStreams;
|
||||||
metadata?.videos && metadata.videos.length > 1 && selectedEpisode ? episodeStreams : groupedStreams;
|
|
||||||
|
|
||||||
if (Object.keys(streams).length > 0) {
|
if (Object.keys(streams).length > 0) {
|
||||||
const bestStream = getBestStream(streams);
|
const bestStream = getBestStream(streams);
|
||||||
|
|
@ -716,7 +713,7 @@ export const useStreamsScreen = () => {
|
||||||
// Filter items for provider selector
|
// Filter items for provider selector
|
||||||
const filterItems = useMemo((): FilterItem[] => {
|
const filterItems = useMemo((): FilterItem[] => {
|
||||||
const installedAddons = stremioService.getInstalledAddons();
|
const installedAddons = stremioService.getInstalledAddons();
|
||||||
const streams = metadata?.videos && metadata.videos.length > 1 && selectedEpisode ? episodeStreams : groupedStreams;
|
const streams = selectedEpisode ? episodeStreams : groupedStreams;
|
||||||
|
|
||||||
const providersWithStreams = Object.keys(streams).filter(key => {
|
const providersWithStreams = Object.keys(streams).filter(key => {
|
||||||
const providerData = streams[key];
|
const providerData = streams[key];
|
||||||
|
|
@ -787,7 +784,7 @@ export const useStreamsScreen = () => {
|
||||||
|
|
||||||
// Sections for stream list
|
// Sections for stream list
|
||||||
const sections = useMemo((): StreamSection[] => {
|
const sections = useMemo((): StreamSection[] => {
|
||||||
const streams = metadata?.videos && metadata.videos.length > 1 && selectedEpisode ? episodeStreams : groupedStreams;
|
const streams = selectedEpisode ? episodeStreams : groupedStreams;
|
||||||
const installedAddons = stremioService.getInstalledAddons();
|
const installedAddons = stremioService.getInstalledAddons();
|
||||||
|
|
||||||
const filteredEntries = Object.entries(streams).filter(([addonId]) => {
|
const filteredEntries = Object.entries(streams).filter(([addonId]) => {
|
||||||
|
|
@ -1014,8 +1011,9 @@ export const useStreamsScreen = () => {
|
||||||
const gradientColors = useMemo(() => createGradientColors(dominantColor), [dominantColor, createGradientColors]);
|
const gradientColors = useMemo(() => createGradientColors(dominantColor), [dominantColor, createGradientColors]);
|
||||||
|
|
||||||
// Loading states
|
// Loading states
|
||||||
const isLoading = metadata?.videos && metadata.videos.length > 1 && selectedEpisode ? loadingEpisodeStreams : loadingStreams;
|
// Loading states
|
||||||
const streams = metadata?.videos && metadata.videos.length > 1 && selectedEpisode ? episodeStreams : groupedStreams;
|
const isLoading = selectedEpisode ? loadingEpisodeStreams : loadingStreams;
|
||||||
|
const streams = selectedEpisode ? episodeStreams : groupedStreams;
|
||||||
|
|
||||||
const streamsEmpty =
|
const streamsEmpty =
|
||||||
Object.keys(streams).length === 0 ||
|
Object.keys(streams).length === 0 ||
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue