diff --git a/docs/vast-vpaid.html b/docs/vast-vpaid.html index 943651b0..1bbf26fa 100644 --- a/docs/vast-vpaid.html +++ b/docs/vast-vpaid.html @@ -30,7 +30,7 @@ var adTagUrl = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpreonly&cmsid=496&vid=short_onecue&correlator="; - player = cloudinary.videoPlayer('player', { + player1 = cloudinary.videoPlayer('player', { cloud_name: 'demo', ads: { adTagUrl: adTagUrl, @@ -38,12 +38,22 @@ } }); - player.playlistByTag('video_race', { + player1.source('elephants'); + + player2 = cloudinary.videoPlayer('player-playlist', { + cloud_name: 'demo', + ads: { + adTagUrl: adTagUrl, + debug: true + } + }); + + player2.playlistByTag('video_race', { autoAdvance: true, repeat: true, }).then(function() { var divElem = document.querySelector("#playlist-data"); - var list = player.playlist().list().map(function(source) { + var list = player2.playlist().list().map(function(source) { return source.publicId() }).join(', '); @@ -62,17 +72,33 @@

Cloudinary Video Player

VAST and VPAID

- - -

+
+

Single video with ads

+ +
+ +
+

Playlist with Ads

+ + + +

+

Ads and monetization documentation @@ -84,6 +110,16 @@

Example Code:

<video id="player" + playsinline + controls + muted + class="cld-video-player" + width="500"> + </video> + + <video + id="player-playlist" + playsinline controls muted autoplay @@ -94,36 +130,30 @@

Example Code:

- // Initialize player - var player = cloudinary.videoPlayer('player', { - cloud_name: 'demo' , - plugins: { - vastClient: { - adTagUrl: "https://rtr.innovid.com/r1.5554946ab01d97.36996823;cb={random_number}", - adCancelTimeout: 5000, - adsEnabled: true, - playAdAlways: true - } + player1 = cloudinary.videoPlayer('player', { + cloud_name: 'demo', + ads: { + adTagUrl: AD_TAG_URL, + debug: true + } + }); + + player1.source('elephants'); + + player2 = cloudinary.videoPlayer('player-playlist', { + cloud_name: 'demo', + ads: { + adTagUrl: AD_TAG_URL, + debug: true } }); - // Pass a sorter to sort list in alphabetical order by publicId - var sorter = function(a, b) { - if (a.publicId < b.publicId) return 1; - if (a.publicId > b.publicId) return -1; - return 0; - }; - - // Fetch playlist by tag. Since this operation involves an API call - // the function returns a Promise when the operation completes. - // The return value is 'player'. - player.playlistByTag('demo', { - sorter: sorter, - autoAdvance: 0, - repeat: true + player2.playlistByTag('video_race', { + autoAdvance: true, + repeat: true, }).then(function() { var divElem = document.querySelector("#playlist-data"); - var list = player.playlist().list().map(function(source) { + var list = player2.playlist().list().map(function(source) { return source.publicId() }).join(', '); diff --git a/package-lock.json b/package-lock.json index 0f07f47d..390a5278 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "uuid": "^9.0.0", "video.js": "8.5.2", "videojs-contrib-ads": "^7.3.2", - "videojs-ima": "^2.1.0", + "videojs-ima": "^2.3.0", "videojs-per-source-behaviors": "^3.0.0", "webfontloader": "^1.6.28" }, @@ -23621,14 +23621,14 @@ "integrity": "sha512-X1LuPfLZPisPLrANIAKCknZbZu5obVM/ylfd1CN+SsCmPZQ3UMDPcvLTpPBJxcBuTpHQq2MO1QCFt7p8spnZ/w==" }, "node_modules/videojs-ima": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/videojs-ima/-/videojs-ima-2.2.0.tgz", - "integrity": "sha512-VKg7mZsaiW89ko2Sjfz/sDcCbCTjj2OAkg8CakvCs9ZiVg20g6QYVtEWj249V/HTm0/1X01GEPk9hnIrRzgd+A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/videojs-ima/-/videojs-ima-2.3.0.tgz", + "integrity": "sha512-8r0BZGT+WCTO6PePyKZHikV79Ojqh4yLMx4+DmPyXeRcKUVsQ7Va0R7Ok8GRcA8Zy3l1PM6jzLrD/W1rwKhZ8g==", "dependencies": { "@hapi/cryptiles": "^5.1.0", "can-autoplay": "^3.0.2", "extend": ">=3.0.2", - "videojs-contrib-ads": "^6.9.0 || ^7" + "videojs-contrib-ads": "^6.9.0" }, "engines": { "node": ">=0.8.0" @@ -23637,6 +23637,151 @@ "video.js": "^5.19.2 || ^6 || ^7 || ^8" } }, + "node_modules/videojs-ima/node_modules/@videojs/http-streaming": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.16.2.tgz", + "integrity": "sha512-etPTUdCFu7gUWc+1XcbiPr+lrhOcBu3rV5OL1M+3PDW89zskScAkkcdqYzP4pFodBPye/ydamQoTDScOnElw5A==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "3.0.5", + "aes-decrypter": "3.1.3", + "global": "^4.4.0", + "m3u8-parser": "4.8.0", + "mpd-parser": "^0.22.1", + "mux.js": "6.0.1", + "video.js": "^6 || ^7" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + }, + "peerDependencies": { + "video.js": "^6 || ^7" + } + }, + "node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.21.5.tgz", + "integrity": "sha512-WRq86tXZKrThA9mK+IR+v4tIQVVvnb5LhvL71fD2AX7TxVOPdaeK1X/wyuUruBqWaOG3w2sZXoMY6HF2Jlo9qA==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/http-streaming": "2.16.2", + "@videojs/vhs-utils": "^3.0.4", + "@videojs/xhr": "2.6.0", + "aes-decrypter": "3.1.3", + "global": "^4.4.0", + "keycode": "^2.2.0", + "m3u8-parser": "4.8.0", + "mpd-parser": "0.22.1", + "mux.js": "6.0.1", + "safe-json-parse": "4.0.0", + "videojs-font": "3.2.0", + "videojs-vtt.js": "^0.15.5" + } + }, + "node_modules/videojs-ima/node_modules/@videojs/vhs-utils": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz", + "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "global": "^4.4.0", + "url-toolkit": "^2.2.1" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, + "node_modules/videojs-ima/node_modules/aes-decrypter": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz", + "integrity": "sha512-VkG9g4BbhMBy+N5/XodDeV6F02chEk9IpgRTq/0bS80y4dzy79VH2Gtms02VXomf3HmyRe3yyJYkJ990ns+d6A==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^3.0.5", + "global": "^4.4.0", + "pkcs7": "^1.0.4" + } + }, + "node_modules/videojs-ima/node_modules/m3u8-parser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.8.0.tgz", + "integrity": "sha512-UqA2a/Pw3liR6Df3gwxrqghCP17OpPlQj6RBPLYygf/ZSQ4MoSgvdvhvt35qV+3NaaA0FSZx93Ix+2brT1U7cA==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^3.0.5", + "global": "^4.4.0" + } + }, + "node_modules/videojs-ima/node_modules/mpd-parser": { + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.22.1.tgz", + "integrity": "sha512-fwBebvpyPUU8bOzvhX0VQZgSohncbgYwUyJJoTSNpmy7ccD2ryiCvM7oRkn/xQH5cv73/xU7rJSNCLjdGFor0Q==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^3.0.5", + "@xmldom/xmldom": "^0.8.3", + "global": "^4.4.0" + }, + "bin": { + "mpd-to-m3u8-json": "bin/parse.js" + } + }, + "node_modules/videojs-ima/node_modules/mux.js": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-6.0.1.tgz", + "integrity": "sha512-22CHb59rH8pWGcPGW5Og7JngJ9s+z4XuSlYvnxhLuc58cA1WqGDQPzuG8I+sPm1/p0CdgpzVTaKW408k5DNn8w==", + "dependencies": { + "@babel/runtime": "^7.11.2", + "global": "^4.4.0" + }, + "bin": { + "muxjs-transmux": "bin/transmux.js" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, + "node_modules/videojs-ima/node_modules/videojs-contrib-ads": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/videojs-contrib-ads/-/videojs-contrib-ads-6.9.0.tgz", + "integrity": "sha512-nzKz+jhCGMTYffSNVYrmp9p70s05v6jUMOY3Z7DpVk3iFrWK4Zi/BIkokDWrMoHpKjdmCdKzfJVBT+CrUj6Spw==", + "dependencies": { + "global": "^4.3.2", + "video.js": "^6 || ^7" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, + "node_modules/videojs-ima/node_modules/videojs-contrib-ads/node_modules/video.js": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.21.5.tgz", + "integrity": "sha512-WRq86tXZKrThA9mK+IR+v4tIQVVvnb5LhvL71fD2AX7TxVOPdaeK1X/wyuUruBqWaOG3w2sZXoMY6HF2Jlo9qA==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/http-streaming": "2.16.2", + "@videojs/vhs-utils": "^3.0.4", + "@videojs/xhr": "2.6.0", + "aes-decrypter": "3.1.3", + "global": "^4.4.0", + "keycode": "^2.2.0", + "m3u8-parser": "4.8.0", + "mpd-parser": "0.22.1", + "mux.js": "6.0.1", + "safe-json-parse": "4.0.0", + "videojs-font": "3.2.0", + "videojs-vtt.js": "^0.15.5" + } + }, + "node_modules/videojs-ima/node_modules/videojs-font": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.2.0.tgz", + "integrity": "sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA==" + }, "node_modules/videojs-per-source-behaviors": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/videojs-per-source-behaviors/-/videojs-per-source-behaviors-3.0.0.tgz", diff --git a/package.json b/package.json index 0269a1ae..73d554ed 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "uuid": "^9.0.0", "video.js": "8.5.2", "videojs-contrib-ads": "^7.3.2", - "videojs-ima": "^2.1.0", + "videojs-ima": "^2.3.0", "videojs-per-source-behaviors": "^3.0.0", "webfontloader": "^1.6.28" }, diff --git a/src/index.all.js b/src/index.all.js index 88e8515d..969779ff 100644 --- a/src/index.all.js +++ b/src/index.all.js @@ -10,6 +10,7 @@ import cloudinary from './index.js'; export * from './index.js'; export * from './plugins/dash/videojs-dash.js'; +export * from './plugins/ima/ima.js'; export * from './plugins/playlist/playlist.js'; export * from './plugins/styled-text-tracks/styled-text-tracks.js'; export * from './plugins/interaction-areas/interaction-areas.service.js'; diff --git a/src/plugins/ima/ima.js b/src/plugins/ima/ima.js index a6a4286d..1b8b0f6a 100644 --- a/src/plugins/ima/ima.js +++ b/src/plugins/ima/ima.js @@ -1,1775 +1,3 @@ -/* eslint-disable */ -/** - * Copyright 2014 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * IMA SDK integration plugin for Video.js. For more information see - * https://www.github.com/googleads/videojs-ima - */ - -(function(factory) { - if (typeof define === 'function' && define['amd']) { - define(['video.js', 'videojs-contrib-ads'], function(videojs){ factory(window, document, (videojs.default || videojs)) }); - } else if (typeof exports === 'object' && typeof module === 'object') { - var vjs = require('video.js'); - require('videojs-contrib-ads'); - factory(window, document, vjs); - } else { - factory(window, document, videojs); - } -})(function(window, document, videojs) { - "use strict"; - - var extend = function(obj) { - var arg; - var index; - var key; - for (index = 1; index < arguments.length; index++) { - arg = arguments[index]; - for (key in arg) { - if (arg.hasOwnProperty(key)) { - obj[key] = arg[key]; - } - } - } - return obj; - }; - - var ima_defaults = { - debug: false, - timeout: 5000, - prerollTimeout: 100, - adLabel: 'Advertisement', - showControlsForAds: true, - showControlsForJSAds: true, - adsRenderingSettings: { - uiElements: [], - }, - }; - - var eventTypes = (videojs.browser.IS_ANDROID || videojs.browser.IS_IOS) ? { - click: 'touchend', - mousedown: 'touchstart', - mouseup: 'touchend', - mousemove: 'touchmove' - } : { - click: 'click', - mousedown: 'mousedown', - mouseup: 'mouseup', - mousemove: 'mousemove' - }; - - var init = function(options, readyCallback) { - this.ima = new ImaPlugin(this, options, readyCallback); - }; - - var ImaPlugin = function(player, options, readyCallback) { - this.player = player; - - /** - * Assigns the unique id and class names to the given element as well as the style class - * @param element - * @param controlName - * @private - */ - var assignControlAttributes_ = function(element, controlName) { - element.id = this.controlPrefix + controlName; - element.className = this.controlPrefix + controlName + ' ' + controlName; - }.bind(this); - - /** - * Returns a regular expression to test a string for the given className - * @param className - * @returns {RegExp} - * @private - */ - var getClassRegexp_ = function(className){ - // Matches on - // (beginning of string OR NOT word char) - // classname - // (negative lookahead word char OR end of string) - return new RegExp('(^|[^A-Za-z-])' + className + '((?![A-Za-z-])|$)', 'gi'); - }; - - /** - * Adds a class to the given element if it doesn't already have the class - * @param element - * @param classToAdd - * @private - */ - var addClass_ = function(element, classToAdd){ - if(getClassRegexp_(classToAdd).test(element.className)){ - return element; - } - - return element.className = element.className.trim() + ' ' + classToAdd; - }; - - /** - * Removes a class from the given element if it has the given class - * @param element - * @param classToRemove - * @private - */ - var removeClass_ = function(element, classToRemove){ - var classRegexp = getClassRegexp_(classToRemove); - - if(!classRegexp.test(element.className)){ - return element; - } - - return element.className = element.className.trim().replace(classRegexp, ''); - }; - - /** - * Creates the ad container passed to the IMA SDK. - * @private - */ - var createAdContainer_ = function() { - // The adContainerDiv is the DOM of the element that will house - // the ads and ad controls. - this.vjsControls = this.player.getChild('controlBar'); - this.adContainerDiv = - this.vjsControls.el().parentNode.appendChild( - document.createElement('div')); - assignControlAttributes_(this.adContainerDiv, 'ima-ad-container'); - this.adContainerDiv.style.position = "absolute"; - this.adContainerDiv.addEventListener( - 'mouseenter', - showAdControls_, - false); - this.adContainerDiv.addEventListener( - 'mouseleave', - hideAdControls_, - false); - createControls_(); - this.adDisplayContainer = - new google.ima.AdDisplayContainer(this.adContainerDiv, this.contentPlayer); - this.showAdContainer(!this.settings.manual); - }.bind(this); - - /** - * Creates the controls for the ad. - * @private - */ - var createControls_ = function() { - this.controlsDiv = document.createElement('div'); - assignControlAttributes_(this.controlsDiv, 'ima-controls-div'); - this.controlsDiv.style.width = '100%'; - this.countdownDiv = document.createElement('div'); - assignControlAttributes_(this.countdownDiv, 'ima-countdown-div'); - this.countdownDiv.innerHTML = this.settings.adLabel; - this.countdownDiv.style.display = this.showCountdown ? '' : 'none'; - this.seekBarDiv = document.createElement('div'); - assignControlAttributes_(this.seekBarDiv, 'ima-seek-bar-div'); - this.seekBarDiv.style.width = '100%'; - this.progressDiv = document.createElement('div'); - assignControlAttributes_(this.progressDiv, 'ima-progress-div'); - this.playPauseDiv = document.createElement('div'); - assignControlAttributes_(this.playPauseDiv, 'ima-play-pause-div'); - addClass_(this.playPauseDiv, 'ima-playing'); - this.playPauseDiv.addEventListener( - eventTypes.click, - onAdPlayPauseClick_, - false); - this.muteDiv = document.createElement('div'); - assignControlAttributes_(this.muteDiv, 'ima-mute-div'); - addClass_(this.muteDiv, 'ima-non-muted'); - this.muteDiv.addEventListener( - eventTypes.click, - onAdMuteClick_, - false); - this.sliderDiv = document.createElement('div'); - assignControlAttributes_(this.sliderDiv, 'ima-slider-div'); - this.sliderDiv.addEventListener( - eventTypes.mousedown, - onAdVolumeSliderMouseDown_, - false); - this.sliderLevelDiv = document.createElement('div'); - assignControlAttributes_(this.sliderLevelDiv, 'ima-slider-level-div'); - this.fullscreenDiv = document.createElement('div'); - assignControlAttributes_(this.fullscreenDiv, 'ima-fullscreen-div'); - addClass_(this.fullscreenDiv, 'ima-non-fullscreen'); - this.fullscreenDiv.addEventListener( - eventTypes.click, - onAdFullscreenClick_, - false); - this.adContainerDiv.appendChild(this.controlsDiv); - this.controlsDiv.appendChild(this.seekBarDiv); - this.controlsDiv.appendChild(this.playPauseDiv); - this.controlsDiv.appendChild(this.muteDiv); - this.controlsDiv.appendChild(this.sliderDiv); - this.controlsDiv.appendChild(this.fullscreenDiv); - this.seekBarDiv.appendChild(this.progressDiv); - this.sliderDiv.appendChild(this.sliderLevelDiv); - if (this.settings.vjsControls) { - this.initVjsControls(); - this.controlsDiv.style.display = 'none'; - this.vjsControls.el().appendChild(this.countdownDiv); - } else { - this.controlsDiv.appendChild(this.countdownDiv); - } - }.bind(this); - - this.showAdContainer = function(show) { - this.adContainerDiv.style.display = show ? 'block' : 'none'; - this.player.toggleClass('vjs-ima-ad', show); - }.bind(this); - - /** - * Initializes the AdDisplayContainer. On mobile, this must be done as a - * result of user action. - */ - this.initializeAdDisplayContainer = function() { - this.adDisplayContainerInitialized = true; - this.adDisplayContainer.initialize(); - }.bind(this); - - /** - * Creates the AdsRequest and request ads through the AdsLoader. - */ - this.requestAds = function() { - if (!this.adDisplayContainerInitialized) { - this.adDisplayContainer.initialize(); - } - var adsRequest = new google.ima.AdsRequest(); - if (this.settings.adTagUrl) { - adsRequest.adTagUrl = this.settings.adTagUrl; - } else { - adsRequest.adsResponse = this.settings.adsResponse; - } - if (this.settings.forceNonLinearFullSlot) { - adsRequest.forceNonLinearFullSlot = true; - } - - adsRequest.linearAdSlotWidth = this.getPlayerWidth(); - adsRequest.linearAdSlotHeight = this.getPlayerHeight(); - adsRequest.nonLinearAdSlotWidth = - this.settings.nonLinearWidth || this.getPlayerWidth(); - adsRequest.nonLinearAdSlotHeight = - this.settings.nonLinearHeight || (this.getPlayerHeight() / 3); - adsRequest.vastLoadTimeout = Math.max(this.settings.prerollTimeout, - this.settings.postrollTimeout); - - this.adsLoader.requestAds(adsRequest); - }.bind(this); - - /** - * Listener for the ADS_MANAGER_LOADED event. Creates the AdsManager, - * sets up event listeners, and triggers the 'adsready' event for - * videojs-ads-contrib. - * @private - */ - var onAdsManagerLoaded_ = function(adsManagerLoadedEvent) { - this.adsManager = adsManagerLoadedEvent.getAdsManager( - this.contentPlayheadTracker, this.adsRenderingSettings); - - this.adsManager.addEventListener( - google.ima.AdErrorEvent.Type.AD_ERROR, - onAdError_); - this.adsManager.addEventListener( - google.ima.AdEvent.Type.AD_BREAK_READY, - onAdBreakReady_); - this.adsManager.addEventListener( - google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, - this.onContentPauseRequested_); - this.adsManager.addEventListener( - google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, - this.onContentResumeRequested_); - this.adsManager.addEventListener( - google.ima.AdEvent.Type.ALL_ADS_COMPLETED, - onAllAdsCompleted_); - - this.adsManager.addEventListener( - google.ima.AdEvent.Type.LOADED, - onAdLoaded_); - this.adsManager.addEventListener( - google.ima.AdEvent.Type.STARTED, - onAdStarted_); - this.adsManager.addEventListener( - google.ima.AdEvent.Type.CLICK, - onAdPlayPauseClick_); - this.adsManager.addEventListener( - google.ima.AdEvent.Type.COMPLETE, - this.onAdComplete_); - this.adsManager.addEventListener( - google.ima.AdEvent.Type.SKIPPED, - this.onAdComplete_); - this.adsManager.addEventListener( - google.ima.AdEvent.Type.PAUSED, - this.onAdPaused_); - this.adsManager.addEventListener( - google.ima.AdEvent.Type.RESUMED, - this.onAdResumed_); - - var eventsMap = { - 'load': google.ima.AdEvent.Type.LOADED, - 'ad-started': google.ima.AdEvent.Type.STARTED, - 'click': google.ima.AdEvent.Type.CLICK, - 'ad-ended': google.ima.AdEvent.Type.COMPLETE, - 'ad-skipped': google.ima.AdEvent.Type.SKIPPED, - 'first-quartile': google.ima.AdEvent.Type.FIRST_QUARTILE, - 'midpoint': google.ima.AdEvent.Type.MIDPOINT, - 'third-quartile': google.ima.AdEvent.Type.THIRD_QUARTILE, - 'impression': google.ima.AdEvent.Type.IMPRESSION, - 'pause': google.ima.AdEvent.Type.PAUSED, - 'play': google.ima.AdEvent.Type.RESUMED, - 'mute': google.ima.AdEvent.Type.VOLUME_MUTED, - 'allpods-completed': google.ima.AdEvent.Type.ALL_ADS_COMPLETED - }; - - Object.keys(eventsMap).forEach(function(event){ - this.adsManager.addEventListener(eventsMap[event], function(){ - this.player.trigger('ads-'+event); - }.bind(this)); - - }.bind(this)); - - setAdMuted(this.player.muted()); - - if (!this.autoPlayAdBreaks) { - try { - var initWidth = this.getPlayerWidth(); - var initHeight = this.getPlayerHeight(); - this.adsManagerDimensions.width = initWidth; - this.adsManagerDimensions.height = initHeight; - this.adsManager.init( - initWidth, - initHeight, - google.ima.ViewMode.NORMAL); - this.adsManager.setVolume(this.player.muted() ? 0 : this.player.volume()); - } catch (adError) { - onAdError_(adError); - } - } - - var cuepoints = this.adsManager.getCuePoints(); - var foundpreroll = !cuepoints.length; // no playlist, just preroll - var foundpostroll = false;; - cuepoints.forEach(function(offset){ - if (!offset) - foundpreroll = true; - else if (offset==-1) - foundpostroll = true; - }); - if (!foundpreroll) - this.player.trigger('nopreroll'); - if (!foundpostroll) - this.player.trigger('nopostroll'); - if (cuepoints.length) - this.player.trigger('ads-cuepoints', cuepoints); - - this.player.trigger('adsready'); - }.bind(this); - - /** - * DEPRECATED: Use startFromReadyCallback - * Start ad playback, or content video playback in the absence of a - * pre-roll. - */ - this.start = function() { - window.console.log( - 'WARNING: player.ima.start is deprecated. Use ' + - 'player.ima.startFromReadyCallback instead.'); - }; - - /** - * Start ad playback, or content video playback in the absence of a - * pre-roll. **NOTE**: This method only needs to be called if you provide - * your own readyCallback as the second parameter to player.ima(). If you - * only provide options and do not provide your own readyCallback, - * **DO NOT** call this method. If you do provide your own readyCallback, - * you should call this method in the last line of that callback. For more - * info, see this method's usage in our advanced and playlist examples. - */ - this.startFromReadyCallback = function() { - if (this.autoPlayAdBreaks && this.adsManager) { - try { - this.adsManager.init( - this.getPlayerWidth(), - this.getPlayerHeight(), - google.ima.ViewMode.NORMAL); - this.adsManager.setVolume(this.player.muted() ? 0 : this.player.volume()); - this.adsManager.start(); - } catch (adError) { - onAdError_(adError); - } - } - }.bind(this); - - /** - * Listener for errors fired by the AdsLoader. - * @param {google.ima.AdErrorEvent} event The error event thrown by the - * AdsLoader. See - * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdError.Type - * @private - */ - var onAdsLoaderError_ = function(event) { - console.log('AdsLoader error: ' + event.getError()); - this.showAdContainer(false); - if (this.adsManager) { - this.adsManager.destroy(); - } - this.player.trigger({type: 'adserror', data: { AdError: event.getError(), AdErrorEvent: event }}); - }.bind(this); - - /** - * Listener for errors thrown by the AdsManager. - * @param {google.ima.AdErrorEvent} adErrorEvent The error event thrown by - * the AdsManager. - * @private - */ - var onAdError_ = function(adErrorEvent) { - var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack; - console.log('Ad error: ' + errorMessage); - this.adsActive = false; - this.adPlaying = false; - this.restoreLoop(); - this.vjsControls.show(); - this.adsManager.destroy(); - this.showAdContainer(false); - this.updateVjsControls(); - this.player.trigger({ type: 'adserror', data: { AdError: errorMessage, AdErrorEvent: adErrorEvent }}); - }.bind(this); - - /** - * Listener for AD_BREAK_READY. Passes event on to publisher's listener. - * @param {google.ima.AdEvent} adEvent AdEvent thrown by the AdsManager. - * @private - */ - var onAdBreakReady_ = function(adEvent) { - this.adBreakReadyListener(adEvent); - }.bind(this); - - /** - * Called by publishers in manual ad break playback mode to start an ad - * break. - */ - this.playAdBreak = function() { - if (!this.autoPlayAdBreaks) { - this.adsManager.start(); - } - }.bind(this); - - this.resetLoop = function() { - this.contentLoop = this.contentPlayer && this.contentPlayer.loop; - if (this.contentLoop) { - this.contentPlayer.loop = false; - } - }.bind(this); - - this.restoreLoop = function() { - if (this.contentLoop) { - this.contentPlayer.loop = true; - this.contentLoop = false; - } - }.bind(this); - - /** - * Pauses the content video and displays the ad container so ads can play. - * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager. - * @private - */ - this.onContentPauseRequested_ = function(adEvent) { - this.contentSource = this.player.currentSrc(); - this.resetLoop(); - this.player.off('contentended', this.localContentEndedListener); - this.player.ads.startLinearAdMode(); - this.showAdContainer(true); - - var contentType = adEvent.getAd().getContentType(); - if (!this.settings.vjsControls || !this.settings.showControlsForAds){ - if (!this.settings.showControlsForAds - || ((contentType === 'application/javascript') && !this.settings.showControlsForJSAds)) { - this.controlsDiv.style.display = 'none'; - } else { - this.controlsDiv.style.display = 'block'; - } - this.vjsControls.hide(); - } - showPlayButton(); - this.player.pause(); - this.adsActive = true; - this.adPlaying = true; - this.updateVjsControls(); - }.bind(this); - - /** - * Resumes content video and hides the ad container. - * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager. - * @private - */ - this.onContentResumeRequested_ = function(adEvent) { - this.contentResumeTimer = clearTimeout(this.contentResumeTimer); - this.restoreLoop(); - this.adsActive = false; - this.adPlaying = false; - this.player.on('contentended', this.localContentEndedListener); - if (this.currentAd == null || // hide for post-roll only playlist - this.currentAd.isLinear()) { // don't hide for non-linear ads - this.showAdContainer(false); - } - this.vjsControls.show(); - this.player.ads.endLinearAdMode(); - this.countdownDiv.innerHTML = ''; - this.updateVjsControls(); - }.bind(this); - - /** - * Records that ads have completed and calls contentAndAdsEndedListeners - * if content is also complete. - * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager. - * @private - */ - var onAllAdsCompleted_ = function(adEvent) { - this.allAdsCompleted = true; - this.showAdContainer(false); - if (this.contentComplete == true) { - if (this.contentPlayer.src && !/^blob:/.test(this.contentPlayer.src) && - this.contentSource && this.contentPlayer.src != this.contentSource) { - this.player.src(this.contentSource); - } - this.player.trigger('') - for (var index in this.contentAndAdsEndedListeners) { - this.contentAndAdsEndedListeners[index](); - } - } - }.bind(this); - - /** - * Starts the content video when a non-linear ad is loaded. - * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager. - * @private - */ - var onAdLoaded_ = function(adEvent) { - if (!adEvent.getAd().isLinear() && !this.player.ended()) { - this.player.ads.endLinearAdMode(); - this.player.play(); - } - }.bind(this); - - /** - * Starts the interval timer to check the current ad time when an ad starts - * playing. - * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager. - * @private - */ - var onAdStarted_ = function(adEvent) { - this.currentAd = adEvent.getAd(); - if (this.currentAd.isLinear()) { - this.adTrackingTimer = setInterval( - onAdPlayheadTrackerInterval_, 250); - // Don't bump container when controls are shown - removeClass_(this.adContainerDiv, 'bumpable-ima-ad-container'); - } else { - // Bump container when controls are shown - addClass_(this.adContainerDiv, 'bumpable-ima-ad-container'); - this.player.addClass('vjs-ima-non-linear'); - this.showAdContainer(true); - } - }.bind(this); - - /** - * Clears the interval timer for current ad time when an ad completes. - * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager. - * @private - */ - this.onAdComplete_ = function(adEvent) { - if (this.currentAd.isLinear()) { - clearInterval(this.adTrackingTimer); - var pod = this.currentAd.getAdPodInfo(); - if (pod && pod.getAdPosition() < pod.getTotalAds()) { - this.player.trigger('ads-pod-ended') - return; - } - - // this is the final ad so we excpect ima sdk to trigger - // CONTENT_RESUME_REQUESTED, but for some reason it isn't triggered - // reliably on iOS, so we fake it - - this.contentResumeTimer = setTimeout(function(){ - this.onContentResumeRequested_(null); - }.bind(this), 1000); - } else { - this.player.removeClass('vjs-ima-non-linear'); - } - }.bind(this); - - this.onAdPaused_ = function(adEvent) { - showPauseButton(); - this.adPlaying = false; - }.bind(this); - - this.onAdResumed_ = function(adEvent) { - showPlayButton(); - this.adPlaying = true; - }.bind(this); - - var formatTime = function(time) { - var m = Math.floor(time / 60); - var s = Math.floor(time % 60); - if (s.toString().length < 2) { - s = '0' + s; - } - return m + ':' + s; - }; - - /** - * Gets the current time and duration of the ad and calls the method to - * update the ad UI. - * @private - */ - var onAdPlayheadTrackerInterval_ = function() { - var remainingTime = this.adsManager.getRemainingTime(); - var duration = this.currentAd.getDuration(); - var currentTime = duration - remainingTime; - currentTime = currentTime > 0 ? currentTime : 0; - var isPod = false; - var totalAds = 0; - var adPosition; - if (this.currentAd.getAdPodInfo()) { - isPod = true; - adPosition = this.currentAd.getAdPodInfo().getAdPosition(); - totalAds = this.currentAd.getAdPodInfo().getTotalAds(); - } - - // Update countdown timer data - var podCount = ': '; - if (isPod && (totalAds > 1)) { - podCount = ' (' + adPosition + ' of ' + totalAds + '): '; - } - this.countdownDiv.innerHTML = - this.settings.adLabel + podCount + formatTime(remainingTime); - - // Update UI - var playProgressRatio = currentTime / duration; - var playProgressPercent = playProgressRatio * 100; - this.progressDiv.style.width = playProgressPercent + '%'; - this.updateVjsControls(); - }.bind(this); - - this.getPlayerWidth = function() { - var retVal = parseInt(getComputedStyle(this.player.el()).width, 10) || - this.player.width(); - return retVal; - }.bind(this); - - this.getPlayerHeight = function() { - var retVal = parseInt(getComputedStyle(this.player.el()).height, 10) || - this.player.height(); - return retVal; - }.bind(this); - - /** - * Hides the ad controls on mouseout. - * @private - */ - var hideAdControls_ = function() { - this.controlsDiv.style.height = '14px'; - this.playPauseDiv.style.display = 'none'; - this.muteDiv.style.display = 'none'; - this.sliderDiv.style.display = 'none'; - this.fullscreenDiv.style.display = 'none'; - }.bind(this); - - /** - * Shows ad controls on mouseover. - * @private - */ - var showAdControls_ = function() { - this.controlsDiv.style.height = '37px'; - this.playPauseDiv.style.display = 'block'; - this.muteDiv.style.display = 'block'; - this.sliderDiv.style.display = 'block'; - this.fullscreenDiv.style.display = 'block'; - }.bind(this); - - /** - * Show pause and hide play button - */ - var showPauseButton = function() { - addClass_(this.playPauseDiv, 'ima-paused'); - removeClass_(this.playPauseDiv, 'ima-playing'); - }.bind(this); - - /** - * Show play and hide pause button - */ - var showPlayButton = function() { - addClass_(this.playPauseDiv, 'ima-playing'); - removeClass_(this.playPauseDiv, 'ima-paused'); - }.bind(this); - - /** - * Listener for clicks on the play/pause button during ad playback. - * @private - */ - var onAdPlayPauseClick_ = function() { - if (this.adPlaying) { - showPauseButton(); - this.adsManager.pause(); - this.adPlaying = false; - } else { - showPlayButton(); - this.adsManager.resume(); - this.adPlaying = true; - } - }.bind(this); - - /** - * Listener for clicks on the mute button during ad playback. - * @private - */ - var onAdMuteClick_ = function() { - setAdMuted(!this.adMuted); - }.bind(this); - - /* Listener for mouse down events during ad playback. Used for volume. - * @private - */ - var onAdVolumeSliderMouseDown_ = function() { - document.addEventListener(eventTypes.mouseup, onMouseUp_, false); - document.addEventListener(eventTypes.mousemove, onMouseMove_, false); - }; - - /* Mouse movement listener used for volume slider. - * @private - */ - var onMouseMove_ = function(event) { - setVolumeSlider_(event); - }; - - /* Mouse release listener used for volume slider. - * @private - */ - var onMouseUp_ = function(event) { - setVolumeSlider_(event); - document.removeEventListener(eventTypes.mousemove, onMouseMove_); - document.removeEventListener(eventTypes.mouseup, onMouseUp_); - }; - - /* Utility function to set volume and associated UI - * @private - */ - var setVolumeSlider_ = function(event) { - var clientX = event.changedTouches ? event.changedTouches[0].clientX : - event.clientX; - var percent = (clientX - this.sliderDiv.getBoundingClientRect().left) / - this.sliderDiv.offsetWidth; - percent *= 100; - //Bounds value 0-100 if mouse is outside slider region. - percent = Math.min(Math.max(percent, 0), 100); - this.sliderLevelDiv.style.width = percent + "%"; - this.player.volume(percent / 100); //0-1 - this.adsManager.setVolume(percent / 100); - if (this.player.volume() == 0) { - addClass_(this.muteDiv, 'ima-muted'); - removeClass_(this.muteDiv, 'ima-non-muted'); - this.player.muted(true); - this.adMuted = true; - } - else - { - addClass_(this.muteDiv, 'ima-non-muted'); - removeClass_(this.muteDiv, 'ima-muted'); - this.player.muted(false); - this.adMuted = false; - } - }.bind(this); - - /** - * Listener for clicks on the fullscreen button during ad playback. - * @private - */ - var onAdFullscreenClick_ = function() { - if (this.player.isFullscreen()) { - this.player.exitFullscreen(); - } else { - this.player.requestFullscreen(); - } - }.bind(this); - - /** - * Listens for the video.js player to change its fullscreen status. This - * keeps the fullscreen-ness of the AdContainer in sync with the player. - * @private - */ - var onFullscreenChange_ = function() { - if (this.player.isFullscreen()) { - addClass_(this.fullscreenDiv, 'ima-fullscreen'); - removeClass_(this.fullscreenDiv, 'ima-non-fullscreen'); - if (this.adsManager) { - this.adsManager.resize( - window.screen.width, - window.screen.height, - google.ima.ViewMode.FULLSCREEN); - } - } else { - addClass_(this.fullscreenDiv, 'ima-non-fullscreen'); - removeClass_(this.fullscreenDiv, 'ima-fullscreen'); - if (this.adsManager) { - this.adsManager.resize( - this.getPlayerWidth(), - this.getPlayerHeight(), - google.ima.ViewMode.NORMAL); - } - } - }.bind(this); - - /** - * Listens for the video.js player to change its volume. This keeps the ad - * volume in sync with the content volume if the volume of the player is - * changed while content is playing - * @private - */ - var onVolumeChange_ = function() { - var newVolume = this.player.muted() ? 0 : this.player.volume(); - if (this.adsManager) { - this.adsManager.setVolume(newVolume); - } - // Update UI - if (newVolume == 0) { - this.adMuted = true; - addClass_(this.muteDiv, 'ima-muted'); - removeClass_(this.muteDiv, 'ima-non-muted'); - this.sliderLevelDiv.style.width = '0%'; - } else { - this.adMuted = false; - addClass_(this.muteDiv, 'ima-non-muted'); - removeClass_(this.muteDiv, 'ima-muted'); - this.sliderLevelDiv.style.width = newVolume * 100 + '%'; - } - }.bind(this); - - /** - * Seeks content to 00:00:00. This is used as an event handler for the - * loadedmetadata event, since seeking is not possible until that event has - * fired. - * @private - */ - var seekContentToZero_ = function() { - this.player.off('loadedmetadata', seekContentToZero_); - this.player.currentTime(0); - }.bind(this); - - /** - * Seeks content to 00:00:00 and starts playback. This is used as an event - * handler for the loadedmetadata event, since seeking is not possible until - * that event has fired. - * @private - */ - var playContentFromZero_ = function() { - this.player.off('loadedmetadata', playContentFromZero_); - this.player.currentTime(0); - this.player.play(); - }.bind(this); - - /** - * Destroys the AdsManager, sets it to null, and calls contentComplete to - * reset correlators. Once this is done it requests ads again to keep the - * inventory available. - * @private - */ - var resetIMA_ = function() { - this.adsActive = false; - this.adPlaying = false; - this.restoreLoop(); - this.player.on('contentended', this.localContentEndedListener); - if (this.currentAd && this.currentAd.isLinear()) { - this.showAdContainer(false); - } - this.vjsControls.show(); - this.player.ads.endLinearAdMode(); - this.contentPlayheadTracker.currentTime = 0; - this.countdownDiv.innerHTML = ''; - this.updateVjsControls(); - if (this.adTrackingTimer) { - // If this is called while an ad is playing, stop trying to get that - // ad's current time. - clearInterval(this.adTrackingTimer); - } - if (this.adsManager) { - this.adsManager.destroy(); - this.adsManager = null; - } - if (this.adsLoader && !this.contentComplete) { - this.adsLoader.contentComplete(); - } - this.contentComplete = false; - this.allAdsCompleted = false; - }.bind(this); - - /** - * Ads an EventListener to the AdsManager. For a list of available events, - * see - * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdEvent.Type - * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to listen. - * @param {function} callback The method to call when the event is fired. - */ - this.addEventListener = function(event, callback) { - if (this.adsManager) { - this.adsManager.addEventListener(event, callback); - } - }.bind(this); - - /** - * Returns the instance of the AdsManager. - * @return {google.ima.AdsManager} The AdsManager being used by the plugin. - */ - this.getAdsManager = function() { - return this.adsManager; - }.bind(this); - - /** - * DEPRECATED: Use setContentWithAdTag. - * Sets the content of the video player. You should use this method instead - * of setting the content src directly to ensure the proper ad tag is - * requested when the video content is loaded. - * @param {?string} contentSrc The URI for the content to be played. Leave - * blank to use the existing content. - * @param {?string} adTag The ad tag to be requested when the content loads. - * Leave blank to use the existing ad tag. - * @param {?boolean} playOnLoad True to play the content once it has loaded, - * false to only load the content but not start playback. - */ - this.setContent = function(contentSrc, adTag, playOnLoad) { - window.console.log( - 'WARNING: player.ima.setContent is deprecated. Use ' + - 'player.ima.setContentWithAdTag instead.'); - this.setContentWithAdTag(contentSrc, adTag, playOnLoad); - }.bind(this); - - /** - * Sets the content of the video player. You should use this method instead - * of setting the content src directly to ensure the proper ad tag is - * requested when the video content is loaded. - * @param {?string} contentSrc The URI for the content to be played. Leave - * blank to use the existing content. - * @param {?string} adTag The ad tag to be requested when the content loads. - * Leave blank to use the existing ad tag. - * @param {?boolean} playOnLoad True to play the content once it has loaded, - * false to only load the content but not start playback. - */ - this.setContentWithAdTag = function(contentSrc, adTag, playOnLoad) { - resetIMA_(); - this.settings.adTagUrl = adTag ? adTag : this.settings.adTagUrl; - changeSource_(contentSrc, playOnLoad); - }.bind(this); - - /** - * Sets the content of the video player. You should use this method instead - * of setting the content src directly to ensure the proper ads response is - * used when the video content is loaded. - * @param {?string} contentSrc The URI for the content to be played. Leave - * blank to use the existing content. - * @param {?string} adsResponse The ads response to be requested when the - * content loads. Leave blank to use the existing ads response. - * @param {?boolean} playOnLoad True to play the content once it has loaded, - * false to only load the content but not start playback. - */ - this.setContentWithAdsResponse = function(contentSrc, adsResponse, playOnLoad) { - resetIMA_(); - this.settings.adsResponse = adsResponse ? adsResponse : this.settings.adsResponse; - changeSource_(contentSrc, playOnLoad); - }.bind(this); - - /** - * Plays an ad immediately - * @param {?string} adTag The ad tag to be requested. - * Leave blank to use the existing ad tag. - */ - this.playAd = function(adTag) { - resetIMA_(); - this.settings.adTagUrl = adTag ? adTag : this.settings.adTagUrl; - // this.showAdContainer(true); - // this.vjsControls.hide(); - this.requestAds(); - }.bind(this); - - /** - * Changes the player source. - * @param {?string} contentSrc The URI for the content to be played. Leave - * blank to use the existing content. - * @param {?boolean} playOnLoad True to play the content once it has loaded, - * false to only load the content but not start playback. - * @private - */ - var changeSource_ = function(contentSrc, playOnLoad) { - // Only try to pause the player when initialised with a source already - if (!!this.player.currentSrc()) { - this.player.currentTime(0); - this.player.pause(); - } - if (contentSrc) { - this.player.src(contentSrc); - } - if (playOnLoad) { - this.player.on('loadedmetadata', playContentFromZero_); - } else { - this.player.on('loadedmetadata', seekContentToZero_); - } - }.bind(this); - - var setAdMuted = function(mute) { - if (mute) { - addClass_(this.muteDiv, 'ima-muted'); - removeClass_(this.muteDiv, 'ima-non-muted'); - this.adsManager.setVolume(0); - // Bubble down to content player - this.player.muted(true); - this.adMuted = true; - this.sliderLevelDiv.style.width = "0%"; - } else { - addClass_(this.muteDiv, 'ima-non-muted'); - removeClass_(this.muteDiv, 'ima-muted'); - this.adsManager.setVolume(this.player.volume()); - // Bubble down to content player - this.player.muted(false); - this.adMuted = false; - this.sliderLevelDiv.style.width = this.player.volume() * 100 + "%"; - } - }.bind(this); - /** - * Adds a listener for the 'contentended' event of the video player. This should be - * used instead of setting an 'contentended' listener directly to ensure that the - * ima can do proper cleanup of the SDK before other event listeners - * are called. - * @param {function} listener The listener to be called when content completes. - */ - this.addContentEndedListener = function(listener) { - this.contentEndedListeners.push(listener); - }.bind(this); - - /** - * Adds a listener that will be called when content and all ads have - * finished playing. - * @param {function} listener The listener to be called when content and ads complete. - */ - this.addContentAndAdsEndedListener = function(listener) { - this.contentAndAdsEndedListeners.push(listener); - }.bind(this); - - /** - * Sets the listener to be called to trigger manual ad break playback. - * @param {function} listener The listener to be called to trigger manual ad break playback. - */ - this.setAdBreakReadyListener = function(listener) { - this.adBreakReadyListener = listener; - }.bind(this); - - /** - * Pauses the ad. - */ - this.pauseAd = function() { - if (this.adsActive && this.adPlaying) { - showPauseButton(); - this.adsManager.pause(); - this.adPlaying = false; - } - }.bind(this); - - /** - * Resumes the ad. - */ - this.resumeAd = function() { - if (this.adsActive && !this.adPlaying) { - showPlayButton(); - this.adsManager.resume(); - this.adPlaying = true; - } - }.bind(this); - - /** - * Set up intervals to check for seeking and update current video time. - * @private - */ - var setUpPlayerIntervals_ = function() { - this.updateTimeIntervalHandle = - setInterval(updateCurrentTime_, this.seekCheckInterval); - this.seekCheckIntervalHandle = - setInterval(checkForSeeking_, this.seekCheckInterval); - this.resizeCheckIntervalHandle = - setInterval(checkForResize_, this.resizeCheckInterval); - }.bind(this); - - /** - * Updates the start time of the video - * @private - */ - var updateStartTime_ = function(){ - var cur = this.player.currentTime(); - if (!cur || this.player.ads.state!='content-playback') - return; - // first time that isn't zero is our start time, but only if it's - // more than the 1sec - if (cur<1) - cur = 0; - this.contentPlayheadTracker.startTime = cur; - this.player.off('timeupdate', updateStartTime_); - }.bind(this); - - /** - * Updates the current time of the video - * @private - */ - var updateCurrentTime_ = function() { - if (this.player.ads.state=='content-playback' && - !this.contentPlayheadTracker.seeking && - this.contentPlayheadTracker.startTime>=0) { - this.contentPlayheadTracker.currentTime = this.player.currentTime() - - this.contentPlayheadTracker.startTime; - } - }.bind(this); - - /** - * Detects when the user is seeking through a video. - * This is used to prevent mid-rolls from playing while a user is seeking. - * - * There *is* a seeking property of the HTML5 video element, but it's not - * properly implemented on all platforms (e.g. mobile safari), so we have to - * check ourselves to be sure. - * - * @private - */ - var checkForSeeking_ = function() { - if (this.player.ads.state!='content-playback') - return; - var tempCurrentTime = this.player.currentTime(); - var diff = (tempCurrentTime - this.contentPlayheadTracker.previousTime) * 1000; - if (Math.abs(diff) > this.seekCheckInterval + this.seekThreshold) { - this.contentPlayheadTracker.seeking = true; - } else { - this.contentPlayheadTracker.seeking = false; - } - this.contentPlayheadTracker.previousTime = this.player.currentTime(); - }.bind(this); - - /** - * Detects when the player is resized (for fluid support) and resizes the - * ads manager to match. - * - * @private - */ - var checkForResize_ = function() { - var currentWidth = this.getPlayerWidth(); - var currentHeight = this.getPlayerHeight(); - - if (this.adsManager && (currentWidth != this.adsManagerDimensions.width || - currentHeight != this.adsManagerDimensions.height)) { - this.adsManagerDimensions.width = currentWidth; - this.adsManagerDimensions.height = currentHeight; - this.adsManager.resize(currentWidth, currentHeight, google.ima.ViewMode.NORMAL); - } - }.bind(this); - - /** - * Changes the flag to show or hide the ad countdown timer. - * - * @param {boolean} showCountdownIn Show or hide the countdown timer. - */ - this.setShowCountdown = function(showCountdownIn) { - this.showCountdown = showCountdownIn; - this.countdownDiv.style.display = this.showCountdown ? '' : 'none'; - }.bind(this); - - /** - * Current plugin version. - */ - this.VERSION = '0.2.0'; - - /** - * Stores user-provided settings. - */ - this.settings; - - /** - * Used to prefix videojs ima - */ - this.controlPrefix; - - /** - * Video element playing content. - */ - this.contentPlayer; - - /** - * Boolean flag to show or hide the ad countdown timer. - */ - this.showCountdown; - - /** - * Boolena flag to enable manual ad break playback. - */ - this.autoPlayAdBreaks; - - /** - * Video.js control bar. - */ - this.vjsControls; - - /** - * Div used as an ad container. - */ - this.adContainerDiv; - - /** - * Div used to display ad controls. - */ - this.controlsDiv; - - /** - * Div used to display ad countdown timer. - */ - this.countdownDiv; - - /** - * Div used to display add seek bar. - */ - this.seekBarDiv; - - /** - * Div used to display ad progress (in seek bar). - */ - this.progressDiv; - - /** - * Div used to display ad play/pause button. - */ - this.playPauseDiv; - - /** - * Div used to display ad mute button. - */ - this.muteDiv; - - /** - * Div used by the volume slider. - */ - this.sliderDiv; - - /** - * Volume slider level visuals - */ - this.sliderLevelDiv; - - /** - * Div used to display ad fullscreen button. - */ - this.fullscreenDiv; - - /** - * IMA SDK AdDisplayContainer. - */ - this.adDisplayContainer; - - /** - * True if the AdDisplayContainer has been initialized. False otherwise. - */ - this.adDisplayContainerInitialized = false; - - /** - * IMA SDK AdsLoader - */ - this.adsLoader; - - /** - * IMA SDK AdsManager - */ - this.adsManager; - - /** - * IMA SDK AdsRenderingSettings. - */ - this.adsRenderingSettings = null; - - /** - * Ad tag URL. Should return VAST, VMAP, or ad rules. - */ - this.adTagUrl; - - /** - * VAST, VMAP, or ad rules response. Used in lieu of fetching a response - * from an ad tag URL. - */ - this.adsResponse; - - /** - * Current IMA SDK Ad. - */ - this.currentAd; - - /** - * Timer used to track content progress. - */ - this.contentTrackingTimer; - - /** - * Timer used to track ad progress. - */ - this.adTrackingTimer; - - /** - * True if ads are currently displayed, false otherwise. - * True regardless of ad pause state if an ad is currently being displayed. - */ - this.adsActive = false; - - /** - * True if ad is currently playing, false if ad is paused or ads are not - * currently displayed. - */ - this.adPlaying = false; - - /** - * True if the ad is muted, false otherwise. - */ - this.adMuted = false; - - /** - * True if our content video has completed, false otherwise. - */ - this.contentComplete = false; - - /** - * True if ALL_ADS_COMPLETED has fired, false until then. - */ - this.allAdsCompleted = false; - - /** - * Handle to interval that repeatedly updates current time. - */ - this.updateTimeIntervalHandle; - - /** - * Handle to interval that repeatedly checks for seeking. - */ - this.seekCheckIntervalHandle; - - /** - * Interval (ms) on which to check if the user is seeking through the - * content. - */ - this.seekCheckInterval = 1000; - - /** - * Handle to interval that repeatedly checks for player resize. - */ - this.resizeCheckIntervalHandle; - - /** - * Interval (ms) to check for player resize for fluid support. - */ - this.resizeCheckInterval = 250; - - /** - * Threshold by which to judge user seeking. We check every 1000 ms to see - * if the user is seeking. In order for us to decide that they are *not* - * seeking, the content video playhead must only change by 900-1100 ms - * between checks. Any greater change and we assume the user is seeking - * through the video. - */ - this.seekThreshold = 100; - - /** - * Stores data for the content playhead tracker. - */ - this.contentPlayheadTracker = { - currentTime: 0, - previousTime: 0, - seeking: false, - duration: 0, - startTime: -1 - }; - - /** - * Stores data for the ad playhead tracker. - */ - this.adPlayheadTracker = { - currentTime: 0, - duration: 0, - isPod: false, - adPosition: 0, - totalAds: 0 - }; - - /** - * Stores the dimensions for the ads manager. - */ - this.adsManagerDimensions = { - width: 0, - height: 0 - }; - - /** - * Content ended listeners passed by the publisher to the plugin. Publishers - * should allow the plugin to handle content ended to ensure proper support - * of custom ad playback. - */ - this.contentEndedListeners = []; - - /** - * Content and ads ended listeners passed by the publisher to the plugin. - * These will be called when the plugin detects that content *and all - * ads* have completed. This differs from the contentEndedListeners in that - * contentEndedListeners will fire between content ending and a post-roll - * playing, whereas the contentAndAdsEndedListeners will fire after the - * post-roll completes. - */ - this.contentAndAdsEndedListeners = []; - - /** - * Listener to be called to trigger manual ad break playback. - */ - this.adBreakReadyListener = function() { - console.log('Please set adBreakReadyListener'); - }; - - /** - * Stores the content source so we can re-populate it manually after a - * post-roll on iOS. - */ - this.contentSource = ''; - - /** - * Local content ended listener for contentComplete. - */ - this.localContentEndedListener = function() { - if (this.adsLoader && !this.contentComplete) { - this.adsLoader.contentComplete(); - this.contentComplete = true; - } - for (var index in this.contentEndedListeners) { - this.contentEndedListeners[index](); - } - if (this.allAdsCompleted) { - for (var index in this.contentAndAdsEndedListeners) { - this.contentAndAdsEndedListeners[index](); - } - } - clearInterval(this.updateTimeIntervalHandle); - clearInterval(this.seekCheckIntervalHandle); - clearInterval(this.resizeCheckIntervalHandle); - if(this.player.el()) { - this.player.one('play', setUpPlayerIntervals_); - } - }.bind(this); - - this.playerDisposedListener = function(){ - this.contentEndedListeners, this.contentAndAdsEndedListeners = [], []; - this.contentComplete = true; - this.player.off('contentended', this.localContentEndedListener); - this.player.off('timeupdate', updateStartTime_); - - // Bug fix: https://github.com/googleads/videojs-ima/issues/306 - if (this.player.ads.adTimeoutTimeout) { - clearTimeout(this.player.ads.adTimeoutTimeout); - } - - var intervalsToClear = [this.updateTimeIntervalHandle, this.seekCheckIntervalHandle, - this.adTrackingTimer, this.resizeCheckIntervalHandle]; - for (var index in intervalsToClear) { - var interval = intervalsToClear[index]; - if (interval) { - clearInterval(interval); - } - } - if (this.adsManager) { - this.adsManager.destroy(); - this.adsManager = null; - } - }.bind(this); - - this.initVjsControls = function() { - var _this = this; - var override = function(cls, obj, method, fn, always) { - var orig = cls.prototype[method]; - return obj[method] = function() { - return _this.adsActive || always ? fn && fn.apply(this, arguments) : - orig && orig.apply(this, arguments); - }; - }; - var overrideHandler = function(cls, obj, target, event, method, fn, always) { - var orig = cls.prototype[method]; - var handler = override(cls, obj, method, fn); - if (target) { - obj.off(target, event, orig); - obj.on(target, event, handler); - } else { - obj.off(event, orig); - obj.on(event, handler); - } - }; - var PlayToggle = videojs.getComponent('PlayToggle'); - var playToggle = this.vjsControls.playToggle; - overrideHandler(PlayToggle, playToggle, null, ['tap', 'click'], - 'handleClick', function() { - onAdPlayPauseClick_(); - if (_this.adPlaying) { - this.handlePlay(); - } else { - this.handlePause(); - } - }); - override(PlayToggle, playToggle, 'update', function() { - var paused = _this.adsActive ? !_this.adPlaying : player.paused(); - this.toggleClass('vjs-play-control-ad', _this.adsActive); - this.toggleClass('vjs-paused', paused); - this.toggleClass('vjs-playing', !paused); - var text = paused ? 'Play' : 'Pause'; - if (text != this.controlText()) - this.controlText(text); - }, true); - overrideHandler(PlayToggle, playToggle, player, 'play', - 'handlePlay', function() { this.update(); }, true); - overrideHandler(PlayToggle, playToggle, player, 'pause', - 'handlePause', function() { this.update(); }, true); - - var SeekBar = videojs.getComponent('SeekBar'); - var DvrSeekBar = videojs.getComponent('DvrSeekBar'); - var seekBar = this.vjsControls.progressControl.seekBar; - var getPercent = function() { - var duration = _this.currentAd && _this.currentAd.getDuration(); - if (!duration || duration<0) { - return 0; - } - var remainingTime = _this.adsManager.getRemainingTime(); - var currentTime = Math.max(duration - remainingTime, 0); - return currentTime / duration; - }; - override(SeekBar, seekBar, 'getPercent', getPercent); - if (DvrSeekBar) { - override(DvrSeekBar, seekBar, 'getPercent', getPercent); - } - overrideHandler(SeekBar, seekBar, null, ['mousedown', 'touchstart'], - 'handleMouseDown', null); - overrideHandler(SeekBar, seekBar, null, 'focus', 'handleFocus', null); - - var DurationDisplay = videojs.getComponent('DurationDisplay'); - var durationDisplay = this.vjsControls.durationDisplay; - overrideHandler(DurationDisplay, durationDisplay, player, - ['timeupdate', 'loadedmetadata'], 'updateContent', function() { - var duration = _this.currentAd && _this.currentAd.getDuration(); - if (duration && duration != this.duration_) { - this.duration_ = duration; - this.contentEl_.innerHTML = ''+ - this.localize('Duration Time')+' '+formatTime(duration); - } - }); - - var CurrentTimeDisplay = videojs.getComponent('CurrentTimeDisplay'); - var currentTimeDisplay = this.vjsControls.currentTimeDisplay; - overrideHandler(CurrentTimeDisplay, currentTimeDisplay, player, - ['timeupdate', 'loadedmetadata'], 'updateContent', function() { - var duration = _this.currentAd && _this.currentAd.getDuration(); - if (!duration) { - return; - } - var time = duration - _this.adsManager.getRemainingTime(); - var formattedTime = formatTime(time); - if (formattedTime !== this.formattedTime_) { - this.formattedTime_ = formattedTime; - this.contentEl_.innerHTML = ''+ - this.localize('Current Time')+' '+formattedTime; - } - }); - }.bind(this); - - this.updateVjsControls = function() { - if (!this.settings.vjsControls) { - return; - } - this.player.toggleClass('vjs-ad-paused', - this.adsActive && !this.adPlaying); - var controls = this.vjsControls; - controls.playToggle.update(); - controls.progressControl.seekBar.update(); - controls.durationDisplay.updateContent(); - controls.currentTimeDisplay.updateContent(); - var duration = this.currentAd && this.currentAd.getDuration(); - var display = !this.adsActive || duration && duration>=0 ? '' : 'none'; - controls.durationDisplay.el().style.display = display; - controls.currentTimeDisplay.el().style.display = display; - controls.timeDivider.el().style.display = display; - }.bind(this); - - var getPosition = function(el) { - var box = el.getBoundingClientRect(); - var docEl = document.documentElement; - var body = document.body; - var clientLeft = docEl.clientLeft || body.clientLeft || 0; - var scrollLeft = window.pageXOffset || body.scrollLeft; - var left = box.left + scrollLeft - clientLeft; - var clientTop = docEl.clientTop || body.clientTop || 0; - var scrollTop = window.pageYOffset || body.scrollTop; - var top = box.top + scrollTop - clientTop; - return { - left: left, - top: top, - width: box.width, - height: box.height, - }; - }; - - // proxy click events to the video element when non-linear ad is active - this.proxyClickEvents = function() { - var events = (videojs && videojs.browser && videojs.browser.IS_ANDROID || videojs.browser.IS_IOS) ? - ['touchstart', 'touchend'] : - ['click', 'dblclick', 'mousedown', 'mouseup']; - var player = this.player, el = player.el(), _this = this; - events.forEach(function(eventName) { - el.addEventListener(eventName, function(e) { - var ad = _this.currentAd, t = e.target; - if (!ad || ad.isLinear() || t.nodeName!='IFRAME' || e.isTrusted) { - return; - } - // ignore clicks on ad ui elements - var adWidth = ad.getWidth() || ad.getVastMediaWidth(); - var adHeight = ad.getHeight() || ad.getVastMediaHeight(); - var pos = getPosition(t); - var touch = e.touches && e.touches[0]; - var x = touch ? touch.pageX : e.clientX; - var y = touch ? touch.pageY : e.clientY; - var adRight = pos.left+pos.width-(pos.width-adWidth)/2; - var adTop = pos.top+pos.height-adHeight-4; - // click on close button - if (x(adRight-40) && y>adTop && y<(adTop+30)) { - return; - } - // click on recall button - if (x>(pos.left+pos.width/2-15) && x<(pos.left+pos.width/2+15) && - y>(pos.top+pos.height-15)) { - return; - } - var newEvent; - var opt = {}; - for (var key in e) { - opt[key] = e[key]; - } - opt.bubbles = false; - try { - newEvent = new e.constructor(e.type, opt); - } catch (err) { - // special case for IE11 - newEvent = document.createEvent('MouseEvent'); - newEvent.initMouseEvent(e.type, opt.bubbles, opt.cancelable, - opt.view, opt.detail, opt.screenX, opt.screenY, opt.clientX, - opt.clientY, opt.ctrlKey, opt.altKey, opt.shiftKey, opt.metaKey, - opt.button, null); - } - newEvent.stopPropagation(); - player.tech_.trigger(newEvent); - }); - }); - }.bind(this); - - this.settings = extend({}, ima_defaults, options || {}); - this.settings.adLabel = this.player.localize(this.settings.adLabel); - - // Currently this isn't used but I can see it being needed in the future, so - // to avoid implementation problems with later updates I'm requiring it. - if (!this.settings['id']) { - window.console.log('Error: must provide id of video.js div'); - return; - } - - this.controlPrefix = (this.settings.id + '_') || ''; - - this.contentPlayer = this.player.$('.vjs-tech'); - // Default showing countdown timer to true. - this.showCountdown = true; - if (this.settings['showCountdown'] === false) { - this.showCountdown = false; - } - - this.autoPlayAdBreaks = true; - if (this.settings['autoPlayAdBreaks'] === false) { - this.autoPlayAdBreaks = false; - } - - var contrib_ads_defaults = { - debug: this.settings.debug, - timeout: this.settings.timeout, - prerollTimeout: this.settings.prerollTimeout, - postrollTimeout: this.settings.postrollTimeout - }; - - var ads_plugin_settings = - extend({}, contrib_ads_defaults, options['contribAdsSettings'] || {}); - - player.ads(ads_plugin_settings); - - player.one('play', setUpPlayerIntervals_); - player.on('contentended', this.localContentEndedListener); - player.on('dispose', this.playerDisposedListener); - player.on('timeupdate', updateStartTime_); - this.adsRenderingSettings = new google.ima.AdsRenderingSettings(); - this.adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; - if (this.settings['adsRenderingSettings']) { - for (var setting in this.settings['adsRenderingSettings']) { - this.adsRenderingSettings[setting] = - this.settings['adsRenderingSettings'][setting]; - } - } - - if (this.settings['locale']) { - google.ima.settings.setLocale(this.settings['locale']); - } - - createAdContainer_(); - this.adsLoader = new google.ima.AdsLoader(this.adDisplayContainer); - - this.adsLoader.getSettings().setVpaidMode( - google.ima.ImaSdkSettings.VpaidMode.ENABLED); - if (this.settings.vpaidAllowed == false) { - this.adsLoader.getSettings().setVpaidMode( - google.ima.ImaSdkSettings.VpaidMode.DISABLED); - } - if (this.settings.vpaidMode) { - this.adsLoader.getSettings().setVpaidMode(this.settings.vpaidMode); - } - - if (this.settings.locale) { - this.adsLoader.getSettings().setLocale(this.settings.locale); - } - - if (this.settings.numRedirects) { - this.adsLoader.getSettings().setNumRedirects(this.settings.numRedirects); - } - - this.adsLoader.getSettings().setPlayerType('videojs-ima'); - this.adsLoader.getSettings().setPlayerVersion(this.VERSION); - this.adsLoader.getSettings().setAutoPlayAdBreaks(this.autoPlayAdBreaks); - - this.adsLoader.addEventListener( - google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, - onAdsManagerLoaded_, - false); - this.adsLoader.addEventListener( - google.ima.AdErrorEvent.Type.AD_ERROR, - onAdsLoaderError_, - false); - - if (!readyCallback) { - readyCallback = this.startFromReadyCallback; - } - player.on('readyforpreroll', readyCallback); - player.ready(function() { - player.on('fullscreenchange', onFullscreenChange_); - player.on('volumechange', onVolumeChange_); - }); - this.proxyClickEvents(); - }; - - videojs.registerPlugin('ima', init); -}); +import 'videojs-contrib-ads'; +import 'videojs-ima'; +import 'videojs-ima/dist/videojs.ima.scss'; diff --git a/src/plugins/ima/index.js b/src/plugins/ima/index.js index 43873798..70867f71 100644 --- a/src/plugins/ima/index.js +++ b/src/plugins/ima/index.js @@ -1,11 +1,9 @@ /* global google */ import { isFunction } from 'utils/type-inference'; import { PLAYER_EVENT } from 'utils/consts'; -import 'videojs-contrib-ads'; -import './ima'; -import './videojs-ima.scss'; -export default function imaPlugin(player, playerOptions) { +export default async function imaPlugin(player, playerOptions) { + await import(/* webpackChunkName: "ima" */ './ima'); const loaded = { contribAdsLoaded: isFunction(player.ads), @@ -38,11 +36,11 @@ export default function imaPlugin(player, playerOptions) { if (Object.keys(playerOptions.ads).length > 0 && typeof player.ima === 'object') { if (playerOptions.ads.adsInPlaylist === 'first-video') { player.one(PLAYER_EVENT.SOURCE_CHANGED, () => { - player.ima.playAd(); + player.ima.playAdBreak(); }); } else { player.on(PLAYER_EVENT.SOURCE_CHANGED, () => { - player.ima.playAd(); + player.ima.playAdBreak(); }); } } diff --git a/src/plugins/ima/videojs-ima.scss b/src/plugins/ima/videojs-ima.scss deleted file mode 100644 index 8d796355..00000000 --- a/src/plugins/ima/videojs-ima.scss +++ /dev/null @@ -1,252 +0,0 @@ -.cld-video-player { - .ima-fullscreen-div, .ima-mute-div, .ima-play-pause-div, .ima-slider-div { - line-height: 1.7; - } - - &.vjs-ad-loading { - > video, - > .vjs-poster { - opacity: 0; - } - } -} - -.ima-ad-container { - top: 0; - left: 0; - position: absolute; - display: block; - width: 100%; - height: 100%; - video { - left: 0; - } -} - -/* Move overlay if user fast-clicks play button. */ -.video-js.vjs-playing .bumpable-ima-ad-container { - margin-top: -50px; -} - -/* Move overlay when controls are active. */ -.video-js.vjs-user-inactive.vjs-playing .bumpable-ima-ad-container { - margin-top: 0px; -} - -.video-js.vjs-paused .bumpable-ima-ad-container, -.video-js.vjs-playing:hover .bumpable-ima-ad-container, -.video-js.vjs-user-active.vjs-playing .bumpable-ima-ad-container { - margin-top: -50px; -} - -.vjs-ima-non-linear .vjs-big-play-button, -.vjs-ima-non-linear .vjs-menu.vjs-settings-menu, -.vjs-ima-non-linear .vjs-info-overlay, -.vjs-ima-non-linear .vjs-modal-overlay, -.vjs-ima-non-linear .vjs-control-bar { - z-index: 1112; -} - -.ima-controls-div { - bottom:0px; - height: 37px; - position: absolute; - overflow: hidden; - display: none; - opacity: 1; - background-color: rgba(7, 20, 30, .7); - background: -moz-linear-gradient( - bottom, - rgba(7, 20, 30, .7) 0%, - rgba(7, 20, 30, 0) 100%); /* FF3.6+ */ - background: -webkit-gradient( - linear, - left bottom, - left top, - color-stop(0%,rgba(7, 20, 30, .7)), - color-stop(100%,rgba(7, 20, 30, 0))); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient( - bottom, - rgba(7, 20, 30, .7) 0%, - rgba(7, 20, 30, 0) 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(bottom, - rgba(7, 20, 30, .7) 0%, - rgba(7, 20, 30, 0) 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(bottom, - rgba(7, 20, 30, .7) 0%, - rgba(7, 20, 30, 0) 100%); /* IE10+ */ - background: linear-gradient(to top, - rgba(7, 20, 30, .7) 0%, - rgba(7, 20, 30, 0) 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( - startColorstr='#0007141E', - endColorstr='#07141E',GradientType=0 ); /* IE6-9 */ -} - -.ima-countdown-div { - height: 10px; - color: #FFFFFF; - text-shadow: 0 0 0.2em #000; - cursor: default; -} - -.ima-seek-bar-div { - top: 12px; - height: 3px; - position: absolute; - background: rgba(255, 255, 255, .4); -} - -.ima-progress-div { - width: 0px; - height: 3px; - background-color: #ECC546; -} - -.ima-play-pause-div, .ima-mute-div, .ima-slider-div, .ima-fullscreen-div { - width: 35px; - height: 20px; - top: 11px; - left: 0px; - position: absolute; - color: #CCCCCC; - font-size: 1.5em; - line-height: 2; - text-align: center; - font-family: VideoJS; - cursor: pointer; -} - -.ima-mute-div { - left: auto; - right: 85px; -} - -.ima-slider-div { - left: auto; - right: 35px; - width: 50px; - height: 10px; - top: 20px; - background-color: #555555; -} - -.ima-slider-level-div { - width: 100%; - height: 10px; - background-color: #ECC546; -} - -.ima-fullscreen-div { - left: auto; - right: 0px; -} - -.ima-playing:before { - content: "\00f103"; -} - -.ima-paused:before { - content: "\00f101"; -} - -.ima-playing:hover:before, .ima-paused:hover:before { - text-shadow: 0 0 1em #fff; -} - -.ima-non-muted:before { - content: "\00f107"; -} - -.ima-muted:before { - content: "\00f104"; -} - -.ima-non-muted:hover:before, .ima-muted:hover:before { - text-shadow: 0 0 1em #fff; -} - -.ima-non-fullscreen:before { - content: "\00f108"; -} - -.ima-fullscreen:before { - content: "\00f109"; -} - -.ima-non-fullscreen:hover:before, .ima-fullscreen:hover:before { - text-shadow: 0 0 1em #fff; -} - -.video-js.vjs-ad-playing .vjs-control-bar { - z-index: 1112; -} - -.video-js.vjs-ad-playing .vjs-control-bar .vjs-progress-control { - pointer-events: none; -} - -.video-js.vjs-ad-playing .vjs-control-bar>:not(.vjs-play-control):not(.vjs-volume-menu-button):not(.vjs-time-control):not(.vjs-progress-control):not(.vjs-spacer):not(.vjs-fullscreen-control):not(.vjs-gradient):not(.ima-countdown-div), -.video-js.vjs-ad-playing .vjs-control-bar .vjs-mouse-display-tooltip, -.video-js.vjs-ad-playing .vjs-control-bar .vjs-progress-control:before, -.video-js.vjs-ad-playing .vjs-control-bar .vjs-play-progress:before, -.video-js.vjs-ad-playing .vjs-control-bar .vjs-progress-control .vjs-load-progress, -.video-js.vjs-ad-playing .vjs-control-bar .vjs-progress-control .vjs-mouse-display { - display: none; -} - -.video-js.vjs-ad-playing .vjs-control-bar { - transition: height 0.1s ease; -} - -.video-js.vjs-ad-playing.vjs-user-inactive:not(.vjs-ad-paused) .vjs-control-bar { - opacity: 1; - height: 0; -} - -.video-js.vjs-ad-playing.vjs-user-inactive:not(.vjs-ad-paused) .vjs-control-bar .vjs-progress-holder { - margin: 0; -} - -.video-js.vjs-ad-playing .vjs-control-bar>:not(.vjs-progress-control):not(.ima-countdown-div) { - transition: opacity 0.1s ease, visibility 0.1s ease; -} - -.video-js.vjs-ad-playing .vjs-control-bar>:not(.vjs-progress-control):not(.ima-countdown-div) div{ - transition: line-height 0.1s ease; -} - -.video-js.vjs-ad-playing.vjs-user-inactive:not(.vjs-ad-paused) .vjs-control-bar>:not(.vjs-progress-control):not(.ima-countdown-div) { - opacity: 0; - visibility: hidden; - overflow: hidden; -} - -.video-js.vjs-ad-playing.vjs-user-inactive:not(.vjs-ad-paused) .vjs-control-bar>:not(.vjs-progress-control):not(.ima-countdown-div) div{ - line-height: 0.01em; -} - -.video-js.vjs-ad-playing .vjs-control-bar .vjs-progress-control .vjs-thumbnail-holder, -.video-js.vjs-ad-playing .vjs-control-bar .vjs-progress-control .vjs-thumbnail { - display: none !important; -} - -.video-js.vjs-ad-playing .vjs-control-bar .vjs-progress-control .vjs-progress-holder { - cursor: auto; - box-shadow: none; - font-size: 100%; - margin: 0 1em; -} - -.video-js .vjs-control-bar .ima-countdown-div { - display: none; - z-index: 1; -} - -.video-js.vjs-ad-playing .vjs-control-bar .ima-countdown-div { - display: block; - position: absolute; - margin-top: -2em; - left: 2em; - font-size: 1.2em; -} diff --git a/src/plugins/index.js b/src/plugins/index.js index cc406014..935fe2b4 100644 --- a/src/plugins/index.js +++ b/src/plugins/index.js @@ -1,8 +1,6 @@ import 'videojs-per-source-behaviors'; // #if (!process.env.WEBPACK_BUILD_LIGHT) -import dashPlugin from './dash'; -import imaPlugin from './ima'; import './videojs-http-source-selector/plugin'; // #endif @@ -19,17 +17,14 @@ import pacedTranscript from './paced-transcript'; import vttThumbnails from './vtt-thumbnails'; // Lazy loaded plugins +import dashPlugin from './dash'; +import imaPlugin from './ima'; import playlist from './playlist'; import shoppable from './shoppable-plugin'; import styledTextTracks from './styled-text-tracks'; import interactionAreas from './interaction-areas'; const plugins = { - // #if (!process.env.WEBPACK_BUILD_LIGHT) - dashPlugin, - imaPlugin, - // #endif - aiHighlightsGraph, analytics, autoplayOnScroll, @@ -43,6 +38,8 @@ const plugins = { vttThumbnails, // Lazy loaded plugins + dashPlugin, + imaPlugin, playlist, shoppable, styledTextTracks,