UNPKG

cloudinary-video-player

Version:

Cloudinary Video Player

1,228 lines (1,127 loc) 231 kB
"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