From c764faf2a74847a300f09152b463df0ea8a3b003 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sun, 1 Mar 2026 15:06:50 +0530 Subject: [PATCH] fix race conditions --- src/components/video/TrailerPlayer.tsx | 29 ++++++++++++++++++-------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/components/video/TrailerPlayer.tsx b/src/components/video/TrailerPlayer.tsx index de8a7b912..cd5d9e75e 100644 --- a/src/components/video/TrailerPlayer.tsx +++ b/src/components/video/TrailerPlayer.tsx @@ -75,6 +75,11 @@ const TrailerPlayer = React.forwardRef(({ const [isFullscreen, setIsFullscreen] = useState(false); const [isComponentMounted, setIsComponentMounted] = useState(true); + // FIX: Track whether this player has ever been in a playing state. + // This prevents the globalTrailerPlaying effect from suppressing the + // very first play attempt before the global state has been set to true. + const hasBeenPlayingRef = useRef(false); + // Animated values const controlsOpacity = useSharedValue(0); const loadingOpacity = useSharedValue(1); @@ -150,6 +155,7 @@ const TrailerPlayer = React.forwardRef(({ useEffect(() => { if (isComponentMounted && paused === undefined) { setIsPlaying(autoPlay); + if (autoPlay) hasBeenPlayingRef.current = true; } }, [autoPlay, isComponentMounted, paused]); @@ -163,18 +169,23 @@ const TrailerPlayer = React.forwardRef(({ // Handle external paused prop to override playing state (highest priority) useEffect(() => { if (paused !== undefined) { - setIsPlaying(!paused); - logger.info('TrailerPlayer', `External paused prop changed: ${paused}, setting isPlaying to ${!paused}`); + const shouldPlay = !paused; + setIsPlaying(shouldPlay); + if (shouldPlay) hasBeenPlayingRef.current = true; + logger.info('TrailerPlayer', `External paused prop changed: ${paused}, setting isPlaying to ${shouldPlay}`); } }, [paused]); // Respond to global trailer state changes (e.g., when modal opens) - // Only apply if no external paused prop is controlling this + // Only apply if no external paused prop is controlling this. + // FIX: Only pause if this player has previously been in a playing state. + // This avoids the race condition where globalTrailerPlaying is still false + // at mount time (before the parent has called setTrailerPlaying(true)), + // which was causing the trailer to be immediately paused on every load. useEffect(() => { if (isComponentMounted && paused === undefined) { - // Always sync with global trailer state when pausing - // This ensures all trailers pause when one screen loses focus - if (!globalTrailerPlaying) { + if (!globalTrailerPlaying && hasBeenPlayingRef.current) { + // Only suppress if the player was previously playing — not on initial mount logger.info('TrailerPlayer', 'Global trailer paused - pausing this trailer'); setIsPlaying(false); } @@ -364,10 +375,10 @@ const TrailerPlayer = React.forwardRef(({ ref={videoRef} source={(() => { const androidHeaders = Platform.OS === 'android' ? { 'User-Agent': 'Nuvio/1.0 (Android)' } : {} as any; - // Help ExoPlayer select proper MediaSource const lower = (trailerUrl || '').toLowerCase(); const looksLikeHls = /\.m3u8(\b|$)/.test(lower) || /hls|applehlsencryption|playlist|m3u/.test(lower); - const looksLikeDash = /\.mpd(\b|$)/.test(lower) || /dash|manifest/.test(lower); + // Detect both .mpd URLs and inline data: DASH manifests + const looksLikeDash = /\.mpd(\b|$)/.test(lower) || /dash|manifest/.test(lower) || lower.startsWith('data:application/dash'); if (Platform.OS === 'android') { if (looksLikeHls) { return { uri: trailerUrl, type: 'm3u8', headers: androidHeaders } as any; @@ -595,4 +606,4 @@ const styles = StyleSheet.create({ }, }); -export default TrailerPlayer; \ No newline at end of file +export default TrailerPlayer;