UNPKG

@zezosoft/zezo-ott-react-native-video-player

Version:

Production-ready React Native OTT video player library for Android & iOS. Features: playlists, seasons, auto-next playback, subtitles (SRT/VTT), custom theming, analytics tracking, fullscreen mode, gesture controls, ads player (pre-roll/mid-roll/post-roll

165 lines (156 loc) 5.99 kB
"use strict"; import { useEffect, useRef } from 'react'; import { useVideoPlayerStore } from "../../VideoPlayer/store/videoPlayerStore.js"; import { useAdsPlayerStore } from "../store/adsPlayerStore.js"; import { useAdInitialization } from "./useAdInitialization.js"; export const useAdsManager = (ads = [], onAdTracking) => { const { currentTime, activeTrack } = useVideoPlayerStore(); const { currentAd, isAdPlaying, pendingMidRollAds, addPendingMidRollAd, clearPendingMidRollAds } = useAdsPlayerStore(); const { startAd } = useAdInitialization({ onAdTracking }); const adsInitializedRef = useRef(false); const previousAdsRef = useRef(''); const playedMidRollAdsRef = useRef(new Set()); const playedPreRollAdsRef = useRef(new Set()); const playedPostRollAdsRef = useRef(new Set()); const previousTimeRef = useRef(0); const isResettingRef = useRef(false); useEffect(() => { // Prevent infinite loops if (isResettingRef.current) { return; } const adsKey = JSON.stringify(ads?.map(ad => ad.id) || []); const hadAds = previousAdsRef.current !== ''; const hasAds = ads && ads.length > 0; if (hasAds && adsKey !== previousAdsRef.current) { previousAdsRef.current = adsKey; // Don't initialize ads if it's a trailer if (activeTrack?.isTrailer) { return; } const preRollAds = ads.filter(ad => ad.position === 'pre'); const midRollAds = ads.filter(ad => ad.position === 'mid'); if (preRollAds.length > 0 && preRollAds[0] && !currentAd) { try { playedPreRollAdsRef.current.add(preRollAds[0].id); startAd(preRollAds[0], { trackImpression: false }); // Impression tracked in AdsPlayer } catch (error) { console.error('Error starting pre-roll ad:', error); } } if (!adsInitializedRef.current) { midRollAds.forEach(ad => { if (ad.time !== undefined) { addPendingMidRollAd(ad); } }); adsInitializedRef.current = true; } } else if (!hasAds && hadAds) { // Only reset when ads change from non-empty to empty isResettingRef.current = true; // Clear all ad state when ads array becomes empty adsInitializedRef.current = false; previousAdsRef.current = ''; clearPendingMidRollAds(); // Reset played ads tracking playedMidRollAdsRef.current.clear(); playedPreRollAdsRef.current.clear(); playedPostRollAdsRef.current.clear(); // If an ad is currently playing, stop it const { isAdPlaying: currentIsAdPlaying, currentAd: currentAdState, resetAdsStore } = useAdsPlayerStore.getState(); if (currentIsAdPlaying || currentAdState) { resetAdsStore(); } // Reset the flag after a short delay to allow state to settle setTimeout(() => { isResettingRef.current = false; }, 0); } else if (!hasAds) { // If ads are empty and were already empty, just update the ref previousAdsRef.current = ''; } }, [ads, currentAd, addPendingMidRollAd, clearPendingMidRollAds, startAd, activeTrack?.isTrailer]); useEffect(() => { // Don't trigger mid-roll ads if it's a trailer if (activeTrack?.isTrailer) { return; } if (!isAdPlaying && pendingMidRollAds.length > 0 && currentTime > 0 && !currentAd) { const previousTime = previousTimeRef.current; const timeDifference = Math.abs(currentTime - previousTime); const isSeeking = timeDifference > 2; // If time jumps more than 2 seconds, it's a seek // Check for ads that should be triggered let nextMidRollAd = pendingMidRollAds.find(ad => ad.time && !playedMidRollAdsRef.current.has(ad.id) && currentTime >= ad.time - 1 && currentTime <= ad.time + 1); // If seeking, check if we skipped past any ads if (!nextMidRollAd && isSeeking && previousTime < currentTime) { const skippedAd = pendingMidRollAds.find(ad => ad.time && !playedMidRollAdsRef.current.has(ad.id) && ad.time > previousTime && ad.time <= currentTime); if (skippedAd) { nextMidRollAd = skippedAd; } } if (nextMidRollAd) { try { playedMidRollAdsRef.current.add(nextMidRollAd.id); const timeBeforeAd = isSeeking ? nextMidRollAd.time || currentTime : currentTime; startAd(nextMidRollAd, { resumeTime: timeBeforeAd, trackImpression: false // Impression tracked in AdsPlayer }); const remainingAds = pendingMidRollAds.filter(ad => ad.id !== nextMidRollAd.id); clearPendingMidRollAds(); remainingAds.forEach(ad => addPendingMidRollAd(ad)); } catch (error) { console.error('Error starting mid-roll ad:', error); } } // Update previous time previousTimeRef.current = currentTime; } else if (currentTime > 0) { // Update previous time even if conditions aren't met previousTimeRef.current = currentTime; } }, [currentTime, isAdPlaying, pendingMidRollAds, currentAd, ads, addPendingMidRollAd, clearPendingMidRollAds, startAd, activeTrack?.isTrailer]); return { checkPostRollAds: () => { try { // Don't show post-roll ads if it's a trailer if (activeTrack?.isTrailer) { return false; } const postRollAds = ads.filter(ad => ad.position === 'post'); if (postRollAds.length > 0 && postRollAds[0]) { playedPostRollAdsRef.current.add(postRollAds[0].id); startAd(postRollAds[0], { trackImpression: false }); // Impression tracked in AdsPlayer return true; } return false; } catch (error) { console.error('Error checking post-roll ads:', error); return false; } } }; }; //# sourceMappingURL=useAdsManager.js.map