shaka-player 4.6.8 → 4.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/locales.js +34 -34
- package/dist/shaka-player.compiled.debug.js +83 -81
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +513 -511
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.debug.js +101 -99
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +615 -613
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/index.json +1 -0
- package/docs/tutorials/text-displayer.md +15 -0
- package/lib/cast/cast_proxy.js +18 -0
- package/lib/hls/hls_utils.js +5 -5
- package/lib/media/media_source_engine.js +1 -1
- package/lib/media/play_rate_controller.js +1 -0
- package/lib/player.js +30 -1
- package/lib/text/ttml_text_parser.js +5 -0
- package/lib/util/language_utils.js +7 -8
- package/package.json +1 -1
- package/test/media/media_source_engine_unit.js +2 -2
- package/test/text/ttml_text_parser_unit.js +16 -16
- package/ui/playback_rate_selection.js +4 -0
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
{ "license-wrapping": { "title": "License Wrapping" } },
|
|
10
10
|
{ "ui": { "title": "UI Library" } },
|
|
11
11
|
{ "ui-customization": { "title": "Configuring the UI" } },
|
|
12
|
+
{ "text-displayer": { "title": "Configuring text displayer" } },
|
|
12
13
|
{ "errors": { "title": "Error Handling" } },
|
|
13
14
|
{ "a11y": { "title": "Creating accessible buttons" } },
|
|
14
15
|
{ "ad_monetization": { "title": "Serving ads with our IMA SDK integration" } },
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Configuring text displayer`
|
|
2
|
+
|
|
3
|
+
Shaka Player supports two types of Text Displayer.
|
|
4
|
+
1) Using the browser's native API, Shaka Player creates a textTrack along
|
|
5
|
+
with the AUDIO or VIDEO Element.
|
|
6
|
+
2) Rendering the subtitles in a container in the DOM.
|
|
7
|
+
3) Providing a custom text displayer factory would allow a developer to make
|
|
8
|
+
their own custom text displayer that fits neither category.
|
|
9
|
+
|
|
10
|
+
By default, if not configured otherwise, the player will use type 1.
|
|
11
|
+
To configure type 2, you have to call `setVideoContainer` function before
|
|
12
|
+
making `load` call in the player.
|
|
13
|
+
|
|
14
|
+
Note: The UI calls setVideoContainer for you if the video's controls are
|
|
15
|
+
disabled, so this isn't always necessary when using the UI.
|
package/lib/cast/cast_proxy.js
CHANGED
|
@@ -496,6 +496,16 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
496
496
|
startTime = this.sender_.get('video', 'currentTime');
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
+
let activeTextTrack;
|
|
500
|
+
const textTracks = this.sender_.get('player', 'getTextTracks')();
|
|
501
|
+
|
|
502
|
+
if (textTracks && textTracks.length) {
|
|
503
|
+
activeTextTrack = textTracks.find((t) => t.active);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const isTextTrackVisible =
|
|
507
|
+
this.sender_.get('player', 'isTextTrackVisible')();
|
|
508
|
+
|
|
499
509
|
// Now load the manifest, if present.
|
|
500
510
|
if (assetUri) {
|
|
501
511
|
// Don't autoplay the content until we finish setting up initial state.
|
|
@@ -527,6 +537,14 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
527
537
|
/** @type {Object} */(this.localPlayer_)[setter](value);
|
|
528
538
|
}
|
|
529
539
|
|
|
540
|
+
this.localPlayer_.setTextTrackVisibility(isTextTrackVisible);
|
|
541
|
+
if (activeTextTrack) {
|
|
542
|
+
this.localPlayer_.selectTextLanguage(
|
|
543
|
+
activeTextTrack.language,
|
|
544
|
+
activeTextTrack.roles,
|
|
545
|
+
activeTextTrack.forced);
|
|
546
|
+
}
|
|
547
|
+
|
|
530
548
|
// Restore the original autoplay setting.
|
|
531
549
|
this.localVideo_.autoplay = autoplay;
|
|
532
550
|
if (assetUri) {
|
package/lib/hls/hls_utils.js
CHANGED
|
@@ -47,12 +47,12 @@ shaka.hls.Utils = class {
|
|
|
47
47
|
* @return {?shaka.hls.Tag}
|
|
48
48
|
*/
|
|
49
49
|
static getFirstTagWithName(tags, name) {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
for (const tag of tags) {
|
|
51
|
+
if (tag.name === name) {
|
|
52
|
+
return tag;
|
|
53
|
+
}
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
-
return tagsWithName[0];
|
|
55
|
+
return null;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|
|
@@ -1793,7 +1793,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1793
1793
|
|
|
1794
1794
|
this.destroyer_.ensureNotDestroyed();
|
|
1795
1795
|
|
|
1796
|
-
this.eventManager_.listenOnce(this.video_, '
|
|
1796
|
+
this.eventManager_.listenOnce(this.video_, 'canplaythrough', () => {
|
|
1797
1797
|
this.destroyer_.ensureNotDestroyed();
|
|
1798
1798
|
|
|
1799
1799
|
this.video_.autoplay = previousAutoPlayState;
|
package/lib/player.js
CHANGED
|
@@ -549,6 +549,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
549
549
|
*/
|
|
550
550
|
this.loadEventManager_ = new shaka.util.EventManager();
|
|
551
551
|
|
|
552
|
+
/**
|
|
553
|
+
* For listeners scoped to the lifetime of the loaded content.
|
|
554
|
+
* @private {shaka.util.EventManager}
|
|
555
|
+
*/
|
|
556
|
+
this.trickPlayEventManager_ = new shaka.util.EventManager();
|
|
557
|
+
|
|
552
558
|
/** @private {shaka.net.NetworkingEngine} */
|
|
553
559
|
this.networkingEngine_ = null;
|
|
554
560
|
|
|
@@ -840,6 +846,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
840
846
|
this.loadEventManager_.release();
|
|
841
847
|
this.loadEventManager_ = null;
|
|
842
848
|
}
|
|
849
|
+
if (this.trickPlayEventManager_) {
|
|
850
|
+
this.trickPlayEventManager_.release();
|
|
851
|
+
this.trickPlayEventManager_ = null;
|
|
852
|
+
}
|
|
843
853
|
|
|
844
854
|
this.abrManagerFactory_ = null;
|
|
845
855
|
this.config_ = null;
|
|
@@ -1157,6 +1167,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1157
1167
|
// element.
|
|
1158
1168
|
if (this.video_) {
|
|
1159
1169
|
this.loadEventManager_.removeAll();
|
|
1170
|
+
this.trickPlayEventManager_.removeAll();
|
|
1160
1171
|
}
|
|
1161
1172
|
|
|
1162
1173
|
// Stop the variant checker timer
|
|
@@ -3504,6 +3515,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3504
3515
|
shaka.log.alwaysWarn('A trick play rate of 0 is unsupported!');
|
|
3505
3516
|
return;
|
|
3506
3517
|
}
|
|
3518
|
+
this.trickPlayEventManager_.removeAll();
|
|
3507
3519
|
|
|
3508
3520
|
if (this.video_.paused) {
|
|
3509
3521
|
// Our fast forward is implemented with playbackRate and needs the video
|
|
@@ -3517,6 +3529,22 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3517
3529
|
this.abrManager_.playbackRateChanged(rate);
|
|
3518
3530
|
this.streamingEngine_.setTrickPlay(Math.abs(rate) > 1);
|
|
3519
3531
|
}
|
|
3532
|
+
if (this.isLive()) {
|
|
3533
|
+
this.trickPlayEventManager_.listen(this.video_, 'timeupdate', () => {
|
|
3534
|
+
const currentTime = this.video_.currentTime;
|
|
3535
|
+
const seekRange = this.seekRange();
|
|
3536
|
+
const safeSeekOffset = this.config_.streaming.safeSeekOffset;
|
|
3537
|
+
if (rate > 0) {
|
|
3538
|
+
if (currentTime >= seekRange.end) {
|
|
3539
|
+
this.cancelTrickPlay();
|
|
3540
|
+
}
|
|
3541
|
+
} else {
|
|
3542
|
+
if (currentTime <= (seekRange.start + safeSeekOffset)) {
|
|
3543
|
+
this.cancelTrickPlay();
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
});
|
|
3547
|
+
}
|
|
3520
3548
|
}
|
|
3521
3549
|
|
|
3522
3550
|
/**
|
|
@@ -3536,6 +3564,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3536
3564
|
this.abrManager_.playbackRateChanged(defaultPlaybackRate);
|
|
3537
3565
|
this.streamingEngine_.setTrickPlay(false);
|
|
3538
3566
|
}
|
|
3567
|
+
this.trickPlayEventManager_.removeAll();
|
|
3539
3568
|
}
|
|
3540
3569
|
|
|
3541
3570
|
/**
|
|
@@ -6785,7 +6814,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6785
6814
|
* @export
|
|
6786
6815
|
*/
|
|
6787
6816
|
// eslint-disable-next-line no-useless-concat
|
|
6788
|
-
shaka.Player.version = 'v4.6.
|
|
6817
|
+
shaka.Player.version = 'v4.6.9' + '-uncompiled'; // x-release-please-version
|
|
6789
6818
|
|
|
6790
6819
|
// Initialize the deprecation system using the version string we just set
|
|
6791
6820
|
// on the player.
|
|
@@ -491,6 +491,11 @@ shaka.text.TtmlTextParser = class {
|
|
|
491
491
|
region.viewportAnchorX = region.viewportAnchorX * 100 /
|
|
492
492
|
globalWidth;
|
|
493
493
|
}
|
|
494
|
+
} else if (!extent) {
|
|
495
|
+
region.width = 100 - region.viewportAnchorX;
|
|
496
|
+
region.widthUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
497
|
+
region.height = 100 - region.viewportAnchorY;
|
|
498
|
+
region.heightUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
494
499
|
}
|
|
495
500
|
|
|
496
501
|
region.viewportAnchorUnits = percentage || globalWidth != null ?
|
|
@@ -192,25 +192,24 @@ shaka.util.LanguageUtils = class {
|
|
|
192
192
|
const LanguageUtils = shaka.util.LanguageUtils;
|
|
193
193
|
|
|
194
194
|
const privateusePrefix = 'x-';
|
|
195
|
-
const
|
|
196
|
-
|
|
195
|
+
const [languageRegion = '', privateuseSuffix = ''] =
|
|
196
|
+
locale.split(`-${privateusePrefix}`);
|
|
197
|
+
const [languageCode = '', regionCode = ''] = languageRegion.split('-');
|
|
197
198
|
|
|
198
199
|
// We are only going to use the language, the region and the "privateuse" part (as per https://datatracker.ietf.org/doc/html/rfc5646).
|
|
199
200
|
// Anything else is thrown away.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const privateuse = components[1] ?
|
|
203
|
-
`${privateusePrefix}${components[1]}` : '';
|
|
201
|
+
const privateuse = privateuseSuffix ?
|
|
202
|
+
`${privateusePrefix}${privateuseSuffix}` : '';
|
|
204
203
|
|
|
205
204
|
// Convert the language to lower case. It is standard for the language code
|
|
206
205
|
// to be in lower case, but it will also make the map look-up easier.
|
|
207
|
-
language =
|
|
206
|
+
let language = languageCode.toLowerCase();
|
|
208
207
|
language = LanguageUtils.isoMap_.get(language) || language;
|
|
209
208
|
|
|
210
209
|
// Convert the region to upper case. It is standard for the region to be in
|
|
211
210
|
// upper case. If there is no upper code, then it will be an empty string
|
|
212
211
|
// and this will be a no-op.
|
|
213
|
-
region =
|
|
212
|
+
const region = regionCode.toUpperCase();
|
|
214
213
|
|
|
215
214
|
return `${region ? `${language}-${region}` : language}${
|
|
216
215
|
privateuse ? `-${privateuse}` : ''}`;
|
package/package.json
CHANGED
|
@@ -1246,7 +1246,7 @@ describe('MediaSourceEngine', () => {
|
|
|
1246
1246
|
const callback = addListenOnceSpy.calls.argsFor(0)[2];
|
|
1247
1247
|
callback();
|
|
1248
1248
|
expect(initSourceBufferSpy).toHaveBeenCalled();
|
|
1249
|
-
expect(addListenOnceSpy.calls.argsFor(0)[1]).toBe('
|
|
1249
|
+
expect(addListenOnceSpy.calls.argsFor(0)[1]).toBe('canplaythrough');
|
|
1250
1250
|
expect(video.autoplay).toBe(true);
|
|
1251
1251
|
expect(playSpy).not.toHaveBeenCalled();
|
|
1252
1252
|
} finally {
|
|
@@ -1313,7 +1313,7 @@ describe('MediaSourceEngine', () => {
|
|
|
1313
1313
|
const callback = addListenOnceSpy.calls.argsFor(0)[2];
|
|
1314
1314
|
callback();
|
|
1315
1315
|
expect(initSourceBufferSpy).toHaveBeenCalled();
|
|
1316
|
-
expect(addListenOnceSpy.calls.argsFor(0)[1]).toBe('
|
|
1316
|
+
expect(addListenOnceSpy.calls.argsFor(0)[1]).toBe('canplaythrough');
|
|
1317
1317
|
expect(video.autoplay).toBe(false);
|
|
1318
1318
|
expect(playSpy).toHaveBeenCalled();
|
|
1319
1319
|
} finally {
|
|
@@ -638,8 +638,8 @@ describe('TtmlTextParser', () => {
|
|
|
638
638
|
id: 'subtitleArea',
|
|
639
639
|
viewportAnchorX: 50,
|
|
640
640
|
viewportAnchorY: 16,
|
|
641
|
-
width:
|
|
642
|
-
height:
|
|
641
|
+
width: 50,
|
|
642
|
+
height: 84,
|
|
643
643
|
},
|
|
644
644
|
startTime: 62.05,
|
|
645
645
|
endTime: 3723.2,
|
|
@@ -666,8 +666,8 @@ describe('TtmlTextParser', () => {
|
|
|
666
666
|
region: {
|
|
667
667
|
viewportAnchorX: 50,
|
|
668
668
|
viewportAnchorY: 16,
|
|
669
|
-
width:
|
|
670
|
-
height:
|
|
669
|
+
width: 50,
|
|
670
|
+
height: 84,
|
|
671
671
|
},
|
|
672
672
|
startTime: 62.05,
|
|
673
673
|
endTime: 3723.2,
|
|
@@ -694,8 +694,8 @@ describe('TtmlTextParser', () => {
|
|
|
694
694
|
region: {
|
|
695
695
|
viewportAnchorX: 50,
|
|
696
696
|
viewportAnchorY: 16,
|
|
697
|
-
width:
|
|
698
|
-
height:
|
|
697
|
+
width: 50,
|
|
698
|
+
height: 84,
|
|
699
699
|
},
|
|
700
700
|
startTime: 62.05,
|
|
701
701
|
endTime: 3723.2,
|
|
@@ -872,8 +872,8 @@ describe('TtmlTextParser', () => {
|
|
|
872
872
|
viewportAnchorY: 16,
|
|
873
873
|
regionAnchorX: 0,
|
|
874
874
|
regionAnchorY: 0,
|
|
875
|
-
width:
|
|
876
|
-
height:
|
|
875
|
+
width: 50,
|
|
876
|
+
height: 84,
|
|
877
877
|
heightUnits: CueRegion.units.PERCENTAGE,
|
|
878
878
|
widthUnits: CueRegion.units.PERCENTAGE,
|
|
879
879
|
viewportAnchorUnits: CueRegion.units.PERCENTAGE,
|
|
@@ -945,8 +945,8 @@ describe('TtmlTextParser', () => {
|
|
|
945
945
|
id: 'subtitleArea',
|
|
946
946
|
viewportAnchorX: 50,
|
|
947
947
|
viewportAnchorY: 16,
|
|
948
|
-
width:
|
|
949
|
-
height:
|
|
948
|
+
width: 50,
|
|
949
|
+
height: 84,
|
|
950
950
|
},
|
|
951
951
|
startTime: 62.05,
|
|
952
952
|
endTime: 3723.2,
|
|
@@ -973,8 +973,8 @@ describe('TtmlTextParser', () => {
|
|
|
973
973
|
region: {
|
|
974
974
|
viewportAnchorX: 50,
|
|
975
975
|
viewportAnchorY: 16,
|
|
976
|
-
width:
|
|
977
|
-
height:
|
|
976
|
+
width: 50,
|
|
977
|
+
height: 84,
|
|
978
978
|
},
|
|
979
979
|
startTime: 62.05,
|
|
980
980
|
endTime: 3723.2,
|
|
@@ -1001,8 +1001,8 @@ describe('TtmlTextParser', () => {
|
|
|
1001
1001
|
region: {
|
|
1002
1002
|
viewportAnchorX: 50,
|
|
1003
1003
|
viewportAnchorY: 16,
|
|
1004
|
-
width:
|
|
1005
|
-
height:
|
|
1004
|
+
width: 50,
|
|
1005
|
+
height: 84,
|
|
1006
1006
|
},
|
|
1007
1007
|
startTime: 62.05,
|
|
1008
1008
|
endTime: 3723.2,
|
|
@@ -1032,8 +1032,8 @@ describe('TtmlTextParser', () => {
|
|
|
1032
1032
|
id: 'subtitleArea',
|
|
1033
1033
|
viewportAnchorX: 12.2,
|
|
1034
1034
|
viewportAnchorY: 50.005,
|
|
1035
|
-
width:
|
|
1036
|
-
height:
|
|
1035
|
+
width: 87.8,
|
|
1036
|
+
height: 49.995,
|
|
1037
1037
|
},
|
|
1038
1038
|
startTime: 62.05,
|
|
1039
1039
|
endTime: 3723.2,
|
|
@@ -44,6 +44,10 @@ shaka.ui.PlaybackRateSelection = class extends shaka.ui.SettingsMenu {
|
|
|
44
44
|
this.updateLocalizedStrings_();
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
+
this.eventManager.listen(this.player, 'loaded', () => {
|
|
48
|
+
this.updatePlaybackRateSelection_(this.player.getPlaybackRate());
|
|
49
|
+
});
|
|
50
|
+
|
|
47
51
|
this.eventManager.listen(this.player, 'ratechange', () => {
|
|
48
52
|
this.updatePlaybackRateSelection_(this.player.getPlaybackRate());
|
|
49
53
|
});
|