UNPKG

videojs-contrib-ads

Version:

A framework that provides common functionality needed by video advertisement libraries working with video.js.

229 lines (191 loc) 7.4 kB
'use strict'; exports.__esModule = true; exports.getPlayerSnapshot = getPlayerSnapshot; exports.restorePlayerSnapshot = restorePlayerSnapshot; var _window = require('global/window'); var _window2 = _interopRequireDefault(_window); var _video = require('video.js'); var _video2 = _interopRequireDefault(_video); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } /** * Returns an object that captures the portions of player state relevant to * video playback. The result of this function can be passed to * restorePlayerSnapshot with a player to return the player to the state it * was in when this function was invoked. * @param {Object} player The videojs player object */ /* The snapshot feature is responsible for saving the player state before an ad, then restoring the player state after an ad. */ function getPlayerSnapshot(player) { var currentTime = void 0; if (_video2['default'].browser.IS_IOS && player.ads.isLive(player)) { // Record how far behind live we are if (player.seekable().length > 0) { currentTime = player.currentTime() - player.seekable().end(0); } else { currentTime = player.currentTime(); } } else { currentTime = player.currentTime(); } var tech = player.$('.vjs-tech'); var remoteTracks = player.remoteTextTracks ? player.remoteTextTracks() : []; var tracks = player.textTracks ? player.textTracks() : []; var suppressedRemoteTracks = []; var suppressedTracks = []; var snapshotObject = { ended: player.ended(), currentSrc: player.currentSrc(), src: player.tech_.src(), currentTime: currentTime, type: player.currentType() }; if (tech) { snapshotObject.nativePoster = tech.poster; snapshotObject.style = tech.getAttribute('style'); } for (var i = 0; i < remoteTracks.length; i++) { var track = remoteTracks[i]; suppressedRemoteTracks.push({ track: track, mode: track.mode }); track.mode = 'disabled'; } snapshotObject.suppressedRemoteTracks = suppressedRemoteTracks; for (var _i = 0; _i < tracks.length; _i++) { var _track = tracks[_i]; suppressedTracks.push({ track: _track, mode: _track.mode }); _track.mode = 'disabled'; } snapshotObject.suppressedTracks = suppressedTracks; return snapshotObject; } /** * Attempts to modify the specified player so that its state is equivalent to * the state of the snapshot. * @param {Object} player - the videojs player object * @param {Object} snapshotObject - the player state to apply */ function restorePlayerSnapshot(player, snapshotObject) { if (player.ads.disableNextSnapshotRestore === true) { player.ads.disableNextSnapshotRestore = false; return; } // The playback tech var tech = player.$('.vjs-tech'); // the number of[ remaining attempts to restore the snapshot var attempts = 20; var suppressedRemoteTracks = snapshotObject.suppressedRemoteTracks; var suppressedTracks = snapshotObject.suppressedTracks; var trackSnapshot = void 0; var restoreTracks = function restoreTracks() { for (var i = 0; i < suppressedRemoteTracks.length; i++) { trackSnapshot = suppressedRemoteTracks[i]; trackSnapshot.track.mode = trackSnapshot.mode; } for (var _i2 = 0; _i2 < suppressedTracks.length; _i2++) { trackSnapshot = suppressedTracks[_i2]; trackSnapshot.track.mode = trackSnapshot.mode; } }; // finish restoring the playback state var resume = function resume() { var currentTime = void 0; if (_video2['default'].browser.IS_IOS && player.ads.isLive(player)) { if (snapshotObject.currentTime < 0) { // Playback was behind real time, so seek backwards to match if (player.seekable().length > 0) { currentTime = player.seekable().end(0) + snapshotObject.currentTime; } else { currentTime = player.currentTime(); } player.currentTime(currentTime); } } else if (snapshotObject.ended) { player.currentTime(player.duration()); } else { player.currentTime(snapshotObject.currentTime); } // Resume playback if this wasn't a postroll if (!snapshotObject.ended) { player.play(); } }; // determine if the video element has loaded enough of the snapshot source // to be ready to apply the rest of the state var tryToResume = function tryToResume() { // tryToResume can either have been called through the `contentcanplay` // event or fired through setTimeout. // When tryToResume is called, we should make sure to clear out the other // way it could've been called by removing the listener and clearing out // the timeout. player.off('contentcanplay', tryToResume); if (player.ads.tryToResumeTimeout_) { player.clearTimeout(player.ads.tryToResumeTimeout_); player.ads.tryToResumeTimeout_ = null; } // Tech may have changed depending on the differences in sources of the // original video and that of the ad tech = player.el().querySelector('.vjs-tech'); if (tech.readyState > 1) { // some browsers and media aren't "seekable". // readyState greater than 1 allows for seeking without exceptions return resume(); } if (tech.seekable === undefined) { // if the tech doesn't expose the seekable time ranges, try to // resume playback immediately return resume(); } if (tech.seekable.length > 0) { // if some period of the video is seekable, resume playback return resume(); } // delay a bit and then check again unless we're out of attempts if (attempts--) { _window2['default'].setTimeout(tryToResume, 50); } else { try { resume(); } catch (e) { _video2['default'].log.warn('Failed to resume the content after an advertisement', e); } } }; if (snapshotObject.nativePoster) { tech.poster = snapshotObject.nativePoster; } if ('style' in snapshotObject) { // overwrite all css style properties to restore state precisely tech.setAttribute('style', snapshotObject.style || ''); } // Determine whether the player needs to be restored to its state // before ad playback began. With a custom ad display or burned-in // ads, the content player state hasn't been modified and so no // restoration is required if (player.ads.videoElementRecycled()) { // on ios7, fiddling with textTracks too early will cause safari to crash player.one('contentloadedmetadata', restoreTracks); // if the src changed for ad playback, reset it player.src({ src: snapshotObject.currentSrc, type: snapshotObject.type }); // safari requires a call to `load` to pick up a changed source player.load(); // and then resume from the snapshots time once the original src has loaded // in some browsers (firefox) `canplay` may not fire correctly. // Reace the `canplay` event with a timeout. player.one('contentcanplay', tryToResume); player.ads.tryToResumeTimeout_ = player.setTimeout(tryToResume, 2000); } else if (!player.ended() || !snapshotObject.ended) { // if we didn't change the src, just restore the tracks restoreTracks(); // the src didn't change and this wasn't a postroll // just resume playback at the current time. player.play(); } }