cloudinary-video-player 3.5.2 → 3.5.3-edge.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adaptive-streaming.js +6 -6
- package/dist/adaptive-streaming.min.js +4 -4
- package/dist/chapters.js +3 -3
- package/dist/chapters.min.js +3 -3
- package/dist/cld-video-player.css +19 -8
- package/dist/cld-video-player.js +38 -38
- package/dist/cld-video-player.light.js +38 -38
- package/dist/cld-video-player.light.min.js +4 -4
- package/dist/cld-video-player.min.css +3 -3
- package/dist/cld-video-player.min.js +4 -4
- package/dist/colors.js +2 -2
- package/dist/colors.min.js +2 -2
- package/dist/dash.js +2 -2
- package/dist/dash.min.js +133 -133
- package/dist/debug.js +3 -3
- package/dist/debug.min.js +3 -3
- package/dist/ima.js +3 -3
- package/dist/ima.min.js +3 -3
- package/dist/interaction-areas.js +4 -4
- package/dist/interaction-areas.min.js +3 -3
- package/dist/node_modules_lodash_throttle_js.js +2 -2
- package/dist/playlist.js +9 -9
- package/dist/playlist.min.js +3 -3
- package/dist/recommendations-overlay.js +4 -4
- package/dist/recommendations-overlay.min.js +3 -3
- package/dist/share.js +3 -3
- package/dist/share.min.js +3 -3
- package/dist/shoppable.js +7 -7
- package/dist/shoppable.min.js +3 -3
- package/dist/visual-search.js +4 -4
- package/dist/visual-search.min.js +3 -3
- package/lib/adaptive-streaming.js +1 -1
- package/lib/all.js +1 -1
- package/lib/all.js.LICENSE.txt +1 -1
- package/lib/chapters.js +1 -1
- package/lib/cld-video-player.js +1 -1
- package/lib/cld-video-player.js.LICENSE.txt +1 -1
- package/lib/cld-video-player.min.css +2 -2
- package/lib/dash.js +1 -1
- package/lib/debug.js +1 -1
- package/lib/ima.js +1 -1
- package/lib/interaction-areas.js +1 -1
- package/lib/player.js +1 -1
- package/lib/player.js.LICENSE.txt +1 -1
- package/lib/playlist.js +1 -1
- package/lib/recommendations-overlay.js +1 -1
- package/lib/share.js +1 -1
- package/lib/shoppable.js +1 -1
- package/lib/videoPlayer.js +1 -1
- package/lib/videoPlayer.js.LICENSE.txt +1 -1
- package/lib/visual-search.js +1 -1
- package/package.json +29 -29
package/dist/ima.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Cloudinary Video Player v3.5.
|
|
3
|
-
* Built on 2025-
|
|
2
|
+
* Cloudinary Video Player v3.5.3-edge.1
|
|
3
|
+
* Built on 2025-12-01T11:07:53.079Z
|
|
4
4
|
* https://github.com/cloudinary/cloudinary-video-player
|
|
5
5
|
*/
|
|
6
6
|
/*
|
|
@@ -73,7 +73,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
|
73
73
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
74
74
|
|
|
75
75
|
"use strict";
|
|
76
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ LiveStream: () => (/* binding */ LiveStream),\n/* harmony export */ VodStream: () => (/* binding */ VodStream),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n\n\nfunction _toPrimitive(t, r) {\n if (\"object\" != typeof t || !t) return t;\n var e = t[Symbol.toPrimitive];\n if (void 0 !== e) {\n var i = e.call(t, r || \"default\");\n if (\"object\" != typeof i) return i;\n throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n }\n return (\"string\" === r ? String : Number)(t);\n}\nfunction _toPropertyKey(t) {\n var i = _toPrimitive(t, \"string\");\n return \"symbol\" == typeof i ? i : String(i);\n}\nfunction _typeof(o) {\n \"@babel/helpers - typeof\";\n\n return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (o) {\n return typeof o;\n } : function (o) {\n return o && \"function\" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? \"symbol\" : typeof o;\n }, _typeof(o);\n}\nfunction _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n}\nfunction _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);\n }\n}\nfunction _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n Object.defineProperty(Constructor, \"prototype\", {\n writable: false\n });\n return Constructor;\n}\nfunction _unsupportedIterableToArray(o, minLen) {\n if (!o) return;\n if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n var n = Object.prototype.toString.call(o).slice(8, -1);\n if (n === \"Object\" && o.constructor) n = o.constructor.name;\n if (n === \"Map\" || n === \"Set\") return Array.from(o);\n if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n}\nfunction _arrayLikeToArray(arr, len) {\n if (len == null || len > arr.length) len = arr.length;\n for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n return arr2;\n}\nfunction _createForOfIteratorHelper(o, allowArrayLike) {\n var it = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"];\n if (!it) {\n if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") {\n if (it) o = it;\n var i = 0;\n var F = function () {};\n return {\n s: F,\n n: function () {\n if (i >= o.length) return {\n done: true\n };\n return {\n done: false,\n value: o[i++]\n };\n },\n e: function (e) {\n throw e;\n },\n f: F\n };\n }\n throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n }\n var normalCompletion = true,\n didErr = false,\n err;\n return {\n s: function () {\n it = it.call(o);\n },\n n: function () {\n var step = it.next();\n normalCompletion = step.done;\n return step;\n },\n e: function (e) {\n didErr = true;\n err = e;\n },\n f: function () {\n try {\n if (!normalCompletion && it.return != null) it.return();\n } finally {\n if (didErr) throw err;\n }\n }\n };\n}\n\n/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Wraps the video.js player for the plugin.\n *\n * @param {Object} player Video.js player instance.\n * @param {Object} adsPluginSettings Settings for the contrib-ads plugin.\n * @param {Controller} controller Reference to the parent controller.\n */\nvar PlayerWrapper = function PlayerWrapper(player, adsPluginSettings, controller) {\n /**\n * Instance of the video.js player.\n */\n this.vjsPlayer = player;\n\n /**\n * Plugin controller.\n */\n this.controller = controller;\n\n /**\n * Timer used to track content progress.\n */\n this.contentTrackingTimer = null;\n\n /**\n * True if our content video has completed, false otherwise.\n */\n this.contentComplete = false;\n\n /**\n * Handle to interval that repeatedly updates current time.\n */\n this.updateTimeIntervalHandle = null;\n\n /**\n * Interval (ms) to check for player resize for fluid support.\n */\n this.updateTimeInterval = 1000;\n\n /**\n * Handle to interval that repeatedly checks for seeking.\n */\n this.seekCheckIntervalHandle = null;\n\n /**\n * Interval (ms) on which to check if the user is seeking through the\n * content.\n */\n this.seekCheckInterval = 1000;\n\n /**\n * Handle to interval that repeatedly checks for player resize.\n */\n this.resizeCheckIntervalHandle = null;\n\n /**\n * Interval (ms) to check for player resize for fluid support.\n */\n this.resizeCheckInterval = 250;\n\n /**\n * Threshold by which to judge user seeking. We check every 1000 ms to see\n * if the user is seeking. In order for us to decide that they are *not*\n * seeking, the content video playhead must only change by 900-1100 ms\n * between checks. Any greater change and we assume the user is seeking\n * through the video.\n */\n this.seekThreshold = 100;\n\n /**\n * Content ended listeners passed by the publisher to the plugin. Publishers\n * should allow the plugin to handle content ended to ensure proper support\n * of custom ad playback.\n */\n this.contentEndedListeners = [];\n\n /**\n * Stores the content source so we can re-populate it manually after a\n * post-roll on iOS.\n */\n this.contentSource = '';\n\n /**\n * Stores the content source type so we can re-populate it manually after a\n * post-roll.\n */\n this.contentSourceType = '';\n\n /**\n * Stores data for the content playhead tracker.\n */\n this.contentPlayheadTracker = {\n currentTime: 0,\n previousTime: 0,\n seeking: false,\n duration: 0\n };\n\n /**\n * Player dimensions. Used in our resize check.\n */\n this.vjsPlayerDimensions = {\n width: this.getPlayerWidth(),\n height: this.getPlayerHeight()\n };\n\n /**\n * Video.js control bar.\n */\n this.vjsControls = this.vjsPlayer.getChild('controlBar');\n\n /**\n * Vanilla HTML5 video player underneath the video.js player.\n */\n this.h5Player = null;\n this.vjsPlayer.one('play', this.setUpPlayerIntervals.bind(this));\n this.boundContentEndedListener = this.localContentEndedListener.bind(this);\n this.vjsPlayer.on('contentended', this.boundContentEndedListener);\n this.vjsPlayer.on('dispose', this.playerDisposedListener.bind(this));\n this.vjsPlayer.on('readyforpreroll', this.onReadyForPreroll.bind(this));\n this.vjsPlayer.on('adtimeout', this.onAdTimeout.bind(this));\n this.vjsPlayer.ready(this.onPlayerReady.bind(this));\n if (this.controller.getSettings().requestMode === 'onPlay') {\n this.vjsPlayer.one('play', this.controller.requestAds.bind(this.controller));\n }\n if (!this.vjsPlayer.ads) {\n window.console.warn('You may be using a version of videojs-contrib-ads ' + 'that is not compatible with your version of video.js.');\n }\n this.vjsPlayer.ads(adsPluginSettings);\n};\n\n/**\n * Set up the intervals we use on the player.\n */\nPlayerWrapper.prototype.setUpPlayerIntervals = function () {\n /**\n * Clear old interval handers in case the method was called more than once\n */\n if (this.updateTimeIntervalHandle) {\n clearInterval(this.updateTimeIntervalHandle);\n }\n if (this.seekCheckIntervalHandle) {\n clearInterval(this.seekCheckIntervalHandle);\n }\n if (this.resizeCheckIntervalHandle) {\n clearInterval(this.resizeCheckIntervalHandle);\n }\n this.updateTimeIntervalHandle = setInterval(this.updateCurrentTime.bind(this), this.updateTimeInterval);\n this.seekCheckIntervalHandle = setInterval(this.checkForSeeking.bind(this), this.seekCheckInterval);\n this.resizeCheckIntervalHandle = setInterval(this.checkForResize.bind(this), this.resizeCheckInterval);\n};\n\n/**\n * Updates the current time of the video\n */\nPlayerWrapper.prototype.updateCurrentTime = function () {\n if (!this.contentPlayheadTracker.seeking) {\n this.contentPlayheadTracker.currentTime = this.vjsPlayer.currentTime();\n }\n};\n\n/**\n * Detects when the user is seeking through a video.\n * This is used to prevent mid-rolls from playing while a user is seeking.\n *\n * There *is* a seeking property of the HTML5 video element, but it's not\n * properly implemented on all platforms (e.g. mobile safari), so we have to\n * check ourselves to be sure.\n */\nPlayerWrapper.prototype.checkForSeeking = function () {\n var tempCurrentTime = this.vjsPlayer.currentTime();\n var diff = (tempCurrentTime - this.contentPlayheadTracker.previousTime) * 1000;\n if (Math.abs(diff) > this.seekCheckInterval + this.seekThreshold) {\n this.contentPlayheadTracker.seeking = true;\n } else {\n this.contentPlayheadTracker.seeking = false;\n }\n this.contentPlayheadTracker.previousTime = this.vjsPlayer.currentTime();\n};\n\n/**\n * Detects when the player is resized (for fluid support) and resizes the\n * ads manager to match.\n */\nPlayerWrapper.prototype.checkForResize = function () {\n var currentWidth = this.getPlayerWidth();\n var currentHeight = this.getPlayerHeight();\n if (currentWidth != this.vjsPlayerDimensions.width || currentHeight != this.vjsPlayerDimensions.height) {\n this.vjsPlayerDimensions.width = currentWidth;\n this.vjsPlayerDimensions.height = currentHeight;\n this.controller.onPlayerResize(currentWidth, currentHeight);\n }\n};\n\n/**\n * Local content ended listener for contentComplete.\n */\nPlayerWrapper.prototype.localContentEndedListener = function () {\n if (!this.contentComplete) {\n this.contentComplete = true;\n this.controller.onContentComplete();\n }\n for (var index in this.contentEndedListeners) {\n if (typeof this.contentEndedListeners[index] === 'function') {\n this.contentEndedListeners[index]();\n }\n }\n if (this.vjsPlayer.el()) {\n this.vjsPlayer.one('play', this.setUpPlayerIntervals.bind(this));\n }\n};\n\n/**\n * Called when it's time to play a post-roll but we don't have one to play.\n */\nPlayerWrapper.prototype.onNoPostroll = function () {\n this.vjsPlayer.trigger('nopostroll');\n};\n\n/**\n * Detects when the video.js player has been disposed.\n */\nPlayerWrapper.prototype.playerDisposedListener = function () {\n this.contentEndedListeners = [];\n this.controller.onPlayerDisposed();\n this.contentComplete = true;\n this.vjsPlayer.off('contentended', this.boundContentEndedListener);\n\n // Bug fix: https://github.com/googleads/videojs-ima/issues/306\n if (this.vjsPlayer.ads.adTimeoutTimeout) {\n clearTimeout(this.vjsPlayer.ads.adTimeoutTimeout);\n }\n var intervalsToClear = [this.updateTimeIntervalHandle, this.seekCheckIntervalHandle, this.resizeCheckIntervalHandle];\n for (var index in intervalsToClear) {\n if (intervalsToClear[index]) {\n clearInterval(intervalsToClear[index]);\n }\n }\n};\n\n/**\n * Start ad playback, or content video playback in the absence of a\n * pre-roll.\n */\nPlayerWrapper.prototype.onReadyForPreroll = function () {\n this.controller.onPlayerReadyForPreroll();\n};\n\n/**\n * Detects if the ad has timed out.\n */\nPlayerWrapper.prototype.onAdTimeout = function () {\n this.controller.onAdTimeout();\n};\n\n/**\n * Called when the player fires its 'ready' event.\n */\nPlayerWrapper.prototype.onPlayerReady = function () {\n this.h5Player = document.getElementById(this.getPlayerId()).getElementsByClassName('vjs-tech')[0];\n\n // Detect inline options\n if (this.h5Player.hasAttribute('autoplay')) {\n this.controller.setSetting('adWillAutoPlay', true);\n }\n\n // Sync ad volume with player volume.\n this.onVolumeChange();\n this.vjsPlayer.on('fullscreenchange', this.onFullscreenChange.bind(this));\n this.vjsPlayer.on('volumechange', this.onVolumeChange.bind(this));\n this.controller.onPlayerReady();\n};\n\n/**\n * Listens for the video.js player to change its fullscreen status. This\n * keeps the fullscreen-ness of the AdContainer in sync with the player.\n */\nPlayerWrapper.prototype.onFullscreenChange = function () {\n if (this.vjsPlayer.isFullscreen()) {\n this.controller.onPlayerEnterFullscreen();\n } else {\n this.controller.onPlayerExitFullscreen();\n }\n};\n\n/**\n * Listens for the video.js player to change its volume. This keeps the ad\n * volume in sync with the content volume if the volume of the player is\n * changed while content is playing.\n */\nPlayerWrapper.prototype.onVolumeChange = function () {\n var newVolume = this.vjsPlayer.muted() ? 0 : this.vjsPlayer.volume();\n this.controller.onPlayerVolumeChanged(newVolume);\n};\n\n/**\n * Inject the ad container div into the DOM.\n *\n * @param{HTMLElement} adContainerDiv The ad container div.\n */\nPlayerWrapper.prototype.injectAdContainerDiv = function (adContainerDiv) {\n this.vjsControls.el().parentNode.appendChild(adContainerDiv);\n};\n\n/**\n * @return {Object} The content player.\n */\nPlayerWrapper.prototype.getContentPlayer = function () {\n return this.h5Player;\n};\n\n/**\n * @return {number} The volume, 0-1.\n */\nPlayerWrapper.prototype.getVolume = function () {\n return this.vjsPlayer.muted() ? 0 : this.vjsPlayer.volume();\n};\n\n/**\n * Set the volume of the player. 0-1.\n *\n * @param {number} volume The new volume.\n */\nPlayerWrapper.prototype.setVolume = function (volume) {\n this.vjsPlayer.volume(volume);\n if (volume == 0) {\n this.vjsPlayer.muted(true);\n } else {\n this.vjsPlayer.muted(false);\n }\n};\n\n/**\n * Ummute the player.\n */\nPlayerWrapper.prototype.unmute = function () {\n this.vjsPlayer.muted(false);\n};\n\n/**\n * Mute the player.\n */\nPlayerWrapper.prototype.mute = function () {\n this.vjsPlayer.muted(true);\n};\n\n/**\n * Play the video.\n */\nPlayerWrapper.prototype.play = function () {\n this.vjsPlayer.play();\n};\n\n/**\n * Toggles playback of the video.\n */\nPlayerWrapper.prototype.togglePlayback = function () {\n if (this.vjsPlayer.paused()) {\n this.vjsPlayer.play();\n } else {\n this.vjsPlayer.pause();\n }\n};\n\n/**\n * Get the player width.\n *\n * @return {number} The player's width.\n */\nPlayerWrapper.prototype.getPlayerWidth = function () {\n var width = (getComputedStyle(this.vjsPlayer.el()) || {}).width;\n if (!width || parseFloat(width) === 0) {\n width = (this.vjsPlayer.el().getBoundingClientRect() || {}).width;\n }\n return parseFloat(width) || this.vjsPlayer.width();\n};\n\n/**\n * Get the player height.\n *\n * @return {number} The player's height.\n */\nPlayerWrapper.prototype.getPlayerHeight = function () {\n var height = (getComputedStyle(this.vjsPlayer.el()) || {}).height;\n if (!height || parseFloat(height) === 0) {\n height = (this.vjsPlayer.el().getBoundingClientRect() || {}).height;\n }\n return parseFloat(height) || this.vjsPlayer.height();\n};\n\n/**\n * @return {Object} The vjs player's options object.\n */\nPlayerWrapper.prototype.getPlayerOptions = function () {\n return this.vjsPlayer.options_;\n};\n\n/**\n * Returns the instance of the player id.\n * @return {string} The player id.\n */\nPlayerWrapper.prototype.getPlayerId = function () {\n return this.vjsPlayer.id();\n};\n\n/**\n * Toggle fullscreen state.\n */\nPlayerWrapper.prototype.toggleFullscreen = function () {\n if (this.vjsPlayer.isFullscreen()) {\n this.vjsPlayer.exitFullscreen();\n } else {\n this.vjsPlayer.requestFullscreen();\n }\n};\n\n/**\n * Returns the content playhead tracker.\n *\n * @return {Object} The content playhead tracker.\n */\nPlayerWrapper.prototype.getContentPlayheadTracker = function () {\n return this.contentPlayheadTracker;\n};\n\n/**\n * Handles ad errors.\n *\n * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nPlayerWrapper.prototype.onAdError = function (adErrorEvent) {\n this.vjsControls.show();\n var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;\n this.vjsPlayer.trigger({\n type: 'adserror',\n data: {\n AdError: errorMessage,\n AdErrorEvent: adErrorEvent\n }\n });\n};\n\n/**\n * Handles ad log messages.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the IMA SDK.\n */\nPlayerWrapper.prototype.onAdLog = function (adEvent) {\n var adData = adEvent.getAdData();\n var errorMessage = adData['adError'] !== undefined ? adData['adError'].getMessage() : undefined;\n this.vjsPlayer.trigger({\n type: 'adslog',\n data: {\n AdError: errorMessage,\n AdEvent: adEvent\n }\n });\n};\n\n/**\n * Handles ad break starting.\n */\nPlayerWrapper.prototype.onAdBreakStart = function () {\n this.contentSource = this.vjsPlayer.currentSrc();\n this.contentSourceType = this.vjsPlayer.currentType();\n this.vjsPlayer.off('contentended', this.boundContentEndedListener);\n this.vjsPlayer.ads.startLinearAdMode();\n this.vjsControls.hide();\n this.vjsPlayer.pause();\n};\n\n/**\n * Handles ad break ending.\n */\nPlayerWrapper.prototype.onAdBreakEnd = function () {\n this.vjsPlayer.on('contentended', this.boundContentEndedListener);\n if (this.vjsPlayer.ads.inAdBreak()) {\n this.vjsPlayer.ads.endLinearAdMode();\n }\n this.vjsControls.show();\n};\n\n/**\n * Handles an individual ad start.\n */\nPlayerWrapper.prototype.onAdStart = function () {\n this.vjsPlayer.trigger('ads-ad-started');\n};\n\n/**\n * Handles when all ads have finished playing.\n */\nPlayerWrapper.prototype.onAllAdsCompleted = function () {\n if (this.contentComplete == true) {\n // The null check on this.contentSource was added to fix\n // an error when the post-roll was an empty VAST tag.\n if (this.contentSource && this.vjsPlayer.currentSrc() != this.contentSource) {\n this.vjsPlayer.src({\n src: this.contentSource,\n type: this.contentSourceType\n });\n }\n this.controller.onContentAndAdsCompleted();\n }\n};\n\n/**\n * Triggers adsready for contrib-ads.\n */\nPlayerWrapper.prototype.onAdsReady = function () {\n this.vjsPlayer.trigger('adsready');\n};\n\n/**\n * Changes the player source.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n */\nPlayerWrapper.prototype.changeSource = function (contentSrc) {\n // Only try to pause the player when initialised with a source already\n if (this.vjsPlayer.currentSrc()) {\n this.vjsPlayer.currentTime(0);\n this.vjsPlayer.pause();\n }\n if (contentSrc) {\n this.vjsPlayer.src(contentSrc);\n }\n this.vjsPlayer.one('loadedmetadata', this.seekContentToZero.bind(this));\n};\n\n/**\n * Seeks content to 00:00:00. This is used as an event handler for the\n * loadedmetadata event, since seeking is not possible until that event has\n * fired.\n */\nPlayerWrapper.prototype.seekContentToZero = function () {\n this.vjsPlayer.currentTime(0);\n};\n\n/**\n * Triggers an event on the VJS player\n * @param {string} name The event name.\n * @param {Object} data The event data.\n */\nPlayerWrapper.prototype.triggerPlayerEvent = function (name, data) {\n this.vjsPlayer.trigger(name, data);\n};\n\n/**\n * Listener JSDoc for ESLint. This listener can be passed to\n * addContentEndedListener.\n * @callback listener\n */\n\n/**\n * Adds a listener for the 'contentended' event of the video player. This should\n * be used instead of setting an 'contentended' listener directly to ensure that\n * the ima can do proper cleanup of the SDK before other event listeners are\n * called.\n * @param {listener} listener The listener to be called when content\n * completes.\n */\nPlayerWrapper.prototype.addContentEndedListener = function (listener) {\n this.contentEndedListeners.push(listener);\n};\n\n/**\n * Reset the player.\n */\nPlayerWrapper.prototype.reset = function () {\n // Attempts to remove the contentEndedListener before adding it.\n // This is to prevent an error where an erroring video caused multiple\n // contentEndedListeners to be added.\n this.vjsPlayer.off('contentended', this.boundContentEndedListener);\n this.vjsPlayer.on('contentended', this.boundContentEndedListener);\n this.vjsControls.show();\n if (this.vjsPlayer.ads.inAdBreak()) {\n this.vjsPlayer.ads.endLinearAdMode();\n }\n // Reset the content time we give the SDK. Fixes an issue where requesting\n // VMAP followed by VMAP would play the second mid-rolls as pre-rolls if\n // the first playthrough of the video passed the second response's\n // mid-roll time.\n this.contentPlayheadTracker.currentTime = 0;\n this.contentComplete = false;\n};\n\n/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Ad UI implementation.\n *\n * @param {Controller} controller Plugin controller.\n * @constructor\n * @struct\n * @final\n */\nvar AdUi = function AdUi(controller) {\n /**\n * Plugin controller.\n */\n this.controller = controller;\n\n /**\n * Div used as an ad container.\n */\n this.adContainerDiv = document.createElement('div');\n\n /**\n * Div used to display ad controls.\n */\n this.controlsDiv = document.createElement('div');\n\n /**\n * Div used to display ad countdown timer.\n */\n this.countdownDiv = document.createElement('div');\n\n /**\n * Div used to display add seek bar.\n */\n this.seekBarDiv = document.createElement('div');\n\n /**\n * Div used to display ad progress (in seek bar).\n */\n this.progressDiv = document.createElement('div');\n\n /**\n * Div used to display ad play/pause button.\n */\n this.playPauseDiv = document.createElement('div');\n\n /**\n * Div used to display ad mute button.\n */\n this.muteDiv = document.createElement('div');\n\n /**\n * Div used by the volume slider.\n */\n this.sliderDiv = document.createElement('div');\n\n /**\n * Volume slider level visuals\n */\n this.sliderLevelDiv = document.createElement('div');\n\n /**\n * Div used to display ad fullscreen button.\n */\n this.fullscreenDiv = document.createElement('div');\n\n /**\n * Bound event handler for onMouseUp.\n */\n this.boundOnMouseUp = this.onMouseUp.bind(this);\n\n /**\n * Bound event handler for onMouseMove.\n */\n this.boundOnMouseMove = this.onMouseMove.bind(this);\n\n /**\n * Stores data for the ad playhead tracker.\n */\n this.adPlayheadTracker = {\n 'currentTime': 0,\n 'duration': 0,\n 'isPod': false,\n 'adPosition': 0,\n 'totalAds': 0\n };\n\n /**\n * Used to prefix videojs ima controls.\n */\n this.controlPrefix = this.controller.getPlayerId() + '_';\n\n /**\n * Boolean flag to show or hide the ad countdown timer.\n */\n this.showCountdown = true;\n if (this.controller.getSettings().showCountdown === false) {\n this.showCountdown = false;\n }\n\n /**\n * Boolean flag if the current ad is nonlinear.\n */\n this.isAdNonlinear = false;\n this.createAdContainer();\n};\n\n/**\n * Creates the ad container.\n */\nAdUi.prototype.createAdContainer = function () {\n this.assignControlAttributes(this.adContainerDiv, 'ima-ad-container');\n this.adContainerDiv.style.position = 'absolute';\n this.adContainerDiv.style.zIndex = 1111;\n this.adContainerDiv.addEventListener('mouseenter', this.showAdControls.bind(this), false);\n this.adContainerDiv.addEventListener('mouseleave', this.hideAdControls.bind(this), false);\n this.adContainerDiv.addEventListener('click', this.onAdContainerClick.bind(this), false);\n this.createControls();\n this.controller.injectAdContainerDiv(this.adContainerDiv);\n};\n\n/**\n * Create the controls.\n */\nAdUi.prototype.createControls = function () {\n this.assignControlAttributes(this.controlsDiv, 'ima-controls-div');\n this.controlsDiv.style.width = '100%';\n if (!this.controller.getIsMobile()) {\n this.assignControlAttributes(this.countdownDiv, 'ima-countdown-div');\n this.countdownDiv.innerHTML = this.controller.getSettings().adLabel;\n this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';\n } else {\n this.countdownDiv.style.display = 'none';\n }\n this.assignControlAttributes(this.seekBarDiv, 'ima-seek-bar-div');\n this.seekBarDiv.style.width = '100%';\n this.assignControlAttributes(this.progressDiv, 'ima-progress-div');\n this.assignControlAttributes(this.playPauseDiv, 'ima-play-pause-div');\n this.addClass(this.playPauseDiv, 'ima-playing');\n this.playPauseDiv.addEventListener('click', this.onAdPlayPauseClick.bind(this), false);\n this.assignControlAttributes(this.muteDiv, 'ima-mute-div');\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.muteDiv.addEventListener('click', this.onAdMuteClick.bind(this), false);\n this.assignControlAttributes(this.sliderDiv, 'ima-slider-div');\n this.sliderDiv.addEventListener('mousedown', this.onAdVolumeSliderMouseDown.bind(this), false);\n\n // Hide volume slider controls on iOS as they aren't supported.\n if (this.controller.getIsIos()) {\n this.sliderDiv.style.display = 'none';\n }\n this.assignControlAttributes(this.sliderLevelDiv, 'ima-slider-level-div');\n this.assignControlAttributes(this.fullscreenDiv, 'ima-fullscreen-div');\n this.addClass(this.fullscreenDiv, 'ima-non-fullscreen');\n this.fullscreenDiv.addEventListener('click', this.onAdFullscreenClick.bind(this), false);\n this.adContainerDiv.appendChild(this.controlsDiv);\n this.controlsDiv.appendChild(this.countdownDiv);\n this.controlsDiv.appendChild(this.seekBarDiv);\n this.controlsDiv.appendChild(this.playPauseDiv);\n this.controlsDiv.appendChild(this.muteDiv);\n this.controlsDiv.appendChild(this.sliderDiv);\n this.controlsDiv.appendChild(this.fullscreenDiv);\n this.seekBarDiv.appendChild(this.progressDiv);\n this.sliderDiv.appendChild(this.sliderLevelDiv);\n};\n\n/**\n * Listener for clicks on the play/pause button during ad playback.\n */\nAdUi.prototype.onAdPlayPauseClick = function () {\n this.controller.onAdPlayPauseClick();\n};\n\n/**\n * Listener for clicks on the play/pause button during ad playback.\n */\nAdUi.prototype.onAdMuteClick = function () {\n this.controller.onAdMuteClick();\n};\n\n/**\n * Listener for clicks on the fullscreen button during ad playback.\n */\nAdUi.prototype.onAdFullscreenClick = function () {\n this.controller.toggleFullscreen();\n};\n\n/**\n * Show pause and hide play button\n */\nAdUi.prototype.onAdsPaused = function () {\n this.controller.sdkImpl.adPlaying = false;\n this.addClass(this.playPauseDiv, 'ima-paused');\n this.removeClass(this.playPauseDiv, 'ima-playing');\n this.showAdControls();\n};\n\n/**\n * Show pause and hide play button\n */\nAdUi.prototype.onAdsResumed = function () {\n this.onAdsPlaying();\n this.showAdControls();\n};\n\n/**\n * Show play and hide pause button\n */\nAdUi.prototype.onAdsPlaying = function () {\n this.controller.sdkImpl.adPlaying = true;\n this.addClass(this.playPauseDiv, 'ima-playing');\n this.removeClass(this.playPauseDiv, 'ima-paused');\n};\n\n/**\n * Takes data from the controller to update the UI.\n *\n * @param {number} currentTime Current time of the ad.\n * @param {number} remainingTime Remaining time of the ad.\n * @param {number} duration Duration of the ad.\n * @param {number} adPosition Index of the ad in the pod.\n * @param {number} totalAds Total number of ads in the pod.\n */\nAdUi.prototype.updateAdUi = function (currentTime, remainingTime, duration, adPosition, totalAds) {\n // Update countdown timer data\n var remainingMinutes = Math.floor(remainingTime / 60);\n var remainingSeconds = Math.floor(remainingTime % 60);\n if (remainingSeconds.toString().length < 2) {\n remainingSeconds = '0' + remainingSeconds;\n }\n var podCount = ': ';\n if (totalAds > 1) {\n podCount = ' (' + adPosition + ' ' + this.controller.getSettings().adLabelNofN + ' ' + totalAds + '): ';\n }\n this.countdownDiv.innerHTML = this.controller.getSettings().adLabel + podCount + remainingMinutes + ':' + remainingSeconds;\n\n // Update UI\n var playProgressRatio = currentTime / duration;\n var playProgressPercent = playProgressRatio * 100;\n this.progressDiv.style.width = playProgressPercent + '%';\n};\n\n/**\n * Handles UI changes when the ad is unmuted.\n */\nAdUi.prototype.unmute = function () {\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.removeClass(this.muteDiv, 'ima-muted');\n this.sliderLevelDiv.style.width = this.controller.getPlayerVolume() * 100 + '%';\n};\n\n/**\n * Handles UI changes when the ad is muted.\n */\nAdUi.prototype.mute = function () {\n this.addClass(this.muteDiv, 'ima-muted');\n this.removeClass(this.muteDiv, 'ima-non-muted');\n this.sliderLevelDiv.style.width = '0%';\n};\n\n/*\n * Listener for mouse down events during ad playback. Used for volume.\n */\nAdUi.prototype.onAdVolumeSliderMouseDown = function () {\n document.addEventListener('mouseup', this.boundOnMouseUp, false);\n document.addEventListener('mousemove', this.boundOnMouseMove, false);\n};\n\n/*\n * Mouse movement listener used for volume slider.\n */\nAdUi.prototype.onMouseMove = function (event) {\n this.changeVolume(event);\n};\n\n/*\n * Mouse release listener used for volume slider.\n */\nAdUi.prototype.onMouseUp = function (event) {\n this.changeVolume(event);\n document.removeEventListener('mouseup', this.boundOnMouseUp);\n document.removeEventListener('mousemove', this.boundOnMouseMove);\n};\n\n/*\n * Utility function to set volume and associated UI\n */\nAdUi.prototype.changeVolume = function (event) {\n var percent = (event.clientX - this.sliderDiv.getBoundingClientRect().left) / this.sliderDiv.offsetWidth;\n percent *= 100;\n // Bounds value 0-100 if mouse is outside slider region.\n percent = Math.min(Math.max(percent, 0), 100);\n this.sliderLevelDiv.style.width = percent + '%';\n if (this.percent == 0) {\n this.addClass(this.muteDiv, 'ima-muted');\n this.removeClass(this.muteDiv, 'ima-non-muted');\n } else {\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.removeClass(this.muteDiv, 'ima-muted');\n }\n this.controller.setVolume(percent / 100); // 0-1\n};\n\n/**\n * Show the ad container.\n */\nAdUi.prototype.showAdContainer = function () {\n this.adContainerDiv.style.display = 'block';\n};\n\n/**\n * Hide the ad container\n */\nAdUi.prototype.hideAdContainer = function () {\n this.adContainerDiv.style.display = 'none';\n};\n\n/**\n * Handles clicks on the ad container\n */\nAdUi.prototype.onAdContainerClick = function () {\n if (this.isAdNonlinear) {\n this.controller.togglePlayback();\n }\n};\n\n/**\n * Resets the state of the ad ui.\n */\nAdUi.prototype.reset = function () {\n this.hideAdContainer();\n};\n\n/**\n * Handles ad errors.\n */\nAdUi.prototype.onAdError = function () {\n this.hideAdContainer();\n};\n\n/**\n * Handles ad break starting.\n *\n * @param {Object} adEvent The event fired by the IMA SDK.\n */\nAdUi.prototype.onAdBreakStart = function (adEvent) {\n this.showAdContainer();\n var contentType = adEvent.getAd().getContentType();\n if (contentType === 'application/javascript' && !this.controller.getSettings().showControlsForJSAds) {\n this.controlsDiv.style.display = 'none';\n } else {\n this.controlsDiv.style.display = 'block';\n }\n this.onAdsPlaying();\n // Start with the ad controls minimized.\n this.hideAdControls();\n};\n\n/**\n * Handles ad break ending.\n */\nAdUi.prototype.onAdBreakEnd = function () {\n var currentAd = this.controller.getCurrentAd();\n if (currentAd == null ||\n // hide for post-roll only playlist\n currentAd.isLinear()) {\n // don't hide for non-linear ads\n this.hideAdContainer();\n }\n this.controlsDiv.style.display = 'none';\n this.countdownDiv.innerHTML = '';\n};\n\n/**\n * Handles when all ads have finished playing.\n */\nAdUi.prototype.onAllAdsCompleted = function () {\n this.hideAdContainer();\n};\n\n/**\n * Handles when a linear ad starts.\n */\nAdUi.prototype.onLinearAdStart = function () {\n // Don't bump container when controls are shown\n this.removeClass(this.adContainerDiv, 'bumpable-ima-ad-container');\n this.isAdNonlinear = false;\n};\n\n/**\n * Handles when a non-linear ad starts.\n */\nAdUi.prototype.onNonLinearAdLoad = function () {\n // For non-linear ads that show after a linear ad. For linear ads, we show the\n // ad container in onAdBreakStart to prevent blinking in pods.\n this.adContainerDiv.style.display = 'block';\n // Bump container when controls are shown\n this.addClass(this.adContainerDiv, 'bumpable-ima-ad-container');\n this.isAdNonlinear = true;\n};\nAdUi.prototype.onPlayerEnterFullscreen = function () {\n this.addClass(this.fullscreenDiv, 'ima-fullscreen');\n this.removeClass(this.fullscreenDiv, 'ima-non-fullscreen');\n};\nAdUi.prototype.onPlayerExitFullscreen = function () {\n this.addClass(this.fullscreenDiv, 'ima-non-fullscreen');\n this.removeClass(this.fullscreenDiv, 'ima-fullscreen');\n};\n\n/**\n * Called when the player volume changes.\n *\n * @param {number} volume The new player volume.\n */\nAdUi.prototype.onPlayerVolumeChanged = function (volume) {\n if (volume == 0) {\n this.addClass(this.muteDiv, 'ima-muted');\n this.removeClass(this.muteDiv, 'ima-non-muted');\n this.sliderLevelDiv.style.width = '0%';\n } else {\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.removeClass(this.muteDiv, 'ima-muted');\n this.sliderLevelDiv.style.width = volume * 100 + '%';\n }\n};\n\n/**\n * Shows ad controls on mouseover.\n */\nAdUi.prototype.showAdControls = function () {\n var _this$controller$getS = this.controller.getSettings(),\n disableAdControls = _this$controller$getS.disableAdControls;\n if (!disableAdControls) {\n this.addClass(this.controlsDiv, 'ima-controls-div-showing');\n }\n};\n\n/**\n * Hide the ad controls.\n */\nAdUi.prototype.hideAdControls = function () {\n this.removeClass(this.controlsDiv, 'ima-controls-div-showing');\n};\n\n/**\n * Assigns the unique id and class names to the given element as well as the\n * style class.\n * @param {HTMLElement} element Element that needs the controlName assigned.\n * @param {string} controlName Control name to assign.\n */\nAdUi.prototype.assignControlAttributes = function (element, controlName) {\n element.id = this.controlPrefix + controlName;\n element.className = this.controlPrefix + controlName + ' ' + controlName;\n};\n\n/**\n * Returns a regular expression to test a string for the given className.\n *\n * @param {string} className The name of the class.\n * @return {RegExp} The regular expression used to test for that class.\n */\nAdUi.prototype.getClassRegexp = function (className) {\n // Matches on\n // (beginning of string OR NOT word char)\n // classname\n // (negative lookahead word char OR end of string)\n return new RegExp('(^|[^A-Za-z-])' + className + '((?![A-Za-z-])|$)', 'gi');\n};\n\n/**\n * Returns whether or not the provided element has the provied class in its\n * className.\n * @param {HTMLElement} element Element to tes.t\n * @param {string} className Class to look for.\n * @return {boolean} True if element has className in class list. False\n * otherwise.\n */\nAdUi.prototype.elementHasClass = function (element, className) {\n var classRegexp = this.getClassRegexp(className);\n return classRegexp.test(element.className);\n};\n\n/**\n * Adds a class to the given element if it doesn't already have the class\n * @param {HTMLElement} element Element to which the class will be added.\n * @param {string} classToAdd Class to add.\n */\nAdUi.prototype.addClass = function (element, classToAdd) {\n element.className = element.className.trim() + ' ' + classToAdd;\n};\n\n/**\n * Removes a class from the given element if it has the given class\n *\n * @param {HTMLElement} element Element from which the class will be removed.\n * @param {string} classToRemove Class to remove.\n */\nAdUi.prototype.removeClass = function (element, classToRemove) {\n var classRegexp = this.getClassRegexp(classToRemove);\n element.className = element.className.trim().replace(classRegexp, '');\n};\n\n/**\n * @return {HTMLElement} The div for the ad container.\n */\nAdUi.prototype.getAdContainerDiv = function () {\n return this.adContainerDiv;\n};\n\n/**\n * Changes the flag to show or hide the ad countdown timer.\n *\n * @param {boolean} showCountdownIn Show or hide the countdown timer.\n */\nAdUi.prototype.setShowCountdown = function (showCountdownIn) {\n this.showCountdown = showCountdownIn;\n this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';\n};\n\nvar name = \"videojs-ima\";\nvar version = \"2.3.0\";\nvar license = \"Apache-2.0\";\nvar main = \"./dist/videojs.ima.js\";\nvar module$1 = \"./dist/videojs.ima.es.js\";\nvar author = {\n\tname: \"Google Inc.\"\n};\nvar engines = {\n\tnode: \">=0.8.0\"\n};\nvar scripts = {\n\tcontBuild: \"watch 'npm run rollup:max' src\",\n\tpredevServer: \"echo \\\"Starting up server on localhost:8000.\\\"\",\n\tdevServer: \"npm-run-all -p testServer contBuild\",\n\tlint: \"eslint \\\"src/**/*.js\\\"\",\n\trollup: \"npm-run-all rollup:*\",\n\t\"rollup:max\": \"rollup -c configs/rollup.config.js\",\n\t\"rollup:es\": \"rollup -c configs/rollup.config.es.js\",\n\t\"rollup:min\": \"rollup -c configs/rollup.config.min.js\",\n\tpretest: \"npm run rollup\",\n\tstart: \"npm run devServer\",\n\ttest: \"npm-run-all test:*\",\n\t\"test:vjs6\": \"npm install video.js@6 --no-save && npm-run-all -p -r testServer webdriver\",\n\t\"test:vjs7\": \"npm install video.js@7 --no-save && npm-run-all -p -r testServer webdriver\",\n\ttestServer: \"http-server --cors -p 8000 --silent\",\n\tpreversion: \"node scripts/preversion.js && npm run lint && npm test\",\n\tversion: \"node scripts/version.js\",\n\tpostversion: \"node scripts/postversion.js\",\n\twebdriver: \"mocha test/webdriver/*.js --no-timeouts\"\n};\nvar repository = {\n\ttype: \"git\",\n\turl: \"https://github.com/googleads/videojs-ima\"\n};\nvar files = [\n\t\"CHANGELOG.md\",\n\t\"LICENSE\",\n\t\"README.md\",\n\t\"dist/\",\n\t\"src/\"\n];\nvar peerDependencies = {\n\t\"video.js\": \"^5.19.2 || ^6 || ^7 || ^8\"\n};\nvar dependencies = {\n\t\"@hapi/cryptiles\": \"^5.1.0\",\n\t\"can-autoplay\": \"^3.0.2\",\n\textend: \">=3.0.2\",\n\t\"videojs-contrib-ads\": \"^6.9.0\"\n};\nvar devDependencies = {\n\taxios: \"^1.6.4\",\n\t\"@babel/core\": \"^7.23.7\",\n\t\"@babel/preset-env\": \"^7.23.7\",\n\tchild_process: \"^1.0.2\",\n\tchromedriver: \"^120.0.1\",\n\t\"conventional-changelog-cli\": \"^2.2.2\",\n\t\"conventional-changelog-videojs\": \"^3.0.2\",\n\tecstatic: \"^4.1.4\",\n\teslint: \"^8.8.0\",\n\t\"eslint-config-google\": \"^0.9.1\",\n\t\"eslint-plugin-jsdoc\": \"^3.15.1\",\n\tgeckodriver: \"^4.3.0\",\n\t\"http-server\": \"^14.1.1\",\n\tini: \">=1.3.7\",\n\tmocha: \"^9.2.0\",\n\t\"npm-run-all\": \"^4.1.5\",\n\tpath: \"^0.12.7\",\n\tprotractor: \"^7.0.0\",\n\trimraf: \"^2.7.1\",\n\trollup: \"^0.60.0\",\n\t\"rollup-plugin-babel\": \"^4.4.0\",\n\t\"rollup-plugin-copy\": \"^0.2.3\",\n\t\"rollup-plugin-json\": \"^4.0.0\",\n\t\"rollup-plugin-uglify\": \"^2.0.1\",\n\t\"selenium-webdriver\": \"^4.16.0\",\n\t\"shell-quote\": \"^1.8.1\",\n\t\"uglify-es\": \"^3.3.9\",\n\t\"video.js\": \"^7.17.0\",\n\twatch: \"^0.13.0\",\n\t\"webdriver-manager\": \"^12.1.7\",\n\t\"@xmldom/xmldom\": \"^0.8.10\"\n};\nvar keywords = [\n\t\"videojs\",\n\t\"videojs-plugin\"\n];\nvar pkg = {\n\tname: name,\n\tversion: version,\n\tlicense: license,\n\tmain: main,\n\tmodule: module$1,\n\tauthor: author,\n\tengines: engines,\n\tscripts: scripts,\n\trepository: repository,\n\tfiles: files,\n\tpeerDependencies: peerDependencies,\n\tdependencies: dependencies,\n\tdevDependencies: devDependencies,\n\tkeywords: keywords\n};\n\n/**\n * Implementation of the IMA SDK for the plugin.\n *\n * @param {Object} controller Reference to the parent controller.\n *\n * @constructor\n * @struct\n * @final\n */\nvar SdkImpl = function SdkImpl(controller) {\n /**\n * Plugin controller.\n */\n this.controller = controller;\n\n /**\n * IMA SDK AdDisplayContainer.\n */\n this.adDisplayContainer = null;\n\n /**\n * True if the AdDisplayContainer has been initialized. False otherwise.\n */\n this.adDisplayContainerInitialized = false;\n\n /**\n * IMA SDK AdsLoader\n */\n this.adsLoader = null;\n\n /**\n * IMA SDK AdsManager\n */\n this.adsManager = null;\n\n /**\n * IMA SDK AdsRenderingSettings.\n */\n this.adsRenderingSettings = null;\n\n /**\n * VAST, VMAP, or ad rules response. Used in lieu of fetching a response\n * from an ad tag URL.\n */\n this.adsResponse = null;\n\n /**\n * Current IMA SDK Ad.\n */\n this.currentAd = null;\n\n /**\n * Timer used to track ad progress.\n */\n this.adTrackingTimer = null;\n\n /**\n * True if ALL_ADS_COMPLETED has fired, false until then.\n */\n this.allAdsCompleted = false;\n\n /**\n * True if ads are currently displayed, false otherwise.\n * True regardless of ad pause state if an ad is currently being displayed.\n */\n this.adsActive = false;\n\n /**\n * True if ad is currently playing, false if ad is paused or ads are not\n * currently displayed.\n */\n this.adPlaying = false;\n\n /**\n * True if the ad is muted, false otherwise.\n */\n this.adMuted = false;\n\n /**\n * Listener to be called to trigger manual ad break playback.\n */\n this.adBreakReadyListener = undefined;\n\n /**\n * Tracks whether or not we have already called adsLoader.contentComplete().\n */\n this.contentCompleteCalled = false;\n\n /**\n * True if the ad has timed out.\n */\n this.isAdTimedOut = false;\n\n /**\n * Stores the dimensions for the ads manager.\n */\n this.adsManagerDimensions = {\n width: 0,\n height: 0\n };\n\n /**\n * Boolean flag to enable manual ad break playback.\n */\n this.autoPlayAdBreaks = true;\n if (this.controller.getSettings().autoPlayAdBreaks === false) {\n this.autoPlayAdBreaks = false;\n }\n\n // Set SDK settings from plugin settings.\n if (this.controller.getSettings().locale) {\n /* eslint no-undef: 'error' */\n /* global google */\n google.ima.settings.setLocale(this.controller.getSettings().locale);\n }\n if (this.controller.getSettings().disableFlashAds) {\n google.ima.settings.setDisableFlashAds(this.controller.getSettings().disableFlashAds);\n }\n if (this.controller.getSettings().disableCustomPlaybackForIOS10Plus) {\n google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.controller.getSettings().disableCustomPlaybackForIOS10Plus);\n }\n if (this.controller.getSettings().ppid) {\n google.ima.settings.setPpid(this.controller.getSettings().ppid);\n }\n if (this.controller.getSettings().featureFlags) {\n google.ima.settings.setFeatureFlags(this.controller.getSettings().featureFlags);\n }\n};\n\n/**\n * Creates and initializes the IMA SDK objects.\n */\nSdkImpl.prototype.initAdObjects = function () {\n this.adDisplayContainer = new google.ima.AdDisplayContainer(this.controller.getAdContainerDiv(), this.controller.getContentPlayer());\n this.adsLoader = new google.ima.AdsLoader(this.adDisplayContainer);\n this.adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.ENABLED);\n if (this.controller.getSettings().vpaidAllowed == false) {\n this.adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.DISABLED);\n }\n if (this.controller.getSettings().vpaidMode !== undefined) {\n this.adsLoader.getSettings().setVpaidMode(this.controller.getSettings().vpaidMode);\n }\n if (this.controller.getSettings().locale) {\n this.adsLoader.getSettings().setLocale(this.controller.getSettings().locale);\n }\n if (this.controller.getSettings().numRedirects) {\n this.adsLoader.getSettings().setNumRedirects(this.controller.getSettings().numRedirects);\n }\n if (this.controller.getSettings().sessionId) {\n this.adsLoader.getSettings().setSessionId(this.controller.getSettings().sessionId);\n }\n this.adsLoader.getSettings().setPlayerType('videojs-ima');\n this.adsLoader.getSettings().setPlayerVersion(pkg.version);\n this.adsLoader.getSettings().setAutoPlayAdBreaks(this.autoPlayAdBreaks);\n this.adsLoader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, this.onAdsManagerLoaded.bind(this), false);\n this.adsLoader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, this.onAdsLoaderError.bind(this), false);\n this.controller.playerWrapper.vjsPlayer.trigger({\n type: 'ads-loader',\n adsLoader: this.adsLoader\n });\n};\n\n/**\n * Creates the AdsRequest and request ads through the AdsLoader.\n */\nSdkImpl.prototype.requestAds = function () {\n var adsRequest = new google.ima.AdsRequest();\n if (this.controller.getSettings().adTagUrl) {\n adsRequest.adTagUrl = this.controller.getSettings().adTagUrl;\n } else {\n adsRequest.adsResponse = this.controller.getSettings().adsResponse;\n }\n if (this.controller.getSettings().forceNonLinearFullSlot) {\n adsRequest.forceNonLinearFullSlot = true;\n }\n if (this.controller.getSettings().vastLoadTimeout) {\n adsRequest.vastLoadTimeout = this.controller.getSettings().vastLoadTimeout;\n }\n if (this.controller.getSettings().omidMode) {\n window.console.warn('The additional setting `omidMode` has been removed. ' + 'Use `omidVendorAccess` instead.');\n }\n if (this.controller.getSettings().omidVendorAccess) {\n adsRequest.omidAccessModeRules = {};\n var omidVendorValues = this.controller.getSettings().omidVendorAccess;\n Object.keys(omidVendorValues).forEach(function (vendorKey) {\n adsRequest.omidAccessModeRules[vendorKey] = omidVendorValues[vendorKey];\n });\n }\n adsRequest.linearAdSlotWidth = this.controller.getPlayerWidth();\n adsRequest.linearAdSlotHeight = this.controller.getPlayerHeight();\n adsRequest.nonLinearAdSlotWidth = this.controller.getSettings().nonLinearWidth || this.controller.getPlayerWidth();\n adsRequest.nonLinearAdSlotHeight = this.controller.getSettings().nonLinearHeight || this.controller.getPlayerHeight();\n adsRequest.setAdWillAutoPlay(this.controller.adsWillAutoplay());\n adsRequest.setAdWillPlayMuted(this.controller.adsWillPlayMuted());\n\n // Populate the adsRequestproperties with those provided in the AdsRequest\n // object in the settings.\n var providedAdsRequest = this.controller.getSettings().adsRequest;\n if (providedAdsRequest && _typeof(providedAdsRequest) === 'object') {\n Object.keys(providedAdsRequest).forEach(function (key) {\n adsRequest[key] = providedAdsRequest[key];\n });\n }\n this.adsLoader.requestAds(adsRequest);\n this.controller.playerWrapper.vjsPlayer.trigger({\n type: 'ads-request',\n AdsRequest: adsRequest\n });\n};\n\n/**\n * Listener for the ADS_MANAGER_LOADED event. Creates the AdsManager,\n * sets up event listeners, and triggers the 'adsready' event for\n * videojs-ads-contrib.\n *\n * @param {google.ima.AdsManagerLoadedEvent} adsManagerLoadedEvent Fired when\n * the AdsManager loads.\n */\nSdkImpl.prototype.onAdsManagerLoaded = function (adsManagerLoadedEvent) {\n this.createAdsRenderingSettings();\n this.adsManager = adsManagerLoadedEvent.getAdsManager(this.controller.getContentPlayheadTracker(), this.adsRenderingSettings);\n this.adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, this.onAdError.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.AD_BREAK_READY, this.onAdBreakReady.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, this.onContentPauseRequested.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, this.onContentResumeRequested.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.ALL_ADS_COMPLETED, this.onAllAdsCompleted.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, this.onAdLoaded.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, this.onAdStarted.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, this.onAdComplete.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.SKIPPED, this.onAdComplete.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.LOG, this.onAdLog.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.PAUSED, this.onAdPaused.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.RESUMED, this.onAdResumed.bind(this));\n this.controller.playerWrapper.vjsPlayer.trigger({\n type: 'ads-manager',\n adsManager: this.adsManager\n });\n if (!this.autoPlayAdBreaks) {\n this.initAdsManager();\n }\n var _this$controller$getS = this.controller.getSettings(),\n preventLateAdStart = _this$controller$getS.preventLateAdStart;\n if (!preventLateAdStart) {\n this.controller.onAdsReady();\n } else if (preventLateAdStart && !this.isAdTimedOut) {\n this.controller.onAdsReady();\n }\n if (this.controller.getSettings().adsManagerLoadedCallback) {\n this.controller.getSettings().adsManagerLoadedCallback();\n }\n};\n\n/**\n * Listener for errors fired by the AdsLoader.\n * @param {google.ima.AdErrorEvent} event The error event thrown by the\n * AdsLoader. See\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdError#.Type\n */\nSdkImpl.prototype.onAdsLoaderError = function (event) {\n window.console.warn('AdsLoader error: ' + event.getError());\n this.controller.onErrorLoadingAds(event);\n if (this.adsManager) {\n this.adsManager.destroy();\n }\n};\n\n/**\n * Initialize the ads manager.\n */\nSdkImpl.prototype.initAdsManager = function () {\n try {\n var initWidth = this.controller.getPlayerWidth();\n var initHeight = this.controller.getPlayerHeight();\n this.adsManagerDimensions.width = initWidth;\n this.adsManagerDimensions.height = initHeight;\n this.adsManager.init(initWidth, initHeight, google.ima.ViewMode.NORMAL);\n this.adsManager.setVolume(this.controller.getPlayerVolume());\n this.initializeAdDisplayContainer();\n } catch (adError) {\n this.onAdError(adError);\n }\n};\n\n/**\n * Create AdsRenderingSettings for the IMA SDK.\n */\nSdkImpl.prototype.createAdsRenderingSettings = function () {\n this.adsRenderingSettings = new google.ima.AdsRenderingSettings();\n this.adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;\n if (this.controller.getSettings().adsRenderingSettings) {\n for (var setting in this.controller.getSettings().adsRenderingSettings) {\n if (setting !== '') {\n this.adsRenderingSettings[setting] = this.controller.getSettings().adsRenderingSettings[setting];\n }\n }\n }\n};\n\n/**\n * Listener for errors thrown by the AdsManager.\n * @param {google.ima.AdErrorEvent} adErrorEvent The error event thrown by\n * the AdsManager.\n */\nSdkImpl.prototype.onAdError = function (adErrorEvent) {\n var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;\n window.console.warn('Ad error: ' + errorMessage);\n this.adsManager.destroy();\n this.controller.onAdError(adErrorEvent);\n\n // reset these so consumers don't think we are still in an ad break,\n // but reset them after any prior cleanup happens\n this.adsActive = false;\n this.adPlaying = false;\n};\n\n/**\n * Listener for AD_BREAK_READY. Passes event on to publisher's listener.\n * @param {google.ima.AdEvent} adEvent AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAdBreakReady = function (adEvent) {\n this.adBreakReadyListener(adEvent);\n};\n\n/**\n * Pauses the content video and displays the ad container so ads can play.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onContentPauseRequested = function (adEvent) {\n this.adsActive = true;\n this.adPlaying = true;\n this.controller.onAdBreakStart(adEvent);\n};\n\n/**\n * Resumes content video and hides the ad container.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onContentResumeRequested = function (adEvent) {\n this.adsActive = false;\n this.adPlaying = false;\n this.controller.onAdBreakEnd();\n // Hide controls in case of future non-linear ads. They'll be unhidden in\n // content_pause_requested.\n};\n\n/**\n * Records that ads have completed and calls contentAndAdsEndedListeners\n * if content is also complete.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAllAdsCompleted = function (adEvent) {\n this.allAdsCompleted = true;\n this.controller.onAllAdsCompleted();\n};\n\n/**\n * Starts the content video when a non-linear ad is loaded.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAdLoaded = function (adEvent) {\n if (!adEvent.getAd().isLinear()) {\n this.controller.onNonLinearAdLoad();\n this.controller.playContent();\n }\n};\n\n/**\n * Starts the interval timer to check the current ad time when an ad starts\n * playing.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAdStarted = function (adEvent) {\n this.currentAd = adEvent.getAd();\n if (this.currentAd.isLinear()) {\n this.adTrackingTimer = setInterval(this.onAdPlayheadTrackerInterval.bind(this), 250);\n this.controller.onLinearAdStart();\n } else {\n this.controller.onNonLinearAdStart();\n }\n};\n\n/**\n * Handles an ad click. Puts the player UI in a paused state.\n */\nSdkImpl.prototype.onAdPaused = function () {\n this.controller.onAdsPaused();\n};\n\n/**\n * Syncs controls when an ad resumes.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAdResumed = function (adEvent) {\n this.controller.onAdsResumed();\n};\n\n/**\n * Clears the interval timer for current ad time when an ad completes.\n */\nSdkImpl.prototype.onAdComplete = function () {\n if (this.currentAd.isLinear()) {\n clearInterval(this.adTrackingTimer);\n }\n};\n\n/**\n * Handles ad log messages.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAdLog = function (adEvent) {\n this.controller.onAdLog(adEvent);\n};\n\n/**\n * Gets the current time and duration of the ad and calls the method to\n * update the ad UI.\n */\nSdkImpl.prototype.onAdPlayheadTrackerInterval = function () {\n if (this.adsManager === null) return;\n var remainingTime = this.adsManager.getRemainingTime();\n var duration = this.currentAd.getDuration();\n var currentTime = duration - remainingTime;\n currentTime = currentTime > 0 ? currentTime : 0;\n var totalAds = 0;\n var adPosition;\n if (this.currentAd.getAdPodInfo()) {\n adPosition = this.currentAd.getAdPodInfo().getAdPosition();\n totalAds = this.currentAd.getAdPodInfo().getTotalAds();\n }\n this.controller.onAdPlayheadUpdated(currentTime, remainingTime, duration, adPosition, totalAds);\n};\n\n/**\n * Called by the player wrapper when content completes.\n */\nSdkImpl.prototype.onContentComplete = function () {\n if (this.adsLoader) {\n this.adsLoader.contentComplete();\n this.contentCompleteCalled = true;\n }\n if (this.adsManager && this.adsManager.getCuePoints() && !this.adsManager.getCuePoints().includes(-1) || !this.adsManager) {\n this.controller.onNoPostroll();\n }\n if (this.allAdsCompleted) {\n this.controller.onContentAndAdsCompleted();\n }\n};\n\n/**\n * Called when the player is disposed.\n */\nSdkImpl.prototype.onPlayerDisposed = function () {\n if (this.adTrackingTimer) {\n clearInterval(this.adTrackingTimer);\n }\n if (this.adsManager) {\n this.adsManager.destroy();\n this.adsManager = null;\n }\n};\nSdkImpl.prototype.onPlayerReadyForPreroll = function () {\n if (this.autoPlayAdBreaks) {\n this.initAdsManager();\n try {\n this.controller.showAdContainer();\n // Sync ad volume with content volume.\n this.adsManager.setVolume(this.controller.getPlayerVolume());\n this.adsManager.start();\n } catch (adError) {\n this.onAdError(adError);\n }\n }\n};\nSdkImpl.prototype.onAdTimeout = function () {\n this.isAdTimedOut = true;\n};\nSdkImpl.prototype.onPlayerReady = function () {\n this.initAdObjects();\n if ((this.controller.getSettings().adTagUrl || this.controller.getSettings().adsResponse) && this.controller.getSettings().requestMode === 'onLoad') {\n this.requestAds();\n }\n};\nSdkImpl.prototype.onPlayerEnterFullscreen = function () {\n if (this.adsManager) {\n this.adsManager.resize(window.screen.width, window.screen.height, google.ima.ViewMode.FULLSCREEN);\n }\n};\nSdkImpl.prototype.onPlayerExitFullscreen = function () {\n if (this.adsManager) {\n this.adsManager.resize(this.controller.getPlayerWidth(), this.controller.getPlayerHeight(), google.ima.ViewMode.NORMAL);\n }\n};\n\n/**\n * Called when the player volume changes.\n *\n * @param {number} volume The new player volume.\n */\nSdkImpl.prototype.onPlayerVolumeChanged = function (volume) {\n if (this.adsManager) {\n this.adsManager.setVolume(volume);\n }\n if (volume == 0) {\n this.adMuted = true;\n } else {\n this.adMuted = false;\n }\n};\n\n/**\n * Called when the player wrapper detects that the player has been resized.\n *\n * @param {number} width The post-resize width of the player.\n * @param {number} height The post-resize height of the player.\n */\nSdkImpl.prototype.onPlayerResize = function (width, height) {\n if (this.adsManager) {\n this.adsManagerDimensions.width = width;\n this.adsManagerDimensions.height = height;\n /* eslint no-undef: 'error' */\n this.adsManager.resize(width, height, google.ima.ViewMode.NORMAL);\n }\n};\n\n/**\n * @return {Object} The current ad.\n */\nSdkImpl.prototype.getCurrentAd = function () {\n return this.currentAd;\n};\n\n/**\n * Listener JSDoc for ESLint. This listener can be passed to\n * setAdBreakReadyListener.\n * @callback listener\n */\n\n/**\n * Sets the listener to be called to trigger manual ad break playback.\n * @param {listener} listener The listener to be called to trigger manual ad\n * break playback.\n */\nSdkImpl.prototype.setAdBreakReadyListener = function (listener) {\n this.adBreakReadyListener = listener;\n};\n\n/**\n * @return {boolean} True if an ad is currently playing. False otherwise.\n */\nSdkImpl.prototype.isAdPlaying = function () {\n return this.adPlaying;\n};\n\n/**\n * @return {boolean} True if an ad is currently playing. False otherwise.\n */\nSdkImpl.prototype.isAdMuted = function () {\n return this.adMuted;\n};\n\n/**\n * Pause ads.\n */\nSdkImpl.prototype.pauseAds = function () {\n this.adsManager.pause();\n this.adPlaying = false;\n};\n\n/**\n * Resume ads.\n */\nSdkImpl.prototype.resumeAds = function () {\n this.adsManager.resume();\n this.adPlaying = true;\n};\n\n/**\n * Unmute ads.\n */\nSdkImpl.prototype.unmute = function () {\n this.adsManager.setVolume(1);\n this.adMuted = false;\n};\n\n/**\n * Mute ads.\n */\nSdkImpl.prototype.mute = function () {\n this.adsManager.setVolume(0);\n this.adMuted = true;\n};\n\n/**\n * Set the volume of the ads. 0-1.\n *\n * @param {number} volume The new volume.\n */\nSdkImpl.prototype.setVolume = function (volume) {\n this.adsManager.setVolume(volume);\n if (volume == 0) {\n this.adMuted = true;\n } else {\n this.adMuted = false;\n }\n};\n\n/**\n * Initializes the AdDisplayContainer. On mobile, this must be done as a\n * result of user action.\n */\nSdkImpl.prototype.initializeAdDisplayContainer = function () {\n if (this.adDisplayContainer) {\n if (!this.adDisplayContainerInitialized) {\n this.adDisplayContainer.initialize();\n this.adDisplayContainerInitialized = true;\n }\n }\n};\n\n/**\n * Called by publishers in manual ad break playback mode to start an ad\n * break.\n */\nSdkImpl.prototype.playAdBreak = function () {\n if (!this.autoPlayAdBreaks) {\n this.controller.showAdContainer();\n // Sync ad volume with content volume.\n this.adsManager.setVolume(this.controller.getPlayerVolume());\n this.adsManager.start();\n }\n};\n\n/**\n * Callback JSDoc for ESLint. This callback can be passed to addEventListener.\n * @callback callback\n */\n\n/**\n * Ads an EventListener to the AdsManager. For a list of available events,\n * see\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent#.Type\n * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to\n * listen.\n * @param {callback} callback The method to call when the event is fired.\n */\nSdkImpl.prototype.addEventListener = function (event, callback) {\n if (this.adsManager) {\n this.adsManager.addEventListener(event, callback);\n }\n};\n\n/**\n * Returns the instance of the AdsManager.\n * @return {google.ima.AdsManager} The AdsManager being used by the plugin.\n */\nSdkImpl.prototype.getAdsManager = function () {\n return this.adsManager;\n};\n\n/**\n * Reset the SDK implementation.\n */\nSdkImpl.prototype.reset = function () {\n this.adsActive = false;\n this.adPlaying = false;\n if (this.adTrackingTimer) {\n // If this is called while an ad is playing, stop trying to get that\n // ad's current time.\n clearInterval(this.adTrackingTimer);\n }\n if (this.adsManager) {\n this.adsManager.destroy();\n this.adsManager = null;\n }\n if (this.adsLoader && !this.contentCompleteCalled) {\n this.adsLoader.contentComplete();\n }\n this.contentCompleteCalled = false;\n this.allAdsCompleted = false;\n};\n\n/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * The grand coordinator of the plugin. Facilitates communication between all\n * other plugin classes.\n *\n * @param {Object} player Instance of the video.js player.\n * @param {Object} options Options provided by the implementation.\n * @constructor\n * @struct\n * @final\n */\nvar Controller = function Controller(player, options) {\n /**\n * Stores user-provided settings.\n * @type {Object}\n */\n this.settings = {};\n\n /**\n * Content and ads ended listeners passed by the publisher to the plugin.\n * These will be called when the plugin detects that content *and all\n * ads* have completed. This differs from the contentEndedListeners in that\n * contentEndedListeners will fire between content ending and a post-roll\n * playing, whereas the contentAndAdsEndedListeners will fire after the\n * post-roll completes.\n */\n this.contentAndAdsEndedListeners = [];\n\n /**\n * Whether or not we are running on a mobile platform.\n */\n this.isMobile = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/Android/i);\n\n /**\n * Whether or not we are running on an iOS platform.\n */\n this.isIos = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i);\n this.initWithSettings(options);\n\n /**\n * Stores contrib-ads default settings.\n */\n var contribAdsDefaults = {\n debug: this.settings.debug,\n timeout: this.settings.timeout,\n prerollTimeout: this.settings.prerollTimeout\n };\n var adsPluginSettings = Object.assign({}, contribAdsDefaults, options.contribAdsSettings || {});\n this.playerWrapper = new PlayerWrapper(player, adsPluginSettings, this);\n this.adUi = new AdUi(this);\n this.sdkImpl = new SdkImpl(this);\n};\nController.IMA_DEFAULTS = {\n adLabel: 'Advertisement',\n adLabelNofN: 'of',\n debug: false,\n disableAdControls: false,\n prerollTimeout: 1000,\n preventLateAdStart: false,\n requestMode: 'onLoad',\n showControlsForJSAds: true,\n timeout: 5000\n};\n\n/**\n * Extends the settings to include user-provided settings.\n *\n * @param {Object} options Options to be used in initialization.\n */\nController.prototype.initWithSettings = function (options) {\n this.settings = Object.assign({}, Controller.IMA_DEFAULTS, options || {});\n this.warnAboutDeprecatedSettings();\n\n // Default showing countdown timer to true.\n this.showCountdown = true;\n if (this.settings.showCountdown === false) {\n this.showCountdown = false;\n }\n};\n\n/**\n * Logs console warnings when deprecated settings are used.\n */\nController.prototype.warnAboutDeprecatedSettings = function () {\n var _this = this;\n var deprecatedSettings = ['adWillAutoplay', 'adsWillAutoplay', 'adWillPlayMuted', 'adsWillPlayMuted'];\n deprecatedSettings.forEach(function (setting) {\n if (_this.settings[setting] !== undefined) {\n console.warn('WARNING: videojs.ima setting ' + setting + ' is deprecated');\n }\n });\n};\n\n/**\n * Return the settings object.\n *\n * @return {Object} The settings object.\n */\nController.prototype.getSettings = function () {\n return this.settings;\n};\n\n/**\n * Return whether or not we're in a mobile environment.\n *\n * @return {boolean} True if running on mobile, false otherwise.\n */\nController.prototype.getIsMobile = function () {\n return this.isMobile;\n};\n\n/**\n * Return whether or not we're in an iOS environment.\n *\n * @return {boolean} True if running on iOS, false otherwise.\n */\nController.prototype.getIsIos = function () {\n return this.isIos;\n};\n\n/**\n * Inject the ad container div into the DOM.\n *\n * @param{HTMLElement} adContainerDiv The ad container div.\n */\nController.prototype.injectAdContainerDiv = function (adContainerDiv) {\n this.playerWrapper.injectAdContainerDiv(adContainerDiv);\n};\n\n/**\n * @return {HTMLElement} The div for the ad container.\n */\nController.prototype.getAdContainerDiv = function () {\n return this.adUi.getAdContainerDiv();\n};\n\n/**\n * @return {Object} The content player.\n */\nController.prototype.getContentPlayer = function () {\n return this.playerWrapper.getContentPlayer();\n};\n\n/**\n * Returns the content playhead tracker.\n *\n * @return {Object} The content playhead tracker.\n */\nController.prototype.getContentPlayheadTracker = function () {\n return this.playerWrapper.getContentPlayheadTracker();\n};\n\n/**\n * Requests ads.\n */\nController.prototype.requestAds = function () {\n this.sdkImpl.requestAds();\n};\n\n/**\n * Add or modify a setting.\n *\n * @param {string} key Key to modify\n * @param {Object} value Value to set at key.\n */\nController.prototype.setSetting = function (key, value) {\n this.settings[key] = value;\n};\n\n/**\n * Called when there is an error loading ads.\n *\n * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nController.prototype.onErrorLoadingAds = function (adErrorEvent) {\n this.adUi.onAdError();\n this.playerWrapper.onAdError(adErrorEvent);\n};\n\n/**\n * Called by the ad UI when the play/pause button is clicked.\n */\nController.prototype.onAdPlayPauseClick = function () {\n if (this.sdkImpl.isAdPlaying()) {\n this.adUi.onAdsPaused();\n this.sdkImpl.pauseAds();\n } else {\n this.adUi.onAdsPlaying();\n this.sdkImpl.resumeAds();\n }\n};\n\n/**\n * Called by the ad UI when the mute button is clicked.\n *\n */\nController.prototype.onAdMuteClick = function () {\n if (this.sdkImpl.isAdMuted()) {\n this.playerWrapper.unmute();\n this.adUi.unmute();\n this.sdkImpl.unmute();\n } else {\n this.playerWrapper.mute();\n this.adUi.mute();\n this.sdkImpl.mute();\n }\n};\n\n/**\n * Set the volume of the player and ads. 0-1.\n *\n * @param {number} volume The new volume.\n */\nController.prototype.setVolume = function (volume) {\n this.playerWrapper.setVolume(volume);\n this.sdkImpl.setVolume(volume);\n};\n\n/**\n * @return {number} The volume of the content player.\n */\nController.prototype.getPlayerVolume = function () {\n return this.playerWrapper.getVolume();\n};\n\n/**\n * Toggle fullscreen state.\n */\nController.prototype.toggleFullscreen = function () {\n this.playerWrapper.toggleFullscreen();\n};\n\n/**\n * Relays ad errors to the player wrapper.\n *\n * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nController.prototype.onAdError = function (adErrorEvent) {\n this.adUi.onAdError();\n this.playerWrapper.onAdError(adErrorEvent);\n};\n\n/**\n * Handles ad break starting.\n *\n * @param {Object} adEvent The event fired by the IMA SDK.\n */\nController.prototype.onAdBreakStart = function (adEvent) {\n this.playerWrapper.onAdBreakStart();\n this.adUi.onAdBreakStart(adEvent);\n};\n\n/**\n * Show the ad container.\n */\nController.prototype.showAdContainer = function () {\n this.adUi.showAdContainer();\n};\n\n/**\n * Handles ad break ending.\n */\nController.prototype.onAdBreakEnd = function () {\n this.playerWrapper.onAdBreakEnd();\n this.adUi.onAdBreakEnd();\n};\n\n/**\n * Handles when all ads have finished playing.\n */\nController.prototype.onAllAdsCompleted = function () {\n this.adUi.onAllAdsCompleted();\n this.playerWrapper.onAllAdsCompleted();\n};\n\n/**\n * Handles the SDK firing an ad paused event.\n */\nController.prototype.onAdsPaused = function () {\n this.adUi.onAdsPaused();\n};\n\n/**\n * Handles the SDK firing an ad resumed event.\n */\nController.prototype.onAdsResumed = function () {\n this.adUi.onAdsResumed();\n};\n\n/**\n * Takes data from the sdk impl and passes it to the ad UI to update the UI.\n *\n * @param {number} currentTime Current time of the ad.\n * @param {number} remainingTime Remaining time of the ad.\n * @param {number} duration Duration of the ad.\n * @param {number} adPosition Index of the ad in the pod.\n * @param {number} totalAds Total number of ads in the pod.\n */\nController.prototype.onAdPlayheadUpdated = function (currentTime, remainingTime, duration, adPosition, totalAds) {\n this.adUi.updateAdUi(currentTime, remainingTime, duration, adPosition, totalAds);\n};\n\n/**\n * Handles ad log messages.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the IMA SDK.\n */\nController.prototype.onAdLog = function (adEvent) {\n this.playerWrapper.onAdLog(adEvent);\n};\n\n/**\n * @return {Object} The current ad.\n */\nController.prototype.getCurrentAd = function () {\n return this.sdkImpl.getCurrentAd();\n};\n\n/**\n * Play content.\n */\nController.prototype.playContent = function () {\n this.playerWrapper.play();\n};\n\n/**\n * Handles when a linear ad starts.\n */\nController.prototype.onLinearAdStart = function () {\n this.adUi.onLinearAdStart();\n this.playerWrapper.onAdStart();\n};\n\n/**\n * Handles when a non-linear ad loads.\n */\nController.prototype.onNonLinearAdLoad = function () {\n this.adUi.onNonLinearAdLoad();\n};\n\n/**\n * Handles when a non-linear ad starts.\n */\nController.prototype.onNonLinearAdStart = function () {\n this.adUi.onNonLinearAdLoad();\n this.playerWrapper.onAdStart();\n};\n\n/**\n * Get the player width.\n *\n * @return {number} The width of the player.\n */\nController.prototype.getPlayerWidth = function () {\n return this.playerWrapper.getPlayerWidth();\n};\n\n/**\n * Get the player height.\n *\n * @return {number} The height of the player.\n */\nController.prototype.getPlayerHeight = function () {\n return this.playerWrapper.getPlayerHeight();\n};\n\n/**\n * Tells the player wrapper that ads are ready.\n */\nController.prototype.onAdsReady = function () {\n this.playerWrapper.onAdsReady();\n};\n\n/**\n * Called when the player wrapper detects that the player has been resized.\n *\n * @param {number} width The post-resize width of the player.\n * @param {number} height The post-resize height of the player.\n */\nController.prototype.onPlayerResize = function (width, height) {\n this.sdkImpl.onPlayerResize(width, height);\n};\n\n/**\n * Called by the player wrapper when content completes.\n */\nController.prototype.onContentComplete = function () {\n this.sdkImpl.onContentComplete();\n};\n\n/**\n * Called by the player wrapper when it's time to play a post-roll but we don't\n * have one to play.\n */\nController.prototype.onNoPostroll = function () {\n this.playerWrapper.onNoPostroll();\n};\n\n/**\n * Called when content and all ads have completed.\n */\nController.prototype.onContentAndAdsCompleted = function () {\n for (var index in this.contentAndAdsEndedListeners) {\n if (typeof this.contentAndAdsEndedListeners[index] === 'function') {\n this.contentAndAdsEndedListeners[index]();\n }\n }\n};\n\n/**\n * Called when the player is disposed.\n */\nController.prototype.onPlayerDisposed = function () {\n this.contentAndAdsEndedListeners = [];\n this.sdkImpl.onPlayerDisposed();\n};\n\n/**\n * Called when the player is ready to play a pre-roll.\n */\nController.prototype.onPlayerReadyForPreroll = function () {\n this.sdkImpl.onPlayerReadyForPreroll();\n};\n\n/**\n * Called if the ad times out.\n */\nController.prototype.onAdTimeout = function () {\n this.sdkImpl.onAdTimeout();\n};\n\n/**\n * Called when the player is ready.\n */\nController.prototype.onPlayerReady = function () {\n this.sdkImpl.onPlayerReady();\n};\n\n/**\n * Called when the player enters fullscreen.\n */\nController.prototype.onPlayerEnterFullscreen = function () {\n this.adUi.onPlayerEnterFullscreen();\n this.sdkImpl.onPlayerEnterFullscreen();\n};\n\n/**\n * Called when the player exits fullscreen.\n */\nController.prototype.onPlayerExitFullscreen = function () {\n this.adUi.onPlayerExitFullscreen();\n this.sdkImpl.onPlayerExitFullscreen();\n};\n\n/**\n * Called when the player volume changes.\n *\n * @param {number} volume The new player volume.\n */\nController.prototype.onPlayerVolumeChanged = function (volume) {\n this.adUi.onPlayerVolumeChanged(volume);\n this.sdkImpl.onPlayerVolumeChanged(volume);\n};\n\n/**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ad tag is\n * requested when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adTag The ad tag to be requested when the content loads.\n * Leave blank to use the existing ad tag.\n */\nController.prototype.setContentWithAdTag = function (contentSrc, adTag) {\n this.reset();\n this.settings.adTagUrl = adTag ? adTag : this.settings.adTagUrl;\n this.playerWrapper.changeSource(contentSrc);\n};\n\n/**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ads response is\n * used when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adsResponse The ads response to be requested when the\n * content loads. Leave blank to use the existing ads response.\n */\nController.prototype.setContentWithAdsResponse = function (contentSrc, adsResponse) {\n this.reset();\n this.settings.adsResponse = adsResponse ? adsResponse : this.settings.adsResponse;\n this.playerWrapper.changeSource(contentSrc);\n};\n\n/**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ads request is\n * used when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?Object} adsRequest The ads request to be requested when the\n * content loads. Leave blank to use the existing ads request.\n */\nController.prototype.setContentWithAdsRequest = function (contentSrc, adsRequest) {\n this.reset();\n this.settings.adsRequest = adsRequest ? adsRequest : this.settings.adsRequest;\n this.playerWrapper.changeSource(contentSrc);\n};\n\n/**\n * Resets the state of the plugin.\n */\nController.prototype.reset = function () {\n this.sdkImpl.reset();\n this.playerWrapper.reset();\n this.adUi.reset();\n};\n\n/**\n * Listener JSDoc for ESLint. This listener can be passed to\n * (add|remove)ContentEndedListener.\n * @callback listener\n */\n\n/**\n * Adds a listener for the 'contentended' event of the video player. This should\n * be used instead of setting an 'contentended' listener directly to ensure that\n * the ima can do proper cleanup of the SDK before other event listeners are\n * called.\n * @param {listener} listener The listener to be called when content\n * completes.\n */\nController.prototype.addContentEndedListener = function (listener) {\n this.playerWrapper.addContentEndedListener(listener);\n};\n\n/**\n * Adds a listener that will be called when content and all ads have\n * finished playing.\n * @param {listener} listener The listener to be called when content and ads\n * complete.\n */\nController.prototype.addContentAndAdsEndedListener = function (listener) {\n this.contentAndAdsEndedListeners.push(listener);\n};\n\n/**\n * Sets the listener to be called to trigger manual ad break playback.\n * @param {listener} listener The listener to be called to trigger manual ad\n * break playback.\n */\nController.prototype.setAdBreakReadyListener = function (listener) {\n this.sdkImpl.setAdBreakReadyListener(listener);\n};\n\n/**\n * Changes the flag to show or hide the ad countdown timer.\n *\n * @param {boolean} showCountdownIn Show or hide the countdown timer.\n */\nController.prototype.setShowCountdown = function (showCountdownIn) {\n this.adUi.setShowCountdown(showCountdownIn);\n this.showCountdown = showCountdownIn;\n this.adUi.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';\n};\n\n/**\n * Initializes the AdDisplayContainer. On mobile, this must be done as a\n * result of user action.\n */\nController.prototype.initializeAdDisplayContainer = function () {\n this.sdkImpl.initializeAdDisplayContainer();\n};\n\n/**\n * Called by publishers in manual ad break playback mode to start an ad\n * break.\n */\nController.prototype.playAdBreak = function () {\n this.sdkImpl.playAdBreak();\n};\n\n/**\n * Callback JSDoc for ESLint. This callback can be passed to addEventListener.\n * @callback callback\n */\n\n/**\n * Ads an EventListener to the AdsManager. For a list of available events,\n * see\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent#.Type\n * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to\n * listen.\n * @param {callback} callback The method to call when the event is fired.\n */\nController.prototype.addEventListener = function (event, callback) {\n this.sdkImpl.addEventListener(event, callback);\n};\n\n/**\n * Returns the instance of the AdsManager.\n * @return {google.ima.AdsManager} The AdsManager being used by the plugin.\n */\nController.prototype.getAdsManager = function () {\n return this.sdkImpl.getAdsManager();\n};\n\n/**\n * Returns the instance of the player id.\n * @return {string} The player id.\n */\nController.prototype.getPlayerId = function () {\n return this.playerWrapper.getPlayerId();\n};\n\n/**\n * Changes the ad tag. You will need to call requestAds after this method\n * for the new ads to be requested.\n * @param {?string} adTag The ad tag to be requested the next time\n * requestAds is called.\n */\nController.prototype.changeAdTag = function (adTag) {\n this.reset();\n this.settings.adTagUrl = adTag;\n};\n\n/**\n * Pauses the ad.\n */\nController.prototype.pauseAd = function () {\n this.adUi.onAdsPaused();\n this.sdkImpl.pauseAds();\n};\n\n/**\n * Resumes the ad.\n */\nController.prototype.resumeAd = function () {\n this.adUi.onAdsPlaying();\n this.sdkImpl.resumeAds();\n};\n\n/**\n * Toggles video/ad playback.\n */\nController.prototype.togglePlayback = function () {\n this.playerWrapper.togglePlayback();\n};\n\n/**\n * @return {boolean} true if we expect that ads will autoplay. false otherwise.\n */\nController.prototype.adsWillAutoplay = function () {\n if (this.settings.adsWillAutoplay !== undefined) {\n return this.settings.adsWillAutoplay;\n } else if (this.settings.adWillAutoplay !== undefined) {\n return this.settings.adWillAutoplay;\n } else {\n return !!this.playerWrapper.getPlayerOptions().autoplay;\n }\n};\n\n/**\n * @return {boolean} true if we expect that ads will autoplay. false otherwise.\n */\nController.prototype.adsWillPlayMuted = function () {\n if (this.settings.adsWillPlayMuted !== undefined) {\n return this.settings.adsWillPlayMuted;\n } else if (this.settings.adWillPlayMuted !== undefined) {\n return this.settings.adWillPlayMuted;\n } else if (this.playerWrapper.getPlayerOptions().muted !== undefined) {\n return this.playerWrapper.getPlayerOptions().muted;\n } else {\n return this.playerWrapper.getVolume() == 0;\n }\n};\n\n/**\n * Triggers an event on the VJS player\n * @param {string} name The event name.\n * @param {Object} data The event data.\n */\nController.prototype.triggerPlayerEvent = function (name, data) {\n this.playerWrapper.triggerPlayerEvent(name, data);\n};\n\n/**\n * Copyright 2021 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Wraps the video.js stream player for the plugin.\n *\n * @param {!Object} player Video.js player instance.\n * @param {!Object} adsPluginSettings Settings for the contrib-ads plugin.\n * @param {!DaiController} daiController Reference to the parent controller.\n */\nvar PlayerWrapper$1 = function PlayerWrapper(player, adsPluginSettings, daiController) {\n /**\n * Instance of the video.js player.\n */\n this.vjsPlayer = player;\n\n /**\n * Plugin DAI controller.\n */\n this.daiController = daiController;\n\n /**\n * Video.js control bar.\n */\n this.vjsControls = this.vjsPlayer.getChild('controlBar');\n\n /**\n * Vanilla HTML5 video player underneath the video.js player.\n */\n this.h5Player = null;\n this.vjsPlayer.on('dispose', this.playerDisposedListener.bind(this));\n this.vjsPlayer.on('pause', this.onPause.bind(this));\n this.vjsPlayer.on('play', this.onPlay.bind(this));\n this.vjsPlayer.on('seeked', this.onSeekEnd.bind(this));\n this.vjsPlayer.ready(this.onPlayerReady.bind(this));\n if (!this.vjsPlayer.ads) {\n window.console.warn('You may be using a version of videojs-contrib-ads ' + 'that is not compatible with your version of video.js.');\n }\n this.vjsPlayer.ads(adsPluginSettings);\n};\n\n/**\n * Called in response to the video.js player's 'disposed' event.\n */\nPlayerWrapper$1.prototype.playerDisposedListener = function () {\n this.contentEndedListeners = [];\n this.daiController.onPlayerDisposed();\n};\n\n/**\n * Called on the player 'pause' event. Handles displaying controls during\n * paused ad breaks.\n */\nPlayerWrapper$1.prototype.onPause = function () {\n // This code will run if the stream is paused during an ad break. Since\n // controls are usually hidden during ads, they will now show to allow\n // users to resume ad playback.\n if (this.daiController.isInAdBreak()) {\n this.vjsControls.show();\n }\n};\n\n/**\n * Called on the player 'play' event. Handles hiding controls during\n * ad breaks while playing.\n */\nPlayerWrapper$1.prototype.onPlay = function () {\n if (this.daiController.isInAdBreak()) {\n this.vjsControls.hide();\n }\n};\n\n/**\n * Called on the player's 'seeked' event. Sets up handling for ad break\n * snapback for VOD streams.\n */\nPlayerWrapper$1.prototype.onSeekEnd = function () {\n this.daiController.onSeekEnd(this.vjsPlayer.currentTime());\n};\n\n/**\n * Called on the player's 'ready' event to begin initiating IMA.\n */\nPlayerWrapper$1.prototype.onPlayerReady = function () {\n this.h5Player = document.getElementById(this.getPlayerId()).getElementsByClassName('vjs-tech')[0];\n this.daiController.onPlayerReady();\n};\n\n/**\n * @return {!Object} The stream player.\n */\nPlayerWrapper$1.prototype.getStreamPlayer = function () {\n return this.h5Player;\n};\n\n/**\n * @return {!Object} The video.js player.\n */\nPlayerWrapper$1.prototype.getVjsPlayer = function () {\n return this.vjsPlayer;\n};\n\n/**\n * @return {!Object} The vjs player's options object.\n */\nPlayerWrapper$1.prototype.getPlayerOptions = function () {\n return this.vjsPlayer.options_;\n};\n\n/**\n * Returns the instance of the player id.\n * @return {string} The player id.\n */\nPlayerWrapper$1.prototype.getPlayerId = function () {\n return this.vjsPlayer.id();\n};\n\n/**\n * Handles ad errors.\n *\n * @param {!Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nPlayerWrapper$1.prototype.onAdError = function (adErrorEvent) {\n this.vjsControls.show();\n var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;\n this.vjsPlayer.trigger({\n type: 'adserror',\n data: {\n AdError: errorMessage,\n AdErrorEvent: adErrorEvent\n }\n });\n};\n\n/**\n * Handles ad break starting.\n */\nPlayerWrapper$1.prototype.onAdBreakStart = function () {\n this.vjsControls.hide();\n};\n\n/**\n * Handles ad break ending.\n */\nPlayerWrapper$1.prototype.onAdBreakEnd = function () {\n this.vjsControls.show();\n};\n\n/**\n * Reset the player.\n */\nPlayerWrapper$1.prototype.reset = function () {\n this.vjsControls.show();\n};\n\n/**\n * Copyright 2021 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Implementation of the IMA DAI SDK for the plugin.\n *\n * @param {DaiController!} daiController Reference to the parent DAI\n * controller.\n *\n * @constructor\n * @struct\n * @final\n */\nvar SdkImpl$1 = function SdkImpl(daiController) {\n /**\n * Plugin DAI controller.\n */\n this.daiController = daiController;\n\n /**\n * The html5 stream player.\n */\n this.streamPlayer = null;\n\n /**\n * The videoJS stream player.\n */\n this.vjsPlayer = null;\n\n /**\n * IMA SDK StreamManager\n */\n this.streamManager = null;\n\n /**\n * IMA stream UI settings.\n */\n /* eslint no-undef: 'error' */\n /* global google */\n this.uiSettings = new google.ima.dai.api.UiSettings();\n\n /**\n * If the stream is currently in an ad break.\n */\n this.isAdBreak = false;\n\n /**\n * If the stream is currently seeking from a snapback.\n */\n this.isSnapback = false;\n\n /**\n * Originally seeked to time, to return stream to after ads.\n */\n this.snapForwardTime = 0;\n\n /**\n * Timed metadata for the stream.\n */\n this.timedMetadata;\n\n /**\n * Timed metadata record.\n */\n this.metadataLoaded = {};\n this.SOURCE_TYPES = {\n hls: 'application/x-mpegURL',\n dash: 'application/dash+xml'\n };\n};\n\n/**\n * Creates and initializes the IMA DAI SDK objects.\n */\nSdkImpl$1.prototype.initImaDai = function () {\n this.streamPlayer = this.daiController.getStreamPlayer();\n this.vjsPlayer = this.daiController.getVjsPlayer();\n this.createAdUiDiv();\n if (this.daiController.getSettings().locale) {\n this.uiSettings.setLocale(this.daiController.getSettings().locale);\n }\n this.streamManager = new google.ima.dai.api.StreamManager(this.streamPlayer, this.adUiDiv, this.uiSettings);\n this.streamPlayer.addEventListener('pause', this.onStreamPause);\n this.streamPlayer.addEventListener('play', this.onStreamPlay);\n this.streamManager.addEventListener([google.ima.dai.api.StreamEvent.Type.LOADED, google.ima.dai.api.StreamEvent.Type.ERROR, google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED, google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED], this.onStreamEvent.bind(this), false);\n this.vjsPlayer.textTracks().onaddtrack = this.onAddTrack.bind(this);\n this.vjsPlayer.trigger({\n type: 'stream-manager',\n StreamManager: this.streamManager\n });\n this.requestStream();\n};\n\n/**\n * Called when the video player has metadata to process.\n * @param {Event!} event The event that triggered this call.\n */\nSdkImpl$1.prototype.onAddTrack = function (event) {\n var _this = this;\n var track = event.track;\n if (track.kind === 'metadata') {\n track.mode = 'hidden';\n track.addEventListener('cuechange', function (e) {\n var _iterator = _createForOfIteratorHelper(track.activeCues_),\n _step;\n try {\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var cue = _step.value;\n var metadata = {};\n metadata[cue.value.key] = cue.value.data;\n _this.streamManager.onTimedMetadata(metadata);\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n });\n }\n};\n\n/**\n * Creates the ad UI container.\n */\nSdkImpl$1.prototype.createAdUiDiv = function () {\n var uiDiv = document.createElement('div');\n uiDiv.id = 'ad-ui';\n // 3em is the height of the control bar.\n uiDiv.style.height = 'calc(100% - 3em)';\n this.streamPlayer.parentNode.appendChild(uiDiv);\n this.adUiDiv = uiDiv;\n};\n\n/**\n * Called on pause to update the ad UI.\n */\nSdkImpl$1.prototype.onStreamPause = function () {\n if (this.isAdBreak) {\n this.adUiDiv.style.display = 'none';\n }\n};\n\n/**\n * Called on play to update the ad UI.\n */\nSdkImpl$1.prototype.onStreamPlay = function () {\n if (this.isAdBreak) {\n this.adUiDiv.style.display = 'block';\n }\n};\n\n/**\n * Called on play to update the ad UI.\n * @param {number} currentTime the current time of the stream.\n */\nSdkImpl$1.prototype.onSeekEnd = function (currentTime) {\n var streamType = this.daiController.getSettings().streamType;\n if (streamType === 'live') {\n return;\n }\n if (this.isSnapback) {\n this.isSnapback = false;\n return;\n }\n var previousCuePoint = this.streamManager.previousCuePointForStreamTime(currentTime);\n if (previousCuePoint && !previousCuePoint.played) {\n this.isSnapback = true;\n this.snapForwardTime = currentTime;\n this.vjsPlayer.currentTime(previousCuePoint.start);\n }\n};\n\n/**\n * Handles IMA events.\n * @param {google.ima.StreamEvent!} event the IMA event\n */\nSdkImpl$1.prototype.onStreamEvent = function (event) {\n switch (event.type) {\n case google.ima.dai.api.StreamEvent.Type.LOADED:\n this.loadUrl(event.getStreamData().url);\n break;\n case google.ima.dai.api.StreamEvent.Type.ERROR:\n window.console.warn('Error loading stream, attempting to play backup ' + 'stream. ' + event.getStreamData().errorMessage);\n this.daiController.onErrorLoadingAds(event);\n if (this.daiController.getSettings().fallbackStreamUrl) {\n this.loadurl(this.daiController.getSettings().fallbackStreamUrl);\n }\n break;\n case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:\n this.isAdBreak = true;\n this.adUiDiv.style.display = 'block';\n this.daiController.onAdBreakStart();\n break;\n case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:\n this.isAdBreak = false;\n this.adUiDiv.style.display = 'none';\n this.daiController.onAdBreakEnd();\n if (this.snapForwardTime && this.snapForwardTime > this.vjsPlayer.currentTime()) {\n this.vjsPlayer.currentTime(this.snapForwardTime);\n this.snapForwardTime = 0;\n }\n break;\n default:\n break;\n }\n};\n\n/**\n * Loads the stream URL .\n * @param {string} streamUrl the URL for the stream being loaded.\n */\nSdkImpl$1.prototype.loadUrl = function (streamUrl) {\n this.vjsPlayer.ready(function () {\n var streamFormat = this.daiController.getSettings().streamFormat;\n this.vjsPlayer.src({\n src: streamUrl,\n type: this.SOURCE_TYPES[streamFormat]\n });\n var bookmarkTime = this.daiController.getSettings().bookmarkTime;\n if (bookmarkTime) {\n var startTime = this.streamManager.streamTimeForContentTime(bookmarkTime);\n // Seeking on load triggers the onSeekEnd event, so treat this seek as\n // if it's snapback. Without this, resuming at a bookmark kicks you\n // back to the ad before the bookmark.\n this.isSnapback = true;\n this.vjsPlayer.currentTime(startTime);\n }\n }.bind(this));\n};\n\n/**\n * Creates the AdsRequest and request ads through the AdsLoader.\n */\nSdkImpl$1.prototype.requestStream = function () {\n var streamRequest;\n var streamType = this.daiController.getSettings().streamType;\n if (streamType === 'vod') {\n streamRequest = new google.ima.dai.api.VODStreamRequest();\n streamRequest.contentSourceId = this.daiController.getSettings().cmsId;\n streamRequest.videoId = this.daiController.getSettings().videoId;\n } else if (streamType === 'live') {\n streamRequest = new google.ima.dai.api.LiveStreamRequest();\n streamRequest.assetKey = this.daiController.getSettings().assetKey;\n } else {\n window.console.warn('No valid stream type selected');\n }\n streamRequest.format = this.daiController.getSettings().streamFormat;\n if (this.daiController.getSettings().apiKey) {\n streamRequest.apiKey = this.daiController.getSettings().apiKey;\n }\n if (this.daiController.getSettings().authToken) {\n streamRequest.authToken = this.daiController.getSettings().authToken;\n }\n if (this.daiController.getSettings().adTagParameters) {\n streamRequest.adTagParameters = this.daiController.getSettings().adTagParameters;\n }\n if (this.daiController.getSettings().streamActivityMonitorId) {\n streamRequest.streamActivityMonitorId = this.daiController.getSettings().streamActivityMonitorId;\n }\n if (this.daiController.getSettings().omidMode) {\n streamRequest.omidAccessModeRules = {};\n var omidValues = this.daiController.getSettings().omidMode;\n if (omidValues.FULL) {\n streamRequest.omidAccessModeRules[google.ima.OmidAccessMode.FULL] = omidValues.FULL;\n }\n if (omidValues.DOMAIN) {\n streamRequest.omidAccessModeRules[google.ima.OmidAccessMode.DOMAIN] = omidValues.DOMAIN;\n }\n if (omidValues.LIMITED) {\n streamRequest.omidAccessModeRules[google.ima.OmidAccessMode.LIMITED] = omidValues.LIMITED;\n }\n }\n this.streamManager.requestStream(streamRequest);\n this.vjsPlayer.trigger({\n type: 'stream-request',\n StreamRequest: streamRequest\n });\n};\n\n/**\n * Initiates IMA when the player is ready.\n */\nSdkImpl$1.prototype.onPlayerReady = function () {\n this.initImaDai();\n};\n\n/**\n * Reset the StreamManager when the player is disposed.\n */\nSdkImpl$1.prototype.onPlayerDisposed = function () {\n if (this.streamManager) {\n this.streamManager.reset();\n }\n};\n\n/**\n * Returns the instance of the StreamManager.\n * @return {google.ima.StreamManager!} The StreamManager being used by the\n * plugin.\n */\nSdkImpl$1.prototype.getStreamManager = function () {\n return this.StreamManager;\n};\n\n/**\n * Reset the SDK implementation.\n */\nSdkImpl$1.prototype.reset = function () {\n if (this.StreamManager) {\n this.StreamManager.reset();\n }\n};\n\n/**\n * Copyright 2021 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * The coordinator for the DAI portion of the plugin. Facilitates\n * communication between all other plugin classes.\n *\n * @param {Object!} player Instance of the video.js player.\n * @param {Object!} options Options provided by the implementation.\n * @constructor\n * @struct\n * @final\n */\nvar DaiController = function DaiController(player, options) {\n /**\n * If the stream is currently in an ad break.\n * @type {boolean}\n */\n this.inAdBreak = false;\n\n /**\n * Stores user-provided settings.\n * @type {Object!}\n */\n this.settings = {};\n\n /**\n * Whether or not we are running on a mobile platform.\n */\n this.isMobile = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/Android/i);\n\n /**\n * Whether or not we are running on an iOS platform.\n */\n this.isIos = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i);\n this.initWithSettings(options);\n\n /**\n * Stores contrib-ads default settings.\n */\n var contribAdsDefaults = {\n debug: this.settings.debug,\n timeout: this.settings.timeout,\n prerollTimeout: this.settings.prerollTimeout\n };\n var adsPluginSettings = Object.assign({}, contribAdsDefaults, options.contribAdsSettings || {});\n this.playerWrapper = new PlayerWrapper$1(player, adsPluginSettings, this);\n this.sdkImpl = new SdkImpl$1(this);\n};\nDaiController.IMA_DEFAULTS = {\n adLabel: 'Advertisement',\n adLabelNofN: 'of',\n debug: false,\n disableAdControls: false,\n showControlsForJSAds: true\n};\n\n/**\n * Extends the settings to include user-provided settings.\n *\n * @param {Object!} options Options to be used in initialization.\n */\nDaiController.prototype.initWithSettings = function (options) {\n this.settings = Object.assign({}, DaiController.IMA_DEFAULTS, options || {});\n this.warnAboutDeprecatedSettings();\n\n // Default showing countdown timer to true.\n this.showCountdown = true;\n if (this.settings.showCountdown === false) {\n this.showCountdown = false;\n }\n};\n\n/**\n * Logs console warnings when deprecated settings are used.\n */\nDaiController.prototype.warnAboutDeprecatedSettings = function () {\n var _this = this;\n var deprecatedSettings = [\n // Currently no DAI plugin settings are deprecated.\n ];\n deprecatedSettings.forEach(function (setting) {\n if (_this.settings[setting] !== undefined) {\n console.warn('WARNING: videojs.imaDai setting ' + setting + ' is deprecated');\n }\n });\n};\n\n/**\n * Return the settings object.\n *\n * @return {Object!} The settings object.\n */\nDaiController.prototype.getSettings = function () {\n return this.settings;\n};\n\n/**\n * Return whether or not we're in a mobile environment.\n *\n * @return {boolean} True if running on mobile, false otherwise.\n */\nDaiController.prototype.getIsMobile = function () {\n return this.isMobile;\n};\n\n/**\n * Return whether or not we're in an iOS environment.\n *\n * @return {boolean} True if running on iOS, false otherwise.\n */\nDaiController.prototype.getIsIos = function () {\n return this.isIos;\n};\n\n/**\n * @return {Object!} The html5 player.\n */\nDaiController.prototype.getStreamPlayer = function () {\n return this.playerWrapper.getStreamPlayer();\n};\n\n/**\n * @return {Object!} The video.js player.\n */\nDaiController.prototype.getVjsPlayer = function () {\n return this.playerWrapper.getVjsPlayer();\n};\n\n/**\n * Requests the stream.\n */\nDaiController.prototype.requestStream = function () {\n this.sdkImpl.requestStream();\n};\n\n/**\n * Add or modify a setting.\n *\n * @param {string} key Key to modify\n * @param {Object!} value Value to set at key.\n*/\nDaiController.prototype.setSetting = function (key, value) {\n this.settings[key] = value;\n};\n\n/**\n * Called when there is an error loading ads.\n *\n * @param {Object!} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nDaiController.prototype.onErrorLoadingAds = function (adErrorEvent) {\n this.playerWrapper.onAdError(adErrorEvent);\n};\n\n/**\n * Relays ad errors to the player wrapper.\n *\n * @param {Object!} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nDaiController.prototype.onAdError = function (adErrorEvent) {\n this.playerWrapper.onAdError(adErrorEvent);\n};\n\n/**\n * Signals player that an ad break has started.\n */\nDaiController.prototype.onAdBreakStart = function () {\n this.inAdBreak = true;\n this.playerWrapper.onAdBreakStart();\n};\n\n/**\n * Signals player that an ad break has ended.\n */\nDaiController.prototype.onAdBreakEnd = function () {\n this.inAdBreak = false;\n this.playerWrapper.onAdBreakEnd();\n};\n\n/**\n * Called when the player is disposed.\n */\nDaiController.prototype.onPlayerDisposed = function () {\n this.contentAndAdsEndedListeners = [];\n this.sdkImpl.onPlayerDisposed();\n};\n\n/**\n * Returns if the stream is currently in an ad break.\n * @return {boolean} If the stream is currently in an ad break.\n */\nDaiController.prototype.isInAdBreak = function () {\n return this.inAdBreak;\n};\n\n/**\n * Called on seek end to check for ad snapback.\n * @param {number} currentTime the current time of the stream.\n */\nDaiController.prototype.onSeekEnd = function (currentTime) {\n this.sdkImpl.onSeekEnd(currentTime);\n};\n\n/**\n * Called when the player is ready.\n */\nDaiController.prototype.onPlayerReady = function () {\n this.sdkImpl.onPlayerReady();\n};\n\n/**\n * Resets the state of the plugin.\n */\nDaiController.prototype.reset = function () {\n this.sdkImpl.reset();\n this.playerWrapper.reset();\n};\n\n/**\n * Adds an EventListener to the StreamManager. For a list of available events,\n * see\n * https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/html5/reference/js/StreamEvent\n * @param {google.ima.StreamEvent.Type!} event The AdEvent.Type for which to\n * listen.\n * @param {callback!} callback The method to call when the event is fired.\n */\nDaiController.prototype.addEventListener = function (event, callback) {\n this.sdkImpl.addEventListener(event, callback);\n};\n\n/**\n * Returns the instance of the StreamManager.\n * @return {google.ima.StreamManager!} The StreamManager being used by the\n * plugin.\n */\nDaiController.prototype.getStreamManager = function () {\n return this.sdkImpl.getStreamManager();\n};\n\n/**\n * Returns the instance of the player id.\n * @return {string} The player id.\n */\nDaiController.prototype.getPlayerId = function () {\n return this.playerWrapper.getPlayerId();\n};\n\n/**\n * @return {boolean} true if we expect that the stream will autoplay. false\n * otherwise.\n */\nDaiController.prototype.streamWillAutoplay = function () {\n if (this.settings.streamWillAutoplay !== undefined) {\n return this.settings.streamWillAutoplay;\n } else {\n return !!this.playerWrapper.getPlayerOptions().autoplay;\n }\n};\n\n/**\n * Triggers an event on the VJS player\n * @param {string} name The event name.\n * @param {Object!} data The event data.\n */\nDaiController.prototype.triggerPlayerEvent = function (name, data) {\n this.playerWrapper.triggerPlayerEvent(name, data);\n};\n\n/**\n * Exposes the ImaPlugin to a publisher implementation.\n *\n * @param {Object} player Instance of the video.js player to which this plugin\n * will be added.\n * @param {Object} options Options provided by the implementation.\n * @constructor\n * @struct\n * @final\n */\nvar ImaPlugin = function ImaPlugin(player, options) {\n this.controller = new Controller(player, options);\n\n /**\n * Listener JSDoc for ESLint. This listener can be passed to\n * addContent(AndAds)EndedListener.\n * @callback listener\n */\n\n /**\n * Adds a listener that will be called when content and all ads have\n * finished playing.\n * @param {listener} listener The listener to be called when content and ads\n * complete.\n */\n this.addContentAndAdsEndedListener = function (listener) {\n this.controller.addContentAndAdsEndedListener(listener);\n }.bind(this);\n\n /**\n * Adds a listener for the 'contentended' event of the video player. This\n * should be used instead of setting an 'contentended' listener directly to\n * ensure that the ima can do proper cleanup of the SDK before other event\n * listeners are called.\n * @param {listener} listener The listener to be called when content\n * completes.\n */\n this.addContentEndedListener = function (listener) {\n this.controller.addContentEndedListener(listener);\n }.bind(this);\n\n /**\n * Callback JSDoc for ESLint. This callback can be passed to addEventListener.\n * @callback callback\n */\n\n /**\n * Ads an EventListener to the AdsManager. For a list of available events,\n * see\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent#.Type\n * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to\n * listen.\n * @param {callback} callback The method to call when the event is fired.\n */\n this.addEventListener = function (event, callback) {\n this.controller.addEventListener(event, callback);\n }.bind(this);\n\n /**\n * Changes the ad tag. You will need to call requestAds after this method\n * for the new ads to be requested.\n * @param {?string} adTag The ad tag to be requested the next time requestAds\n * is called.\n */\n this.changeAdTag = function (adTag) {\n this.controller.changeAdTag(adTag);\n }.bind(this);\n\n /**\n * Returns the instance of the AdsManager.\n * @return {google.ima.AdsManager} The AdsManager being used by the plugin.\n */\n this.getAdsManager = function () {\n return this.controller.getAdsManager();\n }.bind(this);\n\n /**\n * Initializes the AdDisplayContainer. On mobile, this must be done as a\n * result of user action.\n */\n this.initializeAdDisplayContainer = function () {\n this.controller.initializeAdDisplayContainer();\n }.bind(this);\n\n /**\n * Pauses the ad.\n */\n this.pauseAd = function () {\n this.controller.pauseAd();\n }.bind(this);\n\n /**\n * Called by publishers in manual ad break playback mode to start an ad\n * break.\n */\n this.playAdBreak = function () {\n this.controller.playAdBreak();\n }.bind(this);\n\n /**\n * Creates the AdsRequest and request ads through the AdsLoader.\n */\n this.requestAds = function () {\n this.controller.requestAds();\n }.bind(this);\n\n /**\n * Resumes the ad.\n */\n this.resumeAd = function () {\n this.controller.resumeAd();\n }.bind(this);\n\n /**\n * Sets the listener to be called to trigger manual ad break playback.\n * @param {listener} listener The listener to be called to trigger manual ad\n * break playback.\n */\n this.setAdBreakReadyListener = function (listener) {\n this.controller.setAdBreakReadyListener(listener);\n }.bind(this);\n\n /**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ad tag is\n * requested when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adTag The ad tag to be requested when the content loads.\n * Leave blank to use the existing ad tag.\n */\n this.setContentWithAdTag = function (contentSrc, adTag) {\n this.controller.setContentWithAdTag(contentSrc, adTag);\n }.bind(this);\n\n /**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ads response is\n * used when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adsResponse The ads response to be requested when the\n * content loads. Leave blank to use the existing ads response.\n */\n this.setContentWithAdsResponse = function (contentSrc, adsResponse) {\n this.controller.setContentWithAdsResponse(contentSrc, adsResponse);\n }.bind(this);\n\n /**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ads request is\n * used when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?Object} adsRequest The ads request to be requested when the\n * content loads. Leave blank to use the existing ads request.\n */\n this.setContentWithAdsRequest = function (contentSrc, adsRequest) {\n this.controller.setContentWithAdsRequest(contentSrc, adsRequest);\n }.bind(this);\n\n /**\n * Changes the flag to show or hide the ad countdown timer.\n *\n * @param {boolean} showCountdownIn Show or hide the countdown timer.\n */\n this.setShowCountdown = function (showCountdownIn) {\n this.controller.setShowCountdown(showCountdownIn);\n }.bind(this);\n};\n\n/**\n * Exposes the ImaDaiPlugin to a publisher implementation.\n *\n * @param {Object} player Instance of the video.js player to which this plugin\n * will be added.\n * @param {Object} options Options provided by the implementation.\n * @constructor\n * @struct\n * @final\n */\nvar ImaDaiPlugin = function ImaDaiPlugin(player, options) {\n this.controller = new DaiController(player, options);\n\n /**\n * Adds a listener that will be called when content and all ads in the\n * stream have finished playing. VOD stream only.\n * @param {listener} listener The listener to be called when content and ads\n * complete.\n */\n this.streamEndedListener = function (listener) {\n this.controller.addStreamEndedListener(listener);\n }.bind(this);\n\n /**\n * Adds an EventListener to the StreamManager.\n * @param {google.ima.StreamEvent.Type} event The StreamEvent.Type for which\n * to listen.\n * @param {callback} callback The method to call when the event is fired.\n */\n this.addEventListener = function (event, callback) {\n this.controller.addEventListener(event, callback);\n }.bind(this);\n\n /**\n * Returns the instance of the StreamManager.\n * @return {google.ima.StreamManager} The StreamManager being used by the\n * plugin.\n */\n this.getStreamManager = function () {\n return this.controller.getStreamManager();\n }.bind(this);\n};\n\n/**\n * Initializes the plugin for client-side ads.\n * @param {Object} options Plugin option set on initiation.\n */\nvar init = function init(options) {\n /* eslint no-invalid-this: 'off' */\n this.ima = new ImaPlugin(this, options);\n};\n\n/**\n * LiveStream class used for DAI live streams.\n */\nvar LiveStream = /*#__PURE__*/_createClass(\n/**\n * LiveStream class constructor used for DAI live streams.\n * @param {string} streamFormat stream format, plugin currently supports only\n * 'hls' streams.\n * @param {string} assetKey live stream's asset key.\n */\nfunction LiveStream(streamFormat, assetKey) {\n _classCallCheck(this, LiveStream);\n streamFormat = streamFormat.toLowerCase();\n if (streamFormat !== 'hls' && streamFormat !== 'dash') {\n window.console.error('VodStream error: incorrect streamFormat.');\n return;\n } else if (streamFormat === 'dash') {\n window.console.error('streamFormat error: DASH streams are not' + 'currently supported by this plugin.');\n return;\n } else if (typeof assetKey !== 'string') {\n window.console.error('assetKey error: value must be string.');\n return;\n }\n this.streamFormat = streamFormat;\n this.assetKey = assetKey;\n});\n/**\n * VodStream class used for DAI VOD streams.\n */\nvar VodStream = /*#__PURE__*/_createClass(\n/**\n * VodStream class constructor used for DAI VOD streams.\n * @param {string} streamFormat stream format, plugin currently supports only\n * 'hls' streams.\n * @param {string} cmsId VOD stream's CMS ID.\n * @param {string} videoId VOD stream's video ID.\n */\nfunction VodStream(streamFormat, cmsId, videoId) {\n _classCallCheck(this, VodStream);\n streamFormat = streamFormat.toLowerCase();\n if (streamFormat !== 'hls' && streamFormat !== 'dash') {\n window.console.error('VodStream error: incorrect streamFormat.');\n return;\n } else if (streamFormat === 'dash') {\n window.console.error('streamFormat error: DASH streams are not' + 'currently supported by this plugin.');\n return;\n } else if (typeof cmsId !== 'string') {\n window.console.error('cmsId error: value must be string.');\n return;\n } else if (typeof videoId !== 'string') {\n window.console.error('videoId error: value must be string.');\n return;\n }\n this.streamFormat = streamFormat;\n this.cmsId = cmsId;\n this.videoId = videoId;\n});\n/**\n * Initializes the plugin for DAI ads.\n * @param {Object} stream Accepts either an instance of the LiveStream or\n * VodStream classes.\n * @param {Object} options Plugin option set on initiation.\n */\nvar initDai = function initDai(stream, options) {\n if (stream instanceof LiveStream) {\n options.streamType = 'live';\n options.assetKey = stream.assetKey;\n } else if (stream instanceof VodStream) {\n options.streamType = 'vod';\n options.cmsId = stream.cmsId;\n options.videoId = stream.videoId;\n } else {\n window.console.error('initDai() first parameter must be an instance of LiveStream or ' + 'VodStream.');\n return;\n }\n options.streamFormat = stream.streamFormat;\n /* eslint no-invalid-this: 'off' */\n this.imaDai = new ImaDaiPlugin(this, options);\n};\nvar registerPlugin = (video_js__WEBPACK_IMPORTED_MODULE_0___default().registerPlugin) || (video_js__WEBPACK_IMPORTED_MODULE_0___default().plugin);\nregisterPlugin('ima', init);\nregisterPlugin('imaDai', initDai);\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ImaPlugin);\n\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/videojs-ima/dist/videojs.ima.es.js?");
|
|
76
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ LiveStream: () => (/* binding */ LiveStream),\n/* harmony export */ VodStream: () => (/* binding */ VodStream),\n/* harmony export */ \"default\": () => (/* binding */ ImaPlugin)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n\n\nfunction _arrayLikeToArray(r, a) {\n (null == a || a > r.length) && (a = r.length);\n for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];\n return n;\n}\nfunction _classCallCheck(a, n) {\n if (!(a instanceof n)) throw new TypeError(\"Cannot call a class as a function\");\n}\nfunction _createClass(e, r, t) {\n return Object.defineProperty(e, \"prototype\", {\n writable: false\n }), e;\n}\nfunction _createForOfIteratorHelper(r, e) {\n var t = \"undefined\" != typeof Symbol && r[Symbol.iterator] || r[\"@@iterator\"];\n if (!t) {\n if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {\n t && (r = t);\n var n = 0,\n F = function () {};\n return {\n s: F,\n n: function () {\n return n >= r.length ? {\n done: true\n } : {\n done: false,\n value: r[n++]\n };\n },\n e: function (r) {\n throw r;\n },\n f: F\n };\n }\n throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n }\n var o,\n a = true,\n u = false;\n return {\n s: function () {\n t = t.call(r);\n },\n n: function () {\n var r = t.next();\n return a = r.done, r;\n },\n e: function (r) {\n u = true, o = r;\n },\n f: function () {\n try {\n a || null == t.return || t.return();\n } finally {\n if (u) throw o;\n }\n }\n };\n}\nfunction _typeof(o) {\n \"@babel/helpers - typeof\";\n\n return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (o) {\n return typeof o;\n } : function (o) {\n return o && \"function\" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? \"symbol\" : typeof o;\n }, _typeof(o);\n}\nfunction _unsupportedIterableToArray(r, a) {\n if (r) {\n if (\"string\" == typeof r) return _arrayLikeToArray(r, a);\n var t = {}.toString.call(r).slice(8, -1);\n return \"Object\" === t && r.constructor && (t = r.constructor.name), \"Map\" === t || \"Set\" === t ? Array.from(r) : \"Arguments\" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;\n }\n}\n\n/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Wraps the video.js player for the plugin.\n *\n * @param {Object} player Video.js player instance.\n * @param {Object} adsPluginSettings Settings for the contrib-ads plugin.\n * @param {Controller} controller Reference to the parent controller.\n */\nvar PlayerWrapper$1 = function PlayerWrapper(player, adsPluginSettings, controller) {\n /**\n * Instance of the video.js player.\n */\n this.vjsPlayer = player;\n\n /**\n * Plugin controller.\n */\n this.controller = controller;\n\n /**\n * Timer used to track content progress.\n */\n this.contentTrackingTimer = null;\n\n /**\n * True if our content video has completed, false otherwise.\n */\n this.contentComplete = false;\n\n /**\n * Handle to interval that repeatedly updates current time.\n */\n this.updateTimeIntervalHandle = null;\n\n /**\n * Interval (ms) to check for player resize for fluid support.\n */\n this.updateTimeInterval = 1000;\n\n /**\n * Handle to interval that repeatedly checks for seeking.\n */\n this.seekCheckIntervalHandle = null;\n\n /**\n * Interval (ms) on which to check if the user is seeking through the\n * content.\n */\n this.seekCheckInterval = 1000;\n\n /**\n * Handle to interval that repeatedly checks for player resize.\n */\n this.resizeCheckIntervalHandle = null;\n\n /**\n * Interval (ms) to check for player resize for fluid support.\n */\n this.resizeCheckInterval = 250;\n\n /**\n * Threshold by which to judge user seeking. We check every 1000 ms to see\n * if the user is seeking. In order for us to decide that they are *not*\n * seeking, the content video playhead must only change by 900-1100 ms\n * between checks. Any greater change and we assume the user is seeking\n * through the video.\n */\n this.seekThreshold = 100;\n\n /**\n * Content ended listeners passed by the publisher to the plugin. Publishers\n * should allow the plugin to handle content ended to ensure proper support\n * of custom ad playback.\n */\n this.contentEndedListeners = [];\n\n /**\n * Stores the content source so we can re-populate it manually after a\n * post-roll on iOS.\n */\n this.contentSource = '';\n\n /**\n * Stores the content source type so we can re-populate it manually after a\n * post-roll.\n */\n this.contentSourceType = '';\n\n /**\n * Stores data for the content playhead tracker.\n */\n this.contentPlayheadTracker = {\n currentTime: 0,\n previousTime: 0,\n seeking: false,\n duration: 0\n };\n\n /**\n * Player dimensions. Used in our resize check.\n */\n this.vjsPlayerDimensions = {\n width: this.getPlayerWidth(),\n height: this.getPlayerHeight()\n };\n\n /**\n * Video.js control bar.\n */\n this.vjsControls = this.vjsPlayer.getChild('controlBar');\n\n /**\n * Vanilla HTML5 video player underneath the video.js player.\n */\n this.h5Player = null;\n this.vjsPlayer.one('play', this.setUpPlayerIntervals.bind(this));\n this.boundContentEndedListener = this.localContentEndedListener.bind(this);\n this.vjsPlayer.on('readyforpostroll', this.boundContentEndedListener);\n this.vjsPlayer.on('dispose', this.playerDisposedListener.bind(this));\n this.vjsPlayer.on('readyforpreroll', this.onReadyForPreroll.bind(this));\n this.vjsPlayer.on('adtimeout', this.onAdTimeout.bind(this));\n this.vjsPlayer.ready(this.onPlayerReady.bind(this));\n if (this.controller.getSettings().requestMode === 'onPlay') {\n this.vjsPlayer.one('play', this.controller.requestAds.bind(this.controller));\n }\n if (!this.vjsPlayer.ads) {\n window.console.warn('You may be using a version of videojs-contrib-ads ' + 'that is not compatible with your version of video.js.');\n }\n this.vjsPlayer.ads(adsPluginSettings);\n};\n\n/**\n * Set up the intervals we use on the player.\n */\nPlayerWrapper$1.prototype.setUpPlayerIntervals = function () {\n /**\n * Clear old interval handers in case the method was called more than once\n */\n if (this.updateTimeIntervalHandle) {\n clearInterval(this.updateTimeIntervalHandle);\n }\n if (this.seekCheckIntervalHandle) {\n clearInterval(this.seekCheckIntervalHandle);\n }\n if (this.resizeCheckIntervalHandle) {\n clearInterval(this.resizeCheckIntervalHandle);\n }\n this.updateTimeIntervalHandle = setInterval(this.updateCurrentTime.bind(this), this.updateTimeInterval);\n this.seekCheckIntervalHandle = setInterval(this.checkForSeeking.bind(this), this.seekCheckInterval);\n this.resizeCheckIntervalHandle = setInterval(this.checkForResize.bind(this), this.resizeCheckInterval);\n};\n\n/**\n * Updates the current time of the video\n */\nPlayerWrapper$1.prototype.updateCurrentTime = function () {\n if (!this.contentPlayheadTracker.seeking) {\n this.contentPlayheadTracker.currentTime = this.vjsPlayer.currentTime();\n }\n};\n\n/**\n * Detects when the user is seeking through a video.\n * This is used to prevent mid-rolls from playing while a user is seeking.\n *\n * There *is* a seeking property of the HTML5 video element, but it's not\n * properly implemented on all platforms (e.g. mobile safari), so we have to\n * check ourselves to be sure.\n */\nPlayerWrapper$1.prototype.checkForSeeking = function () {\n var tempCurrentTime = this.vjsPlayer.currentTime();\n var diff = (tempCurrentTime - this.contentPlayheadTracker.previousTime) * 1000;\n if (Math.abs(diff) > this.seekCheckInterval + this.seekThreshold) {\n this.contentPlayheadTracker.seeking = true;\n } else {\n this.contentPlayheadTracker.seeking = false;\n }\n this.contentPlayheadTracker.previousTime = this.vjsPlayer.currentTime();\n};\n\n/**\n * Detects when the player is resized (for fluid support) and resizes the\n * ads manager to match.\n */\nPlayerWrapper$1.prototype.checkForResize = function () {\n var currentWidth = this.getPlayerWidth();\n var currentHeight = this.getPlayerHeight();\n if (currentWidth != this.vjsPlayerDimensions.width || currentHeight != this.vjsPlayerDimensions.height) {\n this.vjsPlayerDimensions.width = currentWidth;\n this.vjsPlayerDimensions.height = currentHeight;\n this.controller.onPlayerResize(currentWidth, currentHeight);\n }\n};\n\n/**\n * Local content ended listener for contentComplete.\n */\nPlayerWrapper$1.prototype.localContentEndedListener = function () {\n if (!this.contentComplete) {\n this.contentComplete = true;\n this.controller.onContentComplete();\n }\n for (var index in this.contentEndedListeners) {\n if (typeof this.contentEndedListeners[index] === 'function') {\n this.contentEndedListeners[index]();\n }\n }\n if (this.vjsPlayer.el()) {\n this.vjsPlayer.one('play', this.setUpPlayerIntervals.bind(this));\n }\n};\n\n/**\n * Called when it's time to play a post-roll but we don't have one to play.\n */\nPlayerWrapper$1.prototype.onNoPostroll = function () {\n this.vjsPlayer.trigger('nopostroll');\n};\n\n/**\n * Detects when the video.js player has been disposed.\n */\nPlayerWrapper$1.prototype.playerDisposedListener = function () {\n this.contentEndedListeners = [];\n this.controller.onPlayerDisposed();\n this.contentComplete = true;\n this.vjsPlayer.off('readyforpostroll', this.boundContentEndedListener);\n\n // Bug fix: https://github.com/googleads/videojs-ima/issues/306\n if (this.vjsPlayer.ads.adTimeoutTimeout) {\n clearTimeout(this.vjsPlayer.ads.adTimeoutTimeout);\n }\n var intervalsToClear = [this.updateTimeIntervalHandle, this.seekCheckIntervalHandle, this.resizeCheckIntervalHandle];\n for (var index in intervalsToClear) {\n if (intervalsToClear[index]) {\n clearInterval(intervalsToClear[index]);\n }\n }\n};\n\n/**\n * Start ad playback, or content video playback in the absence of a\n * pre-roll.\n */\nPlayerWrapper$1.prototype.onReadyForPreroll = function () {\n this.controller.onPlayerReadyForPreroll();\n};\n\n/**\n * Detects if the ad has timed out.\n */\nPlayerWrapper$1.prototype.onAdTimeout = function () {\n this.controller.onAdTimeout();\n};\n\n/**\n * Called when the player fires its 'ready' event.\n */\nPlayerWrapper$1.prototype.onPlayerReady = function () {\n this.h5Player = document.getElementById(this.getPlayerId()).getElementsByClassName('vjs-tech')[0];\n\n // Detect inline options\n if (this.h5Player.hasAttribute('autoplay')) {\n this.controller.setSetting('adWillAutoPlay', true);\n }\n\n // Sync ad volume with player volume.\n this.onVolumeChange();\n this.vjsPlayer.on('fullscreenchange', this.onFullscreenChange.bind(this));\n this.vjsPlayer.on('volumechange', this.onVolumeChange.bind(this));\n this.controller.onPlayerReady();\n};\n\n/**\n * Listens for the video.js player to change its fullscreen status. This\n * keeps the fullscreen-ness of the AdContainer in sync with the player.\n */\nPlayerWrapper$1.prototype.onFullscreenChange = function () {\n if (this.vjsPlayer.isFullscreen()) {\n this.controller.onPlayerEnterFullscreen();\n } else {\n this.controller.onPlayerExitFullscreen();\n }\n};\n\n/**\n * Listens for the video.js player to change its volume. This keeps the ad\n * volume in sync with the content volume if the volume of the player is\n * changed while content is playing.\n */\nPlayerWrapper$1.prototype.onVolumeChange = function () {\n var newVolume = this.vjsPlayer.muted() ? 0 : this.vjsPlayer.volume();\n this.controller.onPlayerVolumeChanged(newVolume);\n};\n\n/**\n * Inject the ad container div into the DOM.\n *\n * @param{HTMLElement} adContainerDiv The ad container div.\n */\nPlayerWrapper$1.prototype.injectAdContainerDiv = function (adContainerDiv) {\n this.vjsControls.el().parentNode.appendChild(adContainerDiv);\n};\n\n/**\n * @return {Object} The content player.\n */\nPlayerWrapper$1.prototype.getContentPlayer = function () {\n return this.h5Player;\n};\n\n/**\n * @return {number} The volume, 0-1.\n */\nPlayerWrapper$1.prototype.getVolume = function () {\n return this.vjsPlayer.muted() ? 0 : this.vjsPlayer.volume();\n};\n\n/**\n * Set the volume of the player. 0-1.\n *\n * @param {number} volume The new volume.\n */\nPlayerWrapper$1.prototype.setVolume = function (volume) {\n this.vjsPlayer.volume(volume);\n if (volume == 0) {\n this.vjsPlayer.muted(true);\n } else {\n this.vjsPlayer.muted(false);\n }\n};\n\n/**\n * Ummute the player.\n */\nPlayerWrapper$1.prototype.unmute = function () {\n this.vjsPlayer.muted(false);\n};\n\n/**\n * Mute the player.\n */\nPlayerWrapper$1.prototype.mute = function () {\n this.vjsPlayer.muted(true);\n};\n\n/**\n * Play the video.\n */\nPlayerWrapper$1.prototype.play = function () {\n this.vjsPlayer.play();\n};\n\n/**\n * Toggles playback of the video.\n */\nPlayerWrapper$1.prototype.togglePlayback = function () {\n if (this.vjsPlayer.paused()) {\n this.vjsPlayer.play();\n } else {\n this.vjsPlayer.pause();\n }\n};\n\n/**\n * Get the player width.\n *\n * @return {number} The player's width.\n */\nPlayerWrapper$1.prototype.getPlayerWidth = function () {\n var width = (getComputedStyle(this.vjsPlayer.el()) || {}).width;\n if (!width || parseFloat(width) === 0) {\n width = (this.vjsPlayer.el().getBoundingClientRect() || {}).width;\n }\n return parseFloat(width) || this.vjsPlayer.width();\n};\n\n/**\n * Get the player height.\n *\n * @return {number} The player's height.\n */\nPlayerWrapper$1.prototype.getPlayerHeight = function () {\n var height = (getComputedStyle(this.vjsPlayer.el()) || {}).height;\n if (!height || parseFloat(height) === 0) {\n height = (this.vjsPlayer.el().getBoundingClientRect() || {}).height;\n }\n return parseFloat(height) || this.vjsPlayer.height();\n};\n\n/**\n * @return {Object} The vjs player's options object.\n */\nPlayerWrapper$1.prototype.getPlayerOptions = function () {\n return this.vjsPlayer.options_;\n};\n\n/**\n * Returns the instance of the player id.\n * @return {string} The player id.\n */\nPlayerWrapper$1.prototype.getPlayerId = function () {\n return this.vjsPlayer.id();\n};\n\n/**\n * Toggle fullscreen state.\n */\nPlayerWrapper$1.prototype.toggleFullscreen = function () {\n if (this.vjsPlayer.isFullscreen()) {\n this.vjsPlayer.exitFullscreen();\n } else {\n this.vjsPlayer.requestFullscreen();\n }\n};\n\n/**\n * Returns the content playhead tracker.\n *\n * @return {Object} The content playhead tracker.\n */\nPlayerWrapper$1.prototype.getContentPlayheadTracker = function () {\n return this.contentPlayheadTracker;\n};\n\n/**\n * Handles ad errors.\n *\n * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nPlayerWrapper$1.prototype.onAdError = function (adErrorEvent) {\n this.vjsControls.show();\n var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;\n this.vjsPlayer.trigger({\n type: 'adserror',\n data: {\n AdError: errorMessage,\n AdErrorEvent: adErrorEvent\n }\n });\n};\n\n/**\n * Handles ad log messages.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the IMA SDK.\n */\nPlayerWrapper$1.prototype.onAdLog = function (adEvent) {\n var adData = adEvent.getAdData();\n var errorMessage = adData['adError'] !== undefined ? adData['adError'].getMessage() : undefined;\n this.vjsPlayer.trigger({\n type: 'adslog',\n data: {\n AdError: errorMessage,\n AdEvent: adEvent\n }\n });\n};\n\n/**\n * Handles ad break starting.\n */\nPlayerWrapper$1.prototype.onAdBreakStart = function () {\n this.contentSource = this.vjsPlayer.currentSrc();\n this.contentSourceType = this.vjsPlayer.currentType();\n this.vjsPlayer.off('readyforpostroll', this.boundContentEndedListener);\n this.vjsPlayer.ads.startLinearAdMode();\n this.vjsControls.hide();\n this.vjsPlayer.pause();\n};\n\n/**\n * Handles ad break ending.\n */\nPlayerWrapper$1.prototype.onAdBreakEnd = function () {\n this.vjsPlayer.on('readyforpostroll', this.boundContentEndedListener);\n if (this.vjsPlayer.ads.inAdBreak()) {\n this.vjsPlayer.ads.endLinearAdMode();\n }\n this.vjsControls.show();\n};\n\n/**\n * Handles an individual ad start.\n */\nPlayerWrapper$1.prototype.onAdStart = function () {\n this.vjsPlayer.trigger('ads-ad-started');\n};\n\n/**\n * Handles when all ads have finished playing.\n */\nPlayerWrapper$1.prototype.onAllAdsCompleted = function () {\n if (this.contentComplete == true) {\n // The null check on this.contentSource was added to fix\n // an error when the post-roll was an empty VAST tag.\n if (this.contentSource && this.vjsPlayer.currentSrc() != this.contentSource) {\n this.vjsPlayer.src({\n src: this.contentSource,\n type: this.contentSourceType\n });\n }\n this.controller.onContentAndAdsCompleted();\n }\n};\n\n/**\n * Triggers adsready for contrib-ads.\n */\nPlayerWrapper$1.prototype.onAdsReady = function () {\n this.vjsPlayer.trigger('adsready');\n};\n\n/**\n * Changes the player source.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n */\nPlayerWrapper$1.prototype.changeSource = function (contentSrc) {\n // Only try to pause the player when initialised with a source already\n if (this.vjsPlayer.currentSrc()) {\n this.vjsPlayer.currentTime(0);\n this.vjsPlayer.pause();\n }\n if (contentSrc) {\n this.vjsPlayer.src(contentSrc);\n }\n this.vjsPlayer.one('loadedmetadata', this.seekContentToZero.bind(this));\n};\n\n/**\n * Seeks content to 00:00:00. This is used as an event handler for the\n * loadedmetadata event, since seeking is not possible until that event has\n * fired.\n */\nPlayerWrapper$1.prototype.seekContentToZero = function () {\n this.vjsPlayer.currentTime(0);\n};\n\n/**\n * Triggers an event on the VJS player\n * @param {string} name The event name.\n * @param {Object} data The event data.\n */\nPlayerWrapper$1.prototype.triggerPlayerEvent = function (name, data) {\n this.vjsPlayer.trigger(name, data);\n};\n\n/**\n * Listener JSDoc for ESLint. This listener can be passed to\n * addContentEndedListener.\n * @callback listener\n */\n\n/**\n * Adds a listener for the 'readyforpostroll' event of the video player. This\n * should be used instead of setting an 'readyforpostroll' listener directly to\n * ensure that the ima can do proper cleanup of the SDK before other event\n * listeners are called.\n * @param {listener} listener The listener to be called when content\n * completes.\n */\nPlayerWrapper$1.prototype.addContentEndedListener = function (listener) {\n this.contentEndedListeners.push(listener);\n};\n\n/**\n * Reset the player.\n */\nPlayerWrapper$1.prototype.reset = function () {\n // Attempts to remove the contentEndedListener before adding it.\n // This is to prevent an error where an erroring video caused multiple\n // contentEndedListeners to be added.\n this.vjsPlayer.off('readyforpostroll', this.boundContentEndedListener);\n this.vjsPlayer.on('readyforpostroll', this.boundContentEndedListener);\n this.vjsControls.show();\n if (this.vjsPlayer.ads.inAdBreak()) {\n this.vjsPlayer.ads.endLinearAdMode();\n }\n // Reset the content time we give the SDK. Fixes an issue where requesting\n // VMAP followed by VMAP would play the second mid-rolls as pre-rolls if\n // the first playthrough of the video passed the second response's\n // mid-roll time.\n this.contentPlayheadTracker.currentTime = 0;\n this.contentComplete = false;\n};\n\n/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Ad UI implementation.\n *\n * @param {Controller} controller Plugin controller.\n * @constructor\n * @struct\n * @final\n */\nvar AdUi = function AdUi(controller) {\n /**\n * Plugin controller.\n */\n this.controller = controller;\n\n /**\n * Div used as an ad container.\n */\n this.adContainerDiv = document.createElement('div');\n\n /**\n * Div used to display ad controls.\n */\n this.controlsDiv = document.createElement('div');\n\n /**\n * Div used to display ad countdown timer.\n */\n this.countdownDiv = document.createElement('div');\n\n /**\n * Div used to display add seek bar.\n */\n this.seekBarDiv = document.createElement('div');\n\n /**\n * Div used to display ad progress (in seek bar).\n */\n this.progressDiv = document.createElement('div');\n\n /**\n * Div used to display ad play/pause button.\n */\n this.playPauseDiv = document.createElement('div');\n\n /**\n * Div used to display ad mute button.\n */\n this.muteDiv = document.createElement('div');\n\n /**\n * Div used by the volume slider.\n */\n this.sliderDiv = document.createElement('div');\n\n /**\n * Volume slider level visuals\n */\n this.sliderLevelDiv = document.createElement('div');\n\n /**\n * Div used to display ad fullscreen button.\n */\n this.fullscreenDiv = document.createElement('div');\n\n /**\n * Bound event handler for onMouseUp.\n */\n this.boundOnMouseUp = this.onMouseUp.bind(this);\n\n /**\n * Bound event handler for onMouseMove.\n */\n this.boundOnMouseMove = this.onMouseMove.bind(this);\n\n /**\n * Stores data for the ad playhead tracker.\n */\n this.adPlayheadTracker = {\n 'currentTime': 0,\n 'duration': 0,\n 'isPod': false,\n 'adPosition': 0,\n 'totalAds': 0\n };\n\n /**\n * Used to prefix videojs ima controls.\n */\n this.controlPrefix = this.controller.getPlayerId() + '_';\n\n /**\n * Boolean flag to show or hide the ad countdown timer.\n */\n this.showCountdown = true;\n if (this.controller.getSettings().showCountdown === false) {\n this.showCountdown = false;\n }\n\n /**\n * Boolean flag if the current ad is nonlinear.\n */\n this.isAdNonlinear = false;\n this.createAdContainer();\n};\n\n/**\n * Creates the ad container.\n */\nAdUi.prototype.createAdContainer = function () {\n this.assignControlAttributes(this.adContainerDiv, 'ima-ad-container');\n // Hide the ad container until an ad starts.\n this.adContainerDiv.classList.add('hide-ad-container');\n this.adContainerDiv.addEventListener('mouseenter', this.showAdControls.bind(this), false);\n this.adContainerDiv.addEventListener('mouseleave', this.hideAdControls.bind(this), false);\n this.adContainerDiv.addEventListener('click', this.onAdContainerClick.bind(this), false);\n this.createControls();\n this.controller.injectAdContainerDiv(this.adContainerDiv);\n};\n\n/**\n * Create the controls.\n */\nAdUi.prototype.createControls = function () {\n this.assignControlAttributes(this.controlsDiv, 'ima-controls-div');\n this.controlsDiv.style.width = '100%';\n if (!this.controller.getIsMobile()) {\n this.assignControlAttributes(this.countdownDiv, 'ima-countdown-div');\n this.countdownDiv.innerHTML = this.controller.getSettings().adLabel;\n this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';\n } else {\n this.countdownDiv.style.display = 'none';\n }\n this.assignControlAttributes(this.seekBarDiv, 'ima-seek-bar-div');\n this.seekBarDiv.style.width = '100%';\n this.assignControlAttributes(this.progressDiv, 'ima-progress-div');\n this.assignControlAttributes(this.playPauseDiv, 'ima-play-pause-div');\n this.addClass(this.playPauseDiv, 'ima-playing');\n this.playPauseDiv.addEventListener('click', this.onAdPlayPauseClick.bind(this), false);\n this.assignControlAttributes(this.muteDiv, 'ima-mute-div');\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.muteDiv.addEventListener('click', this.onAdMuteClick.bind(this), false);\n this.assignControlAttributes(this.sliderDiv, 'ima-slider-div');\n this.sliderDiv.addEventListener('mousedown', this.onAdVolumeSliderMouseDown.bind(this), false);\n\n // Hide volume slider controls on iOS as they aren't supported.\n if (this.controller.getIsIos()) {\n this.sliderDiv.style.display = 'none';\n }\n this.assignControlAttributes(this.sliderLevelDiv, 'ima-slider-level-div');\n this.assignControlAttributes(this.fullscreenDiv, 'ima-fullscreen-div');\n this.addClass(this.fullscreenDiv, 'ima-non-fullscreen');\n this.fullscreenDiv.addEventListener('click', this.onAdFullscreenClick.bind(this), false);\n this.adContainerDiv.appendChild(this.controlsDiv);\n this.controlsDiv.appendChild(this.countdownDiv);\n this.controlsDiv.appendChild(this.seekBarDiv);\n this.controlsDiv.appendChild(this.playPauseDiv);\n this.controlsDiv.appendChild(this.muteDiv);\n this.controlsDiv.appendChild(this.sliderDiv);\n this.controlsDiv.appendChild(this.fullscreenDiv);\n this.seekBarDiv.appendChild(this.progressDiv);\n this.sliderDiv.appendChild(this.sliderLevelDiv);\n};\n\n/**\n * Listener for clicks on the play/pause button during ad playback.\n */\nAdUi.prototype.onAdPlayPauseClick = function () {\n this.controller.onAdPlayPauseClick();\n};\n\n/**\n * Listener for clicks on the play/pause button during ad playback.\n */\nAdUi.prototype.onAdMuteClick = function () {\n this.controller.onAdMuteClick();\n};\n\n/**\n * Listener for clicks on the fullscreen button during ad playback.\n */\nAdUi.prototype.onAdFullscreenClick = function () {\n this.controller.toggleFullscreen();\n};\n\n/**\n * Show pause and hide play button\n */\nAdUi.prototype.onAdsPaused = function () {\n this.controller.sdkImpl.adPlaying = false;\n this.addClass(this.playPauseDiv, 'ima-paused');\n this.removeClass(this.playPauseDiv, 'ima-playing');\n this.showAdControls();\n};\n\n/**\n * Show pause and hide play button\n */\nAdUi.prototype.onAdsResumed = function () {\n this.onAdsPlaying();\n this.showAdControls();\n};\n\n/**\n * Show play and hide pause button\n */\nAdUi.prototype.onAdsPlaying = function () {\n this.controller.sdkImpl.adPlaying = true;\n this.addClass(this.playPauseDiv, 'ima-playing');\n this.removeClass(this.playPauseDiv, 'ima-paused');\n};\n\n/**\n * Takes data from the controller to update the UI.\n *\n * @param {number} currentTime Current time of the ad.\n * @param {number} remainingTime Remaining time of the ad.\n * @param {number} duration Duration of the ad.\n * @param {number} adPosition Index of the ad in the pod.\n * @param {number} totalAds Total number of ads in the pod.\n */\nAdUi.prototype.updateAdUi = function (currentTime, remainingTime, duration, adPosition, totalAds) {\n // Update countdown timer data\n var remainingMinutes = Math.floor(remainingTime / 60);\n var remainingSeconds = Math.floor(remainingTime % 60);\n if (remainingSeconds.toString().length < 2) {\n remainingSeconds = '0' + remainingSeconds;\n }\n var podCount = ': ';\n if (totalAds > 1) {\n podCount = ' (' + adPosition + ' ' + this.controller.getSettings().adLabelNofN + ' ' + totalAds + '): ';\n }\n this.countdownDiv.innerHTML = this.controller.getSettings().adLabel + podCount + remainingMinutes + ':' + remainingSeconds;\n\n // Update UI\n var playProgressRatio = currentTime / duration;\n var playProgressPercent = playProgressRatio * 100;\n this.progressDiv.style.width = playProgressPercent + '%';\n};\n\n/**\n * Handles UI changes when the ad is unmuted.\n */\nAdUi.prototype.unmute = function () {\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.removeClass(this.muteDiv, 'ima-muted');\n this.sliderLevelDiv.style.width = this.controller.getPlayerVolume() * 100 + '%';\n};\n\n/**\n * Handles UI changes when the ad is muted.\n */\nAdUi.prototype.mute = function () {\n this.addClass(this.muteDiv, 'ima-muted');\n this.removeClass(this.muteDiv, 'ima-non-muted');\n this.sliderLevelDiv.style.width = '0%';\n};\n\n/*\n * Listener for mouse down events during ad playback. Used for volume.\n */\nAdUi.prototype.onAdVolumeSliderMouseDown = function () {\n document.addEventListener('mouseup', this.boundOnMouseUp, false);\n document.addEventListener('mousemove', this.boundOnMouseMove, false);\n};\n\n/*\n * Mouse movement listener used for volume slider.\n */\nAdUi.prototype.onMouseMove = function (event) {\n this.changeVolume(event);\n};\n\n/*\n * Mouse release listener used for volume slider.\n */\nAdUi.prototype.onMouseUp = function (event) {\n this.changeVolume(event);\n document.removeEventListener('mouseup', this.boundOnMouseUp);\n document.removeEventListener('mousemove', this.boundOnMouseMove);\n};\n\n/*\n * Utility function to set volume and associated UI\n */\nAdUi.prototype.changeVolume = function (event) {\n var percent = (event.clientX - this.sliderDiv.getBoundingClientRect().left) / this.sliderDiv.offsetWidth;\n percent *= 100;\n // Bounds value 0-100 if mouse is outside slider region.\n percent = Math.min(Math.max(percent, 0), 100);\n this.sliderLevelDiv.style.width = percent + '%';\n if (this.percent == 0) {\n this.addClass(this.muteDiv, 'ima-muted');\n this.removeClass(this.muteDiv, 'ima-non-muted');\n } else {\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.removeClass(this.muteDiv, 'ima-muted');\n }\n this.controller.setVolume(percent / 100); // 0-1\n};\n\n/**\n * Show the ad container.\n */\nAdUi.prototype.showAdContainer = function () {\n this.adContainerDiv.classList.remove('hide-ad-container');\n};\n\n/**\n * Hide the ad container.\n */\nAdUi.prototype.hideAdContainer = function () {\n this.adContainerDiv.classList.add('hide-ad-container');\n};\n\n/**\n * Handles clicks on the ad container.\n */\nAdUi.prototype.onAdContainerClick = function () {\n if (this.isAdNonlinear) {\n this.controller.togglePlayback();\n }\n};\n\n/**\n * Resets the state of the ad ui.\n */\nAdUi.prototype.reset = function () {\n this.hideAdContainer();\n};\n\n/**\n * Handles ad errors.\n */\nAdUi.prototype.onAdError = function () {\n this.hideAdContainer();\n};\n\n/**\n * Handles ad break starting.\n *\n * @param {Object} adEvent The event fired by the IMA SDK.\n */\nAdUi.prototype.onAdBreakStart = function (adEvent) {\n this.showAdContainer();\n var contentType = adEvent.getAd().getContentType();\n if (contentType === 'application/javascript' && !this.controller.getSettings().showControlsForJSAds) {\n this.controlsDiv.style.display = 'none';\n } else {\n this.controlsDiv.style.display = 'block';\n }\n this.onAdsPlaying();\n // Start with the ad controls minimized.\n this.hideAdControls();\n};\n\n/**\n * Handles ad break ending.\n */\nAdUi.prototype.onAdBreakEnd = function () {\n var currentAd = this.controller.getCurrentAd();\n if (currentAd == null ||\n // hide for post-roll only playlist\n currentAd.isLinear()) {\n // don't hide for non-linear ads\n this.hideAdContainer();\n }\n this.controlsDiv.style.display = 'none';\n this.countdownDiv.innerHTML = '';\n};\n\n/**\n * Handles when all ads have finished playing.\n */\nAdUi.prototype.onAllAdsCompleted = function () {\n this.hideAdContainer();\n};\n\n/**\n * Handles when a linear ad starts.\n */\nAdUi.prototype.onLinearAdStart = function () {\n // Don't bump container when controls are shown\n this.removeClass(this.adContainerDiv, 'bumpable-ima-ad-container');\n this.isAdNonlinear = false;\n};\n\n/**\n * Handles when a non-linear ad starts.\n */\nAdUi.prototype.onNonLinearAdLoad = function () {\n // Bump container when controls are shown\n this.addClass(this.adContainerDiv, 'bumpable-ima-ad-container');\n this.isAdNonlinear = true;\n};\nAdUi.prototype.onPlayerEnterFullscreen = function () {\n this.addClass(this.fullscreenDiv, 'ima-fullscreen');\n this.removeClass(this.fullscreenDiv, 'ima-non-fullscreen');\n};\nAdUi.prototype.onPlayerExitFullscreen = function () {\n this.addClass(this.fullscreenDiv, 'ima-non-fullscreen');\n this.removeClass(this.fullscreenDiv, 'ima-fullscreen');\n};\n\n/**\n * Called when the player volume changes.\n *\n * @param {number} volume The new player volume.\n */\nAdUi.prototype.onPlayerVolumeChanged = function (volume) {\n if (volume == 0) {\n this.addClass(this.muteDiv, 'ima-muted');\n this.removeClass(this.muteDiv, 'ima-non-muted');\n this.sliderLevelDiv.style.width = '0%';\n } else {\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.removeClass(this.muteDiv, 'ima-muted');\n this.sliderLevelDiv.style.width = volume * 100 + '%';\n }\n};\n\n/**\n * Shows ad controls on mouseover.\n */\nAdUi.prototype.showAdControls = function () {\n var _this$controller$getS = this.controller.getSettings(),\n disableAdControls = _this$controller$getS.disableAdControls;\n if (!disableAdControls) {\n this.addClass(this.controlsDiv, 'ima-controls-div-showing');\n }\n};\n\n/**\n * Hide the ad controls.\n */\nAdUi.prototype.hideAdControls = function () {\n this.removeClass(this.controlsDiv, 'ima-controls-div-showing');\n};\n\n/**\n * Assigns the unique id and class names to the given element as well as the\n * style class.\n * @param {HTMLElement} element Element that needs the controlName assigned.\n * @param {string} controlName Control name to assign.\n */\nAdUi.prototype.assignControlAttributes = function (element, controlName) {\n element.id = this.controlPrefix + controlName;\n element.className = this.controlPrefix + controlName + ' ' + controlName;\n};\n\n/**\n * Returns a regular expression to test a string for the given className.\n *\n * @param {string} className The name of the class.\n * @return {RegExp} The regular expression used to test for that class.\n */\nAdUi.prototype.getClassRegexp = function (className) {\n // Matches on\n // (beginning of string OR NOT word char)\n // classname\n // (negative lookahead word char OR end of string)\n return new RegExp('(^|[^A-Za-z-])' + className + '((?![A-Za-z-])|$)', 'gi');\n};\n\n/**\n * Returns whether or not the provided element has the provied class in its\n * className.\n * @param {HTMLElement} element Element to tes.t\n * @param {string} className Class to look for.\n * @return {boolean} True if element has className in class list. False\n * otherwise.\n */\nAdUi.prototype.elementHasClass = function (element, className) {\n var classRegexp = this.getClassRegexp(className);\n return classRegexp.test(element.className);\n};\n\n/**\n * Adds a class to the given element if it doesn't already have the class\n * @param {HTMLElement} element Element to which the class will be added.\n * @param {string} classToAdd Class to add.\n */\nAdUi.prototype.addClass = function (element, classToAdd) {\n element.className = element.className.trim() + ' ' + classToAdd;\n};\n\n/**\n * Removes a class from the given element if it has the given class\n *\n * @param {HTMLElement} element Element from which the class will be removed.\n * @param {string} classToRemove Class to remove.\n */\nAdUi.prototype.removeClass = function (element, classToRemove) {\n var classRegexp = this.getClassRegexp(classToRemove);\n element.className = element.className.trim().replace(classRegexp, '');\n};\n\n/**\n * @return {HTMLElement} The div for the ad container.\n */\nAdUi.prototype.getAdContainerDiv = function () {\n return this.adContainerDiv;\n};\n\n/**\n * Changes the flag to show or hide the ad countdown timer.\n *\n * @param {boolean} showCountdownIn Show or hide the countdown timer.\n */\nAdUi.prototype.setShowCountdown = function (showCountdownIn) {\n this.showCountdown = showCountdownIn;\n this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';\n};\n\nvar version = \"2.5.0\";\nvar pkg = {\n\tversion: version};\n\n/**\n * Implementation of the IMA SDK for the plugin.\n *\n * @param {Object} controller Reference to the parent controller.\n *\n * @constructor\n * @struct\n * @final\n */\nvar SdkImpl$1 = function SdkImpl(controller) {\n /**\n * Plugin controller.\n */\n this.controller = controller;\n\n /**\n * IMA SDK AdDisplayContainer.\n */\n this.adDisplayContainer = null;\n\n /**\n * True if the AdDisplayContainer has been initialized. False otherwise.\n */\n this.adDisplayContainerInitialized = false;\n\n /**\n * IMA SDK AdsLoader\n */\n this.adsLoader = null;\n\n /**\n * IMA SDK AdsManager\n */\n this.adsManager = null;\n\n /**\n * IMA SDK AdsRenderingSettings.\n */\n this.adsRenderingSettings = null;\n\n /**\n * VAST, VMAP, or ad rules response. Used in lieu of fetching a response\n * from an ad tag URL.\n */\n this.adsResponse = null;\n\n /**\n * Current IMA SDK Ad.\n */\n this.currentAd = null;\n\n /**\n * Timer used to track ad progress.\n */\n this.adTrackingTimer = null;\n\n /**\n * True if ALL_ADS_COMPLETED has fired, false until then.\n */\n this.allAdsCompleted = false;\n\n /**\n * True if ads are currently displayed, false otherwise.\n * True regardless of ad pause state if an ad is currently being displayed.\n */\n this.adsActive = false;\n\n /**\n * True if ad is currently playing, false if ad is paused or ads are not\n * currently displayed.\n */\n this.adPlaying = false;\n\n /**\n * True if the ad is muted, false otherwise.\n */\n this.adMuted = false;\n\n /**\n * Listener to be called to trigger manual ad break playback.\n */\n this.adBreakReadyListener = undefined;\n\n /**\n * Tracks whether or not we have already called adsLoader.contentComplete().\n */\n this.contentCompleteCalled = false;\n\n /**\n * True if the ad has timed out.\n */\n this.isAdTimedOut = false;\n\n /**\n * Stores the dimensions for the ads manager.\n */\n this.adsManagerDimensions = {\n width: 0,\n height: 0\n };\n\n /**\n * Boolean flag to enable manual ad break playback.\n */\n this.autoPlayAdBreaks = true;\n if (this.controller.getSettings().autoPlayAdBreaks === false) {\n this.autoPlayAdBreaks = false;\n }\n\n // Set SDK settings from plugin settings.\n if (this.controller.getSettings().locale) {\n /* eslint no-undef: 'error' */\n /* global google */\n google.ima.settings.setLocale(this.controller.getSettings().locale);\n }\n if (this.controller.getSettings().disableFlashAds) {\n google.ima.settings.setDisableFlashAds(this.controller.getSettings().disableFlashAds);\n }\n if (this.controller.getSettings().disableCustomPlaybackForIOS10Plus) {\n google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.controller.getSettings().disableCustomPlaybackForIOS10Plus);\n }\n if (this.controller.getSettings().ppid) {\n google.ima.settings.setPpid(this.controller.getSettings().ppid);\n }\n if (this.controller.getSettings().featureFlags) {\n google.ima.settings.setFeatureFlags(this.controller.getSettings().featureFlags);\n }\n};\n\n/**\n * Creates and initializes the IMA SDK objects.\n */\nSdkImpl$1.prototype.initAdObjects = function () {\n this.adDisplayContainer = new google.ima.AdDisplayContainer(this.controller.getAdContainerDiv(), this.controller.getContentPlayer());\n this.adsLoader = new google.ima.AdsLoader(this.adDisplayContainer);\n this.adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.ENABLED);\n if (this.controller.getSettings().vpaidAllowed == false) {\n this.adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.DISABLED);\n }\n if (this.controller.getSettings().vpaidMode !== undefined) {\n this.adsLoader.getSettings().setVpaidMode(this.controller.getSettings().vpaidMode);\n }\n if (this.controller.getSettings().locale) {\n this.adsLoader.getSettings().setLocale(this.controller.getSettings().locale);\n }\n if (this.controller.getSettings().numRedirects) {\n this.adsLoader.getSettings().setNumRedirects(this.controller.getSettings().numRedirects);\n }\n if (this.controller.getSettings().sessionId) {\n this.adsLoader.getSettings().setSessionId(this.controller.getSettings().sessionId);\n }\n this.adsLoader.getSettings().setPlayerType('videojs-ima');\n this.adsLoader.getSettings().setPlayerVersion(pkg.version);\n this.adsLoader.getSettings().setAutoPlayAdBreaks(this.autoPlayAdBreaks);\n this.adsLoader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, this.onAdsManagerLoaded.bind(this), false);\n this.adsLoader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, this.onAdsLoaderError.bind(this), false);\n this.controller.playerWrapper.vjsPlayer.trigger({\n type: 'ads-loader',\n adsLoader: this.adsLoader\n });\n};\n\n/**\n * Creates the AdsRequest and request ads through the AdsLoader.\n */\nSdkImpl$1.prototype.requestAds = function () {\n var adsRequest = new google.ima.AdsRequest();\n if (this.controller.getSettings().adTagUrl) {\n adsRequest.adTagUrl = this.controller.getSettings().adTagUrl;\n } else {\n adsRequest.adsResponse = this.controller.getSettings().adsResponse;\n }\n if (this.controller.getSettings().forceNonLinearFullSlot) {\n adsRequest.forceNonLinearFullSlot = true;\n }\n if (this.controller.getSettings().vastLoadTimeout) {\n adsRequest.vastLoadTimeout = this.controller.getSettings().vastLoadTimeout;\n }\n if (this.controller.getSettings().omidMode) {\n window.console.warn('The additional setting `omidMode` has been removed. ' + 'Use `omidVendorAccess` instead.');\n }\n if (this.controller.getSettings().omidVendorAccess) {\n adsRequest.omidAccessModeRules = {};\n var omidVendorValues = this.controller.getSettings().omidVendorAccess;\n Object.keys(omidVendorValues).forEach(function (vendorKey) {\n adsRequest.omidAccessModeRules[vendorKey] = omidVendorValues[vendorKey];\n });\n }\n adsRequest.linearAdSlotWidth = this.controller.getPlayerWidth();\n adsRequest.linearAdSlotHeight = this.controller.getPlayerHeight();\n adsRequest.nonLinearAdSlotWidth = this.controller.getSettings().nonLinearWidth || this.controller.getPlayerWidth();\n adsRequest.nonLinearAdSlotHeight = this.controller.getSettings().nonLinearHeight || this.controller.getPlayerHeight();\n adsRequest.setAdWillAutoPlay(this.controller.adsWillAutoplay());\n adsRequest.setAdWillPlayMuted(this.controller.adsWillPlayMuted());\n\n // Populate the adsRequestproperties with those provided in the AdsRequest\n // object in the settings.\n var providedAdsRequest = this.controller.getSettings().adsRequest;\n if (providedAdsRequest && _typeof(providedAdsRequest) === 'object') {\n Object.keys(providedAdsRequest).forEach(function (key) {\n adsRequest[key] = providedAdsRequest[key];\n });\n }\n this.adsLoader.requestAds(adsRequest);\n this.controller.playerWrapper.vjsPlayer.trigger({\n type: 'ads-request',\n AdsRequest: adsRequest\n });\n};\n\n/**\n * Listener for the ADS_MANAGER_LOADED event. Creates the AdsManager,\n * sets up event listeners, and triggers the 'adsready' event for\n * videojs-ads-contrib.\n *\n * @param {google.ima.AdsManagerLoadedEvent} adsManagerLoadedEvent Fired when\n * the AdsManager loads.\n */\nSdkImpl$1.prototype.onAdsManagerLoaded = function (adsManagerLoadedEvent) {\n this.createAdsRenderingSettings();\n this.adsManager = adsManagerLoadedEvent.getAdsManager(this.controller.getContentPlayheadTracker(), this.adsRenderingSettings);\n this.adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, this.onAdError.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.AD_BREAK_READY, this.onAdBreakReady.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, this.onContentPauseRequested.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, this.onContentResumeRequested.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.ALL_ADS_COMPLETED, this.onAllAdsCompleted.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, this.onAdLoaded.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, this.onAdStarted.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, this.onAdComplete.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.SKIPPED, this.onAdComplete.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.LOG, this.onAdLog.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.PAUSED, this.onAdPaused.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.RESUMED, this.onAdResumed.bind(this));\n this.controller.playerWrapper.vjsPlayer.trigger({\n type: 'ads-manager',\n adsManager: this.adsManager\n });\n if (!this.autoPlayAdBreaks) {\n this.initAdsManager();\n }\n var _this$controller$getS = this.controller.getSettings(),\n preventLateAdStart = _this$controller$getS.preventLateAdStart;\n if (!preventLateAdStart) {\n this.controller.onAdsReady();\n } else if (preventLateAdStart && !this.isAdTimedOut) {\n this.controller.onAdsReady();\n }\n if (this.controller.getSettings().adsManagerLoadedCallback) {\n this.controller.getSettings().adsManagerLoadedCallback();\n }\n};\n\n/**\n * Listener for errors fired by the AdsLoader.\n * @param {google.ima.AdErrorEvent} event The error event thrown by the\n * AdsLoader. See\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdError#.Type\n */\nSdkImpl$1.prototype.onAdsLoaderError = function (event) {\n window.console.warn('AdsLoader error: ' + event.getError());\n this.controller.onErrorLoadingAds(event);\n if (this.adsManager) {\n this.adsManager.destroy();\n }\n};\n\n/**\n * Initialize the ads manager.\n */\nSdkImpl$1.prototype.initAdsManager = function () {\n try {\n var initWidth = this.controller.getPlayerWidth();\n var initHeight = this.controller.getPlayerHeight();\n this.adsManagerDimensions.width = initWidth;\n this.adsManagerDimensions.height = initHeight;\n this.adsManager.init(initWidth, initHeight);\n this.adsManager.setVolume(this.controller.getPlayerVolume());\n this.initializeAdDisplayContainer();\n } catch (adError) {\n this.onAdError(adError);\n }\n};\n\n/**\n * Create AdsRenderingSettings for the IMA SDK.\n */\nSdkImpl$1.prototype.createAdsRenderingSettings = function () {\n this.adsRenderingSettings = new google.ima.AdsRenderingSettings();\n this.adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;\n if (this.controller.getSettings().adsRenderingSettings) {\n for (var setting in this.controller.getSettings().adsRenderingSettings) {\n if (setting !== '') {\n this.adsRenderingSettings[setting] = this.controller.getSettings().adsRenderingSettings[setting];\n }\n }\n }\n};\n\n/**\n * Listener for errors thrown by the AdsManager.\n * @param {google.ima.AdErrorEvent} adErrorEvent The error event thrown by\n * the AdsManager.\n */\nSdkImpl$1.prototype.onAdError = function (adErrorEvent) {\n var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;\n window.console.warn('Ad error: ' + errorMessage);\n this.adsManager.destroy();\n this.controller.onAdError(adErrorEvent);\n\n // reset these so consumers don't think we are still in an ad break,\n // but reset them after any prior cleanup happens\n this.adsActive = false;\n this.adPlaying = false;\n};\n\n/**\n * Listener for AD_BREAK_READY. Passes event on to publisher's listener.\n * @param {google.ima.AdEvent} adEvent AdEvent thrown by the AdsManager.\n */\nSdkImpl$1.prototype.onAdBreakReady = function (adEvent) {\n this.adBreakReadyListener(adEvent);\n};\n\n/**\n * Pauses the content video and displays the ad container so ads can play.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl$1.prototype.onContentPauseRequested = function (adEvent) {\n this.adsActive = true;\n this.adPlaying = true;\n this.controller.onAdBreakStart(adEvent);\n};\n\n/**\n * Resumes content video and hides the ad container.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl$1.prototype.onContentResumeRequested = function (adEvent) {\n this.adsActive = false;\n this.adPlaying = false;\n this.controller.onAdBreakEnd();\n // Hide controls in case of future non-linear ads. They'll be unhidden in\n // content_pause_requested.\n};\n\n/**\n * Records that ads have completed and calls contentAndAdsEndedListeners\n * if content is also complete.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl$1.prototype.onAllAdsCompleted = function (adEvent) {\n this.allAdsCompleted = true;\n this.controller.onAllAdsCompleted();\n};\n\n/**\n * Starts the content video when a non-linear ad is loaded.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl$1.prototype.onAdLoaded = function (adEvent) {\n if (!adEvent.getAd().isLinear()) {\n this.controller.onNonLinearAdLoad();\n this.controller.playContent();\n }\n};\n\n/**\n * Starts the interval timer to check the current ad time when an ad starts\n * playing.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl$1.prototype.onAdStarted = function (adEvent) {\n this.currentAd = adEvent.getAd();\n if (this.currentAd.isLinear()) {\n this.adTrackingTimer = setInterval(this.onAdPlayheadTrackerInterval.bind(this), 250);\n this.controller.onLinearAdStart();\n } else {\n this.controller.onNonLinearAdStart();\n }\n};\n\n/**\n * Handles an ad click. Puts the player UI in a paused state.\n */\nSdkImpl$1.prototype.onAdPaused = function () {\n this.controller.onAdsPaused();\n};\n\n/**\n * Syncs controls when an ad resumes.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl$1.prototype.onAdResumed = function (adEvent) {\n this.controller.onAdsResumed();\n};\n\n/**\n * Clears the interval timer for current ad time when an ad completes.\n */\nSdkImpl$1.prototype.onAdComplete = function () {\n if (this.currentAd.isLinear()) {\n clearInterval(this.adTrackingTimer);\n }\n};\n\n/**\n * Handles ad log messages.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl$1.prototype.onAdLog = function (adEvent) {\n this.controller.onAdLog(adEvent);\n};\n\n/**\n * Gets the current time and duration of the ad and calls the method to\n * update the ad UI.\n */\nSdkImpl$1.prototype.onAdPlayheadTrackerInterval = function () {\n if (this.adsManager === null) return;\n var remainingTime = this.adsManager.getRemainingTime();\n var duration = this.currentAd.getDuration();\n var currentTime = duration - remainingTime;\n currentTime = currentTime > 0 ? currentTime : 0;\n var totalAds = 0;\n var adPosition;\n if (this.currentAd.getAdPodInfo()) {\n adPosition = this.currentAd.getAdPodInfo().getAdPosition();\n totalAds = this.currentAd.getAdPodInfo().getTotalAds();\n }\n this.controller.onAdPlayheadUpdated(currentTime, remainingTime, duration, adPosition, totalAds);\n};\n\n/**\n * Called by the player wrapper when content completes.\n */\nSdkImpl$1.prototype.onContentComplete = function () {\n if (this.adsLoader) {\n this.adsLoader.contentComplete();\n this.contentCompleteCalled = true;\n }\n if (this.adsManager && this.adsManager.getCuePoints() && !this.adsManager.getCuePoints().includes(-1) || !this.adsManager) {\n this.controller.onNoPostroll();\n }\n if (this.allAdsCompleted) {\n this.controller.onContentAndAdsCompleted();\n }\n};\n\n/**\n * Called when the player is disposed.\n */\nSdkImpl$1.prototype.onPlayerDisposed = function () {\n if (this.adTrackingTimer) {\n clearInterval(this.adTrackingTimer);\n }\n if (this.adsManager) {\n this.adsManager.destroy();\n this.adsManager = null;\n }\n};\nSdkImpl$1.prototype.onPlayerReadyForPreroll = function () {\n if (this.autoPlayAdBreaks) {\n this.initAdsManager();\n try {\n this.controller.showAdContainer();\n // Sync ad volume with content volume.\n this.adsManager.setVolume(this.controller.getPlayerVolume());\n this.adsManager.start();\n } catch (adError) {\n this.onAdError(adError);\n }\n }\n};\nSdkImpl$1.prototype.onAdTimeout = function () {\n this.isAdTimedOut = true;\n};\nSdkImpl$1.prototype.onPlayerReady = function () {\n this.initAdObjects();\n if ((this.controller.getSettings().adTagUrl || this.controller.getSettings().adsResponse) && this.controller.getSettings().requestMode === 'onLoad') {\n this.requestAds();\n }\n};\nSdkImpl$1.prototype.onPlayerEnterFullscreen = function () {\n if (this.adsManager) {\n this.adsManager.resize(window.screen.width, window.screen.height);\n }\n};\nSdkImpl$1.prototype.onPlayerExitFullscreen = function () {\n if (this.adsManager) {\n this.adsManager.resize(this.controller.getPlayerWidth(), this.controller.getPlayerHeight());\n }\n};\n\n/**\n * Called when the player volume changes.\n *\n * @param {number} volume The new player volume.\n */\nSdkImpl$1.prototype.onPlayerVolumeChanged = function (volume) {\n if (this.adsManager) {\n this.adsManager.setVolume(volume);\n }\n if (volume == 0) {\n this.adMuted = true;\n } else {\n this.adMuted = false;\n }\n};\n\n/**\n * Called when the player wrapper detects that the player has been resized.\n *\n * @param {number} width The post-resize width of the player.\n * @param {number} height The post-resize height of the player.\n */\nSdkImpl$1.prototype.onPlayerResize = function (width, height) {\n if (this.adsManager) {\n this.adsManagerDimensions.width = width;\n this.adsManagerDimensions.height = height;\n /* eslint no-undef: 'error' */\n this.adsManager.resize(width, height);\n }\n};\n\n/**\n * @return {Object} The current ad.\n */\nSdkImpl$1.prototype.getCurrentAd = function () {\n return this.currentAd;\n};\n\n/**\n * Listener JSDoc for ESLint. This listener can be passed to\n * setAdBreakReadyListener.\n * @callback listener\n */\n\n/**\n * Sets the listener to be called to trigger manual ad break playback.\n * @param {listener} listener The listener to be called to trigger manual ad\n * break playback.\n */\nSdkImpl$1.prototype.setAdBreakReadyListener = function (listener) {\n this.adBreakReadyListener = listener;\n};\n\n/**\n * @return {boolean} True if an ad is currently playing. False otherwise.\n */\nSdkImpl$1.prototype.isAdPlaying = function () {\n return this.adPlaying;\n};\n\n/**\n * @return {boolean} True if an ad is currently playing. False otherwise.\n */\nSdkImpl$1.prototype.isAdMuted = function () {\n return this.adMuted;\n};\n\n/**\n * Pause ads.\n */\nSdkImpl$1.prototype.pauseAds = function () {\n this.adsManager.pause();\n this.adPlaying = false;\n};\n\n/**\n * Resume ads.\n */\nSdkImpl$1.prototype.resumeAds = function () {\n this.adsManager.resume();\n this.adPlaying = true;\n};\n\n/**\n * Unmute ads.\n */\nSdkImpl$1.prototype.unmute = function () {\n this.adsManager.setVolume(1);\n this.adMuted = false;\n};\n\n/**\n * Mute ads.\n */\nSdkImpl$1.prototype.mute = function () {\n this.adsManager.setVolume(0);\n this.adMuted = true;\n};\n\n/**\n * Set the volume of the ads. 0-1.\n *\n * @param {number} volume The new volume.\n */\nSdkImpl$1.prototype.setVolume = function (volume) {\n this.adsManager.setVolume(volume);\n if (volume == 0) {\n this.adMuted = true;\n } else {\n this.adMuted = false;\n }\n};\n\n/**\n * Initializes the AdDisplayContainer. On mobile, this must be done as a\n * result of user action.\n */\nSdkImpl$1.prototype.initializeAdDisplayContainer = function () {\n if (this.adDisplayContainer) {\n if (!this.adDisplayContainerInitialized) {\n this.adDisplayContainer.initialize();\n this.adDisplayContainerInitialized = true;\n }\n }\n};\n\n/**\n * Called by publishers in manual ad break playback mode to start an ad\n * break.\n */\nSdkImpl$1.prototype.playAdBreak = function () {\n if (!this.autoPlayAdBreaks) {\n this.controller.showAdContainer();\n // Sync ad volume with content volume.\n this.adsManager.setVolume(this.controller.getPlayerVolume());\n this.adsManager.start();\n }\n};\n\n/**\n * Callback JSDoc for ESLint. This callback can be passed to addEventListener.\n * @callback callback\n */\n\n/**\n * Adds an EventListener to the AdsManager. For a list of available events,\n * see\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent#.Type\n * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to\n * listen.\n * @param {callback} callback The method to call when the event is fired.\n */\nSdkImpl$1.prototype.addEventListener = function (event, callback) {\n if (this.adsManager) {\n this.adsManager.addEventListener(event, callback);\n }\n};\n\n/**\n * Returns the instance of the AdsManager.\n * @return {google.ima.AdsManager} The AdsManager being used by the plugin.\n */\nSdkImpl$1.prototype.getAdsManager = function () {\n return this.adsManager;\n};\n\n/**\n * Reset the SDK implementation.\n */\nSdkImpl$1.prototype.reset = function () {\n this.adsActive = false;\n this.adPlaying = false;\n if (this.adTrackingTimer) {\n // If this is called while an ad is playing, stop trying to get that\n // ad's current time.\n clearInterval(this.adTrackingTimer);\n }\n if (this.adsManager) {\n this.adsManager.destroy();\n this.adsManager = null;\n }\n if (this.adsLoader && !this.contentCompleteCalled) {\n this.adsLoader.contentComplete();\n }\n this.contentCompleteCalled = false;\n this.allAdsCompleted = false;\n};\n\n/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * The grand coordinator of the plugin. Facilitates communication between all\n * other plugin classes.\n *\n * @param {Object} player Instance of the video.js player.\n * @param {Object} options Options provided by the implementation.\n * @constructor\n * @struct\n * @final\n */\nvar Controller = function Controller(player, options) {\n /**\n * Stores user-provided settings.\n * @type {Object}\n */\n this.settings = {};\n\n /**\n * Content and ads ended listeners passed by the publisher to the plugin.\n * These will be called when the plugin detects that content *and all\n * ads* have completed. This differs from the contentEndedListeners in that\n * contentEndedListeners will fire between content ending and a post-roll\n * playing, whereas the contentAndAdsEndedListeners will fire after the\n * post-roll completes.\n */\n this.contentAndAdsEndedListeners = [];\n\n /**\n * Whether or not we are running on a mobile platform.\n */\n this.isMobile = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/Android/i);\n\n /**\n * Whether or not we are running on an iOS platform.\n */\n this.isIos = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i);\n this.initWithSettings(options);\n\n /**\n * Stores contrib-ads default settings.\n */\n var contribAdsDefaults = {\n debug: this.settings.debug,\n timeout: this.settings.timeout,\n prerollTimeout: this.settings.prerollTimeout\n };\n var adsPluginSettings = Object.assign({}, contribAdsDefaults, options.contribAdsSettings || {});\n this.playerWrapper = new PlayerWrapper$1(player, adsPluginSettings, this);\n this.adUi = new AdUi(this);\n this.sdkImpl = new SdkImpl$1(this);\n};\nController.IMA_DEFAULTS = {\n adLabel: 'Advertisement',\n adLabelNofN: 'of',\n debug: false,\n disableAdControls: false,\n prerollTimeout: 1000,\n preventLateAdStart: false,\n requestMode: 'onLoad',\n showControlsForJSAds: true,\n timeout: 5000\n};\n\n/**\n * Extends the settings to include user-provided settings.\n *\n * @param {Object} options Options to be used in initialization.\n */\nController.prototype.initWithSettings = function (options) {\n this.settings = Object.assign({}, Controller.IMA_DEFAULTS, options || {});\n this.warnAboutDeprecatedSettings();\n\n // Default showing countdown timer to true.\n this.showCountdown = true;\n if (this.settings.showCountdown === false) {\n this.showCountdown = false;\n }\n};\n\n/**\n * Logs console warnings when deprecated settings are used.\n */\nController.prototype.warnAboutDeprecatedSettings = function () {\n var _this = this;\n var deprecatedSettings = ['adWillAutoplay', 'adsWillAutoplay', 'adWillPlayMuted', 'adsWillPlayMuted'];\n deprecatedSettings.forEach(function (setting) {\n if (_this.settings[setting] !== undefined) {\n console.warn('WARNING: videojs.ima setting ' + setting + ' is deprecated');\n }\n });\n};\n\n/**\n * Return the settings object.\n *\n * @return {Object} The settings object.\n */\nController.prototype.getSettings = function () {\n return this.settings;\n};\n\n/**\n * Return whether or not we're in a mobile environment.\n *\n * @return {boolean} True if running on mobile, false otherwise.\n */\nController.prototype.getIsMobile = function () {\n return this.isMobile;\n};\n\n/**\n * Return whether or not we're in an iOS environment.\n *\n * @return {boolean} True if running on iOS, false otherwise.\n */\nController.prototype.getIsIos = function () {\n return this.isIos;\n};\n\n/**\n * Inject the ad container div into the DOM.\n *\n * @param{HTMLElement} adContainerDiv The ad container div.\n */\nController.prototype.injectAdContainerDiv = function (adContainerDiv) {\n this.playerWrapper.injectAdContainerDiv(adContainerDiv);\n};\n\n/**\n * @return {HTMLElement} The div for the ad container.\n */\nController.prototype.getAdContainerDiv = function () {\n return this.adUi.getAdContainerDiv();\n};\n\n/**\n * @return {Object} The content player.\n */\nController.prototype.getContentPlayer = function () {\n return this.playerWrapper.getContentPlayer();\n};\n\n/**\n * Returns the content playhead tracker.\n *\n * @return {Object} The content playhead tracker.\n */\nController.prototype.getContentPlayheadTracker = function () {\n return this.playerWrapper.getContentPlayheadTracker();\n};\n\n/**\n * Requests ads.\n */\nController.prototype.requestAds = function () {\n this.sdkImpl.requestAds();\n};\n\n/**\n * Add or modify a setting.\n *\n * @param {string} key Key to modify\n * @param {Object} value Value to set at key.\n */\nController.prototype.setSetting = function (key, value) {\n this.settings[key] = value;\n};\n\n/**\n * Called when there is an error loading ads.\n *\n * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nController.prototype.onErrorLoadingAds = function (adErrorEvent) {\n this.adUi.onAdError();\n this.playerWrapper.onAdError(adErrorEvent);\n};\n\n/**\n * Called by the ad UI when the play/pause button is clicked.\n */\nController.prototype.onAdPlayPauseClick = function () {\n if (this.sdkImpl.isAdPlaying()) {\n this.adUi.onAdsPaused();\n this.sdkImpl.pauseAds();\n } else {\n this.adUi.onAdsPlaying();\n this.sdkImpl.resumeAds();\n }\n};\n\n/**\n * Called by the ad UI when the mute button is clicked.\n *\n */\nController.prototype.onAdMuteClick = function () {\n if (this.sdkImpl.isAdMuted()) {\n this.playerWrapper.unmute();\n this.adUi.unmute();\n this.sdkImpl.unmute();\n } else {\n this.playerWrapper.mute();\n this.adUi.mute();\n this.sdkImpl.mute();\n }\n};\n\n/**\n * Set the volume of the player and ads. 0-1.\n *\n * @param {number} volume The new volume.\n */\nController.prototype.setVolume = function (volume) {\n this.playerWrapper.setVolume(volume);\n this.sdkImpl.setVolume(volume);\n};\n\n/**\n * @return {number} The volume of the content player.\n */\nController.prototype.getPlayerVolume = function () {\n return this.playerWrapper.getVolume();\n};\n\n/**\n * Toggle fullscreen state.\n */\nController.prototype.toggleFullscreen = function () {\n this.playerWrapper.toggleFullscreen();\n};\n\n/**\n * Relays ad errors to the player wrapper.\n *\n * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nController.prototype.onAdError = function (adErrorEvent) {\n this.adUi.onAdError();\n this.playerWrapper.onAdError(adErrorEvent);\n};\n\n/**\n * Handles ad break starting.\n *\n * @param {Object} adEvent The event fired by the IMA SDK.\n */\nController.prototype.onAdBreakStart = function (adEvent) {\n this.playerWrapper.onAdBreakStart();\n this.adUi.onAdBreakStart(adEvent);\n};\n\n/**\n * Show the ad container.\n */\nController.prototype.showAdContainer = function () {\n this.adUi.showAdContainer();\n};\n\n/**\n * Handles ad break ending.\n */\nController.prototype.onAdBreakEnd = function () {\n this.playerWrapper.onAdBreakEnd();\n this.adUi.onAdBreakEnd();\n};\n\n/**\n * Handles when all ads have finished playing.\n */\nController.prototype.onAllAdsCompleted = function () {\n this.adUi.onAllAdsCompleted();\n this.playerWrapper.onAllAdsCompleted();\n};\n\n/**\n * Handles the SDK firing an ad paused event.\n */\nController.prototype.onAdsPaused = function () {\n this.adUi.onAdsPaused();\n};\n\n/**\n * Handles the SDK firing an ad resumed event.\n */\nController.prototype.onAdsResumed = function () {\n this.adUi.onAdsResumed();\n};\n\n/**\n * Takes data from the sdk impl and passes it to the ad UI to update the UI.\n *\n * @param {number} currentTime Current time of the ad.\n * @param {number} remainingTime Remaining time of the ad.\n * @param {number} duration Duration of the ad.\n * @param {number} adPosition Index of the ad in the pod.\n * @param {number} totalAds Total number of ads in the pod.\n */\nController.prototype.onAdPlayheadUpdated = function (currentTime, remainingTime, duration, adPosition, totalAds) {\n this.adUi.updateAdUi(currentTime, remainingTime, duration, adPosition, totalAds);\n};\n\n/**\n * Handles ad log messages.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the IMA SDK.\n */\nController.prototype.onAdLog = function (adEvent) {\n this.playerWrapper.onAdLog(adEvent);\n};\n\n/**\n * @return {Object} The current ad.\n */\nController.prototype.getCurrentAd = function () {\n return this.sdkImpl.getCurrentAd();\n};\n\n/**\n * Play content.\n */\nController.prototype.playContent = function () {\n this.playerWrapper.play();\n};\n\n/**\n * Handles when a linear ad starts.\n */\nController.prototype.onLinearAdStart = function () {\n this.adUi.onLinearAdStart();\n this.playerWrapper.onAdStart();\n};\n\n/**\n * Handles when a non-linear ad loads.\n */\nController.prototype.onNonLinearAdLoad = function () {\n this.adUi.onNonLinearAdLoad();\n};\n\n/**\n * Handles when a non-linear ad starts.\n */\nController.prototype.onNonLinearAdStart = function () {\n this.adUi.onNonLinearAdLoad();\n this.playerWrapper.onAdStart();\n};\n\n/**\n * Get the player width.\n *\n * @return {number} The width of the player.\n */\nController.prototype.getPlayerWidth = function () {\n return this.playerWrapper.getPlayerWidth();\n};\n\n/**\n * Get the player height.\n *\n * @return {number} The height of the player.\n */\nController.prototype.getPlayerHeight = function () {\n return this.playerWrapper.getPlayerHeight();\n};\n\n/**\n * Tells the player wrapper that ads are ready.\n */\nController.prototype.onAdsReady = function () {\n this.playerWrapper.onAdsReady();\n};\n\n/**\n * Called when the player wrapper detects that the player has been resized.\n *\n * @param {number} width The post-resize width of the player.\n * @param {number} height The post-resize height of the player.\n */\nController.prototype.onPlayerResize = function (width, height) {\n this.sdkImpl.onPlayerResize(width, height);\n};\n\n/**\n * Called by the player wrapper when content completes.\n */\nController.prototype.onContentComplete = function () {\n this.sdkImpl.onContentComplete();\n};\n\n/**\n * Called by the player wrapper when it's time to play a post-roll but we don't\n * have one to play.\n */\nController.prototype.onNoPostroll = function () {\n this.playerWrapper.onNoPostroll();\n};\n\n/**\n * Called when content and all ads have completed.\n */\nController.prototype.onContentAndAdsCompleted = function () {\n for (var index in this.contentAndAdsEndedListeners) {\n if (typeof this.contentAndAdsEndedListeners[index] === 'function') {\n this.contentAndAdsEndedListeners[index]();\n }\n }\n};\n\n/**\n * Called when the player is disposed.\n */\nController.prototype.onPlayerDisposed = function () {\n this.contentAndAdsEndedListeners = [];\n this.sdkImpl.onPlayerDisposed();\n};\n\n/**\n * Called when the player is ready to play a pre-roll.\n */\nController.prototype.onPlayerReadyForPreroll = function () {\n this.sdkImpl.onPlayerReadyForPreroll();\n};\n\n/**\n * Called if the ad times out.\n */\nController.prototype.onAdTimeout = function () {\n this.sdkImpl.onAdTimeout();\n};\n\n/**\n * Called when the player is ready.\n */\nController.prototype.onPlayerReady = function () {\n this.sdkImpl.onPlayerReady();\n};\n\n/**\n * Called when the player enters fullscreen.\n */\nController.prototype.onPlayerEnterFullscreen = function () {\n this.adUi.onPlayerEnterFullscreen();\n this.sdkImpl.onPlayerEnterFullscreen();\n};\n\n/**\n * Called when the player exits fullscreen.\n */\nController.prototype.onPlayerExitFullscreen = function () {\n this.adUi.onPlayerExitFullscreen();\n this.sdkImpl.onPlayerExitFullscreen();\n};\n\n/**\n * Called when the player volume changes.\n *\n * @param {number} volume The new player volume.\n */\nController.prototype.onPlayerVolumeChanged = function (volume) {\n this.adUi.onPlayerVolumeChanged(volume);\n this.sdkImpl.onPlayerVolumeChanged(volume);\n};\n\n/**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ad tag is\n * requested when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adTag The ad tag to be requested when the content loads.\n * Leave blank to use the existing ad tag.\n */\nController.prototype.setContentWithAdTag = function (contentSrc, adTag) {\n this.reset();\n this.settings.adTagUrl = adTag ? adTag : this.settings.adTagUrl;\n this.playerWrapper.changeSource(contentSrc);\n};\n\n/**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ads response is\n * used when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adsResponse The ads response to be requested when the\n * content loads. Leave blank to use the existing ads response.\n */\nController.prototype.setContentWithAdsResponse = function (contentSrc, adsResponse) {\n this.reset();\n this.settings.adsResponse = adsResponse ? adsResponse : this.settings.adsResponse;\n this.playerWrapper.changeSource(contentSrc);\n};\n\n/**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ads request is\n * used when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?Object} adsRequest The ads request to be requested when the\n * content loads. Leave blank to use the existing ads request.\n */\nController.prototype.setContentWithAdsRequest = function (contentSrc, adsRequest) {\n this.reset();\n this.settings.adsRequest = adsRequest ? adsRequest : this.settings.adsRequest;\n this.playerWrapper.changeSource(contentSrc);\n};\n\n/**\n * Resets the state of the plugin.\n */\nController.prototype.reset = function () {\n this.sdkImpl.reset();\n this.playerWrapper.reset();\n this.adUi.reset();\n};\n\n/**\n * Listener JSDoc for ESLint. This listener can be passed to\n * (add|remove)ContentEndedListener.\n * @callback listener\n */\n\n/**\n * Adds a listener for the 'readyforpostroll' event of the video player. This\n * should be used instead of setting an 'readyforpostroll' listener directly to\n * ensure that the ima can do proper cleanup of the SDK before other event\n * listeners are called.\n * @param {listener} listener The listener to be called when content\n * completes.\n */\nController.prototype.addContentEndedListener = function (listener) {\n this.playerWrapper.addContentEndedListener(listener);\n};\n\n/**\n * Adds a listener that will be called when content and all ads have\n * finished playing.\n * @param {listener} listener The listener to be called when content and ads\n * complete.\n */\nController.prototype.addContentAndAdsEndedListener = function (listener) {\n this.contentAndAdsEndedListeners.push(listener);\n};\n\n/**\n * Sets the listener to be called to trigger manual ad break playback.\n * @param {listener} listener The listener to be called to trigger manual ad\n * break playback.\n */\nController.prototype.setAdBreakReadyListener = function (listener) {\n this.sdkImpl.setAdBreakReadyListener(listener);\n};\n\n/**\n * Changes the flag to show or hide the ad countdown timer.\n *\n * @param {boolean} showCountdownIn Show or hide the countdown timer.\n */\nController.prototype.setShowCountdown = function (showCountdownIn) {\n this.adUi.setShowCountdown(showCountdownIn);\n this.showCountdown = showCountdownIn;\n this.adUi.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';\n};\n\n/**\n * Initializes the AdDisplayContainer. On mobile, this must be done as a\n * result of user action.\n */\nController.prototype.initializeAdDisplayContainer = function () {\n this.sdkImpl.initializeAdDisplayContainer();\n};\n\n/**\n * Called by publishers in manual ad break playback mode to start an ad\n * break.\n */\nController.prototype.playAdBreak = function () {\n this.sdkImpl.playAdBreak();\n};\n\n/**\n * Callback JSDoc for ESLint. This callback can be passed to addEventListener.\n * @callback callback\n */\n\n/**\n * Ads an EventListener to the AdsManager. For a list of available events,\n * see\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent#.Type\n * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to\n * listen.\n * @param {callback} callback The method to call when the event is fired.\n */\nController.prototype.addEventListener = function (event, callback) {\n this.sdkImpl.addEventListener(event, callback);\n};\n\n/**\n * Returns the instance of the AdsManager.\n * @return {google.ima.AdsManager} The AdsManager being used by the plugin.\n */\nController.prototype.getAdsManager = function () {\n return this.sdkImpl.getAdsManager();\n};\n\n/**\n * Returns the instance of the player id.\n * @return {string} The player id.\n */\nController.prototype.getPlayerId = function () {\n return this.playerWrapper.getPlayerId();\n};\n\n/**\n * Changes the ad tag. You will need to call requestAds after this method\n * for the new ads to be requested.\n * @param {?string} adTag The ad tag to be requested the next time\n * requestAds is called.\n */\nController.prototype.changeAdTag = function (adTag) {\n this.reset();\n this.settings.adTagUrl = adTag;\n};\n\n/**\n * Pauses the ad.\n */\nController.prototype.pauseAd = function () {\n this.adUi.onAdsPaused();\n this.sdkImpl.pauseAds();\n};\n\n/**\n * Resumes the ad.\n */\nController.prototype.resumeAd = function () {\n this.adUi.onAdsPlaying();\n this.sdkImpl.resumeAds();\n};\n\n/**\n * Toggles video/ad playback.\n */\nController.prototype.togglePlayback = function () {\n this.playerWrapper.togglePlayback();\n};\n\n/**\n * @return {boolean} true if we expect that ads will autoplay. false otherwise.\n */\nController.prototype.adsWillAutoplay = function () {\n if (this.settings.adsWillAutoplay !== undefined) {\n return this.settings.adsWillAutoplay;\n } else if (this.settings.adWillAutoplay !== undefined) {\n return this.settings.adWillAutoplay;\n } else {\n return !!this.playerWrapper.getPlayerOptions().autoplay;\n }\n};\n\n/**\n * @return {boolean} true if we expect that ads will autoplay. false otherwise.\n */\nController.prototype.adsWillPlayMuted = function () {\n if (this.settings.adsWillPlayMuted !== undefined) {\n return this.settings.adsWillPlayMuted;\n } else if (this.settings.adWillPlayMuted !== undefined) {\n return this.settings.adWillPlayMuted;\n } else if (this.playerWrapper.getPlayerOptions().muted !== undefined) {\n return this.playerWrapper.getPlayerOptions().muted;\n } else {\n return this.playerWrapper.getVolume() == 0;\n }\n};\n\n/**\n * Triggers an event on the VJS player\n * @param {string} name The event name.\n * @param {Object} data The event data.\n */\nController.prototype.triggerPlayerEvent = function (name, data) {\n this.playerWrapper.triggerPlayerEvent(name, data);\n};\n\n/**\n * Copyright 2021 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Wraps the video.js stream player for the plugin.\n *\n * @param {!Object} player Video.js player instance.\n * @param {!Object} adsPluginSettings Settings for the contrib-ads plugin.\n * @param {!DaiController} daiController Reference to the parent controller.\n */\nvar PlayerWrapper = function PlayerWrapper(player, adsPluginSettings, daiController) {\n /**\n * Instance of the video.js player.\n */\n this.vjsPlayer = player;\n\n /**\n * Plugin DAI controller.\n */\n this.daiController = daiController;\n\n /**\n * Video.js control bar.\n */\n this.vjsControls = this.vjsPlayer.getChild('controlBar');\n\n /**\n * Vanilla HTML5 video player underneath the video.js player.\n */\n this.h5Player = null;\n this.vjsPlayer.on('dispose', this.playerDisposedListener.bind(this));\n this.vjsPlayer.on('pause', this.onPause.bind(this));\n this.vjsPlayer.on('play', this.onPlay.bind(this));\n this.vjsPlayer.on('seeked', this.onSeekEnd.bind(this));\n this.vjsPlayer.ready(this.onPlayerReady.bind(this));\n if (!this.vjsPlayer.ads) {\n window.console.warn('You may be using a version of videojs-contrib-ads ' + 'that is not compatible with your version of video.js.');\n }\n this.vjsPlayer.ads(adsPluginSettings);\n};\n\n/**\n * Called in response to the video.js player's 'disposed' event.\n */\nPlayerWrapper.prototype.playerDisposedListener = function () {\n this.contentEndedListeners = [];\n this.daiController.onPlayerDisposed();\n};\n\n/**\n * Called on the player 'pause' event. Handles displaying controls during\n * paused ad breaks.\n */\nPlayerWrapper.prototype.onPause = function () {\n // This code will run if the stream is paused during an ad break. Since\n // controls are usually hidden during ads, they will now show to allow\n // users to resume ad playback.\n if (this.daiController.isInAdBreak()) {\n this.vjsControls.show();\n }\n};\n\n/**\n * Called on the player 'play' event. Handles hiding controls during\n * ad breaks while playing.\n */\nPlayerWrapper.prototype.onPlay = function () {\n if (this.daiController.isInAdBreak()) {\n this.vjsControls.hide();\n }\n};\n\n/**\n * Called on the player's 'seeked' event. Sets up handling for ad break\n * snapback for VOD streams.\n */\nPlayerWrapper.prototype.onSeekEnd = function () {\n this.daiController.onSeekEnd(this.vjsPlayer.currentTime());\n};\n\n/**\n * Called on the player's 'ready' event to begin initiating IMA.\n */\nPlayerWrapper.prototype.onPlayerReady = function () {\n this.h5Player = document.getElementById(this.getPlayerId()).getElementsByClassName('vjs-tech')[0];\n this.daiController.onPlayerReady();\n};\n\n/**\n * @return {!Object} The stream player.\n */\nPlayerWrapper.prototype.getStreamPlayer = function () {\n return this.h5Player;\n};\n\n/**\n * @return {!Object} The video.js player.\n */\nPlayerWrapper.prototype.getVjsPlayer = function () {\n return this.vjsPlayer;\n};\n\n/**\n * @return {!Object} The vjs player's options object.\n */\nPlayerWrapper.prototype.getPlayerOptions = function () {\n return this.vjsPlayer.options_;\n};\n\n/**\n * Returns the instance of the player id.\n * @return {string} The player id.\n */\nPlayerWrapper.prototype.getPlayerId = function () {\n return this.vjsPlayer.id();\n};\n\n/**\n * Handles ad errors.\n *\n * @param {!Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nPlayerWrapper.prototype.onAdError = function (adErrorEvent) {\n this.vjsControls.show();\n var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;\n this.vjsPlayer.trigger({\n type: 'adserror',\n data: {\n AdError: errorMessage,\n AdErrorEvent: adErrorEvent\n }\n });\n};\n\n/**\n * Handles ad break starting.\n */\nPlayerWrapper.prototype.onAdBreakStart = function () {\n this.vjsControls.hide();\n};\n\n/**\n * Handles ad break ending.\n */\nPlayerWrapper.prototype.onAdBreakEnd = function () {\n this.vjsControls.show();\n};\n\n/**\n * Reset the player.\n */\nPlayerWrapper.prototype.reset = function () {\n this.vjsControls.show();\n};\n\n/**\n * Copyright 2021 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Implementation of the IMA DAI SDK for the plugin.\n *\n * @param {DaiController!} daiController Reference to the parent DAI\n * controller.\n *\n * @constructor\n * @struct\n * @final\n */\nvar SdkImpl = function SdkImpl(daiController) {\n /**\n * Plugin DAI controller.\n */\n this.daiController = daiController;\n\n /**\n * The html5 stream player.\n */\n this.streamPlayer = null;\n\n /**\n * The videoJS stream player.\n */\n this.vjsPlayer = null;\n\n /**\n * IMA SDK StreamManager\n */\n this.streamManager = null;\n\n /**\n * IMA stream UI settings.\n */\n /* eslint no-undef: 'error' */\n /* global google */\n this.uiSettings = new google.ima.dai.api.UiSettings();\n\n /**\n * If the stream is currently in an ad break.\n */\n this.isAdBreak = false;\n\n /**\n * If the stream is currently seeking from a snapback.\n */\n this.isSnapback = false;\n\n /**\n * Originally seeked to time, to return stream to after ads.\n */\n this.snapForwardTime = 0;\n\n /**\n * Timed metadata for the stream.\n */\n this.timedMetadata;\n\n /**\n * Timed metadata record.\n */\n this.metadataLoaded = {};\n this.SOURCE_TYPES = {\n hls: 'application/x-mpegURL',\n dash: 'application/dash+xml'\n };\n};\n\n/**\n * Creates and initializes the IMA DAI SDK objects.\n */\nSdkImpl.prototype.initImaDai = function () {\n var _this = this;\n this.streamPlayer = this.daiController.getStreamPlayer();\n this.vjsPlayer = this.daiController.getVjsPlayer();\n this.createAdUiDiv();\n if (this.daiController.getSettings().locale) {\n this.uiSettings.setLocale(this.daiController.getSettings().locale);\n }\n this.streamManager = new google.ima.dai.api.StreamManager(this.streamPlayer, this.adUiDiv, this.uiSettings);\n this.streamPlayer.addEventListener('pause', this.onStreamPause);\n this.streamPlayer.addEventListener('play', this.onStreamPlay);\n var imaEvents = [google.ima.dai.api.StreamEvent.Type.LOADED, google.ima.dai.api.StreamEvent.Type.ERROR, google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED, google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED];\n imaEvents.forEach(function (event) {\n _this.streamManager.addEventListener(event, _this.onStreamEvent.bind(_this));\n });\n this.vjsPlayer.textTracks().onaddtrack = this.onAddTrack.bind(this);\n this.vjsPlayer.trigger({\n type: 'stream-manager',\n StreamManager: this.streamManager\n });\n this.requestStream();\n};\n\n/**\n * Called when the video player has metadata to process.\n * @param {Event!} event The event that triggered this call.\n */\nSdkImpl.prototype.onAddTrack = function (event) {\n var _this2 = this;\n var track = event.track;\n if (track.kind === 'metadata') {\n track.mode = 'hidden';\n track.addEventListener('cuechange', function (e) {\n var _iterator = _createForOfIteratorHelper(track.activeCues),\n _step;\n try {\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var cue = _step.value;\n var metadata = {};\n metadata[cue.value.key] = cue.value.data;\n _this2.streamManager.onTimedMetadata(metadata);\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n });\n }\n};\n\n/**\n * Creates the ad UI container.\n */\nSdkImpl.prototype.createAdUiDiv = function () {\n var uiDiv = document.createElement('div');\n uiDiv.id = 'ad-ui';\n // 3em is the height of the control bar.\n uiDiv.style.height = 'calc(100% - 3em)';\n this.streamPlayer.parentNode.appendChild(uiDiv);\n this.adUiDiv = uiDiv;\n};\n\n/**\n * Called on pause to update the ad UI.\n */\nSdkImpl.prototype.onStreamPause = function () {\n if (this.isAdBreak) {\n this.adUiDiv.style.display = 'none';\n }\n};\n\n/**\n * Called on play to update the ad UI.\n */\nSdkImpl.prototype.onStreamPlay = function () {\n if (this.isAdBreak) {\n this.adUiDiv.style.display = 'block';\n }\n};\n\n/**\n * Called on play to update the ad UI.\n * @param {number} currentTime the current time of the stream.\n */\nSdkImpl.prototype.onSeekEnd = function (currentTime) {\n var streamType = this.daiController.getSettings().streamType;\n if (streamType === 'live') {\n return;\n }\n if (this.isSnapback) {\n this.isSnapback = false;\n return;\n }\n var previousCuePoint = this.streamManager.previousCuePointForStreamTime(currentTime);\n if (previousCuePoint && !previousCuePoint.played) {\n this.isSnapback = true;\n this.snapForwardTime = currentTime;\n this.vjsPlayer.currentTime(previousCuePoint.start);\n }\n};\n\n/**\n * Handles IMA events.\n * @param {google.ima.StreamEvent!} event the IMA event\n */\nSdkImpl.prototype.onStreamEvent = function (event) {\n switch (event.type) {\n case google.ima.dai.api.StreamEvent.Type.LOADED:\n this.loadUrl(event.getStreamData().url);\n break;\n case google.ima.dai.api.StreamEvent.Type.ERROR:\n window.console.warn('Error loading stream, attempting to play backup ' + 'stream. ' + event.getStreamData().errorMessage);\n this.daiController.onErrorLoadingAds(event);\n if (this.daiController.getSettings().fallbackStreamUrl) {\n this.loadUrl(this.daiController.getSettings().fallbackStreamUrl);\n }\n break;\n case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:\n this.isAdBreak = true;\n this.adUiDiv.style.display = 'block';\n this.daiController.onAdBreakStart();\n break;\n case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:\n this.isAdBreak = false;\n this.adUiDiv.style.display = 'none';\n this.daiController.onAdBreakEnd();\n if (this.snapForwardTime && this.snapForwardTime > this.vjsPlayer.currentTime()) {\n this.vjsPlayer.currentTime(this.snapForwardTime);\n this.snapForwardTime = 0;\n }\n break;\n }\n};\n\n/**\n * Loads the stream URL .\n * @param {string} streamUrl the URL for the stream being loaded.\n */\nSdkImpl.prototype.loadUrl = function (streamUrl) {\n this.vjsPlayer.ready(function () {\n var streamFormat = this.daiController.getSettings().streamFormat;\n this.vjsPlayer.src({\n src: streamUrl,\n type: this.SOURCE_TYPES[streamFormat]\n });\n var bookmarkTime = this.daiController.getSettings().bookmarkTime;\n if (bookmarkTime) {\n var startTime = this.streamManager.streamTimeForContentTime(bookmarkTime);\n // Seeking on load triggers the onSeekEnd event, so treat this seek as\n // if it's snapback. Without this, resuming at a bookmark kicks you\n // back to the ad before the bookmark.\n this.isSnapback = true;\n this.vjsPlayer.currentTime(startTime);\n }\n }.bind(this));\n};\n\n/**\n * Creates the AdsRequest and request ads through the AdsLoader.\n */\nSdkImpl.prototype.requestStream = function () {\n var streamRequest;\n var streamType = this.daiController.getSettings().streamType;\n if (streamType === 'vod') {\n streamRequest = new google.ima.dai.api.VODStreamRequest();\n streamRequest.contentSourceId = this.daiController.getSettings().cmsId;\n streamRequest.videoId = this.daiController.getSettings().videoId;\n } else if (streamType === 'live') {\n streamRequest = new google.ima.dai.api.LiveStreamRequest();\n streamRequest.assetKey = this.daiController.getSettings().assetKey;\n } else {\n window.console.warn('No valid stream type selected');\n }\n streamRequest.format = this.daiController.getSettings().streamFormat;\n if (this.daiController.getSettings().apiKey) {\n streamRequest.apiKey = this.daiController.getSettings().apiKey;\n }\n if (this.daiController.getSettings().authToken) {\n streamRequest.authToken = this.daiController.getSettings().authToken;\n }\n if (this.daiController.getSettings().adTagParameters) {\n streamRequest.adTagParameters = this.daiController.getSettings().adTagParameters;\n }\n if (this.daiController.getSettings().streamActivityMonitorId) {\n streamRequest.streamActivityMonitorId = this.daiController.getSettings().streamActivityMonitorId;\n }\n if (this.daiController.getSettings().omidMode) {\n streamRequest.omidAccessModeRules = {};\n var omidValues = this.daiController.getSettings().omidMode;\n if (omidValues.FULL) {\n streamRequest.omidAccessModeRules[google.ima.OmidAccessMode.FULL] = omidValues.FULL;\n }\n if (omidValues.DOMAIN) {\n streamRequest.omidAccessModeRules[google.ima.OmidAccessMode.DOMAIN] = omidValues.DOMAIN;\n }\n if (omidValues.LIMITED) {\n streamRequest.omidAccessModeRules[google.ima.OmidAccessMode.LIMITED] = omidValues.LIMITED;\n }\n }\n this.streamManager.requestStream(streamRequest);\n this.vjsPlayer.trigger({\n type: 'stream-request',\n StreamRequest: streamRequest\n });\n};\n\n/**\n * Initiates IMA when the player is ready.\n */\nSdkImpl.prototype.onPlayerReady = function () {\n this.initImaDai();\n};\n\n/**\n * Reset the StreamManager when the player is disposed.\n */\nSdkImpl.prototype.onPlayerDisposed = function () {\n if (this.streamManager) {\n this.streamManager.reset();\n }\n};\n\n/**\n * Adds an EventListener to the StreamManager. For a list of available events,\n * see\n * https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/html5/reference/js/StreamEvent#.Type\n * @param {google.ima.dai.api.StreamEvent.Type} event The StreamEvent.Type for\n * which to listen.\n * @param {callback} callback The method to call when the event is fired.\n */\nSdkImpl.prototype.addEventListener = function (event, callback) {\n if (this.streamManager) {\n this.streamManager.addEventListener(event, callback);\n }\n};\n\n/**\n * Returns the instance of the StreamManager.\n * @return {google.ima.StreamManager!} The StreamManager being used by the\n * plugin.\n */\nSdkImpl.prototype.getStreamManager = function () {\n return this.streamManager;\n};\n\n/**\n * Reset the SDK implementation.\n */\nSdkImpl.prototype.reset = function () {\n if (this.streamManager) {\n this.streamManager.reset();\n }\n};\n\n/**\n * Copyright 2021 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * The coordinator for the DAI portion of the plugin. Facilitates\n * communication between all other plugin classes.\n *\n * @param {Object!} player Instance of the video.js player.\n * @param {Object!} options Options provided by the implementation.\n * @constructor\n * @struct\n * @final\n */\nvar DaiController = function DaiController(player, options) {\n /**\n * If the stream is currently in an ad break.\n * @type {boolean}\n */\n this.inAdBreak = false;\n\n /**\n * Stores user-provided settings.\n * @type {Object!}\n */\n this.settings = {};\n\n /**\n * Whether or not we are running on a mobile platform.\n */\n this.isMobile = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/Android/i);\n\n /**\n * Whether or not we are running on an iOS platform.\n */\n this.isIos = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i);\n this.initWithSettings(options);\n\n /**\n * Stores contrib-ads default settings.\n */\n var contribAdsDefaults = {\n debug: this.settings.debug,\n timeout: this.settings.timeout,\n prerollTimeout: this.settings.prerollTimeout\n };\n var adsPluginSettings = Object.assign({}, contribAdsDefaults, options.contribAdsSettings || {});\n this.playerWrapper = new PlayerWrapper(player, adsPluginSettings, this);\n this.sdkImpl = new SdkImpl(this);\n};\nDaiController.IMA_DEFAULTS = {\n adLabel: 'Advertisement',\n adLabelNofN: 'of',\n debug: false,\n disableAdControls: false,\n showControlsForJSAds: true\n};\n\n/**\n * Extends the settings to include user-provided settings.\n *\n * @param {Object!} options Options to be used in initialization.\n */\nDaiController.prototype.initWithSettings = function (options) {\n this.settings = Object.assign({}, DaiController.IMA_DEFAULTS, options || {});\n this.warnAboutDeprecatedSettings();\n\n // Default showing countdown timer to true.\n this.showCountdown = true;\n if (this.settings.showCountdown === false) {\n this.showCountdown = false;\n }\n};\n\n/**\n * Logs console warnings when deprecated settings are used.\n */\nDaiController.prototype.warnAboutDeprecatedSettings = function () {\n var _this = this;\n var deprecatedSettings = [\n // Currently no DAI plugin settings are deprecated.\n ];\n deprecatedSettings.forEach(function (setting) {\n if (_this.settings[setting] !== undefined) {\n console.warn('WARNING: videojs.imaDai setting ' + setting + ' is deprecated');\n }\n });\n};\n\n/**\n * Return the settings object.\n *\n * @return {Object!} The settings object.\n */\nDaiController.prototype.getSettings = function () {\n return this.settings;\n};\n\n/**\n * Return whether or not we're in a mobile environment.\n *\n * @return {boolean} True if running on mobile, false otherwise.\n */\nDaiController.prototype.getIsMobile = function () {\n return this.isMobile;\n};\n\n/**\n * Return whether or not we're in an iOS environment.\n *\n * @return {boolean} True if running on iOS, false otherwise.\n */\nDaiController.prototype.getIsIos = function () {\n return this.isIos;\n};\n\n/**\n * @return {Object!} The html5 player.\n */\nDaiController.prototype.getStreamPlayer = function () {\n return this.playerWrapper.getStreamPlayer();\n};\n\n/**\n * @return {Object!} The video.js player.\n */\nDaiController.prototype.getVjsPlayer = function () {\n return this.playerWrapper.getVjsPlayer();\n};\n\n/**\n * Requests the stream.\n */\nDaiController.prototype.requestStream = function () {\n this.sdkImpl.requestStream();\n};\n\n/**\n * Add or modify a setting.\n *\n * @param {string} key Key to modify\n * @param {Object!} value Value to set at key.\n*/\nDaiController.prototype.setSetting = function (key, value) {\n this.settings[key] = value;\n};\n\n/**\n * Called when there is an error loading ads.\n *\n * @param {Object!} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nDaiController.prototype.onErrorLoadingAds = function (adErrorEvent) {\n this.playerWrapper.onAdError(adErrorEvent);\n};\n\n/**\n * Relays ad errors to the player wrapper.\n *\n * @param {Object!} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nDaiController.prototype.onAdError = function (adErrorEvent) {\n this.playerWrapper.onAdError(adErrorEvent);\n};\n\n/**\n * Signals player that an ad break has started.\n */\nDaiController.prototype.onAdBreakStart = function () {\n this.inAdBreak = true;\n this.playerWrapper.onAdBreakStart();\n};\n\n/**\n * Signals player that an ad break has ended.\n */\nDaiController.prototype.onAdBreakEnd = function () {\n this.inAdBreak = false;\n this.playerWrapper.onAdBreakEnd();\n};\n\n/**\n * Called when the player is disposed.\n */\nDaiController.prototype.onPlayerDisposed = function () {\n this.contentAndAdsEndedListeners = [];\n this.sdkImpl.onPlayerDisposed();\n};\n\n/**\n * Returns if the stream is currently in an ad break.\n * @return {boolean} If the stream is currently in an ad break.\n */\nDaiController.prototype.isInAdBreak = function () {\n return this.inAdBreak;\n};\n\n/**\n * Called on seek end to check for ad snapback.\n * @param {number} currentTime the current time of the stream.\n */\nDaiController.prototype.onSeekEnd = function (currentTime) {\n this.sdkImpl.onSeekEnd(currentTime);\n};\n\n/**\n * Called when the player is ready.\n */\nDaiController.prototype.onPlayerReady = function () {\n this.sdkImpl.onPlayerReady();\n};\n\n/**\n * Resets the state of the plugin.\n */\nDaiController.prototype.reset = function () {\n this.sdkImpl.reset();\n this.playerWrapper.reset();\n};\n\n/**\n * Adds an EventListener to the StreamManager. For a list of available events,\n * see\n * https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/html5/reference/js/StreamEvent\n * @param {google.ima.StreamEvent.Type!} event The AdEvent.Type for which to\n * listen.\n * @param {callback!} callback The method to call when the event is fired.\n */\nDaiController.prototype.addEventListener = function (event, callback) {\n this.sdkImpl.addEventListener(event, callback);\n};\n\n/**\n * Returns the instance of the StreamManager.\n * @return {google.ima.StreamManager!} The StreamManager being used by the\n * plugin.\n */\nDaiController.prototype.getStreamManager = function () {\n return this.sdkImpl.getStreamManager();\n};\n\n/**\n * Returns the instance of the player id.\n * @return {string} The player id.\n */\nDaiController.prototype.getPlayerId = function () {\n return this.playerWrapper.getPlayerId();\n};\n\n/**\n * @return {boolean} true if we expect that the stream will autoplay. false\n * otherwise.\n */\nDaiController.prototype.streamWillAutoplay = function () {\n if (this.settings.streamWillAutoplay !== undefined) {\n return this.settings.streamWillAutoplay;\n } else {\n return !!this.playerWrapper.getPlayerOptions().autoplay;\n }\n};\n\n/**\n * Triggers an event on the VJS player\n * @param {string} name The event name.\n * @param {Object!} data The event data.\n */\nDaiController.prototype.triggerPlayerEvent = function (name, data) {\n this.playerWrapper.triggerPlayerEvent(name, data);\n};\n\n/**\n * Exposes the ImaPlugin to a publisher implementation.\n *\n * @param {Object} player Instance of the video.js player to which this plugin\n * will be added.\n * @param {Object} options Options provided by the implementation.\n * @constructor\n * @struct\n * @final\n */\nvar ImaPlugin = function ImaPlugin(player, options) {\n this.controller = new Controller(player, options);\n\n /**\n * Listener JSDoc for ESLint. This listener can be passed to\n * addContent(AndAds)EndedListener.\n * @callback listener\n */\n\n /**\n * Adds a listener that will be called when content and all ads have\n * finished playing.\n * @param {listener} listener The listener to be called when content and ads\n * complete.\n */\n this.addContentAndAdsEndedListener = function (listener) {\n this.controller.addContentAndAdsEndedListener(listener);\n }.bind(this);\n\n /**\n * Adds a listener for the 'readyforpostroll' event of the video player. This\n * should be used instead of setting an 'readyforpostroll' listener directly\n * to ensure that the ima can do proper cleanup of the SDK before other event\n * listeners are called.\n * @param {listener} listener The listener to be called when content\n * completes.\n */\n this.addContentEndedListener = function (listener) {\n this.controller.addContentEndedListener(listener);\n }.bind(this);\n\n /**\n * Callback JSDoc for ESLint. This callback can be passed to addEventListener.\n * @callback callback\n */\n\n /**\n * Ads an EventListener to the AdsManager. For a list of available events,\n * see\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent#.Type\n * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to\n * listen.\n * @param {callback} callback The method to call when the event is fired.\n */\n this.addEventListener = function (event, callback) {\n this.controller.addEventListener(event, callback);\n }.bind(this);\n\n /**\n * Changes the ad tag. You will need to call requestAds after this method\n * for the new ads to be requested.\n * @param {?string} adTag The ad tag to be requested the next time requestAds\n * is called.\n */\n this.changeAdTag = function (adTag) {\n this.controller.changeAdTag(adTag);\n }.bind(this);\n\n /**\n * Returns the instance of the AdsManager.\n * @return {google.ima.AdsManager} The AdsManager being used by the plugin.\n */\n this.getAdsManager = function () {\n return this.controller.getAdsManager();\n }.bind(this);\n\n /**\n * Initializes the AdDisplayContainer. On mobile, this must be done as a\n * result of user action.\n */\n this.initializeAdDisplayContainer = function () {\n this.controller.initializeAdDisplayContainer();\n }.bind(this);\n\n /**\n * Pauses the ad.\n */\n this.pauseAd = function () {\n this.controller.pauseAd();\n }.bind(this);\n\n /**\n * Called by publishers in manual ad break playback mode to start an ad\n * break.\n */\n this.playAdBreak = function () {\n this.controller.playAdBreak();\n }.bind(this);\n\n /**\n * Creates the AdsRequest and request ads through the AdsLoader.\n */\n this.requestAds = function () {\n this.controller.requestAds();\n }.bind(this);\n\n /**\n * Resumes the ad.\n */\n this.resumeAd = function () {\n this.controller.resumeAd();\n }.bind(this);\n\n /**\n * Sets the listener to be called to trigger manual ad break playback.\n * @param {listener} listener The listener to be called to trigger manual ad\n * break playback.\n */\n this.setAdBreakReadyListener = function (listener) {\n this.controller.setAdBreakReadyListener(listener);\n }.bind(this);\n\n /**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ad tag is\n * requested when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adTag The ad tag to be requested when the content loads.\n * Leave blank to use the existing ad tag.\n */\n this.setContentWithAdTag = function (contentSrc, adTag) {\n this.controller.setContentWithAdTag(contentSrc, adTag);\n }.bind(this);\n\n /**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ads response is\n * used when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adsResponse The ads response to be requested when the\n * content loads. Leave blank to use the existing ads response.\n */\n this.setContentWithAdsResponse = function (contentSrc, adsResponse) {\n this.controller.setContentWithAdsResponse(contentSrc, adsResponse);\n }.bind(this);\n\n /**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ads request is\n * used when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?Object} adsRequest The ads request to be requested when the\n * content loads. Leave blank to use the existing ads request.\n */\n this.setContentWithAdsRequest = function (contentSrc, adsRequest) {\n this.controller.setContentWithAdsRequest(contentSrc, adsRequest);\n }.bind(this);\n\n /**\n * Changes the flag to show or hide the ad countdown timer.\n *\n * @param {boolean} showCountdownIn Show or hide the countdown timer.\n */\n this.setShowCountdown = function (showCountdownIn) {\n this.controller.setShowCountdown(showCountdownIn);\n }.bind(this);\n};\n\n/**\n * Exposes the ImaDaiPlugin to a publisher implementation.\n *\n * @param {Object} player Instance of the video.js player to which this plugin\n * will be added.\n * @param {Object} options Options provided by the implementation.\n * @constructor\n * @struct\n * @final\n */\nvar ImaDaiPlugin = function ImaDaiPlugin(player, options) {\n this.controller = new DaiController(player, options);\n\n /**\n * Adds a listener that will be called when content and all ads in the\n * stream have finished playing. VOD stream only.\n * @param {listener} listener The listener to be called when content and ads\n * complete.\n */\n this.streamEndedListener = function (listener) {\n this.controller.addStreamEndedListener(listener);\n }.bind(this);\n\n /**\n * Adds an EventListener to the StreamManager.\n * @param {google.ima.StreamEvent.Type} event The StreamEvent.Type for which\n * to listen.\n * @param {callback} callback The method to call when the event is fired.\n */\n this.addEventListener = function (event, callback) {\n this.controller.addEventListener(event, callback);\n }.bind(this);\n\n /**\n * Returns the instance of the StreamManager.\n * @return {google.ima.StreamManager} The StreamManager being used by the\n * plugin.\n */\n this.getStreamManager = function () {\n return this.controller.getStreamManager();\n }.bind(this);\n};\n\n/**\n * Initializes the plugin for client-side ads.\n * @param {Object} options Plugin option set on initiation.\n */\nvar init = function init(options) {\n /* eslint no-invalid-this: 'off' */\n this.ima = new ImaPlugin(this, options);\n};\n\n/**\n * LiveStream class used for DAI live streams.\n */\nvar LiveStream = /*#__PURE__*/_createClass(\n/**\n * LiveStream class constructor used for DAI live streams.\n * @param {string} streamFormat stream format, plugin currently supports only\n * 'hls' streams.\n * @param {string} assetKey live stream's asset key.\n */\nfunction LiveStream(streamFormat, assetKey) {\n _classCallCheck(this, LiveStream);\n streamFormat = streamFormat.toLowerCase();\n if (streamFormat !== 'hls' && streamFormat !== 'dash') {\n window.console.error('VodStream error: incorrect streamFormat.');\n return;\n } else if (streamFormat === 'dash') {\n window.console.error('streamFormat error: DASH streams are not' + 'currently supported by this plugin.');\n return;\n } else if (typeof assetKey !== 'string') {\n window.console.error('assetKey error: value must be string.');\n return;\n }\n this.streamFormat = streamFormat;\n this.assetKey = assetKey;\n});\n/**\n * VodStream class used for DAI VOD streams.\n */\nvar VodStream = /*#__PURE__*/_createClass(\n/**\n * VodStream class constructor used for DAI VOD streams.\n * @param {string} streamFormat stream format, plugin currently supports only\n * 'hls' streams.\n * @param {string} cmsId VOD stream's CMS ID.\n * @param {string} videoId VOD stream's video ID.\n */\nfunction VodStream(streamFormat, cmsId, videoId) {\n _classCallCheck(this, VodStream);\n streamFormat = streamFormat.toLowerCase();\n if (streamFormat !== 'hls' && streamFormat !== 'dash') {\n window.console.error('VodStream error: incorrect streamFormat.');\n return;\n } else if (streamFormat === 'dash') {\n window.console.error('streamFormat error: DASH streams are not' + 'currently supported by this plugin.');\n return;\n } else if (typeof cmsId !== 'string') {\n window.console.error('cmsId error: value must be string.');\n return;\n } else if (typeof videoId !== 'string') {\n window.console.error('videoId error: value must be string.');\n return;\n }\n this.streamFormat = streamFormat;\n this.cmsId = cmsId;\n this.videoId = videoId;\n});\n/**\n * Initializes the plugin for DAI ads.\n * @param {Object} stream Accepts either an instance of the LiveStream or\n * VodStream classes.\n * @param {Object} options Plugin option set on initiation.\n */\nvar initDai = function initDai(stream, options) {\n if (stream instanceof LiveStream) {\n options.streamType = 'live';\n options.assetKey = stream.assetKey;\n } else if (stream instanceof VodStream) {\n options.streamType = 'vod';\n options.cmsId = stream.cmsId;\n options.videoId = stream.videoId;\n } else {\n window.console.error('initDai() first parameter must be an instance of LiveStream or ' + 'VodStream.');\n return;\n }\n options.streamFormat = stream.streamFormat;\n /* eslint no-invalid-this: 'off' */\n this.imaDai = new ImaDaiPlugin(this, options);\n};\nvar registerPlugin = (video_js__WEBPACK_IMPORTED_MODULE_0___default().registerPlugin) || (video_js__WEBPACK_IMPORTED_MODULE_0___default().plugin);\nregisterPlugin('ima', init);\nregisterPlugin('imaDai', initDai);\n\n\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/videojs-ima/dist/videojs.ima.es.js?");
|
|
77
77
|
|
|
78
78
|
/***/ }),
|
|
79
79
|
|