j1-template 2024.0.2 → 2024.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/assets/themes/j1/core/js/template.js +0 -12
- data/assets/themes/j1/core/js/template.min.js.map +1 -1
- data/assets/themes/j1/modules/iframeResizer/README.md +105 -105
- data/assets/themes/j1/modules/lightGallery/js/plugins/lg-video.js +30 -5
- data/assets/themes/j1/modules/videojs/assets/material-icons.woff +0 -0
- data/assets/themes/j1/modules/videojs/assets/material-icons.woff2 +0 -0
- data/assets/themes/j1/modules/videojs/css/plugins/zoom.css +96 -0
- data/assets/themes/j1/modules/videojs/css/plugins/zoom.min.css +21 -0
- data/assets/themes/j1/modules/videojs/css/themes/city.css +1 -1
- data/assets/themes/j1/modules/videojs/css/themes/city.min.css +1 -1
- data/assets/themes/j1/modules/videojs/css/themes/fantasy.css +1 -1
- data/assets/themes/j1/modules/videojs/css/themes/fantasy.min.css +1 -1
- data/assets/themes/j1/modules/videojs/css/themes/forest.css +1 -1
- data/assets/themes/j1/modules/videojs/css/themes/forest.min.css +1 -1
- data/assets/themes/j1/modules/videojs/css/themes/sea.css +1 -1
- data/assets/themes/j1/modules/videojs/css/themes/sea.min.css +1 -1
- data/assets/themes/j1/modules/videojs/css/themes/uno.css +16 -18
- data/assets/themes/j1/modules/videojs/css/themes/uno.min.css +3 -2
- data/assets/themes/j1/modules/videojs/css/{video-js.css → video.css} +9 -7
- data/assets/themes/j1/modules/videojs/css/{video-js.min.css → video.min.css} +2 -2
- data/assets/themes/j1/modules/videojs/js/plugins/zoom.js +377 -0
- data/assets/themes/j1/modules/videojs/js/plugins/zoom.min.js +21 -0
- data/assets/themes/j1/modules/videojs/js/video.js +641 -71
- data/assets/themes/j1/modules/videojs/js/video.min.js +10 -9
- data/lib/j1/version.rb +1 -1
- data/lib/starter_web/README.md +5 -5
- data/lib/starter_web/_config.yml +1 -1
- data/lib/starter_web/_data/modules/gallery.yml +7 -2
- data/lib/starter_web/_data/resources.yml +4 -2
- data/lib/starter_web/_data/templates/feed.xml +1 -1
- data/lib/starter_web/_plugins/asciidoctor/videojs-block.rb +3 -2
- data/lib/starter_web/_plugins/index/lunr.rb +3 -1
- data/lib/starter_web/assets/videos/gallery/video_james_carpool_caraoke.1920.jpg +0 -0
- data/lib/starter_web/package.json +1 -1
- data/lib/starter_web/pages/public/tools/previewer/preview_docsearch.adoc +92 -92
- data/lib/starter_web/pages/public/tools/previewer/preview_iframer.adoc +106 -106
- metadata +11 -4
@@ -1,6 +1,6 @@
|
|
1
1
|
/**
|
2
2
|
* @license
|
3
|
-
* Video.js 8.6.
|
3
|
+
* Video.js 8.6.1 <http://videojs.com/>
|
4
4
|
* Copyright Brightcove, Inc. <https://www.brightcove.com/>
|
5
5
|
* Available under Apache License Version 2.0
|
6
6
|
* <https://github.com/videojs/video.js/blob/main/LICENSE>
|
@@ -8,7 +8,7 @@
|
|
8
8
|
* Includes vtt.js <https://github.com/mozilla/vtt.js>
|
9
9
|
* Available under Apache License Version 2.0
|
10
10
|
* <https://github.com/mozilla/vtt.js/blob/main/LICENSE>
|
11
|
-
|
11
|
+
*/
|
12
12
|
|
13
13
|
(function (global, factory) {
|
14
14
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
@@ -16,7 +16,7 @@
|
|
16
16
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.videojs = factory());
|
17
17
|
})(this, (function () { 'use strict';
|
18
18
|
|
19
|
-
var version$5 = "8.6.
|
19
|
+
var version$5 = "8.6.1";
|
20
20
|
|
21
21
|
/**
|
22
22
|
* An Object that contains lifecycle hooks as keys which point to an array
|
@@ -1996,7 +1996,7 @@
|
|
1996
1996
|
* @param {Element|Object} elem
|
1997
1997
|
* Element or object to bind listeners to
|
1998
1998
|
*
|
1999
|
-
* @param {string}
|
1999
|
+
* @param {string[]} types
|
2000
2000
|
* Type of event to bind to.
|
2001
2001
|
*
|
2002
2002
|
* @param {Function} callback
|
@@ -2719,7 +2719,7 @@
|
|
2719
2719
|
/**
|
2720
2720
|
* All event listeners should follow the following format.
|
2721
2721
|
*
|
2722
|
-
* @callback
|
2722
|
+
* @callback EventListener
|
2723
2723
|
* @this {EventTarget}
|
2724
2724
|
*
|
2725
2725
|
* @param {Event} event
|
@@ -2736,7 +2736,7 @@
|
|
2736
2736
|
* will have extra functionality. See that function for more information.
|
2737
2737
|
*
|
2738
2738
|
* @property EventTarget.prototype.allowedEvents_
|
2739
|
-
* @
|
2739
|
+
* @protected
|
2740
2740
|
*/
|
2741
2741
|
EventTarget$2.prototype.allowedEvents_ = {};
|
2742
2742
|
|
@@ -4169,7 +4169,6 @@
|
|
4169
4169
|
/**
|
4170
4170
|
* Add a child `Component` inside the current `Component`.
|
4171
4171
|
*
|
4172
|
-
*
|
4173
4172
|
* @param {string|Component} child
|
4174
4173
|
* The name or instance of a child to add.
|
4175
4174
|
*
|
@@ -4180,6 +4179,7 @@
|
|
4180
4179
|
* @param {number} [index=this.children_.length]
|
4181
4180
|
* The index to attempt to add a child into.
|
4182
4181
|
*
|
4182
|
+
*
|
4183
4183
|
* @return {Component}
|
4184
4184
|
* The `Component` that gets added as a child. When using a string the
|
4185
4185
|
* `Component` will get created by this process.
|
@@ -4634,9 +4634,8 @@
|
|
4634
4634
|
* @param {boolean} [skipListeners]
|
4635
4635
|
* Skip the componentresize event trigger
|
4636
4636
|
*
|
4637
|
-
* @return {number|
|
4638
|
-
* The width when getting, zero if there is no width
|
4639
|
-
* postpixed with '%' or 'px'.
|
4637
|
+
* @return {number|undefined}
|
4638
|
+
* The width when getting, zero if there is no width
|
4640
4639
|
*/
|
4641
4640
|
width(num, skipListeners) {
|
4642
4641
|
return this.dimension('width', num, skipListeners);
|
@@ -4652,9 +4651,8 @@
|
|
4652
4651
|
* @param {boolean} [skipListeners]
|
4653
4652
|
* Skip the componentresize event trigger
|
4654
4653
|
*
|
4655
|
-
* @return {number|
|
4656
|
-
* The
|
4657
|
-
* postpixed with '%' or 'px'.
|
4654
|
+
* @return {number|undefined}
|
4655
|
+
* The height when getting, zero if there is no height
|
4658
4656
|
*/
|
4659
4657
|
height(num, skipListeners) {
|
4660
4658
|
return this.dimension('height', num, skipListeners);
|
@@ -4700,7 +4698,7 @@
|
|
4700
4698
|
* @param {boolean} [skipListeners]
|
4701
4699
|
* Skip componentresize event trigger
|
4702
4700
|
*
|
4703
|
-
* @return {number}
|
4701
|
+
* @return {number|undefined}
|
4704
4702
|
* The dimension when getting or 0 if unset
|
4705
4703
|
*/
|
4706
4704
|
dimension(widthOrHeight, num, skipListeners) {
|
@@ -4875,7 +4873,7 @@
|
|
4875
4873
|
* delegates to `handleKeyDown`. This means anyone calling `handleKeyPress`
|
4876
4874
|
* will not see their method calls stop working.
|
4877
4875
|
*
|
4878
|
-
* @param {
|
4876
|
+
* @param {KeyboardEvent} event
|
4879
4877
|
* The event that caused this function to be called.
|
4880
4878
|
*/
|
4881
4879
|
handleKeyPress(event) {
|
@@ -4887,7 +4885,7 @@
|
|
4887
4885
|
* support toggling the controls through a tap on the video. They get enabled
|
4888
4886
|
* because every sub-component would have extra overhead otherwise.
|
4889
4887
|
*
|
4890
|
-
* @
|
4888
|
+
* @protected
|
4891
4889
|
* @fires Component#tap
|
4892
4890
|
* @listens Component#touchstart
|
4893
4891
|
* @listens Component#touchmove
|
@@ -6524,7 +6522,7 @@
|
|
6524
6522
|
* Events that can be called with on + eventName. See {@link EventHandler}.
|
6525
6523
|
*
|
6526
6524
|
* @property {Object} TrackList#allowedEvents_
|
6527
|
-
* @
|
6525
|
+
* @protected
|
6528
6526
|
*/
|
6529
6527
|
TrackList.prototype.allowedEvents_ = {
|
6530
6528
|
change: 'change',
|
@@ -6574,7 +6572,7 @@
|
|
6574
6572
|
/**
|
6575
6573
|
* Create an instance of this class.
|
6576
6574
|
*
|
6577
|
-
* @param {
|
6575
|
+
* @param { import('./audio-track').default[] } [tracks=[]]
|
6578
6576
|
* A list of `AudioTrack` to instantiate the list with.
|
6579
6577
|
*/
|
6580
6578
|
constructor(tracks = []) {
|
@@ -8012,7 +8010,9 @@
|
|
8012
8010
|
*/
|
8013
8011
|
addCue(originalCue) {
|
8014
8012
|
let cue = originalCue;
|
8015
|
-
|
8013
|
+
|
8014
|
+
// Testing if the cue is a VTTCue in a way that survives minification
|
8015
|
+
if (!('getCueAsHTML' in cue)) {
|
8016
8016
|
cue = new window.vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text);
|
8017
8017
|
for (const prop in originalCue) {
|
8018
8018
|
if (!(prop in cue)) {
|
@@ -8055,6 +8055,7 @@
|
|
8055
8055
|
|
8056
8056
|
/**
|
8057
8057
|
* cuechange - One or more cues in the track have become active or stopped being active.
|
8058
|
+
* @protected
|
8058
8059
|
*/
|
8059
8060
|
TextTrack.prototype.allowedEvents_ = {
|
8060
8061
|
cuechange: 'cuechange'
|
@@ -8313,6 +8314,10 @@
|
|
8313
8314
|
});
|
8314
8315
|
}
|
8315
8316
|
}
|
8317
|
+
|
8318
|
+
/**
|
8319
|
+
* @protected
|
8320
|
+
*/
|
8316
8321
|
HTMLTrackElement.prototype.allowedEvents_ = {
|
8317
8322
|
load: 'load'
|
8318
8323
|
};
|
@@ -10110,7 +10115,7 @@
|
|
10110
10115
|
* * `var SourceObject = {src: 'http://ex.com/video.mp4', type: 'video/mp4'};`
|
10111
10116
|
* `var SourceString = 'http://example.com/some-video.mp4';`
|
10112
10117
|
*
|
10113
|
-
* @typedef {Object|string}
|
10118
|
+
* @typedef {Object|string} SourceObject
|
10114
10119
|
*
|
10115
10120
|
* @property {string} src
|
10116
10121
|
* The url to the source
|
@@ -10546,7 +10551,7 @@
|
|
10546
10551
|
* > NOTE: This implementation is incomplete. It does not track the played `TimeRange`.
|
10547
10552
|
* It only checks whether the source has played at all or not.
|
10548
10553
|
*
|
10549
|
-
* @return {TimeRange}
|
10554
|
+
* @return { import('../utils/time').TimeRange }
|
10550
10555
|
* - A single time range if this video has played
|
10551
10556
|
* - An empty set of ranges if not.
|
10552
10557
|
*/
|
@@ -11310,7 +11315,7 @@
|
|
11310
11315
|
*
|
11311
11316
|
* TODO: Answer question: should 'probably' be prioritized over 'maybe'
|
11312
11317
|
*
|
11313
|
-
* @param {
|
11318
|
+
* @param {SourceObject} source
|
11314
11319
|
* The source object
|
11315
11320
|
*
|
11316
11321
|
* @param {Object} options
|
@@ -11335,7 +11340,7 @@
|
|
11335
11340
|
/**
|
11336
11341
|
* Check if the tech can support the given source.
|
11337
11342
|
*
|
11338
|
-
* @param {
|
11343
|
+
* @param {SourceObject} srcObj
|
11339
11344
|
* The source object
|
11340
11345
|
*
|
11341
11346
|
* @param {Object} options
|
@@ -11390,7 +11395,7 @@
|
|
11390
11395
|
* and source handlers.
|
11391
11396
|
* Should never be called unless a source handler was found.
|
11392
11397
|
*
|
11393
|
-
* @param {
|
11398
|
+
* @param {SourceObject} source
|
11394
11399
|
* A source object with src and type keys
|
11395
11400
|
*/
|
11396
11401
|
_Tech.prototype.setSource = function (source) {
|
@@ -12169,7 +12174,7 @@
|
|
12169
12174
|
*
|
12170
12175
|
* By default, if the key is Space or Enter, it will trigger a `click` event.
|
12171
12176
|
*
|
12172
|
-
* @param {
|
12177
|
+
* @param {KeyboardEvent} event
|
12173
12178
|
* The `keydown` event that caused this function to be called.
|
12174
12179
|
*
|
12175
12180
|
* @listens keydown
|
@@ -12925,7 +12930,7 @@
|
|
12925
12930
|
* This gets called when a `Button` has focus and `keydown` is triggered via a key
|
12926
12931
|
* press.
|
12927
12932
|
*
|
12928
|
-
* @param {
|
12933
|
+
* @param {KeyboardEvent} event
|
12929
12934
|
* The event that caused this function to get called.
|
12930
12935
|
*
|
12931
12936
|
* @listens keydown
|
@@ -12979,7 +12984,7 @@
|
|
12979
12984
|
* This gets called when a `BigPlayButton` "clicked". See {@link ClickableComponent}
|
12980
12985
|
* for more detailed information on what a click can be.
|
12981
12986
|
*
|
12982
|
-
* @param {KeyboardEvent} event
|
12987
|
+
* @param {KeyboardEvent|MouseEvent|TouchEvent} event
|
12983
12988
|
* The `keydown`, `tap`, or `click` event that caused this function to be
|
12984
12989
|
* called.
|
12985
12990
|
*
|
@@ -12990,7 +12995,7 @@
|
|
12990
12995
|
const playPromise = this.player_.play();
|
12991
12996
|
|
12992
12997
|
// exit early if clicked via the mouse
|
12993
|
-
if (this.mouseused_ &&
|
12998
|
+
if (this.mouseused_ && 'clientX' in event && 'clientY' in event) {
|
12994
12999
|
silencePromise(playPromise);
|
12995
13000
|
if (this.player_.tech(true)) {
|
12996
13001
|
this.player_.tech(true).focus();
|
@@ -13010,10 +13015,29 @@
|
|
13010
13015
|
this.setTimeout(playFocus, 1);
|
13011
13016
|
}
|
13012
13017
|
}
|
13018
|
+
|
13019
|
+
/**
|
13020
|
+
* Event handler that is called when a `BigPlayButton` receives a
|
13021
|
+
* `keydown` event.
|
13022
|
+
*
|
13023
|
+
* @param {KeyboardEvent} event
|
13024
|
+
* The `keydown` event that caused this function to be called.
|
13025
|
+
*
|
13026
|
+
* @listens keydown
|
13027
|
+
*/
|
13013
13028
|
handleKeyDown(event) {
|
13014
13029
|
this.mouseused_ = false;
|
13015
13030
|
super.handleKeyDown(event);
|
13016
13031
|
}
|
13032
|
+
|
13033
|
+
/**
|
13034
|
+
* Handle `mousedown` events on the `BigPlayButton`.
|
13035
|
+
*
|
13036
|
+
* @param {MouseEvent} event
|
13037
|
+
* `mousedown` or `touchstart` event that triggered this function
|
13038
|
+
*
|
13039
|
+
* @listens mousedown
|
13040
|
+
*/
|
13017
13041
|
handleMouseDown(event) {
|
13018
13042
|
this.mouseused_ = true;
|
13019
13043
|
}
|
@@ -13099,7 +13123,7 @@
|
|
13099
13123
|
*
|
13100
13124
|
* By default, if the key is Esc, it will trigger a `click` event.
|
13101
13125
|
*
|
13102
|
-
* @param {
|
13126
|
+
* @param {KeyboardEvent} event
|
13103
13127
|
* The `keydown` event that caused this function to be called.
|
13104
13128
|
*
|
13105
13129
|
* @listens keydown
|
@@ -16726,7 +16750,7 @@
|
|
16726
16750
|
/**
|
16727
16751
|
* Handle a `keydown` event on this menu. This listener is added in the constructor.
|
16728
16752
|
*
|
16729
|
-
* @param {
|
16753
|
+
* @param {KeyboardEvent} event
|
16730
16754
|
* A `keydown` event that happened on the menu.
|
16731
16755
|
*
|
16732
16756
|
* @listens keydown
|
@@ -17323,7 +17347,7 @@
|
|
17323
17347
|
* Ignore keys which are used by the menu, but pass any other ones up. See
|
17324
17348
|
* {@link ClickableComponent#handleKeyDown} for instances where this is called.
|
17325
17349
|
*
|
17326
|
-
* @param {
|
17350
|
+
* @param {KeyboardEvent} event
|
17327
17351
|
* The `keydown` event that caused this function to be called.
|
17328
17352
|
*
|
17329
17353
|
* @listens keydown
|
@@ -22382,8 +22406,8 @@
|
|
22382
22406
|
*
|
22383
22407
|
* After an instance has been created it can be accessed globally in three ways:
|
22384
22408
|
* 1. By calling `videojs.getPlayer('example_video_1');`
|
22385
|
-
* 2. By calling `videojs('example_video_1');` (not
|
22386
|
-
* 2. By using it directly via
|
22409
|
+
* 2. By calling `videojs('example_video_1');` (not recommended)
|
22410
|
+
* 2. By using it directly via `videojs.players.example_video_1;`
|
22387
22411
|
*
|
22388
22412
|
* @extends Component
|
22389
22413
|
* @global
|
@@ -24122,7 +24146,9 @@
|
|
24122
24146
|
*/
|
24123
24147
|
handleTechError_() {
|
24124
24148
|
const error = this.tech_.error();
|
24125
|
-
|
24149
|
+
if (error) {
|
24150
|
+
this.error(error);
|
24151
|
+
}
|
24126
24152
|
}
|
24127
24153
|
|
24128
24154
|
/**
|
@@ -25078,7 +25104,7 @@
|
|
25078
25104
|
* This allows player-wide hotkeys (either as defined below, or optionally
|
25079
25105
|
* by an external function).
|
25080
25106
|
*
|
25081
|
-
* @param {
|
25107
|
+
* @param {KeyboardEvent} event
|
25082
25108
|
* The `keydown` event that caused this function to be called.
|
25083
25109
|
*
|
25084
25110
|
* @listens keydown
|
@@ -27282,7 +27308,7 @@
|
|
27282
27308
|
* @param {Player} player
|
27283
27309
|
* A Video.js player instance.
|
27284
27310
|
*
|
27285
|
-
* @param {
|
27311
|
+
* @param {PluginEventHash} hash
|
27286
27312
|
* A plugin event hash.
|
27287
27313
|
*
|
27288
27314
|
* @param {boolean} [before]
|
@@ -27435,7 +27461,7 @@
|
|
27435
27461
|
* @param {Object} [hash={}]
|
27436
27462
|
* An object to be used as event an event hash.
|
27437
27463
|
*
|
27438
|
-
* @return {
|
27464
|
+
* @return {PluginEventHash}
|
27439
27465
|
* An event hash object with provided properties mixed-in.
|
27440
27466
|
*/
|
27441
27467
|
getEventHash(hash = {}) {
|
@@ -27454,7 +27480,7 @@
|
|
27454
27480
|
*
|
27455
27481
|
* @param {Object} [hash={}]
|
27456
27482
|
* Additional data hash to merge with a
|
27457
|
-
* {@link
|
27483
|
+
* {@link PluginEventHash|PluginEventHash}.
|
27458
27484
|
*
|
27459
27485
|
* @return {boolean}
|
27460
27486
|
* Whether or not default was prevented.
|
@@ -27670,7 +27696,7 @@
|
|
27670
27696
|
* Signals that a plugin is about to be set up on a player.
|
27671
27697
|
*
|
27672
27698
|
* @event Player#beforepluginsetup
|
27673
|
-
* @type {
|
27699
|
+
* @type {PluginEventHash}
|
27674
27700
|
*/
|
27675
27701
|
|
27676
27702
|
/**
|
@@ -27678,14 +27704,14 @@
|
|
27678
27704
|
* is the name of the plugin.
|
27679
27705
|
*
|
27680
27706
|
* @event Player#beforepluginsetup:$name
|
27681
|
-
* @type {
|
27707
|
+
* @type {PluginEventHash}
|
27682
27708
|
*/
|
27683
27709
|
|
27684
27710
|
/**
|
27685
27711
|
* Signals that a plugin has just been set up on a player.
|
27686
27712
|
*
|
27687
27713
|
* @event Player#pluginsetup
|
27688
|
-
* @type {
|
27714
|
+
* @type {PluginEventHash}
|
27689
27715
|
*/
|
27690
27716
|
|
27691
27717
|
/**
|
@@ -27693,11 +27719,11 @@
|
|
27693
27719
|
* is the name of the plugin.
|
27694
27720
|
*
|
27695
27721
|
* @event Player#pluginsetup:$name
|
27696
|
-
* @type {
|
27722
|
+
* @type {PluginEventHash}
|
27697
27723
|
*/
|
27698
27724
|
|
27699
27725
|
/**
|
27700
|
-
* @typedef {Object}
|
27726
|
+
* @typedef {Object} PluginEventHash
|
27701
27727
|
*
|
27702
27728
|
* @property {string} instance
|
27703
27729
|
* For basic plugins, the return value of the plugin function. For
|
@@ -28024,10 +28050,10 @@
|
|
28024
28050
|
* @param {string} name
|
28025
28051
|
* The class name of the component
|
28026
28052
|
*
|
28027
|
-
* @param {Component} comp
|
28053
|
+
* @param {typeof Component} comp
|
28028
28054
|
* The component class
|
28029
28055
|
*
|
28030
|
-
* @return {Component}
|
28056
|
+
* @return {typeof Component}
|
28031
28057
|
* The newly registered component
|
28032
28058
|
*/
|
28033
28059
|
videojs.registerComponent = (name, comp) => {
|
@@ -28110,9 +28136,11 @@
|
|
28110
28136
|
*
|
28111
28137
|
* @param {string} name
|
28112
28138
|
* The plugin name
|
28113
|
-
|
28114
|
-
* @param {Plugin|Function} plugin
|
28139
|
+
*
|
28140
|
+
* @param {typeof Plugin|Function} plugin
|
28115
28141
|
* The plugin sub-class or function
|
28142
|
+
*
|
28143
|
+
* @return {typeof Plugin|Function}
|
28116
28144
|
*/
|
28117
28145
|
videojs.plugin = (name, plugin) => {
|
28118
28146
|
log$1.warn('videojs.plugin() is deprecated; use videojs.registerPlugin() instead');
|
@@ -39079,7 +39107,7 @@
|
|
39079
39107
|
};
|
39080
39108
|
var clock_1 = clock.ONE_SECOND_IN_TS;
|
39081
39109
|
|
39082
|
-
/*! @name @videojs/http-streaming @version 3.
|
39110
|
+
/*! @name @videojs/http-streaming @version 3.7.0 @license Apache-2.0 */
|
39083
39111
|
|
39084
39112
|
/**
|
39085
39113
|
* @file resolve-url.js - Handling how URLs are resolved and manipulated
|
@@ -39813,9 +39841,13 @@
|
|
39813
39841
|
const seekable = function (playlist, expired, liveEdgePadding) {
|
39814
39842
|
const useSafeLiveEnd = true;
|
39815
39843
|
const seekableStart = expired || 0;
|
39816
|
-
|
39844
|
+
let seekableEnd = playlistEnd(playlist, expired, useSafeLiveEnd, liveEdgePadding);
|
39817
39845
|
if (seekableEnd === null) {
|
39818
39846
|
return createTimeRanges();
|
39847
|
+
} // Clamp seekable end since it can not be less than the seekable start
|
39848
|
+
|
39849
|
+
if (seekableEnd < seekableStart) {
|
39850
|
+
seekableEnd = seekableStart;
|
39819
39851
|
}
|
39820
39852
|
return createTimeRanges(seekableStart, seekableEnd);
|
39821
39853
|
};
|
@@ -42253,7 +42285,10 @@
|
|
42253
42285
|
}); // live playlist staleness timeout
|
42254
42286
|
|
42255
42287
|
this.on('mediaupdatetimeout', () => {
|
42256
|
-
|
42288
|
+
// We handle live content steering in the playlist controller
|
42289
|
+
if (!this.media().attributes.serviceLocation) {
|
42290
|
+
this.refreshMedia_(this.media().id);
|
42291
|
+
}
|
42257
42292
|
});
|
42258
42293
|
this.state = 'HAVE_NOTHING';
|
42259
42294
|
this.loadedPlaylists_ = {};
|
@@ -45083,18 +45118,31 @@
|
|
45083
45118
|
var nextByte = packetData[i + 1];
|
45084
45119
|
var win = service.currentWindow;
|
45085
45120
|
var char;
|
45086
|
-
var charCodeArray; //
|
45121
|
+
var charCodeArray; // Converts an array of bytes to a unicode hex string.
|
45122
|
+
|
45123
|
+
function toHexString(byteArray) {
|
45124
|
+
return byteArray.map(byte => {
|
45125
|
+
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
|
45126
|
+
}).join('');
|
45127
|
+
}
|
45128
|
+
if (isMultiByte) {
|
45129
|
+
charCodeArray = [currentByte, nextByte];
|
45130
|
+
i++;
|
45131
|
+
} else {
|
45132
|
+
charCodeArray = [currentByte];
|
45133
|
+
} // Use the TextDecoder if one was created for this service
|
45087
45134
|
|
45088
45135
|
if (service.textDecoder_ && !isExtended) {
|
45136
|
+
char = service.textDecoder_.decode(new Uint8Array(charCodeArray));
|
45137
|
+
} else {
|
45138
|
+
// We assume any multi-byte char without a decoder is unicode.
|
45089
45139
|
if (isMultiByte) {
|
45090
|
-
|
45091
|
-
|
45140
|
+
const unicode = toHexString(charCodeArray); // Takes a unicode hex string and creates a single character.
|
45141
|
+
|
45142
|
+
char = String.fromCharCode(parseInt(unicode, 16));
|
45092
45143
|
} else {
|
45093
|
-
|
45144
|
+
char = get708CharFromCode(extended | currentByte);
|
45094
45145
|
}
|
45095
|
-
char = service.textDecoder_.decode(new Uint8Array(charCodeArray));
|
45096
|
-
} else {
|
45097
|
-
char = get708CharFromCode(extended | currentByte);
|
45098
45146
|
}
|
45099
45147
|
if (win.pendingNewLine && !win.isEmpty()) {
|
45100
45148
|
win.newLine(this.getPts(i));
|
@@ -52091,7 +52139,7 @@
|
|
52091
52139
|
segment.bytes = bytesAsUint8Array = emsgData; // Run through the CaptionParser in case there are captions.
|
52092
52140
|
// Initialize CaptionParser if it hasn't been yet
|
52093
52141
|
|
52094
|
-
if (!tracks.video || !
|
52142
|
+
if (!tracks.video || !emsgData.byteLength || !segment.transmuxer) {
|
52095
52143
|
finishLoading(undefined, id3Frames);
|
52096
52144
|
return;
|
52097
52145
|
}
|
@@ -59082,15 +59130,11 @@
|
|
59082
59130
|
*/
|
59083
59131
|
AUDIO: (type, settings) => () => {
|
59084
59132
|
const {
|
59085
|
-
segmentLoaders: {
|
59086
|
-
[type]: segmentLoader
|
59087
|
-
},
|
59088
59133
|
mediaTypes: {
|
59089
59134
|
[type]: mediaType
|
59090
59135
|
},
|
59091
59136
|
excludePlaylist
|
59092
|
-
} = settings;
|
59093
|
-
stopLoaders(segmentLoader, mediaType); // switch back to default audio track
|
59137
|
+
} = settings; // switch back to default audio track
|
59094
59138
|
|
59095
59139
|
const activeTrack = mediaType.activeTrack();
|
59096
59140
|
const activeGroup = mediaType.activeGroup();
|
@@ -59126,15 +59170,11 @@
|
|
59126
59170
|
*/
|
59127
59171
|
SUBTITLES: (type, settings) => () => {
|
59128
59172
|
const {
|
59129
|
-
segmentLoaders: {
|
59130
|
-
[type]: segmentLoader
|
59131
|
-
},
|
59132
59173
|
mediaTypes: {
|
59133
59174
|
[type]: mediaType
|
59134
59175
|
}
|
59135
59176
|
} = settings;
|
59136
59177
|
videojs.log.warn('Problem encountered loading the subtitle track.' + 'Disabling subtitle track.');
|
59137
|
-
stopLoaders(segmentLoader, mediaType);
|
59138
59178
|
const track = mediaType.activeTrack();
|
59139
59179
|
if (track) {
|
59140
59180
|
track.mode = 'disabled';
|
@@ -59721,6 +59761,388 @@
|
|
59721
59761
|
return mediaTypes;
|
59722
59762
|
};
|
59723
59763
|
|
59764
|
+
/**
|
59765
|
+
* A utility class for setting properties and maintaining the state of the content steering manifest.
|
59766
|
+
*
|
59767
|
+
* Content Steering manifest format:
|
59768
|
+
* VERSION: number (required) currently only version 1 is supported.
|
59769
|
+
* TTL: number in seconds (optional) until the next content steering manifest reload.
|
59770
|
+
* RELOAD-URI: string (optional) uri to fetch the next content steering manifest.
|
59771
|
+
* SERVICE-LOCATION-PRIORITY or PATHWAY-PRIORITY a non empty array of unique string values.
|
59772
|
+
*/
|
59773
|
+
|
59774
|
+
class SteeringManifest {
|
59775
|
+
constructor() {
|
59776
|
+
this.priority_ = [];
|
59777
|
+
}
|
59778
|
+
set version(number) {
|
59779
|
+
// Only version 1 is currently supported for both DASH and HLS.
|
59780
|
+
if (number === 1) {
|
59781
|
+
this.version_ = number;
|
59782
|
+
}
|
59783
|
+
}
|
59784
|
+
set ttl(seconds) {
|
59785
|
+
// TTL = time-to-live, default = 300 seconds.
|
59786
|
+
this.ttl_ = seconds || 300;
|
59787
|
+
}
|
59788
|
+
set reloadUri(uri) {
|
59789
|
+
if (uri) {
|
59790
|
+
// reload URI can be relative to the previous reloadUri.
|
59791
|
+
this.reloadUri_ = resolveUrl(this.reloadUri_, uri);
|
59792
|
+
}
|
59793
|
+
}
|
59794
|
+
set priority(array) {
|
59795
|
+
// priority must be non-empty and unique values.
|
59796
|
+
if (array && array.length) {
|
59797
|
+
this.priority_ = array;
|
59798
|
+
}
|
59799
|
+
}
|
59800
|
+
get version() {
|
59801
|
+
return this.version_;
|
59802
|
+
}
|
59803
|
+
get ttl() {
|
59804
|
+
return this.ttl_;
|
59805
|
+
}
|
59806
|
+
get reloadUri() {
|
59807
|
+
return this.reloadUri_;
|
59808
|
+
}
|
59809
|
+
get priority() {
|
59810
|
+
return this.priority_;
|
59811
|
+
}
|
59812
|
+
}
|
59813
|
+
/**
|
59814
|
+
* This class represents a content steering manifest and associated state. See both HLS and DASH specifications.
|
59815
|
+
* HLS: https://developer.apple.com/streaming/HLSContentSteeringSpecification.pdf and
|
59816
|
+
* https://datatracker.ietf.org/doc/draft-pantos-hls-rfc8216bis/ section 4.4.6.6.
|
59817
|
+
* DASH: https://dashif.org/docs/DASH-IF-CTS-00XX-Content-Steering-Community-Review.pdf
|
59818
|
+
*
|
59819
|
+
* @param {function} xhr for making a network request from the browser.
|
59820
|
+
* @param {function} bandwidth for fetching the current bandwidth from the main segment loader.
|
59821
|
+
*/
|
59822
|
+
|
59823
|
+
class ContentSteeringController extends videojs.EventTarget {
|
59824
|
+
constructor(xhr, bandwidth) {
|
59825
|
+
super();
|
59826
|
+
this.currentPathway = null;
|
59827
|
+
this.defaultPathway = null;
|
59828
|
+
this.queryBeforeStart = null;
|
59829
|
+
this.availablePathways_ = new Set();
|
59830
|
+
this.excludedPathways_ = new Set();
|
59831
|
+
this.steeringManifest = new SteeringManifest();
|
59832
|
+
this.proxyServerUrl_ = null;
|
59833
|
+
this.manifestType_ = null;
|
59834
|
+
this.ttlTimeout_ = null;
|
59835
|
+
this.request_ = null;
|
59836
|
+
this.excludedSteeringManifestURLs = new Set();
|
59837
|
+
this.logger_ = logger('Content Steering');
|
59838
|
+
this.xhr_ = xhr;
|
59839
|
+
this.getBandwidth_ = bandwidth;
|
59840
|
+
}
|
59841
|
+
/**
|
59842
|
+
* Assigns the content steering tag properties to the steering controller
|
59843
|
+
*
|
59844
|
+
* @param {string} baseUrl the baseURL from the manifest for resolving the steering manifest url
|
59845
|
+
* @param {Object} steeringTag the content steering tag from the main manifest
|
59846
|
+
*/
|
59847
|
+
|
59848
|
+
assignTagProperties(baseUrl, steeringTag) {
|
59849
|
+
this.manifestType_ = steeringTag.serverUri ? 'HLS' : 'DASH'; // serverUri is HLS serverURL is DASH
|
59850
|
+
|
59851
|
+
const steeringUri = steeringTag.serverUri || steeringTag.serverURL;
|
59852
|
+
if (!steeringUri) {
|
59853
|
+
this.logger_(`steering manifest URL is ${steeringUri}, cannot request steering manifest.`);
|
59854
|
+
this.trigger('error');
|
59855
|
+
return;
|
59856
|
+
} // Content steering manifests can be encoded as a data URI. We can decode, parse and return early if that's the case.
|
59857
|
+
|
59858
|
+
if (steeringUri.startsWith('data:')) {
|
59859
|
+
this.decodeDataUriManifest_(steeringUri.substring(steeringUri.indexOf(',') + 1));
|
59860
|
+
return;
|
59861
|
+
} // With DASH queryBeforeStart, we want to use the steeringUri as soon as possible for the request.
|
59862
|
+
|
59863
|
+
this.steeringManifest.reloadUri = this.queryBeforeStart ? steeringUri : resolveUrl(baseUrl, steeringUri); // pathwayId is HLS defaultServiceLocation is DASH
|
59864
|
+
|
59865
|
+
this.defaultPathway = steeringTag.pathwayId || steeringTag.defaultServiceLocation; // currently only DASH supports the following properties on <ContentSteering> tags.
|
59866
|
+
|
59867
|
+
this.queryBeforeStart = steeringTag.queryBeforeStart || false;
|
59868
|
+
this.proxyServerUrl_ = steeringTag.proxyServerURL || null; // trigger a steering event if we have a pathway from the content steering tag.
|
59869
|
+
// this tells VHS which segment pathway to start with.
|
59870
|
+
// If queryBeforeStart is true we need to wait for the steering manifest response.
|
59871
|
+
|
59872
|
+
if (this.defaultPathway && !this.queryBeforeStart) {
|
59873
|
+
this.trigger('content-steering');
|
59874
|
+
}
|
59875
|
+
if (this.queryBeforeStart) {
|
59876
|
+
this.requestSteeringManifest(this.steeringManifest.reloadUri);
|
59877
|
+
}
|
59878
|
+
}
|
59879
|
+
/**
|
59880
|
+
* Requests the content steering manifest and parse the response. This should only be called after
|
59881
|
+
* assignTagProperties was called with a content steering tag.
|
59882
|
+
*
|
59883
|
+
* @param {string} initialUri The optional uri to make the request with.
|
59884
|
+
* If set, the request should be made with exactly what is passed in this variable.
|
59885
|
+
* This scenario is specific to DASH when the queryBeforeStart parameter is true.
|
59886
|
+
* This scenario should only happen once on initalization.
|
59887
|
+
*/
|
59888
|
+
|
59889
|
+
requestSteeringManifest(initialUri) {
|
59890
|
+
const reloadUri = this.steeringManifest.reloadUri;
|
59891
|
+
if (!initialUri && !reloadUri) {
|
59892
|
+
return;
|
59893
|
+
} // We currently don't support passing MPD query parameters directly to the content steering URL as this requires
|
59894
|
+
// ExtUrlQueryInfo tag support. See the DASH content steering spec section 8.1.
|
59895
|
+
// This request URI accounts for manifest URIs that have been excluded.
|
59896
|
+
|
59897
|
+
const uri = initialUri || this.getRequestURI(reloadUri); // If there are no valid manifest URIs, we should stop content steering.
|
59898
|
+
|
59899
|
+
if (!uri) {
|
59900
|
+
this.logger_('No valid content steering manifest URIs. Stopping content steering.');
|
59901
|
+
this.trigger('error');
|
59902
|
+
this.dispose();
|
59903
|
+
return;
|
59904
|
+
}
|
59905
|
+
this.request_ = this.xhr_({
|
59906
|
+
uri
|
59907
|
+
}, (error, errorInfo) => {
|
59908
|
+
if (error) {
|
59909
|
+
// If the client receives HTTP 410 Gone in response to a manifest request,
|
59910
|
+
// it MUST NOT issue another request for that URI for the remainder of the
|
59911
|
+
// playback session. It MAY continue to use the most-recently obtained set
|
59912
|
+
// of Pathways.
|
59913
|
+
if (errorInfo.status === 410) {
|
59914
|
+
this.logger_(`manifest request 410 ${error}.`);
|
59915
|
+
this.logger_(`There will be no more content steering requests to ${uri} this session.`);
|
59916
|
+
this.excludedSteeringManifestURLs.add(uri);
|
59917
|
+
return;
|
59918
|
+
} // If the client receives HTTP 429 Too Many Requests with a Retry-After
|
59919
|
+
// header in response to a manifest request, it SHOULD wait until the time
|
59920
|
+
// specified by the Retry-After header to reissue the request.
|
59921
|
+
|
59922
|
+
if (errorInfo.status === 429) {
|
59923
|
+
const retrySeconds = errorInfo.responseHeaders['retry-after'];
|
59924
|
+
this.logger_(`manifest request 429 ${error}.`);
|
59925
|
+
this.logger_(`content steering will retry in ${retrySeconds} seconds.`);
|
59926
|
+
this.startTTLTimeout_(parseInt(retrySeconds, 10));
|
59927
|
+
return;
|
59928
|
+
} // If the Steering Manifest cannot be loaded and parsed correctly, the
|
59929
|
+
// client SHOULD continue to use the previous values and attempt to reload
|
59930
|
+
// it after waiting for the previously-specified TTL (or 5 minutes if
|
59931
|
+
// none).
|
59932
|
+
|
59933
|
+
this.logger_(`manifest failed to load ${error}.`);
|
59934
|
+
this.startTTLTimeout_();
|
59935
|
+
return;
|
59936
|
+
}
|
59937
|
+
const steeringManifestJson = JSON.parse(this.request_.responseText);
|
59938
|
+
this.startTTLTimeout_();
|
59939
|
+
this.assignSteeringProperties_(steeringManifestJson);
|
59940
|
+
});
|
59941
|
+
}
|
59942
|
+
/**
|
59943
|
+
* Set the proxy server URL and add the steering manifest url as a URI encoded parameter.
|
59944
|
+
*
|
59945
|
+
* @param {string} steeringUrl the steering manifest url
|
59946
|
+
* @return the steering manifest url to a proxy server with all parameters set
|
59947
|
+
*/
|
59948
|
+
|
59949
|
+
setProxyServerUrl_(steeringUrl) {
|
59950
|
+
const steeringUrlObject = new window.URL(steeringUrl);
|
59951
|
+
const proxyServerUrlObject = new window.URL(this.proxyServerUrl_);
|
59952
|
+
proxyServerUrlObject.searchParams.set('url', encodeURI(steeringUrlObject.toString()));
|
59953
|
+
return this.setSteeringParams_(proxyServerUrlObject.toString());
|
59954
|
+
}
|
59955
|
+
/**
|
59956
|
+
* Decodes and parses the data uri encoded steering manifest
|
59957
|
+
*
|
59958
|
+
* @param {string} dataUri the data uri to be decoded and parsed.
|
59959
|
+
*/
|
59960
|
+
|
59961
|
+
decodeDataUriManifest_(dataUri) {
|
59962
|
+
const steeringManifestJson = JSON.parse(window.atob(dataUri));
|
59963
|
+
this.assignSteeringProperties_(steeringManifestJson);
|
59964
|
+
}
|
59965
|
+
/**
|
59966
|
+
* Set the HLS or DASH content steering manifest request query parameters. For example:
|
59967
|
+
* _HLS_pathway="<CURRENT-PATHWAY-ID>" and _HLS_throughput=<THROUGHPUT>
|
59968
|
+
* _DASH_pathway and _DASH_throughput
|
59969
|
+
*
|
59970
|
+
* @param {string} uri to add content steering server parameters to.
|
59971
|
+
* @return a new uri as a string with the added steering query parameters.
|
59972
|
+
*/
|
59973
|
+
|
59974
|
+
setSteeringParams_(url) {
|
59975
|
+
const urlObject = new window.URL(url);
|
59976
|
+
const path = this.getPathway();
|
59977
|
+
const networkThroughput = this.getBandwidth_();
|
59978
|
+
if (path) {
|
59979
|
+
const pathwayKey = `_${this.manifestType_}_pathway`;
|
59980
|
+
urlObject.searchParams.set(pathwayKey, path);
|
59981
|
+
}
|
59982
|
+
if (networkThroughput) {
|
59983
|
+
const throughputKey = `_${this.manifestType_}_throughput`;
|
59984
|
+
urlObject.searchParams.set(throughputKey, networkThroughput);
|
59985
|
+
}
|
59986
|
+
return urlObject.toString();
|
59987
|
+
}
|
59988
|
+
/**
|
59989
|
+
* Assigns the current steering manifest properties and to the SteeringManifest object
|
59990
|
+
*
|
59991
|
+
* @param {Object} steeringJson the raw JSON steering manifest
|
59992
|
+
*/
|
59993
|
+
|
59994
|
+
assignSteeringProperties_(steeringJson) {
|
59995
|
+
this.steeringManifest.version = steeringJson.VERSION;
|
59996
|
+
if (!this.steeringManifest.version) {
|
59997
|
+
this.logger_(`manifest version is ${steeringJson.VERSION}, which is not supported.`);
|
59998
|
+
this.trigger('error');
|
59999
|
+
return;
|
60000
|
+
}
|
60001
|
+
this.steeringManifest.ttl = steeringJson.TTL;
|
60002
|
+
this.steeringManifest.reloadUri = steeringJson['RELOAD-URI']; // HLS = PATHWAY-PRIORITY required. DASH = SERVICE-LOCATION-PRIORITY optional
|
60003
|
+
|
60004
|
+
this.steeringManifest.priority = steeringJson['PATHWAY-PRIORITY'] || steeringJson['SERVICE-LOCATION-PRIORITY']; // TODO: HLS handle PATHWAY-CLONES. See section 7.2 https://datatracker.ietf.org/doc/draft-pantos-hls-rfc8216bis/
|
60005
|
+
// 1. apply first pathway from the array.
|
60006
|
+
// 2. if first pathway doesn't exist in manifest, try next pathway.
|
60007
|
+
// a. if all pathways are exhausted, ignore the steering manifest priority.
|
60008
|
+
// 3. if segments fail from an established pathway, try all variants/renditions, then exclude the failed pathway.
|
60009
|
+
// a. exclude a pathway for a minimum of the last TTL duration. Meaning, from the next steering response,
|
60010
|
+
// the excluded pathway will be ignored.
|
60011
|
+
// See excludePathway usage in excludePlaylist().
|
60012
|
+
// If there are no available pathways, we need to stop content steering.
|
60013
|
+
|
60014
|
+
if (!this.availablePathways_.size) {
|
60015
|
+
this.logger_('There are no available pathways for content steering. Ending content steering.');
|
60016
|
+
this.trigger('error');
|
60017
|
+
this.dispose();
|
60018
|
+
}
|
60019
|
+
const chooseNextPathway = pathwaysByPriority => {
|
60020
|
+
for (const path of pathwaysByPriority) {
|
60021
|
+
if (this.availablePathways_.has(path)) {
|
60022
|
+
return path;
|
60023
|
+
}
|
60024
|
+
} // If no pathway matches, ignore the manifest and choose the first available.
|
60025
|
+
|
60026
|
+
return [...this.availablePathways_][0];
|
60027
|
+
};
|
60028
|
+
const nextPathway = chooseNextPathway(this.steeringManifest.priority);
|
60029
|
+
if (this.currentPathway !== nextPathway) {
|
60030
|
+
this.currentPathway = nextPathway;
|
60031
|
+
this.trigger('content-steering');
|
60032
|
+
}
|
60033
|
+
}
|
60034
|
+
/**
|
60035
|
+
* Returns the pathway to use for steering decisions
|
60036
|
+
*
|
60037
|
+
* @return {string} returns the current pathway or the default
|
60038
|
+
*/
|
60039
|
+
|
60040
|
+
getPathway() {
|
60041
|
+
return this.currentPathway || this.defaultPathway;
|
60042
|
+
}
|
60043
|
+
/**
|
60044
|
+
* Chooses the manifest request URI based on proxy URIs and server URLs.
|
60045
|
+
* Also accounts for exclusion on certain manifest URIs.
|
60046
|
+
*
|
60047
|
+
* @param {string} reloadUri the base uri before parameters
|
60048
|
+
*
|
60049
|
+
* @return {string} the final URI for the request to the manifest server.
|
60050
|
+
*/
|
60051
|
+
|
60052
|
+
getRequestURI(reloadUri) {
|
60053
|
+
if (!reloadUri) {
|
60054
|
+
return null;
|
60055
|
+
}
|
60056
|
+
const isExcluded = uri => this.excludedSteeringManifestURLs.has(uri);
|
60057
|
+
if (this.proxyServerUrl_) {
|
60058
|
+
const proxyURI = this.setProxyServerUrl_(reloadUri);
|
60059
|
+
if (!isExcluded(proxyURI)) {
|
60060
|
+
return proxyURI;
|
60061
|
+
}
|
60062
|
+
}
|
60063
|
+
const steeringURI = this.setSteeringParams_(reloadUri);
|
60064
|
+
if (!isExcluded(steeringURI)) {
|
60065
|
+
return steeringURI;
|
60066
|
+
} // Return nothing if all valid manifest URIs are excluded.
|
60067
|
+
|
60068
|
+
return null;
|
60069
|
+
}
|
60070
|
+
/**
|
60071
|
+
* Start the timeout for re-requesting the steering manifest at the TTL interval.
|
60072
|
+
*
|
60073
|
+
* @param {number} ttl time in seconds of the timeout. Defaults to the
|
60074
|
+
* ttl interval in the steering manifest
|
60075
|
+
*/
|
60076
|
+
|
60077
|
+
startTTLTimeout_(ttl = this.steeringManifest.ttl) {
|
60078
|
+
// 300 (5 minutes) is the default value.
|
60079
|
+
const ttlMS = ttl * 1000;
|
60080
|
+
this.ttlTimeout_ = window.setTimeout(() => {
|
60081
|
+
this.requestSteeringManifest();
|
60082
|
+
}, ttlMS);
|
60083
|
+
}
|
60084
|
+
/**
|
60085
|
+
* Clear the TTL timeout if necessary.
|
60086
|
+
*/
|
60087
|
+
|
60088
|
+
clearTTLTimeout_() {
|
60089
|
+
window.clearTimeout(this.ttlTimeout_);
|
60090
|
+
this.ttlTimeout_ = null;
|
60091
|
+
}
|
60092
|
+
/**
|
60093
|
+
* aborts any current steering xhr and sets the current request object to null
|
60094
|
+
*/
|
60095
|
+
|
60096
|
+
abort() {
|
60097
|
+
if (this.request_) {
|
60098
|
+
this.request_.abort();
|
60099
|
+
}
|
60100
|
+
this.request_ = null;
|
60101
|
+
}
|
60102
|
+
/**
|
60103
|
+
* aborts steering requests clears the ttl timeout and resets all properties.
|
60104
|
+
*/
|
60105
|
+
|
60106
|
+
dispose() {
|
60107
|
+
this.off('content-steering');
|
60108
|
+
this.off('error');
|
60109
|
+
this.abort();
|
60110
|
+
this.clearTTLTimeout_();
|
60111
|
+
this.currentPathway = null;
|
60112
|
+
this.defaultPathway = null;
|
60113
|
+
this.queryBeforeStart = null;
|
60114
|
+
this.proxyServerUrl_ = null;
|
60115
|
+
this.manifestType_ = null;
|
60116
|
+
this.ttlTimeout_ = null;
|
60117
|
+
this.request_ = null;
|
60118
|
+
this.excludedSteeringManifestURLs = new Set();
|
60119
|
+
this.availablePathways_ = new Set();
|
60120
|
+
this.excludedPathways_ = new Set();
|
60121
|
+
this.steeringManifest = new SteeringManifest();
|
60122
|
+
}
|
60123
|
+
/**
|
60124
|
+
* adds a pathway to the available pathways set
|
60125
|
+
*
|
60126
|
+
* @param {string} pathway the pathway string to add
|
60127
|
+
*/
|
60128
|
+
|
60129
|
+
addAvailablePathway(pathway) {
|
60130
|
+
if (pathway) {
|
60131
|
+
this.availablePathways_.add(pathway);
|
60132
|
+
}
|
60133
|
+
}
|
60134
|
+
/**
|
60135
|
+
* clears all pathways from the available pathways set
|
60136
|
+
*/
|
60137
|
+
|
60138
|
+
clearAvailablePathways() {
|
60139
|
+
this.availablePathways_.clear();
|
60140
|
+
}
|
60141
|
+
excludePathway(pathway) {
|
60142
|
+
return this.availablePathways_.delete(pathway);
|
60143
|
+
}
|
60144
|
+
}
|
60145
|
+
|
59724
60146
|
/**
|
59725
60147
|
* @file playlist-controller.js
|
59726
60148
|
*/
|
@@ -59948,6 +60370,10 @@
|
|
59948
60370
|
tech.addWebVttScript_();
|
59949
60371
|
})
|
59950
60372
|
}), options);
|
60373
|
+
const getBandwidth = () => {
|
60374
|
+
return this.mainSegmentLoader_.bandwidth;
|
60375
|
+
};
|
60376
|
+
this.contentSteeringController_ = new ContentSteeringController(this.vhs_.xhr, getBandwidth);
|
59951
60377
|
this.setupSegmentLoaderListeners_();
|
59952
60378
|
if (this.bufferBasedABR) {
|
59953
60379
|
this.mainPlaylistLoader_.one('loadedplaylist', () => this.startABRTimer_());
|
@@ -60033,6 +60459,32 @@
|
|
60033
60459
|
}
|
60034
60460
|
this.mainPlaylistLoader_.media(playlist, delay);
|
60035
60461
|
}
|
60462
|
+
/**
|
60463
|
+
* A function that ensures we switch our playlists inside of `mediaTypes`
|
60464
|
+
* to match the current `serviceLocation` provided by the contentSteering controller.
|
60465
|
+
* We want to check media types of `AUDIO`, `SUBTITLES`, and `CLOSED-CAPTIONS`.
|
60466
|
+
*
|
60467
|
+
* This should only be called on a DASH playback scenario while using content steering.
|
60468
|
+
* This is necessary due to differences in how media in HLS manifests are generally tied to
|
60469
|
+
* a video playlist, where in DASH that is not always the case.
|
60470
|
+
*/
|
60471
|
+
|
60472
|
+
switchMediaForDASHContentSteering_() {
|
60473
|
+
['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(type => {
|
60474
|
+
const mediaType = this.mediaTypes_[type];
|
60475
|
+
const activeGroup = mediaType ? mediaType.activeGroup() : null;
|
60476
|
+
const pathway = this.contentSteeringController_.getPathway();
|
60477
|
+
if (activeGroup && pathway) {
|
60478
|
+
// activeGroup can be an array or a single group
|
60479
|
+
const mediaPlaylists = activeGroup.length ? activeGroup[0].playlists : activeGroup.playlists;
|
60480
|
+
const dashMediaPlaylists = mediaPlaylists.filter(p => p.attributes.serviceLocation === pathway); // Switch the current active playlist to the correct CDN
|
60481
|
+
|
60482
|
+
if (dashMediaPlaylists.length) {
|
60483
|
+
this.mediaTypes_[type].activePlaylistLoader.media(dashMediaPlaylists[0]);
|
60484
|
+
}
|
60485
|
+
}
|
60486
|
+
});
|
60487
|
+
}
|
60036
60488
|
/**
|
60037
60489
|
* Start a timer that periodically calls checkABR_
|
60038
60490
|
*
|
@@ -60181,8 +60633,9 @@
|
|
60181
60633
|
}
|
60182
60634
|
let updatedPlaylist = this.mainPlaylistLoader_.media();
|
60183
60635
|
if (!updatedPlaylist) {
|
60184
|
-
// exclude any variants that are not supported by the browser before selecting
|
60636
|
+
this.initContentSteeringController_(); // exclude any variants that are not supported by the browser before selecting
|
60185
60637
|
// an initial media as the playlist selectors do not consider browser support
|
60638
|
+
|
60186
60639
|
this.excludeUnsupportedVariants_();
|
60187
60640
|
let selectedMedia;
|
60188
60641
|
if (this.enableLowInitialPlaylist) {
|
@@ -60763,10 +61216,22 @@
|
|
60763
61216
|
return this.mainPlaylistLoader_.load(isFinalRendition);
|
60764
61217
|
}
|
60765
61218
|
if (isFinalRendition) {
|
60766
|
-
//
|
61219
|
+
// If we're content steering, try other pathways.
|
61220
|
+
if (this.main().contentSteering) {
|
61221
|
+
const pathway = this.pathwayAttribute_(playlistToExclude); // Ignore at least 1 steering manifest refresh.
|
61222
|
+
|
61223
|
+
const reIncludeDelay = this.contentSteeringController_.steeringManifest.ttl * 1000;
|
61224
|
+
this.contentSteeringController_.excludePathway(pathway);
|
61225
|
+
this.excludeThenChangePathway_();
|
61226
|
+
setTimeout(() => {
|
61227
|
+
this.contentSteeringController_.addAvailablePathway(pathway);
|
61228
|
+
}, reIncludeDelay);
|
61229
|
+
return;
|
61230
|
+
} // Since we're on the final non-excluded playlist, and we're about to exclude
|
60767
61231
|
// it, instead of erring the player or retrying this playlist, clear out the current
|
60768
61232
|
// exclusion list. This allows other playlists to be attempted in case any have been
|
60769
61233
|
// fixed.
|
61234
|
+
|
60770
61235
|
let reincluded = false;
|
60771
61236
|
playlists.forEach(playlist => {
|
60772
61237
|
// skip current playlist which is about to be excluded
|
@@ -61104,6 +61569,7 @@
|
|
61104
61569
|
this.decrypter_.terminate();
|
61105
61570
|
this.mainPlaylistLoader_.dispose();
|
61106
61571
|
this.mainSegmentLoader_.dispose();
|
61572
|
+
this.contentSteeringController_.dispose();
|
61107
61573
|
if (this.loadOnPlay_) {
|
61108
61574
|
this.tech_.off('play', this.loadOnPlay_);
|
61109
61575
|
}
|
@@ -61444,6 +61910,110 @@
|
|
61444
61910
|
videoDuration
|
61445
61911
|
});
|
61446
61912
|
}
|
61913
|
+
pathwayAttribute_(playlist) {
|
61914
|
+
return playlist.attributes['PATHWAY-ID'] || playlist.attributes.serviceLocation;
|
61915
|
+
}
|
61916
|
+
/**
|
61917
|
+
* Initialize content steering listeners and apply the tag properties.
|
61918
|
+
*/
|
61919
|
+
|
61920
|
+
initContentSteeringController_() {
|
61921
|
+
const initialMain = this.main();
|
61922
|
+
if (!initialMain.contentSteering) {
|
61923
|
+
return;
|
61924
|
+
}
|
61925
|
+
const updateSteeringValues = main => {
|
61926
|
+
for (const playlist of main.playlists) {
|
61927
|
+
this.contentSteeringController_.addAvailablePathway(this.pathwayAttribute_(playlist));
|
61928
|
+
}
|
61929
|
+
this.contentSteeringController_.assignTagProperties(main.uri, main.contentSteering);
|
61930
|
+
};
|
61931
|
+
updateSteeringValues(initialMain);
|
61932
|
+
this.contentSteeringController_.on('content-steering', this.excludeThenChangePathway_.bind(this)); // We need to ensure we update the content steering values when a new
|
61933
|
+
// manifest is loaded in live DASH with content steering.
|
61934
|
+
|
61935
|
+
if (this.sourceType_ === 'dash') {
|
61936
|
+
this.mainPlaylistLoader_.on('mediaupdatetimeout', () => {
|
61937
|
+
this.mainPlaylistLoader_.refreshMedia_(this.mainPlaylistLoader_.media().id); // clear past values
|
61938
|
+
|
61939
|
+
this.contentSteeringController_.abort();
|
61940
|
+
this.contentSteeringController_.clearTTLTimeout_();
|
61941
|
+
this.contentSteeringController_.clearAvailablePathways();
|
61942
|
+
updateSteeringValues(this.main());
|
61943
|
+
});
|
61944
|
+
} // Do this at startup only, after that the steering requests are managed by the Content Steering class.
|
61945
|
+
// DASH queryBeforeStart scenarios will be handled by the Content Steering class.
|
61946
|
+
|
61947
|
+
if (!this.contentSteeringController_.queryBeforeStart) {
|
61948
|
+
this.tech_.one('canplay', () => {
|
61949
|
+
this.contentSteeringController_.requestSteeringManifest();
|
61950
|
+
});
|
61951
|
+
}
|
61952
|
+
}
|
61953
|
+
/**
|
61954
|
+
* Simple exclude and change playlist logic for content steering.
|
61955
|
+
*/
|
61956
|
+
|
61957
|
+
excludeThenChangePathway_() {
|
61958
|
+
const currentPathway = this.contentSteeringController_.getPathway();
|
61959
|
+
if (!currentPathway) {
|
61960
|
+
return;
|
61961
|
+
}
|
61962
|
+
const main = this.main();
|
61963
|
+
const playlists = main.playlists;
|
61964
|
+
const ids = new Set();
|
61965
|
+
let didEnablePlaylists = false;
|
61966
|
+
Object.keys(playlists).forEach(key => {
|
61967
|
+
const variant = playlists[key];
|
61968
|
+
const pathwayId = this.pathwayAttribute_(variant);
|
61969
|
+
const differentPathwayId = pathwayId && currentPathway !== pathwayId;
|
61970
|
+
const steeringExclusion = variant.excludeUntil === Infinity && variant.lastExcludeReason_ === 'content-steering';
|
61971
|
+
if (steeringExclusion && !differentPathwayId) {
|
61972
|
+
delete variant.excludeUntil;
|
61973
|
+
delete variant.lastExcludeReason_;
|
61974
|
+
didEnablePlaylists = true;
|
61975
|
+
}
|
61976
|
+
const noExcludeUntil = !variant.excludeUntil && variant.excludeUntil !== Infinity;
|
61977
|
+
const shouldExclude = !ids.has(variant.id) && differentPathwayId && noExcludeUntil;
|
61978
|
+
if (!shouldExclude) {
|
61979
|
+
return;
|
61980
|
+
}
|
61981
|
+
ids.add(variant.id);
|
61982
|
+
variant.excludeUntil = Infinity;
|
61983
|
+
variant.lastExcludeReason_ = 'content-steering'; // TODO: kind of spammy, maybe move this.
|
61984
|
+
|
61985
|
+
this.logger_(`excluding ${variant.id} for ${variant.lastExcludeReason_}`);
|
61986
|
+
});
|
61987
|
+
if (this.contentSteeringController_.manifestType_ === 'DASH') {
|
61988
|
+
Object.keys(this.mediaTypes_).forEach(key => {
|
61989
|
+
const type = this.mediaTypes_[key];
|
61990
|
+
if (type.activePlaylistLoader) {
|
61991
|
+
const currentPlaylist = type.activePlaylistLoader.media_; // Check if the current media playlist matches the current CDN
|
61992
|
+
|
61993
|
+
if (currentPlaylist && currentPlaylist.attributes.serviceLocation !== currentPathway) {
|
61994
|
+
didEnablePlaylists = true;
|
61995
|
+
}
|
61996
|
+
}
|
61997
|
+
});
|
61998
|
+
}
|
61999
|
+
if (didEnablePlaylists) {
|
62000
|
+
this.changeSegmentPathway_();
|
62001
|
+
}
|
62002
|
+
}
|
62003
|
+
/**
|
62004
|
+
* Changes the current playlists for audio, video and subtitles after a new pathway
|
62005
|
+
* is chosen from content steering.
|
62006
|
+
*/
|
62007
|
+
|
62008
|
+
changeSegmentPathway_() {
|
62009
|
+
const nextPlaylist = this.selectPlaylist();
|
62010
|
+
this.pauseLoading(); // Switch audio and text track playlists if necessary in DASH
|
62011
|
+
|
62012
|
+
if (this.contentSteeringController_.manifestType_ === 'DASH') {
|
62013
|
+
this.switchMediaForDASHContentSteering_();
|
62014
|
+
}
|
62015
|
+
this.switchMedia_(nextPlaylist, 'content-steering');
|
62016
|
+
}
|
61447
62017
|
}
|
61448
62018
|
|
61449
62019
|
/**
|
@@ -62192,8 +62762,8 @@
|
|
62192
62762
|
const reloadSourceOnError = function (options) {
|
62193
62763
|
initPlugin(this, options);
|
62194
62764
|
};
|
62195
|
-
var version$4 = "3.
|
62196
|
-
var version$3 = "7.0.
|
62765
|
+
var version$4 = "3.7.0";
|
62766
|
+
var version$3 = "7.0.1";
|
62197
62767
|
var version$2 = "1.2.2";
|
62198
62768
|
var version$1 = "7.1.0";
|
62199
62769
|
var version = "4.0.1";
|