From 71e2d39d9612e5f919a2989fd7c365a19b576ae7 Mon Sep 17 00:00:00 2001 From: tapframe Date: Fri, 20 Jun 2025 18:07:30 +0530 Subject: [PATCH] Implement stream provider checks and error handling in StreamsScreen This update enhances the StreamsScreen component by adding checks for available streaming sources, improving user feedback when no sources are available. A new state for displaying an error message is introduced, along with logic to handle the loading of streams based on the availability of Stremio addons and internal providers. Additionally, the UI is updated to reflect these changes, ensuring a more responsive and informative user experience during content loading. --- src/screens/StreamsScreen.tsx | 159 ++++++++++++++++++++++----------- src/services/stremioService.ts | 23 +++++ 2 files changed, 131 insertions(+), 51 deletions(-) diff --git a/src/screens/StreamsScreen.tsx b/src/screens/StreamsScreen.tsx index c3750c5c7..bb8698703 100644 --- a/src/screens/StreamsScreen.tsx +++ b/src/screens/StreamsScreen.tsx @@ -390,6 +390,13 @@ export const StreamsScreen = () => { const [autoplayTriggered, setAutoplayTriggered] = useState(false); const [isAutoplayWaiting, setIsAutoplayWaiting] = useState(false); + // Add check for available streaming sources + const [hasStreamProviders, setHasStreamProviders] = useState(true); // Assume true initially + const [hasStremioStreamProviders, setHasStremioStreamProviders] = useState(true); // For footer logic + + // Add state for no sources error + const [showNoSourcesError, setShowNoSourcesError] = useState(false); + // Monitor streams loading and update available providers immediately useEffect(() => { // Skip processing if component is unmounting @@ -433,35 +440,50 @@ export const StreamsScreen = () => { } }, [selectedProvider, availableProviders]); + // Update useEffect to check for sources + useEffect(() => { + const checkProviders = async () => { + // Check for both Stremio addons and if the internal provider is enabled + const hasStremioProviders = await stremioService.hasStreamProviders(); + const hasProviders = hasStremioProviders || settings.enableInternalProviders; + if (!isMounted.current) return; - React.useEffect(() => { - if (type === 'series' && episodeId) { - logger.log(`🎬 Loading episode streams for: ${episodeId}`); - setLoadingProviders({ - 'stremio': true, - 'hdrezka': true - }); - setSelectedEpisode(episodeId); - loadEpisodeStreams(episodeId); - } else if (type === 'movie') { - logger.log(`🎬 Loading movie streams for: ${id}`); - // setLoadingProviders({ // This is now handled by the main effect - // 'stremio': true, - // 'hdrezka': true - // }); - loadStreams(); - } + setHasStreamProviders(hasProviders); + setHasStremioStreamProviders(hasStremioProviders); - // Reset autoplay state when content changes - setAutoplayTriggered(false); - if (settings.autoplayBestStream) { - setIsAutoplayWaiting(true); - logger.log('🔄 Autoplay enabled, waiting for best stream...'); - } else { - setIsAutoplayWaiting(false); - } - }, [type, episodeId, settings.autoplayBestStream]); + if (!hasProviders) { + const timer = setTimeout(() => { + if (isMounted.current) setShowNoSourcesError(true); + }, 500); + return () => clearTimeout(timer); + } else { + if (type === 'series' && episodeId) { + logger.log(`🎬 Loading episode streams for: ${episodeId}`); + setLoadingProviders({ + 'stremio': true, + 'hdrezka': true + }); + setSelectedEpisode(episodeId); + loadEpisodeStreams(episodeId); + } else if (type === 'movie') { + logger.log(`🎬 Loading movie streams for: ${id}`); + loadStreams(); + } + + // Reset autoplay state when content changes + setAutoplayTriggered(false); + if (settings.autoplayBestStream) { + setIsAutoplayWaiting(true); + logger.log('🔄 Autoplay enabled, waiting for best stream...'); + } else { + setIsAutoplayWaiting(false); + } + } + }; + + checkProviders(); + }, [type, id, episodeId, settings.autoplayBestStream, settings.enableInternalProviders]); React.useEffect(() => { // Trigger entrance animations @@ -1281,9 +1303,25 @@ export const StreamsScreen = () => { )} - {/* Show streams immediately as they become available */} - {Object.keys(streams).length === 0 ? ( - // Only show initial loading if no streams are available yet + {/* Update the streams/loading state display logic */} + { showNoSourcesError ? ( + + + No streaming sources available + + Please add streaming sources in settings + + navigation.navigate('Settings')} + > + Add Sources + + + ) : Object.keys(streams).length === 0 ? ( (loadingStreams || loadingEpisodeStreams) ? ( { bounces={true} overScrollMode="never" ListFooterComponent={ - (loadingStreams || loadingEpisodeStreams) ? ( + (loadingStreams || loadingEpisodeStreams) && hasStremioStreamProviders ? ( Loading more sources... @@ -1394,25 +1432,25 @@ const createStyles = (colors: any) => StyleSheet.create({ flexGrow: 0, }, filterChip: { - backgroundColor: colors.transparentLight, + backgroundColor: 'transparent', paddingHorizontal: 16, paddingVertical: 8, borderRadius: 20, marginRight: 8, borderWidth: 1, - borderColor: colors.transparent, + borderColor: colors.border, }, filterChipSelected: { - backgroundColor: colors.transparentLight, + backgroundColor: colors.primary, borderColor: colors.primary, }, filterChipText: { - color: colors.text, + color: colors.mediumEmphasis, fontWeight: '500', }, filterChipTextSelected: { - color: colors.primary, - fontWeight: 'bold', + color: colors.white, + fontWeight: '600', }, streamsContent: { flex: 1, @@ -1429,23 +1467,23 @@ const createStyles = (colors: any) => StyleSheet.create({ width: '100%', }, streamGroupTitle: { - color: colors.text, - fontSize: 16, - fontWeight: '600', - marginBottom: 4, + color: colors.highEmphasis, + fontSize: 15, + fontWeight: '700', + marginBottom: 8, marginTop: 0, backgroundColor: 'transparent', }, streamCard: { flexDirection: 'row', alignItems: 'flex-start', - padding: 12, - borderRadius: 12, - marginBottom: 8, + padding: 16, + borderRadius: 10, + marginBottom: 12, minHeight: 70, - backgroundColor: colors.elevation1, + backgroundColor: colors.card, borderWidth: 1, - borderColor: 'rgba(255,255,255,0.05)', + borderColor: colors.cardHighlight, width: '100%', zIndex: 1, }, @@ -1487,11 +1525,12 @@ const createStyles = (colors: any) => StyleSheet.create({ alignItems: 'center', }, chip: { - paddingHorizontal: 8, - paddingVertical: 2, + paddingHorizontal: 10, + paddingVertical: 4, borderRadius: 4, marginRight: 4, marginBottom: 4, + backgroundColor: colors.surfaceVariant, }, chipText: { color: colors.highEmphasis, @@ -1516,10 +1555,10 @@ const createStyles = (colors: any) => StyleSheet.create({ marginLeft: 8, }, streamAction: { - width: 40, - height: 40, - borderRadius: 20, - backgroundColor: colors.elevation2, + width: 36, + height: 36, + borderRadius: 18, + backgroundColor: colors.card, justifyContent: 'center', alignItems: 'center', }, @@ -1793,6 +1832,24 @@ const createStyles = (colors: any) => StyleSheet.create({ marginLeft: 8, fontWeight: '600', }, + noStreamsSubText: { + color: colors.mediumEmphasis, + fontSize: 14, + marginTop: 8, + textAlign: 'center', + }, + addSourcesButton: { + marginTop: 24, + paddingHorizontal: 20, + paddingVertical: 10, + backgroundColor: colors.primary, + borderRadius: 8, + }, + addSourcesButtonText: { + color: colors.white, + fontSize: 14, + fontWeight: '600', + }, }); export default memo(StreamsScreen); \ No newline at end of file diff --git a/src/services/stremioService.ts b/src/services/stremioService.ts index 7aef7993d..6415c145c 100644 --- a/src/services/stremioService.ts +++ b/src/services/stremioService.ts @@ -1039,6 +1039,29 @@ class StremioService { } return false; } + + // Check if any installed addons can provide streams + async hasStreamProviders(): Promise { + await this.ensureInitialized(); + const addons = Array.from(this.installedAddons.values()); + + for (const addon of addons) { + if (addon.resources && Array.isArray(addon.resources)) { + // Check for 'stream' resource in the modern format + const hasStreamResource = addon.resources.some(resource => + typeof resource === 'string' + ? resource === 'stream' + : resource.name === 'stream' + ); + + if (hasStreamResource) { + return true; + } + } + } + + return false; + } } export const stremioService = StremioService.getInstance();