From c767de12aac698382b92f26df2b0300096049c58 Mon Sep 17 00:00:00 2001 From: tapframe Date: Wed, 17 Sep 2025 20:23:46 +0530 Subject: [PATCH] VideoPlayer code cleanup --- src/components/player/AndroidVideoPlayer.tsx | 41 +--------- src/components/player/VideoPlayer.tsx | 81 +++++++++---------- .../player/modals/SubtitleModals.tsx | 4 + src/screens/CatalogScreen.tsx | 50 +++++++++--- 4 files changed, 87 insertions(+), 89 deletions(-) diff --git a/src/components/player/AndroidVideoPlayer.tsx b/src/components/player/AndroidVideoPlayer.tsx index 92bb600..ea5089a 100644 --- a/src/components/player/AndroidVideoPlayer.tsx +++ b/src/components/player/AndroidVideoPlayer.tsx @@ -75,9 +75,6 @@ const AndroidVideoPlayer: React.FC = () => { backdrop } = route.params; - // Check if the stream is from Xprime (by provider name or URL pattern) - const isXprimeStream = streamProvider === 'xprime' || streamProvider === 'Xprime' || - (uri && /flutch.*\.workers\.dev|fsl\.fastcloud\.casa|xprime/i.test(uri)); // Check if the stream is HLS (m3u8 playlist) const isHlsStream = (url: string) => { @@ -99,37 +96,11 @@ const AndroidVideoPlayer: React.FC = () => { } as any; }; - // Xprime-specific headers for better compatibility (from local-scrapers-repo) - const getXprimeHeaders = () => { - if (!isXprimeStream) return {}; - const xprimeHeaders = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', - 'Accept': 'video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5', - 'Accept-Language': 'en-US,en;q=0.9', - 'Accept-Encoding': 'identity', - 'Origin': 'https://xprime.tv', - 'Referer': 'https://xprime.tv/', - 'Sec-Fetch-Dest': 'video', - 'Sec-Fetch-Mode': 'no-cors', - 'Sec-Fetch-Site': 'cross-site', - 'DNT': '1' - } as any; - logger.log('[AndroidVideoPlayer] Applying Xprime headers for stream:', uri); - return xprimeHeaders; - }; // Get appropriate headers based on stream type const getStreamHeaders = () => { - // For Xprime streams, be more flexible - only use HLS headers if it actually looks like HLS - if (isXprimeStream) { - if (isHlsStream(currentStreamUrl)) { - logger.log('[AndroidVideoPlayer] Xprime HLS stream detected, applying HLS headers'); - return getXprimeHeaders(); - } else { - logger.log('[AndroidVideoPlayer] Xprime MP4 stream detected, using default headers'); - return Platform.OS === 'android' ? defaultAndroidHeaders() : defaultIosHeaders(); - } - } else if (isHlsStream(currentStreamUrl)) { + // Use HLS headers for HLS streams, default headers for everything else + if (isHlsStream(currentStreamUrl)) { logger.log('[AndroidVideoPlayer] Detected HLS stream, applying HLS headers'); return getHlsHeaders(); } @@ -1535,12 +1506,8 @@ const AndroidVideoPlayer: React.FC = () => { return; } - // Detect Xprime provider to enable a one-shot silent retry (warms upstream/cache) - const providerName = ((currentStreamProvider || streamProvider || '') as string).toLowerCase(); - const isXprimeProvider = providerName.includes('xprime'); - // One-shot, silent retry without showing error UI - if (isXprimeProvider && retryAttemptRef.current < 1) { + if (retryAttemptRef.current < 1) { retryAttemptRef.current = 1; // Cache-bust to force a fresh fetch and warm upstream const addRetryParam = (url: string) => { @@ -1548,7 +1515,7 @@ const AndroidVideoPlayer: React.FC = () => { return `${url}${sep}rn_retry_ts=${Date.now()}`; }; const bustedUrl = addRetryParam(currentStreamUrl); - logger.warn('[AndroidVideoPlayer] Silent retry for Xprime with cache-busted URL'); + logger.warn('[AndroidVideoPlayer] Silent retry with cache-busted URL'); // Ensure no modal is visible if (errorTimeoutRef.current) { clearTimeout(errorTimeoutRef.current); diff --git a/src/components/player/VideoPlayer.tsx b/src/components/player/VideoPlayer.tsx index 7d658d5..123adaa 100644 --- a/src/components/player/VideoPlayer.tsx +++ b/src/components/player/VideoPlayer.tsx @@ -46,57 +46,23 @@ import * as Brightness from 'expo-brightness'; const VideoPlayer: React.FC = () => { const insets = useSafeAreaInsets(); const route = useRoute>(); - const { streamProvider, uri, headers, forceVlc } = route.params as any; - - // Check if the stream is from Xprime (by provider name or URL pattern) - const isXprimeStream = streamProvider === 'xprime' || streamProvider === 'Xprime' || - (uri && /flutch.*\.workers\.dev|fsl\.fastcloud\.casa|xprime/i.test(uri)); - - safeDebugLog("Stream detection", { - uri, - streamProvider, - isXprimeStream, - platform: Platform.OS - }); - - // Xprime-specific headers for better compatibility (from local-scrapers-repo) - const getXprimeHeaders = () => { - if (!isXprimeStream) return {}; - const xprimeHeaders = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', - 'Accept': 'video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5', - 'Accept-Language': 'en-US,en;q=0.9', - 'Accept-Encoding': 'identity', - 'Origin': 'https://xprime.tv', - 'Referer': 'https://xprime.tv/', - 'Sec-Fetch-Dest': 'video', - 'Sec-Fetch-Mode': 'no-cors', - 'Sec-Fetch-Site': 'cross-site', - 'DNT': '1' - } as any; - logger.log('[VideoPlayer] Applying Xprime headers for stream:', uri); - return xprimeHeaders; - }; + const { uri, headers, forceVlc, streamProvider } = route.params as any; // Detect if stream is MKV format const isMkvFile = isMkvStream(uri, headers); // Use AndroidVideoPlayer for: // - Android devices - // - Xprime streams (unless it's MKV on iOS - allow VLC for better compatibility) // - Non-MKV files on iOS (unless forceVlc is set) // Use VideoPlayer (VLC) for: - // - MKV files on iOS (unless forceVlc is set, even for Xprime) + // - MKV files on iOS (unless forceVlc is set) const shouldUseAndroidPlayer = Platform.OS === 'android' || - (isXprimeStream && !(Platform.OS === 'ios' && isMkvFile)) || (Platform.OS === 'ios' && !isMkvFile && !forceVlc); safeDebugLog("Player selection logic", { platform: Platform.OS, - isXprimeStream, isMkvFile, forceVlc, - xprimeException: isXprimeStream && Platform.OS === 'ios' && isMkvFile, shouldUseAndroidPlayer }); if (shouldUseAndroidPlayer) { @@ -1176,6 +1142,38 @@ const VideoPlayer: React.FC = () => { } if (data.textTracks && data.textTracks.length > 0) { setVlcTextTracks(data.textTracks); + + // Auto-select English subtitle track if available + if (selectedTextTrack === -1 && !useCustomSubtitles && data.textTracks.length > 0) { + if (DEBUG_MODE) { + logger.log(`[VideoPlayer] Available subtitle tracks:`, data.textTracks.map((track: any) => ({ + id: track.id, + index: track.index, + name: track.name, + language: track.language + }))); + } + + // Look for English track first + const englishTrack = data.textTracks.find((track: any) => { + const lang = (track.language || '').toLowerCase(); + const name = (track.name || '').toLowerCase(); + return lang === 'english' || lang === 'en' || lang === 'eng' || + name.includes('english') || name.includes('en'); + }); + + if (englishTrack) { + // Try different ID fields that VLC might use + const trackId = englishTrack.id !== undefined ? englishTrack.id : + englishTrack.index !== undefined ? englishTrack.index : 0; + setSelectedTextTrack(trackId); + if (DEBUG_MODE) { + logger.log(`[VideoPlayer] Auto-selected English subtitle track: ${englishTrack.name || 'Unknown'} (ID: ${trackId})`); + } + } else if (DEBUG_MODE) { + logger.log(`[VideoPlayer] No English subtitle track found, keeping subtitles disabled`); + } + } } setIsVideoLoaded(true); @@ -2557,13 +2555,12 @@ const VideoPlayer: React.FC = () => { ref={vlcRef} style={[styles.video, customVideoStyles, { transform: [{ scale: zoomScale }] }]} source={(() => { - // Use Xprime headers if detected, otherwise use headers from route params - const finalHeaders = getXprimeHeaders() || headers; - const sourceWithHeaders = finalHeaders ? { + // Use route headers for VLC streams + const sourceWithHeaders = headers && Object.keys(headers).length > 0 ? { uri: currentStreamUrl, - headers: finalHeaders + headers: headers } : { uri: currentStreamUrl }; - + return sourceWithHeaders; })()} paused={paused} @@ -2576,7 +2573,7 @@ const VideoPlayer: React.FC = () => { onPaused={onPaused} resizeMode={resizeMode as any} audioTrack={selectedAudioTrack ?? undefined} - textTrack={useCustomSubtitles ? -1 : (selectedTextTrack ?? undefined)} + textTrack={useCustomSubtitles ? -1 : (selectedTextTrack >= 0 ? selectedTextTrack : -1)} autoAspectRatio volume={volume / 100} /> diff --git a/src/components/player/modals/SubtitleModals.tsx b/src/components/player/modals/SubtitleModals.tsx index 5f2695a..d09f59a 100644 --- a/src/components/player/modals/SubtitleModals.tsx +++ b/src/components/player/modals/SubtitleModals.tsx @@ -288,6 +288,10 @@ export const SubtitleModals: React.FC = ({ {vlcTextTracks.map((track) => { const isSelected = selectedTextTrack === track.id && !useCustomSubtitles; + // Debug logging for subtitle selection + if (__DEV__ && vlcTextTracks.length > 0) { + console.log('[SubtitleModals] Track:', track.id, track.name, 'Selected:', selectedTextTrack, 'isSelected:', isSelected, 'useCustom:', useCustomSubtitles); + } return ( StyleSheet.create({ top: 10, right: 10, backgroundColor: 'rgba(0,0,0,0.7)', - borderRadius: 0, + borderRadius: 10, paddingHorizontal: 10, paddingVertical: 6, flexDirection: 'row', alignItems: 'center', }, + badgeBlur: { + position: 'absolute', + top: 10, + right: 10, + borderRadius: 10, + overflow: 'hidden', + }, + badgeContent: { + flexDirection: 'row', + alignItems: 'center', + paddingHorizontal: 10, + paddingVertical: 6, + }, badgeText: { fontSize: 11, fontWeight: '600', @@ -584,15 +598,31 @@ const CatalogScreen: React.FC = ({ route, navigation }) => { /> {type === 'movie' && nowPlayingMovies.has(item.id) && ( - - - In Theaters - + Platform.OS === 'ios' ? ( + + + + + In Theaters + + + + ) : ( + + + In Theaters + + ) )} );