cloudinary-video-player
Version:
Cloudinary Video Player
1,228 lines (1,127 loc) • 231 kB
JavaScript
"use strict";
(self["cloudinaryVideoPlayerChunkLoading"] = self["cloudinaryVideoPlayerChunkLoading"] || []).push([["ima"],{
/***/ "./plugins/ima/ima.js":
/*!****************************!*\
!*** ./plugins/ima/ima.js ***!
\****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var videojs_contrib_ads__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! videojs-contrib-ads */ "../node_modules/videojs-contrib-ads/dist/videojs-contrib-ads.es.js");
/* harmony import */ var videojs_ima__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! videojs-ima */ "../node_modules/videojs-ima/dist/videojs.ima.es.js");
/* harmony import */ var videojs_ima_dist_videojs_ima_scss__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! videojs-ima/dist/videojs.ima.scss */ "../node_modules/videojs-ima/dist/videojs.ima.scss");
/***/ }),
/***/ "../node_modules/videojs-ima/dist/videojs.ima.scss":
/*!*********************************************************!*\
!*** ../node_modules/videojs-ima/dist/videojs.ima.scss ***!
\*********************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
// extracted by mini-css-extract-plugin
/***/ }),
/***/ "../node_modules/videojs-contrib-ads/dist/videojs-contrib-ads.es.js":
/*!**************************************************************************!*\
!*** ../node_modules/videojs-contrib-ads/dist/videojs-contrib-ads.es.js ***!
\**************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ "../node_modules/video.js/dist/video.es-exposed.js");
/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var global_window__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! global/window */ "../node_modules/global/window.js");
/* harmony import */ var global_window__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(global_window__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var global_document__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! global/document */ "../node_modules/global/document.js");
/* harmony import */ var global_document__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(global_document__WEBPACK_IMPORTED_MODULE_2__);
/*! @name videojs-contrib-ads @version 7.5.2 @license Apache-2.0 */
var version = "7.5.2";
/*
* Implements the public API available in `player.ads` as well as application state.
*/
function getAds(player) {
return {
disableNextSnapshotRestore: false,
// This is true if we have finished actual content playback but haven't
// dealt with postrolls and officially ended yet
_contentEnding: false,
// This is set to true if the content has officially ended at least once.
// After that, the user can seek backwards and replay content, but _contentHasEnded
// remains true.
_contentHasEnded: false,
// Tracks if loadstart has happened yet for the initial source. It is not reset
// on source changes because loadstart is the event that signals to the ad plugin
// that the source has changed. Therefore, no special signaling is needed to know
// that there has been one for subsequent sources.
_hasThereBeenALoadStartDuringPlayerLife: false,
// Tracks if loadeddata has happened yet for the current source.
_hasThereBeenALoadedData: false,
// Tracks if loadedmetadata has happened yet for the current source.
_hasThereBeenALoadedMetaData: false,
// Are we after startLinearAdMode and before endLinearAdMode?
_inLinearAdMode: false,
// Should we block calls to play on the content player?
_shouldBlockPlay: false,
// Was play blocked by the plugin's playMiddleware feature?
_playBlocked: false,
// Tracks whether play has been requested for this source,
// either by the play method or user interaction
_playRequested: false,
// Contains error information when an error occurs in contrib-ads.
// When set, will contain an object with a type and metadata.
_error: null,
// This is an estimation of the current ad type being played
// This is experimental currently. Do not rely on its presence or behavior!
adType: null,
VERSION: version,
reset: function reset() {
player.ads.disableNextSnapshotRestore = false;
player.ads._contentEnding = false;
player.ads._contentHasEnded = false;
player.ads.snapshot = null;
player.ads.adType = null;
player.ads._hasThereBeenALoadedData = false;
player.ads._hasThereBeenALoadedMetaData = false;
player.ads._cancelledPlay = false;
player.ads._shouldBlockPlay = false;
player.ads._playBlocked = false;
player.ads.nopreroll_ = false;
player.ads.nopostroll_ = false;
player.ads._playRequested = false;
player.ads._error = null;
},
// Call this when an ad response has been received and there are
// linear ads ready to be played.
startLinearAdMode: function startLinearAdMode() {
player.ads._state.startLinearAdMode();
},
// Call this when a linear ad pod has finished playing.
endLinearAdMode: function endLinearAdMode() {
player.ads._state.endLinearAdMode();
},
// Call this when an ad response has been received but there are no
// linear ads to be played (i.e. no ads available, or overlays).
// This has no effect if we are already in an ad break. Always
// use endLinearAdMode() to exit from linear ad-playback state.
skipLinearAdMode: function skipLinearAdMode() {
player.ads._state.skipLinearAdMode();
},
// With no arguments, returns a boolean value indicating whether or not
// contrib-ads is set to treat ads as stitched with content in a single
// stream. With arguments, treated as a setter, but this behavior is
// deprecated.
stitchedAds: function stitchedAds(arg) {
if (arg !== undefined) {
video_js__WEBPACK_IMPORTED_MODULE_0___default().log.warn('Using player.ads.stitchedAds() as a setter is deprecated, ' + 'it should be set as an option upon initialization of contrib-ads.');
// Keep the private property and the settings in sync. When this
// setter is removed, we can probably stop using the private property.
this.settings.stitchedAds = !!arg;
}
return this.settings.stitchedAds;
},
// Returns whether the video element has been modified since the
// snapshot was taken.
// We test both src and currentSrc because changing the src attribute to a URL that
// AdBlocker is intercepting doesn't update currentSrc.
videoElementRecycled: function videoElementRecycled() {
if (player.ads.shouldPlayContentBehindAd(player)) {
return false;
}
if (!this.snapshot) {
throw new Error('You cannot use videoElementRecycled while there is no snapshot.');
}
var srcChanged = player.tech_.src() !== this.snapshot.src;
var currentSrcChanged = player.currentSrc() !== this.snapshot.currentSrc;
return srcChanged || currentSrcChanged;
},
// Returns a boolean indicating if given player is in live mode.
// One reason for this: https://github.com/videojs/video.js/issues/3262
// Also, some live content can have a duration.
isLive: function isLive(somePlayer) {
if (somePlayer === void 0) {
somePlayer = player;
}
if (typeof somePlayer.ads.settings.contentIsLive === 'boolean') {
return somePlayer.ads.settings.contentIsLive;
} else if (somePlayer.duration() === Infinity) {
return true;
} else if ((video_js__WEBPACK_IMPORTED_MODULE_0___default().browser).IOS_VERSION === '8' && somePlayer.duration() === 0) {
return true;
}
return false;
},
// Return true if content playback should mute and continue during ad breaks.
// This is only done during live streams on platforms where it's supported.
// This improves speed and accuracy when returning from an ad break.
shouldPlayContentBehindAd: function shouldPlayContentBehindAd(somePlayer) {
if (somePlayer === void 0) {
somePlayer = player;
}
if (!somePlayer) {
throw new Error('shouldPlayContentBehindAd requires a player as a param');
} else if (!somePlayer.ads.settings.liveCuePoints) {
return false;
} else {
return !(video_js__WEBPACK_IMPORTED_MODULE_0___default().browser).IS_IOS && !(video_js__WEBPACK_IMPORTED_MODULE_0___default().browser).IS_ANDROID && somePlayer.duration() === Infinity;
}
},
// Return true if the ads plugin should save and restore snapshots of the
// player state when moving into and out of ad mode.
shouldTakeSnapshots: function shouldTakeSnapshots(somePlayer) {
if (somePlayer === void 0) {
somePlayer = player;
}
return !this.shouldPlayContentBehindAd(somePlayer) && !this.stitchedAds();
},
// Returns true if player is in ad mode.
//
// Ad mode definition:
// If content playback is blocked by the ad plugin.
//
// Examples of ad mode:
//
// * Waiting to find out if an ad is going to play while content would normally be
// playing.
// * Waiting for an ad to start playing while content would normally be playing.
// * An ad is playing (even if content is also playing)
// * An ad has completed and content is about to resume, but content has not resumed
// yet.
//
// Examples of not ad mode:
//
// * Content playback has not been requested
// * Content playback is paused
// * An asynchronous ad request is ongoing while content is playing
// * A non-linear ad is active
isInAdMode: function isInAdMode() {
return this._state.isAdState();
},
// Returns true if in ad mode but an ad break hasn't started yet.
isWaitingForAdBreak: function isWaitingForAdBreak() {
return this._state.isWaitingForAdBreak();
},
// Returns true if content is resuming after an ad. This is part of ad mode.
isContentResuming: function isContentResuming() {
return this._state.isContentResuming();
},
// Deprecated because the name was misleading. Use inAdBreak instead.
isAdPlaying: function isAdPlaying() {
return this._state.inAdBreak();
},
// Returns true if an ad break is ongoing. This is part of ad mode.
// An ad break is the time between startLinearAdMode and endLinearAdMode.
inAdBreak: function inAdBreak() {
return this._state.inAdBreak();
},
/*
* Remove the poster attribute from the video element tech, if present. When
* reusing a video element for multiple videos, the poster image will briefly
* reappear while the new source loads. Removing the attribute ahead of time
* prevents the poster from showing up between videos.
*
* @param {Object} player The videojs player object
*/
removeNativePoster: function removeNativePoster() {
var tech = player.$('.vjs-tech');
if (tech) {
tech.removeAttribute('poster');
}
},
debug: function debug() {
if (this.settings.debug) {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
if (args.length === 1 && typeof args[0] === 'string') {
video_js__WEBPACK_IMPORTED_MODULE_0___default().log('ADS: ' + args[0]);
} else {
video_js__WEBPACK_IMPORTED_MODULE_0___default().log.apply((video_js__WEBPACK_IMPORTED_MODULE_0___default()), ['ADS:'].concat(args));
}
}
},
/**
* Set or get the current ads error.
*
* @fires Player#vjsadserror
*
* @param {import('video.js/dist/types/media-error').ErrorMetadata|null} [err]
* The error to be set. This can either be a string
* of the error type, or it can be an object containing the
* type, along with error metadata.
* If nothing is passed in, this function will return the current error.
* @param {string} err.errorType The error type.
*
* @return {Object|null|undefined}
* The current ads error. The function will return undefined if the function
* is used to set an error. It will return null if there is no error.
*/
error: function error(err) {
// If `err` doesn't exist, return the current error.
if (err === undefined) {
return this._error || null;
}
// If `err` is null or not a valid error, reset the ads error.
if (err === null || !err.errorType) {
this._error = null;
return;
}
this._error = err;
video_js__WEBPACK_IMPORTED_MODULE_0___default().log.error("An error with Ads occured. Type: " + err.errorType + ".");
/**
* @event Player#vjsadserror
* @type {Event}
*/
player.trigger({
type: 'vjsadserror',
error: this._error
});
}
};
}
/*
The goal of this feature is to make player events work as an integrator would
expect despite the presense of ads. For example, an integrator would expect
an `ended` event to happen once the content is ended. If an `ended` event is sent
as a result of a preroll ending, that is a bug. The `redispatch` method should recognize
such `ended` events and prefix them so they are sent as `adended`, and so on with
all other player events.
*/
// Cancel an event.
// Video.js wraps native events. This technique stops propagation for the Video.js event
// (AKA player event or wrapper event) while native events continue propagating.
var cancelEvent = function cancelEvent(player, event) {
event.isImmediatePropagationStopped = function () {
return true;
};
event.cancelBubble = true;
event.isPropagationStopped = function () {
return true;
};
};
// Redispatch an event with a prefix.
// Cancels the event, then sends a new event with the type of the original
// event with the given prefix added.
// The inclusion of the "state" property should be removed in a future
// major version update with instructions to migrate any code that relies on it.
// It is an implementation detail and relying on it creates fragility.
var prefixEvent = function prefixEvent(player, prefix, event) {
cancelEvent(player, event);
player.trigger({
type: prefix + event.type,
originalEvent: event
});
};
// Playing event
// Requirements:
// * Normal playing event when there is no preroll
// * No playing event before preroll
// * At least one playing event after preroll
var handlePlaying = function handlePlaying(player, event) {
if (player.ads.isInAdMode()) {
if (player.ads.isContentResuming()) {
// Prefix playing event when switching back to content after postroll.
if (player.ads._contentEnding) {
prefixEvent(player, 'content', event);
}
// Prefix all other playing events during ads.
} else {
prefixEvent(player, 'ad', event);
}
}
};
// Ended event
// Requirements:
// * A single ended event when there is no postroll
// * No ended event before postroll
// * A single ended event after postroll
var handleEnded = function handleEnded(player, event) {
if (player.ads.isInAdMode()) {
// Cancel ended events during content resuming. Normally we would
// prefix them, but `contentended` has a special meaning. In the
// future we'd like to rename the existing `contentended` to
// `readyforpostroll`, then we could remove the special `resumeended`
// and do a conventional content prefix here.
if (player.ads.isContentResuming()) {
cancelEvent(player, event);
// Important: do not use this event outside of videojs-contrib-ads.
// It will be removed and your code will break.
// Ideally this would simply be `contentended`, but until
// `contentended` no longer has a special meaning it cannot be
// changed.
player.trigger('resumeended');
// Ad prefix in ad mode
} else {
prefixEvent(player, 'ad', event);
}
// Prefix ended due to content ending before postroll check
} else if (!player.ads._contentHasEnded && !player.ads.stitchedAds()) {
// This will change to cancelEvent after the contentended deprecation
// period (contrib-ads 7)
prefixEvent(player, 'content', event);
// Content ended for the first time, time to check for postrolls
player.trigger('readyforpostroll');
}
};
// handleLoadEvent is used for loadstart, loadeddata, and loadedmetadata
// Requirements:
// * Initial event is not prefixed
// * Event due to ad loading is prefixed
// * Event due to content source change is not prefixed
// * Event due to content resuming is prefixed
var handleLoadEvent = function handleLoadEvent(player, event) {
// Initial event
if (event.type === 'loadstart' && !player.ads._hasThereBeenALoadStartDuringPlayerLife || event.type === 'loadeddata' && !player.ads._hasThereBeenALoadedData || event.type === 'loadedmetadata' && !player.ads._hasThereBeenALoadedMetaData) {
return;
// Ad playing
} else if (player.ads.inAdBreak()) {
prefixEvent(player, 'ad', event);
// Source change
} else if (player.currentSrc() !== player.ads.contentSrc) {
return;
// Content resuming
} else {
prefixEvent(player, 'content', event);
}
};
// Play event
// Requirements:
// * Play events have the "ad" prefix when an ad is playing
// * Play events have the "content" prefix when content is resuming
// Play requests are unique because they represent user intention to play. They happen
// because the user clicked play, or someone called player.play(), etc. It could happen
// multiple times during ad loading, regardless of where we are in the process. With our
// current architecture, this could cause the content to start playing.
// Therefore, contrib-ads must always either:
// - cancelContentPlay if there is any possible chance the play caused the
// content to start playing, even if we are technically in ad mode. In order for
// that to happen, play events need to be unprefixed until the last possible moment.
// - use playMiddleware to stop the play from reaching the Tech so there is no risk
// of the content starting to play.
// Currently, playMiddleware is only supported on desktop browsers with
// video.js after version 6.7.1.
var handlePlay = function handlePlay(player, event) {
if (player.ads.inAdBreak()) {
prefixEvent(player, 'ad', event);
// Content resuming
} else if (player.ads.isContentResuming()) {
prefixEvent(player, 'content', event);
}
};
// Handle a player event, either by redispatching it with a prefix, or by
// letting it go on its way without any meddling.
function redispatch(event) {
// Events with special treatment
if (event.type === 'playing') {
handlePlaying(this, event);
} else if (event.type === 'ended') {
handleEnded(this, event);
} else if (event.type === 'loadstart' || event.type === 'loadeddata' || event.type === 'loadedmetadata') {
handleLoadEvent(this, event);
} else if (event.type === 'play') {
handlePlay(this, event);
// Standard handling for all other events
} else if (this.ads.isInAdMode()) {
if (this.ads.isContentResuming()) {
// Event came from snapshot restore after an ad, use "content" prefix
prefixEvent(this, 'content', event);
} else {
// Event came from ad playback, use "ad" prefix
prefixEvent(this, 'ad', event);
}
}
}
/*
This feature sends a `contentupdate` event when the player source changes.
*/
// Start sending contentupdate events
function initializeContentupdate(player) {
// Keep track of the current content source
// If you want to change the src of the video without triggering
// the ad workflow to restart, you can update this variable before
// modifying the player's source
player.ads.contentSrc = player.currentSrc();
player.ads._seenInitialLoadstart = false;
// Check if a new src has been set, if so, trigger contentupdate
var checkSrc = function checkSrc() {
if (!player.ads.inAdBreak()) {
var src = player.currentSrc();
if (src !== player.ads.contentSrc) {
if (player.ads._seenInitialLoadstart) {
player.trigger({
type: 'contentchanged'
});
}
player.trigger({
type: 'contentupdate',
oldValue: player.ads.contentSrc,
newValue: src
});
player.ads.contentSrc = src;
}
player.ads._seenInitialLoadstart = true;
}
};
// loadstart reliably indicates a new src has been set
player.on('loadstart', checkSrc);
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
/**
* Current tcfData returned from CMP
* Updated on event listener rather than having to make an asyc
* check within the macro resolver
*/
var tcData = {};
/**
* Sets up a proxy for the TCF API in an iframed player, if a parent frame
* that has implemented the TCF API is detected
* https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#is-there-a-sample-iframe-script-call-to-the-cmp-api
*/
var proxyTcfApi = function proxyTcfApi(_) {
if (video_js__WEBPACK_IMPORTED_MODULE_0___default().dom.isInFrame() && typeof (global_window__WEBPACK_IMPORTED_MODULE_1___default().__tcfapi) !== 'function') {
var frame = (global_window__WEBPACK_IMPORTED_MODULE_1___default());
var cmpFrame;
var cmpCallbacks = {};
while (frame) {
try {
if (frame.frames.__tcfapiLocator) {
cmpFrame = frame;
break;
}
} catch (ignore) {
// empty
}
if (frame === (global_window__WEBPACK_IMPORTED_MODULE_1___default().top)) {
break;
}
frame = frame.parent;
}
if (!cmpFrame) {
return;
}
(global_window__WEBPACK_IMPORTED_MODULE_1___default().__tcfapi) = function (cmd, version, callback, arg) {
var callId = Math.random() + '';
var msg = {
__tcfapiCall: {
command: cmd,
parameter: arg,
version: version,
callId: callId
}
};
cmpCallbacks[callId] = callback;
cmpFrame.postMessage(msg, '*');
};
global_window__WEBPACK_IMPORTED_MODULE_1___default().addEventListener('message', function (event) {
var json = {};
try {
json = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
} catch (ignore) {
// empty
}
var payload = json.__tcfapiReturn;
if (payload) {
if (typeof cmpCallbacks[payload.callId] === 'function') {
cmpCallbacks[payload.callId](payload.returnValue, payload.success);
cmpCallbacks[payload.callId] = null;
}
}
}, false);
}
};
/**
* Sets up event listener for changes to consent data.
*/
var listenToTcf = function listenToTcf() {
proxyTcfApi();
if (typeof (global_window__WEBPACK_IMPORTED_MODULE_1___default().__tcfapi) === 'function') {
global_window__WEBPACK_IMPORTED_MODULE_1___default().__tcfapi('addEventListener', 2, function (data, success) {
if (success) {
tcData = data;
}
});
}
};
var findUspApiLocatorWindow = function findUspApiLocatorWindow(windowObj) {
var targetWindow = windowObj.parent;
while (targetWindow !== windowObj.top) {
try {
if (targetWindow.frames && targetWindow.frames.__uspapiLocator) {
return targetWindow;
}
} catch (ignore) {
// do nothing
}
targetWindow = targetWindow.parent;
}
// Check for the __uspapiLocator frame in the top window
try {
if (windowObj.top.frames && windowObj.top.frames.__uspapiLocator) {
return windowObj.top;
}
} catch (ignore) {
// do nothing
}
// Return null if no __uspapiLocator frame is found in any window
return null;
};
var uspString = '';
var getCurrentUspString = function getCurrentUspString() {
return uspString;
};
// Call the USP API to get the US Privacy String, either by invoking it directly or via postMessage() if inside an iframe.
// In the former case the callback is synchronous, if the latter it is asynchronous, so to be safe it should always be
// assumed to be asynchronous.
// The window is passable as an argument for ease of testing
var obtainUsPrivacyString = function obtainUsPrivacyString(callback, windowObj) {
if (windowObj === void 0) {
windowObj = (global_window__WEBPACK_IMPORTED_MODULE_1___default());
}
if (windowObj.__uspapi) {
windowObj.__uspapi('getUSPData', 1, function (uspData, success) {
var privacyString = success ? uspData.uspString : null;
uspString = privacyString;
callback(privacyString);
});
} else {
var targetWindow = findUspApiLocatorWindow(windowObj);
// If no __uspapiLocator frame is found, execute the callback with a null privacy string
if (!targetWindow) {
callback(null);
return;
}
var uniqueId = Math.random().toString(36).substring(2);
var message = {
__uspapiCall: {
command: 'getUSPData',
version: 1,
callId: uniqueId
}
};
var handleMessageEvent = function handleMessageEvent(event) {
if (event && event.data && event.data.__uspapiReturn && event.data.__uspapiReturn.callId === uniqueId) {
windowObj.removeEventListener('message', handleMessageEvent, false);
var _event$data$__uspapiR = event.data.__uspapiReturn,
returnValue = _event$data$__uspapiR.returnValue,
success = _event$data$__uspapiR.success;
var privacyString = success ? returnValue.uspString : null;
uspString = privacyString;
callback(privacyString);
}
};
windowObj.addEventListener('message', handleMessageEvent, false);
targetWindow.postMessage(message, '*');
}
};
var Error$1 = {
AdsBeforePrerollError: 'ads-before-preroll-error',
AdsPrerollError: 'ads-preroll-error',
AdsMidrollError: 'ads-midroll-error',
AdsPostrollError: 'ads-postroll-error',
AdsMacroReplacementFailed: 'ads-macro-replacement-failed',
AdsResumeContentFailed: 'ads-resume-content-failed'
};
var uriEncodeIfNeeded = function uriEncodeIfNeeded(value, uriEncode) {
return uriEncode ? encodeURIComponent(value) : value;
};
// Add custom field macros to macros object
// based on given name for custom fields property of mediainfo object.
var customFields = function customFields(mediainfo, macros, customFieldsName) {
if (mediainfo && mediainfo[customFieldsName]) {
var fields = mediainfo[customFieldsName];
var fieldNames = Object.keys(fields);
for (var i = 0; i < fieldNames.length; i++) {
var tag = '{mediainfo.' + customFieldsName + '.' + fieldNames[i] + '}';
macros[tag] = fields[fieldNames[i]];
}
}
};
var getMediaInfoMacros = function getMediaInfoMacros(mediainfo, defaults) {
var macros = {};
['description', 'tags', 'reference_id', 'ad_keys'].forEach(function (prop) {
if (mediainfo && mediainfo[prop]) {
macros["{mediainfo." + prop + "}"] = mediainfo[prop];
} else if (defaults["{mediainfo." + prop + "}"]) {
macros["{mediainfo." + prop + "}"] = defaults["{mediainfo." + prop + "}"];
} else {
macros["{mediainfo." + prop + "}"] = '';
}
});
['custom_fields', 'customFields'].forEach(function (customFieldProp) {
customFields(mediainfo, macros, customFieldProp);
});
return macros;
};
var getDefaultValues = function getDefaultValues(string) {
var defaults = {};
var modifiedString = string.replace(/{([^}=]+)=([^}]*)}/g, function (match, name, defaultVal) {
defaults["{" + name + "}"] = defaultVal;
return "{" + name + "}";
});
return {
defaults: defaults,
modifiedString: modifiedString
};
};
var getStaticMacros = function getStaticMacros(player) {
return {
'{player.id}': player.options_['data-player'] || player.id_,
'{player.height}': player.currentHeight(),
'{player.width}': player.currentWidth(),
'{player.heightInt}': Math.round(player.currentHeight()),
'{player.widthInt}': Math.round(player.currentWidth()),
'{player.autoplay}': player.autoplay() ? 1 : 0,
'{player.muted}': player.muted() ? 1 : 0,
'{player.language}': player.language() || '',
'{mediainfo.id}': player.mediainfo ? player.mediainfo.id : '',
'{mediainfo.name}': player.mediainfo ? player.mediainfo.name : '',
'{mediainfo.duration}': player.mediainfo ? player.mediainfo.duration : '',
'{player.duration}': player.duration(),
'{player.durationInt}': Math.round(player.duration()),
'{player.live}': player.duration() === Infinity ? 1 : 0,
'{player.pageUrl}': video_js__WEBPACK_IMPORTED_MODULE_0___default().dom.isInFrame() ? (global_document__WEBPACK_IMPORTED_MODULE_2___default().referrer) : (global_window__WEBPACK_IMPORTED_MODULE_1___default().location).href,
'{playlistinfo.id}': player.playlistinfo ? player.playlistinfo.id : '',
'{playlistinfo.name}': player.playlistinfo ? player.playlistinfo.name : '',
'{timestamp}': new Date().getTime(),
'{document.referrer}': (global_document__WEBPACK_IMPORTED_MODULE_2___default().referrer),
'{window.location.href}': (global_window__WEBPACK_IMPORTED_MODULE_1___default().location).href,
'{random}': Math.floor(Math.random() * 1000000000000)
};
};
var getTcfMacros = function getTcfMacros(tcDataObj) {
var tcfMacros = {};
Object.keys(tcDataObj).forEach(function (key) {
tcfMacros["{tcf." + key + "}"] = tcDataObj[key];
});
tcfMacros['{tcf.gdprAppliesInt}'] = tcDataObj.gdprApplies ? 1 : 0;
return tcfMacros;
};
var getUspMacros = function getUspMacros() {
return {
'{usp.uspString}': getCurrentUspString()
};
};
// This extracts and evaluates variables from the `window` object for macro replacement. While replaceMacros() handles generic macro name
// overriding for other macro types, this function also needs to reference the overrides in order to map custom macro names in the string
// to their corresponding default pageVariable names, so they can be evaluated on the `window` and stored for later replacement in replaceMacros().
var getPageVariableMacros = function getPageVariableMacros(string, defaults, macroNameOverrides) {
var pageVarRegex = new RegExp('{pageVariable\\.([^}]+)}', 'g');
var pageVariablesMacros = {};
// Aggregate any default pageVariable macros found in the string with any pageVariable macros that have custom names specified in
// macroNameOverrides.
var pageVariables = (string.match(pageVarRegex) || []).concat(Object.keys(macroNameOverrides).filter(function (macroName) {
return pageVarRegex.test(macroName) && string.includes(macroNameOverrides[macroName]);
}));
if (!pageVariables) {
return;
}
pageVariables.forEach(function (pageVar) {
var key = pageVar;
var name = pageVar.slice(14, -1);
var names = name.split('.');
var context = (global_window__WEBPACK_IMPORTED_MODULE_1___default());
var value;
// Iterate down multiple levels of selector without using eval
// This makes things like pageVariable.foo.bar work
for (var i = 0; i < names.length; i++) {
if (i === names.length - 1) {
value = context[names[i]];
} else {
context = context[names[i]];
if (typeof context === 'undefined') {
break;
}
}
}
var type = typeof value;
// Only allow certain types of values. Anything else is probably a mistake.
if (value === null) {
pageVariablesMacros[key] = 'null';
} else if (value === undefined) {
if (defaults[key]) {
pageVariablesMacros[key] = defaults[key];
} else {
video_js__WEBPACK_IMPORTED_MODULE_0___default().log.warn("Page variable \"" + name + "\" not found");
pageVariablesMacros[key] = '';
}
} else if (type !== 'string' && type !== 'number' && type !== 'boolean') {
video_js__WEBPACK_IMPORTED_MODULE_0___default().log.warn("Page variable \"" + name + "\" is not a supported type");
pageVariablesMacros[key] = '';
} else {
pageVariablesMacros[key] = value;
}
});
return pageVariablesMacros;
};
var replaceMacros = function replaceMacros(string, macros, uriEncode, overrides, player) {
if (overrides === void 0) {
overrides = {};
}
for (var macroName in macros) {
// The resolvedMacroName is the macro as it is expected to appear in the actual string, or regex if it has been provided.
var resolvedMacroName = overrides.hasOwnProperty(macroName) ? overrides[macroName] : macroName;
if (resolvedMacroName.startsWith('r:')) {
try {
var regex = new RegExp(resolvedMacroName.slice(2), 'g');
string = string.replace(regex, uriEncodeIfNeeded(macros[macroName], uriEncode));
} catch (error) {
player.ads.error({
errorType: Error$1.AdsMacroReplacementFailed,
macro: macroName,
error: error
});
video_js__WEBPACK_IMPORTED_MODULE_0___default().log.warn("Unable to replace macro with regex \"" + resolvedMacroName + "\". The provided regex may be invalid.");
}
} else {
string = string.split(resolvedMacroName).join(uriEncodeIfNeeded(macros[macroName], uriEncode));
}
}
return string;
};
/**
*
* @param {string} string
* Any string with macros to be replaced
* @param {boolean} uriEncode
* A Boolean value indicating whether the macros should be replaced with URI-encoded values
* @param {object} customMacros
* An object with custom macros and values to map them to. For example: {'{five}': 5}
* @param {boolean} customMacros.disableDefaultMacros
* A boolean indicating whether replacement of default macros should be forgone in favor of only customMacros
* @param {object} customMacros.macroNameOverrides
* An object that specifies custom names for default macros, following the following format:
* // {'{default-macro-name}': '{new-macro-name}'}
* {'{player.id}': '{{PLAYER_ID}}', ...}
* @returns {string}
* The provided string with all macros replaced. For example: adMacroReplacement('{player.id}') returns a string of the player id
*/
function adMacroReplacement(string, uriEncode, customMacros) {
if (uriEncode === void 0) {
uriEncode = false;
}
if (customMacros === void 0) {
customMacros = {};
}
var disableDefaultMacros = customMacros.disableDefaultMacros || false;
var macroNameOverrides = customMacros.macroNameOverrides || {};
// Remove special properties from customMacros
delete customMacros.disableDefaultMacros;
delete customMacros.macroNameOverrides;
var macros = customMacros;
if (disableDefaultMacros) {
return replaceMacros(string, macros, uriEncode, macroNameOverrides);
}
// Get macros with defaults e.g. {x=y}, store the values in `defaults` and replace with standard macros in the string
var _getDefaultValues = getDefaultValues(string),
defaults = _getDefaultValues.defaults,
modifiedString = _getDefaultValues.modifiedString;
string = modifiedString;
// Get all macro values
_extends(macros, getStaticMacros(this), getMediaInfoMacros(this.mediainfo, defaults), getTcfMacros(tcData), getUspMacros(), getPageVariableMacros(string, defaults, macroNameOverrides));
// Perform macro replacement
string = replaceMacros(string, macros, uriEncode, macroNameOverrides, this);
// Replace any remaining default values that have not already been replaced. This includes mediainfo custom fields.
for (var macro in defaults) {
string = string.replace(macro, defaults[macro]);
}
return string;
}
/*
* This feature allows metadata text tracks to be manipulated once available
* @see processMetadataTracks.
* It also allows ad implementations to leverage ad cues coming through
* text tracks, @see processAdTrack
**/
var cueTextTracks = {};
/*
* This feature allows metadata text tracks to be manipulated once they are available,
* usually after the 'loadstart' event is observed on the player
* @param player A reference to a player
* @param processMetadataTrack A callback that performs some operations on a
* metadata text track
**/
cueTextTracks.processMetadataTracks = function (player, processMetadataTrack) {
var tracks = player.textTracks();
var setModeAndProcess = function setModeAndProcess(track) {
if (track.kind === 'metadata') {
player.ads.cueTextTracks.setMetadataTrackMode(track);
processMetadataTrack(player, track);
}
};
// Text tracks are available
for (var i = 0; i < tracks.length; i++) {
setModeAndProcess(tracks[i]);
}
// Wait until text tracks are added
tracks.addEventListener('addtrack', function (event) {
setModeAndProcess(event.track);
});
};
/*
* Sets the track mode to one of 'disabled', 'hidden' or 'showing'
* @see https://github.com/videojs/video.js/blob/master/docs/guides/text-tracks.md
* Default behavior is to do nothing, @override if this is not desired
* @param track The text track to set the mode on
*/
cueTextTracks.setMetadataTrackMode = function (track) {
return;
};
/*
* Determines whether cue is an ad cue and returns the cue data.
* @param player A reference to the player
* @param cue The full cue object
* Returns the given cue by default @override if futher processing is required
* @return {Object} a useable ad cue or null if not supported
**/
cueTextTracks.getSupportedAdCue = function (player, cue) {
return cue;
};
/*
* Defines whether a cue is supported or not, potentially
* based on the player settings
* @param player A reference to the player
* @param cue The cue to be checked
* Default behavior is to return true, @override if this is not desired
* @return {Boolean}
*/
cueTextTracks.isSupportedAdCue = function (player, cue) {
return true;
};
/*
* Gets the id associated with a cue.
* @param cue The cue to extract an ID from
* @returns The first occurance of 'id' in the object,
* @override if this is not the desired cue id
**/
cueTextTracks.getCueId = function (player, cue) {
return cue.id;
};
/*
* Checks whether a cue has already been used
* @param cueId The Id associated with a cue
**/
var cueAlreadySeen = function cueAlreadySeen(player, cueId) {
return cueId !== undefined && player.ads.includedCues[cueId];
};
/*
* Indicates that a cue has been used
* @param cueId The Id associated with a cue
**/
var setCueAlreadySeen = function setCueAlreadySeen(player, cueId) {
if (cueId !== undefined && cueId !== '') {
player.ads.includedCues[cueId] = true;
}
};
/*
* This feature allows ad metadata tracks to be manipulated in ad implementations
* @param player A reference to the player
* @param cues The set of cues to work with
* @param processCue A method that uses a cue to make some
* ad request in the ad implementation
* @param [cancelAdsHandler] A method that dynamically cancels ads in the ad implementation
**/
cueTextTracks.processAdTrack = function (player, cues, processCue, cancelAdsHandler) {
player.ads.includedCues = {};
// loop over set of cues
for (var i = 0; i < cues.length; i++) {
var cue = cues[i];
var cueData = this.getSupportedAdCue(player, cue);
// Exit if this is not a supported cue
if (!this.isSupportedAdCue(player, cue)) {
video_js__WEBPACK_IMPORTED_MODULE_0___default().log.warn('Skipping as this is not a supported ad cue.', cue);
return;
}
// Continue processing supported cue
var cueId = this.getCueId(player, cue);
var startTime = cue.startTime;
// Skip ad if cue was already used
if (cueAlreadySeen(player, cueId)) {
video_js__WEBPACK_IMPORTED_MODULE_0___default().log('Skipping ad already seen with ID ' + cueId);
return;
}
// Optional dynamic ad cancellation
if (cancelAdsHandler) {
cancelAdsHandler(player, cueData, cueId, startTime);
}
// Process cue as an ad cue
processCue(player, cueData, cueId, startTime);
// Indicate that this cue has been used
setCueAlreadySeen(player, cueId);
}
};
function initCancelContentPlay(player, debug) {
if (debug) {
video_js__WEBPACK_IMPORTED_MODULE_0___default().log('Using cancelContentPlay to block content playback');
}
// Listen to play events to "cancel" them afterward
player.on('play', cancelContentPlay);
}
/*
This feature makes sure the player is paused during ad loading.
It does this by pausing the player immediately after a "play" where ads will be requested,
then signalling that we should play after the ad is done.
*/
function cancelContentPlay() {
// this function is in the player's context
if (this.ads._shouldBlockPlay === false) {
// Only block play if the ad plugin is in a state when content
// playback should be blocked. This currently means during
// BeforePrerollState and PrerollState.
return;
}
// pause playback so ads can be handled.
if (!this.paused()) {
this.ads.debug('Playback was canceled by cancelContentPlay');
this.pause();
}
// When the 'content-playback' state is entered, this will let us know to play.
// This is needed if there is no preroll or if it errors, times out, etc.
this.ads._cancelledPlay = true;
}
var obj = {};
// This reference allows videojs to be mocked in unit tests
// while still using the available videojs import in the source code
// @see obj.testHook
var videojsReference = (video_js__WEBPACK_IMPORTED_MODULE_0___default());
/**
* Checks if middleware mediators are available and
* can be used on this platform.
* Currently we can only use mediators on desktop platforms.
*/
obj.isMiddlewareMediatorSupported = function () {
if (videojsReference.browser.IS_IOS || videojsReference.browser.IS_ANDROID) {
return false;
} else if (
// added when middleware was introduced in video.js
videojsReference.use &&
// added when mediators were introduced in video.js
videojsReference.middleware && videojsReference.middleware.TERMINATOR) {
return true;
}
return false;
};
obj.playMiddleware = function (player) {
return {
setSource: function setSource(srcObj, next) {
next(null, srcObj);
},
callPlay: function callPlay() {
// Block play calls while waiting for an ad, only if this is an
// ad supported player
if (player.ads && player.ads._shouldBlockPlay === true) {
player.ads.debug('Using playMiddleware to block content playback');
player.ads._playBlocked = true;
return videojsReference.middleware.TERMINATOR;
}
},
play: function play(terminated, playPromise) {
if (player.ads && player.ads._playBlocked && terminated) {
player.ads.debug('Play call to Tech was terminated.');
// Trigger play event to match the user's intent to play.
// The call to play on the Tech has been blocked, so triggering
// the event on the Player will not affect the Tech's playback state.
player.trigger('play');
// At this point the player has technically started
player.addClass('vjs-has-started');
// Reset playBlocked
player.ads._playBlocked = false;
// Safari issues a pause event when autoplay is blocked but other browsers
// do not, so we send a pause for consistency in those cases. This keeps the
// play button in the correct state if play is rejected.
} else if (playPromise && playPromise.catch) {
playPromise.catch(function (e) {
if (e.name === 'NotAllowedError' && !(video_js__WEBPACK_IMPORTED_MODULE_0___default().browser).IS_SAFARI) {
player.trigger('pause');
}
});
}
}
};
};
obj.testHook = function (testVjs) {
videojsReference = testVjs;
};
var playMiddleware = obj.playMiddleware,
isMiddlewareMediatorSupported = obj.isMiddlewareMediatorSupported;
/**
* Whether or not this copy of Video.js has the ads plugin.
*
* @return {boolean}
* If `true`, has the plugin. `false` otherwise.
*/
var hasAdsPlugin = function hasAdsPlugin() {
// Video.js 6 and 7 have a getPlugin method.
if ((video_js__WEBPACK_IMPORTED_MODULE_0___default().getPlugin)) {
return Boolean(video_js__WEBPACK_IMPORTED_MODULE_0___default().getPlugin('ads'));
}
// Video.js 5 does not have a getPlugin method, so check the player prototype.
var Player = video_js__WEBPACK_IMPORTED_MODULE_0___default().getComponent('Player');
return Boolean(Player && Player.prototype.ads);
};
/**
* Register contrib-ads with Video.js, but provide protection for duplicate
* copies of the plugin. This could happen if, for example, a stitched ads
* plugin and a client-side ads plugin are included simultaneously with their
* own copies of contrib-ads.
*
* If contrib-ads detects a pre-existing duplicate, it will not register
* itself.
*
* Ad plugins using contrib-ads and anticipating that this could come into
* effect should verify that the contrib-ads they are using is of a compatible
* version.
*
* @param {Function} contribAdsPlugin
* The plugin function.
*
* @return {boolean}
* When `true`, the plugin was registered. When `false`, the plugin
* was not registered.
*/
function register(contribAdsPlugin) {
// If the ads plugin already exists, do not overwrite it.
if (hasAdsPlugin((video_js__WEBPACK_IMPORTED_MODULE_0___default()))) {
return false;
}
// Cross-compatibility with Video.js 6/7 and 5.
var registerPlugin = (video_js__WEBPACK_IMPORTED_MODULE_0___default().registerPlugin) || (video_js__WEBPACK_IMPORTED_MODULE_0___default().plugin);
// Register this plugin with Video.js.
registerPlugin('ads', contribAdsPlugin);
// Register the play middleware with Video.js on script execution,
// to avoid a new playMiddleware factory being added for each player.
// The `usingContribAdsMiddleware_` flag is used to ensure that we only ever
// register the middleware once - despite the ability to de-register and
// re-register the plugin itself.
if (isMiddlewareMediatorSupported() && !(video_js__WEBPACK_IMPORTED_MODULE_0___default().usingContribAdsMiddleware_)) {
// Register the play middleware
video_js__WEBPACK_IMPORTED_MODULE_0___default().use('*', playMiddleware);
(video_js__WEBPACK_IMPORTED_MODULE_0___default().usingContribAdsMiddleware_) = true;
video_js__WEBPACK_IMPORTED_MODULE_0___default().log.debug('Play middleware has been registered with videojs');
}
return true;
}
var OUTSTREAM_VIDEO = {
src: 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAxJtZGF03ABMYXZjNjEuMy4xMDAAQiAIwRg4AAACrgYF//+q3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE2NCByMzEwOCAzMWUxOWY5IC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAyMyAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTcgbG9va2FoZWFkX3RocmVhZHM9MSBzbGljZWRfdGhyZWFkcz0wIG5yPTAgZGVjaW1hdGU9MSBpbnRlcmxhY2VkPTAgYmx1cmF5X2NvbXBhdD0wIGNvbnN0cmFpbmVkX2ludHJhPTAgYmZyYW1lcz0zIGJfcHlyYW1pZD0yIGJfYWRhcHQ9MSBiX2JpYXM9MCBkaXJlY3Q9MSB3ZWlnaHRiPTEgb3Blbl9nb3A9MCB3ZWlnaHRwPTIga2V5aW50PTI1MCBrZXlpbnRfbWluPTI1IHNjZW5lY3V0PTQwIGludHJhX3JlZnJlc2g9MCByY19sb29rYWhlYWQ9NDAgcmM9Y3JmIG1idHJlZT0xIGNyZj0yMy4wIHFjb21wPTAuNjAgcXBtaW49MCBxcG1heD02OSBxcHN0ZXA9NCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAAn//71sXwKaunqigzoMi7hlyTJrrYi4m0AwABFxzcqWKGahTaoBcQAAMWK4AlcFlIICBeldSEQBGCMHAAABVNtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAIgABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAACQXRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAAIgAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAABQAAAAPAAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAACIAAAAAAAEAAAAAAbltZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAADwAAAACAFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAFkbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABJHN0YmwAAADAc3RzZAAAAAAAAAABAAAAsGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAABQADwAEgAAABIAAAAAAAAAAEUTGF2YzYxLjMuMTAwIGxpYngyNjQAAAAAAAAAAAAAAAAY//8AAAA2YXZjQwFkAA3/4QAZZ2QADazZQUH7ARAAAAMAEAAAAwPA8UKZYAEABmjr48siwP34+AAAAAAQcGFzcAAAAAEAAAABAAA