/** * This script hunts for video tags and initializes the correct player * depending on the platform: * - web: jwplayer * - iOS/Android: Native player * * Once jwplayer is initialized there's no follow up actions to be taken. * Mobile Native players send back information into the DOM in order to * interact and update the UI, therefore a MutationObserver is registered. */ /* eslint no-use-before-define: 0 */ /* eslint no-param-reassign: 0 */ /* eslint no-useless-escape: 0 */ /* global jwplayer, ahoy, Runtime */ function initializeVideoPlayback() { var currentTime = '0'; var deviceType = 'web'; var lastEvent = ''; function getById(name) { return document.getElementById(name); } function getParameterByName(name, url) { if (!url) url = window.location.href; name = name.replace(/[\[\]]/g, '\\$&'); var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'), results = regex.exec(url); if (!results) return null; if (!results[2]) return ''; return decodeURIComponent(results[2].replace(/\+/g, ' ')); } function timeToSeconds(hms) { var a; if (hms.length < 3) { return hms; } else if (hms.length < 6) { a = hms.split(':'); return (hms = +a[0] * 60 + +a[1]); } else { a = hms.split(':'); return (hms = +a[0] * 60 * 60 + +a[1] * 60 + +a[2]); } } function videoPlayerEvent(isPlaying) { // jwtplayer tends to send multiple 'play' actions. This check makes sure // we're not tracking repeated 'play' events for a single interaction. var eventName = isPlaying ? 'play' : 'pause'; if (lastEvent === eventName) { return; } lastEvent = eventName; var metadata = videoMetadata(getById('video-player-source')); var properties = { article: metadata.id, deviceType: deviceType, action: eventName, }; ahoy.track('Video Player Streaming', properties); } function initWebPlayer(seconds, metadata) { var waitingOnJWP = setInterval(function () { if (typeof jwplayer !== 'undefined') { clearInterval(waitingOnJWP); var playerInstance = jwplayer(`video-player-${metadata.id}`); playerInstance.setup({ file: metadata.video_source_url, mediaid: metadata.video_code, image: metadata.video_thumbnail_url, playbackRateControls: true, tracks: [ { file: metadata.video_closed_caption_track_url, label: 'English', kind: 'captions', default: false, }, ], }); if (seconds) { jwplayer().on('firstFrame', function () { jwplayer().seek(seconds); }); jwplayer().on('play', function () { videoPlayerEvent(true); }); jwplayer().on('pause', function () { videoPlayerEvent(false); }); } } }, 2); } function videoMetadata(videoSource) { try { return JSON.parse(videoSource.dataset.meta); } catch (e) { console.log('Unable to load Podcast Episode metadata', e); // eslint-disable-line no-console } } function requestFocus() { var metadata = videoMetadata(videoSource); var playerElement = getById(`video-player-${metadata.id}`); getById('pause-butt').classList.add('active'); getById('play-butt').classList.remove('active'); Runtime.videoMessage({ action: 'play', url: metadata.video_source_url, seconds: currentTime, }); videoPlayerEvent(true); } function handleVideoMessages(mutation) { if (mutation.type !== 'attributes') { return; } var message = {}; try { var messageData = getById('video-player-source').dataset.message; message = JSON.parse(messageData); } catch (e) { console.log(e); // eslint-disable-line no-console return; } switch (message.action) { case 'play': getById('pause-butt').classList.add('active'); getById('play-butt').classList.remove('active'); videoPlayerEvent(true); break; case 'pause': getById('pause-butt').classList.remove('active'); getById('play-butt').classList.add('active'); videoPlayerEvent(false); break; case 'tick': currentTime = message.currentTime; break; default: console.log('Unrecognized video message: ', message); // eslint-disable-line no-console } } function initializePlayer(videoSource) { var seconds = timeToSeconds(getParameterByName('t') || '0'); var metadata = videoMetadata(videoSource); if (Runtime.isNativeIOS('video')) { deviceType = 'iOS'; Runtime.videoMessage = function (message) { try { window.webkit.messageHandlers.video.postMessage(message); } catch (err) { console.log(err.message); // eslint-disable-line no-console } }; } else if (Runtime.isNativeAndroid('videoMessage')) { deviceType = 'Android'; Runtime.videoMessage = function (message) { try { AndroidBridge.videoMessage(JSON.stringify(message)); } catch (err) { console.log(err.message); // eslint-disable-line no-console } }; } else { // jwplayer is initialized and no further interaction is needed initWebPlayer(seconds, metadata); return; } var playerElement = getById(`video-player-${metadata.id}`); playerElement.addEventListener('click', requestFocus); playerElement.classList.add('native'); getById('play-butt').classList.add('active'); var mutationObserver = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { handleVideoMessages(mutation); }); }); mutationObserver.observe(videoSource, { attributes: true }); currentTime = `${seconds}`; } // If an video player element is found initialize it var videoSource = getById('video-player-source'); if (videoSource !== null) { initializePlayer(videoSource); } }