PageSourceSearch

https://www.ntr24.tv/wp-content/plugins/videoadplayer/js/plugins/videojs.ads.js?ver=6.3.12

js ntr24.tv collected 2026-10-02 05:24:31 UTC 26,545 bytes, 791 lines download raw bytes

1(function(factory){
2    "use strict";
3    if (typeof define === 'function' && define.amd) {
4        define('videojs-contrib-ads', ['videojs'], function(vjs){factory(window, document, vjs);});
5    } else if (typeof exports === 'object' && typeof module === 'object') {
6        factory(window, document, require('video.js'));
7    } else {
8        factory(window, document, videojs);
9    }
10})
11/**
12 * Basic Ad support plugin for video.js.
13 *
14 * Common code to support ad integrations.
15 */
16(function(window, document, vjs, undefined) {
17"use strict";
18
19var
20
21  /**
22   * Copies properties from one or more objects onto an original.
23   */
24  extend = function(obj /*, arg1, arg2, ... */) {
25    var arg, i, k;
26    for (i=1; i<arguments.length; i++) {
27      arg = arguments[i];
28      for (k in arg) {
29        if (arg.hasOwnProperty(k)) {
30          obj[k] = arg[k];
31        }
32      }
33    }
34    return obj;
35  },
36
37  /**
38   * Add a handler for multiple listeners to an object that supports addEventListener() or on().
39   *
40   * @param {object} obj The object to which the handler will be assigned.
41   * @param {mixed} events A string, array of strings, or hash of string/callback pairs.
42   * @param {function} callback Invoked when specified events occur, if events param is not a hash.
43   *
44   * @return {object} obj The object passed in.
45   */
46  on = function(obj, events, handler) {
47
48    var
49
50      type = Object.prototype.toString.call(events),
51
52      register = function(obj, event, handler) {
53        if (obj.addEventListener) {
54          obj.addEventListener(event, handler);
55        } else if (obj.on) {
56          obj.on(event, handler);
57        } else if (obj.attachEvent) {
58          obj.attachEvent('on' + event, handler);
59        } else {
60          throw new Error('object has no mechanism for adding event listeners');
61        }
62      },
63
64      i,
65      ii;
66
67    switch (type) {
68      case '[object String]':
69        register(obj, events, handler);
70        break;
71      case '[object Array]':
72        for (i = 0, ii = events.length; i<ii; i++) {
73          register(obj, events[i], handler);
74        }
75        break;
76      case '[object Object]':
77        for (i in events) {
78          if (events.hasOwnProperty(i)) {
79            register(obj, i, events[i]);
80          }
81        }
82        break;
83      default:
84        throw new Error('Unrecognized events parameter type: ' + type);
85    }
86
87    return obj;
88
89  },
90
91  /**
92   * Runs the callback at the next available opportunity.
93   * @see https://developer.mozilla.org/en-US/docs/Web/API/window.setImmediate
94   */
95  setImmediate = function(callback) {
96    return (
97      window.setImmediate ||
98      window.requestAnimationFrame ||
99      window.mozRequestAnimationFrame ||
100      window.webkitRequestAnimationFrame ||
101      window.setTimeout
102    )(callback, 0);
103  },
104
105  /**
106   * Clears a callback previously registered with `setImmediate`.
107   * @param {id} id The identifier of the callback to abort
108   */
109  clearImmediate = function(id) {
110    return (window.clearImmediate ||
111            window.cancelAnimationFrame ||
112            window.webkitCancelAnimationFrame ||
113            window.mozCancelAnimationFrame ||
114            window.clearTimeout)(id);
115  },
116
117  /**
118   * If ads are not playing, pauses the player at the next available
119   * opportunity. Has no effect if ads have started. This function is necessary
120   * because pausing a video element while processing a `play` event on iOS can
121   * cause the video element to continuously toggle between playing and paused
122   * states.
123   *
124   * @param {object} player The video player
125   */
126  cancelContentPlay = function(player) {
127    if (player.ads.cancelPlayTimeout) {
128      // another cancellation is already in flight, so do nothing
129      return;
130    }
131    player.ads.cancelPlayTimeout = setImmediate(function() {
132      // deregister the cancel timeout so subsequent cancels are scheduled
133      player.ads.cancelPlayTimeout = null;
134
135      // pause playback so ads can be handled.
136      if (!player.paused()) {
137        player.pause();
138      }
139
140      // add a contentplayback handler to resume playback when ads finish.
141      player.one('contentplayback', function() {
142        if (player.paused()) {
143          player.play();
144        }
145      });
146    });
147  },
148
149  /**
150   * Returns an object that captures the portions of player state relevant to
151   * video playback. The result of this function can be passed to
152   * restorePlayerSnapshot with a player to return the player to the state it
153   * was in when this function was invoked.
154   * @param {object} player The videojs player object
155   */
156  getPlayerSnapshot = function(player) {
157    var
158      tech = player.el().querySelector('.vjs-tech'),
159      tracks = player.remoteTextTracks ? player.remoteTextTracks() : [],
160      track,
161      i,
162      suppressedTracks = [],
163      snapshot = {
164        ended: player.ended(),
165        src: player.currentSrc(),
166        currentTime: player.currentTime(),
167        type: player.currentType()
168      };
169
170    if (tech) {
171      snapshot.nativePoster = tech.poster;
172      snapshot.style = tech.getAttribute('style');
173    }
174
175    i = tracks.length;
176    while (i--) {
177      track = tracks[i];
178      suppressedTracks.push({
179        track: track,
180        mode: track.mode
181      });
182      track.mode = 'disabled';
183    }
184    snapshot.suppressedTracks = suppressedTracks;
185
186    return snapshot;
187  },
188
189  removeClass = function(element, className) {
190    var
191      classes = element.className.split(/\s+/),
192      i = classes.length,
193      newClasses = [];
194    while (i--) {
195      if (classes[i] !== className) {
196        newClasses.push(classes[i]);
197      }
198    }
199    element.className = newClasses.join(' ');
200  },
201
202  /**
203   * Attempts to modify the specified player so that its state is equivalent to
204   * the state of the snapshot.
205   * @param {object} snapshot - the player state to apply
206   */
207  restorePlayerSnapshot = function(player, snapshot) {
208    var
209      // the playback tech
210      tech = player.el().querySelector('.vjs-tech'),
211
212      // the number of remaining attempts to restore the snapshot
213      attempts = 20,
214
215      suppressedTracks = snapshot.suppressedTracks,
216      trackSnapshot,
217      restoreTracks =  function() {
218        var i = suppressedTracks.length;
219        while (i--) {
220          trackSnapshot = suppressedTracks[i];
221          trackSnapshot.track.mode = trackSnapshot.mode;
222        }
223      },
224
225      // finish restoring the playback state
226      resume = function() {
227        var
228          ended = false,
229          updateEnded = function() {
230            ended = true;
231          };
232        player.currentTime(snapshot.currentTime);
233
234        // Resume playback if this wasn't a postroll
235        if (!snapshot.ended) {
236          player.play();
237        } else {
238          // On iOS 8.1, the "ended" event will not fire if you seek
239          // directly to the end of a video. To make that behavior
240          // consistent with the standard, fire a synthetic event if
241          // "ended" does not fire within 250ms. Note that the ended
242          // event should occur whether the browser actually has data
243          // available for that position
244          // (https://html.spec.whatwg.org/multipage/embedded-content.html#seeking),
245          // so it should not be necessary to wait for the seek to
246          // indicate completion.
247          window.setTimeout(function() {
248            if (!ended) {
249              player.play();
250            }
251            player.off('ended', updateEnded);
252          }, 250);
253          player.on('ended', updateEnded);
254        }
255      },
256
257      // determine if the video element has loaded enough of the snapshot source
258      // to be ready to apply the rest of the state
259      tryToResume = function() {
260        if (tech.readyState > 1) {
261          // some browsers and media aren't "seekable".
262          // readyState greater than 1 allows for seeking without exceptions
263          return resume();
264        }
265
266        if (tech.seekable === undefined) {
267          // if the tech doesn't expose the seekable time ranges, try to
268          // resume playback immediately
269          return resume();
270        }
271
272        if (tech.seekable.length > 0) {
273          // if some period of the video is seekable, resume playback
274          return resume();
275        }
276
277        // delay a bit and then check again unless we're out of attempts
278        if (attempts--) {
279          setTimeout(tryToResume, 50);
280        } else {
281          (function() {
282            try {
283              resume();
284            } catch(e) {
285              videojs.log.warn('Failed to resume the content after an advertisement', e);
286            }
287          })();
288        }
289      },
290
291      // whether the video element has been modified since the
292      // snapshot was taken
293      srcChanged;
294
295    if (snapshot.nativePoster) {
296      tech.poster = snapshot.nativePoster;
297    }
298
299    if ('style' in snapshot) {
300      // overwrite all css style properties to restore state precisely
301      tech.setAttribute('style', snapshot.style || '');
302    }
303
304    // Determine whether the player needs to be restored to its state
305    // before ad playback began. With a custom ad display or burned-in
306    // ads, the content player state hasn't been modified and so no
307    // restoration is required
308
309    if (player.src()) {
310      // the player was in src attribute mode before the ad and the
311      // src attribute has not been modified, no restoration is required
312      // to resume playback
313      srcChanged = player.src() !== snapshot.src;
314    } else {
315      // the player was configured through source element children
316      // and the currentSrc hasn't changed, no restoration is required
317      // to resume playback
318      srcChanged = player.currentSrc() !== snapshot.src;
319    }
320
321    if (srcChanged) {
322      // on ios7, fiddling with textTracks too early will cause safari to crash
323      player.one('contentloadedmetadata', restoreTracks);
324
325      // if the src changed for ad playback, reset it
326      player.src({ src: snapshot.src, type: snapshot.type });
327      // safari requires a call to `load` to pick up a changed source
328      player.load();
329      // and then resume from the snapshots time once the original src has loaded
330      player.one('contentcanplay', tryToResume);
331    } else if (!player.ended() || !snapshot.ended) {
332      // if we didn't change the src, just restore the tracks
333      restoreTracks();
334
335      // the src didn't change and this wasn't a postroll
336      // just resume playback at the current time.
337      player.play();
338    }
339  },
340
341  /**
342   * Remove the poster attribute from the video element tech, if present. When
343   * reusing a video element for multiple videos, the poster image will briefly
344   * reappear while the new source loads. Removing the attribute ahead of time
345   * prevents the poster from showing up between videos.
346   * @param {object} player The videojs player object
347   */
348  removeNativePoster = function(player) {
349    var tech = player.el().querySelector('.vjs-tech');
350    if (tech) {
351      tech.removeAttribute('poster');
352    }
353  },
354
355  // ---------------------------------------------------------------------------
356  // Ad Framework
357  // ---------------------------------------------------------------------------
358
359  // default framework settings
360  defaults = {
361    // maximum amount of time in ms to wait to receive `adsready` from the ad
362    // implementation after play has been requested. Ad implementations are
363    // expected to load any dynamic libraries and make any requests to determine
364    // ad policies for a video during this time.
365    timeout: 5000,
366
367    // maximum amount of time in ms to wait for the ad implementation to start
368    // linear ad mode after `readyforpreroll` has fired. This is in addition to
369    // the standard timeout.
370    prerollTimeout: 100,
371
372    // maximum amount of time in ms to wait for the ad implementation to start
373    // linear ad mode after `contentended` has fired.
374    postrollTimeout: 100,
375
376    // when truthy, instructs the plugin to output additional information about
377    // plugin state to the video.js log. On most devices, the video.js log is
378    // the same as the developer console.
379    debug: false
380  },
381
382  adFramework = function(options) {
383    var
384      player = this,
385
386      // merge options and defaults
387      settings = extend({}, defaults, options || {}),
388
389      fsmHandler;
390
391    // prefix all video element events during ad playback
392    // if the video element emits ad-related events directly,
393    // plugins that aren't ad-aware will break. prefixing allows
394    // plugins that wish to handle ad events to do so while
395    // avoiding the complexity for common usage
396    (function() {
397      var
398        videoEvents = videojs.Html5.Events,
399        i = videoEvents.length,
400        returnTrue = function() { return true; },
401        triggerEvent = function(type, event) {
402          // pretend we called stopImmediatePropagation because we want the native
403          // element events to continue propagating
404          event.isImmediatePropagationStopped = returnTrue;
405          event.cancelBubble = true;
406          event.isPropagationStopped = returnTrue;
407          player.trigger({
408            type: type + event.type,
409            state: player.ads.state,
410            originalEvent: event
411          });
412        },
413        redispatch = function(event) {
414          if (player.ads.state === 'ad-playback') {
415            triggerEvent('ad', event);
416
417          } else if (player.ads.state === 'content-playback' && event.type === 'ended') {
418            triggerEvent('content', event);
419
420          } else if (player.ads.state === 'content-resuming') {
421            if (player.ads.snapshot) {
422              // the video element was recycled for ad playback
423              if (player.currentSrc() !== player.ads.snapshot.src) {
424                if (event.type === 'loadstart') {
425                  return;
426                }
427                return triggerEvent('content', event);
428
429              // we ended playing postrolls and the video itself
430              // the content src is back in place
431              } else if (player.ads.snapshot.ended) {
432                if ((event.type === 'pause' ||
433                    event.type === 'ended')) {
434                  // after loading a video, the natural state is to not be started
435                  // in this case, it actually has, so, we do it manually
436                  player.addClass('vjs-has-started');
437                  // let `pause` and `ended` events through, naturally
438                  return;
439                }
440                // prefix all other events in content-resuming with `content`
441                return triggerEvent('content', event);
442              }
443            }
444            if (event.type !== 'playing') {
445              triggerEvent('content', event);
446            }
447          }
448        };
449
450      while (i--) {
451        player.on(videoEvents[i], redispatch);
452      }
453      return redispatch;
454    })();
455
456    // We now auto-play when an ad gets loaded if we're playing ads in the same video element as the content.
457    // The problem is that in IE11, we cannot play in addurationchange but in iOS8, we cannot play from adcanplay.
458    // This will allow ad-integrations from needing to do this themselves.
459    player.on(['addurationchange', 'adcanplay'], function() {
460      var snapshot = player.ads.snapshot;
461      if (player.currentSrc() === snapshot.src) {
462        return;  // do nothing
463      }
464
465      player.play();
466    });
467
468    // replace the ad initializer with the ad namespace
469    player.ads = {
470      state: 'content-set',
471
472      startLinearAdMode: function() {
473        player.trigger('adstart');
474      },
475
476      endLinearAdMode: function() {
477        player.trigger('adend');
478      }
479    };
480
481    fsmHandler = function(event) {
482      // Ad Playback State Machine
483      var
484        fsm = {
485          'content-set': {
486            events: {
487              'adscanceled': function() {
488                this.state = 'content-playback';
489              },
490              'adsready': function() {
491                this.state = 'ads-ready';
492              },
493              'play': function() {
494                this.state = 'ads-ready?';
495                cancelContentPlay(player);
496                // remove the poster so it doesn't flash between videos
497                removeNativePoster(player);
498              },
499              'adserror': function() {
500                this.state = 'content-playback';
501              }
502            }
503          },
504          'ads-ready': {
505            events: {
506              'play': function() {
507                this.state = 'preroll?';
508                cancelContentPlay(player);
509              },
510              'adserror': function() {
511                this.state = 'content-playback';
512              }
513            }
514          },
515          'preroll?': {
516            enter: function() {
517              // change class to show that we're waiting on ads
518              player.el().className += ' vjs-ad-loading';
519              // schedule an adtimeout event to fire if we waited too long
520              player.ads.timeout = window.setTimeout(function() {
521                player.trigger('adtimeout');
522              }, settings.prerollTimeout);
523              // signal to ad plugin that it's their opportunity to play a preroll
524              player.trigger('readyforpreroll');
525            },
526            leave: function() {
527              window.clearTimeout(player.ads.timeout);
528              removeClass(player.el(), 'vjs-ad-loading');
529            },
530            events: {
531              'play': function() {
532                cancelContentPlay(player);
533              },
534              'adstart': function() {
535                this.state = 'ad-playback';
536                player.el().className += ' vjs-ad-playing';
537              },
538              'adtimeout': function() {
539                this.state = 'content-playback';
540              },
541              'adserror': function() {
542                this.state = 'content-playback';
543              }
544            }
545          },
546          'ads-ready?': {
547            enter: function() {
548              player.el().className += ' vjs-ad-loading';
549              player.ads.timeout = window.setTimeout(function() {
550                player.trigger('adtimeout');
551              }, settings.timeout);
552            },
553            leave: function() {
554              window.clearTimeout(player.ads.timeout);
555              removeClass(player.el(), 'vjs-ad-loading');
556            },
557            events: {
558              'play': function() {
559                cancelContentPlay(player);
560              },
561              'adscanceled': function() {
562                this.state = 'content-playback';
563              },
564              'adsready': function() {
565                this.state = 'preroll?';
566              },
567              'adtimeout': function() {
568                this.state = 'content-playback';
569              },
570              'adserror': function() {
571                this.state = 'content-playback';
572              }
573            }
574          },
575          'ad-playback': {
576            enter: function() {
577              // capture current player state snapshot (playing, currentTime, src)
578              this.snapshot = getPlayerSnapshot(player);
579
580              // remove the poster so it doesn't flash between videos
581              removeNativePoster(player);
582              // We no longer need to supress play events once an ad is playing.
583              // Clear it if we were.
584              if (player.ads.cancelPlayTimeout) {
585                clearImmediate(player.ads.cancelPlayTimeout);
586                player.ads.cancelPlayTimeout = null;
587              }
588            },
589            leave: function() {
590              removeClass(player.el(), 'vjs-ad-playing');
591
592              restorePlayerSnapshot(player, this.snapshot);
593              if (player.ads.triggerevent !== 'adend') {
594                // trigger 'adend' as a consistent notification
595                // event that we're exiting ad-playback.
596                player.trigger('adend');
597              }
598            },
599            events: {
600              'adend': function() {
601                this.state = 'content-resuming';
602              },
603              'adserror': function() {
604                this.state = 'content-resuming';
605              }
606            }
607          },
608          'content-resuming': {
609            enter: function() {
610              if (this.snapshot.ended) {
611                window.clearTimeout(player.ads._fireEndedTimeout);
612                // in some cases, ads are played in a swf or another video element
613                // so we do not get an ended event in this state automatically.
614                // If we don't get an ended event we can use, we need to trigger
615                // one ourselves or else we won't actually ever end the current video.
616                player.ads._fireEndedTimeout = window.setTimeout(function() {
617                  player.trigger('ended');
618                }, 1000);
619              }
620            },
621            leave: function() {
622              window.clearTimeout(player.ads._fireEndedTimeout);
623            },
624            events: {
625              'contentupdate': function() {
626                this.state = 'content-set';
627              },
628              'playing': function() {
629                this.state = 'content-playback';
630              },
631              'ended': function() {
632                this.state = 'content-playback';
633              }
634            }
635          },
636          'postroll?': {
637            enter: function() {
638              this.snapshot = getPlayerSnapshot(player);
639
640              player.el().className += ' vjs-ad-loading';
641
642              player.ads.timeout = window.setTimeout(function() {
643                player.trigger('adtimeout');
644              }, settings.postrollTimeout);
645            },
646            leave: function() {
647              window.clearTimeout(player.ads.timeout);
648              removeClass(player.el(), 'vjs-ad-loading');
649            },
650            events: {
651              'adstart': function() {
652                this.state = 'ad-playback';
653                player.el().className += ' vjs-ad-playing';
654              },
655              'adtimeout': function() {
656                this.state = 'content-resuming';
657                setImmediate(function() {
658                  player.trigger('ended');
659                });
660              },
661              'adserror': function() {
662                this.state = 'content-resuming';
663                setImmediate(function() {
664                  player.trigger('ended');
665                });
666              }
667            }
668          },
669          'content-playback': {
670            enter: function() {
671              // make sure that any cancelPlayTimeout is cleared
672              if (player.ads.cancelPlayTimeout) {
673                clearImmediate(player.ads.cancelPlayTimeout);
674                player.ads.cancelPlayTimeout = null;
675              }
676              // this will cause content to start if a user initiated
677              // 'play' event was canceled earlier.
678              player.trigger({
679                type: 'contentplayback',
680                triggerevent: player.ads.triggerevent
681              });
682            },
683            events: {
684              // in the case of a timeout, adsready might come in late.
685              'adsready': function() {
686                player.trigger('readyforpreroll');
687              },
688              'adstart': function() {
689                this.state = 'ad-playback';
690                player.el().className += ' vjs-ad-playing';
691                // remove the poster so it doesn't flash between videos
692                removeNativePoster(player);
693              },
694              'contentupdate': function() {
695                if (player.paused()) {
696                  this.state = 'content-set';
697                } else {
698                  this.state = 'ads-ready?';
699                }
700              },
701              'contentended': function() {
702                this.state = 'postroll?';
703              }
704            }
705          }
706        };
707
708      (function(state) {
709        var noop = function() {};
710
711        // process the current event with a noop default handler
712        ((fsm[state].events || {})[event.type] || noop).apply(player.ads);
713
714        // check whether the state has changed
715        if (state !== player.ads.state) {
716
717          // record the event that caused the state transition
718          player.ads.triggerevent = event.type;
719
720          // execute leave/enter callbacks if present
721          (fsm[state].leave || noop).apply(player.ads);
722          (fsm[player.ads.state].enter || noop).apply(player.ads);
723
724          // output debug logging
725          if (settings.debug) {
726            videojs.log('ads', player.ads.triggerevent + ' triggered: ' + state + ' -> ' + player.ads.state);
727          }
728        }
729
730      })(player.ads.state);
731
732    };
733
734    // register for the events we're interested in
735    on(player, vjs.Html5.Events.concat([
736      // events emitted by ad plugin
737      'adtimeout',
738      'contentupdate',
739      'contentplaying',
740      'contentended',
741
742      // events emitted by third party ad implementors
743      'adsready',
744      'adserror',
745      'adscanceled',
746      'adstart',  // startLinearAdMode()
747      'adend'     // endLinearAdMode()
748    ]), fsmHandler);
749
750    // keep track of the current content source
751    // if you want to change the src of the video without triggering
752    // the ad workflow to restart, you can update this variable before
753    // modifying the player's source
754    player.ads.contentSrc = player.currentSrc();
755
756    // implement 'contentupdate' event.
757    (function(){
758      var
759        // check if a new src has been set, if so, trigger contentupdate
760        checkSrc = function() {
761          var src;
762          if (player.ads.state !== 'ad-playback') {
763            src = player.currentSrc();
764            if (src !== player.ads.contentSrc) {
765              player.trigger({
766                type: 'contentupdate',
767                oldValue: player.ads.contentSrc,
768                newValue: src
769              });
770              player.ads.contentSrc = src;
771            }
772          }
773        };
774      // loadstart reliably indicates a new src has been set
775      player.on(['loadstart'], checkSrc);
776      // check immediately in case we missed the loadstart
777      setImmediate(checkSrc);
778    })();
779
780    // kick off the fsm
781    if (!player.paused()) {
782      // simulate a play event if we're autoplaying
783      fsmHandler({type:'play'});
784    }
785
786  };
787
788  // register the ad plugin framework
789  vjs.plugin('ads', adFramework);
790
791});

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.