1(function ($) { 2 class VideoPlayerController { 3 constructor(configObject) { 4 this.currentlyActive = null; 5 this.videos = new Map(); 6 this.init(); 7 } 8 9 init() { 10 // To account for async behavior, we look for window.initializedVideos that may have been populated before VideoPlayerController could be initialized 11 let initializedVideos = window.initializedVideos ? window.initializedVideos : []; 12 initializedVideos.forEach((video) => { 13 this.registerNewVideo(video); 14 }) 15 } 16 17 registerNewVideo(video) { 18 // check if video is playing.. if so, assign it to this.currentlyActive 19 if (video?.playerWrapper?.currentStatus === 'playing' && video.playerWrapper.lastCurrentTime > 0) { 20 this.currentlyActive = video; 21 } 22 23 this.videos.set(video.videoContainerId ? video.videoContainerId : 'mini-live-player', video); 24 25 if (video.registerMiniLivePlayerNeeded) { 26 // Mini Live Player started loading for playback before Controller was ready 27 this.registerMiniLivePlayerLoading(); 28 } 29 } 30 31 resetCurrentlyActive() { 32 this.currentlyActive = null; 33 } 34 35 isVideoCurrentlyActive(videoContainerId) { 36 const videoToCheck = this.videos.get(videoContainerId); 37 const isVideoPlaying = this.currentlyActive === videoToCheck; 38 return isVideoPlaying; 39 } 40 41 registerMiniLivePlayerLoading() { 42 let miniLivePlayer = this.videos.get('mini-live-player'); 43 if (this.currentlyActive && this.currentlyActive !== miniLivePlayer && !this.currentlyActive.videoCompleted) { 44 // stop non-MLP if started before VideoController has loaded 45 this.currentlyActive.onVideoControllerStop(); 46 } 47 this.currentlyActive = miniLivePlayer; 48 } 49 50 async requestNewPlayback(videoContainerId) { 51 let videoToPlay = this.videos.get(videoContainerId); 52 if (videoContainerId == 'mini-live-player') { 53 // Playback request is for linear 54 if (this.currentlyActive && this.currentlyActive !== videoToPlay) { 55 this.currentlyActive.onVideoControllerStop(); 56 } 57 if (document.pictureInPictureElement) { 58 // Exit any open picture-in-picture players before we start playing new video 59 await document.exitPictureInPicture(); 60 } 61 videoToPlay.onVideoControllerPlay(); 62 this.currentlyActive = videoToPlay; 63 } 64 else { 65 // Playback request is for VOD 66 if (this.isVideoCurrentlyActive(videoContainerId)) { 67 // The video request is self-contained (video was paused or stopped without another video being involved). We know we aren't switching videos due to a conflict, so allow built-in VOD video event listeners to handle events normally. 68 return false; 69 } 70 else if (!this.currentlyActive) { 71 // The video request is the first video request, so we just set the video as currentlyActive. We know we aren't switching videos due to a conflict, so allow built-in VOD video event listeners to handle the events normally. 72 this.currentlyActive = videoToPlay; 73 return true; 74 } 75 76 // The video request is for a video different from what is currentlyActive in the VideoPlayerController. Use onVideoControllerStop() and onVideoControllerPlay() to override standard analytics events 77 if (this.currentlyActive && this.currentlyActive.videoCompleted !== true) { 78 // If the currentlyActive VOD video is completed, we don't need to do anything to close out its analytics lifecycle 79 if (this.currentlyActive.isTuning) { 80 // Currently active video is a still-tuning mini live player 81 // Wait for tuning to complete before firing analytics events 82 this.isWaitingToStopCurrentlyActive = true; 83 84 const stopMlpAndFireStopEvents = () => { 85 this.currentlyActive.onVideoControllerStop(); 86 const currentlyActiveStopped = new CustomEvent("currentlyActiveStopped"); 87 window.dispatchEvent(currentlyActiveStopped); 88 } 89 90 window.addEventListener("mlpTuningComplete", () => { 91 if (this.currentlyActive.awaitingPlaybackSelect) { 92 // add listener for when playbackSelect has completed 93 window.addEventListener("mlpPlaybackSelectFired", () => { 94 stopMlpAndFireStopEvents(); 95 }) 96 } else { 97 stopMlpAndFireStopEvents(); 98 } 99 }) 100 101 } else { 102 this.currentlyActive.onVideoControllerStop(); 103 } 104 105 } 106 if (document.pictureInPictureElement) { 107 // Exit any open picture-in-picture players before we start playing new video 108 await document.exitPictureInPicture(); 109 } 110 111 const playNewVideoAndFirePlayEvents = () => { 112 videoToPlay.onVideoControllerPlay(); 113 this.currentlyActive = videoToPlay; 114 // The previously playing video may have been paused already when we switched over to a new active video (leaving the Quantum Analytics state as isPlayBackPause = true). Reset Quantum analytics pause status to false to ensure the new active video handles self-contained pauses correctly. 115 News.App.QuantumAnalytics.isPlayBackPause = false;
116 // Do the same for the potentially paused previouslyActive video in Adobe Analytics 117 if (News.App.MediaAnalytics.IsPaused) { 118 News.App.MediaAnalytics.IsPaused = false; 119 News.App.MediaAnalytics.clearBufferPingInterval(); 120 News.App.MediaAnalytics.clearPausePingInterval(); 121 } 122 return true; 123 } 124 125 if (this.isWaitingToStopCurrentlyActive) { 126 // Currently active video is a still-tuning mini live player 127 // Wait for tuning to complete before playing / firing analytics events 128 window.addEventListener("currentlyActiveStopped", () => { 129 playNewVideoAndFirePlayEvents() 130 }) 131 132 } else { 133 playNewVideoAndFirePlayEvents() 134 } 135 } 136 } 137 138 unloadPage() { 139 // Handle cleanup for all instances of VOD IVP (Mini Live-Player does not have a video.videoType) 140 this.videos.forEach((video) => { 141 if (video.videoType && video.videoType.includes('vod') && video.userProfileSwitch) { 142 let vodwatchtime = video.watchedTime ? video.watchedTime : 0; 143 video.vodMutationCall(video.vodDuration, Math.round(vodwatchtime)); 144 clearInterval(video.intervalForLastPlayTime); 145 } 146 }); 147 } 148 } 149 150 $(document).ready(function () { 151 let configObject = {}; 152 ns('News').VideoPlayerController = new VideoPlayerController(configObject); 153 154 $(window).off("beforeunload", News.VideoPlayerController.unloadPage); 155 156 $(window).on("beforeunload", function () { 157 News.VideoPlayerController.unloadPage(); 158 }); 159 }); 160 161 162 163 $(window).on("load", function () { 164 165 }) 166})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.