PageSourceSearch

https://www.cadena3.com/js/videojs.ima.js

js cadena3.com collected 2026-10-01 09:03:46 UTC 110,707 bytes, 3,748 lines download raw bytes

1(function (global, factory) {
2	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('video.js')) :
3	typeof define === 'function' && define.amd ? define(['exports', 'video.js'], factory) :
4	(factory((global.videojsIma = {}),global.videojs));
5}(this, (function (exports,videojs) { 'use strict';
6
7videojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs;
8
9/**
10 * Copyright 2017 Google Inc.
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 *     http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 * IMA SDK integration plugin for Video.js. For more information see
25 * https://www.github.com/googleads/videojs-ima
26 */
27
28/**
29 * Wraps the video.js player for the plugin.
30 *
31 * @param {Object} player Video.js player instance.
32 * @param {Object} adsPluginSettings Settings for the contrib-ads plugin.
33 * @param {Controller} controller Reference to the parent controller.
34 */
35const PlayerWrapper = function (player, adsPluginSettings, controller) {
36  /**
37   * Instance of the video.js player.
38   */
39  this.vjsPlayer = player;
40
41  /**
42   * Plugin controller.
43   */
44  this.controller = controller;
45
46  /**
47   * Timer used to track content progress.
48   */
49  this.contentTrackingTimer = null;
50
51  /**
52   * True if our content video has completed, false otherwise.
53   */
54  this.contentComplete = false;
55
56  /**
57   * Handle to interval that repeatedly updates current time.
58   */
59  this.updateTimeIntervalHandle = null;
60
61  /**
62   * Interval (ms) to check for player resize for fluid support.
63   */
64  this.updateTimeInterval = 1000;
65
66  /**
67   * Handle to interval that repeatedly checks for seeking.
68   */
69  this.seekCheckIntervalHandle = null;
70
71  /**
72   * Interval (ms) on which to check if the user is seeking through the
73   * content.
74   */
75  this.seekCheckInterval = 1000;
76
77  /**
78   * Handle to interval that repeatedly checks for player resize.
79   */
80  this.resizeCheckIntervalHandle = null;
81
82  /**
83   * Interval (ms) to check for player resize for fluid support.
84   */
85  this.resizeCheckInterval = 250;
86
87  /**
88   * Threshold by which to judge user seeking. We check every 1000 ms to see
89   * if the user is seeking. In order for us to decide that they are *not*
90   * seeking, the content video playhead must only change by 900-1100 ms
91   * between checks. Any greater change and we assume the user is seeking
92   * through the video.
93   */
94  this.seekThreshold = 100;
95
96  /**
97   * Content ended listeners passed by the publisher to the plugin. Publishers
98   * should allow the plugin to handle content ended to ensure proper support
99   * of custom ad playback.
100   */
101  this.contentEndedListeners = [];
102
103  /**
104   * Stores the content source so we can re-populate it manually after a
105   * post-roll on iOS.
106   */
107  this.contentSource = '';
108
109  /**
110   * Stores the content source type so we can re-populate it manually after a
111   * post-roll.
112   */
113  this.contentSourceType = '';
114
115  /**
116   * Stores data for the content playhead tracker.
117   */
118  this.contentPlayheadTracker = {
119    currentTime: 0,
120    previousTime: 0,
121    seeking: false,
122    duration: 0
123  };
124
125  /**
126   * Player dimensions. Used in our resize check.
127   */
128  this.vjsPlayerDimensions = {
129    width: this.getPlayerWidth(),
130    height: this.getPlayerHeight()
131  };
132
133  /**
134   * Video.js control bar.
135   */
136  this.vjsControls = this.vjsPlayer.getChild('controlBar');
137
138  /**
139   * Vanilla HTML5 video player underneath the video.js player.
140   */
141  this.h5Player = null;
142
143  this.vjsPlayer.one('play', this.setUpPlayerIntervals.bind(this));
144  this.boundContentEndedListener = this.localContentEndedListener.bind(this);
145  this.vjsPlayer.on('contentended', this.boundContentEndedListener);
146  this.vjsPlayer.on('dispose', this.playerDisposedListener.bind(this));
147  this.vjsPlayer.on('readyforpreroll', this.onReadyForPreroll.bind(this));
148  this.vjsPlayer.on('adtimeout', this.onAdTimeout.bind(this));
149  this.vjsPlayer.ready(this.onPlayerReady.bind(this));
150
151  if (this.controller.getSettings().requestMode === 'onPlay') {
152    this.vjsPlayer.one('play', this.controller.requestAds.bind(this.controller));
153  }
154
155  this.vjsPlayer.ads(adsPluginSettings);
156};
157
158/**
159 * Set up the intervals we use on the player.
160 */
161PlayerWrapper.prototype.setUpPlayerIntervals = function () {
162  this.updateTimeIntervalHandle = setInterval(this.updateCurrentTime.bind(this), this.updateTimeInterval);
163  this.seekCheckIntervalHandle = setInterval(this.checkForSeeking.bind(this), this.seekCheckInterval);
164  this.resizeCheckIntervalHandle = setInterval(this.checkForResize.bind(this), this.resizeCheckInterval);
165};
166
167/**
168 * Updates the current time of the video
169 */
170PlayerWrapper.prototype.updateCurrentTime = function () {
171  if (!this.contentPlayheadTracker.seeking) {
172    this.contentPlayheadTracker.currentTime = this.vjsPlayer.currentTime();
173  }
174};
175
176/**
177 * Detects when the user is seeking through a video.
178 * This is used to prevent mid-rolls from playing while a user is seeking.
179 *
180 * There *is* a seeking property of the HTML5 video element, but it's not
181 * properly implemented on all platforms (e.g. mobile safari), so we have to
182 * check ourselves to be sure.
183 */
184PlayerWrapper.prototype.checkForSeeking = function () {
185  const tempCurrentTime = this.vjsPlayer.currentTime();
186  const diff = (tempCurrentTime - this.contentPlayheadTracker.previousTime) * 1000;
187  if (Math.abs(diff) > this.seekCheckInterval + this.seekThreshold) {
188    this.contentPlayheadTracker.seeking = true;
189  } else {
190    this.contentPlayheadTracker.seeking = false;
191  }
192  this.contentPlayheadTracker.previousTime = this.vjsPlayer.currentTime();
193};
194
195/**
196 * Detects when the player is resized (for fluid support) and resizes the
197 * ads manager to match.
198 */
199PlayerWrapper.prototype.checkForResize = function () {
200  const currentWidth = this.getPlayerWidth();
201  const currentHeight = this.getPlayerHeight();
202
203  if (currentWidth != this.vjsPlayerDimensions.width || currentHeight != this.vjsPlayerDimensions.height) {
204    this.vjsPlayerDimensions.width = currentWidth;
205    this.vjsPlayerDimensions.height = currentHeight;
206    this.controller.onPlayerResize(currentWidth, currentHeight);
207  }
208};
209
210/**
211 * Local content ended listener for contentComplete.
212 */
213PlayerWrapper.prototype.localContentEndedListener = function () {
214  if (!this.contentComplete) {
215    this.contentComplete = true;
216    this.controller.onContentComplete();
217  }
218
219  for (let index in this.contentEndedListeners) {
220    if (typeof this.contentEndedListeners[index] === 'function') {
221      this.contentEndedListeners[index]();
222    }
223  }
224
225  clearInterval(this.updateTimeIntervalHandle);
226  clearInterval(this.seekCheckIntervalHandle);
227  clearInterval(this.resizeCheckIntervalHandle);
228  if (this.vjsPlayer.el()) {
229    this.vjsPlayer.one('play', this.setUpPlayerIntervals.bind(this));
230  }
231};
232
233/**
234 * Called when it's time to play a post-roll but we don't have one to play.
235 */
236PlayerWrapper.prototype.onNoPostroll = function () {
237  this.vjsPlayer.trigger('nopostroll');
238};
239
240/**
241 * Detects when the video.js player has been disposed.
242 */
243PlayerWrapper.prototype.playerDisposedListener = function () {
244  this.contentEndedListeners = [];
245  this.controller.onPlayerDisposed();
246
247  this.contentComplete = true;
248  this.vjsPlayer.off('contentended', this.boundContentEndedListener);
249
250  // Bug fix: https://github.com/googleads/videojs-ima/issues/306
251  if (this.vjsPlayer.ads.adTimeoutTimeout) {
252    clearTimeout(this.vjsPlayer.ads.adTimeoutTimeout);
253  }
254
255  const intervalsToClear = [this.updateTimeIntervalHandle, this.seekCheckIntervalHandle, this.resizeCheckIntervalHandle];
256  for (let index in intervalsToClear) {
257    if (intervalsToClear[index]) {
258      clearInterval(intervalsToClear[index]);
259    }
260  }
261};
262
263/**
264 * Start ad playback, or content video playback in the absence of a
265 * pre-roll.
266 */
267PlayerWrapper.prototype.onReadyForPreroll = function () {
268  this.controller.onPlayerReadyForPreroll();
269};
270
271/**
272 * Detects if the ad has timed out.
273 */
274PlayerWrapper.prototype.onAdTimeout = function () {
275  this.controller.onAdTimeout();
276};
277
278/**
279 * Called when the player fires its 'ready' event.
280 */
281PlayerWrapper.prototype.onPlayerReady = function () {
282  this.h5Player = document.getElementById(this.getPlayerId()).getElementsByClassName('vjs-tech')[0];
283
284  // Detect inline options
285  if (this.h5Player.hasAttribute('autoplay')) {
286    this.controller.setSetting('adWillAutoPlay', true);
287  }
288
289  // Sync ad volume with player volume.
290  this.onVolumeChange();
291  this.vjsPlayer.on('fullscreenchange', this.onFullscreenChange.bind(this));
292  this.vjsPlayer.on('volumechange', this.onVolumeChange.bind(this));
293
294  this.controller.onPlayerReady();
295};
296
297/**
298 * Listens for the video.js player to change its fullscreen status. This
299 * keeps the fullscreen-ness of the AdContainer in sync with the player.
300 */
301PlayerWrapper.prototype.onFullscreenChange = function () {
302  if (this.vjsPlayer.isFullscreen()) {
303    this.controller.onPlayerEnterFullscreen();
304  } else {
305    this.controller.onPlayerExitFullscreen();
306  }
307};
308
309/**
310 * Listens for the video.js player to change its volume. This keeps the ad
311 * volume in sync with the content volume if the volume of the player is
312 * changed while content is playing.
313 */
314PlayerWrapper.prototype.onVolumeChange = function () {
315  const newVolume = this.vjsPlayer.muted() ? 0 : this.vjsPlayer.volume();
316  this.controller.onPlayerVolumeChanged(newVolume);
317};
318
319/**
320 * Inject the ad container div into the DOM.
321 *
322 * @param{HTMLElement} adContainerDiv The ad container div.
323 */
324PlayerWrapper.prototype.injectAdContainerDiv = function (adContainerDiv) {
325  this.vjsControls.el().parentNode.appendChild(adContainerDiv);
326};
327
328/**
329 * @return {Object} The content player.
330 */
331PlayerWrapper.prototype.getContentPlayer = function () {
332  return this.h5Player;
333};
334
335/**
336 * @return {number} The volume, 0-1.
337 */
338PlayerWrapper.prototype.getVolume = function () {
339  return this.vjsPlayer.muted() ? 0 : this.vjsPlayer.volume();
340};
341
342/**
343 * Set the volume of the player. 0-1.
344 *
345 * @param {number} volume The new volume.
346 */
347PlayerWrapper.prototype.setVolume = function (volume) {
348  this.vjsPlayer.volume(volume);
349  if (volume == 0) {
350    this.vjsPlayer.muted(true);
351  } else {
352    this.vjsPlayer.muted(false);
353  }
354};
355
356/**
357 * Ummute the player.
358 */
359PlayerWrapper.prototype.unmute = function () {
360  this.vjsPlayer.muted(false);
361};
362
363/**
364 * Mute the player.
365 */
366PlayerWrapper.prototype.mute = function () {
367  this.vjsPlayer.muted(true);
368};
369
370/**
371 * Play the video.
372 */
373PlayerWrapper.prototype.play = function () {
374  this.vjsPlayer.play();
375};
376
377/**
378 * Toggles playback of the video.
379 */
380PlayerWrapper.prototype.togglePlayback = function () {
381  if (this.vjsPlayer.paused()) {
382    this.vjsPlayer.play();
383  } else {
384    this.vjsPlayer.pause();
385  }
386};
387
388/**
389 * Get the player width.
390 *
391 * @return {number}
vendor: 12,517 bytes, lines 391-826
391 The player's width.
392 */
393PlayerWrapper.prototype.getPlayerWidth = function () {
394  let width = (getComputedStyle(this.vjsPlayer.el()) || {}).width;
395
396  if (!width || parseFloat(width) === 0) {
397    width = (this.vjsPlayer.el().getBoundingClientRect() || {}).width;
398  }
399
400  return parseFloat(width) || this.vjsPlayer.width();
401};
402
403/**
404 * Get the player height.
405 *
406 * @return {number} The player's height.
407 */
408PlayerWrapper.prototype.getPlayerHeight = function () {
409  let height = (getComputedStyle(this.vjsPlayer.el()) || {}).height;
410
411  if (!height || parseFloat(height) === 0) {
412    height = (this.vjsPlayer.el().getBoundingClientRect() || {}).height;
413  }
414
415  return parseFloat(height) || this.vjsPlayer.height();
416};
417
418/**
419 * @return {Object} The vjs player's options object.
420 */
421PlayerWrapper.prototype.getPlayerOptions = function () {
422  return this.vjsPlayer.options_;
423};
424
425/**
426 * Returns the instance of the player id.
427 * @return {string} The player id.
428 */
429PlayerWrapper.prototype.getPlayerId = function () {
430  return this.vjsPlayer.id();
431};
432
433/**
434 * Toggle fullscreen state.
435 */
436PlayerWrapper.prototype.toggleFullscreen = function () {
437  if (this.vjsPlayer.isFullscreen()) {
438    this.vjsPlayer.exitFullscreen();
439  } else {
440    this.vjsPlayer.requestFullscreen();
441  }
442};
443
444/**
445 * Returns the content playhead tracker.
446 *
447 * @return {Object} The content playhead tracker.
448 */
449PlayerWrapper.prototype.getContentPlayheadTracker = function () {
450  return this.contentPlayheadTracker;
451};
452
453/**
454 * Handles ad errors.
455 *
456 * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.
457 */
458PlayerWrapper.prototype.onAdError = function (adErrorEvent) {
459  this.vjsControls.show();
460  const errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;
461  this.vjsPlayer.trigger({ type: 'adserror', data: {
462      AdError: errorMessage,
463      AdErrorEvent: adErrorEvent
464    } });
465};
466
467/**
468 * Handles ad log messages.
469 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the IMA SDK.
470 */
471PlayerWrapper.prototype.onAdLog = function (adEvent) {
472  const adData = adEvent.getAdData();
473  const errorMessage = adData['adError'] !== undefined ? adData['adError'].getMessage() : undefined;
474  this.vjsPlayer.trigger({ type: 'adslog', data: {
475      AdError: errorMessage,
476      AdEvent: adEvent
477    } });
478};
479
480/**
481 * Handles ad break starting.
482 */
483PlayerWrapper.prototype.onAdBreakStart = function () {
484  this.contentSource = this.vjsPlayer.currentSrc();
485  this.contentSourceType = this.vjsPlayer.currentType();
486  this.vjsPlayer.off('contentended', this.boundContentEndedListener);
487  this.vjsPlayer.ads.startLinearAdMode();
488  this.vjsControls.hide();
489  this.vjsPlayer.pause();
490};
491
492/**
493 * Handles ad break ending.
494 */
495PlayerWrapper.prototype.onAdBreakEnd = function () {
496  this.vjsPlayer.on('contentended', this.boundContentEndedListener);
497  if (this.vjsPlayer.ads.inAdBreak()) {
498    this.vjsPlayer.ads.endLinearAdMode();
499  }
500  this.vjsControls.show();
501};
502
503/**
504 * Handles an individual ad start.
505 */
506PlayerWrapper.prototype.onAdStart = function () {
507  this.vjsPlayer.trigger('ads-ad-started');
508};
509
510/**
511 * Handles when all ads have finished playing.
512 */
513PlayerWrapper.prototype.onAllAdsCompleted = function () {
514  if (this.contentComplete == true) {
515    // The null check on this.contentSource was added to fix
516    // an error when the post-roll was an empty VAST tag.
517    if (this.contentSource && this.vjsPlayer.currentSrc() != this.contentSource) {
518      this.vjsPlayer.src({
519        src: this.contentSource,
520        type: this.contentSourceType
521      });
522    }
523    this.controller.onContentAndAdsCompleted();
524  }
525};
526
527/**
528 * Triggers adsready for contrib-ads.
529 */
530PlayerWrapper.prototype.onAdsReady = function () {
531  this.vjsPlayer.trigger('adsready');
532};
533
534/**
535 * Changes the player source.
536 * @param {?string} contentSrc The URI for the content to be played. Leave
537 *     blank to use the existing content.
538 */
539PlayerWrapper.prototype.changeSource = function (contentSrc) {
540  // Only try to pause the player when initialised with a source already
541  if (this.vjsPlayer.currentSrc()) {
542    this.vjsPlayer.currentTime(0);
543    this.vjsPlayer.pause();
544  }
545  if (contentSrc) {
546    this.vjsPlayer.src(contentSrc);
547  }
548  this.vjsPlayer.one('loadedmetadata', this.seekContentToZero.bind(this));
549};
550
551/**
552 * Seeks content to 00:00:00. This is used as an event handler for the
553 * loadedmetadata event, since seeking is not possible until that event has
554 * fired.
555 */
556PlayerWrapper.prototype.seekContentToZero = function () {
557  this.vjsPlayer.currentTime(0);
558};
559
560/**
561 * Triggers an event on the VJS player
562 * @param  {string} name The event name.
563 * @param  {Object} data The event data.
564 */
565PlayerWrapper.prototype.triggerPlayerEvent = function (name, data) {
566  this.vjsPlayer.trigger(name, data);
567};
568
569/**
570 * Listener JSDoc for ESLint. This listener can be passed to
571 * addContentEndedListener.
572 * @callback listener
573 */
574
575/**
576 * Adds a listener for the 'contentended' event of the video player. This should
577 * be used instead of setting an 'contentended' listener directly to ensure that
578 * the ima can do proper cleanup of the SDK before other event listeners are
579 * called.
580 * @param {listener} listener The listener to be called when content
581 *     completes.
582 */
583PlayerWrapper.prototype.addContentEndedListener = function (listener) {
584  this.contentEndedListeners.push(listener);
585};
586
587/**
588 * Reset the player.
589 */
590PlayerWrapper.prototype.reset = function () {
591  // Attempts to remove the contentEndedListener before adding it.
592  // This is to prevent an error where an erroring video caused multiple
593  // contentEndedListeners to be added.
594  this.vjsPlayer.off('contentended', this.boundContentEndedListener);
595
596  this.vjsPlayer.on('contentended', this.boundContentEndedListener);
597  this.vjsControls.show();
598  if (this.vjsPlayer.ads.inAdBreak()) {
599    this.vjsPlayer.ads.endLinearAdMode();
600  }
601  // Reset the content time we give the SDK. Fixes an issue where requesting
602  // VMAP followed by VMAP would play the second mid-rolls as pre-rolls if
603  // the first playthrough of the video passed the second response's
604  // mid-roll time.
605  this.contentPlayheadTracker.currentTime = 0;
606  this.contentComplete = false;
607};
608
609/**
610 * Copyright 2017 Google Inc.
611 *
612 * Licensed under the Apache License, Version 2.0 (the "License");
613 * you may not use this file except in compliance with the License.
614 * You may obtain a copy of the License at
615 *
616 *     http://www.apache.org/licenses/LICENSE-2.0
617 *
618 * Unless required by applicable law or agreed to in writing, software
619 * distributed under the License is distributed on an "AS IS" BASIS,
620 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
621 * See the License for the specific language governing permissions and
622 * limitations under the License.
623 *
624 * IMA SDK integration plugin for Video.js. For more information see
625 * https://www.github.com/googleads/videojs-ima
626 */
627
628/**
629 * Ad UI implementation.
630 *
631 * @param {Controller} controller Plugin controller.
632 * @constructor
633 * @struct
634 * @final
635 */
636const AdUi = function (controller) {
637  /**
638   * Plugin controller.
639   */
640  this.controller = controller;
641
642  /**
643   * Div used as an ad container.
644   */
645  this.adContainerDiv = document.createElement('div');
646
647  /**
648   * Div used to display ad controls.
649   */
650  this.controlsDiv = document.createElement('div');
651
652  /**
653   * Div used to display ad countdown timer.
654   */
655  this.countdownDiv = document.createElement('div');
656
657  /**
658   * Div used to display add seek bar.
659   */
660  this.seekBarDiv = document.createElement('div');
661
662  /**
663   * Div used to display ad progress (in seek bar).
664   */
665  this.progressDiv = document.createElement('div');
666
667  /**
668   * Div used to display ad play/pause button.
669   */
670  this.playPauseDiv = document.createElement('div');
671
672  /**
673   * Div used to display ad mute button.
674   */
675  this.muteDiv = document.createElement('div');
676
677  /**
678   * Div used by the volume slider.
679   */
680  this.sliderDiv = document.createElement('div');
681
682  /**
683   * Volume slider level visuals
684   */
685  this.sliderLevelDiv = document.createElement('div');
686
687  /**
688   * Div used to display ad fullscreen button.
689   */
690  this.fullscreenDiv = document.createElement('div');
691
692  /**
693   * Bound event handler for onMouseUp.
694   */
695  this.boundOnMouseUp = this.onMouseUp.bind(this);
696
697  /**
698   * Bound event handler for onMouseMove.
699   */
700  this.boundOnMouseMove = this.onMouseMove.bind(this);
701
702  /**
703   * Stores data for the ad playhead tracker.
704   */
705  this.adPlayheadTracker = {
706    'currentTime': 0,
707    'duration': 0,
708    'isPod': false,
709    'adPosition': 0,
710    'totalAds': 0
711  };
712
713  /**
714   * Used to prefix videojs ima controls.
715   */
716  this.controlPrefix = this.controller.getPlayerId() + '_';
717
718  /**
719   * Boolean flag to show or hide the ad countdown timer.
720   */
721  this.showCountdown = true;
722  if (this.controller.getSettings().showCountdown === false) {
723    this.showCountdown = false;
724  }
725
726  /**
727   * Boolean flag if the current ad is nonlinear.
728   */
729  this.isAdNonlinear = false;
730
731  this.createAdContainer();
732};
733
734/**
735 * Creates the ad container.
736 */
737AdUi.prototype.createAdContainer = function () {
738  this.assignControlAttributes(this.adContainerDiv, 'ima-ad-container');
739  this.adContainerDiv.style.position = 'absolute';
740  this.adContainerDiv.style.zIndex = 1111;
741  this.adContainerDiv.addEventListener('mouseenter', this.showAdControls.bind(this), false);
742  this.adContainerDiv.addEventListener('mouseleave', this.hideAdControls.bind(this), false);
743  this.adContainerDiv.addEventListener('click', this.onAdContainerClick.bind(this), false);
744  this.createControls();
745  this.controller.injectAdContainerDiv(this.adContainerDiv);
746};
747
748/**
749 * Create the controls.
750 */
751AdUi.prototype.createControls = function () {
752  this.assignControlAttributes(this.controlsDiv, 'ima-controls-div');
753  this.controlsDiv.style.width = '100%';
754
755  if (!this.controller.getIsMobile()) {
756    this.assignControlAttributes(this.countdownDiv, 'ima-countdown-div');
757    this.countdownDiv.innerHTML = this.controller.getSettings().adLabel;
758    this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';
759  } else {
760    this.countdownDiv.style.display = 'none';
761  }
762
763  this.assignControlAttributes(this.seekBarDiv, 'ima-seek-bar-div');
764  this.seekBarDiv.style.width = '100%';
765
766  this.assignControlAttributes(this.progressDiv, 'ima-progress-div');
767
768  this.assignControlAttributes(this.playPauseDiv, 'ima-play-pause-div');
769  this.addClass(this.playPauseDiv, 'ima-playing');
770  this.playPauseDiv.addEventListener('click', this.onAdPlayPauseClick.bind(this), false);
771
772  this.assignControlAttributes(this.muteDiv, 'ima-mute-div');
773  this.addClass(this.muteDiv, 'ima-non-muted');
774  this.muteDiv.addEventListener('click', this.onAdMuteClick.bind(this), false);
775
776  this.assignControlAttributes(this.sliderDiv, 'ima-slider-div');
777  this.sliderDiv.addEventListener('mousedown', this.onAdVolumeSliderMouseDown.bind(this), false);
778
779  // Hide volume slider controls on iOS as they aren't supported.
780  if (this.controller.getIsIos()) {
781    this.sliderDiv.style.display = 'none';
782  }
783
784  this.assignControlAttributes(this.sliderLevelDiv, 'ima-slider-level-div');
785
786  this.assignControlAttributes(this.fullscreenDiv, 'ima-fullscreen-div');
787  this.addClass(this.fullscreenDiv, 'ima-non-fullscreen');
788  this.fullscreenDiv.addEventListener('click', this.onAdFullscreenClick.bind(this), false);
789
790  this.adContainerDiv.appendChild(this.controlsDiv);
791  this.controlsDiv.appendChild(this.countdownDiv);
792  this.controlsDiv.appendChild(this.seekBarDiv);
793  this.controlsDiv.appendChild(this.playPauseDiv);
794  this.controlsDiv.appendChild(this.muteDiv);
795  this.controlsDiv.appendChild(this.sliderDiv);
796  this.controlsDiv.appendChild(this.fullscreenDiv);
797  this.seekBarDiv.appendChild(this.progressDiv);
798  this.sliderDiv.appendChild(this.sliderLevelDiv);
799};
800
801/**
802 * Listener for clicks on the play/pause button during ad playback.
803 */
804AdUi.prototype.onAdPlayPauseClick = function () {
805  this.controller.onAdPlayPauseClick();
806};
807
808/**
809 * Listener for clicks on the play/pause button during ad playback.
810 */
811AdUi.prototype.onAdMuteClick = function () {
812  this.controller.onAdMuteClick();
813};
814
815/**
816 * Listener for clicks on the fullscreen button during ad playback.
817 */
818AdUi.prototype.onAdFullscreenClick = function () {
819  this.controller.toggleFullscreen();
820};
821
822/**
823 * Show pause and hide play button
824 */
825AdUi.prototype.onAdsPaused = function () {
826  this.controller.sdkImpl.adPlaying = false;
827  this.addClass(this.playPauseDiv, 'ima-paused');
828  this.removeClass(this.playPauseDiv, 'ima-playing');
829  this.showAdControls();
830};
831
832/**
833 * Show pause and hide play button
834 */
835AdUi.prototype.onAdsResumed = function () {
836  this.onAdsPlaying();
837  this.showAdControls();
838};
839
840/**
841 * Show play and hide pause button
842 */
843AdUi.prototype.onAdsPlaying = function () {
844  this.controller.sdkImpl.adPlaying = true;
845  this.addClass(this.playPauseDiv, 'ima-playing');
846  this.removeClass(this.playPauseDiv, 'ima-paused');
847};
848
849/**
850 * Takes data from the controller to update the UI.
851 *
852 * @param {number} currentTime Current time of the ad.
853 * @param {number} remainingTime Remaining time of the ad.
854 * @param {number} duration Duration of the ad.
855 * @param {number} adPosition Index of the ad in the pod.
856 * @param {number} totalAds Total number of ads in the pod.
857 */
858AdUi.prototype.updateAdUi = function (currentTime, remainingTime, duration, adPosition, totalAds) {
859  // Update countdown timer data
860  const remainingMinutes = Math.floor(remainingTime / 60);
861  let remainingSeconds = Math.floor(remainingTime % 60);
862  if (remainingSeconds.toString().length < 2) {
863    remainingSeconds = '0' + remainingSeconds;
864  }
865  let podCount = ': ';
866  if (totalAds > 1) {
867    podCount = ' (' + adPosition + ' ' + this.controller.getSettings().adLabelNofN + ' ' + totalAds + '): ';
868  }
869  this.countdownDiv.innerHTML = this.controller.getSettings().adLabel + podCount + remainingMinutes + ':' + remainingSeconds;
870
871  // Update UI
872  const playProgressRatio = currentTime / duration;
873  const playProgressPercent = playProgressRatio * 100;
874  this.progressDiv.style.width = playProgressPercent + '%';
875};
876
877/**
878 * Handles UI changes when the ad is unmuted.
879 */
880AdUi.prototype.unmute = function () {
881  this.addClass(this.muteDiv, 'ima-non-muted');
882  this.removeClass(this.muteDiv, 'ima-muted');
883  this.sliderLevelDiv.style.width = this.controller.getPlayerVolume() * 100 + '%';
884};
885
886/**
887 * Handles UI changes when the ad is muted.
888 */
889AdUi.prototype.mute = function () {
890  this.addClass(this.muteDiv, 'ima-muted');
891  this.removeClass(this.muteDiv, 'ima-non-muted');
892  this.sliderLevelDiv.style.width = '0%';
893};
894
895/*
896 * Listener for mouse down events during ad playback. Used for volume.
897 */
898AdUi.prototype.onAdVolumeSliderMouseDown = function () {
899  document.addEventListener('mouseup', this.boundOnMouseUp, false);
900  document.addEventListener('mousemove', this.boundOnMouseMove, false);
901};
902
903/*
904 * Mouse movement listener used for volume slider.
905 */
906AdUi.prototype.onMouseMove = function (event) {
907  this.changeVolume(event);
908};
909
910/*
911 * Mouse release listener used for volume slider.
912 */
913AdUi.prototype.onMouseUp = function (event) {
914  this.changeVolume(event);
915  document.removeEventListener('mouseup', this.boundOnMouseUp);
916  document.removeEventListener('mousemove', this.boundOnMouseMove);
917};
918
919/*
920 * Utility function to set volume and associated UI
921 */
922AdUi.prototype.changeVolume = function (event) {
923  let percent = (event.clientX - this.sliderDiv.getBoundingClientRect().left) / this.sliderDiv.offsetWidth;
924  percent *= 100;
925  // Bounds value 0-100 if mouse is outside slider region.
926  percent = Math.min(Math.max(percent, 0), 100);
927  this.sliderLevelDiv.style.width = percent + '%';
928  if (this.percent == 0) {
929    this.addClass(this.muteDiv, 'ima-muted');
930    this.removeClass(this.muteDiv, 'ima-non-muted');
931  } else {
932    this.addClass(this.muteDiv, 'ima-non-muted');
933    this.removeClass(this.muteDiv, 'ima-muted');
934  }
935  this.controller.setVolume(percent / 100); // 0-1
936};
937
938/**
939 * Show the ad container.
940 */
941AdUi.prototype.showAdContainer = function () {
942  this.adContainerDiv.style.display = 'block';
943};
944
945/**
946 * Hide the ad container
947 */
948AdUi.prototype.hideAdContainer = function () {
949  this.adContainerDiv.style.display = 'none';
950};
951
952/**
953 * Handles clicks on the ad container
954 */
955AdUi.prototype.onAdContainerClick = function () {
956  if (this.isAdNonlinear) {
957    this.controller.togglePlayback();
958  }
959};
960
961/**
962 * Resets the state of the ad ui.
963 */
964AdUi.prototype.reset = function () {
965  this.hideAdContainer();
966};
967
968/**
969 * Handles ad errors.
970 */
971AdUi.prototype.onAdError = function () {
972  this.hideAdContainer();
973};
974
975/**
976 * Handles ad break starting.
977 *
978 * @param {Object} adEvent The event fired by the IMA SDK.
979 */
980AdUi.prototype.onAdBreakStart = function (adEvent) {
981  this.showAdContainer();
982
983  const contentType = adEvent.getAd().getContentType();
984  if (contentType === 'application/javascript' && !this.controller.getSettings().showControlsForJSAds) {
985    this.controlsDiv.style.display = 'none';
986  } else {
987    this.controlsDiv.style.display = 'block';
988  }
989  this.onAdsPlaying();
990  // Start with the ad controls minimized.
991  this.hideAdControls();
992};
993
994/**
995 * Handles ad break ending.
996 */
997AdUi.prototype.onAdBreakEnd = function () {
998  const currentAd = this.controller.getCurrentAd();
999  if (currentAd == null || // hide for post-roll only playlist
1000  currentAd.isLinear()) {
1001    // don't hide for non-linear ads
1002    this.hideAdContainer();
1003  }
1004  this.controlsDiv.style.display = 'none';
1005  this.countdownDiv.innerHTML = '';
1006};
1007
1008/**
1009 * Handles when all ads have finished playing.
1010 */
1011AdUi.prototype.onAllAdsCompleted = function () {
1012  this.hideAdContainer();
1013};
1014
1015/**
1016 * Handles when a linear ad starts.
1017 */
1018AdUi.prototype.onLinearAdStart = function () {
1019  // Don't bump container when controls are shown
1020  this.removeClass(this.adContainerDiv, 'bumpable-ima-ad-container');
1021  this.isAdNonlinear = false;
vendor: 5,604 bytes, lines 1022-1164
1022};
1023
1024/**
1025 * Handles when a non-linear ad starts.
1026 */
1027AdUi.prototype.onNonLinearAdLoad = function () {
1028  // For non-linear ads that show after a linear ad. For linear ads, we show the
1029  // ad container in onAdBreakStart to prevent blinking in pods.
1030  this.adContainerDiv.style.display = 'block';
1031  // Bump container when controls are shown
1032  this.addClass(this.adContainerDiv, 'bumpable-ima-ad-container');
1033  this.isAdNonlinear = true;
1034};
1035
1036AdUi.prototype.onPlayerEnterFullscreen = function () {
1037  this.addClass(this.fullscreenDiv, 'ima-fullscreen');
1038  this.removeClass(this.fullscreenDiv, 'ima-non-fullscreen');
1039};
1040
1041AdUi.prototype.onPlayerExitFullscreen = function () {
1042  this.addClass(this.fullscreenDiv, 'ima-non-fullscreen');
1043  this.removeClass(this.fullscreenDiv, 'ima-fullscreen');
1044};
1045
1046/**
1047 * Called when the player volume changes.
1048 *
1049 * @param {number} volume The new player volume.
1050 */
1051AdUi.prototype.onPlayerVolumeChanged = function (volume) {
1052  if (volume == 0) {
1053    this.addClass(this.muteDiv, 'ima-muted');
1054    this.removeClass(this.muteDiv, 'ima-non-muted');
1055    this.sliderLevelDiv.style.width = '0%';
1056  } else {
1057    this.addClass(this.muteDiv, 'ima-non-muted');
1058    this.removeClass(this.muteDiv, 'ima-muted');
1059    this.sliderLevelDiv.style.width = volume * 100 + '%';
1060  }
1061};
1062
1063/**
1064 * Shows ad controls on mouseover.
1065 */
1066AdUi.prototype.showAdControls = function () {
1067  const { disableAdControls } = this.controller.getSettings();
1068  if (!disableAdControls) {
1069    this.addClass(this.controlsDiv, 'ima-controls-div-showing');
1070  }
1071};
1072
1073/**
1074 * Hide the ad controls.
1075 */
1076AdUi.prototype.hideAdControls = function () {
1077  this.removeClass(this.controlsDiv, 'ima-controls-div-showing');
1078};
1079
1080/**
1081 * Assigns the unique id and class names to the given element as well as the
1082 * style class.
1083 * @param {HTMLElement} element Element that needs the controlName assigned.
1084 * @param {string} controlName Control name to assign.
1085 */
1086AdUi.prototype.assignControlAttributes = function (element, controlName) {
1087  element.id = this.controlPrefix + controlName;
1088  element.className = this.controlPrefix + controlName + ' ' + controlName;
1089};
1090
1091/**
1092 * Returns a regular expression to test a string for the given className.
1093 *
1094 * @param {string} className The name of the class.
1095 * @return {RegExp} The regular expression used to test for that class.
1096 */
1097AdUi.prototype.getClassRegexp = function (className) {
1098  // Matches on
1099  // (beginning of string OR NOT word char)
1100  // classname
1101  // (negative lookahead word char OR end of string)
1102  return new RegExp('(^|[^A-Za-z-])' + className + '((?![A-Za-z-])|$)', 'gi');
1103};
1104
1105/**
1106 * Returns whether or not the provided element has the provied class in its
1107 * className.
1108 * @param {HTMLElement} element Element to tes.t
1109 * @param {string} className Class to look for.
1110 * @return {boolean} True if element has className in class list. False
1111 *     otherwise.
1112 */
1113AdUi.prototype.elementHasClass = function (element, className) {
1114  const classRegexp = this.getClassRegexp(className);
1115  return classRegexp.test(element.className);
1116};
1117
1118/**
1119 * Adds a class to the given element if it doesn't already have the class
1120 * @param {HTMLElement} element Element to which the class will be added.
1121 * @param {string} classToAdd Class to add.
1122 */
1123AdUi.prototype.addClass = function (element, classToAdd) {
1124  element.className = element.className.trim() + ' ' + classToAdd;
1125};
1126
1127/**
1128 * Removes a class from the given element if it has the given class
1129 *
1130 * @param {HTMLElement} element Element from which the class will be removed.
1131 * @param {string} classToRemove Class to remove.
1132 */
1133AdUi.prototype.removeClass = function (element, classToRemove) {
1134  const classRegexp = this.getClassRegexp(classToRemove);
1135  element.className = element.className.trim().replace(classRegexp, '');
1136};
1137
1138/**
1139 * @return {HTMLElement} The div for the ad container.
1140 */
1141AdUi.prototype.getAdContainerDiv = function () {
1142  return this.adContainerDiv;
1143};
1144
1145/**
1146 * Changes the flag to show or hide the ad countdown timer.
1147 *
1148 * @param {boolean} showCountdownIn Show or hide the countdown timer.
1149 */
1150AdUi.prototype.setShowCountdown = function (showCountdownIn) {
1151  this.showCountdown = showCountdownIn;
1152  this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';
1153};
1154
1155var name = "videojs-ima";
1156var version = "2.0.1";
1157var license = "Apache-2.0";
1158var main = "./dist/videojs.ima.js";
1159var module$1 = "./dist/videojs.ima.es.js";
1160var author = { "name": "Google Inc." };
1161var engines = { "node": ">=0.8.0" };
1162var scripts = { "contBuild": "watch 'npm run rollup:max' src", "predevServer": "echo \"Starting up server on localhost:8000.\"", "devServer": "npm-run-all -p testServer contBuild", "lint": "eslint \"src/**/*.js\"", "rollup": "npm-run-all rollup:*", "rollup:max": "rollup -c configs/rollup.config.js", "rollup:es": "rollup -c configs/rollup.config.es.js", "rollup:min": "rollup -c configs/rollup.config.min.js", "pretest": "npm run rollup", "start": "npm run devServer", "test": "npm-run-all test:*", "test:vjs6": "npm install video.js@6 --no-save && npm-run-all -p -r testServer webdriver", "test:vjs7": "npm install video.js@7 --no-save && npm-run-all -p -r testServer webdriver", "testServer": "http-server --cors -p 8000 --silent", "preversion": "node scripts/preversion.js && npm run lint && npm test", "version": "node scripts/version.js", "postversion": "node scripts/postversion.js", "webdriver": "mocha test/webdriver/*.js --no-timeouts" };
1163var repository = { "type": "git", "url": "https://github.com/googleads/videojs-ima" };
1164var files = ["CHANGELOG.md", "LICENSE", "README.md", "dist/", "src/"];
1165var peerDependencies = { "video.js": "^5.19.2 || ^6 || ^7" };
1166var dependencies = { "@hapi/cryptiles": "^5.1.0", "can-autoplay": "^3.0.2", "extend": ">=3.0.2", "videojs-contrib-ads": "^6.9.0" };
1167var devDependencies = { "axios": "^0.25.0", "babel-core": "^6.26.3", "babel-preset-env": "^1.7.0", "child_process": "^1.0.2", "chromedriver": "^102.0.0", "conventional-changelog-cli": "^2.2.2", "conventional-changelog-videojs": "^3.0.2", "ecstatic": "^4.1.4", "eslint": "^8.8.0", "eslint-config-google": "^0.9.1", "eslint-plugin-jsdoc": "^3.15.1", "geckodriver": "^2.0.4", "http-server": "^14.1.0", "ini": ">=1.3.7", "mocha": "^9.2.0", "npm-run-all": "^4.1.5", "path": "^0.12.7", "protractor": "^7.0.0", "rimraf": "^2.7.1", "rollup": "^0.51.8", "rollup-plugin-babel": "^3.0.7", "rollup-plugin-copy": "^0.2.3", "rollup-plugin-json": "^2.3.1", "rollup-plugin-uglify": "^2.0.1", "selenium-webdriver": "^3.6.0", "uglify-es": "^3.3.9", "video.js": "^7.17.0", "watch": "^0.13.0", "webdriver-manager": "^12.1.7", "xmldom": "^0.6.0" };
1168var keywords = ["videojs", "videojs-plugin"];
1169var pkg = {
1170	name: name,
1171	version: version,
1172	license: license,
1173	main: main,
1174	module: module$1,
1175	author: author,
1176	engines: engines,
1177	scripts: scripts,
1178	repository: repository,
1179	files: files,
1180	peerDependencies: peerDependencies,
1181	dependencies: dependencies,
1182	devDependencies: devDependencies,
1183	keywords: keywords
1184};
1185
1186/**
1187 * Copyright 2017 Google Inc.
1188 *
1189 * Licensed under the Apache License, Version 2.0 (the "License");
1190 * you may not use this file except in compliance with the License.
1191 * You may obtain a copy of the License at
1192 *
1193 *     http://www.apache.org/licenses/LICENSE-2.0
1194 *
1195 * Unless required by applicable law or agreed to in writing, software
1196 * distributed under the License is distributed on an "AS IS" BASIS,
1197 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1198 * See the License for the specific language governing permissions and
1199 * limitations under the License.
1200 *
1201 * IMA SDK integration plugin for Video.js. For more information see
1202 * https://www.github.com/googleads/videojs-ima
1203 */
1204
1205/**
1206 * Implementation of the IMA SDK for the plugin.
1207 *
1208 * @param {Object} controller Reference to the parent controller.
1209 *
1210 * @constructor
1211 * @struct
1212 * @final
1213 */
1214const SdkImpl = function (controller) {
1215  /**
1216   * Plugin controller.
1217   */
1218  this.controller = controller;
1219
1220  /**
1221   * IMA SDK AdDisplayContainer.
1222   */
1223  this.adDisplayContainer = null;
1224
1225  /**
1226   * True if the AdDisplayContainer has been initialized. False otherwise.
1227   */
1228  this.adDisplayContainerInitialized = false;
1229
1230  /**
1231   * IMA SDK AdsLoader
1232   */
1233  this.adsLoader = null;
1234
1235  /**
1236   * IMA SDK AdsManager
1237   */
1238  this.adsManager = null;
1239
1240  /**
1241   * IMA SDK AdsRenderingSettings.
1242   */
1243  this.adsRenderingSettings = null;
1244
1245  /**
1246   * VAST, VMAP, or ad rules response. Used in lieu of fetching a response
1247   * from an ad tag URL.
1248   */
1249  this.adsResponse = null;
1250
1251  /**
1252   * Current IMA SDK Ad.
1253   */
1254  this.currentAd = null;
1255
1256  /**
1257   * Timer used to track ad progress.
1258   */
1259  this.adTrackingTimer = null;
1260
1261  /**
1262   * True if ALL_ADS_COMPLETED has fired, false until then.
1263   */
1264  this.allAdsCompleted = false;
1265
1266  /**
1267   * True if ads are currently displayed, false otherwise.
1268   * True regardless of ad pause state if an ad is currently being displayed.
1269   */
1270  this.adsActive = false;
1271
1272  /**
1273   * True if ad is currently playing, false if ad is paused or ads are not
1274   * currently displayed.
1275   */
1276  this.adPlaying = false;
1277
1278  /**
1279   * True if the ad is muted, false otherwise.
1280   */
1281  this.adMuted = false;
1282
1283  /**
1284   * Listener to be called to trigger manual ad break playback.
1285   */
1286  this.adBreakReadyListener = undefined;
1287
1288  /**
1289   * Tracks whether or not we have already called adsLoader.contentComplete().
1290   */
1291  this.contentCompleteCalled = false;
1292
1293  /**
1294   * True if the ad has timed out.
1295   */
1296  this.isAdTimedOut = false;
1297
1298  /**
1299   * Stores the dimensions for the ads manager.
1300   */
1301  this.adsManagerDimensions = {
1302    width: 0,
1303    height: 0
1304  };
1305
1306  /**
1307   * Boolean flag to enable manual ad break playback.
1308   */
1309  this.autoPlayAdBreaks = true;
1310  if (this.controller.getSettings().autoPlayAdBreaks === false) {
1311    this.autoPlayAdBreaks = false;
vendor: 4,817 bytes, lines 1312-1434
1312  }
1313
1314  // Set SDK settings from plugin settings.
1315  if (this.controller.getSettings().locale) {
1316    /* eslint no-undef: 'error' */
1317    /* global google */
1318    google.ima.settings.setLocale(this.controller.getSettings().locale);
1319  }
1320  if (this.controller.getSettings().disableFlashAds) {
1321    google.ima.settings.setDisableFlashAds(this.controller.getSettings().disableFlashAds);
1322  }
1323  if (this.controller.getSettings().disableCustomPlaybackForIOS10Plus) {
1324    google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.controller.getSettings().disableCustomPlaybackForIOS10Plus);
1325  }
1326
1327  if (this.controller.getSettings().ppid) {
1328    google.ima.settings.setPpid(this.controller.getSettings().ppid);
1329  }
1330
1331  if (this.controller.getSettings().featureFlags) {
1332    google.ima.settings.setFeatureFlags(this.controller.getSettings().featureFlags);
1333  }
1334};
1335
1336/**
1337 * Creates and initializes the IMA SDK objects.
1338 */
1339SdkImpl.prototype.initAdObjects = function () {
1340  this.adDisplayContainer = new google.ima.AdDisplayContainer(this.controller.getAdContainerDiv(), this.controller.getContentPlayer());
1341
1342  this.adsLoader = new google.ima.AdsLoader(this.adDisplayContainer);
1343
1344  this.adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.ENABLED);
1345  if (this.controller.getSettings().vpaidAllowed == false) {
1346    this.adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.DISABLED);
1347  }
1348  if (this.controller.getSettings().vpaidMode !== undefined) {
1349    this.adsLoader.getSettings().setVpaidMode(this.controller.getSettings().vpaidMode);
1350  }
1351
1352  if (this.controller.getSettings().locale) {
1353    this.adsLoader.getSettings().setLocale(this.controller.getSettings().locale);
1354  }
1355
1356  if (this.controller.getSettings().numRedirects) {
1357    this.adsLoader.getSettings().setNumRedirects(this.controller.getSettings().numRedirects);
1358  }
1359
1360  if (this.controller.getSettings().sessionId) {
1361    this.adsLoader.getSettings().setSessionId(this.controller.getSettings().sessionId);
1362  }
1363
1364  this.adsLoader.getSettings().setPlayerType('videojs-ima');
1365  this.adsLoader.getSettings().setPlayerVersion(pkg.version);
1366  this.adsLoader.getSettings().setAutoPlayAdBreaks(this.autoPlayAdBreaks);
1367
1368  this.adsLoader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, this.onAdsManagerLoaded.bind(this), false);
1369  this.adsLoader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, this.onAdsLoaderError.bind(this), false);
1370
1371  this.controller.playerWrapper.vjsPlayer.trigger({
1372    type: 'ads-loader',
1373    adsLoader: this.adsLoader
1374  });
1375};
1376
1377/**
1378 * Creates the AdsRequest and request ads through the AdsLoader.
1379 */
1380SdkImpl.prototype.requestAds = function () {
1381  const adsRequest = new google.ima.AdsRequest();
1382  if (this.controller.getSettings().adTagUrl) {
1383    adsRequest.adTagUrl = this.controller.getSettings().adTagUrl;
1384  } else {
1385    adsRequest.adsResponse = this.controller.getSettings().adsResponse;
1386  }
1387  if (this.controller.getSettings().forceNonLinearFullSlot) {
1388    adsRequest.forceNonLinearFullSlot = true;
1389  }
1390
1391  if (this.controller.getSettings().vastLoadTimeout) {
1392    adsRequest.vastLoadTimeout = this.controller.getSettings().vastLoadTimeout;
1393  }
1394
1395  if (this.controller.getSettings().omidMode) {
1396    adsRequest.omidAccessModeRules = {};
1397    const omidValues = this.controller.getSettings().omidMode;
1398
1399    if (omidValues.FULL) {
1400      adsRequest.omidAccessModeRules[google.ima.OmidAccessMode.FULL] = omidValues.FULL;
1401    }
1402    if (omidValues.DOMAIN) {
1403      adsRequest.omidAccessModeRules[google.ima.OmidAccessMode.DOMAIN] = omidValues.DOMAIN;
1404    }
1405    if (omidValues.LIMITED) {
1406      adsRequest.omidAccessModeRules[google.ima.OmidAccessMode.LIMITED] = omidValues.LIMITED;
1407    }
1408  }
1409
1410  adsRequest.linearAdSlotWidth = this.controller.getPlayerWidth();
1411  adsRequest.linearAdSlotHeight = this.controller.getPlayerHeight();
1412  adsRequest.nonLinearAdSlotWidth = this.controller.getSettings().nonLinearWidth || this.controller.getPlayerWidth();
1413  adsRequest.nonLinearAdSlotHeight = this.controller.getSettings().nonLinearHeight || this.controller.getPlayerHeight();
1414  adsRequest.setAdWillAutoPlay(this.controller.adsWillAutoplay());
1415  adsRequest.setAdWillPlayMuted(this.controller.adsWillPlayMuted());
1416
1417  // Populate the adsRequestproperties with those provided in the AdsRequest
1418  // object in the settings.
1419  let providedAdsRequest = this.controller.getSettings().adsRequest;
1420  if (providedAdsRequest && typeof providedAdsRequest === 'object') {
1421    Object.keys(providedAdsRequest).forEach(key => {
1422      adsRequest[key] = providedAdsRequest[key];
1423    });
1424  }
1425
1426  this.adsLoader.requestAds(adsRequest);
1427  this.controller.playerWrapper.vjsPlayer.trigger({
1428    type: 'ads-request',
1429    AdsRequest: adsRequest
1430  });
1431};
1432
1433/**
1434 * Listener for the ADS_MANAGER_LOADED event. Creates the AdsManager,
1435 * sets up event listeners, and triggers the 'adsready' event for
1436 * videojs-ads-contrib.
1437 *
1438 * @param {google.ima.AdsManagerLoadedEvent} adsManagerLoadedEvent Fired when
1439 *     the AdsManager loads.
1440 */
1441SdkImpl.prototype.onAdsManagerLoaded = function (adsManagerLoadedEvent) {
1442  this.createAdsRenderingSettings();
1443
1444  this.adsManager = adsManagerLoadedEvent.getAdsManager(this.controller.getContentPlayheadTracker(), this.adsRenderingSettings);
1445
1446  this.adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, this.onAdError.bind(this));
1447  this.adsManager.addEventListener(google.ima.AdEvent.Type.AD_BREAK_READY, this.onAdBreakReady.bind(this));
1448  this.adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, this.onContentPauseRequested.bind(this));
1449  this.adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, this.onContentResumeRequested.bind(this));
1450  this.adsManager.addEventListener(google.ima.AdEvent.Type.ALL_ADS_COMPLETED, this.onAllAdsCompleted.bind(this));
1451
1452  this.adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, this.onAdLoaded.bind(this));
1453  this.adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, this.onAdStarted.bind(this));
1454  this.adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, this.onAdComplete.bind(this));
1455  this.adsManager.addEventListener(google.ima.AdEvent.Type.SKIPPED, this.onAdComplete.bind(this));
1456  this.adsManager.addEventListener(google.ima.AdEvent.Type.LOG, this.onAdLog.bind(this));
1457  this.adsManager.addEventListener(google.ima.AdEvent.Type.PAUSED, this.onAdPaused.bind(this));
1458  this.adsManager.addEventListener(google.ima.AdEvent.Type.RESUMED, this.onAdResumed.bind(this));
1459
1460  this.controller.playerWrapper.vjsPlayer.trigger({
1461    type: 'ads-manager',
1462    adsManager: this.adsManager
1463  });
1464
1465  if (!this.autoPlayAdBreaks) {
1466    this.initAdsManager();
1467  }
1468
1469  const { preventLateAdStart } = this.controller.getSettings();
1470
1471  if (!preventLateAdStart) {
1472    this.controller.onAdsReady();
1473  } else if (preventLateAdStart && !this.isAdTimedOut) {
1474    this.controller.onAdsReady();
1475  }
1476
1477  if (this.controller.getSettings().adsManagerLoadedCallback) {
1478    this.controller.getSettings().adsManagerLoadedCallback();
1479  }
1480};
1481
1482/**
1483 * Listener for errors fired by the AdsLoader.
1484 * @param {google.ima.AdErrorEvent} event The error event thrown by the
1485 *     AdsLoader. See
1486 *     https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdError#.Type
1487 */
1488SdkImpl.prototype.onAdsLoaderError = function (event) {
1489  window.console.warn('AdsLoader error: ' + event.getError());
1490  this.controller.onErrorLoadingAds(event);
1491  if (this.adsManager) {
1492    this.adsManager.destroy();
1493  }
1494};
1495
1496/**
1497 * Initialize the ads manager.
1498 */
1499SdkImpl.prototype.initAdsManager = function () {
1500  try {
1501    const initWidth = this.controller.getPlayerWidth();
1502    const initHeight = this.controller.getPlayerHeight();
1503    this.adsManagerDimensions.width = initWidth;
1504    this.adsManagerDimensions.height = initHeight;
1505    this.adsManager.init(initWidth, initHeight, google.ima.ViewMode.NORMAL);
1506    this.adsManager.setVolume(this.controller.getPlayerVolume());
1507    this.initializeAdDisplayContainer();
1508  } catch (adError) {
1509    this.onAdError(adError);
1510  }
1511};
1512
1513/**
1514 * Create AdsRenderingSettings for the IMA SDK.
1515 */
1516SdkImpl.prototype.createAdsRenderingSettings = function () {
1517  this.adsRenderingSettings = new google.ima.AdsRenderingSettings();
1518  this.adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
1519  if (this.controller.getSettings().adsRenderingSettings) {
1520    for (let setting in this.controller.getSettings().adsRenderingSettings) {
1521      if (setting !== '') {
1522        this.adsRenderingSettings[setting] = this.controller.getSettings().adsRenderingSettings[setting];
1523      }
1524    }
1525  }
1526};
1527
1528/**
1529 * Listener for errors thrown by the AdsManager.
1530 * @param {google.ima.AdErrorEvent} adErrorEvent The error event thrown by
1531 *     the AdsManager.
1532 */
1533SdkImpl.prototype.onAdError = function (adErrorEvent) {
1534  const errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;
1535  window.console.warn('Ad error: ' + errorMessage);
1536
1537  this.adsManager.destroy();
1538  this.controller.onAdError(adErrorEvent);
1539
1540  // reset these so consumers don't think we are still in an ad break,
1541  // but reset them after any prior cleanup happens
1542  this.adsActive = false;
vendor: 29,487 bytes, lines 1543-2630
1543  this.adPlaying = false;
1544};
1545
1546/**
1547 * Listener for AD_BREAK_READY. Passes event on to publisher's listener.
1548 * @param {google.ima.AdEvent} adEvent AdEvent thrown by the AdsManager.
1549 */
1550SdkImpl.prototype.onAdBreakReady = function (adEvent) {
1551  this.adBreakReadyListener(adEvent);
1552};
1553
1554/**
1555 * Pauses the content video and displays the ad container so ads can play.
1556 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1557 */
1558SdkImpl.prototype.onContentPauseRequested = function (adEvent) {
1559  this.adsActive = true;
1560  this.adPlaying = true;
1561  this.controller.onAdBreakStart(adEvent);
1562};
1563
1564/**
1565 * Resumes content video and hides the ad container.
1566 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1567 */
1568SdkImpl.prototype.onContentResumeRequested = function (adEvent) {
1569  this.adsActive = false;
1570  this.adPlaying = false;
1571  this.controller.onAdBreakEnd();
1572  // Hide controls in case of future non-linear ads. They'll be unhidden in
1573  // content_pause_requested.
1574};
1575
1576/**
1577 * Records that ads have completed and calls contentAndAdsEndedListeners
1578 * if content is also complete.
1579 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1580 */
1581SdkImpl.prototype.onAllAdsCompleted = function (adEvent) {
1582  this.allAdsCompleted = true;
1583  this.controller.onAllAdsCompleted();
1584};
1585
1586/**
1587 * Starts the content video when a non-linear ad is loaded.
1588 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1589 */
1590SdkImpl.prototype.onAdLoaded = function (adEvent) {
1591  if (!adEvent.getAd().isLinear()) {
1592    this.controller.onNonLinearAdLoad();
1593    this.controller.playContent();
1594  }
1595};
1596
1597/**
1598 * Starts the interval timer to check the current ad time when an ad starts
1599 * playing.
1600 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1601 */
1602SdkImpl.prototype.onAdStarted = function (adEvent) {
1603  this.currentAd = adEvent.getAd();
1604  if (this.currentAd.isLinear()) {
1605    this.adTrackingTimer = setInterval(this.onAdPlayheadTrackerInterval.bind(this), 250);
1606    this.controller.onLinearAdStart();
1607  } else {
1608    this.controller.onNonLinearAdStart();
1609  }
1610};
1611
1612/**
1613 * Handles an ad click. Puts the player UI in a paused state.
1614 */
1615SdkImpl.prototype.onAdPaused = function () {
1616  this.controller.onAdsPaused();
1617};
1618
1619/**
1620 * Syncs controls when an ad resumes.
1621 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1622 */
1623SdkImpl.prototype.onAdResumed = function (adEvent) {
1624  this.controller.onAdsResumed();
1625};
1626
1627/**
1628 * Clears the interval timer for current ad time when an ad completes.
1629 */
1630SdkImpl.prototype.onAdComplete = function () {
1631  if (this.currentAd.isLinear()) {
1632    clearInterval(this.adTrackingTimer);
1633  }
1634};
1635
1636/**
1637 * Handles ad log messages.
1638 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.
1639 */
1640SdkImpl.prototype.onAdLog = function (adEvent) {
1641  this.controller.onAdLog(adEvent);
1642};
1643
1644/**
1645 * Gets the current time and duration of the ad and calls the method to
1646 * update the ad UI.
1647 */
1648SdkImpl.prototype.onAdPlayheadTrackerInterval = function () {
1649  if (this.adsManager === null) return;
1650  const remainingTime = this.adsManager.getRemainingTime();
1651  const duration = this.currentAd.getDuration();
1652  let currentTime = duration - remainingTime;
1653  currentTime = currentTime > 0 ? currentTime : 0;
1654  let totalAds = 0;
1655  let adPosition;
1656  if (this.currentAd.getAdPodInfo()) {
1657    adPosition = this.currentAd.getAdPodInfo().getAdPosition();
1658    totalAds = this.currentAd.getAdPodInfo().getTotalAds();
1659  }
1660
1661  this.controller.onAdPlayheadUpdated(currentTime, remainingTime, duration, adPosition, totalAds);
1662};
1663
1664/**
1665 * Called by the player wrapper when content completes.
1666 */
1667SdkImpl.prototype.onContentComplete = function () {
1668  if (this.adsLoader) {
1669    this.adsLoader.contentComplete();
1670    this.contentCompleteCalled = true;
1671  }
1672
1673  if (this.adsManager && this.adsManager.getCuePoints() && !this.adsManager.getCuePoints().includes(-1) || !this.adsManager) {
1674    this.controller.onNoPostroll();
1675  }
1676
1677  if (this.allAdsCompleted) {
1678    this.controller.onContentAndAdsCompleted();
1679  }
1680};
1681
1682/**
1683 * Called when the player is disposed.
1684 */
1685SdkImpl.prototype.onPlayerDisposed = function () {
1686  if (this.adTrackingTimer) {
1687    clearInterval(this.adTrackingTimer);
1688  }
1689  if (this.adsManager) {
1690    this.adsManager.destroy();
1691    this.adsManager = null;
1692  }
1693};
1694
1695SdkImpl.prototype.onPlayerReadyForPreroll = function () {
1696  if (this.autoPlayAdBreaks) {
1697    this.initAdsManager();
1698    try {
1699      this.controller.showAdContainer();
1700      // Sync ad volume with content volume.
1701      this.adsManager.setVolume(this.controller.getPlayerVolume());
1702      this.adsManager.start();
1703    } catch (adError) {
1704      this.onAdError(adError);
1705    }
1706  }
1707};
1708
1709SdkImpl.prototype.onAdTimeout = function () {
1710  this.isAdTimedOut = true;
1711};
1712
1713SdkImpl.prototype.onPlayerReady = function () {
1714  this.initAdObjects();
1715
1716  if ((this.controller.getSettings().adTagUrl || this.controller.getSettings().adsResponse) && this.controller.getSettings().requestMode === 'onLoad') {
1717    this.requestAds();
1718  }
1719};
1720
1721SdkImpl.prototype.onPlayerEnterFullscreen = function () {
1722  if (this.adsManager) {
1723    this.adsManager.resize(window.screen.width, window.screen.height, google.ima.ViewMode.FULLSCREEN);
1724  }
1725};
1726
1727SdkImpl.prototype.onPlayerExitFullscreen = function () {
1728  if (this.adsManager) {
1729    this.adsManager.resize(this.controller.getPlayerWidth(), this.controller.getPlayerHeight(), google.ima.ViewMode.NORMAL);
1730  }
1731};
1732
1733/**
1734 * Called when the player volume changes.
1735 *
1736 * @param {number} volume The new player volume.
1737 */
1738SdkImpl.prototype.onPlayerVolumeChanged = function (volume) {
1739  if (this.adsManager) {
1740    this.adsManager.setVolume(volume);
1741  }
1742
1743  if (volume == 0) {
1744    this.adMuted = true;
1745  } else {
1746    this.adMuted = false;
1747  }
1748};
1749
1750/**
1751 * Called when the player wrapper detects that the player has been resized.
1752 *
1753 * @param {number} width The post-resize width of the player.
1754 * @param {number} height The post-resize height of the player.
1755 */
1756SdkImpl.prototype.onPlayerResize = function (width, height) {
1757  if (this.adsManager) {
1758    this.adsManagerDimensions.width = width;
1759    this.adsManagerDimensions.height = height;
1760    /* eslint no-undef: 'error' */
1761    this.adsManager.resize(width, height, google.ima.ViewMode.NORMAL);
1762  }
1763};
1764
1765/**
1766 * @return {Object} The current ad.
1767 */
1768SdkImpl.prototype.getCurrentAd = function () {
1769  return this.currentAd;
1770};
1771
1772/**
1773 * Listener JSDoc for ESLint. This listener can be passed to
1774 * setAdBreakReadyListener.
1775 * @callback listener
1776 */
1777
1778/**
1779 * Sets the listener to be called to trigger manual ad break playback.
1780 * @param {listener} listener The listener to be called to trigger manual ad
1781 *     break playback.
1782 */
1783SdkImpl.prototype.setAdBreakReadyListener = function (listener) {
1784  this.adBreakReadyListener = listener;
1785};
1786
1787/**
1788 * @return {boolean} True if an ad is currently playing. False otherwise.
1789 */
1790SdkImpl.prototype.isAdPlaying = function () {
1791  return this.adPlaying;
1792};
1793
1794/**
1795 * @return {boolean} True if an ad is currently playing. False otherwise.
1796 */
1797SdkImpl.prototype.isAdMuted = function () {
1798  return this.adMuted;
1799};
1800
1801/**
1802 * Pause ads.
1803 */
1804SdkImpl.prototype.pauseAds = function () {
1805  this.adsManager.pause();
1806  this.adPlaying = false;
1807};
1808
1809/**
1810 * Resume ads.
1811 */
1812SdkImpl.prototype.resumeAds = function () {
1813  this.adsManager.resume();
1814  this.adPlaying = true;
1815};
1816
1817/**
1818 * Unmute ads.
1819 */
1820SdkImpl.prototype.unmute = function () {
1821  this.adsManager.setVolume(1);
1822  this.adMuted = false;
1823};
1824
1825/**
1826 * Mute ads.
1827 */
1828SdkImpl.prototype.mute = function () {
1829  this.adsManager.setVolume(0);
1830  this.adMuted = true;
1831};
1832
1833/**
1834 * Set the volume of the ads. 0-1.
1835 *
1836 * @param {number} volume The new volume.
1837 */
1838SdkImpl.prototype.setVolume = function (volume) {
1839  this.adsManager.setVolume(volume);
1840  if (volume == 0) {
1841    this.adMuted = true;
1842  } else {
1843    this.adMuted = false;
1844  }
1845};
1846
1847/**
1848 * Initializes the AdDisplayContainer. On mobile, this must be done as a
1849 * result of user action.
1850 */
1851SdkImpl.prototype.initializeAdDisplayContainer = function () {
1852  if (this.adDisplayContainer) {
1853    if (!this.adDisplayContainerInitialized) {
1854      this.adDisplayContainer.initialize();
1855      this.adDisplayContainerInitialized = true;
1856    }
1857  }
1858};
1859
1860/**
1861 * Called by publishers in manual ad break playback mode to start an ad
1862 * break.
1863 */
1864SdkImpl.prototype.playAdBreak = function () {
1865  if (!this.autoPlayAdBreaks) {
1866    this.controller.showAdContainer();
1867    // Sync ad volume with content volume.
1868    this.adsManager.setVolume(this.controller.getPlayerVolume());
1869    this.adsManager.start();
1870  }
1871};
1872
1873/**
1874 * Callback JSDoc for ESLint. This callback can be passed to addEventListener.
1875 * @callback callback
1876 */
1877
1878/**
1879 * Ads an EventListener to the AdsManager. For a list of available events,
1880 * see
1881 * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent#.Type
1882 * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to
1883 *     listen.
1884 * @param {callback} callback The method to call when the event is fired.
1885 */
1886SdkImpl.prototype.addEventListener = function (event, callback) {
1887  if (this.adsManager) {
1888    this.adsManager.addEventListener(event, callback);
1889  }
1890};
1891
1892/**
1893 * Returns the instance of the AdsManager.
1894 * @return {google.ima.AdsManager} The AdsManager being used by the plugin.
1895 */
1896SdkImpl.prototype.getAdsManager = function () {
1897  return this.adsManager;
1898};
1899
1900/**
1901 * Reset the SDK implementation.
1902 */
1903SdkImpl.prototype.reset = function () {
1904  this.adsActive = false;
1905  this.adPlaying = false;
1906  if (this.adTrackingTimer) {
1907    // If this is called while an ad is playing, stop trying to get that
1908    // ad's current time.
1909    clearInterval(this.adTrackingTimer);
1910  }
1911  if (this.adsManager) {
1912    this.adsManager.destroy();
1913    this.adsManager = null;
1914  }
1915  if (this.adsLoader && !this.contentCompleteCalled) {
1916    this.adsLoader.contentComplete();
1917  }
1918  this.contentCompleteCalled = false;
1919  this.allAdsCompleted = false;
1920};
1921
1922/**
1923 * Copyright 2017 Google Inc.
1924 *
1925 * Licensed under the Apache License, Version 2.0 (the "License");
1926 * you may not use this file except in compliance with the License.
1927 * You may obtain a copy of the License at
1928 *
1929 *     http://www.apache.org/licenses/LICENSE-2.0
1930 *
1931 * Unless required by applicable law or agreed to in writing, software
1932 * distributed under the License is distributed on an "AS IS" BASIS,
1933 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1934 * See the License for the specific language governing permissions and
1935 * limitations under the License.
1936 *
1937 * IMA SDK integration plugin for Video.js. For more information see
1938 * https://www.github.com/googleads/videojs-ima
1939 */
1940/**
1941 * The grand coordinator of the plugin. Facilitates communication between all
1942 * other plugin classes.
1943 *
1944 * @param {Object} player Instance of the video.js player.
1945 * @param {Object} options Options provided by the implementation.
1946 * @constructor
1947 * @struct
1948 * @final
1949 */
1950const Controller = function (player, options) {
1951  /**
1952   * Stores user-provided settings.
1953   * @type {Object}
1954   */
1955  this.settings = {};
1956
1957  /**
1958   * Content and ads ended listeners passed by the publisher to the plugin.
1959   * These will be called when the plugin detects that content *and all
1960   * ads* have completed. This differs from the contentEndedListeners in that
1961   * contentEndedListeners will fire between content ending and a post-roll
1962   * playing, whereas the contentAndAdsEndedListeners will fire after the
1963   * post-roll completes.
1964   */
1965  this.contentAndAdsEndedListeners = [];
1966
1967  /**
1968   * Whether or not we are running on a mobile platform.
1969   */
1970  this.isMobile = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/Android/i);
1971
1972  /**
1973   * Whether or not we are running on an iOS platform.
1974   */
1975  this.isIos = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i);
1976
1977  this.initWithSettings(options);
1978
1979  /**
1980   * Stores contrib-ads default settings.
1981   */
1982  const contribAdsDefaults = {
1983    debug: this.settings.debug,
1984    timeout: this.settings.timeout,
1985    prerollTimeout: this.settings.prerollTimeout
1986  };
1987  const adsPluginSettings = Object.assign({}, contribAdsDefaults, options.contribAdsSettings || {});
1988
1989  this.playerWrapper = new PlayerWrapper(player, adsPluginSettings, this);
1990  this.adUi = new AdUi(this);
1991  this.sdkImpl = new SdkImpl(this);
1992};
1993
1994Controller.IMA_DEFAULTS = {
1995  adLabel: 'Advertisement',
1996  adLabelNofN: 'of',
1997  debug: false,
1998  disableAdControls: false,
1999  prerollTimeout: 1000,
2000  preventLateAdStart: false,
2001  requestMode: 'onLoad',
2002  showControlsForJSAds: true,
2003  timeout: 5000
2004};
2005
2006/**
2007 * Extends the settings to include user-provided settings.
2008 *
2009 * @param {Object} options Options to be used in initialization.
2010 */
2011Controller.prototype.initWithSettings = function (options) {
2012  this.settings = Object.assign({}, Controller.IMA_DEFAULTS, options || {});
2013
2014  this.warnAboutDeprecatedSettings();
2015
2016  // Default showing countdown timer to true.
2017  this.showCountdown = true;
2018  if (this.settings.showCountdown === false) {
2019    this.showCountdown = false;
2020  }
2021};
2022
2023/**
2024 * Logs console warnings when deprecated settings are used.
2025 */
2026Controller.prototype.warnAboutDeprecatedSettings = function () {
2027  const deprecatedSettings = ['adWillAutoplay', 'adsWillAutoplay', 'adWillPlayMuted', 'adsWillPlayMuted'];
2028  deprecatedSettings.forEach(setting => {
2029    if (this.settings[setting] !== undefined) {
2030      console.warn('WARNING: videojs.ima setting ' + setting + ' is deprecated');
2031    }
2032  });
2033};
2034
2035/**
2036 * Return the settings object.
2037 *
2038 * @return {Object} The settings object.
2039 */
2040Controller.prototype.getSettings = function () {
2041  return this.settings;
2042};
2043
2044/**
2045 * Return whether or not we're in a mobile environment.
2046 *
2047 * @return {boolean} True if running on mobile, false otherwise.
2048 */
2049Controller.prototype.getIsMobile = function () {
2050  return this.isMobile;
2051};
2052
2053/**
2054 * Return whether or not we're in an iOS environment.
2055 *
2056 * @return {boolean} True if running on iOS, false otherwise.
2057 */
2058Controller.prototype.getIsIos = function () {
2059  return this.isIos;
2060};
2061
2062/**
2063 * Inject the ad container div into the DOM.
2064 *
2065 * @param{HTMLElement} adContainerDiv The ad container div.
2066 */
2067Controller.prototype.injectAdContainerDiv = function (adContainerDiv) {
2068  this.playerWrapper.injectAdContainerDiv(adContainerDiv);
2069};
2070
2071/**
2072 * @return {HTMLElement} The div for the ad container.
2073 */
2074Controller.prototype.getAdContainerDiv = function () {
2075  return this.adUi.getAdContainerDiv();
2076};
2077
2078/**
2079 * @return {Object} The content player.
2080 */
2081Controller.prototype.getContentPlayer = function () {
2082  return this.playerWrapper.getContentPlayer();
2083};
2084
2085/**
2086 * Returns the content playhead tracker.
2087 *
2088 * @return {Object} The content playhead tracker.
2089 */
2090Controller.prototype.getContentPlayheadTracker = function () {
2091  return this.playerWrapper.getContentPlayheadTracker();
2092};
2093
2094/**
2095 * Requests ads.
2096 */
2097Controller.prototype.requestAds = function () {
2098  this.sdkImpl.requestAds();
2099};
2100
2101/**
2102 * Add or modify a setting.
2103 *
2104 * @param {string} key Key to modify
2105 * @param {Object} value Value to set at key.
2106 */
2107Controller.prototype.setSetting = function (key, value) {
2108  this.settings[key] = value;
2109};
2110
2111/**
2112 * Called when there is an error loading ads.
2113 *
2114 * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.
2115 */
2116Controller.prototype.onErrorLoadingAds = function (adErrorEvent) {
2117  this.adUi.onAdError();
2118  this.playerWrapper.onAdError(adErrorEvent);
2119};
2120
2121/**
2122 * Called by the ad UI when the play/pause button is clicked.
2123 */
2124Controller.prototype.onAdPlayPauseClick = function () {
2125  if (this.sdkImpl.isAdPlaying()) {
2126    this.adUi.onAdsPaused();
2127    this.sdkImpl.pauseAds();
2128  } else {
2129    this.adUi.onAdsPlaying();
2130    this.sdkImpl.resumeAds();
2131  }
2132};
2133
2134/**
2135 * Called by the ad UI when the mute button is clicked.
2136 *
2137 */
2138Controller.prototype.onAdMuteClick = function () {
2139  if (this.sdkImpl.isAdMuted()) {
2140    this.playerWrapper.unmute();
2141    this.adUi.unmute();
2142    this.sdkImpl.unmute();
2143  } else {
2144    this.playerWrapper.mute();
2145    this.adUi.mute();
2146    this.sdkImpl.mute();
2147  }
2148};
2149
2150/**
2151 * Set the volume of the player and ads. 0-1.
2152 *
2153 * @param {number} volume The new volume.
2154 */
2155Controller.prototype.setVolume = function (volume) {
2156  this.playerWrapper.setVolume(volume);
2157  this.sdkImpl.setVolume(volume);
2158};
2159
2160/**
2161 * @return {number} The volume of the content player.
2162 */
2163Controller.prototype.getPlayerVolume = function () {
2164  return this.playerWrapper.getVolume();
2165};
2166
2167/**
2168 * Toggle fullscreen state.
2169 */
2170Controller.prototype.toggleFullscreen = function () {
2171  this.playerWrapper.toggleFullscreen();
2172};
2173
2174/**
2175 * Relays ad errors to the player wrapper.
2176 *
2177 * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.
2178 */
2179Controller.prototype.onAdError = function (adErrorEvent) {
2180  this.adUi.onAdError();
2181  this.playerWrapper.onAdError(adErrorEvent);
2182};
2183
2184/**
2185 * Handles ad break starting.
2186 *
2187 * @param {Object} adEvent The event fired by the IMA SDK.
2188 */
2189Controller.prototype.onAdBreakStart = function (adEvent) {
2190  this.playerWrapper.onAdBreakStart();
2191  this.adUi.onAdBreakStart(adEvent);
2192};
2193
2194/**
2195 * Show the ad container.
2196 */
2197Controller.prototype.showAdContainer = function () {
2198  this.adUi.showAdContainer();
2199};
2200
2201/**
2202 * Handles ad break ending.
2203 */
2204Controller.prototype.onAdBreakEnd = function () {
2205  this.playerWrapper.onAdBreakEnd();
2206  this.adUi.onAdBreakEnd();
2207};
2208
2209/**
2210 * Handles when all ads have finished playing.
2211 */
2212Controller.prototype.onAllAdsCompleted = function () {
2213  this.adUi.onAllAdsCompleted();
2214  this.playerWrapper.onAllAdsCompleted();
2215};
2216
2217/**
2218 * Handles the SDK firing an ad paused event.
2219 */
2220Controller.prototype.onAdsPaused = function () {
2221  this.adUi.onAdsPaused();
2222};
2223
2224/**
2225 * Handles the SDK firing an ad resumed event.
2226 */
2227Controller.prototype.onAdsResumed = function () {
2228  this.adUi.onAdsResumed();
2229};
2230
2231/**
2232 * Takes data from the sdk impl and passes it to the ad UI to update the UI.
2233 *
2234 * @param {number} currentTime Current time of the ad.
2235 * @param {number} remainingTime Remaining time of the ad.
2236 * @param {number} duration Duration of the ad.
2237 * @param {number} adPosition Index of the ad in the pod.
2238 * @param {number} totalAds Total number of ads in the pod.
2239 */
2240Controller.prototype.onAdPlayheadUpdated = function (currentTime, remainingTime, duration, adPosition, totalAds) {
2241  this.adUi.updateAdUi(currentTime, remainingTime, duration, adPosition, totalAds);
2242};
2243
2244/**
2245 * Handles ad log messages.
2246 * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the IMA SDK.
2247 */
2248Controller.prototype.onAdLog = function (adEvent) {
2249  this.playerWrapper.onAdLog(adEvent);
2250};
2251
2252/**
2253 * @return {Object} The current ad.
2254 */
2255Controller.prototype.getCurrentAd = function () {
2256  return this.sdkImpl.getCurrentAd();
2257};
2258
2259/**
2260 * Play content.
2261 */
2262Controller.prototype.playContent = function () {
2263  this.playerWrapper.play();
2264};
2265
2266/**
2267 * Handles when a linear ad starts.
2268 */
2269Controller.prototype.onLinearAdStart = function () {
2270  this.adUi.onLinearAdStart();
2271  this.playerWrapper.onAdStart();
2272};
2273
2274/**
2275 * Handles when a non-linear ad loads.
2276 */
2277Controller.prototype.onNonLinearAdLoad = function () {
2278  this.adUi.onNonLinearAdLoad();
2279};
2280
2281/**
2282 * Handles when a non-linear ad starts.
2283 */
2284Controller.prototype.onNonLinearAdStart = function () {
2285  this.adUi.onNonLinearAdLoad();
2286  this.playerWrapper.onAdStart();
2287};
2288
2289/**
2290 * Get the player width.
2291 *
2292 * @return {number} The width of the player.
2293 */
2294Controller.prototype.getPlayerWidth = function () {
2295  return this.playerWrapper.getPlayerWidth();
2296};
2297
2298/**
2299 * Get the player height.
2300 *
2301 * @return {number} The height of the player.
2302 */
2303Controller.prototype.getPlayerHeight = function () {
2304  return this.playerWrapper.getPlayerHeight();
2305};
2306
2307/**
2308 * Tells the player wrapper that ads are ready.
2309 */
2310Controller.prototype.onAdsReady = function () {
2311  this.playerWrapper.onAdsReady();
2312};
2313
2314/**
2315 * Called when the player wrapper detects that the player has been resized.
2316 *
2317 * @param {number} width The post-resize width of the player.
2318 * @param {number} height The post-resize height of the player.
2319 */
2320Controller.prototype.onPlayerResize = function (width, height) {
2321  this.sdkImpl.onPlayerResize(width, height);
2322};
2323
2324/**
2325 * Called by the player wrapper when content completes.
2326 */
2327Controller.prototype.onContentComplete = function () {
2328  this.sdkImpl.onContentComplete();
2329};
2330
2331/**
2332 * Called by the player wrapper when it's time to play a post-roll but we don't
2333 * have one to play.
2334 */
2335Controller.prototype.onNoPostroll = function () {
2336  this.playerWrapper.onNoPostroll();
2337};
2338
2339/**
2340 * Called when content and all ads have completed.
2341 */
2342Controller.prototype.onContentAndAdsCompleted = function () {
2343  for (let index in this.contentAndAdsEndedListeners) {
2344    if (typeof this.contentAndAdsEndedListeners[index] === 'function') {
2345      this.contentAndAdsEndedListeners[index]();
2346    }
2347  }
2348};
2349
2350/**
2351 * Called when the player is disposed.
2352 */
2353Controller.prototype.onPlayerDisposed = function () {
2354  this.contentAndAdsEndedListeners = [];
2355  this.sdkImpl.onPlayerDisposed();
2356};
2357
2358/**
2359 * Called when the player is ready to play a pre-roll.
2360 */
2361Controller.prototype.onPlayerReadyForPreroll = function () {
2362  this.sdkImpl.onPlayerReadyForPreroll();
2363};
2364
2365/**
2366 * Called if the ad times out.
2367 */
2368Controller.prototype.onAdTimeout = function () {
2369  this.sdkImpl.onAdTimeout();
2370};
2371
2372/**
2373 * Called when the player is ready.
2374 */
2375Controller.prototype.onPlayerReady = function () {
2376  this.sdkImpl.onPlayerReady();
2377};
2378
2379/**
2380 * Called when the player enters fullscreen.
2381 */
2382Controller.prototype.onPlayerEnterFullscreen = function () {
2383  this.adUi.onPlayerEnterFullscreen();
2384  this.sdkImpl.onPlayerEnterFullscreen();
2385};
2386
2387/**
2388 * Called when the player exits fullscreen.
2389 */
2390Controller.prototype.onPlayerExitFullscreen = function () {
2391  this.adUi.onPlayerExitFullscreen();
2392  this.sdkImpl.onPlayerExitFullscreen();
2393};
2394
2395/**
2396 * Called when the player volume changes.
2397 *
2398 * @param {number} volume The new player volume.
2399 */
2400Controller.prototype.onPlayerVolumeChanged = function (volume) {
2401  this.adUi.onPlayerVolumeChanged(volume);
2402  this.sdkImpl.onPlayerVolumeChanged(volume);
2403};
2404
2405/**
2406 * Sets the content of the video player. You should use this method instead
2407 * of setting the content src directly to ensure the proper ad tag is
2408 * requested when the video content is loaded.
2409 * @param {?string} contentSrc The URI for the content to be played. Leave
2410 *     blank to use the existing content.
2411 * @param {?string} adTag The ad tag to be requested when the content loads.
2412 *     Leave blank to use the existing ad tag.
2413 */
2414Controller.prototype.setContentWithAdTag = function (contentSrc, adTag) {
2415  this.reset();
2416  this.settings.adTagUrl = adTag ? adTag : this.settings.adTagUrl;
2417  this.playerWrapper.changeSource(contentSrc);
2418};
2419
2420/**
2421 * Sets the content of the video player. You should use this method instead
2422 * of setting the content src directly to ensure the proper ads response is
2423 * used when the video content is loaded.
2424 * @param {?string} contentSrc The URI for the content to be played. Leave
2425 *     blank to use the existing content.
2426 * @param {?string} adsResponse The ads response to be requested when the
2427 *     content loads. Leave blank to use the existing ads response.
2428 */
2429Controller.prototype.setContentWithAdsResponse = function (contentSrc, adsResponse) {
2430  this.reset();
2431  this.settings.adsResponse = adsResponse ? adsResponse : this.settings.adsResponse;
2432  this.playerWrapper.changeSource(contentSrc);
2433};
2434
2435/**
2436 * Sets the content of the video player. You should use this method instead
2437 * of setting the content src directly to ensure the proper ads request is
2438 * used when the video content is loaded.
2439 * @param {?string} contentSrc The URI for the content to be played. Leave
2440 *     blank to use the existing content.
2441 * @param {?Object} adsRequest The ads request to be requested when the
2442 *     content loads. Leave blank to use the existing ads request.
2443 */
2444Controller.prototype.setContentWithAdsRequest = function (contentSrc, adsRequest) {
2445  this.reset();
2446  this.settings.adsRequest = adsRequest ? adsRequest : this.settings.adsRequest;
2447  this.playerWrapper.changeSource(contentSrc);
2448};
2449
2450/**
2451 * Resets the state of the plugin.
2452 */
2453Controller.prototype.reset = function () {
2454  this.sdkImpl.reset();
2455  this.playerWrapper.reset();
2456  this.adUi.reset();
2457};
2458
2459/**
2460 * Listener JSDoc for ESLint. This listener can be passed to
2461 * (add|remove)ContentEndedListener.
2462 * @callback listener
2463 */
2464
2465/**
2466 * Adds a listener for the 'contentended' event of the video player. This should
2467 * be used instead of setting an 'contentended' listener directly to ensure that
2468 * the ima can do proper cleanup of the SDK before other event listeners are
2469 * called.
2470 * @param {listener} listener The listener to be called when content
2471 *     completes.
2472 */
2473Controller.prototype.addContentEndedListener = function (listener) {
2474  this.playerWrapper.addContentEndedListener(listener);
2475};
2476
2477/**
2478 * Adds a listener that will be called when content and all ads have
2479 * finished playing.
2480 * @param {listener} listener The listener to be called when content and ads
2481 *     complete.
2482 */
2483Controller.prototype.addContentAndAdsEndedListener = function (listener) {
2484  this.contentAndAdsEndedListeners.push(listener);
2485};
2486
2487/**
2488 * Sets the listener to be called to trigger manual ad break playback.
2489 * @param {listener} listener The listener to be called to trigger manual ad
2490 *     break playback.
2491 */
2492Controller.prototype.setAdBreakReadyListener = function (listener) {
2493  this.sdkImpl.setAdBreakReadyListener(listener);
2494};
2495
2496/**
2497 * Changes the flag to show or hide the ad countdown timer.
2498 *
2499 * @param {boolean} showCountdownIn Show or hide the countdown timer.
2500 */
2501Controller.prototype.setShowCountdown = function (showCountdownIn) {
2502  this.adUi.setShowCountdown(showCountdownIn);
2503  this.showCountdown = showCountdownIn;
2504  this.adUi.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';
2505};
2506
2507/**
2508 * Initializes the AdDisplayContainer. On mobile, this must be done as a
2509 * result of user action.
2510 */
2511Controller.prototype.initializeAdDisplayContainer = function () {
2512  this.sdkImpl.initializeAdDisplayContainer();
2513};
2514
2515/**
2516 * Called by publishers in manual ad break playback mode to start an ad
2517 * break.
2518 */
2519Controller.prototype.playAdBreak = function () {
2520  this.sdkImpl.playAdBreak();
2521};
2522
2523/**
2524 * Callback JSDoc for ESLint. This callback can be passed to addEventListener.
2525 * @callback callback
2526 */
2527
2528/**
2529 * Ads an EventListener to the AdsManager. For a list of available events,
2530 * see
2531 * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent#.Type
2532 * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to
2533 *     listen.
2534 * @param {callback} callback The method to call when the event is fired.
2535 */
2536Controller.prototype.addEventListener = function (event, callback) {
2537  this.sdkImpl.addEventListener(event, callback);
2538};
2539
2540/**
2541 * Returns the instance of the AdsManager.
2542 * @return {google.ima.AdsManager} The AdsManager being used by the plugin.
2543 */
2544Controller.prototype.getAdsManager = function () {
2545  return this.sdkImpl.getAdsManager();
2546};
2547
2548/**
2549 * Returns the instance of the player id.
2550 * @return {string} The player id.
2551 */
2552Controller.prototype.getPlayerId = function () {
2553  return this.playerWrapper.getPlayerId();
2554};
2555
2556/**
2557 * Changes the ad tag. You will need to call requestAds after this method
2558 * for the new ads to be requested.
2559 * @param {?string} adTag The ad tag to be requested the next time
2560 *     requestAds is called.
2561 */
2562Controller.prototype.changeAdTag = function (adTag) {
2563  this.reset();
2564  this.settings.adTagUrl = adTag;
2565};
2566
2567/**
2568 * Pauses the ad.
2569 */
2570Controller.prototype.pauseAd = function () {
2571  this.adUi.onAdsPaused();
2572  this.sdkImpl.pauseAds();
2573};
2574
2575/**
2576 * Resumes the ad.
2577 */
2578Controller.prototype.resumeAd = function () {
2579  this.adUi.onAdsPlaying();
2580  this.sdkImpl.resumeAds();
2581};
2582
2583/**
2584 * Toggles video/ad playback.
2585 */
2586Controller.prototype.togglePlayback = function () {
2587  this.playerWrapper.togglePlayback();
2588};
2589
2590/**
2591 * @return {boolean} true if we expect that ads will autoplay. false otherwise.
2592 */
2593Controller.prototype.adsWillAutoplay = function () {
2594  if (this.settings.adsWillAutoplay !== undefined) {
2595    return this.settings.adsWillAutoplay;
2596  } else if (this.settings.adWillAutoplay !== undefined) {
2597    return this.settings.adWillAutoplay;
2598  } else {
2599    return !!this.playerWrapper.getPlayerOptions().autoplay;
2600  }
2601};
2602
2603/**
2604 * @return {boolean} true if we expect that ads will autoplay. false otherwise.
2605 */
2606Controller.prototype.adsWillPlayMuted = function () {
2607  if (this.settings.adsWillPlayMuted !== undefined) {
2608    return this.settings.adsWillPlayMuted;
2609  } else if (this.settings.adWillPlayMuted !== undefined) {
2610    return this.settings.adWillPlayMuted;
2611  } else if (this.playerWrapper.getPlayerOptions().muted !== undefined) {
2612    return this.playerWrapper.getPlayerOptions().muted;
2613  } else {
2614    return this.playerWrapper.getVolume() == 0;
2615  }
2616};
2617
2618/**
2619 * Triggers an event on the VJS player
2620 * @param  {string} name The event name.
2621 * @param  {Object} data The event data.
2622 */
2623Controller.prototype.triggerPlayerEvent = function (name, data) {
2624  this.playerWrapper.triggerPlayerEvent(name, data);
2625};
2626
2627/**
2628 * Copyright 2021 Google Inc.
2629 *
2630 * Licensed under the Apache License, Version 2.0 (the "License");
2631 * you may not use this file except in compliance with the License.
2632 * You may obtain a copy of the License at
2633 *
2634 *     http://www.apache.org/licenses/LICENSE-2.0
2635 *
2636 * Unless required by applicable law or agreed to in writing, software
2637 * distributed under the License is distributed on an "AS IS" BASIS,
2638 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2639 * See the License for the specific language governing permissions and
2640 * limitations under the License.
2641 *
2642 * IMA SDK integration plugin for Video.js. For more information see
2643 * https://www.github.com/googleads/videojs-ima
2644 */
2645
2646/**
2647 * Wraps the video.js stream player for the plugin.
2648 *
2649 * @param {!Object} player Video.js player instance.
2650 * @param {!Object} adsPluginSettings Settings for the contrib-ads plugin.
2651 * @param {!DaiController} daiController Reference to the parent controller.
2652 */
2653const PlayerWrapper$2 = function (player, adsPluginSettings, daiController) {
2654  /**
2655   * Instance of the video.js player.
2656   */
2657  this.vjsPlayer = player;
2658
2659  /**
2660   * Plugin DAI controller.
2661   */
2662  this.daiController = daiController;
2663
2664  /**
2665   * Video.js control bar.
2666   */
2667  this.vjsControls = this.vjsPlayer.getChild('controlBar');
2668
2669  /**
2670   * Vanilla HTML5 video player underneath the video.js player.
2671   */
2672  this.h5Player = null;
2673
2674  this.vjsPlayer.on('dispose', this.playerDisposedListener.bind(this));
2675  this.vjsPlayer.on('pause', this.onPause.bind(this));
2676  this.vjsPlayer.on('play', this.onPlay.bind(this));
2677  this.vjsPlayer.on('seeked', this.onSeekEnd.bind(this));
2678  this.vjsPlayer.ready(this.onPlayerReady.bind(this));
2679  this.vjsPlayer.ads(adsPluginSettings);
2680};
2681
2682/**
2683 * Called in response to the video.js player's 'disposed' event.
2684 */
2685PlayerWrapper$2.prototype.playerDisposedListener = function () {
2686  this.contentEndedListeners = [];
2687  this.daiController.onPlayerDisposed();
2688};
2689
2690/**
2691 * Called on the player 'pause' event. Handles displaying controls during
2692 * paused ad breaks.
2693 */
2694PlayerWrapper$2.prototype.onPause = function () {
2695  // This code will run if the stream is paused during an ad break. Since
2696  // controls are usually hidden during ads, they will now show to allow
2697  // users to resume ad playback.
2698  if (this.daiController.isInAdBreak()) {
2699    this.vjsControls.show();
2700  }
2701};
2702
2703/**
2704 * Called on the player 'play' event. Handles hiding controls during
2705 * ad breaks while playing.
2706 */
2707PlayerWrapper$2.prototype.onPlay = function () {
2708  if (this.daiController.isInAdBreak()) {
2709    this.vjsControls.hide();
2710  }
2711};
2712
2713/**
2714 * Called on the player's 'seeked' event. Sets up handling for ad break
2715 * snapback for VOD streams.
2716 */
2717PlayerWrapper$2.prototype.onSeekEnd = function () {
2718  this.daiController.onSeekEnd(this.vjsPlayer.currentTime());
2719};
2720
2721/**
2722 * Called on the player's 'ready' event to begin initiating IMA.
2723 */
2724PlayerWrapper$2.prototype.onPlayerReady = function () {
2725  this.h5Player = document.getElementById(this.getPlayerId()).getElementsByClassName('vjs-tech')[0];
2726  this.daiController.onPlayerReady();
2727};
2728
2729/**
2730 * @return {!Object} The stream player.
2731 */
2732PlayerWrapper$2.prototype.getStreamPlayer = function () {
2733  return this.h5Player;
2734};
2735
2736/**
2737 * @return {!Object} The video.js player.
2738 */
2739PlayerWrapper$2.prototype.getVjsPlayer = function () {
2740  return this.vjsPlayer;
2741};
2742
2743/**
2744 * @return {!Object} The vjs player's options object.
2745 */
2746PlayerWrapper$2.prototype.getPlayerOptions = function () {
2747  return this.vjsPlayer.options_;
2748};
2749
2750/**
2751 * Returns the instance of the player id.
2752 * @return {string} The player id.
2753 */
2754PlayerWrapper$2.prototype.getPlayerId = function () {
2755  return this.vjsPlayer.id();
2756};
2757
2758/**
2759 * Handles ad errors.
2760 *
2761 * @param {!Object} adErrorEvent The ad error event thrown by the IMA SDK.
2762 */
2763PlayerWrapper$2.prototype.onAdError = function (adErrorEvent) {
2764  this.vjsControls.show();
2765  const errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;
2766  this.vjsPlayer.trigger({ type: 'adserror', data: {
2767      AdError: errorMessage,
2768      AdErrorEvent: adErrorEvent
2769    } });
2770};
2771
2772/**
2773 * Handles ad break starting.
2774 */
2775PlayerWrapper$2.prototype.onAdBreakStart = function () {
2776  this.vjsControls.hide();
2777};
2778
2779/**
2780 * Handles ad break ending.
2781 */
2782PlayerWrapper$2.prototype.onAdBreakEnd = function () {
2783  this.vjsControls.show();
2784};
2785
2786/**
2787 * Reset the player.
2788 */
2789PlayerWrapper$2.prototype.reset = function () {
2790  this.vjsControls.show();
2791};
2792
2793/**
2794 * Copyright 2021 Google Inc.
2795 *
2796 * Licensed under the Apache License, Version 2.0 (the "License");
2797 * you may not use this file except in compliance with the License.
2798 * You may obtain a copy of the License at
2799 *
2800 *     http://www.apache.org/licenses/LICENSE-2.0
2801 *
2802 * Unless required by applicable law or agreed to in writing, software
2803 * distributed under the License is distributed on an "AS IS" BASIS,
2804 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2805 * See the License for the specific language governing permissions and
2806 * limitations under the License.
2807 *
2808 * IMA SDK integration plugin for Video.js. For more information see
2809 * https://www.github.com/googleads/videojs-ima
2810 */
2811
2812/**
2813 * Implementation of the IMA DAI SDK for the plugin.
2814 *
2815 * @param {DaiController!} daiController Reference to the parent DAI
2816 * controller.
2817 *
2818 * @constructor
2819 * @struct
2820 * @final
2821 */
2822const SdkImpl$2 = function (daiController) {
2823  /**
2824   * Plugin DAI controller.
2825   */
2826  this.daiController = daiController;
2827
2828  /**
2829   * The html5 stream player.
2830   */
2831  this.streamPlayer = null;
2832
2833  /**
2834   * The videoJS stream player.
2835   */
2836  this.vjsPlayer = null;
2837
2838  /**
2839   * IMA SDK StreamManager
2840   */
2841  this.streamManager = null;
2842
2843  /**
2844   * IMA stream UI settings.
2845   */
2846  /* eslint no-undef: 'error' */
2847  /* global google */
2848  this.uiSettings = new google.ima.dai.api.UiSettings();
2849
2850  /**
2851   * If the stream is currently in an ad break.
2852   */
2853  this.isAdBreak = false;
2854
2855  /**
2856   * If the stream is currently seeking from a snapback.
2857   */
2858  this.isSnapback = false;
2859
2860  /**
2861   * Originally seeked to time, to return stream to after ads.
2862   */
2863  this.snapForwardTime = 0;
2864
2865  /**
2866   * Timed metadata for the stream.
2867   */
2868  this.timedMetadata;
2869
2870  /**
2871   * Timed metadata record.
2872   */
2873  this.metadataLoaded = {};
2874
2875  this.SOURCE_TYPES = {
2876    hls: 'application/x-mpegURL',
2877    dash: 'application/dash+xml'
2878  };
2879};
2880
2881/**
2882 * Creates and initializes the IMA DAI SDK objects.
2883 */
2884SdkImpl$2.prototype.initImaDai = function () {
2885  this.streamPlayer = this.daiController.getStreamPlayer();
2886  this.vjsPlayer = this.daiController.getVjsPlayer();
2887
2888  this.createAdUiDiv();
2889  if (this.daiController.getSettings().locale) {
2890    this.uiSettings.setLocale(this.daiController.getSettings().locale);
2891  }
2892
2893  this.streamManager = new google.ima.dai.api.StreamManager(this.streamPlayer, this.adUiDiv, this.uiSettings);
2894
2895  this.streamPlayer.addEventListener('pause', this.onStreamPause);
2896  this.streamPlayer.addEventListener('play', this.onStreamPlay);
2897
2898  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);
2899
2900  this.vjsPlayer.textTracks().onaddtrack = this.onAddTrack.bind(this);
2901
2902  this.vjsPlayer.trigger({
2903    type: 'stream-manager',
2904    StreamManager: this.streamManager
2905  });
2906
2907  this.requestStream();
2908};
2909
2910/**
2911 * Called when the video player has metadata to process.
2912 * @param {Event!} event The event that triggered this call.
2913 */
2914SdkImpl$2.prototype.onAddTrack = function (event) {
2915  const track = event.track;
2916  if (track.kind === 'metadata') {
2917    track.mode = 'hidden';
2918    track.oncuechange = e => {
2919      for (const cue of track.activeCues_) {
2920        const metadata = {};
2921        metadata[cue.value.key] = cue.value.data;
2922        this.streamManager.onTimedMetadata(metadata);
2923      }
2924    };
2925  }
2926};
2927
2928/**
2929 * Creates the ad UI container.
2930 */
2931SdkImpl$2.prototype.createAdUiDiv = function () {
2932  const uiDiv = document.createElement('div');
2933  uiDiv.id = 'ad-ui';
2934  // 3em is the height of the control bar.
2935  uiDiv.style.height = 'calc(100% - 3em)';
2936  this.streamPlayer.parentNode.appendChild(uiDiv);
2937  this.adUiDiv = uiDiv;
2938};
2939
2940/**
2941 * Called on pause to update the ad UI.
2942 */
2943SdkImpl$2.prototype.onStreamPause = function () {
2944  if (this.isAdBreak) {
2945    this.adUiDiv.style.display = 'none';
2946  }
2947};
2948
2949/**
2950 * Called on play to update the ad UI.
2951 */
2952SdkImpl$2.prototype.onStreamPlay = function () {
2953  if (this.isAdBreak) {
2954    this.adUiDiv.style.display = 'block';
2955  }
2956};
2957
2958/**
2959 * Called on play to update the ad UI.
2960 * @param {number} currentTime the current time of the stream.
2961 */
2962SdkImpl$2.prototype.onSeekEnd = function (currentTime) {
2963  const streamType = this.daiController.getSettings().streamType;
2964  if (streamType === 'live') {
2965    return;
2966  }
2967  if (this.isSnapback) {
2968    this.isSnapback = false;
vendor: 5,234 bytes, lines 2969-3128
2969    return;
2970  }
2971  const previousCuePoint = this.streamManager.previousCuePointForStreamTime(currentTime);
2972  if (previousCuePoint && !previousCuePoint.played) {
2973    this.isSnapback = true;
2974    this.snapForwardTime = currentTime;
2975    this.vjsPlayer.currentTime(previousCuePoint.start);
2976  }
2977};
2978
2979/**
2980 * Handles IMA events.
2981 * @param {google.ima.StreamEvent!} event the IMA event
2982 */
2983SdkImpl$2.prototype.onStreamEvent = function (event) {
2984  switch (event.type) {
2985    case google.ima.dai.api.StreamEvent.Type.LOADED:
2986      this.loadUrl(event.getStreamData().url);
2987      break;
2988    case google.ima.dai.api.StreamEvent.Type.ERROR:
2989      window.console.warn('Error loading stream, attempting to play backup ' + 'stream. ' + event.getStreamData().errorMessage);
2990      this.daiController.onErrorLoadingAds(event);
2991      if (this.daiController.getSettings().fallbackStreamUrl) {
2992        this.loadurl(this.daiController.getSettings().fallbackStreamUrl);
2993      }
2994      break;
2995    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:
2996      this.isAdBreak = true;
2997      this.adUiDiv.style.display = 'block';
2998      this.daiController.onAdBreakStart();
2999      break;
3000    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:
3001      this.isAdBreak = false;
3002      this.adUiDiv.style.display = 'none';
3003      this.daiController.onAdBreakEnd();
3004      if (this.snapForwardTime && this.snapForwardTime > this.vjsPlayer.currentTime()) {
3005        this.vjsPlayer.currentTime(this.snapForwardTime);
3006        this.snapForwardTime = 0;
3007      }
3008      break;
3009    default:
3010      break;
3011  }
3012};
3013
3014/**
3015 * Loads the stream URL .
3016 * @param {string} streamUrl the URL for the stream being loaded.
3017 */
3018SdkImpl$2.prototype.loadUrl = function (streamUrl) {
3019  this.vjsPlayer.ready(function () {
3020    const streamFormat = this.daiController.getSettings().streamFormat;
3021    this.vjsPlayer.src({
3022      src: streamUrl,
3023      type: this.SOURCE_TYPES[streamFormat]
3024    });
3025
3026    const bookmarkTime = this.daiController.getSettings().bookmarkTime;
3027    if (bookmarkTime) {
3028      const startTime = this.streamManager.streamTimeForContentTime(bookmarkTime);
3029      // Seeking on load triggers the onSeekEnd event, so treat this seek as
3030      // if it's snapback. Without this, resuming at a bookmark kicks you
3031      // back to the ad before the bookmark.
3032      this.isSnapback = true;
3033      this.vjsPlayer.currentTime(startTime);
3034    }
3035  }.bind(this));
3036};
3037
3038/**
3039 * Creates the AdsRequest and request ads through the AdsLoader.
3040 */
3041SdkImpl$2.prototype.requestStream = function () {
3042  let streamRequest;
3043  const streamType = this.daiController.getSettings().streamType;
3044  if (streamType === 'vod') {
3045    streamRequest = new google.ima.dai.api.VODStreamRequest();
3046    streamRequest.contentSourceId = this.daiController.getSettings().cmsId;
3047    streamRequest.videoId = this.daiController.getSettings().videoId;
3048  } else if (streamType === 'live') {
3049    streamRequest = new google.ima.dai.api.LiveStreamRequest();
3050    streamRequest.assetKey = this.daiController.getSettings().assetKey;
3051  } else {
3052    window.console.warn('No valid stream type selected');
3053  }
3054  streamRequest.format = this.daiController.getSettings().streamFormat;
3055
3056  if (this.daiController.getSettings().apiKey) {
3057    streamRequest.apiKey = this.daiController.getSettings().apiKey;
3058  }
3059  if (this.daiController.getSettings().authKey) {
3060    streamRequest.authKey = this.daiController.getSettings().authKey;
3061  }
3062  if (this.daiController.getSettings().adTagParameters) {
3063    streamRequest.adTagParameters = this.daiController.getSettings().adTagParameters;
3064  }
3065  if (this.daiController.getSettings().streamActivityMonitorId) {
3066    streamRequest.streamActivityMonitorId = this.daiController.getSettings().streamActivityMonitorId;
3067  }
3068
3069  if (this.daiController.getSettings().omidMode) {
3070    streamRequest.omidAccessModeRules = {};
3071    const omidValues = this.daiController.getSettings().omidMode;
3072
3073    if (omidValues.FULL) {
3074      streamRequest.omidAccessModeRules[google.ima.OmidAccessMode.FULL] = omidValues.FULL;
3075    }
3076    if (omidValues.DOMAIN) {
3077      streamRequest.omidAccessModeRules[google.ima.OmidAccessMode.DOMAIN] = omidValues.DOMAIN;
3078    }
3079    if (omidValues.LIMITED) {
3080      streamRequest.omidAccessModeRules[google.ima.OmidAccessMode.LIMITED] = omidValues.LIMITED;
3081    }
3082  }
3083
3084  this.streamManager.requestStream(streamRequest);
3085  this.vjsPlayer.trigger({
3086    type: 'stream-request',
3087    StreamRequest: streamRequest
3088  });
3089};
3090
3091/**
3092 * Initiates IMA when the player is ready.
3093 */
3094SdkImpl$2.prototype.onPlayerReady = function () {
3095  this.initImaDai();
3096};
3097
3098/**
3099 * Reset the StreamManager when the player is disposed.
3100 */
3101SdkImpl$2.prototype.onPlayerDisposed = function () {
3102  if (this.streamManager) {
3103    this.streamManager.reset();
3104  }
3105};
3106
3107/**
3108 * Returns the instance of the StreamManager.
3109 * @return {google.ima.StreamManager!} The StreamManager being used by the
3110 * plugin.
3111 */
3112SdkImpl$2.prototype.getStreamManager = function () {
3113  return this.StreamManager;
3114};
3115
3116/**
3117 * Reset the SDK implementation.
3118 */
3119SdkImpl$2.prototype.reset = function () {
3120  if (this.StreamManager) {
3121    this.StreamManager.reset();
3122  }
3123};
3124
3125/**
3126 * Copyright 2021 Google Inc.
3127 *
3128 * Licensed under the Apache License, Version 2.0 (the "License");
3129 * you may not use this file except in compliance with the License.
3130 * You may obtain a copy of the License at
3131 *
3132 *     http://www.apache.org/licenses/LICENSE-2.0
3133 *
3134 * Unless required by applicable law or agreed to in writing, software
3135 * distributed under the License is distributed on an "AS IS" BASIS,
3136 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3137 * See the License for the specific language governing permissions and
3138 * limitations under the License.
3139 *
3140 * IMA SDK integration plugin for Video.js. For more information see
3141 * https://www.github.com/googleads/videojs-ima
3142 */
3143/**
3144 * The coordinator for the DAI portion of the plugin. Facilitates
3145 * communication between all other plugin classes.
3146 *
3147 * @param {Object!} player Instance of the video.js player.
3148 * @param {Object!} options Options provided by the implementation.
3149 * @constructor
3150 * @struct
3151 * @final
3152 */
3153const DaiController = function (player, options) {
3154  /**
3155  * If the stream is currently in an ad break.
3156  * @type {boolean}
3157  */
3158  this.inAdBreak = false;
3159
3160  /**
3161  * Stores user-provided settings.
3162  * @type {Object!}
3163  */
3164  this.settings = {};
3165
3166  /**
3167  * Whether or not we are running on a mobile platform.
3168  */
3169  this.isMobile = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/Android/i);
3170
3171  /**
3172  * Whether or not we are running on an iOS platform.
3173  */
3174  this.isIos = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i);
3175
3176  this.initWithSettings(options);
3177
3178  /**
3179  * Stores contrib-ads default settings.
3180  */
3181  const contribAdsDefaults = {
3182    debug: this.settings.debug,
3183    timeout: this.settings.timeout,
3184    prerollTimeout: this.settings.prerollTimeout
3185  };
3186  const adsPluginSettings = Object.assign({}, contribAdsDefaults, options.contribAdsSettings || {});
3187
3188  this.playerWrapper = new PlayerWrapper$2(player, adsPluginSettings, this);
3189  this.sdkImpl = new SdkImpl$2(this);
3190};
3191
3192DaiController.IMA_DEFAULTS = {
3193  adLabel: 'Advertisement',
3194  adLabelNofN: 'of',
3195  debug: false,
3196  disableAdControls: false,
3197  showControlsForJSAds: true
3198};
3199
3200/**
3201 * Extends the settings to include user-provided settings.
3202 *
3203 * @param {Object!} options Options to be used in initialization.
3204 */
3205DaiController.prototype.initWithSettings = function (options) {
3206  this.settings = Object.assign({}, DaiController.IMA_DEFAULTS, options || {});
3207
3208  this.warnAboutDeprecatedSettings();
3209
3210  // Default showing countdown timer to true.
3211  this.showCountdown = true;
3212  if (this.settings.showCountdown === false) {
3213    this.showCountdown = false;
3214  }
3215};
3216
3217/**
3218 * Logs console warnings when deprecated settings are used.
3219 */
3220DaiController.prototype.warnAboutDeprecatedSettings = function () {
3221  const deprecatedSettings = [
3222    // Currently no DAI plugin settings are deprecated.
3223  ];
3224  deprecatedSettings.forEach(setting => {
3225    if (this.settings[setting] !== undefined) {
3226      console.warn('WARNING: videojs.imaDai setting ' + setting + ' is deprecated');
3227    }
3228  });
3229};
3230
3231/**
3232 * Return the settings object.
3233 *
3234 * @return {Object!} The settings object.
3235 */
3236DaiController.prototype.getSettings = function () {
3237  return this.settings;
3238};
3239
3240/**
3241 * Return whether or not we're in a mobile environment.
3242 *
3243 * @return {boolean} True if running on mobile, false otherwise.
3244 */
3245DaiController.prototype.getIsMobile = function () {
3246  return this.isMobile;
3247};
3248
3249/**
3250 * Return whether or not we're in an iOS environment.
3251 *
3252 * @return {boolean} True if running on iOS, false otherwise.
3253 */
3254DaiController.prototype.getIsIos = function () {
3255  return this.isIos;
3256};
3257
3258/**
3259 * @return {Object!} The html5 player.
3260 */
3261DaiController.prototype.getStreamPlayer = function () {
3262  return this.playerWrapper.getStreamPlayer();
3263};
3264
3265/**
3266 * @return {Object!} The video.js player.
3267 */
3268DaiController.prototype.getVjsPlayer = function () {
3269  return this.playerWrapper.getVjsPlayer();
3270};
3271
3272/**
3273 * Requests the stream.
3274 */
3275DaiController.prototype.requestStream = function () {
3276  this.sdkImpl.requestStream();
3277};
3278
3279/**
3280 * Add or modify a setting.
3281 *
3282 * @param {string} key Key to modify
3283 * @param {Object!} value Value to set at key.
3284*/
3285DaiController.prototype.setSetting = function (key, value) {
3286  this.settings[key] = value;
3287};
3288
3289/**
3290 * Called when there is an error loading ads.
3291 *
3292 * @param {Object!} adErrorEvent The ad error event thrown by the IMA SDK.
3293 */
3294DaiController.prototype.onErrorLoadingAds = function (adErrorEvent) {
3295  this.playerWrapper.onAdError(adErrorEvent);
3296};
3297
3298/**
3299 * Relays ad errors to the player wrapper.
3300 *
3301 * @param {Object!} adErrorEvent The ad error event thrown by the IMA SDK.
3302 */
3303DaiController.prototype.onAdError = function (adErrorEvent) {
3304  this.playerWrapper.onAdError(adErrorEvent);
3305};
3306
3307/**
3308 * Signals player that an ad break has started.
3309 */
3310DaiController.prototype.onAdBreakStart = function () {
3311  this.inAdBreak = true;
3312  this.playerWrapper.onAdBreakStart();
3313};
3314
3315/**
3316 * Signals player that an ad break has ended.
3317 */
3318DaiController.prototype.onAdBreakEnd = function () {
3319  this.inAdBreak = false;
vendor: 10,215 bytes, lines 3320-3639
3320  this.playerWrapper.onAdBreakEnd();
3321};
3322
3323/**
3324 * Called when the player is disposed.
3325 */
3326DaiController.prototype.onPlayerDisposed = function () {
3327  this.contentAndAdsEndedListeners = [];
3328  this.sdkImpl.onPlayerDisposed();
3329};
3330
3331/**
3332 * Returns if the stream is currently in an ad break.
3333 * @return {boolean} If the stream is currently in an ad break.
3334 */
3335DaiController.prototype.isInAdBreak = function () {
3336  return this.inAdBreak;
3337};
3338
3339/**
3340 * Called on seek end to check for ad snapback.
3341 * @param {number} currentTime the current time of the stream.
3342 */
3343DaiController.prototype.onSeekEnd = function (currentTime) {
3344  this.sdkImpl.onSeekEnd(currentTime);
3345};
3346
3347/**
3348 * Called when the player is ready.
3349 */
3350DaiController.prototype.onPlayerReady = function () {
3351  this.sdkImpl.onPlayerReady();
3352};
3353
3354/**
3355 * Resets the state of the plugin.
3356 */
3357DaiController.prototype.reset = function () {
3358  this.sdkImpl.reset();
3359  this.playerWrapper.reset();
3360};
3361
3362/**
3363 * Adds an EventListener to the StreamManager. For a list of available events,
3364 * see
3365 * https://developers.google.com/interactive-media-ads/docs/sdks/html5/dai/reference/js/StreamEvent
3366 * @param {google.ima.StreamEvent.Type!} event The AdEvent.Type for which to
3367 *     listen.
3368 * @param {callback!} callback The method to call when the event is fired.
3369 */
3370DaiController.prototype.addEventListener = function (event, callback) {
3371  this.sdkImpl.addEventListener(event, callback);
3372};
3373
3374/**
3375 * Returns the instance of the StreamManager.
3376 * @return {google.ima.StreamManager!} The StreamManager being used by the
3377 * plugin.
3378 */
3379DaiController.prototype.getStreamManager = function () {
3380  return this.sdkImpl.getStreamManager();
3381};
3382
3383/**
3384 * Returns the instance of the player id.
3385 * @return {string} The player id.
3386 */
3387DaiController.prototype.getPlayerId = function () {
3388  return this.playerWrapper.getPlayerId();
3389};
3390
3391/**
3392 * @return {boolean} true if we expect that the stream will autoplay. false
3393 * otherwise.
3394 */
3395DaiController.prototype.streamWillAutoplay = function () {
3396  if (this.settings.streamWillAutoplay !== undefined) {
3397    return this.settings.streamWillAutoplay;
3398  } else {
3399    return !!this.playerWrapper.getPlayerOptions().autoplay;
3400  }
3401};
3402
3403/**
3404 * Triggers an event on the VJS player
3405 * @param  {string} name The event name.
3406 * @param  {Object!} data The event data.
3407 */
3408DaiController.prototype.triggerPlayerEvent = function (name, data) {
3409  this.playerWrapper.triggerPlayerEvent(name, data);
3410};
3411
3412/**
3413 * Copyright 2017 Google Inc.
3414 *
3415 * Licensed under the Apache License, Version 2.0 (the "License");
3416 * you may not use this file except in compliance with the License.
3417 * You may obtain a copy of the License at
3418 *
3419 *     http://www.apache.org/licenses/LICENSE-2.0
3420 *
3421 * Unless required by applicable law or agreed to in writing, software
3422 * distributed under the License is distributed on an "AS IS" BASIS,
3423 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3424 * See the License for the specific language governing permissions and
3425 * limitations under the License.
3426 *
3427 * IMA SDK integration plugin for Video.js. For more information see
3428 * https://www.github.com/googleads/videojs-ima
3429 */
3430
3431/**
3432 * Exposes the ImaPlugin to a publisher implementation.
3433 *
3434 * @param {Object} player Instance of the video.js player to which this plugin
3435 *     will be added.
3436 * @param {Object} options Options provided by the implementation.
3437 * @constructor
3438 * @struct
3439 * @final
3440 */
3441const ImaPlugin = function (player, options) {
3442  this.controller = new Controller(player, options);
3443
3444  /**
3445   * Listener JSDoc for ESLint. This listener can be passed to
3446   * addContent(AndAds)EndedListener.
3447   * @callback listener
3448   */
3449
3450  /**
3451   * Adds a listener that will be called when content and all ads have
3452   * finished playing.
3453   * @param {listener} listener The listener to be called when content and ads
3454   *     complete.
3455   */
3456  this.addContentAndAdsEndedListener = function (listener) {
3457    this.controller.addContentAndAdsEndedListener(listener);
3458  }.bind(this);
3459
3460  /**
3461   * Adds a listener for the 'contentended' event of the video player. This
3462   * should be used instead of setting an 'contentended' listener directly to
3463   * ensure that the ima can do proper cleanup of the SDK before other event
3464   * listeners are called.
3465   * @param {listener} listener The listener to be called when content
3466   *     completes.
3467   */
3468  this.addContentEndedListener = function (listener) {
3469    this.controller.addContentEndedListener(listener);
3470  }.bind(this);
3471
3472  /**
3473   * Callback JSDoc for ESLint. This callback can be passed to addEventListener.
3474   * @callback callback
3475   */
3476
3477  /**
3478   * Ads an EventListener to the AdsManager. For a list of available events,
3479   * see
3480   * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent#.Type
3481   * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to
3482   *     listen.
3483   * @param {callback} callback The method to call when the event is fired.
3484   */
3485  this.addEventListener = function (event, callback) {
3486    this.controller.addEventListener(event, callback);
3487  }.bind(this);
3488
3489  /**
3490   * Changes the ad tag. You will need to call requestAds after this method
3491   * for the new ads to be requested.
3492   * @param {?string} adTag The ad tag to be requested the next time requestAds
3493   *     is called.
3494   */
3495  this.changeAdTag = function (adTag) {
3496    this.controller.changeAdTag(adTag);
3497  }.bind(this);
3498
3499  /**
3500   * Returns the instance of the AdsManager.
3501   * @return {google.ima.AdsManager} The AdsManager being used by the plugin.
3502   */
3503  this.getAdsManager = function () {
3504    return this.controller.getAdsManager();
3505  }.bind(this);
3506
3507  /**
3508   * Initializes the AdDisplayContainer. On mobile, this must be done as a
3509   * result of user action.
3510   */
3511  this.initializeAdDisplayContainer = function () {
3512    this.controller.initializeAdDisplayContainer();
3513  }.bind(this);
3514
3515  /**
3516   * Pauses the ad.
3517   */
3518  this.pauseAd = function () {
3519    this.controller.pauseAd();
3520  }.bind(this);
3521
3522  /**
3523   * Called by publishers in manual ad break playback mode to start an ad
3524   * break.
3525   */
3526  this.playAdBreak = function () {
3527    this.controller.playAdBreak();
3528  }.bind(this);
3529
3530  /**
3531   * Creates the AdsRequest and request ads through the AdsLoader.
3532   */
3533  this.requestAds = function () {
3534    this.controller.requestAds();
3535  }.bind(this);
3536
3537  /**
3538   * Resumes the ad.
3539   */
3540  this.resumeAd = function () {
3541    this.controller.resumeAd();
3542  }.bind(this);
3543
3544  /**
3545   * Sets the listener to be called to trigger manual ad break playback.
3546   * @param {listener} listener The listener to be called to trigger manual ad
3547   *     break playback.
3548   */
3549  this.setAdBreakReadyListener = function (listener) {
3550    this.controller.setAdBreakReadyListener(listener);
3551  }.bind(this);
3552
3553  /**
3554   * Sets the content of the video player. You should use this method instead
3555   * of setting the content src directly to ensure the proper ad tag is
3556   * requested when the video content is loaded.
3557   * @param {?string} contentSrc The URI for the content to be played. Leave
3558   *     blank to use the existing content.
3559   * @param {?string} adTag The ad tag to be requested when the content loads.
3560   *     Leave blank to use the existing ad tag.
3561   */
3562  this.setContentWithAdTag = function (contentSrc, adTag) {
3563    this.controller.setContentWithAdTag(contentSrc, adTag);
3564  }.bind(this);
3565
3566  /**
3567   * Sets the content of the video player. You should use this method instead
3568   * of setting the content src directly to ensure the proper ads response is
3569   * used when the video content is loaded.
3570   * @param {?string} contentSrc The URI for the content to be played. Leave
3571   *     blank to use the existing content.
3572   * @param {?string} adsResponse The ads response to be requested when the
3573   *     content loads. Leave blank to use the existing ads response.
3574   */
3575  this.setContentWithAdsResponse = function (contentSrc, adsResponse) {
3576    this.controller.setContentWithAdsResponse(contentSrc, adsResponse);
3577  }.bind(this);
3578
3579  /**
3580   * Sets the content of the video player. You should use this method instead
3581   * of setting the content src directly to ensure the proper ads request is
3582   * used when the video content is loaded.
3583   * @param {?string} contentSrc The URI for the content to be played. Leave
3584   *     blank to use the existing content.
3585   * @param {?Object} adsRequest The ads request to be requested when the
3586   *     content loads. Leave blank to use the existing ads request.
3587   */
3588  this.setContentWithAdsRequest = function (contentSrc, adsRequest) {
3589    this.controller.setContentWithAdsRequest(contentSrc, adsRequest);
3590  }.bind(this);
3591
3592  /**
3593   * Changes the flag to show or hide the ad countdown timer.
3594   *
3595   * @param {boolean} showCountdownIn Show or hide the countdown timer.
3596   */
3597  this.setShowCountdown = function (showCountdownIn) {
3598    this.controller.setShowCountdown(showCountdownIn);
3599  }.bind(this);
3600};
3601
3602/**
3603 * Exposes the ImaDaiPlugin to a publisher implementation.
3604 *
3605 * @param {Object} player Instance of the video.js player to which this plugin
3606 *     will be added.
3607 * @param {Object} options Options provided by the implementation.
3608 * @constructor
3609 * @struct
3610 * @final
3611 */
3612const ImaDaiPlugin = function (player, options) {
3613  this.controller = new DaiController(player, options);
3614
3615  /**
3616   * Adds a listener that will be called when content and all ads in the
3617   * stream have finished playing. VOD stream only.
3618   * @param {listener} listener The listener to be called when content and ads
3619   *     complete.
3620   */
3621  this.streamEndedListener = function (listener) {
3622    this.controller.addStreamEndedListener(listener);
3623  }.bind(this);
3624
3625  /**
3626   * Adds an EventListener to the StreamManager.
3627   * @param {google.ima.StreamEvent.Type} event The StreamEvent.Type for which
3628   * to listen.
3629   * @param {callback} callback The method to call when the event is fired.
3630   */
3631  this.addEventListener = function (event, callback) {
3632    this.controller.addEventListener(event, callback);
3633  }.bind(this);
3634
3635  /**
3636   * Returns the instance of the StreamManager.
3637   * @return {google.ima.StreamManager} The StreamManager being used by the
3638   * plugin.
3639   */
3640  this.getStreamManager = function () {
3641    return this.controller.getStreamManager();
3642  }.bind(this);
3643};
3644
3645/**
3646 * Initializes the plugin for client-side ads.
3647 * @param {Object} options Plugin option set on initiation.
3648 */
3649const init = function (options) {
3650  /* eslint no-invalid-this: 'off' */
3651  this.ima = new ImaPlugin(this, options);
3652};
3653
3654/**
3655 * LiveStream class used for DAI live streams.
3656 */
3657class LiveStream {
3658  /**
3659   * LiveStream class constructor used for DAI live streams.
3660   * @param {string} streamFormat stream format, plugin currently supports only
3661   * 'hls' streams.
3662   * @param {string} assetKey live stream's asset key.
3663   */
3664  constructor(streamFormat, assetKey) {
3665    streamFormat = streamFormat.toLowerCase();
3666    if (streamFormat !== 'hls' && streamFormat !== 'dash') {
3667      window.console.error('VodStream error: incorrect streamFormat.');
3668      return;
3669    } else if (streamFormat === 'dash') {
3670      window.console.error('streamFormat error: DASH streams are not' + 'currently supported by this plugin.');
3671      return;
3672    } else if (typeof assetKey !== 'string') {
3673      window.console.error('assetKey error: value must be string.');
3674      return;
3675    }
3676    this.streamFormat = streamFormat;
3677    this.assetKey = assetKey;
3678  }
3679}
3680
3681/**
3682 * VodStream class used for DAI VOD streams.
3683 */
3684class VodStream {
3685  /**
3686   * VodStream class constructor used for DAI VOD streams.
3687   * @param {string} streamFormat stream format, plugin currently supports only
3688   * 'hls' streams.
3689   * @param {string} cmsId VOD stream's CMS ID.
3690   * @param {string} videoId VOD stream's video ID.
3691   */
3692  constructor(streamFormat, cmsId, videoId) {
3693    streamFormat = streamFormat.toLowerCase();
3694    if (streamFormat !== 'hls' && streamFormat !== 'dash') {
3695      window.console.error('VodStream error: incorrect streamFormat.');
3696      return;
3697    } else if (streamFormat === 'dash') {
3698      window.console.error('streamFormat error: DASH streams are not' + 'currently supported by this plugin.');
3699      return;
3700    } else if (typeof cmsId !== 'string') {
3701      window.console.error('cmsId error: value must be string.');
3702      return;
3703    } else if (typeof videoId !== 'string') {
3704      window.console.error('videoId error: value must be string.');
3705      return;
3706    }
3707
3708    this.streamFormat = streamFormat;
3709    this.cmsId = cmsId;
3710    this.videoId = videoId;
3711  }
3712}
3713
3714/**
3715 * Initializes the plugin for DAI ads.
3716 * @param {Object} stream Accepts either an instance of the LiveStream or
3717 * VodStream classes.
3718 * @param {Object} options Plugin option set on initiation.
3719 */
3720const initDai = function (stream, options) {
3721  if (stream instanceof LiveStream) {
3722    options.streamType = 'live';
3723    options.assetKey = stream.assetKey;
3724  } else if (stream instanceof VodStream) {
3725    options.streamType = 'vod';
3726    options.cmsId = stream.cmsId;
3727    options.videoId = stream.videoId;
3728  } else {
3729    window.console.error('initDai() first parameter must be an instance of LiveStream or ' + 'VodStream.');
3730    return;
3731  }
3732
3733  options.streamFormat = stream.streamFormat;
3734  /* eslint no-invalid-this: 'off' */
3735  this.imaDai = new ImaDaiPlugin(this, options);
3736};
3737
3738const registerPlugin = videojs.registerPlugin || videojs.plugin;
3739registerPlugin('ima', init);
3740registerPlugin('imaDai', initDai);
3741
3742exports['default'] = ImaPlugin;
3743exports.VodStream = VodStream;
3744exports.LiveStream = LiveStream;
3745
3746Object.defineProperty(exports, '__esModule', { value: true });
3747
3748})));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.