@gcorevideo/player 2.28.36 → 2.30.0
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/assets/media-control/media-control.scss +8 -6
- package/assets/multi-camera/multicamera.ejs +27 -23
- package/assets/multi-camera/style.scss +7 -34
- package/assets/style/main.scss +2 -2
- package/dist/core.js +24 -7
- package/dist/index.css +324 -346
- package/dist/index.embed.js +24 -46
- package/dist/index.js +471 -245
- package/docs/api/player.md +22 -9
- package/docs/api/player.mediacontrol.setkeepvisible.md +56 -0
- package/docs/api/player.multicamera.md +0 -28
- package/docs/api/player.multiccamerasourceinfo.md +27 -0
- package/docs/api/{player.multicamera.unbindevents.md → player.multisourcesmode.md} +4 -7
- package/docs/api/player.sourcecontroller.md +0 -37
- 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 +2 -1
- 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 +2 -1
- package/lib/playback/hls-playback/HlsPlayback.d.ts.map +1 -1
- package/lib/playback/types.d.ts +9 -0
- package/lib/playback/types.d.ts.map +1 -1
- package/lib/playback.types.d.ts +0 -6
- package/lib/playback.types.d.ts.map +1 -1
- package/lib/plugins/multi-camera/MultiCamera.d.ts +21 -4
- package/lib/plugins/multi-camera/MultiCamera.d.ts.map +1 -1
- package/lib/plugins/multi-camera/MultiCamera.js +70 -134
- package/lib/plugins/source-controller/SourceController.d.ts +0 -39
- package/lib/plugins/source-controller/SourceController.d.ts.map +1 -1
- package/lib/plugins/source-controller/SourceController.js +0 -39
- 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/lib/utils/mediaSources.d.ts +4 -0
- package/lib/utils/mediaSources.d.ts.map +1 -1
- package/lib/utils/mediaSources.js +8 -6
- 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 +7 -3
- package/src/playback/hls-playback/HlsPlayback.ts +1 -1
- package/src/playback/types.ts +10 -0
- package/src/playback.types.ts +0 -6
- package/src/plugins/multi-camera/MultiCamera.ts +103 -166
- package/src/plugins/source-controller/SourceController.ts +0 -39
- package/src/plugins/subtitles/ClosedCaptions.ts +1 -1
- package/src/plugins/token-refresh/TokenRefreshPlugin.ts +425 -0
- package/src/plugins/token-refresh/index.ts +5 -0
- package/src/utils/mediaSources.ts +10 -6
- package/tsconfig.tsbuildinfo +1 -1
- package/docs/api/player.multicamera.activebyid.md +0 -67
package/dist/index.js
CHANGED
|
@@ -12778,6 +12778,9 @@ var PlayerEvent;
|
|
|
12778
12778
|
PlayerEvent["VolumeUpdate"] = "volumeupdate";
|
|
12779
12779
|
})(PlayerEvent || (PlayerEvent = {}));
|
|
12780
12780
|
|
|
12781
|
+
const MIME_TYPES_HLS = ['application/x-mpegurl', 'application/vnd.apple.mpegurl'];
|
|
12782
|
+
const MIME_TYPE_HLS = MIME_TYPES_HLS[0];
|
|
12783
|
+
const MIME_TYPE_DASH = 'application/dash+xml';
|
|
12781
12784
|
// TODO rewrite using the Playback classes and canPlay static methods
|
|
12782
12785
|
function buildMediaSourcesList(sources, priorityTransport = 'dash') {
|
|
12783
12786
|
const playbacks = Loader.registeredPlaybacks;
|
|
@@ -12817,22 +12820,21 @@ function wrapSource(s) {
|
|
|
12817
12820
|
}
|
|
12818
12821
|
function guessMimeType(s) {
|
|
12819
12822
|
if (s.endsWith('.mpd')) {
|
|
12820
|
-
return
|
|
12823
|
+
return MIME_TYPE_DASH;
|
|
12821
12824
|
}
|
|
12822
12825
|
if (s.endsWith('.m3u8')) {
|
|
12823
|
-
|
|
12824
|
-
return 'application/x-mpegurl';
|
|
12826
|
+
return MIME_TYPE_HLS;
|
|
12825
12827
|
}
|
|
12826
12828
|
}
|
|
12827
12829
|
function isDashSource(source, mimeType) {
|
|
12828
12830
|
if (mimeType) {
|
|
12829
|
-
return mimeType ===
|
|
12831
|
+
return mimeType === MIME_TYPE_DASH; // TODO consider video/mp4
|
|
12830
12832
|
}
|
|
12831
12833
|
return source.endsWith('.mpd');
|
|
12832
12834
|
}
|
|
12833
12835
|
function isHlsSource(source, mimeType) {
|
|
12834
12836
|
if (mimeType) {
|
|
12835
|
-
return
|
|
12837
|
+
return MIME_TYPES_HLS.includes(mimeType.toLowerCase());
|
|
12836
12838
|
}
|
|
12837
12839
|
return source.endsWith('.m3u8');
|
|
12838
12840
|
}
|
|
@@ -12920,7 +12922,7 @@ var PlaybackEvents;
|
|
|
12920
12922
|
// https://github.com/clappr/clappr/blob/8752995ea439321ac7ca3cd35e8c64de7a3c3d17/LICENSE
|
|
12921
12923
|
const AUTO$1 = -1;
|
|
12922
12924
|
const { now: now$2 } = Utils;
|
|
12923
|
-
const T$
|
|
12925
|
+
const T$f = 'playback.dash';
|
|
12924
12926
|
class DashPlayback extends BasePlayback {
|
|
12925
12927
|
_levels = [];
|
|
12926
12928
|
_currentLevel = AUTO$1;
|
|
@@ -13053,6 +13055,7 @@ class DashPlayback extends BasePlayback {
|
|
|
13053
13055
|
this._dash = dash;
|
|
13054
13056
|
this._dash.initialize();
|
|
13055
13057
|
if (this.options.dash) {
|
|
13058
|
+
const { requestInterceptor, ...dashSettings } = this.options.dash;
|
|
13056
13059
|
const settings = $.extend(true, {
|
|
13057
13060
|
streaming: {
|
|
13058
13061
|
text: {
|
|
@@ -13064,8 +13067,11 @@ class DashPlayback extends BasePlayback {
|
|
|
13064
13067
|
// dispatchForManualRendering: true, // TODO only when useNativeSubtitles is not true?
|
|
13065
13068
|
},
|
|
13066
13069
|
},
|
|
13067
|
-
},
|
|
13070
|
+
}, dashSettings);
|
|
13068
13071
|
this._dash.updateSettings(settings);
|
|
13072
|
+
if (typeof requestInterceptor === 'function') {
|
|
13073
|
+
this._dash.addRequestInterceptor(requestInterceptor);
|
|
13074
|
+
}
|
|
13069
13075
|
}
|
|
13070
13076
|
this._dash.attachView(this.el);
|
|
13071
13077
|
this._dash.setAutoPlay(false);
|
|
@@ -13193,7 +13199,7 @@ class DashPlayback extends BasePlayback {
|
|
|
13193
13199
|
this.trigger(Events$1.PLAYBACK_SETTINGSUPDATE);
|
|
13194
13200
|
}
|
|
13195
13201
|
_onPlaybackError = (event) => {
|
|
13196
|
-
trace(`${T$
|
|
13202
|
+
trace(`${T$f} _onPlaybackError`, { type: event.type, code: event.error.code, message: event.error.message });
|
|
13197
13203
|
};
|
|
13198
13204
|
_onDASHJSSError = (event) => {
|
|
13199
13205
|
this._stopTimeUpdateTimer();
|
|
@@ -50093,7 +50099,7 @@ const { now } = Utils;
|
|
|
50093
50099
|
const AUTO = -1;
|
|
50094
50100
|
const DEFAULT_RECOVER_ATTEMPTS = 16;
|
|
50095
50101
|
Events$1.register('PLAYBACK_FRAGMENT_PARSING_METADATA');
|
|
50096
|
-
const T$
|
|
50102
|
+
const T$e = 'playback.hls';
|
|
50097
50103
|
class HlsPlayback extends BasePlayback {
|
|
50098
50104
|
_ccTracksUpdated = false;
|
|
50099
50105
|
_currentFragment = null;
|
|
@@ -50418,7 +50424,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50418
50424
|
}
|
|
50419
50425
|
else {
|
|
50420
50426
|
Log.error('hlsjs: failed to recover', { evt, data });
|
|
50421
|
-
trace(`${T$
|
|
50427
|
+
trace(`${T$e} _recover failed to recover`, {
|
|
50422
50428
|
type: data.type,
|
|
50423
50429
|
details: data.details,
|
|
50424
50430
|
});
|
|
@@ -50505,7 +50511,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50505
50511
|
this.trigger(Events$1.PLAYBACK_SETTINGSUPDATE);
|
|
50506
50512
|
}
|
|
50507
50513
|
_onHLSJSError(evt, data) {
|
|
50508
|
-
trace(`${T$
|
|
50514
|
+
trace(`${T$e} _onHLSJSError`, {
|
|
50509
50515
|
fatal: data.fatal,
|
|
50510
50516
|
type: data.type,
|
|
50511
50517
|
details: data.details,
|
|
@@ -50553,7 +50559,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50553
50559
|
evt,
|
|
50554
50560
|
data,
|
|
50555
50561
|
});
|
|
50556
|
-
trace(`${T$
|
|
50562
|
+
trace(`${T$e} _onHLSJSError trying to recover from network error`, {
|
|
50557
50563
|
details: data.details,
|
|
50558
50564
|
});
|
|
50559
50565
|
error.level = PlayerError.Levels.WARN;
|
|
@@ -50566,7 +50572,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50566
50572
|
evt,
|
|
50567
50573
|
data,
|
|
50568
50574
|
});
|
|
50569
|
-
trace(`${T$
|
|
50575
|
+
trace(`${T$e} _onHLSJSError trying to recover from media error`, {
|
|
50570
50576
|
details: data.details,
|
|
50571
50577
|
});
|
|
50572
50578
|
error.level = PlayerError.Levels.WARN;
|
|
@@ -50596,7 +50602,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50596
50602
|
return;
|
|
50597
50603
|
}
|
|
50598
50604
|
Log.warn('hlsjs: non-fatal error occurred', { evt, data });
|
|
50599
|
-
trace(`${T$
|
|
50605
|
+
trace(`${T$e} _onHLSJSError non-fatal error occurred`, {
|
|
50600
50606
|
type: data.type,
|
|
50601
50607
|
details: data.details,
|
|
50602
50608
|
});
|
|
@@ -50937,7 +50943,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
50937
50943
|
this.trigger(Events$1.PLAYBACK_AUDIO_AVAILABLE, data.audioTracks.map(toClapprTrack));
|
|
50938
50944
|
}
|
|
50939
50945
|
_onAudioTrackSwitched(_, data) {
|
|
50940
|
-
trace(`${T$
|
|
50946
|
+
trace(`${T$e} onAudioTrackSwitched`);
|
|
50941
50947
|
// @ts-ignore
|
|
50942
50948
|
const track = this._hls.audioTracks[data.id];
|
|
50943
50949
|
this.trigger(Events$1.PLAYBACK_AUDIO_CHANGED, toClapprTrack(track));
|
|
@@ -50982,7 +50988,7 @@ function toClapprTrack(t) {
|
|
|
50982
50988
|
};
|
|
50983
50989
|
}
|
|
50984
50990
|
|
|
50985
|
-
const T$
|
|
50991
|
+
const T$d = 'playback.html5_video';
|
|
50986
50992
|
const STALL_TIMEOUT = 15000;
|
|
50987
50993
|
class HTML5Video extends BasePlayback {
|
|
50988
50994
|
stallTimerId = null;
|
|
@@ -51083,7 +51089,7 @@ class HTML5Video extends BasePlayback {
|
|
|
51083
51089
|
switchAudioTrack(id) {
|
|
51084
51090
|
const tracks = this.el.audioTracks;
|
|
51085
51091
|
const supported = !!tracks;
|
|
51086
|
-
trace(`${T$
|
|
51092
|
+
trace(`${T$d} switchAudioTrack`, {
|
|
51087
51093
|
supported,
|
|
51088
51094
|
});
|
|
51089
51095
|
if (supported) {
|
|
@@ -51102,7 +51108,7 @@ function registerPlaybacks() {
|
|
|
51102
51108
|
Loader.registerPlayback(DashPlayback);
|
|
51103
51109
|
}
|
|
51104
51110
|
|
|
51105
|
-
const T$
|
|
51111
|
+
const T$c = 'gplayer';
|
|
51106
51112
|
const DEFAULT_OPTIONS = {
|
|
51107
51113
|
autoPlay: false,
|
|
51108
51114
|
debug: 'none',
|
|
@@ -51296,6 +51302,17 @@ class Player {
|
|
|
51296
51302
|
}
|
|
51297
51303
|
this.player?.load(ms, ms[0].mimeType ?? '');
|
|
51298
51304
|
}
|
|
51305
|
+
/**
|
|
51306
|
+
* Returns a registered core plugin instance by name, or `null` if not found.
|
|
51307
|
+
*
|
|
51308
|
+
* @example
|
|
51309
|
+
* ```ts
|
|
51310
|
+
* const tokenRefresh = player.getPlugin('token_refresh') as TokenRefreshPlugin | null
|
|
51311
|
+
* ```
|
|
51312
|
+
*/
|
|
51313
|
+
getPlugin(name) {
|
|
51314
|
+
return this.player?.core.getPlugin(name) ?? null;
|
|
51315
|
+
}
|
|
51299
51316
|
/**
|
|
51300
51317
|
* Mutes the sound of the video.
|
|
51301
51318
|
*/
|
|
@@ -51438,7 +51455,7 @@ class Player {
|
|
|
51438
51455
|
}
|
|
51439
51456
|
}
|
|
51440
51457
|
triggerAutoPlay() {
|
|
51441
|
-
trace(`${T$
|
|
51458
|
+
trace(`${T$c} triggerAutoPlay`);
|
|
51442
51459
|
setTimeout(() => {
|
|
51443
51460
|
this.player?.play({
|
|
51444
51461
|
autoPlay: true,
|
|
@@ -51456,7 +51473,7 @@ class Player {
|
|
|
51456
51473
|
// TODO test
|
|
51457
51474
|
events = {
|
|
51458
51475
|
onReady: () => {
|
|
51459
|
-
trace(`${T$
|
|
51476
|
+
trace(`${T$c} onReady`, {
|
|
51460
51477
|
ready: this.ready,
|
|
51461
51478
|
});
|
|
51462
51479
|
if (this.ready) {
|
|
@@ -51490,7 +51507,7 @@ class Player {
|
|
|
51490
51507
|
buildCoreOptions(rootNode) {
|
|
51491
51508
|
const sources = this.buildMediaSourcesList();
|
|
51492
51509
|
const source = sources[0];
|
|
51493
|
-
trace(`${T$
|
|
51510
|
+
trace(`${T$c} buildCoreOptions`, {
|
|
51494
51511
|
source,
|
|
51495
51512
|
sources,
|
|
51496
51513
|
});
|
|
@@ -51567,7 +51584,7 @@ class Player {
|
|
|
51567
51584
|
}
|
|
51568
51585
|
}
|
|
51569
51586
|
|
|
51570
|
-
var version$1 = "2.
|
|
51587
|
+
var version$1 = "2.30.0";
|
|
51571
51588
|
|
|
51572
51589
|
var packages = {
|
|
51573
51590
|
"node_modules/@clappr/core": {
|
|
@@ -52000,7 +52017,7 @@ const INITIAL_SETTINGS = {
|
|
|
52000
52017
|
default: [],
|
|
52001
52018
|
seekEnabled: false,
|
|
52002
52019
|
};
|
|
52003
|
-
const T$
|
|
52020
|
+
const T$b = 'plugins.media_control';
|
|
52004
52021
|
/**
|
|
52005
52022
|
* Extended events for the {@link MediaControl} plugin
|
|
52006
52023
|
* @public
|
|
@@ -52293,7 +52310,7 @@ class MediaControl extends UICorePlugin {
|
|
|
52293
52310
|
* Reenables the plugin disabled earlier with the {@link MediaControl.disable} method
|
|
52294
52311
|
*/
|
|
52295
52312
|
enable() {
|
|
52296
|
-
trace(`${T$
|
|
52313
|
+
trace(`${T$b} enable`, {
|
|
52297
52314
|
chromeless: this.options.chromeless,
|
|
52298
52315
|
userDisabled: this.userDisabled,
|
|
52299
52316
|
});
|
|
@@ -52450,7 +52467,7 @@ class MediaControl extends UICorePlugin {
|
|
|
52450
52467
|
this.$el.removeClass('w370');
|
|
52451
52468
|
this.$el.removeClass('w270');
|
|
52452
52469
|
this.verticalVolume = false;
|
|
52453
|
-
trace(`${T$
|
|
52470
|
+
trace(`${T$b} playerResize`, {
|
|
52454
52471
|
size,
|
|
52455
52472
|
width: this.container.$el.width(),
|
|
52456
52473
|
height: this.container.$el.height(),
|
|
@@ -53452,7 +53469,7 @@ class AudioTracks extends UICorePlugin {
|
|
|
53452
53469
|
|
|
53453
53470
|
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";
|
|
53454
53471
|
|
|
53455
|
-
const T$
|
|
53472
|
+
const T$a = 'plugins.big_mute_button';
|
|
53456
53473
|
// TODO rewrite as a container plugin
|
|
53457
53474
|
/**
|
|
53458
53475
|
* `PLUGIN` that displays a big mute button over the video when it's being played muted.
|
|
@@ -53515,7 +53532,7 @@ class BigMuteButton extends UICorePlugin {
|
|
|
53515
53532
|
if (autoPlay) {
|
|
53516
53533
|
this.autoPlay = true;
|
|
53517
53534
|
}
|
|
53518
|
-
trace(`${T$
|
|
53535
|
+
trace(`${T$a} onPlay`, {
|
|
53519
53536
|
autoPlay: this.autoPlay,
|
|
53520
53537
|
wasMuted,
|
|
53521
53538
|
volume,
|
|
@@ -53529,7 +53546,7 @@ class BigMuteButton extends UICorePlugin {
|
|
|
53529
53546
|
}
|
|
53530
53547
|
onStop(_, metadata) {
|
|
53531
53548
|
const ui = metadata?.ui;
|
|
53532
|
-
trace(`${T$
|
|
53549
|
+
trace(`${T$a} onStop`, { ui });
|
|
53533
53550
|
if (ui) {
|
|
53534
53551
|
this.destroy();
|
|
53535
53552
|
}
|
|
@@ -56493,7 +56510,7 @@ const PLAYBACK_NAMES = {
|
|
|
56493
56510
|
hls: 'HLS.js',
|
|
56494
56511
|
html5_video: 'Native',
|
|
56495
56512
|
};
|
|
56496
|
-
const T$
|
|
56513
|
+
const T$9 = 'plugins.nerd_stats';
|
|
56497
56514
|
/**
|
|
56498
56515
|
* `PLUGIN` that displays useful statistics regarding the playback as well as the network quality estimation.
|
|
56499
56516
|
* @public
|
|
@@ -56630,7 +56647,7 @@ class NerdStats extends UICorePlugin {
|
|
|
56630
56647
|
return super.destroy();
|
|
56631
56648
|
}
|
|
56632
56649
|
toggle = () => {
|
|
56633
|
-
trace(`${T$
|
|
56650
|
+
trace(`${T$9} toggle`, {
|
|
56634
56651
|
open: this.open,
|
|
56635
56652
|
});
|
|
56636
56653
|
if (this.open) {
|
|
@@ -56650,14 +56667,14 @@ class NerdStats extends UICorePlugin {
|
|
|
56650
56667
|
})
|
|
56651
56668
|
.catch((e) => {
|
|
56652
56669
|
reportError(e);
|
|
56653
|
-
trace(`${T$
|
|
56670
|
+
trace(`${T$9} speedtest error`, {
|
|
56654
56671
|
error: e,
|
|
56655
56672
|
});
|
|
56656
56673
|
this.disable();
|
|
56657
56674
|
});
|
|
56658
56675
|
}
|
|
56659
56676
|
hide() {
|
|
56660
|
-
trace(`${T$
|
|
56677
|
+
trace(`${T$9} hide`);
|
|
56661
56678
|
this.$el.hide();
|
|
56662
56679
|
this.open = false;
|
|
56663
56680
|
stopSpeedtest();
|
|
@@ -57390,7 +57407,7 @@ const reloadIcon = "<svg fill=\"#FFFFFF\" height=\"24\" viewBox=\"0 0 24 24\" wi
|
|
|
57390
57407
|
|
|
57391
57408
|
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";
|
|
57392
57409
|
|
|
57393
|
-
const T$
|
|
57410
|
+
const T$8 = 'plugins.error_screen';
|
|
57394
57411
|
/**
|
|
57395
57412
|
* `PLUGIN` that displays fatal errors nicely in the overlay on top of the player.
|
|
57396
57413
|
* @public
|
|
@@ -57442,11 +57459,11 @@ class ErrorScreen extends UICorePlugin {
|
|
|
57442
57459
|
this.listenTo(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
|
|
57443
57460
|
}
|
|
57444
57461
|
onPlay() {
|
|
57445
|
-
trace(`${T$
|
|
57462
|
+
trace(`${T$8} onPlay`);
|
|
57446
57463
|
this.unmount();
|
|
57447
57464
|
}
|
|
57448
57465
|
unmount() {
|
|
57449
|
-
trace(`${T$
|
|
57466
|
+
trace(`${T$8} unmount`);
|
|
57450
57467
|
this.err = null;
|
|
57451
57468
|
this.$el.remove();
|
|
57452
57469
|
}
|
|
@@ -57459,7 +57476,7 @@ class ErrorScreen extends UICorePlugin {
|
|
|
57459
57476
|
};
|
|
57460
57477
|
}
|
|
57461
57478
|
reload() {
|
|
57462
|
-
trace(`${T$
|
|
57479
|
+
trace(`${T$8} reload`);
|
|
57463
57480
|
setTimeout(() => {
|
|
57464
57481
|
this.core.configure({
|
|
57465
57482
|
reloading: true,
|
|
@@ -57482,7 +57499,7 @@ class ErrorScreen extends UICorePlugin {
|
|
|
57482
57499
|
}
|
|
57483
57500
|
}
|
|
57484
57501
|
onError(err) {
|
|
57485
|
-
trace(`${T$
|
|
57502
|
+
trace(`${T$8} onError`, { err });
|
|
57486
57503
|
if (err.UI) {
|
|
57487
57504
|
if (this.err) {
|
|
57488
57505
|
this.unmount();
|
|
@@ -57958,16 +57975,12 @@ class Logo extends UIContainerPlugin {
|
|
|
57958
57975
|
}
|
|
57959
57976
|
}
|
|
57960
57977
|
|
|
57961
|
-
const pluginHtml$3 = "<button data-multicamera-button class='gcore-skin-button-color'>\n <span class=\"multicamera-icon\"></span>\n</button>\n\n<ul class=\"gcore-skin-bg-color\">\n <% for (var i
|
|
57978
|
+
const pluginHtml$3 = "<button data-multicamera-button class='gcore-skin-button-color media-control-button'>\n <span class=\"multicamera-icon\"></span>\n</button>\n\n<ul class=\"gcore-skin-bg-color\">\n <% for (var i=0; i < streams.length; i++) { %>\n <% if(!streams[i].live && multisources_mode==='only_live' ) { %>\n <% continue; %>\n <% } %>\n <li>\n <div class=\"multicamera-item\" data-multicamera-selector-live=\"<%= streams[i].live %>\"\n data-multicamera-selector-select=\"<%= streams[i].id %>\">\n <div class=\"multicamera-screenshot\">\n <% if (streams[i].screenshot) { %>\n <img src=\"<%= streams[i].screenshot %>\" alt=\"<%= streams[i].title %>\" />\n <% } %>\n </div>\n <div class=\"multicamera-text gcore-skin-text-color\">\n <% if (streams[i].title) { %>\n <div class=\"multicamera-title gcore-skin-text-color\">\n <%= streams[i].title %>\n </div>\n <% } %>\n <% if (streams[i].description) { %>\n <div class=\"multicamera-description gcore-skin-text-color\">\n <%= streams[i].description %>\n </div>\n <% } %>\n </div>\n </div>\n </li>\n <% } %>\n</ul>";
|
|
57962
57979
|
|
|
57963
57980
|
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";
|
|
57964
57981
|
|
|
57965
|
-
const streamsMomentoIcon = "<svg id=\"Слой_1\" data-name=\"Слой 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 230.73 173.61\"><defs><style>.cls-1{fill:#fff;}</style></defs><path class=\"cls-1\" d=\"M71.82,16.09c11.43,0,22.87-.05,34.31,0,12,.06,19.45,7.45,19.7,19.52.23,11.31.23,11.31,11.81,11.31q24.36,0,48.73,0c12.74,0,20.21,7.3,20.27,19.88q.11,24.12,0,48.23c-.06,12.66-7.12,19.65-19.75,19.77-2,0-4,0-6,0-7.78,0-7.84.05-6,7.79a59.23,59.23,0,0,0,1.95,6.67c1.44,3.95.33,7.18-2.66,9.82-3.28,2.89-6.93,2.88-10.59.76-9.31-5.4-16.95-12.73-23.55-21.11-2.29-2.93-4.66-4.2-8.35-4-5.12.28-10.28.19-15.41,0-10.39-.37-17.64-7.65-18.09-18a62.93,62.93,0,0,0-.09-6.45c-.3-2.07,1.6-5.54-1.49-6-3.62-.48-7.92-2.08-11.07,1.89-6.09,7.7-12.82,14.76-21,20.24a42,42,0,0,1-5.09,3.08,8.16,8.16,0,0,1-9.29-1.12,8.25,8.25,0,0,1-3-8.86c1-4,2-8,3-12,.59-2.51-.34-3.66-3.07-3.59-4.14.12-8.3.14-12.43-.11-9.61-.59-16.86-7.76-17-17.42-.24-17.57-.21-35.14,0-52.71.12-10.07,8-17.46,18.43-17.58C48,16,59.88,16.09,71.82,16.09ZM56.66,120.5c2.53-.3,3.87-1.89,5.38-3.08A99.31,99.31,0,0,0,79.83,98.8a8.72,8.72,0,0,1,8-3.83c6.12.18,12.25.12,18.38,0,7.31-.12,10.6-3.39,10.64-10.72q.11-24.33,0-48.68c0-7-3.5-10.51-10.36-10.53q-35-.11-70,0c-6.34,0-9.92,3.51-9.95,9.83q-.15,25.08,0,50.18c0,6.37,3.42,9.72,9.86,9.89,5.62.14,11.26.1,16.89.06,4.37,0,6.2,2,6.25,6.4C59.55,107.88,58.17,114.1,56.66,120.5ZM167.78,152c-1.93-6.72-3.37-12.44-3.41-18.4,0-6.33,1.17-7.71,7.37-7.77,5-.05,9.94.06,14.9,0,7.6-.13,10.79-3.35,10.81-11q.08-23.85,0-47.69c0-7.61-3.38-11-10.86-11.08-18.88-.07-37.76,0-56.64-.08-3.21,0-4.29.89-4.2,4.21.24,8.27.18,16.56,0,24.83-.13,8.6-4.46,16.11-11.88,17.55-6.73,1.3-7.44,4.81-6.78,10.16.14,1.14,0,2.32,0,3.48.3,6.1,3.53,9.44,9.69,9.63,5.79.18,11.6.34,17.38,0,4.81-.31,7.94,1.3,10.83,5.22A79.08,79.08,0,0,0,167.78,152Z\"/><path class=\"cls-1\" d=\"M73.07,56c-6.4,0-12.15-.06-17.9,0-3.28,0-5.76-1-5.68-4.63s2.66-4.59,5.88-4.45c1.49.06,3-.12,4.47,0,4.79.46,8.51.12,7.44-6.47-.43-2.67,1.82-4.32,4.42-4.26s4.81,1.75,4.35,4.4c-1.18,6.75,2.76,6.72,7.44,6.34a43.43,43.43,0,0,1,6.45.09,4,4,0,0,1,4,4.17c0,2.59-1.46,4.88-4.17,4.48-7-1-7.55,5.72-11.08,8.81-1.54,1.35.36,2.28,1.27,3.06,2.13,1.83,4.38,3.53,6.52,5.36s2.74,4.28.8,6.54c-1.74,2-4,2-6.27.53-.28-.18-.52-.41-.79-.6-3.22-2.29-5.94-6.88-9.46-6.66s-6.61,4-9.91,6.17a19.94,19.94,0,0,1-2.55,1.52c-2.51,1.19-5,1.29-6.46-1.44-1.42-2.57-.6-4.82,1.91-6.34A88.31,88.31,0,0,0,68.17,62.07C69.84,60.52,71.73,59.09,73.07,56Z\"/><path class=\"cls-1\" d=\"M153,104.27a43.76,43.76,0,0,1-4.91,0c-3.27-.4-5.24.75-6.27,4-.9,2.88-2.84,5.23-6.28,3.82-3.66-1.5-3.21-4.49-1.94-7.52,4.68-11.12,9.36-22.22,13.94-33.37,1-2.36,2.28-4.1,5-4.08s3.89,2,4.85,4.25c4.66,11.11,9.4,22.2,14.14,33.28,1.3,3,1.69,6-2,7.46-3.4,1.35-5.49-.73-6.29-3.74C161.49,102,156.3,105.12,153,104.27Zm-.84-20.39a64.73,64.73,0,0,1-2.78,6.37c-2.25,3.89-1.16,4.85,3.14,4.89s4.82-1.35,2.93-4.73C154.36,88.42,154.15,86,152.18,83.88Z\"/></svg>";
|
|
57966
|
-
|
|
57967
|
-
const streamsWhiteNightsIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"50\" height=\"50\" viewBox=\"0 0 50 50\">\n <defs>\n <clipPath id=\"clip-Icon\">\n <rect width=\"50\" height=\"50\"/>\n </clipPath>\n </defs>\n <g id=\"Icon\" clip-path=\"url(#clip-Icon)\">\n <g id=\"icon2\" transform=\"translate(-0.041 0)\">\n <path id=\"Контур_77\" data-name=\"Контур 77\" d=\"M6.493,13v8.266h6.275V19.74H8.31V17.714h4.006V16.3H8.31V14.53h4.365V13Zm7.5,0v8.266h1.7V15.732h.023l3.438,5.534h1.818V13h-1.7v5.545h-.023L15.8,13Z\" fill=\"#fff\"/>\n <path id=\"Контур_76\" data-name=\"Контур 76\" d=\"M29.949,29.1V26.774H31.94a1.4,1.4,0,0,1,.938.272,1.1,1.1,0,0,1,.313.874,1.155,1.155,0,0,1-.313.9,1.375,1.375,0,0,1-.938.278ZM28.132,25.36v8.266h1.817V30.4h1.818a1.353,1.353,0,0,1,.984.3,1.637,1.637,0,0,1,.394.949c.046.333.079.681.1,1.042a3.2,3.2,0,0,0,.185.938h1.819a1.218,1.218,0,0,1-.191-.423,3.611,3.611,0,0,1-.093-.527c-.019-.185-.033-.367-.041-.544s-.016-.332-.023-.463a5.052,5.052,0,0,0-.087-.625,2.109,2.109,0,0,0-.2-.573,1.586,1.586,0,0,0-.359-.451,1.414,1.414,0,0,0-.556-.284v-.023a1.926,1.926,0,0,0,1-.81,2.494,2.494,0,0,0,.307-1.262,2.308,2.308,0,0,0-.165-.88,2.128,2.128,0,0,0-.486-.724,2.3,2.3,0,0,0-.764-.492,2.67,2.67,0,0,0-1-.179ZM43.506,30.5V25.36H41.689V30.5a2.065,2.065,0,0,1-.37,1.36,1.7,1.7,0,0,1-1.343.434,2.086,2.086,0,0,1-.886-.156,1.283,1.283,0,0,1-.758-.978,3.748,3.748,0,0,1-.058-.66V25.36H36.456V30.5a3.16,3.16,0,0,0,.92,2.5,3.807,3.807,0,0,0,2.6.81,3.82,3.82,0,0,0,2.593-.816,3.132,3.132,0,0,0,.937-2.492Z\" fill=\"#fff\"/>\n <path id=\"Контур_80\" data-name=\"Контур 80\" d=\"M22.646,31.2H4.689a4.505,4.505,0,0,1-4.5-4.5V8.5A4.505,4.505,0,0,1,4.689,4h18.2a4.505,4.505,0,0,1,4.5,4.5v8.445l-.893.1a3.184,3.184,0,0,0-2.846,3.177V30.5l-.465.7ZM4.689,6a2.5,2.5,0,0,0-2.5,2.5V26.7a2.5,2.5,0,0,0,2.5,2.5H21.65V20.22a5.18,5.18,0,0,1,3.739-4.992V8.5a2.5,2.5,0,0,0-2.5-2.5Z\" fill=\"#fff\"/>\n <path id=\"Контур_81\" data-name=\"Контур 81\" d=\"M30.127,47.884a1,1,0,0,1-1-1V43.267H26.846a5.206,5.206,0,0,1-5.2-5.2V20.222a5.206,5.206,0,0,1,5.2-5.2H44.692a5.206,5.206,0,0,1,5.2,5.2V38.068a5.206,5.206,0,0,1-5.2,5.2H35.058l-4.216,4.316A1,1,0,0,1,30.127,47.884ZM26.846,17.022a3.2,3.2,0,0,0-3.2,3.2V38.067a3.2,3.2,0,0,0,3.2,3.2h3.281a1,1,0,0,1,1,1v2.162l2.8-2.86a1,1,0,0,1,.715-.3H44.692a3.2,3.2,0,0,0,3.2-3.2V20.222a3.2,3.2,0,0,0-3.2-3.2Z\" fill=\"#fff\"/>\n </g>\n </g>\n</svg>\n";
|
|
57968
|
-
|
|
57969
57982
|
const VERSION$4 = '0.0.1';
|
|
57970
|
-
const T$
|
|
57983
|
+
const T$7 = 'plugins.multicamera';
|
|
57971
57984
|
/**
|
|
57972
57985
|
* `PLUGIN` that adds support for loading multiple streams and switching between them using the media control UI.
|
|
57973
57986
|
* @beta
|
|
@@ -58013,6 +58026,8 @@ class MultiCamera extends UICorePlugin {
|
|
|
58013
58026
|
// Don't mutate the options, TODO check if some plugin observes the options.multicamera
|
|
58014
58027
|
this.multicamera = this.options.multisources.map((item) => ({ ...item }));
|
|
58015
58028
|
this.noActiveStreams = this.multicamera.every((item) => !item.live);
|
|
58029
|
+
// TODO filter out non-live
|
|
58030
|
+
this.core.options.sources = expandMediaSource(this.multicamera[0]);
|
|
58016
58031
|
}
|
|
58017
58032
|
bindEvents() {
|
|
58018
58033
|
this.listenTo(this.core, Events$1.CORE_READY, this.bindPlaybackEvents);
|
|
@@ -58021,15 +58036,10 @@ class MultiCamera extends UICorePlugin {
|
|
|
58021
58036
|
this.listenTo(this.core.mediaControl, Events$1.MEDIACONTROL_HIDE, this.hideSelectLevelMenu);
|
|
58022
58037
|
}
|
|
58023
58038
|
unBindEvents() {
|
|
58024
|
-
|
|
58025
|
-
this.stopListening(this.core, Events$1.
|
|
58026
|
-
|
|
58027
|
-
this.stopListening(this.core.mediaControl, Events$1.
|
|
58028
|
-
// @ts-ignore
|
|
58029
|
-
this.stopListening(this.core.mediaControl, Events$1.MEDIACONTROL_RENDERED);
|
|
58030
|
-
// @ts-ignore
|
|
58031
|
-
this.stopListening(this.core.mediaControl, Events$1.MEDIACONTROL_HIDE);
|
|
58032
|
-
// @ts-ignore
|
|
58039
|
+
this.stopListening(this.core, Events$1.CORE_READY, this.bindPlaybackEvents);
|
|
58040
|
+
this.stopListening(this.core.mediaControl, Events$1.MEDIACONTROL_CONTAINERCHANGED, this.reload);
|
|
58041
|
+
this.stopListening(this.core.mediaControl, Events$1.MEDIACONTROL_RENDERED, this.render);
|
|
58042
|
+
this.stopListening(this.core.mediaControl, Events$1.MEDIACONTROL_HIDE, this.hideSelectLevelMenu);
|
|
58033
58043
|
this.stopListening(this.core.activePlayback, Events$1.PLAYBACK_PLAY, this.onPlay);
|
|
58034
58044
|
}
|
|
58035
58045
|
onPlay() {
|
|
@@ -58045,119 +58055,65 @@ class MultiCamera extends UICorePlugin {
|
|
|
58045
58055
|
this.bindPlaybackEvents();
|
|
58046
58056
|
}
|
|
58047
58057
|
shouldRender() {
|
|
58048
|
-
if (
|
|
58049
|
-
return false;
|
|
58050
|
-
}
|
|
58051
|
-
if (!this.core.activePlayback) {
|
|
58058
|
+
if (this.noActiveStreams) {
|
|
58052
58059
|
return false;
|
|
58053
58060
|
}
|
|
58054
58061
|
return this.multicamera.length >= 2;
|
|
58055
58062
|
}
|
|
58056
58063
|
render() {
|
|
58057
|
-
if (this.
|
|
58058
|
-
|
|
58059
|
-
|
|
58060
|
-
|
|
58061
|
-
|
|
58062
|
-
|
|
58063
|
-
|
|
58064
|
-
|
|
58065
|
-
|
|
58066
|
-
|
|
58067
|
-
|
|
58068
|
-
}
|
|
58069
|
-
// const mediaControl = this.core.getPlugin('media_control')
|
|
58070
|
-
if (this.currentTime &&
|
|
58071
|
-
// TODO check the last active playback type instead
|
|
58072
|
-
// !mediaControl.$el.hasClass('live') &&
|
|
58073
|
-
this.core.getPlaybackType() !== Playback.LIVE) {
|
|
58074
|
-
if (this.currentTime < this.core.activePlayback.getDuration()) {
|
|
58075
|
-
this.core.activePlayback.seek(this.currentTime);
|
|
58076
|
-
}
|
|
58077
|
-
this.currentTime = 0;
|
|
58078
|
-
// if (mediaControl.$el.hasClass('dvr')) {
|
|
58079
|
-
// this.core.activeContainer.dvrInUse = true;
|
|
58080
|
-
// }
|
|
58081
|
-
}
|
|
58082
|
-
// TODO current source
|
|
58083
|
-
this.$el.html(this.template({
|
|
58084
|
-
streams: this.multicamera,
|
|
58085
|
-
multisources_mode: this.options.multisourcesMode,
|
|
58086
|
-
}));
|
|
58087
|
-
if ((numActiveSources <= 1 &&
|
|
58088
|
-
this.options.multisourcesMode !== 'show_all') ||
|
|
58089
|
-
this.options.multisourcesMode === 'one_first') {
|
|
58090
|
-
this.$el.hide();
|
|
58091
|
-
}
|
|
58092
|
-
else {
|
|
58093
|
-
this.$el.show();
|
|
58064
|
+
if (!this.core.activeContainer || !this.core.activePlayback) {
|
|
58065
|
+
return this;
|
|
58066
|
+
}
|
|
58067
|
+
if (!this.shouldRender()) {
|
|
58068
|
+
return this;
|
|
58069
|
+
}
|
|
58070
|
+
let numActiveSources = 0;
|
|
58071
|
+
const currentSource = this.core.activePlayback?.sourceMedia;
|
|
58072
|
+
for (const item of this.multicamera) {
|
|
58073
|
+
if (item.live) {
|
|
58074
|
+
numActiveSources++;
|
|
58094
58075
|
}
|
|
58095
|
-
if (this.
|
|
58096
|
-
this.
|
|
58097
|
-
this.core.mediaControl.$multiCameraSelector.append(this.el);
|
|
58076
|
+
if (!this.currentCamera && item.source === currentSource) {
|
|
58077
|
+
this.currentCamera = item;
|
|
58098
58078
|
}
|
|
58099
|
-
|
|
58100
|
-
|
|
58101
|
-
|
|
58102
|
-
if (
|
|
58103
|
-
this.core.
|
|
58104
|
-
if (~window.location.href.indexOf('whitenights.gcdn.co')) {
|
|
58105
|
-
this.core.mediaControl.$multiCameraSelector
|
|
58106
|
-
.find('span.multicamera-icon')
|
|
58107
|
-
.append(streamsWhiteNightsIcon);
|
|
58108
|
-
}
|
|
58109
|
-
else if (~window.location.href.indexOf('momentosolutions.gcdn.co')) {
|
|
58110
|
-
this.core.mediaControl.$multiCameraSelector
|
|
58111
|
-
.find('span.multicamera-icon')
|
|
58112
|
-
.append(streamsMomentoIcon);
|
|
58113
|
-
}
|
|
58114
|
-
else {
|
|
58115
|
-
this.core.mediaControl.$multiCameraSelector
|
|
58116
|
-
.find('span.multicamera-icon')
|
|
58117
|
-
.append(streamsIcon);
|
|
58118
|
-
}
|
|
58079
|
+
}
|
|
58080
|
+
if (this.currentTime &&
|
|
58081
|
+
this.core.getPlaybackType() !== Playback.LIVE) {
|
|
58082
|
+
if (this.currentTime < this.core.activePlayback.getDuration()) {
|
|
58083
|
+
this.core.activePlayback.seek(this.currentTime);
|
|
58119
58084
|
}
|
|
58120
|
-
this.
|
|
58085
|
+
this.currentTime = 0;
|
|
58086
|
+
}
|
|
58087
|
+
this.$el.html(this.template({
|
|
58088
|
+
streams: this.multicamera,
|
|
58089
|
+
multisources_mode: this.options.multisourcesMode,
|
|
58090
|
+
}));
|
|
58091
|
+
if ((numActiveSources < 2 &&
|
|
58092
|
+
this.options.multisourcesMode !== 'show_all') ||
|
|
58093
|
+
this.options.multisourcesMode === 'one_first') {
|
|
58094
|
+
this.$el.hide();
|
|
58095
|
+
}
|
|
58096
|
+
else {
|
|
58097
|
+
this.$el.show();
|
|
58121
58098
|
}
|
|
58099
|
+
const mediaControl = this.core.getPlugin('media_control');
|
|
58100
|
+
mediaControl.slot('multicamera', this.$el);
|
|
58101
|
+
this.$el
|
|
58102
|
+
.find('span.multicamera-icon')
|
|
58103
|
+
.html(streamsIcon);
|
|
58104
|
+
this.highlightCurrentLevel();
|
|
58122
58105
|
return this;
|
|
58123
58106
|
}
|
|
58124
58107
|
onCameraSelect(event) {
|
|
58125
58108
|
const value = event.currentTarget.dataset
|
|
58126
58109
|
.multicameraSelectorSelect;
|
|
58127
|
-
trace(`${T$
|
|
58110
|
+
trace(`${T$7} onCameraSelect`, { value });
|
|
58128
58111
|
if (value !== undefined) {
|
|
58129
58112
|
this.changeById(parseInt(value, 10));
|
|
58130
58113
|
}
|
|
58131
58114
|
event.stopPropagation();
|
|
58132
58115
|
return false;
|
|
58133
58116
|
}
|
|
58134
|
-
activeById(id, active) {
|
|
58135
|
-
this.setLiveStatus(id, active);
|
|
58136
|
-
if (!this.currentCamera && !this.noActiveStreams) {
|
|
58137
|
-
return;
|
|
58138
|
-
}
|
|
58139
|
-
if (this.noActiveStreams && !active) {
|
|
58140
|
-
return;
|
|
58141
|
-
}
|
|
58142
|
-
if (this.currentCamera) {
|
|
58143
|
-
if (this.options.multisourcesMode === 'only_live') {
|
|
58144
|
-
this.behaviorLive(id, active);
|
|
58145
|
-
}
|
|
58146
|
-
if (this.options.multisourcesMode === 'one_first') {
|
|
58147
|
-
this.behaviorOne(id, active);
|
|
58148
|
-
}
|
|
58149
|
-
if (this.options.multisourcesMode === 'show_all') {
|
|
58150
|
-
this.behaviorAll(id, active);
|
|
58151
|
-
}
|
|
58152
|
-
}
|
|
58153
|
-
else {
|
|
58154
|
-
if (this.noActiveStreams && active) {
|
|
58155
|
-
this.changeById(id);
|
|
58156
|
-
this.noActiveStreams = false;
|
|
58157
|
-
}
|
|
58158
|
-
}
|
|
58159
|
-
this.render();
|
|
58160
|
-
}
|
|
58161
58117
|
setLiveStatus(id, active) {
|
|
58162
58118
|
try {
|
|
58163
58119
|
const index = this.findIndexById(id);
|
|
@@ -58220,7 +58176,6 @@ class MultiCamera extends UICorePlugin {
|
|
|
58220
58176
|
this.currentCamera = null;
|
|
58221
58177
|
this.noActiveStreams = true;
|
|
58222
58178
|
this.core.trigger('core:multicamera:no_active_translation');
|
|
58223
|
-
// this.changeById(this.multicamera[nextIndex].id);
|
|
58224
58179
|
}
|
|
58225
58180
|
showError() {
|
|
58226
58181
|
this.core.activePlayback.pause();
|
|
@@ -58243,24 +58198,19 @@ class MultiCamera extends UICorePlugin {
|
|
|
58243
58198
|
}
|
|
58244
58199
|
hideError() {
|
|
58245
58200
|
try {
|
|
58246
|
-
this.core.
|
|
58201
|
+
this.core.getPlugin('media_control')?.enableControlButton();
|
|
58247
58202
|
}
|
|
58248
58203
|
catch (error) {
|
|
58249
58204
|
reportError(error);
|
|
58250
58205
|
}
|
|
58251
58206
|
}
|
|
58252
58207
|
changeById(id) {
|
|
58253
|
-
trace(`${T$
|
|
58208
|
+
trace(`${T$7} changeById`, { id });
|
|
58254
58209
|
queueMicrotask(() => {
|
|
58255
58210
|
const playbackOptions = this.core.options.playback || {};
|
|
58256
|
-
// TODO figure out
|
|
58211
|
+
// TODO figure out if it's needed
|
|
58257
58212
|
playbackOptions.recycleVideo = Browser.isMobile;
|
|
58258
|
-
this.currentCamera = this.findElementById(id)
|
|
58259
|
-
trace(`${T$6} changeById`, {
|
|
58260
|
-
id,
|
|
58261
|
-
currentCamera: this.currentCamera,
|
|
58262
|
-
multicamera: this.multicamera,
|
|
58263
|
-
});
|
|
58213
|
+
this.currentCamera = this.findElementById(id);
|
|
58264
58214
|
if (!this.currentCamera) {
|
|
58265
58215
|
return;
|
|
58266
58216
|
}
|
|
@@ -58277,31 +58227,21 @@ class MultiCamera extends UICorePlugin {
|
|
|
58277
58227
|
// TODO remove?
|
|
58278
58228
|
// for html5 playback:
|
|
58279
58229
|
this.options.dvrEnabled = this.currentCamera.dvr;
|
|
58280
|
-
trace(`${T$
|
|
58230
|
+
trace(`${T$7} changeById`, { currentCamera: this.currentCamera });
|
|
58281
58231
|
// TODO
|
|
58282
58232
|
this.core.configure({
|
|
58283
58233
|
playback: playbackOptions,
|
|
58284
58234
|
source: this.currentCamera.source, // TODO ensure that the preferred transport is used
|
|
58285
|
-
video360: {
|
|
58286
|
-
// TODO
|
|
58287
|
-
projection: this.currentCamera.projection,
|
|
58288
|
-
},
|
|
58289
58235
|
fullscreenDisable,
|
|
58290
58236
|
autoPlay: this.playing,
|
|
58291
58237
|
disableCanAutoPlay: true,
|
|
58292
58238
|
});
|
|
58293
|
-
this.core.activeContainer
|
|
58239
|
+
this.core.activeContainer?.enableMediaControl();
|
|
58294
58240
|
});
|
|
58295
58241
|
this.toggleContextMenu();
|
|
58296
58242
|
}
|
|
58297
|
-
getCamerasList() {
|
|
58298
|
-
return this.multicamera;
|
|
58299
|
-
}
|
|
58300
|
-
getCurrentCamera() {
|
|
58301
|
-
return this.currentCamera;
|
|
58302
|
-
}
|
|
58303
58243
|
findElementById(id) {
|
|
58304
|
-
return this.multicamera.find((element) => element.id === id);
|
|
58244
|
+
return this.multicamera.find((element) => element.id === id) ?? null;
|
|
58305
58245
|
}
|
|
58306
58246
|
findIndexById(id) {
|
|
58307
58247
|
return this.multicamera.findIndex((element) => element.id === id);
|
|
@@ -58310,19 +58250,13 @@ class MultiCamera extends UICorePlugin {
|
|
|
58310
58250
|
this.toggleContextMenu();
|
|
58311
58251
|
}
|
|
58312
58252
|
hideSelectLevelMenu() {
|
|
58313
|
-
this.$('
|
|
58253
|
+
this.$('ul').hide();
|
|
58314
58254
|
}
|
|
58315
58255
|
toggleContextMenu() {
|
|
58316
|
-
this.$('
|
|
58256
|
+
this.$('ul').toggle();
|
|
58317
58257
|
}
|
|
58318
|
-
// private buttonElement(): ZeptoResult {
|
|
58319
|
-
// return this.$('.multicamera button');
|
|
58320
|
-
// }
|
|
58321
|
-
// private buttonElementText(): ZeptoResult {
|
|
58322
|
-
// return this.$('.multicamera button .quality-text');
|
|
58323
|
-
// }
|
|
58324
58258
|
levelElement(id) {
|
|
58325
|
-
return this.$('.multicamera
|
|
58259
|
+
return this.$('ul .multicamera-item' +
|
|
58326
58260
|
(id !== undefined
|
|
58327
58261
|
? '[data-multicamera-selector-select="' + id + '"]'
|
|
58328
58262
|
: ''));
|
|
@@ -58334,13 +58268,29 @@ class MultiCamera extends UICorePlugin {
|
|
|
58334
58268
|
this.levelElement(this.currentCamera.id).addClass('multicamera-active');
|
|
58335
58269
|
}
|
|
58336
58270
|
}
|
|
58271
|
+
function expandMediaSource(source) {
|
|
58272
|
+
const result = [{
|
|
58273
|
+
source: source.source,
|
|
58274
|
+
mimeType: guessMimeType(source.source),
|
|
58275
|
+
}];
|
|
58276
|
+
if (source.source_dash) {
|
|
58277
|
+
result.push({
|
|
58278
|
+
source: source.source_dash,
|
|
58279
|
+
mimeType: MIME_TYPE_DASH,
|
|
58280
|
+
});
|
|
58281
|
+
}
|
|
58282
|
+
if (source.hls_mpegts_url) {
|
|
58283
|
+
result.push(source.hls_mpegts_url);
|
|
58284
|
+
}
|
|
58285
|
+
return result;
|
|
58286
|
+
}
|
|
58337
58287
|
|
|
58338
58288
|
const pipIcon = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M21.05 3.00001C21.302 3.00001 21.5435 3.10003 21.7217 3.27833C21.9 3.45646 22 3.69802 22 3.95003V10.6H20.1V4.90003H4.90001V18.2H10.6V20.1H3.95001C3.69802 20.1 3.45647 20 3.27832 19.8217C3.10002 19.6436 3 19.402 3 19.15V3.95001C3 3.69802 3.10002 3.45647 3.27832 3.27832C3.45644 3.10002 3.69801 3 3.95001 3L21.05 3.00001ZM21.05 12.5C21.302 12.5 21.5435 12.6 21.7217 12.7783C21.9 12.9565 22 13.198 22 13.45V19.15C22 19.402 21.9 19.6436 21.7217 19.8217C21.5436 20 21.302 20.1 21.05 20.1H13.45C13.198 20.1 12.9564 20 12.7783 19.8217C12.6 19.6436 12.5 19.402 12.5 19.15V13.45C12.5 13.198 12.6 12.9565 12.7783 12.7783C12.9564 12.6 13.198 12.5 13.45 12.5H21.05ZM7.47178 6.12823L9.60928 8.26572L11.5501 6.32492V11.5499H6.32509L8.26589 9.60911L6.12839 7.47161L7.47178 6.12823Z\"\n fill=\"#C9C9C9\"/>\n</svg>\n";
|
|
58339
58289
|
|
|
58340
58290
|
const buttonHtml$2 = "<button class=\"gplayer-lite-btn gcore-skin-button-color\">\n <%= pipIcon %>\n</button>\n";
|
|
58341
58291
|
|
|
58342
58292
|
const VERSION$3 = '0.0.1';
|
|
58343
|
-
const T$
|
|
58293
|
+
const T$6 = `plugins.pip`;
|
|
58344
58294
|
/**
|
|
58345
58295
|
* `PLUGIN` that enables picture-in-picture mode.
|
|
58346
58296
|
* @public
|
|
@@ -58398,7 +58348,7 @@ class PictureInPicture extends UICorePlugin {
|
|
|
58398
58348
|
});
|
|
58399
58349
|
}
|
|
58400
58350
|
isPiPSupported() {
|
|
58401
|
-
trace(`${T$
|
|
58351
|
+
trace(`${T$6} isPiPSupported`, {
|
|
58402
58352
|
pictureInPictureEnabled: !!document.pictureInPictureEnabled,
|
|
58403
58353
|
requestPictureInPicture: !!HTMLVideoElement.prototype.requestPictureInPicture,
|
|
58404
58354
|
});
|
|
@@ -58420,7 +58370,7 @@ class PictureInPicture extends UICorePlugin {
|
|
|
58420
58370
|
return this;
|
|
58421
58371
|
}
|
|
58422
58372
|
togglePictureInPicture() {
|
|
58423
|
-
trace(`${T$
|
|
58373
|
+
trace(`${T$6} togglePictureInPicture`);
|
|
58424
58374
|
if (this.videoElement !== document.pictureInPictureElement) {
|
|
58425
58375
|
this.requestPictureInPicture();
|
|
58426
58376
|
}
|
|
@@ -58429,13 +58379,13 @@ class PictureInPicture extends UICorePlugin {
|
|
|
58429
58379
|
}
|
|
58430
58380
|
}
|
|
58431
58381
|
requestPictureInPicture() {
|
|
58432
|
-
trace(`${T$
|
|
58382
|
+
trace(`${T$6} requestPictureInPicture`, {
|
|
58433
58383
|
videoElement: !!this.videoElement,
|
|
58434
58384
|
});
|
|
58435
58385
|
this.videoElement.requestPictureInPicture();
|
|
58436
58386
|
}
|
|
58437
58387
|
exitPictureInPicture() {
|
|
58438
|
-
trace(`${T$
|
|
58388
|
+
trace(`${T$6} exitPictureInPicture`);
|
|
58439
58389
|
document.exitPictureInPicture();
|
|
58440
58390
|
}
|
|
58441
58391
|
}
|
|
@@ -58462,7 +58412,7 @@ const DEFAULT_PLAYBACK_RATES = [
|
|
|
58462
58412
|
{ value: 2.0, label: '2x' },
|
|
58463
58413
|
];
|
|
58464
58414
|
const DEFAULT_PLAYBACK_RATE = 1;
|
|
58465
|
-
const T$
|
|
58415
|
+
const T$5 = 'plugins.playback_rate';
|
|
58466
58416
|
/**
|
|
58467
58417
|
* `PLUGIN` that allows changing the playback speed of the video.
|
|
58468
58418
|
* @public
|
|
@@ -58548,7 +58498,7 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58548
58498
|
this.listenTo(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChange);
|
|
58549
58499
|
}
|
|
58550
58500
|
onCoreReady() {
|
|
58551
|
-
trace(`${T$
|
|
58501
|
+
trace(`${T$5} onCoreReady`);
|
|
58552
58502
|
const mediaControl = this.core.getPlugin('media_control');
|
|
58553
58503
|
assert(mediaControl, 'media_control plugin is required');
|
|
58554
58504
|
const gear = this.core.getPlugin('bottom_gear');
|
|
@@ -58557,7 +58507,7 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58557
58507
|
this.listenTo(gear, GearEvents.RENDERED, this.onGearRendered);
|
|
58558
58508
|
}
|
|
58559
58509
|
onActiveContainerChange() {
|
|
58560
|
-
trace(`${T$
|
|
58510
|
+
trace(`${T$5} onActiveContainerChange`);
|
|
58561
58511
|
this.metadataLoaded = false;
|
|
58562
58512
|
this.listenTo(this.core.activePlayback, Events$1.PLAYBACK_STOP, this.onStop);
|
|
58563
58513
|
this.listenTo(this.core.activePlayback, Events$1.PLAYBACK_PLAY, this.onPlay);
|
|
@@ -58565,15 +58515,15 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58565
58515
|
this.listenTo(this.core.activeContainer, Events$1.CONTAINER_LOADEDMETADATA, this.onMetaDataLoaded);
|
|
58566
58516
|
}
|
|
58567
58517
|
onMediaControlRendered() {
|
|
58568
|
-
trace(`${T$
|
|
58518
|
+
trace(`${T$5} onMediaControlRendered`);
|
|
58569
58519
|
this.render();
|
|
58570
58520
|
}
|
|
58571
58521
|
onGearRendered() {
|
|
58572
|
-
trace(`${T$
|
|
58522
|
+
trace(`${T$5} onGearRendered`);
|
|
58573
58523
|
this.mount();
|
|
58574
58524
|
}
|
|
58575
58525
|
mount() {
|
|
58576
|
-
trace(`${T$
|
|
58526
|
+
trace(`${T$5} mount`, {
|
|
58577
58527
|
shouldMount: this.shouldMount(),
|
|
58578
58528
|
});
|
|
58579
58529
|
if (!this.shouldMount()) {
|
|
@@ -58590,7 +58540,7 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58590
58540
|
})));
|
|
58591
58541
|
}
|
|
58592
58542
|
onMetaDataLoaded() {
|
|
58593
|
-
trace(`${T$
|
|
58543
|
+
trace(`${T$5} onMetaDataLoaded`, {
|
|
58594
58544
|
playbackType: this.core.activePlayback.getPlaybackType(),
|
|
58595
58545
|
dvrEnabled: this.core.activePlayback.dvrEnabled,
|
|
58596
58546
|
});
|
|
@@ -58612,7 +58562,7 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58612
58562
|
this.core.activePlayback?.setPlaybackRate(this.selectedRate);
|
|
58613
58563
|
}
|
|
58614
58564
|
else {
|
|
58615
|
-
trace(`${T$
|
|
58565
|
+
trace(`${T$5} onPlaybackRateChange not steering to the selected rate, it is seemingly a catchup algorithm working`, {
|
|
58616
58566
|
playbackRate,
|
|
58617
58567
|
selectedRate: this.selectedRate,
|
|
58618
58568
|
});
|
|
@@ -58675,13 +58625,13 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58675
58625
|
}
|
|
58676
58626
|
}
|
|
58677
58627
|
syncRate() {
|
|
58678
|
-
trace(`${T$
|
|
58628
|
+
trace(`${T$5} syncRate`, {
|
|
58679
58629
|
selectedRate: this.selectedRate,
|
|
58680
58630
|
});
|
|
58681
58631
|
this.core.activePlayback?.setPlaybackRate(this.selectedRate);
|
|
58682
58632
|
}
|
|
58683
58633
|
resetPlaybackRate() {
|
|
58684
|
-
trace(`${T$
|
|
58634
|
+
trace(`${T$5} resetPlaybackRate`, {
|
|
58685
58635
|
selectedRate: this.selectedRate,
|
|
58686
58636
|
});
|
|
58687
58637
|
this.core.activePlayback?.setPlaybackRate(DEFAULT_PLAYBACK_RATE);
|
|
@@ -58716,7 +58666,7 @@ class PlaybackRate extends UICorePlugin {
|
|
|
58716
58666
|
?.label || `x${rate}`);
|
|
58717
58667
|
}
|
|
58718
58668
|
highlightCurrentRate() {
|
|
58719
|
-
trace(`${T$
|
|
58669
|
+
trace(`${T$5} highlightCurrentRate`, {
|
|
58720
58670
|
selectedRate: this.selectedRate,
|
|
58721
58671
|
});
|
|
58722
58672
|
this.allRateElements().removeClass('current');
|
|
@@ -59752,7 +59702,7 @@ class SpinnerThreeBounce extends UIContainerPlugin {
|
|
|
59752
59702
|
}
|
|
59753
59703
|
}
|
|
59754
59704
|
|
|
59755
|
-
const T$
|
|
59705
|
+
const T$4 = 'plugins.source_controller';
|
|
59756
59706
|
const INITIAL_RETRY_DELAY = 1000;
|
|
59757
59707
|
const MAX_RETRY_DELAY = 5000;
|
|
59758
59708
|
const RETRY_DELAY_BLUR = 500;
|
|
@@ -59764,45 +59714,6 @@ function noSync(cb) {
|
|
|
59764
59714
|
* `PLUGIN` that is managing the automatic failover between media sources.
|
|
59765
59715
|
* @public
|
|
59766
59716
|
* @remarks
|
|
59767
|
-
* Have a look at the {@link https://miro.com/app/board/uXjVLiN15tY=/?share_link_id=390327585787 | source failover diagram} for the details
|
|
59768
|
-
* on how sources ordering and selection works. Below is a simplified diagram:
|
|
59769
|
-
*
|
|
59770
|
-
* ```markdown
|
|
59771
|
-
* sources_list:
|
|
59772
|
-
* - a.mpd | +--------------------+
|
|
59773
|
-
* - b.m3u8 |--->| init |
|
|
59774
|
-
* - ... | |--------------------|
|
|
59775
|
-
* | current_source = 0 |
|
|
59776
|
-
* +--------------------+
|
|
59777
|
-
* |
|
|
59778
|
-
* | source = a.mpd
|
|
59779
|
-
* | playback = dash.js
|
|
59780
|
-
* v
|
|
59781
|
-
* +------------------+
|
|
59782
|
-
* +-->| load source |
|
|
59783
|
-
* | +---------|--------+
|
|
59784
|
-
* | v
|
|
59785
|
-
* | +------------------+
|
|
59786
|
-
* | | play |
|
|
59787
|
-
* | +---------|--------+
|
|
59788
|
-
* | |
|
|
59789
|
-
* | v
|
|
59790
|
-
* | +-----------------------+
|
|
59791
|
-
* | | on playback_error |
|
|
59792
|
-
* | |-----------------------|
|
|
59793
|
-
* | | current_source = |
|
|
59794
|
-
* | | (current_source + 1) |
|
|
59795
|
-
* | | % len sources_list |
|
|
59796
|
-
* | | |
|
|
59797
|
-
* | | delay 1..3s |
|
|
59798
|
-
* | +---------------|-------+
|
|
59799
|
-
* | |
|
|
59800
|
-
* | source=b.m3u8 |
|
|
59801
|
-
* | playback=hls.js |
|
|
59802
|
-
* +-------------------+
|
|
59803
|
-
*
|
|
59804
|
-
* ```
|
|
59805
|
-
*
|
|
59806
59717
|
* @example
|
|
59807
59718
|
* ```ts
|
|
59808
59719
|
* import { SourceController } from '@gcorevideo/player'
|
|
@@ -59928,7 +59839,7 @@ class SourceController extends CorePlugin {
|
|
|
59928
59839
|
}
|
|
59929
59840
|
bindContainerEventListeners() {
|
|
59930
59841
|
this.core.activePlayback.on(Events$1.PLAYBACK_ERROR, (error) => {
|
|
59931
|
-
trace(`${T$
|
|
59842
|
+
trace(`${T$4} on PLAYBACK_ERROR`, {
|
|
59932
59843
|
error: {
|
|
59933
59844
|
code: error?.code,
|
|
59934
59845
|
description: error?.description,
|
|
@@ -59952,7 +59863,7 @@ class SourceController extends CorePlugin {
|
|
|
59952
59863
|
}
|
|
59953
59864
|
});
|
|
59954
59865
|
this.listenTo(this.core.activeContainer, Events$1.CONTAINER_PLAY, (_, { autoPlay }) => {
|
|
59955
|
-
trace(`${T$
|
|
59866
|
+
trace(`${T$4} onContainerPlay`, {
|
|
59956
59867
|
autoPlay,
|
|
59957
59868
|
currentSource: this.sourcesList[this.currentSourceIndex],
|
|
59958
59869
|
retrying: this.active,
|
|
@@ -59970,7 +59881,7 @@ class SourceController extends CorePlugin {
|
|
|
59970
59881
|
this.sourcesDelay = {};
|
|
59971
59882
|
}
|
|
59972
59883
|
retryPlayback() {
|
|
59973
|
-
trace(`${T$
|
|
59884
|
+
trace(`${T$4} retryPlayback enter`, {
|
|
59974
59885
|
currentSourceIndex: this.currentSourceIndex,
|
|
59975
59886
|
currentSource: this.sourcesList[this.currentSourceIndex],
|
|
59976
59887
|
});
|
|
@@ -59978,18 +59889,18 @@ class SourceController extends CorePlugin {
|
|
|
59978
59889
|
this.switching = true;
|
|
59979
59890
|
this.core.activeContainer?.getPlugin('spinner')?.show(0);
|
|
59980
59891
|
this.getNextMediaSource().then((nextSource) => {
|
|
59981
|
-
trace(`${T$
|
|
59892
|
+
trace(`${T$4} retryPlayback syncing...`, {
|
|
59982
59893
|
nextSource,
|
|
59983
59894
|
});
|
|
59984
59895
|
const rnd = Math.round(RETRY_DELAY_BLUR * Math.random());
|
|
59985
59896
|
this.sync(() => {
|
|
59986
59897
|
this.switching = false;
|
|
59987
59898
|
this.core.load(nextSource.source, nextSource.mimeType);
|
|
59988
|
-
trace(`${T$
|
|
59899
|
+
trace(`${T$4} retryPlayback loaded`, {
|
|
59989
59900
|
nextSource,
|
|
59990
59901
|
});
|
|
59991
59902
|
setTimeout(() => {
|
|
59992
|
-
trace(`${T$
|
|
59903
|
+
trace(`${T$4} retryPlayback playing`, {
|
|
59993
59904
|
autoPlay: this.autoPlay,
|
|
59994
59905
|
nextSource,
|
|
59995
59906
|
});
|
|
@@ -60501,7 +60412,7 @@ class ClosedCaptions extends UICorePlugin {
|
|
|
60501
60412
|
// An example implementation of client side performancestatistics
|
|
60502
60413
|
const WATCH_CUTOFF = 5;
|
|
60503
60414
|
const STALL_MEASURE_PERIOD = 10;
|
|
60504
|
-
const T$
|
|
60415
|
+
const T$3 = 'plugins.telemetry';
|
|
60505
60416
|
/**
|
|
60506
60417
|
* Telemetry event type
|
|
60507
60418
|
* @beta
|
|
@@ -60611,7 +60522,7 @@ class Telemetry extends ContainerPlugin {
|
|
|
60611
60522
|
}
|
|
60612
60523
|
onReady() {
|
|
60613
60524
|
this.sendInit();
|
|
60614
|
-
trace(`${T$
|
|
60525
|
+
trace(`${T$3} onReady`, {
|
|
60615
60526
|
autoPlay: this.options.autoPlay,
|
|
60616
60527
|
});
|
|
60617
60528
|
if (this.options.autoPlay) {
|
|
@@ -63312,7 +63223,7 @@ function loadImageDimensions(url) {
|
|
|
63312
63223
|
});
|
|
63313
63224
|
}
|
|
63314
63225
|
|
|
63315
|
-
const T$
|
|
63226
|
+
const T$2 = 'plugins.thumbnails';
|
|
63316
63227
|
/**
|
|
63317
63228
|
* `PLUGIN` that displays the thumbnails of the video when available.
|
|
63318
63229
|
* @public
|
|
@@ -63430,14 +63341,14 @@ class Thumbnails extends UICorePlugin {
|
|
|
63430
63341
|
if (!this.options.thumbnails ||
|
|
63431
63342
|
!this.options.thumbnails.sprite ||
|
|
63432
63343
|
!this.options.thumbnails.vtt) {
|
|
63433
|
-
trace(`${T$
|
|
63344
|
+
trace(`${T$2} misconfigured: options.thumbnails.sprite and options.thumbnails.vtt are required`);
|
|
63434
63345
|
this.destroy();
|
|
63435
63346
|
return;
|
|
63436
63347
|
}
|
|
63437
63348
|
const { sprite: spriteSheet, vtt } = this.options.thumbnails;
|
|
63438
63349
|
this.thumbs = this.buildSpriteConfig(parseVTT(vtt), spriteSheet);
|
|
63439
63350
|
if (!this.thumbs.length) {
|
|
63440
|
-
trace(`${T$
|
|
63351
|
+
trace(`${T$2} failed to parse the sprite sheet`);
|
|
63441
63352
|
this.destroy();
|
|
63442
63353
|
return;
|
|
63443
63354
|
}
|
|
@@ -63686,6 +63597,321 @@ function parseVTT(vtt) {
|
|
|
63686
63597
|
return cues;
|
|
63687
63598
|
}
|
|
63688
63599
|
|
|
63600
|
+
const T$1 = 'plugins.token_refresh';
|
|
63601
|
+
/**
|
|
63602
|
+
* Matches the `/{token}/{expires}/` segment in a Gcore protected-content URL.
|
|
63603
|
+
* Token is base64url (letters, digits, `-`, `_`); expires is a ≥10-digit Unix timestamp.
|
|
63604
|
+
*/
|
|
63605
|
+
const TOKEN_SEGMENT_RE = /\/([A-Za-z0-9_-]{6,})\/(1\d{9,})\//;
|
|
63606
|
+
function extractTokenState(url) {
|
|
63607
|
+
const m = url.match(TOKEN_SEGMENT_RE);
|
|
63608
|
+
if (!m)
|
|
63609
|
+
return null;
|
|
63610
|
+
return { token: m[1], expires: parseInt(m[2], 10) };
|
|
63611
|
+
}
|
|
63612
|
+
/** Replaces the exact `/{oldToken}/{oldExpires}/` segment in a URL. */
|
|
63613
|
+
function rewriteUrl(url, from, to) {
|
|
63614
|
+
const oldPart = `/${from.token}/${from.expires}/`;
|
|
63615
|
+
const newPart = `/${to.token}/${to.expires}/`;
|
|
63616
|
+
return url.includes(oldPart) ? url.replace(oldPart, newPart) : url;
|
|
63617
|
+
}
|
|
63618
|
+
/**
|
|
63619
|
+
* Normalises a URL by removing the `/{token}/{expires}/` segment so two URLs
|
|
63620
|
+
* for the same stream with different token pairs compare equal.
|
|
63621
|
+
* Returns `null` for unparseable input.
|
|
63622
|
+
*/
|
|
63623
|
+
function streamKey(url) {
|
|
63624
|
+
try {
|
|
63625
|
+
const u = new URL(url);
|
|
63626
|
+
return u.origin + u.pathname.replace(TOKEN_SEGMENT_RE, '/');
|
|
63627
|
+
}
|
|
63628
|
+
catch {
|
|
63629
|
+
return null;
|
|
63630
|
+
}
|
|
63631
|
+
}
|
|
63632
|
+
/**
|
|
63633
|
+
* Returns a custom hls.js loader class that transparently rewrites the
|
|
63634
|
+
* token/expires path segments in every request URL.
|
|
63635
|
+
*
|
|
63636
|
+
* The returned class extends the default hls.js XhrLoader so all native
|
|
63637
|
+
* hls.js behaviour (retry, timeout, range requests …) is preserved.
|
|
63638
|
+
*/
|
|
63639
|
+
function createTokenRewritingLoader(getOriginal, getCurrent) {
|
|
63640
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63641
|
+
const DefaultLoader = Hls.DefaultConfig.loader;
|
|
63642
|
+
return class TokenRewritingLoader extends DefaultLoader {
|
|
63643
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63644
|
+
load(context, config, callbacks) {
|
|
63645
|
+
const original = getOriginal();
|
|
63646
|
+
const current = getCurrent();
|
|
63647
|
+
if (original && current && context.url) {
|
|
63648
|
+
context.url = rewriteUrl(context.url, original, current);
|
|
63649
|
+
}
|
|
63650
|
+
super.load(context, config, callbacks);
|
|
63651
|
+
}
|
|
63652
|
+
};
|
|
63653
|
+
}
|
|
63654
|
+
/**
|
|
63655
|
+
* `PLUGIN` — automatic token refresh for Gcore protected-content streams.
|
|
63656
|
+
*
|
|
63657
|
+
* Supports all three playback engines:
|
|
63658
|
+
*
|
|
63659
|
+
* | Engine | Mechanism | Interruption |
|
|
63660
|
+
* |--------|-----------|--------------|
|
|
63661
|
+
* | **hls.js** | Custom loader rewrites every request URL | None |
|
|
63662
|
+
* | **dash.js** | `addRequestInterceptor` rewrites every request URL | None |
|
|
63663
|
+
* | **Native `<video>`** (Safari ≤ iOS 14.4) | Source reload + seek restore | Brief |
|
|
63664
|
+
*
|
|
63665
|
+
* @public
|
|
63666
|
+
* @remarks
|
|
63667
|
+
* Register the plugin once before creating any player instance:
|
|
63668
|
+
* ```ts
|
|
63669
|
+
* import { Player, TokenRefreshPlugin } from '@gcorevideo/player'
|
|
63670
|
+
* Player.registerPlugin(TokenRefreshPlugin)
|
|
63671
|
+
* ```
|
|
63672
|
+
*
|
|
63673
|
+
* Then pass `tokenRefresh` in `PlayerConfig`:
|
|
63674
|
+
* ```ts
|
|
63675
|
+
* const player = new Player({
|
|
63676
|
+
* sources: [{ source: initialUrl, mimeType: 'application/x-mpegURL' }],
|
|
63677
|
+
* tokenRefresh: {
|
|
63678
|
+
* getToken: () => fetch('https://…/token').then(r => r.json()),
|
|
63679
|
+
* ipBound: false,
|
|
63680
|
+
* refreshLeadSeconds: 5,
|
|
63681
|
+
* onTokenRefreshed: (data) => console.log('new token expires', data.expires),
|
|
63682
|
+
* },
|
|
63683
|
+
* })
|
|
63684
|
+
* ```
|
|
63685
|
+
*
|
|
63686
|
+
* @example
|
|
63687
|
+
* Safari native — opt-in Service Worker for fully seamless refresh:
|
|
63688
|
+
* ```js
|
|
63689
|
+
* // Register token-refresh-sw.js (see example/ directory)
|
|
63690
|
+
* // and omit tokenRefresh config — the SW handles rewriting.
|
|
63691
|
+
* ```
|
|
63692
|
+
*/
|
|
63693
|
+
class TokenRefreshPlugin extends CorePlugin {
|
|
63694
|
+
/** @internal */
|
|
63695
|
+
static get type() {
|
|
63696
|
+
return 'core';
|
|
63697
|
+
}
|
|
63698
|
+
/** @internal */
|
|
63699
|
+
get name() {
|
|
63700
|
+
return 'token_refresh';
|
|
63701
|
+
}
|
|
63702
|
+
/** @internal */
|
|
63703
|
+
get supportedVersion() {
|
|
63704
|
+
return { min: CLAPPR_VERSION$1 };
|
|
63705
|
+
}
|
|
63706
|
+
/** Token state extracted from the currently-managed source URL */
|
|
63707
|
+
originalState = null;
|
|
63708
|
+
/** Latest token state (updated after each refresh) */
|
|
63709
|
+
currentState = null;
|
|
63710
|
+
/** Scheduled refresh timer handle */
|
|
63711
|
+
refreshTimer = null;
|
|
63712
|
+
/** Playback time (seconds) to restore after a native-video source reload */
|
|
63713
|
+
savedPosition = null;
|
|
63714
|
+
/** True when using native HTML5 Video playback (no request interception) */
|
|
63715
|
+
isNativePlayback = false;
|
|
63716
|
+
/** Set in destroy(); short-circuits late timer callbacks and getToken() resolutions */
|
|
63717
|
+
destroyed = false;
|
|
63718
|
+
/** @internal */
|
|
63719
|
+
bindEvents() {
|
|
63720
|
+
this.listenTo(this.core, Events$1.CORE_CONTAINERS_CREATED, this.onContainersCreated);
|
|
63721
|
+
}
|
|
63722
|
+
/** @internal */
|
|
63723
|
+
destroy() {
|
|
63724
|
+
this.destroyed = true;
|
|
63725
|
+
this.clearTimer();
|
|
63726
|
+
super.destroy();
|
|
63727
|
+
}
|
|
63728
|
+
onContainersCreated() {
|
|
63729
|
+
const container = this.core.containers[0];
|
|
63730
|
+
if (!container)
|
|
63731
|
+
return;
|
|
63732
|
+
const playbackName = container.playback.name;
|
|
63733
|
+
const src = container.playback.options?.src ?? '';
|
|
63734
|
+
trace(`${T$1} onContainersCreated`, { playbackName, src: src.slice(0, 80) });
|
|
63735
|
+
this.isNativePlayback = playbackName !== 'hls' && playbackName !== 'dash';
|
|
63736
|
+
const state = extractTokenState(src);
|
|
63737
|
+
if (!state) {
|
|
63738
|
+
// Active source has no token pattern — drop any refresh state we were
|
|
63739
|
+
// holding for a previous stream (e.g. SourceController rotated away).
|
|
63740
|
+
if (this.originalState) {
|
|
63741
|
+
trace(`${T$1} active source has no token pattern — clearing refresh state`);
|
|
63742
|
+
this.clearTimer();
|
|
63743
|
+
this.originalState = null;
|
|
63744
|
+
this.currentState = null;
|
|
63745
|
+
}
|
|
63746
|
+
return;
|
|
63747
|
+
}
|
|
63748
|
+
// Adopt the new token state if this is the first source we see, or if
|
|
63749
|
+
// the stream has changed (SourceController rotated, consumer called
|
|
63750
|
+
// player.load() with a different stream, or the plugin itself reloaded
|
|
63751
|
+
// with a refreshed URL in the native path).
|
|
63752
|
+
const isNewStream = !this.originalState ||
|
|
63753
|
+
state.token !== this.originalState.token ||
|
|
63754
|
+
state.expires !== this.originalState.expires;
|
|
63755
|
+
if (isNewStream) {
|
|
63756
|
+
trace(`${T$1} adopting source token state`, {
|
|
63757
|
+
token: state.token.slice(0, 8) + '…',
|
|
63758
|
+
expires: new Date(state.expires * 1000).toISOString(),
|
|
63759
|
+
});
|
|
63760
|
+
this.originalState = { ...state };
|
|
63761
|
+
this.currentState = { ...state };
|
|
63762
|
+
this.scheduleRefresh();
|
|
63763
|
+
}
|
|
63764
|
+
// Inject the appropriate interception mechanism for this playback engine.
|
|
63765
|
+
switch (playbackName) {
|
|
63766
|
+
case 'hls':
|
|
63767
|
+
this.injectHlsLoader(container);
|
|
63768
|
+
break;
|
|
63769
|
+
case 'dash':
|
|
63770
|
+
this.injectDashInterceptor(container);
|
|
63771
|
+
break;
|
|
63772
|
+
default:
|
|
63773
|
+
// Native HTML5 Video — no request hooks available.
|
|
63774
|
+
// Seek restore after a token-triggered reload.
|
|
63775
|
+
this.listenToOnce(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChangedForNative);
|
|
63776
|
+
break;
|
|
63777
|
+
}
|
|
63778
|
+
}
|
|
63779
|
+
injectHlsLoader(container) {
|
|
63780
|
+
const getOriginal = () => this.originalState;
|
|
63781
|
+
const getCurrent = () => this.currentState;
|
|
63782
|
+
const TokenLoader = createTokenRewritingLoader(getOriginal, getCurrent);
|
|
63783
|
+
$.extend(true, container.playback.options, {
|
|
63784
|
+
playback: {
|
|
63785
|
+
hlsjsConfig: {
|
|
63786
|
+
loader: TokenLoader,
|
|
63787
|
+
},
|
|
63788
|
+
},
|
|
63789
|
+
});
|
|
63790
|
+
trace(`${T$1} HLS custom loader injected`);
|
|
63791
|
+
}
|
|
63792
|
+
injectDashInterceptor(container) {
|
|
63793
|
+
$.extend(true, container.playback.options, {
|
|
63794
|
+
dash: {
|
|
63795
|
+
requestInterceptor: (request) => {
|
|
63796
|
+
if (this.originalState && this.currentState) {
|
|
63797
|
+
request.url = rewriteUrl(request.url, this.originalState, this.currentState);
|
|
63798
|
+
}
|
|
63799
|
+
return Promise.resolve(request);
|
|
63800
|
+
},
|
|
63801
|
+
},
|
|
63802
|
+
});
|
|
63803
|
+
trace(`${T$1} DASH request interceptor injected`);
|
|
63804
|
+
}
|
|
63805
|
+
async reloadNativeSource(data) {
|
|
63806
|
+
const container = this.core.activeContainer;
|
|
63807
|
+
const playback = container?.playback;
|
|
63808
|
+
if (!playback)
|
|
63809
|
+
return;
|
|
63810
|
+
// SourceController (or any other actor) may have switched the active
|
|
63811
|
+
// playback to hls/dash while getToken() was in flight. Those engines
|
|
63812
|
+
// have their own request-interception path; a native reload would
|
|
63813
|
+
// undo the switch.
|
|
63814
|
+
if (playback.name === 'hls' || playback.name === 'dash') {
|
|
63815
|
+
trace(`${T$1} skipping native reload — active playback is ${playback.name}`);
|
|
63816
|
+
return;
|
|
63817
|
+
}
|
|
63818
|
+
if (!this.isNativePlayback) {
|
|
63819
|
+
trace(`${T$1} skipping native reload — no longer in native playback mode`);
|
|
63820
|
+
return;
|
|
63821
|
+
}
|
|
63822
|
+
// Verify the URL we're about to load belongs to the same stream that's
|
|
63823
|
+
// currently active. If SourceController rotated to a different stream
|
|
63824
|
+
// during the getToken() await, the refreshed URL would silently swap
|
|
63825
|
+
// us back, undoing SourceController's decision.
|
|
63826
|
+
const currentSrc = playback.options?.src ?? '';
|
|
63827
|
+
const newUrl = this.opts.ipBound ? data.url_ip : data.url;
|
|
63828
|
+
const activeKey = streamKey(currentSrc);
|
|
63829
|
+
const nextKey = streamKey(newUrl);
|
|
63830
|
+
if (!activeKey || !nextKey || activeKey !== nextKey) {
|
|
63831
|
+
trace(`${T$1} skipping native reload — active source differs from refresh URL`, {
|
|
63832
|
+
activeKey,
|
|
63833
|
+
nextKey,
|
|
63834
|
+
});
|
|
63835
|
+
return;
|
|
63836
|
+
}
|
|
63837
|
+
// Capture current playback position before tearing down the container.
|
|
63838
|
+
const mediaEl = playback.el;
|
|
63839
|
+
const currentTime = mediaEl?.currentTime ?? 0;
|
|
63840
|
+
this.savedPosition = currentTime > 0 ? currentTime : null;
|
|
63841
|
+
trace(`${T$1} native reload`, { newUrl: newUrl.slice(0, 80), savedPosition: this.savedPosition });
|
|
63842
|
+
// core.load() destroys and recreates all containers.
|
|
63843
|
+
this.core.load([{ source: newUrl, mimeType: this.core.options.mimeType ?? 'application/x-mpegURL' }]);
|
|
63844
|
+
}
|
|
63845
|
+
onActiveContainerChangedForNative() {
|
|
63846
|
+
if (this.savedPosition === null)
|
|
63847
|
+
return;
|
|
63848
|
+
const pos = this.savedPosition;
|
|
63849
|
+
this.savedPosition = null;
|
|
63850
|
+
// Wait for the new container to be fully ready before seeking.
|
|
63851
|
+
const container = this.core.activeContainer;
|
|
63852
|
+
if (!container)
|
|
63853
|
+
return;
|
|
63854
|
+
this.listenToOnce(container, Events$1.CONTAINER_READY, () => {
|
|
63855
|
+
trace(`${T$1} native: restoring position`, { pos });
|
|
63856
|
+
container.seek(pos);
|
|
63857
|
+
container.play();
|
|
63858
|
+
});
|
|
63859
|
+
}
|
|
63860
|
+
scheduleRefresh() {
|
|
63861
|
+
this.clearTimer();
|
|
63862
|
+
if (this.destroyed || !this.currentState)
|
|
63863
|
+
return;
|
|
63864
|
+
const leadMs = (this.opts.refreshLeadSeconds ?? 5) * 1000;
|
|
63865
|
+
const msUntilRefresh = this.currentState.expires * 1000 - Date.now() - leadMs;
|
|
63866
|
+
trace(`${T$1} next refresh in`, {
|
|
63867
|
+
seconds: Math.round(msUntilRefresh / 1000),
|
|
63868
|
+
expires: new Date(this.currentState.expires * 1000).toISOString(),
|
|
63869
|
+
});
|
|
63870
|
+
this.refreshTimer = setTimeout(() => this.performRefresh(), Math.max(msUntilRefresh, 1000));
|
|
63871
|
+
}
|
|
63872
|
+
async performRefresh() {
|
|
63873
|
+
trace(`${T$1} fetching new token`);
|
|
63874
|
+
try {
|
|
63875
|
+
const data = await this.opts.getToken();
|
|
63876
|
+
// Plugin may have been destroyed while getToken() was in flight; drop the result.
|
|
63877
|
+
if (this.destroyed)
|
|
63878
|
+
return;
|
|
63879
|
+
const newToken = this.opts.ipBound ? data.token_ip : data.token;
|
|
63880
|
+
const newState = { token: newToken, expires: data.expires };
|
|
63881
|
+
if (this.isNativePlayback) {
|
|
63882
|
+
// Must reload source because the <video> element has no request hook.
|
|
63883
|
+
await this.reloadNativeSource(data);
|
|
63884
|
+
}
|
|
63885
|
+
// originalState is never changed after init — it holds the token that was
|
|
63886
|
+
// baked into every URL in the initial manifest. hls.js/dash.js always
|
|
63887
|
+
// produces request URLs based on that manifest, so every segment URL
|
|
63888
|
+
// still contains the original token regardless of how many refreshes
|
|
63889
|
+
// have already happened. The loader replaces original→current on each
|
|
63890
|
+
// request, so updating only currentState is sufficient.
|
|
63891
|
+
this.currentState = newState;
|
|
63892
|
+
this.opts.onTokenRefreshed?.(data);
|
|
63893
|
+
trace(`${T$1} token refreshed`, {
|
|
63894
|
+
token: newToken.slice(0, 8) + '…',
|
|
63895
|
+
expires: new Date(data.expires * 1000).toISOString(),
|
|
63896
|
+
});
|
|
63897
|
+
}
|
|
63898
|
+
catch (err) {
|
|
63899
|
+
trace(`${T$1} token refresh failed`, { err });
|
|
63900
|
+
}
|
|
63901
|
+
// Always reschedule, even after an error (will retry near next expiry).
|
|
63902
|
+
this.scheduleRefresh();
|
|
63903
|
+
}
|
|
63904
|
+
get opts() {
|
|
63905
|
+
return this.options.tokenRefresh;
|
|
63906
|
+
}
|
|
63907
|
+
clearTimer() {
|
|
63908
|
+
if (this.refreshTimer !== null) {
|
|
63909
|
+
clearTimeout(this.refreshTimer);
|
|
63910
|
+
this.refreshTimer = null;
|
|
63911
|
+
}
|
|
63912
|
+
}
|
|
63913
|
+
}
|
|
63914
|
+
|
|
63689
63915
|
/**
|
|
63690
63916
|
* Events emitted by the VolumeFade plugin.
|
|
63691
63917
|
* @public
|
|
@@ -63794,4 +64020,4 @@ class VolumeFade extends UICorePlugin {
|
|
|
63794
64020
|
}
|
|
63795
64021
|
}
|
|
63796
64022
|
|
|
63797
|
-
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 };
|
|
64023
|
+
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 };
|