@gcorevideo/player 2.29.0 → 2.30.1
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/README.md +108 -0
- package/dist/core.js +81 -22
- package/dist/index.css +370 -370
- package/dist/index.embed.js +80 -23
- package/dist/index.js +459 -87
- package/docs/api/player.md +37 -0
- package/docs/api/player.player.getplugin.md +59 -0
- package/docs/api/player.player.md +14 -0
- package/docs/api/player.tokenrefreshoptions.gettoken.md +13 -0
- package/docs/api/player.tokenrefreshoptions.ipbound.md +13 -0
- package/docs/api/player.tokenrefreshoptions.md +115 -0
- package/docs/api/player.tokenrefreshoptions.ontokenrefreshed.md +13 -0
- package/docs/api/player.tokenrefreshoptions.refreshleadseconds.md +13 -0
- package/docs/api/player.tokenrefreshplugin.md +50 -0
- package/docs/api/player.tokenresponse.client_ip.md +13 -0
- package/docs/api/player.tokenresponse.expires.md +13 -0
- package/docs/api/player.tokenresponse.md +153 -0
- package/docs/api/player.tokenresponse.token.md +13 -0
- package/docs/api/player.tokenresponse.token_ip.md +13 -0
- package/docs/api/player.tokenresponse.url.md +13 -0
- package/docs/api/player.tokenresponse.url_ip.md +13 -0
- package/lib/Player.d.ts +9 -0
- package/lib/Player.d.ts.map +1 -1
- package/lib/Player.js +11 -0
- package/lib/index.plugins.d.ts +1 -0
- package/lib/index.plugins.d.ts.map +1 -1
- package/lib/index.plugins.js +1 -0
- package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.js +5 -1
- package/lib/playback/hls-playback/HlsPlayback.d.ts +1 -1
- package/lib/playback/hls-playback/HlsPlayback.d.ts.map +1 -1
- package/lib/playback/hls-playback/HlsPlayback.js +23 -20
- package/lib/playback/hls-playback/RangesList.d.ts +7 -0
- package/lib/playback/hls-playback/RangesList.d.ts.map +1 -0
- package/lib/playback/hls-playback/RangesList.js +41 -0
- package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -1
- package/lib/plugins/subtitles/ClosedCaptions.js +0 -2
- package/lib/plugins/token-refresh/TokenRefreshPlugin.d.ts +119 -0
- package/lib/plugins/token-refresh/TokenRefreshPlugin.d.ts.map +1 -0
- package/lib/plugins/token-refresh/TokenRefreshPlugin.js +318 -0
- package/lib/plugins/token-refresh/index.d.ts +2 -0
- package/lib/plugins/token-refresh/index.d.ts.map +1 -0
- package/lib/plugins/token-refresh/index.js +1 -0
- package/package.json +1 -1
- package/src/Player.ts +12 -0
- package/src/index.plugins.ts +1 -0
- package/src/playback/dash-playback/DashPlayback.ts +6 -1
- package/src/playback/hls-playback/HlsPlayback.ts +40 -37
- package/src/playback/hls-playback/RangesList.ts +45 -0
- package/src/playback/hls-playback/__tests__/RangesList.test.ts +60 -0
- package/src/plugins/subtitles/ClosedCaptions.ts +0 -5
- package/src/plugins/token-refresh/TokenRefreshPlugin.ts +425 -0
- package/src/plugins/token-refresh/index.ts +5 -0
- package/tsconfig.tsbuildinfo +1 -1
package/dist/index.js
CHANGED
|
@@ -12922,7 +12922,7 @@ var PlaybackEvents;
|
|
|
12922
12922
|
// https://github.com/clappr/clappr/blob/8752995ea439321ac7ca3cd35e8c64de7a3c3d17/LICENSE
|
|
12923
12923
|
const AUTO$1 = -1;
|
|
12924
12924
|
const { now: now$2 } = Utils;
|
|
12925
|
-
const T$
|
|
12925
|
+
const T$f = 'playback.dash';
|
|
12926
12926
|
class DashPlayback extends BasePlayback {
|
|
12927
12927
|
_levels = [];
|
|
12928
12928
|
_currentLevel = AUTO$1;
|
|
@@ -13055,6 +13055,7 @@ class DashPlayback extends BasePlayback {
|
|
|
13055
13055
|
this._dash = dash;
|
|
13056
13056
|
this._dash.initialize();
|
|
13057
13057
|
if (this.options.dash) {
|
|
13058
|
+
const { requestInterceptor, ...dashSettings } = this.options.dash;
|
|
13058
13059
|
const settings = $.extend(true, {
|
|
13059
13060
|
streaming: {
|
|
13060
13061
|
text: {
|
|
@@ -13066,8 +13067,11 @@ class DashPlayback extends BasePlayback {
|
|
|
13066
13067
|
// dispatchForManualRendering: true, // TODO only when useNativeSubtitles is not true?
|
|
13067
13068
|
},
|
|
13068
13069
|
},
|
|
13069
|
-
},
|
|
13070
|
+
}, dashSettings);
|
|
13070
13071
|
this._dash.updateSettings(settings);
|
|
13072
|
+
if (typeof requestInterceptor === 'function') {
|
|
13073
|
+
this._dash.addRequestInterceptor(requestInterceptor);
|
|
13074
|
+
}
|
|
13071
13075
|
}
|
|
13072
13076
|
this._dash.attachView(this.el);
|
|
13073
13077
|
this._dash.setAutoPlay(false);
|
|
@@ -13195,7 +13199,7 @@ class DashPlayback extends BasePlayback {
|
|
|
13195
13199
|
this.trigger(Events$1.PLAYBACK_SETTINGSUPDATE);
|
|
13196
13200
|
}
|
|
13197
13201
|
_onPlaybackError = (event) => {
|
|
13198
|
-
trace(`${T$
|
|
13202
|
+
trace(`${T$f} _onPlaybackError`, { type: event.type, code: event.error.code, message: event.error.message });
|
|
13199
13203
|
};
|
|
13200
13204
|
_onDASHJSSError = (event) => {
|
|
13201
13205
|
this._stopTimeUpdateTimer();
|
|
@@ -50088,6 +50092,48 @@ Hls.defaultConfig = void 0;
|
|
|
50088
50092
|
// export const CLAPPR_VERSION: string = process.env.CLAPPR_VERSION || '0.11.3';
|
|
50089
50093
|
const CLAPPR_VERSION$1 = '0.13.0';
|
|
50090
50094
|
|
|
50095
|
+
class RangesList {
|
|
50096
|
+
// TODO write an efficient implementation
|
|
50097
|
+
items = [];
|
|
50098
|
+
insert(start, end, value) {
|
|
50099
|
+
const index = this.findIndex((start + end) / 2);
|
|
50100
|
+
this.items.splice(index, 0, [start, end, value]);
|
|
50101
|
+
}
|
|
50102
|
+
find(position) {
|
|
50103
|
+
const index = this.findIndex(position);
|
|
50104
|
+
const item = this.items[index];
|
|
50105
|
+
if (!item || item[0] > position || item[1] < position) {
|
|
50106
|
+
return null;
|
|
50107
|
+
}
|
|
50108
|
+
return item[2];
|
|
50109
|
+
}
|
|
50110
|
+
findIndex(position) {
|
|
50111
|
+
let low = 0;
|
|
50112
|
+
let high = this.items.length;
|
|
50113
|
+
let index = 0;
|
|
50114
|
+
while (low < high) {
|
|
50115
|
+
index = low + Math.floor((high - low) / 2);
|
|
50116
|
+
const item = this.items[index];
|
|
50117
|
+
if (item[0] > position) {
|
|
50118
|
+
if (index === low) {
|
|
50119
|
+
return index;
|
|
50120
|
+
}
|
|
50121
|
+
high = index;
|
|
50122
|
+
continue;
|
|
50123
|
+
}
|
|
50124
|
+
if (item[1] <= position) {
|
|
50125
|
+
if (index === high - 1) {
|
|
50126
|
+
return index + 1;
|
|
50127
|
+
}
|
|
50128
|
+
low = index + 1;
|
|
50129
|
+
continue;
|
|
50130
|
+
}
|
|
50131
|
+
break;
|
|
50132
|
+
}
|
|
50133
|
+
return index;
|
|
50134
|
+
}
|
|
50135
|
+
}
|
|
50136
|
+
|
|
50091
50137
|
// Copyright 2014 Globo.com Player authors. All rights reserved.
|
|
50092
50138
|
// Use of this source code is governed by a BSD-style
|
|
50093
50139
|
// license that can be found on https://github.com/clappr/hlsjs-playback/blob/main/LICENSE
|
|
@@ -50095,9 +50141,8 @@ const { now } = Utils;
|
|
|
50095
50141
|
const AUTO = -1;
|
|
50096
50142
|
const DEFAULT_RECOVER_ATTEMPTS = 16;
|
|
50097
50143
|
Events$1.register('PLAYBACK_FRAGMENT_PARSING_METADATA');
|
|
50098
|
-
const T$
|
|
50144
|
+
const T$e = 'playback.hls';
|
|
50099
50145
|
class HlsPlayback extends BasePlayback {
|
|
50100
|
-
_ccTracksUpdated = false;
|
|
50101
50146
|
_currentFragment = null;
|
|
50102
50147
|
_currentLevel = null;
|
|
50103
50148
|
_durationExcludesAfterLiveSyncPoint = false;
|
|
@@ -50122,7 +50167,8 @@ class HlsPlayback extends BasePlayback {
|
|
|
50122
50167
|
_timeUpdateTimer = null;
|
|
50123
50168
|
oncueenter = null;
|
|
50124
50169
|
oncueexit = null;
|
|
50125
|
-
cues =
|
|
50170
|
+
cues = null;
|
|
50171
|
+
cuesByTrack = {};
|
|
50126
50172
|
currentCueId = null;
|
|
50127
50173
|
/**
|
|
50128
50174
|
* @internal
|
|
@@ -50319,7 +50365,6 @@ class HlsPlayback extends BasePlayback {
|
|
|
50319
50365
|
}
|
|
50320
50366
|
this._manifestParsed = false;
|
|
50321
50367
|
// this._ccIsSetup = false
|
|
50322
|
-
this._ccTracksUpdated = false;
|
|
50323
50368
|
this._setInitialState();
|
|
50324
50369
|
this._hls.destroy();
|
|
50325
50370
|
this._hls = null;
|
|
@@ -50373,12 +50418,20 @@ class HlsPlayback extends BasePlayback {
|
|
|
50373
50418
|
this._hls.on(Events.AUDIO_TRACK_SWITCHED, (evt, data) => this._onAudioTrackSwitched(evt, data));
|
|
50374
50419
|
this._hls.on(Events.CUES_PARSED, (evt, data) => {
|
|
50375
50420
|
data.cues?.forEach((cue) => {
|
|
50376
|
-
this.cues
|
|
50421
|
+
if (!this.cues) {
|
|
50422
|
+
const trackId = this._hls.subtitleTrack;
|
|
50423
|
+
if (!this.cuesByTrack[trackId]) {
|
|
50424
|
+
this.cuesByTrack[trackId] = new RangesList();
|
|
50425
|
+
}
|
|
50426
|
+
this.cues = this.cuesByTrack[trackId];
|
|
50427
|
+
}
|
|
50428
|
+
const cueInfo = {
|
|
50377
50429
|
id: cue.id,
|
|
50378
50430
|
start: cue.startTime,
|
|
50379
50431
|
end: cue.endTime,
|
|
50380
50432
|
text: cue.text,
|
|
50381
|
-
}
|
|
50433
|
+
};
|
|
50434
|
+
this.cues.insert(cue.startTime, cue.endTime, cueInfo);
|
|
50382
50435
|
});
|
|
50383
50436
|
});
|
|
50384
50437
|
this.bindCustomListeners();
|
|
@@ -50420,7 +50473,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50420
50473
|
}
|
|
50421
50474
|
else {
|
|
50422
50475
|
Log.error('hlsjs: failed to recover', { evt, data });
|
|
50423
|
-
trace(`${T$
|
|
50476
|
+
trace(`${T$e} _recover failed to recover`, {
|
|
50424
50477
|
type: data.type,
|
|
50425
50478
|
details: data.details,
|
|
50426
50479
|
});
|
|
@@ -50507,7 +50560,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50507
50560
|
this.trigger(Events$1.PLAYBACK_SETTINGSUPDATE);
|
|
50508
50561
|
}
|
|
50509
50562
|
_onHLSJSError(evt, data) {
|
|
50510
|
-
trace(`${T$
|
|
50563
|
+
trace(`${T$e} _onHLSJSError`, {
|
|
50511
50564
|
fatal: data.fatal,
|
|
50512
50565
|
type: data.type,
|
|
50513
50566
|
details: data.details,
|
|
@@ -50555,7 +50608,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50555
50608
|
evt,
|
|
50556
50609
|
data,
|
|
50557
50610
|
});
|
|
50558
|
-
trace(`${T$
|
|
50611
|
+
trace(`${T$e} _onHLSJSError trying to recover from network error`, {
|
|
50559
50612
|
details: data.details,
|
|
50560
50613
|
});
|
|
50561
50614
|
error.level = PlayerError.Levels.WARN;
|
|
@@ -50568,7 +50621,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50568
50621
|
evt,
|
|
50569
50622
|
data,
|
|
50570
50623
|
});
|
|
50571
|
-
trace(`${T$
|
|
50624
|
+
trace(`${T$e} _onHLSJSError trying to recover from media error`, {
|
|
50572
50625
|
details: data.details,
|
|
50573
50626
|
});
|
|
50574
50627
|
error.level = PlayerError.Levels.WARN;
|
|
@@ -50598,14 +50651,14 @@ class HlsPlayback extends BasePlayback {
|
|
|
50598
50651
|
return;
|
|
50599
50652
|
}
|
|
50600
50653
|
Log.warn('hlsjs: non-fatal error occurred', { evt, data });
|
|
50601
|
-
trace(`${T$
|
|
50654
|
+
trace(`${T$e} _onHLSJSError non-fatal error occurred`, {
|
|
50602
50655
|
type: data.type,
|
|
50603
50656
|
details: data.details,
|
|
50604
50657
|
});
|
|
50605
50658
|
}
|
|
50606
50659
|
}
|
|
50607
50660
|
reload() {
|
|
50608
|
-
this.cues =
|
|
50661
|
+
this.cues = null;
|
|
50609
50662
|
this.currentCueId = null;
|
|
50610
50663
|
this._hls?.startLoad(-1);
|
|
50611
50664
|
}
|
|
@@ -50670,9 +50723,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50670
50723
|
}
|
|
50671
50724
|
triggerCues() {
|
|
50672
50725
|
const currentTime = this.getCurrentTime();
|
|
50673
|
-
|
|
50674
|
-
// TODO build a search tree
|
|
50675
|
-
const cue = this.cues.find((cue) => currentTime >= cue.start && currentTime <= cue.end);
|
|
50726
|
+
const cue = this.cues?.find(currentTime);
|
|
50676
50727
|
if (cue) {
|
|
50677
50728
|
this.currentCueId = cue.id;
|
|
50678
50729
|
this.oncueenter?.(cue);
|
|
@@ -50715,20 +50766,14 @@ class HlsPlayback extends BasePlayback {
|
|
|
50715
50766
|
destroy() {
|
|
50716
50767
|
this._stopTimeUpdateTimer();
|
|
50717
50768
|
this._destroyHLSInstance();
|
|
50769
|
+
this.cues = null;
|
|
50770
|
+
this.cuesByTrack = {};
|
|
50718
50771
|
return super.destroy();
|
|
50719
50772
|
}
|
|
50720
50773
|
_updatePlaybackType(evt, data) {
|
|
50721
50774
|
const prevPlaybackType = this._playbackType;
|
|
50722
50775
|
this._playbackType = (data.details.live ? Playback.LIVE : Playback.VOD);
|
|
50723
50776
|
this._onLevelUpdated(evt, data);
|
|
50724
|
-
// Live stream subtitle tracks detection hack (may not immediately available)
|
|
50725
|
-
// if (
|
|
50726
|
-
// this._ccTracksUpdated &&
|
|
50727
|
-
// this._playbackType === Playback.LIVE &&
|
|
50728
|
-
// this.hasClosedCaptionsTracks
|
|
50729
|
-
// ) {
|
|
50730
|
-
// this._onSubtitleLoaded()
|
|
50731
|
-
// }
|
|
50732
50777
|
if (prevPlaybackType !== this._playbackType) {
|
|
50733
50778
|
this._updateSettings();
|
|
50734
50779
|
}
|
|
@@ -50939,7 +50984,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50939
50984
|
this.trigger(Events$1.PLAYBACK_AUDIO_AVAILABLE, data.audioTracks.map(toClapprTrack));
|
|
50940
50985
|
}
|
|
50941
50986
|
_onAudioTrackSwitched(_, data) {
|
|
50942
|
-
trace(`${T$
|
|
50987
|
+
trace(`${T$e} onAudioTrackSwitched`);
|
|
50943
50988
|
// @ts-ignore
|
|
50944
50989
|
const track = this._hls.audioTracks[data.id];
|
|
50945
50990
|
this.trigger(Events$1.PLAYBACK_AUDIO_CHANGED, toClapprTrack(track));
|
|
@@ -50949,7 +50994,10 @@ class HlsPlayback extends BasePlayback {
|
|
|
50949
50994
|
return;
|
|
50950
50995
|
}
|
|
50951
50996
|
this._hls.subtitleTrack = id;
|
|
50952
|
-
this.
|
|
50997
|
+
if (!this.cuesByTrack[id]) {
|
|
50998
|
+
this.cuesByTrack[id] = new RangesList();
|
|
50999
|
+
}
|
|
51000
|
+
this.cues = this.cuesByTrack[id];
|
|
50953
51001
|
}
|
|
50954
51002
|
/**
|
|
50955
51003
|
* @override
|
|
@@ -50958,7 +51006,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50958
51006
|
return this.getTextTracks();
|
|
50959
51007
|
}
|
|
50960
51008
|
getTextTracks() {
|
|
50961
|
-
return this._hls?.subtitleTracks.map((t) => ({
|
|
51009
|
+
return (this._hls?.subtitleTracks.map((t) => ({
|
|
50962
51010
|
id: t.id,
|
|
50963
51011
|
name: t.name,
|
|
50964
51012
|
track: {
|
|
@@ -50966,7 +51014,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50966
51014
|
label: t.name,
|
|
50967
51015
|
language: t.lang,
|
|
50968
51016
|
},
|
|
50969
|
-
})) || [];
|
|
51017
|
+
})) || []);
|
|
50970
51018
|
}
|
|
50971
51019
|
}
|
|
50972
51020
|
HlsPlayback.canPlay = function (resource, mimeType) {
|
|
@@ -50984,7 +51032,7 @@ function toClapprTrack(t) {
|
|
|
50984
51032
|
};
|
|
50985
51033
|
}
|
|
50986
51034
|
|
|
50987
|
-
const T$
|
|
51035
|
+
const T$d = 'playback.html5_video';
|
|
50988
51036
|
const STALL_TIMEOUT = 15000;
|
|
50989
51037
|
class HTML5Video extends BasePlayback {
|
|
50990
51038
|
stallTimerId = null;
|
|
@@ -51085,7 +51133,7 @@ class HTML5Video extends BasePlayback {
|
|
|
51085
51133
|
switchAudioTrack(id) {
|
|
51086
51134
|
const tracks = this.el.audioTracks;
|
|
51087
51135
|
const supported = !!tracks;
|
|
51088
|
-
trace(`${T$
|
|
51136
|
+
trace(`${T$d} switchAudioTrack`, {
|
|
51089
51137
|
supported,
|
|
51090
51138
|
});
|
|
51091
51139
|
if (supported) {
|
|
@@ -51104,7 +51152,7 @@ function registerPlaybacks() {
|
|
|
51104
51152
|
Loader.registerPlayback(DashPlayback);
|
|
51105
51153
|
}
|
|
51106
51154
|
|
|
51107
|
-
const T$
|
|
51155
|
+
const T$c = 'gplayer';
|
|
51108
51156
|
const DEFAULT_OPTIONS = {
|
|
51109
51157
|
autoPlay: false,
|
|
51110
51158
|
debug: 'none',
|
|
@@ -51298,6 +51346,17 @@ class Player {
|
|
|
51298
51346
|
}
|
|
51299
51347
|
this.player?.load(ms, ms[0].mimeType ?? '');
|
|
51300
51348
|
}
|
|
51349
|
+
/**
|
|
51350
|
+
* Returns a registered core plugin instance by name, or `null` if not found.
|
|
51351
|
+
*
|
|
51352
|
+
* @example
|
|
51353
|
+
* ```ts
|
|
51354
|
+
* const tokenRefresh = player.getPlugin('token_refresh') as TokenRefreshPlugin | null
|
|
51355
|
+
* ```
|
|
51356
|
+
*/
|
|
51357
|
+
getPlugin(name) {
|
|
51358
|
+
return this.player?.core.getPlugin(name) ?? null;
|
|
51359
|
+
}
|
|
51301
51360
|
/**
|
|
51302
51361
|
* Mutes the sound of the video.
|
|
51303
51362
|
*/
|
|
@@ -51440,7 +51499,7 @@ class Player {
|
|
|
51440
51499
|
}
|
|
51441
51500
|
}
|
|
51442
51501
|
triggerAutoPlay() {
|
|
51443
|
-
trace(`${T$
|
|
51502
|
+
trace(`${T$c} triggerAutoPlay`);
|
|
51444
51503
|
setTimeout(() => {
|
|
51445
51504
|
this.player?.play({
|
|
51446
51505
|
autoPlay: true,
|
|
@@ -51458,7 +51517,7 @@ class Player {
|
|
|
51458
51517
|
// TODO test
|
|
51459
51518
|
events = {
|
|
51460
51519
|
onReady: () => {
|
|
51461
|
-
trace(`${T$
|
|
51520
|
+
trace(`${T$c} onReady`, {
|
|
51462
51521
|
ready: this.ready,
|
|
51463
51522
|
});
|
|
51464
51523
|
if (this.ready) {
|
|
@@ -51492,7 +51551,7 @@ class Player {
|
|
|
51492
51551
|
buildCoreOptions(rootNode) {
|
|
51493
51552
|
const sources = this.buildMediaSourcesList();
|
|
51494
51553
|
const source = sources[0];
|
|
51495
|
-
trace(`${T$
|
|
51554
|
+
trace(`${T$c} buildCoreOptions`, {
|
|
51496
51555
|
source,
|
|
51497
51556
|
sources,
|
|
51498
51557
|
});
|
|
@@ -51569,7 +51628,7 @@ class Player {
|
|
|
51569
51628
|
}
|
|
51570
51629
|
}
|
|
51571
51630
|
|
|
51572
|
-
var version$1 = "2.
|
|
51631
|
+
var version$1 = "2.30.1";
|
|
51573
51632
|
|
|
51574
51633
|
var packages = {
|
|
51575
51634
|
"node_modules/@clappr/core": {
|
|
@@ -52002,7 +52061,7 @@ const INITIAL_SETTINGS = {
|
|
|
52002
52061
|
default: [],
|
|
52003
52062
|
seekEnabled: false,
|
|
52004
52063
|
};
|
|
52005
|
-
const T$
|
|
52064
|
+
const T$b = 'plugins.media_control';
|
|
52006
52065
|
/**
|
|
52007
52066
|
* Extended events for the {@link MediaControl} plugin
|
|
52008
52067
|
* @public
|
|
@@ -52295,7 +52354,7 @@ class MediaControl extends UICorePlugin {
|
|
|
52295
52354
|
* Reenables the plugin disabled earlier with the {@link MediaControl.disable} method
|
|
52296
52355
|
*/
|
|
52297
52356
|
enable() {
|
|
52298
|
-
trace(`${T$
|
|
52357
|
+
trace(`${T$b} enable`, {
|
|
52299
52358
|
chromeless: this.options.chromeless,
|
|
52300
52359
|
userDisabled: this.userDisabled,
|
|
52301
52360
|
});
|
|
@@ -52452,7 +52511,7 @@ class MediaControl extends UICorePlugin {
|
|
|
52452
52511
|
this.$el.removeClass('w370');
|
|
52453
52512
|
this.$el.removeClass('w270');
|
|
52454
52513
|
this.verticalVolume = false;
|
|
52455
|
-
trace(`${T$
|
|
52514
|
+
trace(`${T$b} playerResize`, {
|
|
52456
52515
|
size,
|
|
52457
52516
|
width: this.container.$el.width(),
|
|
52458
52517
|
height: this.container.$el.height(),
|
|
@@ -53454,7 +53513,7 @@ class AudioTracks extends UICorePlugin {
|
|
|
53454
53513
|
|
|
53455
53514
|
const templateHtml$2 = "<div class=\"big-mute-icon-wrapper\" data-big-mute id=\"gplayer-big-mute-button\">\n <div class=\"big-mute-icon gcore-skin-border-color\" data-big-mute-icon id=\"gplayer-big-mute-icon\"></div>\n</div>\n";
|
|
53456
53515
|
|
|
53457
|
-
const T$
|
|
53516
|
+
const T$a = 'plugins.big_mute_button';
|
|
53458
53517
|
// TODO rewrite as a container plugin
|
|
53459
53518
|
/**
|
|
53460
53519
|
* `PLUGIN` that displays a big mute button over the video when it's being played muted.
|
|
@@ -53517,7 +53576,7 @@ class BigMuteButton extends UICorePlugin {
|
|
|
53517
53576
|
if (autoPlay) {
|
|
53518
53577
|
this.autoPlay = true;
|
|
53519
53578
|
}
|
|
53520
|
-
trace(`${T$
|
|
53579
|
+
trace(`${T$a} onPlay`, {
|
|
53521
53580
|
autoPlay: this.autoPlay,
|
|
53522
53581
|
wasMuted,
|
|
53523
53582
|
volume,
|
|
@@ -53531,7 +53590,7 @@ class BigMuteButton extends UICorePlugin {
|
|
|
53531
53590
|
}
|
|
53532
53591
|
onStop(_, metadata) {
|
|
53533
53592
|
const ui = metadata?.ui;
|
|
53534
|
-
trace(`${T$
|
|
53593
|
+
trace(`${T$a} onStop`, { ui });
|
|
53535
53594
|
if (ui) {
|
|
53536
53595
|
this.destroy();
|
|
53537
53596
|
}
|
|
@@ -56495,7 +56554,7 @@ const PLAYBACK_NAMES = {
|
|
|
56495
56554
|
hls: 'HLS.js',
|
|
56496
56555
|
html5_video: 'Native',
|
|
56497
56556
|
};
|
|
56498
|
-
const T$
|
|
56557
|
+
const T$9 = 'plugins.nerd_stats';
|
|
56499
56558
|
/**
|
|
56500
56559
|
* `PLUGIN` that displays useful statistics regarding the playback as well as the network quality estimation.
|
|
56501
56560
|
* @public
|
|
@@ -56632,7 +56691,7 @@ class NerdStats extends UICorePlugin {
|
|
|
56632
56691
|
return super.destroy();
|
|
56633
56692
|
}
|
|
56634
56693
|
toggle = () => {
|
|
56635
|
-
trace(`${T$
|
|
56694
|
+
trace(`${T$9} toggle`, {
|
|
56636
56695
|
open: this.open,
|
|
56637
56696
|
});
|
|
56638
56697
|
if (this.open) {
|
|
@@ -56652,14 +56711,14 @@ class NerdStats extends UICorePlugin {
|
|
|
56652
56711
|
})
|
|
56653
56712
|
.catch((e) => {
|
|
56654
56713
|
reportError(e);
|
|
56655
|
-
trace(`${T$
|
|
56714
|
+
trace(`${T$9} speedtest error`, {
|
|
56656
56715
|
error: e,
|
|
56657
56716
|
});
|
|
56658
56717
|
this.disable();
|
|
56659
56718
|
});
|
|
56660
56719
|
}
|
|
56661
56720
|
hide() {
|
|
56662
|
-
trace(`${T$
|
|
56721
|
+
trace(`${T$9} hide`);
|
|
56663
56722
|
this.$el.hide();
|
|
56664
56723
|
this.open = false;
|
|
56665
56724
|
stopSpeedtest();
|
|
@@ -57392,7 +57451,7 @@ const reloadIcon = "<svg fill=\"#FFFFFF\" height=\"24\" viewBox=\"0 0 24 24\" wi
|
|
|
57392
57451
|
|
|
57393
57452
|
const templateHtml = "<div class=\"player-error-screen__content\" data-error-screen>\n <% if (icon) { %>\n <div class=\"player-error-screen__icon\" data-error-screen><%= icon %></div>\n <% } %>\n <div class=\"player-error-screen__title\" data-error-screen><%= title %></div>\n <% if (message) { %>\n <div class=\"player-error-screen__message\" data-error-screen><%= message %></div>\n <% } %>\n <% if (code) { %>\n <div class=\"player-error-screen__code\" data-error-screen><%= i18n.t('error_code') %>: <%= code %></div>\n <% } %>\n <% if (reloadIcon) { %>\n <div class=\"player-error-screen__reload\" data-error-screen><%= reloadIcon %></div>\n <% } %>\n</div>\n";
|
|
57394
57453
|
|
|
57395
|
-
const T$
|
|
57454
|
+
const T$8 = 'plugins.error_screen';
|
|
57396
57455
|
/**
|
|
57397
57456
|
* `PLUGIN` that displays fatal errors nicely in the overlay on top of the player.
|
|
57398
57457
|
* @public
|
|
@@ -57444,11 +57503,11 @@ class ErrorScreen extends UICorePlugin {
|
|
|
57444
57503
|
this.listenTo(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
|
|
57445
57504
|
}
|
|
57446
57505
|
onPlay() {
|
|
57447
|
-
trace(`${T$
|
|
57506
|
+
trace(`${T$8} onPlay`);
|
|
57448
57507
|
this.unmount();
|
|
57449
57508
|
}
|
|
57450
57509
|
unmount() {
|
|
57451
|
-
trace(`${T$
|
|
57510
|
+
trace(`${T$8} unmount`);
|
|
57452
57511
|
this.err = null;
|
|
57453
57512
|
this.$el.remove();
|
|
57454
57513
|
}
|
|
@@ -57461,7 +57520,7 @@ class ErrorScreen extends UICorePlugin {
|
|
|
57461
57520
|
};
|
|
57462
57521
|
}
|
|
57463
57522
|
reload() {
|
|
57464
|
-
trace(`${T$
|
|
57523
|
+
trace(`${T$8} reload`);
|
|
57465
57524
|
setTimeout(() => {
|
|
57466
57525
|
this.core.configure({
|
|
57467
57526
|
reloading: true,
|
|
@@ -57484,7 +57543,7 @@ class ErrorScreen extends UICorePlugin {
|
|
|
57484
57543
|
}
|
|
57485
57544
|
}
|
|
57486
57545
|
onError(err) {
|
|
57487
|
-
trace(`${T$
|
|
57546
|
+
trace(`${T$8} onError`, { err });
|
|
57488
57547
|
if (err.UI) {
|
|
57489
57548
|
if (this.err) {
|
|
57490
57549
|
this.unmount();
|
|
@@ -57965,7 +58024,7 @@ const pluginHtml$3 = "<button data-multicamera-button class='gcore-skin-button-c
|
|
|
57965
58024
|
const streamsIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"20\" viewBox=\"0 0 24 20\">\n <path fill=\"#FFF\" fill-rule=\"nonzero\" d=\"M24 1.5v13a1.5 1.5 0 0 1-1.5 1.5h-1a.5.5 0 0 1-.5-.5v-10A2.5 2.5 0 0 0 18.5 3h-14a.5.5 0 0 1-.5-.5v-1A1.5 1.5 0 0 1 5.5 0h17A1.5 1.5 0 0 1 24 1.5M12.724 12.447l-5 2.5a.505.505 0 0 1-.487-.021A.503.503 0 0 1 7 14.5v-5c0-.173.09-.334.237-.426a.505.505 0 0 1 .487-.021l5 2.5a.5.5 0 0 1 0 .894M18.5 4h-17C.673 4 0 4.673 0 5.5v13c0 .827.673 1.5 1.5 1.5h17c.827 0 1.5-.673 1.5-1.5v-13c0-.827-.673-1.5-1.5-1.5\"/>\n</svg>\n";
|
|
57966
58025
|
|
|
57967
58026
|
const VERSION$4 = '0.0.1';
|
|
57968
|
-
const T$
|
|
58027
|
+
const T$7 = 'plugins.multicamera';
|
|
57969
58028
|
/**
|
|
57970
58029
|
* `PLUGIN` that adds support for loading multiple streams and switching between them using the media control UI.
|
|
57971
58030
|
* @beta
|
|
@@ -58092,7 +58151,7 @@ class MultiCamera extends UICorePlugin {
|
|
|
58092
58151
|
onCameraSelect(event) {
|
|
58093
58152
|
const value = event.currentTarget.dataset
|
|
58094
58153
|
.multicameraSelectorSelect;
|
|
58095
|
-
trace(`${T$
|
|
58154
|
+
trace(`${T$7} onCameraSelect`, { value });
|
|
58096
58155
|
if (value !== undefined) {
|
|
58097
58156
|
this.changeById(parseInt(value, 10));
|
|
58098
58157
|
}
|
|
@@ -58190,7 +58249,7 @@ class MultiCamera extends UICorePlugin {
|
|
|
58190
58249
|
}
|
|
58191
58250
|
}
|
|
58192
58251
|
changeById(id) {
|
|
58193
|
-
trace(`${T$
|
|
58252
|
+
trace(`${T$7} changeById`, { id });
|
|
58194
58253
|
queueMicrotask(() => {
|
|
58195
58254
|
const playbackOptions = this.core.options.playback || {};
|
|
58196
58255
|
// TODO figure out if it's needed
|
|
@@ -58212,7 +58271,7 @@ class MultiCamera extends UICorePlugin {
|
|
|
58212
58271
|
// TODO remove?
|
|
58213
58272
|
// for html5 playback:
|
|
58214
58273
|
this.options.dvrEnabled = this.currentCamera.dvr;
|
|
58215
|
-
trace(`${T$
|
|
58274
|
+
trace(`${T$7} changeById`, { currentCamera: this.currentCamera });
|
|
58216
58275
|
// TODO
|
|
58217
58276
|
this.core.configure({
|
|
58218
58277
|
playback: playbackOptions,
|
|
@@ -58275,7 +58334,7 @@ const pipIcon = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"no
|
|
|
58275
58334
|
const buttonHtml$2 = "<button class=\"gplayer-lite-btn gcore-skin-button-color\">\n <%= pipIcon %>\n</button>\n";
|
|
58276
58335
|
|
|
58277
58336
|
const VERSION$3 = '0.0.1';
|
|
58278
|
-
const T$
|
|
58337
|
+
const T$6 = `plugins.pip`;
|
|
58279
58338
|
/**
|
|
58280
58339
|
* `PLUGIN` that enables picture-in-picture mode.
|
|
58281
58340
|
* @public
|
|
@@ -58333,7 +58392,7 @@ class PictureInPicture extends UICorePlugin {
|
|
|
58333
58392
|
});
|
|
58334
58393
|
}
|
|
58335
58394
|
isPiPSupported() {
|
|
58336
|
-
trace(`${T$
|
|
58395
|
+
trace(`${T$6} isPiPSupported`, {
|
|
58337
58396
|
pictureInPictureEnabled: !!document.pictureInPictureEnabled,
|
|
58338
58397
|
requestPictureInPicture: !!HTMLVideoElement.prototype.requestPictureInPicture,
|
|
58339
58398
|
});
|
|
@@ -58355,7 +58414,7 @@ class PictureInPicture extends UICorePlugin {
|
|
|
58355
58414
|
return this;
|
|
58356
58415
|
}
|
|
58357
58416
|
togglePictureInPicture() {
|
|
58358
|
-
trace(`${T$
|
|
58417
|
+
trace(`${T$6} togglePictureInPicture`);
|
|
58359
58418
|
if (this.videoElement !== document.pictureInPictureElement) {
|
|
58360
58419
|
this.requestPictureInPicture();
|
|
58361
58420
|
}
|
|
@@ -58364,13 +58423,13 @@ class PictureInPicture extends UICorePlugin {
|
|
|
58364
58423
|
}
|
|
58365
58424
|
}
|
|
58366
58425
|
requestPictureInPicture() {
|
|
58367
|
-
trace(`${T$
|
|
58426
|
+
trace(`${T$6} requestPictureInPicture`, {
|
|
58368
58427
|
videoElement: !!this.videoElement,
|
|
58369
58428
|
});
|
|
58370
58429
|
this.videoElement.requestPictureInPicture();
|
|
58371
58430
|
}
|
|
58372
58431
|
exitPictureInPicture() {
|
|
58373
|
-
trace(`${T$
|
|
58432
|
+
trace(`${T$6} exitPictureInPicture`);
|
|
58374
58433
|
document.exitPictureInPicture();
|
|
58375
58434
|
}
|
|
58376
58435
|
}
|
|
@@ -58397,7 +58456,7 @@ const DEFAULT_PLAYBACK_RATES = [
|
|
|
58397
58456
|
{ value: 2.0, label: '2x' },
|
|
58398
58457
|
];
|
|
58399
58458
|
const DEFAULT_PLAYBACK_RATE = 1;
|
|
58400
|
-
const T$
|
|
58459
|
+
const T$5 = 'plugins.playback_rate';
|
|
58401
58460
|
/**
|
|
58402
58461
|
* `PLUGIN` that allows changing the playback speed of the video.
|
|
58403
58462
|
* @public
|
|
@@ -58483,7 +58542,7 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58483
58542
|
this.listenTo(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChange);
|
|
58484
58543
|
}
|
|
58485
58544
|
onCoreReady() {
|
|
58486
|
-
trace(`${T$
|
|
58545
|
+
trace(`${T$5} onCoreReady`);
|
|
58487
58546
|
const mediaControl = this.core.getPlugin('media_control');
|
|
58488
58547
|
assert(mediaControl, 'media_control plugin is required');
|
|
58489
58548
|
const gear = this.core.getPlugin('bottom_gear');
|
|
@@ -58492,7 +58551,7 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58492
58551
|
this.listenTo(gear, GearEvents.RENDERED, this.onGearRendered);
|
|
58493
58552
|
}
|
|
58494
58553
|
onActiveContainerChange() {
|
|
58495
|
-
trace(`${T$
|
|
58554
|
+
trace(`${T$5} onActiveContainerChange`);
|
|
58496
58555
|
this.metadataLoaded = false;
|
|
58497
58556
|
this.listenTo(this.core.activePlayback, Events$1.PLAYBACK_STOP, this.onStop);
|
|
58498
58557
|
this.listenTo(this.core.activePlayback, Events$1.PLAYBACK_PLAY, this.onPlay);
|
|
@@ -58500,15 +58559,15 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58500
58559
|
this.listenTo(this.core.activeContainer, Events$1.CONTAINER_LOADEDMETADATA, this.onMetaDataLoaded);
|
|
58501
58560
|
}
|
|
58502
58561
|
onMediaControlRendered() {
|
|
58503
|
-
trace(`${T$
|
|
58562
|
+
trace(`${T$5} onMediaControlRendered`);
|
|
58504
58563
|
this.render();
|
|
58505
58564
|
}
|
|
58506
58565
|
onGearRendered() {
|
|
58507
|
-
trace(`${T$
|
|
58566
|
+
trace(`${T$5} onGearRendered`);
|
|
58508
58567
|
this.mount();
|
|
58509
58568
|
}
|
|
58510
58569
|
mount() {
|
|
58511
|
-
trace(`${T$
|
|
58570
|
+
trace(`${T$5} mount`, {
|
|
58512
58571
|
shouldMount: this.shouldMount(),
|
|
58513
58572
|
});
|
|
58514
58573
|
if (!this.shouldMount()) {
|
|
@@ -58525,7 +58584,7 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58525
58584
|
})));
|
|
58526
58585
|
}
|
|
58527
58586
|
onMetaDataLoaded() {
|
|
58528
|
-
trace(`${T$
|
|
58587
|
+
trace(`${T$5} onMetaDataLoaded`, {
|
|
58529
58588
|
playbackType: this.core.activePlayback.getPlaybackType(),
|
|
58530
58589
|
dvrEnabled: this.core.activePlayback.dvrEnabled,
|
|
58531
58590
|
});
|
|
@@ -58547,7 +58606,7 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58547
58606
|
this.core.activePlayback?.setPlaybackRate(this.selectedRate);
|
|
58548
58607
|
}
|
|
58549
58608
|
else {
|
|
58550
|
-
trace(`${T$
|
|
58609
|
+
trace(`${T$5} onPlaybackRateChange not steering to the selected rate, it is seemingly a catchup algorithm working`, {
|
|
58551
58610
|
playbackRate,
|
|
58552
58611
|
selectedRate: this.selectedRate,
|
|
58553
58612
|
});
|
|
@@ -58610,13 +58669,13 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58610
58669
|
}
|
|
58611
58670
|
}
|
|
58612
58671
|
syncRate() {
|
|
58613
|
-
trace(`${T$
|
|
58672
|
+
trace(`${T$5} syncRate`, {
|
|
58614
58673
|
selectedRate: this.selectedRate,
|
|
58615
58674
|
});
|
|
58616
58675
|
this.core.activePlayback?.setPlaybackRate(this.selectedRate);
|
|
58617
58676
|
}
|
|
58618
58677
|
resetPlaybackRate() {
|
|
58619
|
-
trace(`${T$
|
|
58678
|
+
trace(`${T$5} resetPlaybackRate`, {
|
|
58620
58679
|
selectedRate: this.selectedRate,
|
|
58621
58680
|
});
|
|
58622
58681
|
this.core.activePlayback?.setPlaybackRate(DEFAULT_PLAYBACK_RATE);
|
|
@@ -58651,7 +58710,7 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58651
58710
|
?.label || `x${rate}`);
|
|
58652
58711
|
}
|
|
58653
58712
|
highlightCurrentRate() {
|
|
58654
|
-
trace(`${T$
|
|
58713
|
+
trace(`${T$5} highlightCurrentRate`, {
|
|
58655
58714
|
selectedRate: this.selectedRate,
|
|
58656
58715
|
});
|
|
58657
58716
|
this.allRateElements().removeClass('current');
|
|
@@ -59687,7 +59746,7 @@ class SpinnerThreeBounce extends UIContainerPlugin {
|
|
|
59687
59746
|
}
|
|
59688
59747
|
}
|
|
59689
59748
|
|
|
59690
|
-
const T$
|
|
59749
|
+
const T$4 = 'plugins.source_controller';
|
|
59691
59750
|
const INITIAL_RETRY_DELAY = 1000;
|
|
59692
59751
|
const MAX_RETRY_DELAY = 5000;
|
|
59693
59752
|
const RETRY_DELAY_BLUR = 500;
|
|
@@ -59824,7 +59883,7 @@ class SourceController extends CorePlugin {
|
|
|
59824
59883
|
}
|
|
59825
59884
|
bindContainerEventListeners() {
|
|
59826
59885
|
this.core.activePlayback.on(Events$1.PLAYBACK_ERROR, (error) => {
|
|
59827
|
-
trace(`${T$
|
|
59886
|
+
trace(`${T$4} on PLAYBACK_ERROR`, {
|
|
59828
59887
|
error: {
|
|
59829
59888
|
code: error?.code,
|
|
59830
59889
|
description: error?.description,
|
|
@@ -59848,7 +59907,7 @@ class SourceController extends CorePlugin {
|
|
|
59848
59907
|
}
|
|
59849
59908
|
});
|
|
59850
59909
|
this.listenTo(this.core.activeContainer, Events$1.CONTAINER_PLAY, (_, { autoPlay }) => {
|
|
59851
|
-
trace(`${T$
|
|
59910
|
+
trace(`${T$4} onContainerPlay`, {
|
|
59852
59911
|
autoPlay,
|
|
59853
59912
|
currentSource: this.sourcesList[this.currentSourceIndex],
|
|
59854
59913
|
retrying: this.active,
|
|
@@ -59866,7 +59925,7 @@ class SourceController extends CorePlugin {
|
|
|
59866
59925
|
this.sourcesDelay = {};
|
|
59867
59926
|
}
|
|
59868
59927
|
retryPlayback() {
|
|
59869
|
-
trace(`${T$
|
|
59928
|
+
trace(`${T$4} retryPlayback enter`, {
|
|
59870
59929
|
currentSourceIndex: this.currentSourceIndex,
|
|
59871
59930
|
currentSource: this.sourcesList[this.currentSourceIndex],
|
|
59872
59931
|
});
|
|
@@ -59874,18 +59933,18 @@ class SourceController extends CorePlugin {
|
|
|
59874
59933
|
this.switching = true;
|
|
59875
59934
|
this.core.activeContainer?.getPlugin('spinner')?.show(0);
|
|
59876
59935
|
this.getNextMediaSource().then((nextSource) => {
|
|
59877
|
-
trace(`${T$
|
|
59936
|
+
trace(`${T$4} retryPlayback syncing...`, {
|
|
59878
59937
|
nextSource,
|
|
59879
59938
|
});
|
|
59880
59939
|
const rnd = Math.round(RETRY_DELAY_BLUR * Math.random());
|
|
59881
59940
|
this.sync(() => {
|
|
59882
59941
|
this.switching = false;
|
|
59883
59942
|
this.core.load(nextSource.source, nextSource.mimeType);
|
|
59884
|
-
trace(`${T$
|
|
59943
|
+
trace(`${T$4} retryPlayback loaded`, {
|
|
59885
59944
|
nextSource,
|
|
59886
59945
|
});
|
|
59887
59946
|
setTimeout(() => {
|
|
59888
|
-
trace(`${T$
|
|
59947
|
+
trace(`${T$4} retryPlayback playing`, {
|
|
59889
59948
|
autoPlay: this.autoPlay,
|
|
59890
59949
|
nextSource,
|
|
59891
59950
|
});
|
|
@@ -60243,8 +60302,6 @@ class ClosedCaptions extends UICorePlugin {
|
|
|
60243
60302
|
// event.target does not exist for some reason in tests
|
|
60244
60303
|
const id = Number((event.target ?? event.currentTarget).dataset?.item ??
|
|
60245
60304
|
'-1');
|
|
60246
|
-
// TODO review, make configurable, and emit event in addition
|
|
60247
|
-
// localStorage.setItem(LOCAL_STORAGE_CC_ID, id) // TODO store language instead?
|
|
60248
60305
|
this.userSelectedItemId = id;
|
|
60249
60306
|
this.selectItem(this.findById(id));
|
|
60250
60307
|
this.hideMenu();
|
|
@@ -60397,7 +60454,7 @@ class ClosedCaptions extends UICorePlugin {
|
|
|
60397
60454
|
// An example implementation of client side performancestatistics
|
|
60398
60455
|
const WATCH_CUTOFF = 5;
|
|
60399
60456
|
const STALL_MEASURE_PERIOD = 10;
|
|
60400
|
-
const T$
|
|
60457
|
+
const T$3 = 'plugins.telemetry';
|
|
60401
60458
|
/**
|
|
60402
60459
|
* Telemetry event type
|
|
60403
60460
|
* @beta
|
|
@@ -60507,7 +60564,7 @@ class Telemetry extends ContainerPlugin {
|
|
|
60507
60564
|
}
|
|
60508
60565
|
onReady() {
|
|
60509
60566
|
this.sendInit();
|
|
60510
|
-
trace(`${T$
|
|
60567
|
+
trace(`${T$3} onReady`, {
|
|
60511
60568
|
autoPlay: this.options.autoPlay,
|
|
60512
60569
|
});
|
|
60513
60570
|
if (this.options.autoPlay) {
|
|
@@ -63208,7 +63265,7 @@ function loadImageDimensions(url) {
|
|
|
63208
63265
|
});
|
|
63209
63266
|
}
|
|
63210
63267
|
|
|
63211
|
-
const T$
|
|
63268
|
+
const T$2 = 'plugins.thumbnails';
|
|
63212
63269
|
/**
|
|
63213
63270
|
* `PLUGIN` that displays the thumbnails of the video when available.
|
|
63214
63271
|
* @public
|
|
@@ -63326,14 +63383,14 @@ class Thumbnails extends UICorePlugin {
|
|
|
63326
63383
|
if (!this.options.thumbnails ||
|
|
63327
63384
|
!this.options.thumbnails.sprite ||
|
|
63328
63385
|
!this.options.thumbnails.vtt) {
|
|
63329
|
-
trace(`${T$
|
|
63386
|
+
trace(`${T$2} misconfigured: options.thumbnails.sprite and options.thumbnails.vtt are required`);
|
|
63330
63387
|
this.destroy();
|
|
63331
63388
|
return;
|
|
63332
63389
|
}
|
|
63333
63390
|
const { sprite: spriteSheet, vtt } = this.options.thumbnails;
|
|
63334
63391
|
this.thumbs = this.buildSpriteConfig(parseVTT(vtt), spriteSheet);
|
|
63335
63392
|
if (!this.thumbs.length) {
|
|
63336
|
-
trace(`${T$
|
|
63393
|
+
trace(`${T$2} failed to parse the sprite sheet`);
|
|
63337
63394
|
this.destroy();
|
|
63338
63395
|
return;
|
|
63339
63396
|
}
|
|
@@ -63582,6 +63639,321 @@ function parseVTT(vtt) {
|
|
|
63582
63639
|
return cues;
|
|
63583
63640
|
}
|
|
63584
63641
|
|
|
63642
|
+
const T$1 = 'plugins.token_refresh';
|
|
63643
|
+
/**
|
|
63644
|
+
* Matches the `/{token}/{expires}/` segment in a Gcore protected-content URL.
|
|
63645
|
+
* Token is base64url (letters, digits, `-`, `_`); expires is a ≥10-digit Unix timestamp.
|
|
63646
|
+
*/
|
|
63647
|
+
const TOKEN_SEGMENT_RE = /\/([A-Za-z0-9_-]{6,})\/(1\d{9,})\//;
|
|
63648
|
+
function extractTokenState(url) {
|
|
63649
|
+
const m = url.match(TOKEN_SEGMENT_RE);
|
|
63650
|
+
if (!m)
|
|
63651
|
+
return null;
|
|
63652
|
+
return { token: m[1], expires: parseInt(m[2], 10) };
|
|
63653
|
+
}
|
|
63654
|
+
/** Replaces the exact `/{oldToken}/{oldExpires}/` segment in a URL. */
|
|
63655
|
+
function rewriteUrl(url, from, to) {
|
|
63656
|
+
const oldPart = `/${from.token}/${from.expires}/`;
|
|
63657
|
+
const newPart = `/${to.token}/${to.expires}/`;
|
|
63658
|
+
return url.includes(oldPart) ? url.replace(oldPart, newPart) : url;
|
|
63659
|
+
}
|
|
63660
|
+
/**
|
|
63661
|
+
* Normalises a URL by removing the `/{token}/{expires}/` segment so two URLs
|
|
63662
|
+
* for the same stream with different token pairs compare equal.
|
|
63663
|
+
* Returns `null` for unparseable input.
|
|
63664
|
+
*/
|
|
63665
|
+
function streamKey(url) {
|
|
63666
|
+
try {
|
|
63667
|
+
const u = new URL(url);
|
|
63668
|
+
return u.origin + u.pathname.replace(TOKEN_SEGMENT_RE, '/');
|
|
63669
|
+
}
|
|
63670
|
+
catch {
|
|
63671
|
+
return null;
|
|
63672
|
+
}
|
|
63673
|
+
}
|
|
63674
|
+
/**
|
|
63675
|
+
* Returns a custom hls.js loader class that transparently rewrites the
|
|
63676
|
+
* token/expires path segments in every request URL.
|
|
63677
|
+
*
|
|
63678
|
+
* The returned class extends the default hls.js XhrLoader so all native
|
|
63679
|
+
* hls.js behaviour (retry, timeout, range requests …) is preserved.
|
|
63680
|
+
*/
|
|
63681
|
+
function createTokenRewritingLoader(getOriginal, getCurrent) {
|
|
63682
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63683
|
+
const DefaultLoader = Hls.DefaultConfig.loader;
|
|
63684
|
+
return class TokenRewritingLoader extends DefaultLoader {
|
|
63685
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63686
|
+
load(context, config, callbacks) {
|
|
63687
|
+
const original = getOriginal();
|
|
63688
|
+
const current = getCurrent();
|
|
63689
|
+
if (original && current && context.url) {
|
|
63690
|
+
context.url = rewriteUrl(context.url, original, current);
|
|
63691
|
+
}
|
|
63692
|
+
super.load(context, config, callbacks);
|
|
63693
|
+
}
|
|
63694
|
+
};
|
|
63695
|
+
}
|
|
63696
|
+
/**
|
|
63697
|
+
* `PLUGIN` — automatic token refresh for Gcore protected-content streams.
|
|
63698
|
+
*
|
|
63699
|
+
* Supports all three playback engines:
|
|
63700
|
+
*
|
|
63701
|
+
* | Engine | Mechanism | Interruption |
|
|
63702
|
+
* |--------|-----------|--------------|
|
|
63703
|
+
* | **hls.js** | Custom loader rewrites every request URL | None |
|
|
63704
|
+
* | **dash.js** | `addRequestInterceptor` rewrites every request URL | None |
|
|
63705
|
+
* | **Native `<video>`** (Safari ≤ iOS 14.4) | Source reload + seek restore | Brief |
|
|
63706
|
+
*
|
|
63707
|
+
* @public
|
|
63708
|
+
* @remarks
|
|
63709
|
+
* Register the plugin once before creating any player instance:
|
|
63710
|
+
* ```ts
|
|
63711
|
+
* import { Player, TokenRefreshPlugin } from '@gcorevideo/player'
|
|
63712
|
+
* Player.registerPlugin(TokenRefreshPlugin)
|
|
63713
|
+
* ```
|
|
63714
|
+
*
|
|
63715
|
+
* Then pass `tokenRefresh` in `PlayerConfig`:
|
|
63716
|
+
* ```ts
|
|
63717
|
+
* const player = new Player({
|
|
63718
|
+
* sources: [{ source: initialUrl, mimeType: 'application/x-mpegURL' }],
|
|
63719
|
+
* tokenRefresh: {
|
|
63720
|
+
* getToken: () => fetch('https://…/token').then(r => r.json()),
|
|
63721
|
+
* ipBound: false,
|
|
63722
|
+
* refreshLeadSeconds: 5,
|
|
63723
|
+
* onTokenRefreshed: (data) => console.log('new token expires', data.expires),
|
|
63724
|
+
* },
|
|
63725
|
+
* })
|
|
63726
|
+
* ```
|
|
63727
|
+
*
|
|
63728
|
+
* @example
|
|
63729
|
+
* Safari native — opt-in Service Worker for fully seamless refresh:
|
|
63730
|
+
* ```js
|
|
63731
|
+
* // Register token-refresh-sw.js (see example/ directory)
|
|
63732
|
+
* // and omit tokenRefresh config — the SW handles rewriting.
|
|
63733
|
+
* ```
|
|
63734
|
+
*/
|
|
63735
|
+
class TokenRefreshPlugin extends CorePlugin {
|
|
63736
|
+
/** @internal */
|
|
63737
|
+
static get type() {
|
|
63738
|
+
return 'core';
|
|
63739
|
+
}
|
|
63740
|
+
/** @internal */
|
|
63741
|
+
get name() {
|
|
63742
|
+
return 'token_refresh';
|
|
63743
|
+
}
|
|
63744
|
+
/** @internal */
|
|
63745
|
+
get supportedVersion() {
|
|
63746
|
+
return { min: CLAPPR_VERSION$1 };
|
|
63747
|
+
}
|
|
63748
|
+
/** Token state extracted from the currently-managed source URL */
|
|
63749
|
+
originalState = null;
|
|
63750
|
+
/** Latest token state (updated after each refresh) */
|
|
63751
|
+
currentState = null;
|
|
63752
|
+
/** Scheduled refresh timer handle */
|
|
63753
|
+
refreshTimer = null;
|
|
63754
|
+
/** Playback time (seconds) to restore after a native-video source reload */
|
|
63755
|
+
savedPosition = null;
|
|
63756
|
+
/** True when using native HTML5 Video playback (no request interception) */
|
|
63757
|
+
isNativePlayback = false;
|
|
63758
|
+
/** Set in destroy(); short-circuits late timer callbacks and getToken() resolutions */
|
|
63759
|
+
destroyed = false;
|
|
63760
|
+
/** @internal */
|
|
63761
|
+
bindEvents() {
|
|
63762
|
+
this.listenTo(this.core, Events$1.CORE_CONTAINERS_CREATED, this.onContainersCreated);
|
|
63763
|
+
}
|
|
63764
|
+
/** @internal */
|
|
63765
|
+
destroy() {
|
|
63766
|
+
this.destroyed = true;
|
|
63767
|
+
this.clearTimer();
|
|
63768
|
+
super.destroy();
|
|
63769
|
+
}
|
|
63770
|
+
onContainersCreated() {
|
|
63771
|
+
const container = this.core.containers[0];
|
|
63772
|
+
if (!container)
|
|
63773
|
+
return;
|
|
63774
|
+
const playbackName = container.playback.name;
|
|
63775
|
+
const src = container.playback.options?.src ?? '';
|
|
63776
|
+
trace(`${T$1} onContainersCreated`, { playbackName, src: src.slice(0, 80) });
|
|
63777
|
+
this.isNativePlayback = playbackName !== 'hls' && playbackName !== 'dash';
|
|
63778
|
+
const state = extractTokenState(src);
|
|
63779
|
+
if (!state) {
|
|
63780
|
+
// Active source has no token pattern — drop any refresh state we were
|
|
63781
|
+
// holding for a previous stream (e.g. SourceController rotated away).
|
|
63782
|
+
if (this.originalState) {
|
|
63783
|
+
trace(`${T$1} active source has no token pattern — clearing refresh state`);
|
|
63784
|
+
this.clearTimer();
|
|
63785
|
+
this.originalState = null;
|
|
63786
|
+
this.currentState = null;
|
|
63787
|
+
}
|
|
63788
|
+
return;
|
|
63789
|
+
}
|
|
63790
|
+
// Adopt the new token state if this is the first source we see, or if
|
|
63791
|
+
// the stream has changed (SourceController rotated, consumer called
|
|
63792
|
+
// player.load() with a different stream, or the plugin itself reloaded
|
|
63793
|
+
// with a refreshed URL in the native path).
|
|
63794
|
+
const isNewStream = !this.originalState ||
|
|
63795
|
+
state.token !== this.originalState.token ||
|
|
63796
|
+
state.expires !== this.originalState.expires;
|
|
63797
|
+
if (isNewStream) {
|
|
63798
|
+
trace(`${T$1} adopting source token state`, {
|
|
63799
|
+
token: state.token.slice(0, 8) + '…',
|
|
63800
|
+
expires: new Date(state.expires * 1000).toISOString(),
|
|
63801
|
+
});
|
|
63802
|
+
this.originalState = { ...state };
|
|
63803
|
+
this.currentState = { ...state };
|
|
63804
|
+
this.scheduleRefresh();
|
|
63805
|
+
}
|
|
63806
|
+
// Inject the appropriate interception mechanism for this playback engine.
|
|
63807
|
+
switch (playbackName) {
|
|
63808
|
+
case 'hls':
|
|
63809
|
+
this.injectHlsLoader(container);
|
|
63810
|
+
break;
|
|
63811
|
+
case 'dash':
|
|
63812
|
+
this.injectDashInterceptor(container);
|
|
63813
|
+
break;
|
|
63814
|
+
default:
|
|
63815
|
+
// Native HTML5 Video — no request hooks available.
|
|
63816
|
+
// Seek restore after a token-triggered reload.
|
|
63817
|
+
this.listenToOnce(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChangedForNative);
|
|
63818
|
+
break;
|
|
63819
|
+
}
|
|
63820
|
+
}
|
|
63821
|
+
injectHlsLoader(container) {
|
|
63822
|
+
const getOriginal = () => this.originalState;
|
|
63823
|
+
const getCurrent = () => this.currentState;
|
|
63824
|
+
const TokenLoader = createTokenRewritingLoader(getOriginal, getCurrent);
|
|
63825
|
+
$.extend(true, container.playback.options, {
|
|
63826
|
+
playback: {
|
|
63827
|
+
hlsjsConfig: {
|
|
63828
|
+
loader: TokenLoader,
|
|
63829
|
+
},
|
|
63830
|
+
},
|
|
63831
|
+
});
|
|
63832
|
+
trace(`${T$1} HLS custom loader injected`);
|
|
63833
|
+
}
|
|
63834
|
+
injectDashInterceptor(container) {
|
|
63835
|
+
$.extend(true, container.playback.options, {
|
|
63836
|
+
dash: {
|
|
63837
|
+
requestInterceptor: (request) => {
|
|
63838
|
+
if (this.originalState && this.currentState) {
|
|
63839
|
+
request.url = rewriteUrl(request.url, this.originalState, this.currentState);
|
|
63840
|
+
}
|
|
63841
|
+
return Promise.resolve(request);
|
|
63842
|
+
},
|
|
63843
|
+
},
|
|
63844
|
+
});
|
|
63845
|
+
trace(`${T$1} DASH request interceptor injected`);
|
|
63846
|
+
}
|
|
63847
|
+
async reloadNativeSource(data) {
|
|
63848
|
+
const container = this.core.activeContainer;
|
|
63849
|
+
const playback = container?.playback;
|
|
63850
|
+
if (!playback)
|
|
63851
|
+
return;
|
|
63852
|
+
// SourceController (or any other actor) may have switched the active
|
|
63853
|
+
// playback to hls/dash while getToken() was in flight. Those engines
|
|
63854
|
+
// have their own request-interception path; a native reload would
|
|
63855
|
+
// undo the switch.
|
|
63856
|
+
if (playback.name === 'hls' || playback.name === 'dash') {
|
|
63857
|
+
trace(`${T$1} skipping native reload — active playback is ${playback.name}`);
|
|
63858
|
+
return;
|
|
63859
|
+
}
|
|
63860
|
+
if (!this.isNativePlayback) {
|
|
63861
|
+
trace(`${T$1} skipping native reload — no longer in native playback mode`);
|
|
63862
|
+
return;
|
|
63863
|
+
}
|
|
63864
|
+
// Verify the URL we're about to load belongs to the same stream that's
|
|
63865
|
+
// currently active. If SourceController rotated to a different stream
|
|
63866
|
+
// during the getToken() await, the refreshed URL would silently swap
|
|
63867
|
+
// us back, undoing SourceController's decision.
|
|
63868
|
+
const currentSrc = playback.options?.src ?? '';
|
|
63869
|
+
const newUrl = this.opts.ipBound ? data.url_ip : data.url;
|
|
63870
|
+
const activeKey = streamKey(currentSrc);
|
|
63871
|
+
const nextKey = streamKey(newUrl);
|
|
63872
|
+
if (!activeKey || !nextKey || activeKey !== nextKey) {
|
|
63873
|
+
trace(`${T$1} skipping native reload — active source differs from refresh URL`, {
|
|
63874
|
+
activeKey,
|
|
63875
|
+
nextKey,
|
|
63876
|
+
});
|
|
63877
|
+
return;
|
|
63878
|
+
}
|
|
63879
|
+
// Capture current playback position before tearing down the container.
|
|
63880
|
+
const mediaEl = playback.el;
|
|
63881
|
+
const currentTime = mediaEl?.currentTime ?? 0;
|
|
63882
|
+
this.savedPosition = currentTime > 0 ? currentTime : null;
|
|
63883
|
+
trace(`${T$1} native reload`, { newUrl: newUrl.slice(0, 80), savedPosition: this.savedPosition });
|
|
63884
|
+
// core.load() destroys and recreates all containers.
|
|
63885
|
+
this.core.load([{ source: newUrl, mimeType: this.core.options.mimeType ?? 'application/x-mpegURL' }]);
|
|
63886
|
+
}
|
|
63887
|
+
onActiveContainerChangedForNative() {
|
|
63888
|
+
if (this.savedPosition === null)
|
|
63889
|
+
return;
|
|
63890
|
+
const pos = this.savedPosition;
|
|
63891
|
+
this.savedPosition = null;
|
|
63892
|
+
// Wait for the new container to be fully ready before seeking.
|
|
63893
|
+
const container = this.core.activeContainer;
|
|
63894
|
+
if (!container)
|
|
63895
|
+
return;
|
|
63896
|
+
this.listenToOnce(container, Events$1.CONTAINER_READY, () => {
|
|
63897
|
+
trace(`${T$1} native: restoring position`, { pos });
|
|
63898
|
+
container.seek(pos);
|
|
63899
|
+
container.play();
|
|
63900
|
+
});
|
|
63901
|
+
}
|
|
63902
|
+
scheduleRefresh() {
|
|
63903
|
+
this.clearTimer();
|
|
63904
|
+
if (this.destroyed || !this.currentState)
|
|
63905
|
+
return;
|
|
63906
|
+
const leadMs = (this.opts.refreshLeadSeconds ?? 5) * 1000;
|
|
63907
|
+
const msUntilRefresh = this.currentState.expires * 1000 - Date.now() - leadMs;
|
|
63908
|
+
trace(`${T$1} next refresh in`, {
|
|
63909
|
+
seconds: Math.round(msUntilRefresh / 1000),
|
|
63910
|
+
expires: new Date(this.currentState.expires * 1000).toISOString(),
|
|
63911
|
+
});
|
|
63912
|
+
this.refreshTimer = setTimeout(() => this.performRefresh(), Math.max(msUntilRefresh, 1000));
|
|
63913
|
+
}
|
|
63914
|
+
async performRefresh() {
|
|
63915
|
+
trace(`${T$1} fetching new token`);
|
|
63916
|
+
try {
|
|
63917
|
+
const data = await this.opts.getToken();
|
|
63918
|
+
// Plugin may have been destroyed while getToken() was in flight; drop the result.
|
|
63919
|
+
if (this.destroyed)
|
|
63920
|
+
return;
|
|
63921
|
+
const newToken = this.opts.ipBound ? data.token_ip : data.token;
|
|
63922
|
+
const newState = { token: newToken, expires: data.expires };
|
|
63923
|
+
if (this.isNativePlayback) {
|
|
63924
|
+
// Must reload source because the <video> element has no request hook.
|
|
63925
|
+
await this.reloadNativeSource(data);
|
|
63926
|
+
}
|
|
63927
|
+
// originalState is never changed after init — it holds the token that was
|
|
63928
|
+
// baked into every URL in the initial manifest. hls.js/dash.js always
|
|
63929
|
+
// produces request URLs based on that manifest, so every segment URL
|
|
63930
|
+
// still contains the original token regardless of how many refreshes
|
|
63931
|
+
// have already happened. The loader replaces original→current on each
|
|
63932
|
+
// request, so updating only currentState is sufficient.
|
|
63933
|
+
this.currentState = newState;
|
|
63934
|
+
this.opts.onTokenRefreshed?.(data);
|
|
63935
|
+
trace(`${T$1} token refreshed`, {
|
|
63936
|
+
token: newToken.slice(0, 8) + '…',
|
|
63937
|
+
expires: new Date(data.expires * 1000).toISOString(),
|
|
63938
|
+
});
|
|
63939
|
+
}
|
|
63940
|
+
catch (err) {
|
|
63941
|
+
trace(`${T$1} token refresh failed`, { err });
|
|
63942
|
+
}
|
|
63943
|
+
// Always reschedule, even after an error (will retry near next expiry).
|
|
63944
|
+
this.scheduleRefresh();
|
|
63945
|
+
}
|
|
63946
|
+
get opts() {
|
|
63947
|
+
return this.options.tokenRefresh;
|
|
63948
|
+
}
|
|
63949
|
+
clearTimer() {
|
|
63950
|
+
if (this.refreshTimer !== null) {
|
|
63951
|
+
clearTimeout(this.refreshTimer);
|
|
63952
|
+
this.refreshTimer = null;
|
|
63953
|
+
}
|
|
63954
|
+
}
|
|
63955
|
+
}
|
|
63956
|
+
|
|
63585
63957
|
/**
|
|
63586
63958
|
* Events emitted by the VolumeFade plugin.
|
|
63587
63959
|
* @public
|
|
@@ -63690,4 +64062,4 @@ class VolumeFade extends UICorePlugin {
|
|
|
63690
64062
|
}
|
|
63691
64063
|
}
|
|
63692
64064
|
|
|
63693
|
-
export { AudioTracks as AudioSelector, AudioTracks, BigMuteButton, BottomGear, ChainedTracer, NerdStats as ClapprNerdStats, ClapprStats, ClapprStatsChronograph, ClapprStatsCounter, ClapprStatsEvents, ClickToPause, Clips, ClosedCaptions, CmcdConfig, ContextMenu, DvrControls, ErrorScreen, ExtendedEvents, Favicon, GearEvents, GoogleAnalytics, QualityLevels as LevelSelector, LogTracer, Logger$1 as Logger, Logo, MediaControl, MultiCamera, NerdStats, PictureInPicture, PlaybackErrorCode, PlaybackRate, Player, PlayerEvent, Poster, QualityLevels, RemoteTracer, SeekTime, SentryTracer, Share, SkipTime, SourceController, SpinnerThreeBounce as Spinner, SpinnerEvents, SpinnerThreeBounce, ClosedCaptions as Subtitles, Telemetry, TelemetryEvent, Thumbnails, VolumeFade, VolumeFadeEvents, reportError, setTracer, trace, version };
|
|
64065
|
+
export { AudioTracks as AudioSelector, AudioTracks, BigMuteButton, BottomGear, ChainedTracer, NerdStats as ClapprNerdStats, ClapprStats, ClapprStatsChronograph, ClapprStatsCounter, ClapprStatsEvents, ClickToPause, Clips, ClosedCaptions, CmcdConfig, ContextMenu, DvrControls, ErrorScreen, ExtendedEvents, Favicon, GearEvents, GoogleAnalytics, QualityLevels as LevelSelector, LogTracer, Logger$1 as Logger, Logo, MediaControl, MultiCamera, NerdStats, PictureInPicture, PlaybackErrorCode, PlaybackRate, Player, PlayerEvent, Poster, QualityLevels, RemoteTracer, SeekTime, SentryTracer, Share, SkipTime, SourceController, SpinnerThreeBounce as Spinner, SpinnerEvents, SpinnerThreeBounce, ClosedCaptions as Subtitles, Telemetry, TelemetryEvent, Thumbnails, TokenRefreshPlugin, VolumeFade, VolumeFadeEvents, reportError, setTracer, trace, version };
|