PageSourceSearch

https://cdn.globalkidneyacademy.org/assets/js/videojs-ads.js?212d097c3e0f6c7d0b19d648383ef940

js globalkidneyacademy.org collected 2026-10-08 07:26:35 UTC 104,904 bytes, 2,687 lines download raw bytes

1/**
2    * Patched by USH Team for lazy-loading feature.
3    * Check <filename>.original.js for original source code.
4*/
5
6(function (global, factory) {
7    global = global || self;
8    global.videojsIma = factory();
9}(window, (function () {
10    'use strict';
11
12    var videojs = window.videojs;
13
14    var version = "6.7.0";
15
16    /*
17     * Implements the public API available in `player.ads` as well as application state.
18     */
19    function getAds(player) {
20        return {
21            disableNextSnapshotRestore: false,
22            // This is true if we have finished actual content playback but haven't
23            // dealt with postrolls and officially ended yet
24            _contentEnding: false,
25            // This is set to true if the content has officially ended at least once.
26            // After that, the user can seek backwards and replay content, but _contentHasEnded
27            // remains true.
28            _contentHasEnded: false,
29            // Tracks if loadstart has happened yet for the initial source. It is not reset
30            // on source changes because loadstart is the event that signals to the ad plugin
31            // that the source has changed. Therefore, no special signaling is needed to know
32            // that there has been one for subsequent sources.
33            _hasThereBeenALoadStartDuringPlayerLife: false,
34            // Tracks if loadeddata has happened yet for the current source.
35            _hasThereBeenALoadedData: false,
36            // Tracks if loadedmetadata has happened yet for the current source.
37            _hasThereBeenALoadedMetaData: false,
38            // Are we after startLinearAdMode and before endLinearAdMode?
39            _inLinearAdMode: false,
40            // Should we block calls to play on the content player?
41            _shouldBlockPlay: false,
42            // Was play blocked by the plugin's playMiddleware feature?
43            _playBlocked: false,
44            // Tracks whether play has been requested for this source,
45            // either by the play method or user interaction
46            _playRequested: false,
47            // This is an estimation of the current ad type being played
48            // This is experimental currently. Do not rely on its presence or behavior!
49            adType: null,
50            VERSION: version,
51            reset: function reset() {
52                player.ads.disableNextSnapshotRestore = false;
53                player.ads._contentEnding = false;
54                player.ads._contentHasEnded = false;
55                player.ads.snapshot = null;
56                player.ads.adType = null;
57                player.ads._hasThereBeenALoadedData = false;
58                player.ads._hasThereBeenALoadedMetaData = false;
59                player.ads._cancelledPlay = false;
60                player.ads._shouldBlockPlay = false;
61                player.ads._playBlocked = false;
62                player.ads.nopreroll_ = false;
63                player.ads.nopostroll_ = false;
64                player.ads._playRequested = false;
65            },
66            // Call this when an ad response has been received and there are
67            // linear ads ready to be played.
68            startLinearAdMode: function startLinearAdMode() {
69                player.ads._state.startLinearAdMode();
70            },
71            // Call this when a linear ad pod has finished playing.
72            endLinearAdMode: function endLinearAdMode() {
73                player.ads._state.endLinearAdMode();
74            },
75            // Call this when an ad response has been received but there are no
76            // linear ads to be played (i.e. no ads available, or overlays).
77            // This has no effect if we are already in an ad break.  Always
78            // use endLinearAdMode() to exit from linear ad-playback state.
79            skipLinearAdMode: function skipLinearAdMode() {
80                player.ads._state.skipLinearAdMode();
81            },
vendor: 5,848 bytes, lines 82-198
82            // With no arguments, returns a boolean value indicating whether or not
83            // contrib-ads is set to treat ads as stitched with content in a single
84            // stream. With arguments, treated as a setter, but this behavior is
85            // deprecated.
86            stitchedAds: function stitchedAds(arg) {
87                if (arg !== undefined) {
88                    videojs.log.warn('Using player.ads.stitchedAds() as a setter is deprecated, ' + 'it should be set as an option upon initialization of contrib-ads.'); // Keep the private property and the settings in sync. When this
89                    // setter is removed, we can probably stop using the private property.
90
91                    this.settings.stitchedAds = !!arg;
92                }
93
94                return this.settings.stitchedAds;
95            },
96            // Returns whether the video element has been modified since the
97            // snapshot was taken.
98            // We test both src and currentSrc because changing the src attribute to a URL that
99            // AdBlocker is intercepting doesn't update currentSrc.
100            videoElementRecycled: function videoElementRecycled() {
101                if (player.ads.shouldPlayContentBehindAd(player)) {
102                    return false;
103                }
104
105                if (!this.snapshot) {
106                    throw new Error('You cannot use videoElementRecycled while there is no snapshot.');
107                }
108
109                var srcChanged = player.tech_.src() !== this.snapshot.src;
110                var currentSrcChanged = player.currentSrc() !== this.snapshot.currentSrc;
111                return srcChanged || currentSrcChanged;
112            },
113            // Returns a boolean indicating if given player is in live mode.
114            // One reason for this: https://github.com/videojs/video.js/issues/3262
115            // Also, some live content can have a duration.
116            isLive: function isLive(somePlayer) {
117                if (somePlayer === void 0) {
118                    somePlayer = player;
119                }
120
121                if (typeof somePlayer.ads.settings.contentIsLive === 'boolean') {
122                    return somePlayer.ads.settings.contentIsLive;
123                } else if (somePlayer.duration() === Infinity) {
124                    return true;
125                } else if (videojs.browser.IOS_VERSION === '8' && somePlayer.duration() === 0) {
126                    return true;
127                }
128
129                return false;
130            },
131            // Return true if content playback should mute and continue during ad breaks.
132            // This is only done during live streams on platforms where it's supported.
133            // This improves speed and accuracy when returning from an ad break.
134            shouldPlayContentBehindAd: function shouldPlayContentBehindAd(somePlayer) {
135                if (somePlayer === void 0) {
136                    somePlayer = player;
137                }
138
139                if (!somePlayer) {
140                    throw new Error('shouldPlayContentBehindAd requires a player as a param');
141                } else if (!somePlayer.ads.settings.liveCuePoints) {
142                    return false;
143                } else {
144                    return !videojs.browser.IS_IOS && !videojs.browser.IS_ANDROID && somePlayer.duration() === Infinity;
145                }
146            },
147            // Return true if the ads plugin should save and restore snapshots of the
148            // player state when moving into and out of ad mode.
149            shouldTakeSnapshots: function shouldTakeSnapshots(somePlayer) {
150                if (somePlayer === void 0) {
151                    somePlayer = player;
152                }
153
154                return !this.shouldPlayContentBehindAd(somePlayer) && !this.stitchedAds();
155            },
156            // Returns true if player is in ad mode.
157            //
158            // Ad mode definition:
159            // If content playback is blocked by the ad plugin.
160            //
161            // Examples of ad mode:
162            //
163            // * Waiting to find out if an ad is going to play while content would normally be
164            //   playing.
165            // * Waiting for an ad to start playing while content would normally be playing.
166            // * An ad is playing (even if content is also playing)
167            // * An ad has completed and content is about to resume, but content has not resumed
168            //   yet.
169            //
170            // Examples of not ad mode:
171            //
172            // * Content playback has not been requested
173            // * Content playback is paused
174            // * An asynchronous ad request is ongoing while content is playing
175            // * A non-linear ad is active
176            isInAdMode: function isInAdMode() {
177                return this._state.isAdState();
178            },
179            // Returns true if in ad mode but an ad break hasn't started yet.
180            isWaitingForAdBreak: function isWaitingForAdBreak() {
181                return this._state.isWaitingForAdBreak();
182            },
183            // Returns true if content is resuming after an ad. This is part of ad mode.
184            isContentResuming: function isContentResuming() {
185                return this._state.isContentResuming();
186            },
187            // Deprecated because the name was misleading. Use inAdBreak instead.
188            isAdPlaying: function isAdPlaying() {
189                return this._state.inAdBreak();
190            },
191            // Returns true if an ad break is ongoing. This is part of ad mode.
192            // An ad break is the time between startLinearAdMode and endLinearAdMode.
193            inAdBreak: function inAdBreak() {
194                return this._state.inAdBreak();
195            },
196
197            /*
198             * Remove the poster attribute from the video element te
vendor: 15,835 bytes, lines 198-560
198ch, if present. When
199             * reusing a video element for multiple videos, the poster image will briefly
200             * reappear while the new source loads. Removing the attribute ahead of time
201             * prevents the poster from showing up between videos.
202             *
203             * @param {Object} player The videojs player object
204             */
205            removeNativePoster: function removeNativePoster() {
206                var tech = player.$('.vjs-tech');
207
208                if (tech) {
209                    tech.removeAttribute('poster');
210                }
211            },
212            debug: function debug() {
213                if (this.settings.debug) {
214                    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
215                        args[_key] = arguments[_key];
216                    }
217
218                    if (args.length === 1 && typeof args[0] === 'string') {
219                        videojs.log('ADS: ' + args[0]);
220                    } else {
221                        videojs.log.apply(videojs, ['ADS:'].concat(args));
222                    }
223                }
224            }
225        };
226    }
227
228    /*
229    The goal of this feature is to make player events work as an integrator would
230    expect despite the presense of ads. For example, an integrator would expect
231    an `ended` event to happen once the content is ended. If an `ended` event is sent
232    as a result of a preroll ending, that is a bug. The `redispatch` method should recognize
233    such `ended` events and prefix them so they are sent as `adended`, and so on with
234    all other player events.
235    */
236    // Cancel an event.
237    // Video.js wraps native events. This technique stops propagation for the Video.js event
238    // (AKA player event or wrapper event) while native events continue propagating.
239    var cancelEvent = function cancelEvent(player, event) {
240        event.isImmediatePropagationStopped = function () {
241            return true;
242        };
243
244        event.cancelBubble = true;
245
246        event.isPropagationStopped = function () {
247            return true;
248        };
249    }; // Redispatch an event with a prefix.
250    // Cancels the event, then sends a new event with the type of the original
251    // event with the given prefix added.
252    // The inclusion of the "state" property should be removed in a future
253    // major version update with instructions to migrate any code that relies on it.
254    // It is an implementation detail and relying on it creates fragility.
255
256
257    var prefixEvent = function prefixEvent(player, prefix, event) {
258        cancelEvent(player, event);
259        player.trigger({
260            type: prefix + event.type,
261            originalEvent: event
262        });
263    }; // Playing event
264    // Requirements:
265    // * Normal playing event when there is no preroll
266    // * No playing event before preroll
267    // * At least one playing event after preroll
268
269
270    var handlePlaying = function handlePlaying(player, event) {
271        if (player.ads.isInAdMode()) {
272            if (player.ads.isContentResuming()) {
273                // Prefix playing event when switching back to content after postroll.
274                if (player.ads._contentEnding) {
275                    prefixEvent(player, 'content', event);
276                } // Prefix all other playing events during ads.
277
278            } else {
279                prefixEvent(player, 'ad', event);
280            }
281        }
282    }; // Ended event
283    // Requirements:
284    // * A single ended event when there is no postroll
285    // * No ended event before postroll
286    // * A single ended event after postroll
287
288
289    var handleEnded = function handleEnded(player, event) {
290        if (player.ads.isInAdMode()) {
291            // Cancel ended events during content resuming. Normally we would
292            // prefix them, but `contentended` has a special meaning. In the
293            // future we'd like to rename the existing `contentended` to
294            // `readyforpostroll`, then we could remove the special `resumeended`
295            // and do a conventional content prefix here.
296            if (player.ads.isContentResuming()) {
297                cancelEvent(player, event); // Important: do not use this event outside of videojs-contrib-ads.
298                // It will be removed and your code will break.
299                // Ideally this would simply be `contentended`, but until
300                // `contentended` no longer has a special meaning it cannot be
301                // changed.
302
303                player.trigger('resumeended'); // Ad prefix in ad mode
304            } else {
305                prefixEvent(player, 'ad', event);
306            } // Prefix ended due to content ending before postroll check
307
308        } else if (!player.ads._contentHasEnded && !player.ads.stitchedAds()) {
309            // This will change to cancelEvent after the contentended deprecation
310            // period (contrib-ads 7)
311            prefixEvent(player, 'content', event); // Content ended for the first time, time to check for postrolls
312
313            player.trigger('readyforpostroll');
314        }
315    }; // handleLoadEvent is used for loadstart, loadeddata, and loadedmetadata
316    // Requirements:
317    // * Initial event is not prefixed
318    // * Event due to ad loading is prefixed
319    // * Event due to content source change is not prefixed
320    // * Event due to content resuming is prefixed
321
322
323    var handleLoadEvent = function handleLoadEvent(player, event) {
324        // Initial event
325        if (event.type === 'loadstart' && !player.ads._hasThereBeenALoadStartDuringPlayerLife || event.type === 'loadeddata' && !player.ads._hasThereBeenALoadedData || event.type === 'loadedmetadata' && !player.ads._hasThereBeenALoadedMetaData) {
326            return; // Ad playing
327        } else if (player.ads.inAdBreak()) {
328            prefixEvent(player, 'ad', event); // Source change
329        } else if (player.currentSrc() !== player.ads.contentSrc) {
330            return; // Content resuming
331        } else {
332            prefixEvent(player, 'content', event);
333        }
334    }; // Play event
335    // Requirements:
336    // * Play events have the "ad" prefix when an ad is playing
337    // * Play events have the "content" prefix when content is resuming
338    // Play requests are unique because they represent user intention to play. They happen
339    // because the user clicked play, or someone called player.play(), etc. It could happen
340    // multiple times during ad loading, regardless of where we are in the process. With our
341    // current architecture, this could cause the content to start playing.
342    // Therefore, contrib-ads must always either:
343    //   - cancelContentPlay if there is any possible chance the play caused the
344    //     content to start playing, even if we are technically in ad mode. In order for
345    //     that to happen, play events need to be unprefixed until the last possible moment.
346    //   - use playMiddleware to stop the play from reaching the Tech so there is no risk
347    //     of the content starting to play.
348    // Currently, playMiddleware is only supported on desktop browsers with
349    // video.js after version 6.7.1.
350
351
352    var handlePlay = function handlePlay(player, event) {
353        if (player.ads.inAdBreak()) {
354            prefixEvent(player, 'ad', event); // Content resuming
355        } else if (player.ads.isContentResuming()) {
356            prefixEvent(player, 'content', event);
357        }
358    }; // Handle a player event, either by redispatching it with a prefix, or by
359    // letting it go on its way without any meddling.
360
361
362    function redispatch(event) {
363        // Events with special treatment
364        if (event.type === 'playing') {
365            handlePlaying(this, event);
366        } else if (event.type === 'ended') {
367            handleEnded(this, event);
368        } else if (event.type === 'loadstart' || event.type === 'loadeddata' || event.type === 'loadedmetadata') {
369            handleLoadEvent(this, event);
370        } else if (event.type === 'play') {
371            handlePlay(this, event); // Standard handling for all other events
372        } else if (this.ads.isInAdMode()) {
373            if (this.ads.isContentResuming()) {
374                // Event came from snapshot restore after an ad, use "content" prefix
375                prefixEvent(this, 'content', event);
376            } else {
377                // Event came from ad playback, use "ad" prefix
378                prefixEvent(this, 'ad', event);
379            }
380        }
381    }
382
383    /*
384    This feature sends a `contentupdate` event when the player source changes.
385    */
386    // Start sending contentupdate events
387    function initializeContentupdate(player) {
388        // Keep track of the current content source
389        // If you want to change the src of the video without triggering
390        // the ad workflow to restart, you can update this variable before
391        // modifying the player's source
392        player.ads.contentSrc = player.currentSrc();
393        player.ads._seenInitialLoadstart = false; // Check if a new src has been set, if so, trigger contentupdate
394
395        var checkSrc = function checkSrc() {
396            if (!player.ads.inAdBreak()) {
397                var src = player.currentSrc();
398
399                if (src !== player.ads.contentSrc) {
400                    if (player.ads._seenInitialLoadstart) {
401                        player.trigger({
402                            type: 'contentchanged'
403                        });
404                    }
405
406                    player.trigger({
407                        type: 'contentupdate',
408                        oldValue: player.ads.contentSrc,
409                        newValue: src
410                    });
411                    player.ads.contentSrc = src;
412                }
413
414                player.ads._seenInitialLoadstart = true;
415            }
416        }; // loadstart reliably indicates a new src has been set
417
418
419        player.on('loadstart', checkSrc);
420    }
421
422    /*
423    This feature provides an optional method for ad plugins to insert run-time values
424    into an ad server URL or configuration.
425    */
426
427    var uriEncodeIfNeeded = function uriEncodeIfNeeded(value, uriEncode) {
428        if (uriEncode) {
429            return encodeURIComponent(value);
430        }
431
432        return value;
433    }; // Add custom field macros to macros object
434    // based on given name for custom fields property of mediainfo object.
435
436
437    var customFields = function customFields(mediainfo, macros, customFieldsName) {
438        if (mediainfo && mediainfo[customFieldsName]) {
439            var fields = mediainfo[customFieldsName];
440            var fieldNames = Object.keys(fields);
441
442            for (var i = 0; i < fieldNames.length; i++) {
443                var tag = '{mediainfo.' + customFieldsName + '.' + fieldNames[i] + '}';
444                macros[tag] = fields[fieldNames[i]];
445            }
446        }
447    }; // Public method that ad plugins use for ad macros.
448    // "string" is any string with macros to be replaced
449    // "uriEncode" if true will uri encode macro values when replaced
450    // "customMacros" is a object with custom macros and values to map them to
451    //  - For example: {'{five}': 5}
452    // Return value is is "string" with macros replaced
453    //  - For example: adMacroReplacement('{player.id}') returns a string of the player id
454
455
456    function adMacroReplacement(string, uriEncode, customMacros) {
457        var _this = this;
458
459        var defaults = {}; // Get macros with defaults e.g. {x=y}, store values and replace with standard macros
460
461        string = string.replace(/{([^}=]+)=([^}]+)}/g, function (match, name, defaultVal) {
462            defaults["{" + name + "}"] = defaultVal;
463            return "{" + name + "}";
464        });
465
466        if (uriEncode === undefined) {
467            uriEncode = false;
468        }
469
470        var macros = {};
471
472        if (customMacros !== undefined) {
473            macros = customMacros;
474        } // Static macros
475
476
477        macros['{player.id}'] = this.options_['data-player'];
478        macros['{player.height}'] = this.currentHeight();
479        macros['{player.width}'] = this.currentWidth();
480        macros['{mediainfo.id}'] = this.mediainfo ? this.mediainfo.id : '';
481        macros['{mediainfo.name}'] = this.mediainfo ? this.mediainfo.name : '';
482        macros['{mediainfo.duration}'] = this.mediainfo ? this.mediainfo.duration : '';
483        macros['{player.duration}'] = this.duration();
484        macros['{player.pageUrl}'] = videojs.dom.isInFrame() ? document.referrer : window.location.href;
485        macros['{playlistinfo.id}'] = this.playlistinfo ? this.playlistinfo.id : '';
486        macros['{playlistinfo.name}'] = this.playlistinfo ? this.playlistinfo.name : '';
487        macros['{timestamp}'] = new Date().getTime();
488        macros['{document.referrer}'] = document.referrer;
489        macros['{window.location.href}'] = window.location.href;
490        macros['{random}'] = Math.floor(Math.random() * 1000000000000);
491        ['description', 'tags', 'reference_id', 'ad_keys'].forEach(function (prop) {
492            if (_this.mediainfo && _this.mediainfo[prop]) {
493                macros["{mediainfo." + prop + "}"] = _this.mediainfo[prop];
494            } else if (defaults["{mediainfo." + prop + "}"]) {
495                macros["{mediainfo." + prop + "}"] = defaults["{mediainfo." + prop + "}"];
496            } else {
497                macros["{mediainfo." + prop + "}"] = '';
498            }
499        }); // Custom fields in mediainfo
500
501        customFields(this.mediainfo, macros, 'custom_fields');
502        customFields(this.mediainfo, macros, 'customFields'); // Go through all the replacement macros and apply them to the string.
503        // This will replace all occurrences of the replacement macros.
504
505        for (var i in macros) {
506            string = string.split(i).join(uriEncodeIfNeeded(macros[i], uriEncode));
507        } // Page variables
508
509
510        string = string.replace(/{pageVariable\.([^}]+)}/g, function (match, name) {
511            var value;
512            var context = window;
513            var names = name.split('.'); // Iterate down multiple levels of selector without using eval
514            // This makes things like pageVariable.foo.bar work
515
516            for (var _i = 0; _i < names.length; _i++) {
517                if (_i === names.length - 1) {
518                    value = context[names[_i]];
519                } else {
520                    context = context[names[_i]];
521                }
522            }
523
524            var type = typeof value; // Only allow certain types of values. Anything else is probably a mistake.
525
526            if (value === null) {
527                return 'null';
528            } else if (value === undefined) {
529                if (defaults["{pageVariable." + name + "}"]) {
530                    return defaults["{pageVariable." + name + "}"];
531                }
532
533                videojs.log.warn("Page variable \"" + name + "\" not found");
534                return '';
535            } else if (type !== 'string' && type !== 'number' && type !== 'boolean') {
536                videojs.log.warn("Page variable \"" + name + "\" is not a supported type");
537                return '';
538            }
539
540            return uriEncodeIfNeeded(String(value), uriEncode);
541        }); // Replace defaults
542
543        for (var defaultVal in defaults) {
544            string = string.replace(defaultVal, defaults[defaultVal]);
545        }
546
547        return string;
548    }
549
550    /*
551    * This feature allows metadata text tracks to be manipulated once available
552    * @see processMetadataTracks.
553    * It also allows ad implementations to leverage ad cues coming through
554    * text tracks, @see processAdTrack
555    **/
556    var cueTextTracks = {};
557    /*
558    * This feature allows metadata text tracks to be manipulated once they are available,
559    * usually after the 'loadstart' event is observed on the player
560    * @param player A reference to a player
vendor: 9,417 bytes, lines 561-816
561    * @param processMetadataTrack A callback that performs some operations on a
562    * metadata text track
563    **/
564
565    cueTextTracks.processMetadataTracks = function (player, processMetadataTrack) {
566        var tracks = player.textTracks();
567
568        var setModeAndProcess = function setModeAndProcess(track) {
569            if (track.kind === 'metadata') {
570                player.ads.cueTextTracks.setMetadataTrackMode(track);
571                processMetadataTrack(player, track);
572            }
573        }; // Text tracks are available
574
575
576        for (var i = 0; i < tracks.length; i++) {
577            setModeAndProcess(tracks[i]);
578        } // Wait until text tracks are added
579
580
581        tracks.addEventListener('addtrack', function (event) {
582            setModeAndProcess(event.track);
583        });
584    };
585    /*
586    * Sets the track mode to one of 'disabled', 'hidden' or 'showing'
587    * @see https://github.com/videojs/video.js/blob/master/docs/guides/text-tracks.md
588    * Default behavior is to do nothing, @override if this is not desired
589    * @param track The text track to set the mode on
590    */
591
592
593    cueTextTracks.setMetadataTrackMode = function (track) {
594        return;
595    };
596    /*
597    * Determines whether cue is an ad cue and returns the cue data.
598    * @param player A reference to the player
599    * @param cue The full cue object
600    * Returns the given cue by default @override if futher processing is required
601    * @return {Object} a useable ad cue or null if not supported
602    **/
603
604
605    cueTextTracks.getSupportedAdCue = function (player, cue) {
606        return cue;
607    };
608    /*
609    * Defines whether a cue is supported or not, potentially
610    * based on the player settings
611    * @param player A reference to the player
612    * @param cue The cue to be checked
613    * Default behavior is to return true, @override if this is not desired
614    * @return {Boolean}
615    */
616
617
618    cueTextTracks.isSupportedAdCue = function (player, cue) {
619        return true;
620    };
621    /*
622    * Gets the id associated with a cue.
623    * @param cue The cue to extract an ID from
624    * @returns The first occurance of 'id' in the object,
625    * @override if this is not the desired cue id
626    **/
627
628
629    cueTextTracks.getCueId = function (player, cue) {
630        return cue.id;
631    };
632    /*
633    * Checks whether a cue has already been used
634    * @param cueId The Id associated with a cue
635    **/
636
637
638    var cueAlreadySeen = function cueAlreadySeen(player, cueId) {
639        return cueId !== undefined && player.ads.includedCues[cueId];
640    };
641    /*
642    * Indicates that a cue has been used
643    * @param cueId The Id associated with a cue
644    **/
645
646
647    var setCueAlreadySeen = function setCueAlreadySeen(player, cueId) {
648        if (cueId !== undefined && cueId !== '') {
649            player.ads.includedCues[cueId] = true;
650        }
651    };
652    /*
653    * This feature allows ad metadata tracks to be manipulated in ad implementations
654    * @param player A reference to the player
655    * @param cues The set of cues to work with
656    * @param processCue A method that uses a cue to make some
657    * ad request in the ad implementation
658    * @param [cancelAdsHandler] A method that dynamically cancels ads in the ad implementation
659    **/
660
661
662    cueTextTracks.processAdTrack = function (player, cues, processCue, cancelAdsHandler) {
663        player.ads.includedCues = {}; // loop over set of cues
664
665        for (var i = 0; i < cues.length; i++) {
666            var cue = cues[i];
667            var cueData = this.getSupportedAdCue(player, cue); // Exit if this is not a supported cue
668
669            if (!this.isSupportedAdCue(player, cue)) {
670                videojs.log.warn('Skipping as this is not a supported ad cue.', cue);
671                return;
672            } // Continue processing supported cue
673
674
675            var cueId = this.getCueId(player, cue);
676            var startTime = cue.startTime; // Skip ad if cue was already used
677
678            if (cueAlreadySeen(player, cueId)) {
679                videojs.log('Skipping ad already seen with ID ' + cueId);
680                return;
681            } // Optional dynamic ad cancellation
682
683
684            if (cancelAdsHandler) {
685                cancelAdsHandler(player, cueData, cueId, startTime);
686            } // Process cue as an ad cue
687
688
689            processCue(player, cueData, cueId, startTime); // Indicate that this cue has been used
690
691            setCueAlreadySeen(player, cueId);
692        }
693    };
694
695    function initCancelContentPlay(player, debug) {
696        if (debug) {
697            videojs.log('Using cancelContentPlay to block content playback');
698        } // Listen to play events to "cancel" them afterward
699
700
701        player.on('play', cancelContentPlay);
702    }
703    /*
704    This feature makes sure the player is paused during ad loading.
705
706    It does this by pausing the player immediately after a "play" where ads will be requested,
707    then signalling that we should play after the ad is done.
708    */
709
710    function cancelContentPlay() {
711        // this function is in the player's context
712        if (this.ads._shouldBlockPlay === false) {
713            // Only block play if the ad plugin is in a state when content
714            // playback should be blocked. This currently means during
715            // BeforePrerollState and PrerollState.
716            return;
717        } // pause playback so ads can be handled.
718
719
720        if (!this.paused()) {
721            this.ads.debug('Playback was canceled by cancelContentPlay');
722            this.pause();
723        } // When the 'content-playback' state is entered, this will let us know to play.
724        // This is needed if there is no preroll or if it errors, times out, etc.
725
726
727        this.ads._cancelledPlay = true;
728    }
729
730    var obj = {}; // This reference allows videojs to be mocked in unit tests
731    // while still using the available videojs import in the source code
732    // @see obj.testHook
733
734    var videojsReference = videojs;
735    /**
736     * Checks if middleware mediators are available and
737     * can be used on this platform.
738     * Currently we can only use mediators on desktop platforms.
739     */
740
741    obj.isMiddlewareMediatorSupported = function () {
742        if (videojsReference.browser.IS_IOS || videojsReference.browser.IS_ANDROID) {
743            return false;
744        } else if ( // added when middleware was introduced in video.js
745            videojsReference.use && // added when mediators were introduced in video.js
746            videojsReference.middleware && videojsReference.middleware.TERMINATOR) {
747            return true;
748        }
749
750        return false;
751    };
752
753    obj.playMiddleware = function (player) {
754        return {
755            setSource: function setSource(srcObj, next) {
756                next(null, srcObj);
757            },
758            callPlay: function callPlay() {
759                // Block play calls while waiting for an ad, only if this is an
760                // ad supported player
761                if (player.ads && player.ads._shouldBlockPlay === true) {
762                    player.ads.debug('Using playMiddleware to block content playback');
763                    player.ads._playBlocked = true;
764                    return videojsReference.middleware.TERMINATOR;
765                }
766            },
767            play: function play(terminated, playPromise) {
768                if (player.ads && player.ads._playBlocked && terminated) {
769                    player.ads.debug('Play call to Tech was terminated.'); // Trigger play event to match the user's intent to play.
770                    // The call to play on the Tech has been blocked, so triggering
771                    // the event on the Player will not affect the Tech's playback state.
772
773                    player.trigger('play'); // At this point the player has technically started
774
775                    player.addClass('vjs-has-started'); // Reset playBlocked
776
777                    player.ads._playBlocked = false; // Safari issues a pause event when autoplay is blocked but other browsers
778                    // do not, so we send a pause for consistency in those cases. This keeps the
779                    // play button in the correct state if play is rejected.
780                } else if (playPromise && playPromise.catch) {
781                    playPromise.catch(function (e) {
782                        if (e.name === 'NotAllowedError' && !videojs.browser.IS_SAFARI) {
783                            player.trigger('pause');
784                        }
785                    });
786                }
787            }
788        };
789    };
790
791    obj.testHook = function (testVjs) {
792        videojsReference = testVjs;
793    };
794
795    var playMiddleware = obj.playMiddleware,
796        isMiddlewareMediatorSupported = obj.isMiddlewareMediatorSupported;
797    /**
798     * Whether or not this copy of Video.js has the ads plugin.
799     *
800     * @return {boolean}
801     *         If `true`, has the plugin. `false` otherwise.
802     */
803
804    var hasAdsPlugin = function hasAdsPlugin() {
805        // Video.js 6 and 7 have a getPlugin method.
806        if (videojs.getPlugin) {
807            return Boolean(videojs.getPlugin('ads'));
808        } // Video.js 5 does not have a getPlugin method, so check the player prototype.
809
810
811        var Player = videojs.getComponent('Player');
812        return Boolean(Player && Player.prototype.ads);
813    };
814    /**
815     * Register contrib-ads with Video.js, but provide protection for duplicate
816     * copies of the plugin. This could happen if, for example, a stitched ads
817     * plugin and a client-side ads plugin are included simultaneously with their
818     * own copies of contrib-ads.
819     *
820     * If contrib-ads detects a pre-existing duplicate, it will not register
821     * itself.
822     *
823     * Ad plugins using contrib-ads and anticipating that this could come into
824     * effect should verify that the contrib-ads they are using is of a compatible
825     * version.
826     *
827     * @param  {Function} contribAdsPlugin
828     *         The plugin function.
829     *
830     * @return {boolean}
831     *         When `true`, the plugin was registered. When `false`, the plugin
832     *         was not registered.
833     */
834
835
836    function register(contribAdsPlugin) {
837        // If the ads plugin already exists, do not overwrite it.
838        if (hasAdsPlugin(videojs)) {
839            return false;
840        } // Cross-compatibility with Video.js 6/7 and 5.
841
842
843        var registerPlugin = videojs.registerPlugin || videojs.plugin; // Register this plugin with Video.js.
844
845        registerPlugin('ads', contribAdsPlugin); // Register the play middleware with Video.js on script execution,
846        // to avoid a new playMiddleware factory being added for each player.
847        // The `usingContribAdsMiddleware_` flag is used to ensure that we only ever
848        // register the middleware once - despite the ability to de-register and
849        // re-register the plugin itself.
850
851        if (isMiddlewareMediatorSupported() && !videojs.usingContribAdsMiddleware_) {
852            // Register the play middleware
853            videojs.use('*', playMiddleware);
854            videojs.usingContribAdsMiddleware_ = true;
855            videojs.log.debug('Play middleware has been registered with videojs');
856        }
857
858        return true;
859    }
860
861    var States =
862        /*#__PURE__*/
863        function () {
864            function States() {}
865
866            States.getState = function getState(name) {
867                if (!name) {
868                    return;
869                }
870
871                if (States.states_ && States.states_[name]) {
872                    return States.states_[name];
873                }
874            };
875
876            States.registerState = function registerState(name, StateToRegister) {
877                if (typeof name !== 'string' || !name) {
878                    throw new Error("Illegal state name, \"" + name + "\"; must be a non-empty string.");
879                }
880
881                if (!States.states_) {
882                    States.states_ = {};
883                }
884
885                States.states_[name] = StateToRegister;
886                return StateToRegister;
887            };
888
889            return States;
890        }();
891
892    var State =
893        /*#__PURE__*/
894        function () {
895            State._getName = function _getName() {
896                return 'Anonymous State';
897            };
898
899            function State(player) {
900                this.player = player;
901            }
902            /*
903             * This is the only allowed way to perform state transitions. State transitions usually
904             * happen in player event handlers. They can also happen recursively in `init`. They
905             * should _not_ happen in `cleanup`.
906             */
907
908
909            var _proto = State.prototype;
910
911            _proto.transitionTo = function transitionTo(NewState) {
912                var player = this.player; // Since State is an abstract class, this will refer to
913                // the state that is extending this class
914
915                this.cleanup(player);
916                var newState = new NewState(player);
917                player.ads._state = newState;
918                player.ads.debug(this.constructor._getName() + ' -> ' + newState.constructor._getName());
919
920                for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
921                    args[_key - 1] = arguments[_key];
922                }
923
924                newState.init.apply(newState, [player].concat(args));
925            }
926            /*
927             * Implemented by subclasses to provide initialization logic when transitioning
928             * to a new state.
929             */
930            ;
931
vendor: 35,463 bytes, lines 932-1904
932            _proto.init = function init() {}
933            /*
934             * Implemented by subclasses to provide cleanup logic when transitioning
935             * to a new state.
936             */
937            ;
938
939            _proto.cleanup = function cleanup() {}
940            /*
941             * Default event handlers. Different states can override these to provide behaviors.
942             */
943            ;
944
945            _proto.onPlay = function onPlay() {};
946
947            _proto.onPlaying = function onPlaying() {};
948
949            _proto.onEnded = function onEnded() {};
950
951            _proto.onAdEnded = function onAdEnded() {};
952
953            _proto.onAdsReady = function onAdsReady() {
954                videojs.log.warn('Unexpected adsready event');
955            };
956
957            _proto.onAdsError = function onAdsError() {};
958
959            _proto.onAdsCanceled = function onAdsCanceled() {};
960
961            _proto.onAdTimeout = function onAdTimeout() {};
962
963            _proto.onAdStarted = function onAdStarted() {};
964
965            _proto.onContentChanged = function onContentChanged() {};
966
967            _proto.onContentResumed = function onContentResumed() {};
968
969            _proto.onReadyForPostroll = function onReadyForPostroll() {
970                videojs.log.warn('Unexpected readyforpostroll event');
971            };
972
973            _proto.onNoPreroll = function onNoPreroll() {};
974
975            _proto.onNoPostroll = function onNoPostroll() {}
976            /*
977             * Method handlers. Different states can override these to provide behaviors.
978             */
979            ;
980
981            _proto.startLinearAdMode = function startLinearAdMode() {
982                videojs.log.warn('Unexpected startLinearAdMode invocation ' + '(State via ' + this.constructor._getName() + ')');
983            };
984
985            _proto.endLinearAdMode = function endLinearAdMode() {
986                videojs.log.warn('Unexpected endLinearAdMode invocation ' + '(State via ' + this.constructor._getName() + ')');
987            };
988
989            _proto.skipLinearAdMode = function skipLinearAdMode() {
990                videojs.log.warn('Unexpected skipLinearAdMode invocation ' + '(State via ' + this.constructor._getName() + ')');
991            }
992            /*
993             * Overridden by ContentState and AdState. Should not be overriden elsewhere.
994             */
995            ;
996
997            _proto.isAdState = function isAdState() {
998                throw new Error('isAdState unimplemented for ' + this.constructor._getName());
999            }
1000            /*
1001             * Overridden by Preroll and Postroll. Midrolls jump right into the ad break
1002             * so there is no "waiting" state for them.
1003             */
1004            ;
1005
1006            _proto.isWaitingForAdBreak = function isWaitingForAdBreak() {
1007                return false;
1008            }
1009            /*
1010             * Overridden by Preroll, Midroll, and Postroll.
1011             */
1012            ;
1013
1014            _proto.isContentResuming = function isContentResuming() {
1015                return false;
1016            };
1017
1018            _proto.inAdBreak = function inAdBreak() {
1019                return false;
1020            }
1021            /*
1022             * Invoke event handler methods when events come in.
1023             */
1024            ;
1025
1026            _proto.handleEvent = function handleEvent(type) {
1027                var player = this.player;
1028
1029                if (type === 'play') {
1030                    this.onPlay(player);
1031                } else if (type === 'adsready') {
1032                    this.onAdsReady(player);
1033                } else if (type === 'adserror') {
1034                    this.onAdsError(player);
1035                } else if (type === 'adscanceled') {
1036                    this.onAdsCanceled(player);
1037                } else if (type === 'adtimeout') {
1038                    this.onAdTimeout(player);
1039                } else if (type === 'ads-ad-started') {
1040                    this.onAdStarted(player);
1041                } else if (type === 'contentchanged') {
1042                    this.onContentChanged(player);
1043                } else if (type === 'contentresumed') {
1044                    this.onContentResumed(player);
1045                } else if (type === 'readyforpostroll') {
1046                    this.onReadyForPostroll(player);
1047                } else if (type === 'playing') {
1048                    this.onPlaying(player);
1049                } else if (type === 'ended') {
1050                    this.onEnded(player);
1051                } else if (type === 'nopreroll') {
1052                    this.onNoPreroll(player);
1053                } else if (type === 'nopostroll') {
1054                    this.onNoPostroll(player);
1055                } else if (type === 'adended') {
1056                    this.onAdEnded(player);
1057                }
1058            };
1059
1060            return State;
1061        }();
1062
1063    States.registerState('State', State);
1064
1065    function _inheritsLoose(subClass, superClass) {
1066        subClass.prototype = Object.create(superClass.prototype);
1067        subClass.prototype.constructor = subClass;
1068        subClass.__proto__ = superClass;
1069    }
1070
1071    /*
1072     * This class contains logic for all ads, be they prerolls, midrolls, or postrolls.
1073     * Primarily, this involves handling startLinearAdMode and endLinearAdMode.
1074     * It also handles content resuming.
1075     */
1076
1077    var AdState =
1078        /*#__PURE__*/
1079        function (_State) {
1080            _inheritsLoose(AdState, _State);
1081
1082            function AdState(player) {
1083                var _this;
1084
1085                _this = _State.call(this, player) || this;
1086                _this.contentResuming = false;
1087                _this.waitingForAdBreak = false;
1088                return _this;
1089            }
1090            /*
1091             * Overrides State.isAdState
1092             */
1093
1094
1095            var _proto = AdState.prototype;
1096
1097            _proto.isAdState = function isAdState() {
1098                return true;
1099            }
1100            /*
1101             * We end the content-resuming process on the playing event because this is the exact
1102             * moment that content playback is no longer blocked by ads.
1103             */
1104            ;
1105
1106            _proto.onPlaying = function onPlaying() {
1107                var ContentPlayback = States.getState('ContentPlayback');
1108
1109                if (this.contentResuming) {
1110                    this.transitionTo(ContentPlayback);
1111                }
1112            }
1113            /*
1114             * If the ad plugin does not result in a playing event when resuming content after an
1115             * ad, they should instead trigger a contentresumed event to signal that content should
1116             * resume. The main use case for this is when ads are stitched into the content video.
1117             */
1118            ;
1119
1120            _proto.onContentResumed = function onContentResumed() {
1121                var ContentPlayback = States.getState('ContentPlayback');
1122
1123                if (this.contentResuming) {
1124                    this.transitionTo(ContentPlayback);
1125                }
1126            }
1127            /*
1128             * Check if we are in an ad state waiting for the ad plugin to start
1129             * an ad break.
1130             */
1131            ;
1132
1133            _proto.isWaitingForAdBreak = function isWaitingForAdBreak() {
1134                return this.waitingForAdBreak;
1135            }
1136            /*
1137             * Allows you to check if content is currently resuming after an ad break.
1138             */
1139            ;
1140
1141            _proto.isContentResuming = function isContentResuming() {
1142                return this.contentResuming;
1143            }
1144            /*
1145             * Allows you to check if an ad break is in progress.
1146             */
1147            ;
1148
1149            _proto.inAdBreak = function inAdBreak() {
1150                return this.player.ads._inLinearAdMode === true;
1151            };
1152
1153            return AdState;
1154        }(State);
1155
1156    States.registerState('AdState', AdState);
1157
1158    var ContentState =
1159        /*#__PURE__*/
1160        function (_State) {
1161            _inheritsLoose(ContentState, _State);
1162
1163            function ContentState() {
1164                return _State.apply(this, arguments) || this;
1165            }
1166
1167            var _proto = ContentState.prototype;
1168
1169            /*
1170             * Overrides State.isAdState
1171             */
1172            _proto.isAdState = function isAdState() {
1173                return false;
1174            }
1175            /*
1176             * Source change sends you back to preroll checks. contentchanged does not
1177             * fire during ad breaks, so we don't need to worry about that.
1178             */
1179            ;
1180
1181            _proto.onContentChanged = function onContentChanged(player) {
1182                var BeforePreroll = States.getState('BeforePreroll');
1183                var Preroll = States.getState('Preroll');
1184                player.ads.debug('Received contentchanged event (ContentState)');
1185
1186                if (player.paused()) {
1187                    this.transitionTo(BeforePreroll);
1188                } else {
1189                    this.transitionTo(Preroll, false);
1190                    player.pause();
1191                    player.ads._pausedOnContentupdate = true;
1192                }
1193            };
1194
1195            return ContentState;
1196        }(State);
1197
1198    States.registerState('ContentState', ContentState);
1199
1200    var ContentState$1 = States.getState('ContentState');
1201
1202    var AdsDone =
1203        /*#__PURE__*/
1204        function (_ContentState) {
1205            _inheritsLoose(AdsDone, _ContentState);
1206
1207            function AdsDone() {
1208                return _ContentState.apply(this, arguments) || this;
1209            }
1210
1211            /*
1212             * Allows state name to be logged even after minification.
1213             */
1214            AdsDone._getName = function _getName() {
1215                return 'AdsDone';
1216            }
1217            /*
1218             * For state transitions to work correctly, initialization should
1219             * happen here, not in a constructor.
1220             */
1221            ;
1222
1223            var _proto = AdsDone.prototype;
1224
1225            _proto.init = function init(player) {
1226                // From now on, `ended` events won't be redispatched
1227                player.ads._contentHasEnded = true;
1228                // Do not trigger ended event as it's causing issues on next recommended flow
1229                // and for now we do not have a post roll ad
1230                // player.trigger('ended');
1231            }
1232            /*
1233             * Midrolls do not play after ads are done.
1234             */
1235            ;
1236
1237            _proto.startLinearAdMode = function startLinearAdMode() {
1238                videojs.log.warn('Unexpected startLinearAdMode invocation (AdsDone)');
1239            };
1240
1241            return AdsDone;
1242        }(ContentState$1);
1243
1244    States.registerState('AdsDone', AdsDone);
1245
1246    /*
1247    The snapshot feature is responsible for saving the player state before an ad, then
1248    restoring the player state after an ad.
1249    */
1250    var tryToResumeTimeout_;
1251    /*
1252     * Returns an object that captures the portions of player state relevant to
1253     * video playback. The result of this function can be passed to
1254     * restorePlayerSnapshot with a player to return the player to the state it
1255     * was in when this function was invoked.
1256     * @param {Object} player The videojs player object
1257     */
1258
1259    function getPlayerSnapshot(player) {
1260        var currentTime;
1261
1262        if (videojs.browser.IS_IOS && player.ads.isLive(player)) {
1263            // Record how far behind live we are
1264            if (player.seekable().length > 0) {
1265                currentTime = player.currentTime() - player.seekable().end(0);
1266            } else {
1267                currentTime = player.currentTime();
1268            }
1269        } else {
1270            currentTime = player.currentTime();
1271        }
1272
1273        var tech = player.$('.vjs-tech');
1274        var tracks = player.textTracks ? player.textTracks() : [];
1275        var suppressedTracks = [];
1276        var snapshotObject = {
1277            ended: player.ended(),
1278            currentSrc: player.currentSrc(),
1279            sources: player.currentSources(),
1280            src: player.tech_.src(),
1281            currentTime: currentTime,
1282            type: player.currentType()
1283        };
1284
1285        if (tech) {
1286            snapshotObject.style = tech.getAttribute('style');
1287        }
1288
1289        for (var i = 0; i < tracks.length; i++) {
1290            var track = tracks[i];
1291            suppressedTracks.push({
1292                track: track,
1293                mode: track.mode
1294            });
1295            track.mode = 'disabled';
1296        }
1297
1298        snapshotObject.suppressedTracks = suppressedTracks;
1299        return snapshotObject;
1300    }
1301    /*
1302     * Attempts to modify the specified player so that its state is equivalent to
1303     * the state of the snapshot.
1304     * @param {Object} player - the videojs player object
1305     * @param {Object} snapshotObject - the player state to apply
1306     */
1307
1308    function restorePlayerSnapshot(player, callback) {
1309        var snapshotObject = player.ads.snapshot;
1310
1311        if (callback === undefined) {
1312            callback = function callback() {};
1313        }
1314
1315        if (player.ads.disableNextSnapshotRestore === true) {
1316            player.ads.disableNextSnapshotRestore = false;
1317            delete player.ads.snapshot;
1318            callback();
1319            return;
1320        } // The playback tech
1321
1322
1323        var tech = player.$('.vjs-tech'); // the number of[ remaining attempts to restore the snapshot
1324
1325        var attempts = 20;
1326        var suppressedTracks = snapshotObject.suppressedTracks;
1327        var trackSnapshot;
1328
1329        var restoreTracks = function restoreTracks() {
1330            for (var i = 0; i < suppressedTracks.length; i++) {
1331                trackSnapshot = suppressedTracks[i];
1332                trackSnapshot.track.mode = trackSnapshot.mode;
1333            }
1334        }; // Finish restoring the playback state.
1335        // This only happens if the content video element was reused for ad playback.
1336
1337
1338        var resume = function resume() {
1339            var currentTime; // Live video on iOS has special logic to try to seek to the right place after
1340            // an ad.
1341
1342            if (videojs.browser.IS_IOS && player.ads.isLive(player)) {
1343                if (snapshotObject.currentTime < 0) {
1344                    // Playback was behind real time, so seek backwards to match
1345                    if (player.seekable().length > 0) {
1346                        currentTime = player.seekable().end(0) + snapshotObject.currentTime;
1347                    } else {
1348                        currentTime = player.currentTime();
1349                    }
1350
1351                    player.currentTime(currentTime);
1352                } // iOS live play after restore if player was paused (would not be paused if
1353                // ad played muted behind ad)
1354
1355
1356                if (player.paused()) {
1357                    var playPromise = player.play();
1358
1359                    if (playPromise && playPromise.catch) {
1360                        playPromise.catch(function (error) {
1361                            videojs.log.warn('Play promise rejected in IOS snapshot resume', error);
1362                        });
1363                    }
1364                } // Restore the video position after an ad.
1365                // We check snapshotObject.ended because the content starts at the beginning again
1366                // after being restored.
1367
1368            } else if (snapshotObject.ended) {
1369                // For postrolls, seek to the player's current duration.
1370                // It could be different from the snapshot's currentTime due to
1371                // inaccuracy in HLS.
1372                player.currentTime(player.duration());
1373            } else {
1374                // Prerolls and midrolls, just seek to the player time before the ad.
1375                player.currentTime(snapshotObject.currentTime);
1376
1377                var _playPromise = player.play();
1378
1379                if (_playPromise && _playPromise.catch) {
1380                    _playPromise.catch(function (error) {
1381                        videojs.log.warn('Play promise rejected in snapshot resume', error);
1382                    });
1383                }
1384            } // if we added autoplay to force content loading on iOS, remove it now
1385            // that it has served its purpose
1386
1387
1388            if (player.ads.shouldRemoveAutoplay_) {
1389                player.autoplay(false);
1390                player.ads.shouldRemoveAutoplay_ = false;
1391            }
1392        }; // Determine if the video element has loaded enough of the snapshot source
1393        // to be ready to apply the rest of the state.
1394        // This only happens if the content video element was reused for ad playback.
1395
1396
1397        var tryToResume = function tryToResume() {
1398            // tryToResume can either have been called through the `contentcanplay`
1399            // event or fired through setTimeout.
1400            // When tryToResume is called, we should make sure to clear out the other
1401            // way it could've been called by removing the listener and clearing out
1402            // the timeout.
1403            player.off('contentcanplay', tryToResume);
1404
1405            if (tryToResumeTimeout_) {
1406                player.clearTimeout(tryToResumeTimeout_);
1407            } // Tech may have changed depending on the differences in sources of the
1408            // original video and that of the ad
1409
1410
1411            tech = player.el().querySelector('.vjs-tech');
1412
1413            if (tech.readyState > 1) {
1414                // some browsers and media aren't "seekable".
1415                // readyState greater than 1 allows for seeking without exceptions
1416                return resume();
1417            }
1418
1419            if (tech.seekable === undefined) {
1420                // if the tech doesn't expose the seekable time ranges, try to
1421                // resume playback immediately
1422                return resume();
1423            }
1424
1425            if (tech.seekable.length > 0) {
1426                // if some period of the video is seekable, resume playback
1427                return resume();
1428            } // delay a bit and then check again unless we're out of attempts
1429
1430
1431            if (attempts--) {
1432                player.setTimeout(tryToResume, 50);
1433            } else {
1434                try {
1435                    resume();
1436                } catch (e) {
1437                    videojs.log.warn('Failed to resume the content after an advertisement', e);
1438                }
1439            }
1440        };
1441
1442        if ('style' in snapshotObject) {
1443            // overwrite all css style properties to restore state precisely
1444            tech.setAttribute('style', snapshotObject.style || '');
1445        } // Determine whether the player needs to be restored to its state
1446        // before ad playback began. With a custom ad display or burned-in
1447        // ads, the content player state hasn't been modified and so no
1448        // restoration is required
1449
1450
1451        if (player.ads.videoElementRecycled()) {
1452            // Snapshot restore is done, so now we're really finished.
1453            player.one('resumeended', function () {
1454                delete player.ads.snapshot;
1455                callback();
1456            }); // on ios7, fiddling with textTracks too early will cause safari to crash
1457
1458            player.one('contentloadedmetadata', restoreTracks); // adding autoplay guarantees that Safari will load the content so we can
1459            // seek back to the correct time after ads
1460
1461            if (videojs.browser.IS_IOS && !player.autoplay()) {
1462                player.autoplay(true); // if we get here, the player was not originally configured to autoplay,
1463                // so we should remove it after it has served its purpose
1464
1465                player.ads.shouldRemoveAutoplay_ = true;
1466            } // if the src changed for ad playback, reset it
1467
1468
1469            player.src(snapshotObject.sources); // and then resume from the snapshots time once the original src has loaded
1470            // in some browsers (firefox) `canplay` may not fire correctly.
1471            // Reace the `canplay` event with a timeout.
1472
1473            player.one('contentcanplay', tryToResume);
1474            tryToResumeTimeout_ = player.setTimeout(tryToResume, 2000);
1475        } else {
1476            // if we didn't change the src, just restore the tracks
1477            restoreTracks(); // we don't need to check snapshotObject.ended here because the content video
1478            // element wasn't recycled
1479
1480            if (!player.ended()) {
1481                // the src didn't change and this wasn't a postroll
1482                // just resume playback at the current time.
1483                var playPromise = player.play();
1484
1485                if (playPromise && playPromise.catch) {
1486                    playPromise.catch(function (error) {
1487                        videojs.log.warn('Play promise rejected in snapshot restore', error);
1488                    });
1489                }
1490            } // snapshot restore is complete
1491
1492
1493            delete player.ads.snapshot;
1494            callback();
1495        }
1496    }
1497
1498    /*
1499     * Encapsulates logic for starting and ending ad breaks. An ad break
1500     * is the time between startLinearAdMode and endLinearAdMode. The ad
1501     * plugin may play 0 or more ads during this time.
1502     */
1503
1504    function start(player) {
1505        player.ads.debug('Starting ad break');
1506        player.ads._inLinearAdMode = true; // No longer does anything, used to move us to ad-playback
1507
1508        player.trigger('adstart'); // Capture current player state snapshot
1509
1510        if (player.ads.shouldTakeSnapshots()) {
1511            player.ads.snapshot = getPlayerSnapshot(player);
1512        } // Mute the player behind the ad
1513
1514
1515        if (player.ads.shouldPlayContentBehindAd(player)) {
1516            player.ads.preAdVolume_ = player.volume();
1517            player.volume(0);
1518        } // Add css to the element to indicate and ad is playing.
1519
1520
1521        player.addClass('vjs-ad-playing'); // We should remove the vjs-live class if it has been added in order to
1522        // show the adprogress control bar on Android devices for falsely
1523        // determined LIVE videos due to the duration incorrectly reported as Infinity
1524
1525        if (player.hasClass('vjs-live')) {
1526            player.removeClass('vjs-live');
1527        } // This removes the native poster so the ads don't show the content
1528        // poster if content element is reused for ad playback.
1529
1530
1531        player.ads.removeNativePoster();
1532    }
1533
1534    function end(player, callback) {
1535        player.ads.debug('Ending ad break');
1536
1537        if (callback === undefined) {
1538            callback = function callback() {};
1539        }
1540
1541        player.ads.adType = null;
1542        player.ads._inLinearAdMode = false; // Signals the end of the ad break to anyone listening.
1543
1544        player.trigger('adend');
1545        player.removeClass('vjs-ad-playing'); // We should add the vjs-live class back if the video is a LIVE video
1546        // If we dont do this, then for a LIVE Video, we will get an incorrect
1547        // styled control, which displays the time for the video
1548
1549        if (player.ads.isLive(player)) {
1550            player.addClass('vjs-live');
1551        } // Restore snapshot
1552
1553
1554        if (player.ads.shouldTakeSnapshots()) {
1555            restorePlayerSnapshot(player, callback); // Reset the volume to pre-ad levels
1556        } else {
1557            player.volume(player.ads.preAdVolume_);
1558            callback();
1559        }
1560    }
1561
1562    var obj$1 = {
1563        start: start,
1564        end: end
1565    };
1566
1567    var AdState$1 = States.getState('AdState');
1568    /*
1569     * This state encapsulates waiting for prerolls, preroll playback, and
1570     * content restoration after a preroll.
1571     */
1572
1573    var Preroll =
1574        /*#__PURE__*/
1575        function (_AdState) {
1576            _inheritsLoose(Preroll, _AdState);
1577
1578            function Preroll() {
1579                return _AdState.apply(this, arguments) || this;
1580            }
1581
1582            /*
1583             * Allows state name to be logged even after minification.
1584             */
1585            Preroll._getName = function _getName() {
1586                return 'Preroll';
1587            }
1588            /*
1589             * For state transitions to work correctly, initialization should
1590             * happen here, not in a constructor.
1591             */
1592            ;
1593
1594            var _proto = Preroll.prototype;
1595
1596            _proto.init = function init(player, adsReady, shouldResumeToContent) {
1597                this.waitingForAdBreak = true; // Loading spinner from now until ad start or end of ad break.
1598
1599                player.addClass('vjs-ad-loading'); // If adserror, adscanceled, nopreroll or skipLinearAdMode already
1600                // ocurred, resume to content immediately
1601
1602                if (shouldResumeToContent || player.ads.nopreroll_) {
1603                    return this.resumeAfterNoPreroll(player);
1604                } // Determine preroll timeout based on plugin settings
1605
1606
1607                var timeout = player.ads.settings.timeout;
1608
1609                if (typeof player.ads.settings.prerollTimeout === 'number') {
1610                    timeout = player.ads.settings.prerollTimeout;
1611                } // Start the clock ticking for ad timeout
1612
1613
1614                this._timeout = player.setTimeout(function () {
1615                    player.trigger('adtimeout');
1616                }, timeout); // If adsready already happened, lets get started. Otherwise,
1617                // wait until onAdsReady.
1618
1619                if (adsReady) {
1620                    this.handleAdsReady();
1621                } else {
1622                    this.adsReady = false;
1623                }
1624            }
1625            /*
1626             * Adsready event after play event.
1627             */
1628            ;
1629
1630            _proto.onAdsReady = function onAdsReady(player) {
1631                if (!player.ads.inAdBreak()) {
1632                    player.ads.debug('Received adsready event (Preroll)');
1633                    this.handleAdsReady();
1634                } else {
1635                    videojs.log.warn('Unexpected adsready event (Preroll)');
1636                }
1637            }
1638            /*
1639             * Ad plugin is ready. Let's get started on this preroll.
1640             */
1641            ;
1642
1643            _proto.handleAdsReady = function handleAdsReady() {
1644                this.adsReady = true;
1645                this.readyForPreroll();
1646            }
1647            /*
1648             * Helper to call a callback only after a loadstart event.
1649             * If we start content or ads before loadstart, loadstart
1650             * will not be prefixed correctly.
1651             */
1652            ;
1653
1654            _proto.afterLoadStart = function afterLoadStart(callback) {
1655                var player = this.player;
1656
1657                if (player.ads._hasThereBeenALoadStartDuringPlayerLife) {
1658                    callback();
1659                } else {
1660                    player.ads.debug('Waiting for loadstart...');
1661                    player.one('loadstart', function () {
1662                        player.ads.debug('Received loadstart event');
1663                        callback();
1664                    });
1665                }
1666            }
1667            /*
1668             * If there is no preroll, play content instead.
1669             */
1670            ;
1671
1672            _proto.noPreroll = function noPreroll() {
1673                var _this = this;
1674
1675                this.afterLoadStart(function () {
1676                    _this.player.ads.debug('Skipping prerolls due to nopreroll event (Preroll)');
1677
1678                    _this.resumeAfterNoPreroll(_this.player);
1679                });
1680            }
1681            /*
1682             * Fire the readyforpreroll event. If loadstart hasn't happened yet,
1683             * wait until loadstart first.
1684             */
1685            ;
1686
1687            _proto.readyForPreroll = function readyForPreroll() {
1688                var player = this.player;
1689                this.afterLoadStart(function () {
1690                    player.ads.debug('Triggered readyforpreroll event (Preroll)');
1691                    player.trigger('readyforpreroll');
1692                });
1693            }
1694            /*
1695             * adscanceled cancels all ads for the source. Play content now.
1696             */
1697            ;
1698
1699            _proto.onAdsCanceled = function onAdsCanceled(player) {
1700                var _this2 = this;
1701
1702                player.ads.debug('adscanceled (Preroll)');
1703                this.afterLoadStart(function () {
1704                    _this2.resumeAfterNoPreroll(player);
1705                });
1706            }
1707            /*
1708             * An ad error occured. Play content instead.
1709             */
1710            ;
1711
1712            _proto.onAdsError = function onAdsError(player) {
1713                var _this3 = this;
1714
1715                videojs.log('adserror (Preroll)'); // In the future, we may not want to do this automatically.
1716                // Ad plugins should be able to choose to continue the ad break
1717                // if there was an error.
1718
1719                if (this.inAdBreak()) {
1720                    player.ads.endLinearAdMode();
1721                } else {
1722                    this.afterLoadStart(function () {
1723                        _this3.resumeAfterNoPreroll(player);
1724                    });
1725                }
1726            }
1727            /*
1728             * Ad plugin invoked startLinearAdMode, the ad break starts now.
1729             */
1730            ;
1731
1732            _proto.startLinearAdMode = function startLinearAdMode() {
1733                var player = this.player;
1734
1735                if (this.adsReady && !player.ads.inAdBreak() && !this.isContentResuming()) {
1736                    this.clearTimeout(player);
1737                    player.ads.adType = 'preroll';
1738                    this.waitingForAdBreak = false;
1739                    obj$1.start(player); // We don't need to block play calls anymore
1740
1741                    player.ads._shouldBlockPlay = false;
1742                } else {
1743                    videojs.log.warn('Unexpected startLinearAdMode invocation (Preroll)');
1744                }
1745            }
1746            /*
1747             * An ad has actually started playing.
1748             * Remove the loading spinner.
1749             */
1750            ;
1751
1752            _proto.onAdStarted = function onAdStarted(player) {
1753                player.removeClass('vjs-ad-loading');
1754            }
1755            /*
1756             * Ad plugin invoked endLinearAdMode, the ad break ends now.
1757             */
1758            ;
1759
1760            _proto.endLinearAdMode = function endLinearAdMode() {
1761                var player = this.player;
1762
1763                if (this.inAdBreak()) {
1764                    player.removeClass('vjs-ad-loading');
1765                    player.addClass('vjs-ad-content-resuming');
1766                    this.contentResuming = true;
1767                    obj$1.end(player);
1768                }
1769            }
1770            /*
1771             * Ad skipped by ad plugin. Play content instead.
1772             */
1773            ;
1774
1775            _proto.skipLinearAdMode = function skipLinearAdMode() {
1776                var _this4 = this;
1777
1778                var player = this.player;
1779
1780                if (player.ads.inAdBreak() || this.isContentResuming()) {
1781                    videojs.log.warn('Unexpected skipLinearAdMode invocation');
1782                } else {
1783                    this.afterLoadStart(function () {
1784                        player.trigger('adskip');
1785                        player.ads.debug('skipLinearAdMode (Preroll)');
1786
1787                        _this4.resumeAfterNoPreroll(player);
1788                    });
1789                }
1790            }
1791            /*
1792             * Prerolls took too long! Play content instead.
1793             */
1794            ;
1795
1796            _proto.onAdTimeout = function onAdTimeout(player) {
1797                var _this5 = this;
1798
1799                this.afterLoadStart(function () {
1800                    player.ads.debug('adtimeout (Preroll)');
1801
1802                    _this5.resumeAfterNoPreroll(player);
1803                });
1804            }
1805            /*
1806             * Check if nopreroll event was too late before handling it.
1807             */
1808            ;
1809
1810            _proto.onNoPreroll = function onNoPreroll(player) {
1811                if (player.ads.inAdBreak() || this.isContentResuming()) {
1812                    videojs.log.warn('Unexpected nopreroll event (Preroll)');
1813                } else {
1814                    this.noPreroll();
1815                }
1816            };
1817
1818            _proto.resumeAfterNoPreroll = function resumeAfterNoPreroll(player) {
1819                // Resume to content and unblock play as there is no preroll ad
1820                this.contentResuming = true;
1821                player.ads._shouldBlockPlay = false;
1822                this.cleanupPartial(player); // Play the content if we had requested play or we paused on 'contentupdate'
1823                // and we haven't played yet. This happens if there was no preroll or if it
1824                // errored, timed out, etc. Otherwise snapshot restore would play.
1825
1826                if (player.paused() && (player.ads._playRequested || player.ads._pausedOnContentupdate)) {
1827                    var playPromise = player.play();
1828
1829                    if (playPromise && playPromise.then) {
1830                        playPromise.then(null, function (e) {});
1831                    }
1832                }
1833            }
1834            /*
1835             * Cleanup timeouts and spinner.
1836             */
1837            ;
1838
1839            _proto.cleanup = function cleanup(player) {
1840                if (!player.ads._hasThereBeenALoadStartDuringPlayerLife) {
1841                    videojs.log.warn('Leaving Preroll state before loadstart event can cause issues.');
1842                }
1843
1844                this.cleanupPartial(player);
1845            }
1846            /*
1847             * Performs cleanup tasks without depending on a state transition. This is
1848             * used mainly in cases where a preroll failed.
1849             */
1850            ;
1851
1852            _proto.cleanupPartial = function cleanupPartial(player) {
1853                player.removeClass('vjs-ad-loading');
1854                player.removeClass('vjs-ad-content-resuming');
1855                this.clearTimeout(player);
1856            }
1857            /*
1858             * Clear the preroll timeout and nulls out the pointer.
1859             */
1860            ;
1861
1862            _proto.clearTimeout = function clearTimeout(player) {
1863                player.clearTimeout(this._timeout);
1864                this._timeout = null;
1865            };
1866
1867            return Preroll;
1868        }(AdState$1);
1869
1870    States.registerState('Preroll', Preroll);
1871
1872    var ContentState$2 = States.getState('ContentState');
1873    /*
1874     * This is the initial state for a player with an ad plugin. Normally, it remains in this
1875     * state until a "play" event is seen. After that, we enter the Preroll state to check for
1876     * prerolls. This happens regardless of whether or not any prerolls ultimately will play.
1877     * Errors and other conditions may lead us directly from here to ContentPlayback.
1878     */
1879
1880    var BeforePreroll =
1881        /*#__PURE__*/
1882        function (_ContentState) {
1883            _inheritsLoose(BeforePreroll, _ContentState);
1884
1885            function BeforePreroll() {
1886                return _ContentState.apply(this, arguments) || this;
1887            }
1888
1889            /*
1890             * Allows state name to be logged even after minification.
1891             */
1892            BeforePreroll._getName = function _getName() {
1893                return 'BeforePreroll';
1894            }
1895            /*
1896             * For state transitions to work correctly, initialization should
1897             * happen here, not in a constructor.
1898             */
1899            ;
1900
1901            var _proto = BeforePreroll.prototype;
1902
1903            _proto.init = function init(player) {
1904                this.adsReady = false;
1905                this.shouldResumeToContent = false; // Content playback should be blocked until we are done
1906                // playing ads or we know there are no ads to play
1907
1908                player.ads._shouldBlockPlay = true;
1909            }
1910            /*
1911             * The ad plugin may trigger adsready before the play request. If so,
1912             * we record that adsready already happened so the Preroll state will know.
1913             */
1914            ;
1915
1916            _proto.onAdsReady = function onAdsReady(player) {
1917                player.ads.debug('Received adsready event (BeforePreroll)');
1918                this.adsReady = true;
1919            }
1920            /*
1921             * Ad mode officially begins on the play request, because at this point
1922             * content playback is blocked by the ad plugin.
1923             */
1924            ;
1925
1926            _proto.onPlay = function onPlay(player) {
1927                var Preroll = States.getState('Preroll');
1928                player.ads.debug('Received play event (BeforePreroll)'); // Check for prerolls
1929
1930                this.transitionTo(Preroll, this.adsReady, this.shouldResumeToContent);
1931            }
1932            /*
1933             * All ads for the entire video are canceled.
1934             */
1935            ;
1936
1937            _proto.onAdsCanceled = function onAdsCanceled(player) {
1938                player.ads.debug('adscanceled (BeforePreroll)');
1939                this.shouldResumeToContent = true;
1940            }
1941            /*
1942             * An ad error occured. Play content instead.
1943             */
1944            ;
1945
1946            _proto.onAdsError = function onAdsError() {
1947                this.player.ads.debug('adserror (BeforePreroll)');
1948                this.shouldResumeToContent = true;
1949            }
1950            /*
1951             * If there is no preroll, don't wait for a play event to move forward.
1952             */
1953            ;
1954
1955            _proto.onNoPreroll = function onNoPreroll() {
1956                this.player.ads.debug('Skipping prerolls due to nopreroll event (BeforePreroll)');
1957                this.shouldResumeToContent = true;
1958            }
1959            /*
vendor: 28,175 bytes, lines 1960-2687
1960             * Prerolls skipped by ad plugin. Play content instead.
1961             */
1962            ;
1963
1964            _proto.skipLinearAdMode = function skipLinearAdMode() {
1965                var player = this.player;
1966                player.trigger('adskip');
1967                player.ads.debug('skipLinearAdMode (BeforePreroll)');
1968                this.shouldResumeToContent = true;
1969            };
1970
1971            _proto.onContentChanged = function onContentChanged() {
1972                this.init(this.player);
1973            };
1974
1975            return BeforePreroll;
1976        }(ContentState$2);
1977
1978    States.registerState('BeforePreroll', BeforePreroll);
1979
1980    var AdState$2 = States.getState('AdState');
1981
1982    var Midroll =
1983        /*#__PURE__*/
1984        function (_AdState) {
1985            _inheritsLoose(Midroll, _AdState);
1986
1987            function Midroll() {
1988                return _AdState.apply(this, arguments) || this;
1989            }
1990
1991            /*
1992             * Allows state name to be logged even after minification.
1993             */
1994            Midroll._getName = function _getName() {
1995                return 'Midroll';
1996            }
1997            /*
1998             * Midroll breaks happen when the ad plugin calls startLinearAdMode,
1999             * which can happen at any time during content playback.
2000             */
2001            ;
2002
2003            var _proto = Midroll.prototype;
2004
2005            _proto.init = function init(player) {
2006                player.ads.adType = 'midroll';
2007                obj$1.start(player);
2008                player.addClass('vjs-ad-loading');
2009            }
2010            /*
2011             * An ad has actually started playing.
2012             * Remove the loading spinner.
2013             */
2014            ;
2015
2016            _proto.onAdStarted = function onAdStarted(player) {
2017                player.removeClass('vjs-ad-loading');
2018            }
2019            /*
2020             * Midroll break is done.
2021             */
2022            ;
2023
2024            _proto.endLinearAdMode = function endLinearAdMode() {
2025                var player = this.player;
2026
2027                if (this.inAdBreak()) {
2028                    this.contentResuming = true;
2029                    player.addClass('vjs-ad-content-resuming');
2030                    player.removeClass('vjs-ad-loading');
2031                    obj$1.end(player);
2032                }
2033            }
2034            /*
2035             * End midroll break if there is an error.
2036             */
2037            ;
2038
2039            _proto.onAdsError = function onAdsError(player) {
2040                // In the future, we may not want to do this automatically.
2041                // Ad plugins should be able to choose to continue the ad break
2042                // if there was an error.
2043                if (this.inAdBreak()) {
2044                    player.ads.endLinearAdMode();
2045                }
2046            }
2047            /*
2048             * Cleanup CSS classes.
2049             */
2050            ;
2051
2052            _proto.cleanup = function cleanup(player) {
2053                player.removeClass('vjs-ad-loading');
2054                player.removeClass('vjs-ad-content-resuming');
2055            };
2056
2057            return Midroll;
2058        }(AdState$2);
2059
2060    States.registerState('Midroll', Midroll);
2061
2062    var AdState$3 = States.getState('AdState');
2063
2064    var Postroll =
2065        /*#__PURE__*/
2066        function (_AdState) {
2067            _inheritsLoose(Postroll, _AdState);
2068
2069            function Postroll() {
2070                return _AdState.apply(this, arguments) || this;
2071            }
2072
2073            /*
2074             * Allows state name to be logged even after minification.
2075             */
2076            Postroll._getName = function _getName() {
2077                return 'Postroll';
2078            }
2079            /*
2080             * For state transitions to work correctly, initialization should
2081             * happen here, not in a constructor.
2082             */
2083            ;
2084
2085            var _proto = Postroll.prototype;
2086
2087            _proto.init = function init(player) {
2088                this.waitingForAdBreak = true; // Legacy name that now simply means "handling postrolls".
2089
2090                player.ads._contentEnding = true; // Start postroll process.
2091
2092                if (!player.ads.nopostroll_) {
2093                    player.addClass('vjs-ad-loading'); // Determine postroll timeout based on plugin settings
2094
2095                    var timeout = player.ads.settings.timeout;
2096
2097                    if (typeof player.ads.settings.postrollTimeout === 'number') {
2098                        timeout = player.ads.settings.postrollTimeout;
2099                    }
2100
2101                    this._postrollTimeout = player.setTimeout(function () {
2102                        player.trigger('adtimeout');
2103                    }, timeout); // No postroll, ads are done
2104                } else {
2105                    this.resumeContent(player);
2106                    var AdsDone = States.getState('AdsDone');
2107                    this.transitionTo(AdsDone);
2108                }
2109            }
2110            /*
2111             * Start the postroll if it's not too late.
2112             */
2113            ;
2114
2115            _proto.startLinearAdMode = function startLinearAdMode() {
2116                var player = this.player;
2117
2118                if (!player.ads.inAdBreak() && !this.isContentResuming()) {
2119                    player.ads.adType = 'postroll';
2120                    player.clearTimeout(this._postrollTimeout);
2121                    this.waitingForAdBreak = false;
2122                    obj$1.start(player);
2123                } else {
2124                    videojs.log.warn('Unexpected startLinearAdMode invocation (Postroll)');
2125                }
2126            }
2127            /*
2128             * An ad has actually started playing.
2129             * Remove the loading spinner.
2130             */
2131            ;
2132
2133            _proto.onAdStarted = function onAdStarted(player) {
2134                player.removeClass('vjs-ad-loading');
2135            }
2136            /*
2137             * Ending a postroll triggers the ended event.
2138             */
2139            ;
2140
2141            _proto.endLinearAdMode = function endLinearAdMode() {
2142                var _this = this;
2143
2144                var player = this.player;
2145                var AdsDone = States.getState('AdsDone');
2146
2147                if (this.inAdBreak()) {
2148                    player.removeClass('vjs-ad-loading');
2149                    this.resumeContent(player);
2150                    obj$1.end(player, function () {
2151                        _this.transitionTo(AdsDone);
2152                    });
2153                }
2154            }
2155            /*
2156             * Postroll skipped, time to clean up.
2157             */
2158            ;
2159
2160            _proto.skipLinearAdMode = function skipLinearAdMode() {
2161                var player = this.player;
2162
2163                if (player.ads.inAdBreak() || this.isContentResuming()) {
2164                    videojs.log.warn('Unexpected skipLinearAdMode invocation');
2165                } else {
2166                    player.ads.debug('Postroll abort (skipLinearAdMode)');
2167                    player.trigger('adskip');
2168                    this.abort(player);
2169                }
2170            }
2171            /*
2172             * Postroll timed out, time to clean up.
2173             */
2174            ;
2175
2176            _proto.onAdTimeout = function onAdTimeout(player) {
2177                player.ads.debug('Postroll abort (adtimeout)');
2178                this.abort(player);
2179            }
2180            /*
2181             * Postroll errored out, time to clean up.
2182             */
2183            ;
2184
2185            _proto.onAdsError = function onAdsError(player) {
2186
2187                player.ads.debug('Postroll abort (adserror)'); // In the future, we may not want to do this automatically.
2188                // Ad plugins should be able to choose to continue the ad break
2189                // if there was an error.
2190
2191                if (player.ads.inAdBreak()) {
2192                    player.ads.endLinearAdMode();
2193                } else {
2194                    this.abort(player);
2195                }
2196            }
2197            /*
2198             * Handle content change if we're not in an ad break.
2199             */
2200            ;
2201
2202            _proto.onContentChanged = function onContentChanged(player) {
2203                // Content resuming after Postroll. Content is paused
2204                // at this point, since it is done playing.
2205                if (this.isContentResuming()) {
2206                    var BeforePreroll = States.getState('BeforePreroll');
2207                    this.transitionTo(BeforePreroll); // Waiting for postroll to start. Content is considered playing
2208                    // at this point, since it had to be playing to start the postroll.
2209                } else if (!this.inAdBreak()) {
2210                    var Preroll = States.getState('Preroll');
2211                    this.transitionTo(Preroll);
2212                }
2213            }
2214            /*
2215             * Wrap up if there is no postroll.
2216             */
2217            ;
2218
2219            _proto.onNoPostroll = function onNoPostroll(player) {
2220                if (!this.isContentResuming() && !this.inAdBreak()) {
2221                    this.abort(player);
2222                } else {
2223                    videojs.log.warn('Unexpected nopostroll event (Postroll)');
2224                }
2225            };
2226
2227            _proto.resumeContent = function resumeContent(player) {
2228                this.contentResuming = true;
2229                player.addClass('vjs-ad-content-resuming');
2230            }
2231            /*
2232             * Helper for ending Postrolls. In the future we may want to
2233             * refactor this class so that `cleanup` handles all of this.
2234             */
2235            ;
2236
2237            _proto.abort = function abort(player) {
2238                var AdsDone = States.getState('AdsDone');
2239                this.resumeContent(player);
2240                player.removeClass('vjs-ad-loading');
2241                this.transitionTo(AdsDone);
2242            }
2243            /*
2244             * Cleanup timeouts and state.
2245             */
2246            ;
2247
2248            _proto.cleanup = function cleanup(player) {
2249                player.removeClass('vjs-ad-content-resuming');
2250                player.clearTimeout(this._postrollTimeout);
2251                player.ads._contentEnding = false;
2252            };
2253
2254            return Postroll;
2255        }(AdState$3);
2256
2257    States.registerState('Postroll', Postroll);
2258
2259    var ContentState$3 = States.getState('ContentState');
2260    /*
2261     * This state represents content playback the first time through before
2262     * content ends. After content has ended once, we check for postrolls and
2263     * move on to the AdsDone state rather than returning here.
2264     */
2265
2266    var ContentPlayback =
2267        /*#__PURE__*/
2268        function (_ContentState) {
2269            _inheritsLoose(ContentPlayback, _ContentState);
2270
2271            function ContentPlayback() {
2272                return _ContentState.apply(this, arguments) || this;
2273            }
2274
2275            /*
2276             * Allows state name to be logged even after minification.
2277             */
2278            ContentPlayback._getName = function _getName() {
2279                return 'ContentPlayback';
2280            }
2281            /*
2282             * For state transitions to work correctly, initialization should
2283             * happen here, not in a constructor.
2284             */
2285            ;
2286
2287            var _proto = ContentPlayback.prototype;
2288
2289            _proto.init = function init(player) {
2290                // Don't block calls to play in content playback
2291                player.ads._shouldBlockPlay = false;
2292            }
2293            /*
2294             * In the case of a timeout, adsready might come in late. This assumes the behavior
2295             * that if an ad times out, it could still interrupt the content and start playing.
2296             * An ad plugin could behave otherwise by ignoring this event.
2297             */
2298            ;
2299
2300            _proto.onAdsReady = function onAdsReady(player) {
2301                player.ads.debug('Received adsready event (ContentPlayback)');
2302
2303                if (!player.ads.nopreroll_) {
2304                    player.ads.debug('Triggered readyforpreroll event (ContentPlayback)');
2305                    player.trigger('readyforpreroll');
2306                }
2307            }
2308            /*
2309             * Content ended before postroll checks.
2310             */
2311            ;
2312
2313            _proto.onReadyForPostroll = function onReadyForPostroll(player) {
2314                var Postroll = States.getState('Postroll');
2315                player.ads.debug('Received readyforpostroll event');
2316                this.transitionTo(Postroll);
2317            }
2318            /*
2319             * This is how midrolls start.
2320             */
2321            ;
2322
2323            _proto.startLinearAdMode = function startLinearAdMode() {
2324                var Midroll = States.getState('Midroll');
2325                this.transitionTo(Midroll);
2326            };
2327
2328            return ContentPlayback;
2329        }(ContentState$3);
2330
2331    States.registerState('ContentPlayback', ContentPlayback);
2332
2333    var ContentState$4 = States.getState('ContentState');
2334    /*
2335     * This state represents content playback when stitched ads are in play.
2336     */
2337
2338    var StitchedContentPlayback =
2339        /*#__PURE__*/
2340        function (_ContentState) {
2341            _inheritsLoose(StitchedContentPlayback, _ContentState);
2342
2343            function StitchedContentPlayback() {
2344                return _ContentState.apply(this, arguments) || this;
2345            }
2346
2347            /*
2348             * Allows state name to be logged even after minification.
2349             */
2350            StitchedContentPlayback._getName = function _getName() {
2351                return 'StitchedContentPlayback';
2352            }
2353            /*
2354             * For state transitions to work correctly, initialization should
2355             * happen here, not in a constructor.
2356             */
2357            ;
2358
2359            var _proto = StitchedContentPlayback.prototype;
2360
2361            _proto.init = function init() {
2362                // Don't block calls to play in stitched ad players, ever.
2363                this.player.ads._shouldBlockPlay = false;
2364            }
2365            /*
2366             * Source change does not do anything for stitched ad players.
2367             * contentchanged does not fire during ad breaks, so we don't need to
2368             * worry about that.
2369             */
2370            ;
2371
2372            _proto.onContentChanged = function onContentChanged() {
2373                this.player.ads.debug("Received contentchanged event (" + this.constructor._getName() + ")");
2374            }
2375            /*
2376             * This is how stitched ads start.
2377             */
2378            ;
2379
2380            _proto.startLinearAdMode = function startLinearAdMode() {
2381                var StitchedAdRoll = States.getState('StitchedAdRoll');
2382                this.transitionTo(StitchedAdRoll);
2383            };
2384
2385            return StitchedContentPlayback;
2386        }(ContentState$4);
2387
2388    States.registerState('StitchedContentPlayback', StitchedContentPlayback);
2389
2390    var AdState$4 = States.getState('AdState');
2391
2392    var StitchedAdRoll =
2393        /*#__PURE__*/
2394        function (_AdState) {
2395            _inheritsLoose(StitchedAdRoll, _AdState);
2396
2397            function StitchedAdRoll() {
2398                return _AdState.apply(this, arguments) || this;
2399            }
2400
2401            /*
2402             * Allows state name to be logged even after minification.
2403             */
2404            StitchedAdRoll._getName = function _getName() {
2405                return 'StitchedAdRoll';
2406            }
2407            /*
2408             * StitchedAdRoll breaks happen when the ad plugin calls startLinearAdMode,
2409             * which can happen at any time during content playback.
2410             */
2411            ;
2412
2413            var _proto = StitchedAdRoll.prototype;
2414
2415            _proto.init = function init() {
2416                this.waitingForAdBreak = false;
2417                this.contentResuming = false;
2418                this.player.ads.adType = 'stitched';
2419                obj$1.start(this.player);
2420            }
2421            /*
2422             * For stitched ads, there is no "content resuming" scenario, so a "playing"
2423             * event is not relevant.
2424             */
2425            ;
2426
2427            _proto.onPlaying = function onPlaying() {}
2428            /*
2429             * For stitched ads, there is no "content resuming" scenario, so a
2430             * "contentresumed" event is not relevant.
2431             */
2432            ;
2433
2434            _proto.onContentResumed = function onContentResumed() {}
2435            /*
2436             * When we see an "adended" event, it means that we are in a postroll that
2437             * has ended (because the media ended and we are still in an ad state).
2438             *
2439             * In these cases, we transition back to content mode and fire ended.
2440             */
2441            ;
2442
2443            _proto.onAdEnded = function onAdEnded() {
2444                this.endLinearAdMode();
2445                this.player.trigger('ended');
2446            }
2447            /*
2448             * StitchedAdRoll break is done.
2449             */
2450            ;
2451
2452            _proto.endLinearAdMode = function endLinearAdMode() {
2453                var StitchedContentPlayback = States.getState('StitchedContentPlayback');
2454                obj$1.end(this.player);
2455                this.transitionTo(StitchedContentPlayback);
2456            };
2457
2458            return StitchedAdRoll;
2459        }(AdState$4);
2460
2461    States.registerState('StitchedAdRoll', StitchedAdRoll);
2462
2463    /*
2464    This main plugin file is responsible for the public API and enabling the features
2465    that live in in separate files.
2466    */
2467    var isMiddlewareMediatorSupported$1 = obj.isMiddlewareMediatorSupported;
2468    var VIDEO_EVENTS = videojs.getTech('Html5').Events; // Default settings
2469
2470    var defaults = {
2471        // Maximum amount of time in ms to wait to receive `adsready` from the ad
2472        // implementation after play has been requested. Ad implementations are
2473        // expected to load any dynamic libraries and make any requests to determine
2474        // ad policies for a video during this time.
2475        timeout: 5000,
2476        // Maximum amount of time in ms to wait for the ad implementation to start
2477        // linear ad mode after `readyforpreroll` has fired. This is in addition to
2478        // the standard timeout.
2479        prerollTimeout: undefined,
2480        // Maximum amount of time in ms to wait for the ad implementation to start
2481        // linear ad mode after `readyforpostroll` has fired.
2482        postrollTimeout: undefined,
2483        // When truthy, instructs the plugin to output additional information about
2484        // plugin state to the video.js log. On most devices, the video.js log is
2485        // the same as the developer console.
2486        debug: false,
2487        // Set this to true when using ads that are part of the content video
2488        stitchedAds: false,
2489        // Force content to be treated as live or not live
2490        // if not defined, the code will try to infer if content is live,
2491        // which can have limitations.
2492        contentIsLive: undefined,
2493        // If set to true, content will play muted behind ads on supported platforms. This is
2494        // to support ads on video metadata cuepoints during a live stream. It also results in
2495        // more precise resumes after ads during a live stream.
2496        liveCuePoints: true
2497    };
2498
2499    var contribAdsPlugin = function contribAdsPlugin(options) {
2500        var player = this; // eslint-disable-line consistent-this
2501
2502        var settings = videojs.mergeOptions(defaults, options); // Prefix all video element events during ad playback
2503        // if the video element emits ad-related events directly,
2504        // plugins that aren't ad-aware will break. prefixing allows
2505        // plugins that wish to handle ad events to do so while
2506        // avoiding the complexity for common usage
2507
2508        var videoEvents = []; // dedupe event names
2509
2510        VIDEO_EVENTS.concat(['firstplay', 'loadedalldata']).forEach(function (eventName) {
2511            if (videoEvents.indexOf(eventName) === -1) {
2512                videoEvents.push(eventName);
2513            }
2514        }); // Set up redispatching of player events
2515
2516        player.on(videoEvents, redispatch); // Set up features to block content playback while waiting for ads.
2517        // Play middleware is only supported on later versions of video.js
2518        // and on desktop currently(as the user-gesture requirement on mobile
2519        // will disallow calling play once play blocking is lifted)
2520        // The middleware must also be registered outside of the plugin,
2521        // to avoid a middleware factory being created for each player
2522
2523        if (!isMiddlewareMediatorSupported$1()) {
2524            initCancelContentPlay(player, settings.debug);
2525        } // If we haven't seen a loadstart after 5 seconds, the plugin was not initialized
2526        // correctly.
2527
2528
2529        player.setTimeout(function () {
2530            if (!player.ads._hasThereBeenALoadStartDuringPlayerLife && player.src() !== '') {
2531                videojs.log.error('videojs-contrib-ads has not seen a loadstart event 5 seconds ' + 'after being initialized, but a source is present. This indicates that ' + 'videojs-contrib-ads was initialized too late. It must be initialized ' + 'immediately after video.js in the same tick. As a result, some ads will not ' + 'play and some media events will be incorrect. For more information, see ' + 'http://videojs.github.io/videojs-contrib-ads/integrator/getting-started.html');
2532            }
2533        }, 5000); // "vjs-has-started" should be present at the end of a video. This makes sure it's
2534        // always there.
2535
2536        player.on('ended', function () {
2537            if (!player.hasClass('vjs-has-started')) {
2538                player.addClass('vjs-has-started');
2539            }
2540        }); // video.js removes the vjs-waiting class on timeupdate. We want
2541        // to make sure this still happens during content restoration.
2542
2543        player.on('contenttimeupdate', function () {
2544            player.removeClass('vjs-waiting');
2545        }); // We now auto-play when an ad gets loaded if we're playing ads in the same video
2546        // element as the content.
2547        // The problem is that in IE11, we cannot play in addurationchange but in iOS8, we
2548        // cannot play from adcanplay.
2549        // This will prevent ad plugins from needing to do this themselves.
2550
2551        player.on(['addurationchange', 'adcanplay'], function () {
2552            // We don't need to handle this for stitched ads because
2553            // linear ads in such cases are stitched into the content.
2554            if (player.ads.settings.stitchedAds) {
2555                return;
2556            } // Some techs may retrigger canplay after playback has begun.
2557            // So we want to procceed only if playback hasn't started.
2558
2559
2560            if (player.hasStarted()) {
2561                return;
2562            }
2563
2564            if (player.ads.snapshot && player.currentSrc() === player.ads.snapshot.currentSrc) {
2565                return;
2566            } // If an ad isn't playing, don't try to play an ad. This could result from prefixed
2567            // events when the player is blocked by a preroll check, but there is no preroll.
2568
2569
2570            if (!player.ads.inAdBreak()) {
2571                return;
2572            }
2573
2574            var playPromise = player.play();
2575
2576            if (playPromise && playPromise.catch) {
2577                playPromise.catch(function (error) {
2578                    videojs.log.warn('Play promise rejected when playing ad', error);
2579                });
2580            }
2581        });
2582        player.on('nopreroll', function () {
2583            player.ads.debug('Received nopreroll event');
2584            player.ads.nopreroll_ = true;
2585        });
2586        player.on('nopostroll', function () {
2587            player.ads.debug('Received nopostroll event');
2588            player.ads.nopostroll_ = true;
2589        }); // Restart the cancelContentPlay process.
2590
2591        player.on('playing', function () {
2592            player.ads._cancelledPlay = false;
2593            player.ads._pausedOnContentupdate = false;
2594        }); // Keep track of whether a play event has happened
2595
2596        player.on('play', function () {
2597            player.ads._playRequested = true;
2598        });
2599        player.one('loadstart', function () {
2600            player.ads._hasThereBeenALoadStartDuringPlayerLife = true;
2601        });
2602        player.on('loadeddata', function () {
2603            player.ads._hasThereBeenALoadedData = true;
2604        });
2605        player.on('loadedmetadata', function () {
2606            player.ads._hasThereBeenALoadedMetaData = true;
2607        }); // Replace the plugin constructor with the ad namespace
2608
2609        player.ads = getAds(player);
2610        player.ads.settings = settings; // Set the stitched ads state. This needs to happen before the `_state` is
2611        // initialized below - BeforePreroll needs to know whether contrib-ads is
2612        // playing stitched ads or not.
2613        // The setter is deprecated, so this does not use it.
2614        // But first, cast to boolean.
2615
2616        settings.stitchedAds = !!settings.stitchedAds;
2617
2618        if (settings.stitchedAds) {
2619            player.ads._state = new (States.getState('StitchedContentPlayback'))(player);
2620        } else {
2621            player.ads._state = new (States.getState('BeforePreroll'))(player);
2622        }
2623
2624        player.ads._state.init(player);
2625
2626        player.ads.cueTextTracks = cueTextTracks;
2627        player.ads.adMacroReplacement = adMacroReplacement.bind(player); // Start sending contentupdate and contentchanged events for this player
2628
2629        initializeContentupdate(player); // Global contentchanged handler for resetting plugin state
2630
2631        player.on('contentchanged', player.ads.reset); // A utility method for textTrackChangeHandler to define the conditions
2632        // when text tracks should be disabled.
2633        // Currently this includes:
2634        //  - on iOS with native text tracks, during an ad playing
2635
2636        var shouldDisableTracks = function shouldDisableTracks() {
2637            // If the platform matches iOS with native text tracks
2638            // and this occurs during ad playback, we should disable tracks again.
2639            // If shouldPlayContentBehindAd, no special handling is needed.
2640            return !player.ads.shouldPlayContentBehindAd(player) && player.ads.inAdBreak() && player.tech_.featuresNativeTextTracks && videojs.browser.IS_IOS && // older versions of video.js did not use an emulated textTrackList
2641                !Array.isArray(player.textTracks());
2642        };
2643        /*
2644         * iOS Safari will change caption mode to 'showing' if a user previously
2645         * turned captions on manually for that video source, so this TextTrackList
2646         * 'change' event handler will re-disable them in case that occurs during ad playback
2647         */
2648
2649
2650        var textTrackChangeHandler = function textTrackChangeHandler() {
2651            var textTrackList = player.textTracks();
2652
2653            if (shouldDisableTracks()) {
2654                // We must double check all tracks
2655                for (var i = 0; i < textTrackList.length; i++) {
2656                    var track = textTrackList[i];
2657
2658                    if (track.mode === 'showing') {
2659                        track.mode = 'disabled';
2660                    }
2661                }
2662            }
2663        }; // Add the listener to the text track list
2664
2665
2666        player.ready(function () {
2667            player.textTracks().addEventListener('change', textTrackChangeHandler);
2668        }); // Event handling for the current state.
2669
2670        player.on(['play', 'playing', 'ended', 'adsready', 'adscanceled', 'adskip', 'adserror', 'adtimeout', 'adended', 'ads-ad-started', 'contentchanged', 'dispose', 'contentresumed', 'readyforpostroll', 'nopreroll', 'nopostroll'], function (e) {
2671            player.ads._state.handleEvent(e.type);
2672        }); // Clear timeouts and handlers when player is disposed
2673
2674        player.on('dispose', function () {
2675            player.ads.reset();
2676            player.textTracks().removeEventListener('change', textTrackChangeHandler);
2677        });
2678    }; // Expose the contrib-ads version before it is initialized. Will be replaced
2679    // after initialization in ads.js
2680
2681
2682    contribAdsPlugin.VERSION = version; // Attempt to register the plugin, if we can.
2683
2684    register(contribAdsPlugin);
2685
2686    return contribAdsPlugin;
2687})));

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.