@gcorevideo/player 2.22.17 → 2.22.20
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/assets/audio-selector/track-selector.ejs +3 -3
- package/assets/bottom-gear/bottomgear.ejs +3 -3
- package/assets/clappr-nerd-stats/clappr-nerd-stats.ejs +76 -78
- package/assets/clappr-nerd-stats/clappr-nerd-stats.scss +10 -7
- package/assets/dvr-controls/dvr_controls.scss +0 -12
- package/dist/core.js +5 -7
- package/dist/index.css +1245 -1251
- package/dist/index.js +425 -261
- package/dist/player.d.ts +121 -108
- package/dist/plugins/index.css +577 -583
- package/dist/plugins/index.js +355 -187
- package/docs/api/player.bitratetrackrecord.md +20 -0
- package/docs/api/player.clapprstats.exportmetrics.md +2 -2
- package/docs/api/player.clapprstats.md +0 -4
- package/docs/api/player.clapprstatschronograph.md +115 -0
- package/docs/api/player.clapprstatscounter.md +211 -0
- package/docs/api/player.clapprstatsevents.md +51 -0
- package/docs/api/player.clapprstatsmetrics.md +52 -0
- package/docs/api/player.clipspluginsettings.md +1 -1
- package/docs/api/player.md +57 -2
- package/docs/api/player.nerdstats.md +3 -3
- package/docs/api/player.playerconfig.md +1 -1
- package/docs/api/player.playerconfig.playbacktype.md +6 -1
- package/docs/api/player.timeupdate.md +6 -3
- package/lib/playback/dash-playback/DashPlayback.d.ts +0 -1
- package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.js +4 -5
- 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 +0 -1
- package/lib/playback.types.d.ts +2 -3
- package/lib/playback.types.d.ts.map +1 -1
- package/lib/plugins/audio-selector/AudioSelector.d.ts +1 -1
- package/lib/plugins/audio-selector/AudioSelector.d.ts.map +1 -1
- package/lib/plugins/audio-selector/AudioSelector.js +15 -8
- package/lib/plugins/bottom-gear/BottomGear.d.ts +1 -1
- package/lib/plugins/bottom-gear/BottomGear.js +2 -2
- package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts +17 -14
- package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts.map +1 -1
- package/lib/plugins/clappr-nerd-stats/NerdStats.js +175 -124
- package/lib/plugins/clappr-nerd-stats/formatter.d.ts +5 -0
- package/lib/plugins/clappr-nerd-stats/formatter.d.ts.map +1 -1
- package/lib/plugins/clappr-nerd-stats/formatter.js +56 -24
- package/lib/plugins/clappr-nerd-stats/speedtest/index.d.ts +2 -2
- package/lib/plugins/clappr-nerd-stats/speedtest/index.d.ts.map +1 -1
- package/lib/plugins/clappr-nerd-stats/speedtest/types.d.ts +1 -1
- package/lib/plugins/clappr-nerd-stats/speedtest/types.d.ts.map +1 -1
- package/lib/plugins/clappr-nerd-stats/types.d.ts +3 -0
- package/lib/plugins/clappr-nerd-stats/types.d.ts.map +1 -1
- package/lib/plugins/clappr-nerd-stats/utils.d.ts +7 -0
- package/lib/plugins/clappr-nerd-stats/utils.d.ts.map +1 -0
- package/lib/plugins/clappr-nerd-stats/utils.js +67 -0
- package/lib/plugins/clappr-stats/ClapprStats.d.ts +5 -2
- package/lib/plugins/clappr-stats/ClapprStats.d.ts.map +1 -1
- package/lib/plugins/clappr-stats/ClapprStats.js +31 -33
- package/lib/plugins/clappr-stats/types.d.ts +21 -22
- package/lib/plugins/clappr-stats/types.d.ts.map +1 -1
- package/lib/plugins/clappr-stats/types.js +22 -22
- package/lib/plugins/clappr-stats/utils.d.ts +2 -2
- package/lib/plugins/clappr-stats/utils.d.ts.map +1 -1
- package/lib/plugins/clappr-stats/utils.js +0 -1
- package/lib/plugins/click-to-pause/ClickToPause.js +1 -1
- package/lib/plugins/clips/Clips.d.ts +1 -1
- package/lib/plugins/dvr-controls/DvrControls.d.ts +6 -2
- package/lib/plugins/dvr-controls/DvrControls.d.ts.map +1 -1
- package/lib/plugins/dvr-controls/DvrControls.js +39 -27
- package/lib/plugins/media-control/MediaControl.d.ts +6 -2
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +20 -9
- package/lib/plugins/picture-in-picture/PictureInPicture.js +1 -1
- package/lib/plugins/seek-time/SeekTime.d.ts +1 -1
- package/lib/plugins/seek-time/SeekTime.d.ts.map +1 -1
- package/lib/plugins/seek-time/SeekTime.js +3 -4
- package/lib/plugins/subtitles/ClosedCaptions.js +1 -1
- package/lib/plugins/vast-ads/VastAds.js +1 -1
- package/lib/plugins/vast-ads/rollmanager.js +1 -1
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +7 -4
- package/lib/types.d.ts +1 -1
- package/package.json +3 -3
- package/src/playback/__tests__/HTML5Video.test.ts +2 -2
- package/src/playback/dash-playback/DashPlayback.ts +5 -7
- package/src/playback/hls-playback/HlsPlayback.ts +2 -4
- package/src/playback.types.ts +2 -3
- package/src/plugins/audio-selector/AudioSelector.ts +14 -7
- package/src/plugins/audio-selector/__tests__/AudioSelector.test.ts +8 -8
- package/src/plugins/audio-selector/__tests__/__snapshots__/AudioSelector.test.ts.snap +15 -15
- package/src/plugins/bottom-gear/BottomGear.ts +2 -2
- package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +8 -5
- package/src/plugins/bottom-gear/__tests__/__snapshots__/BottomGear.test.ts.snap +3 -3
- package/src/plugins/clappr-nerd-stats/NerdStats.ts +216 -143
- package/src/plugins/clappr-nerd-stats/formatter.ts +91 -47
- package/src/plugins/clappr-nerd-stats/speedtest/index.ts +2 -2
- package/src/plugins/clappr-nerd-stats/speedtest/types.ts +1 -1
- package/src/plugins/clappr-nerd-stats/types.ts +43 -3
- package/src/plugins/clappr-nerd-stats/utils.ts +75 -0
- package/src/plugins/clappr-stats/ClapprStats.ts +41 -40
- package/src/plugins/clappr-stats/__tests__/ClapprStats.test.ts +12 -12
- package/src/plugins/clappr-stats/types.ts +43 -44
- package/src/plugins/clappr-stats/utils.ts +4 -5
- package/src/plugins/click-to-pause/ClickToPause.ts +1 -1
- package/src/plugins/clips/Clips.ts +1 -1
- package/src/plugins/clips/__tests__/Clips.test.ts +1 -1
- package/src/plugins/clips/__tests__/__snapshots__/Clips.test.ts.snap +1 -1
- package/src/plugins/dvr-controls/DvrControls.ts +51 -37
- package/src/plugins/dvr-controls/__tests__/DvrControls.test.ts +84 -26
- package/src/plugins/dvr-controls/__tests__/__snapshots__/DvrControls.test.ts.snap +0 -12
- package/src/plugins/media-control/MediaControl.ts +21 -9
- package/src/plugins/media-control/__tests__/MediaControl.test.ts +8 -5
- package/src/plugins/media-control/__tests__/__snapshots__/MediaControl.test.ts.snap +20 -20
- package/src/plugins/picture-in-picture/PictureInPicture.ts +1 -1
- package/src/plugins/seek-time/SeekTime.ts +4 -5
- package/src/plugins/subtitles/ClosedCaptions.ts +1 -1
- package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +1 -1
- package/src/plugins/vast-ads/VastAds.ts +1 -1
- package/src/plugins/vast-ads/rollmanager.ts +1 -1
- package/src/testUtils.ts +11 -5
- package/src/types.ts +1 -1
- package/temp/player.api.json +630 -12
- package/tsconfig.tsbuildinfo +1 -1
package/dist/index.js
CHANGED
|
@@ -12680,7 +12680,7 @@ var PlaybackEvents;
|
|
|
12680
12680
|
// https://github.com/clappr/clappr/blob/8752995ea439321ac7ca3cd35e8c64de7a3c3d17/LICENSE
|
|
12681
12681
|
const AUTO$1 = -1;
|
|
12682
12682
|
const { now: now$2 } = Utils;
|
|
12683
|
-
const T$
|
|
12683
|
+
const T$k = 'playback.dash';
|
|
12684
12684
|
class DashPlayback extends BasePlayback {
|
|
12685
12685
|
_levels = null;
|
|
12686
12686
|
_currentLevel = null;
|
|
@@ -12703,7 +12703,6 @@ class DashPlayback extends BasePlayback {
|
|
|
12703
12703
|
_playbackType = Playback.VOD;
|
|
12704
12704
|
// #EXT-X-PLAYLIST-TYPE
|
|
12705
12705
|
_playlistType = null;
|
|
12706
|
-
// #EXT-X-PROGRAM-DATE-TIME
|
|
12707
12706
|
_programDateTime = 0;
|
|
12708
12707
|
_dash = null;
|
|
12709
12708
|
_extrapolatedWindowDuration = 0;
|
|
@@ -12891,9 +12890,9 @@ class DashPlayback extends BasePlayback {
|
|
|
12891
12890
|
clearInterval(this._timeUpdateTimer);
|
|
12892
12891
|
}
|
|
12893
12892
|
}
|
|
12894
|
-
getProgramDateTime() {
|
|
12895
|
-
|
|
12896
|
-
}
|
|
12893
|
+
// getProgramDateTime() {
|
|
12894
|
+
// return this._programDateTime
|
|
12895
|
+
// }
|
|
12897
12896
|
// the duration on the video element itself should not be used
|
|
12898
12897
|
// as this does not necesarily represent the duration of the stream
|
|
12899
12898
|
// https://github.com/clappr/clappr/issues/668#issuecomment-157036678
|
|
@@ -12956,10 +12955,10 @@ class DashPlayback extends BasePlayback {
|
|
|
12956
12955
|
}
|
|
12957
12956
|
_onPlaybackError = (event) => {
|
|
12958
12957
|
// TODO
|
|
12959
|
-
trace(`${T$
|
|
12958
|
+
trace(`${T$k} _onPlaybackError`, { event });
|
|
12960
12959
|
};
|
|
12961
12960
|
_onDASHJSSError = (event) => {
|
|
12962
|
-
trace(`${T$
|
|
12961
|
+
trace(`${T$k} _onDASHJSSError`, { event });
|
|
12963
12962
|
this._stopTimeUpdateTimer();
|
|
12964
12963
|
// Note that the other error types are deprecated
|
|
12965
12964
|
const e = event.error;
|
|
@@ -12994,7 +12993,7 @@ class DashPlayback extends BasePlayback {
|
|
|
12994
12993
|
}
|
|
12995
12994
|
};
|
|
12996
12995
|
triggerError(error) {
|
|
12997
|
-
trace(`${T$
|
|
12996
|
+
trace(`${T$k} triggerError`, { error });
|
|
12998
12997
|
// this triggers Events.ERROR to be handled by the UI
|
|
12999
12998
|
this.trigger(Events$1.PLAYBACK_ERROR, this.createError(error, {
|
|
13000
12999
|
useCodePrefix: false,
|
|
@@ -13012,7 +13011,7 @@ class DashPlayback extends BasePlayback {
|
|
|
13012
13011
|
const update = {
|
|
13013
13012
|
current: this.getCurrentTime(),
|
|
13014
13013
|
total: this.getDuration(),
|
|
13015
|
-
firstFragDateTime: this.getProgramDateTime(),
|
|
13014
|
+
// firstFragDateTime: this.getProgramDateTime(), // TODO figure out if needed
|
|
13016
13015
|
};
|
|
13017
13016
|
const isSame = this._lastTimeUpdate &&
|
|
13018
13017
|
update.current === this._lastTimeUpdate.current &&
|
|
@@ -13033,10 +13032,10 @@ class DashPlayback extends BasePlayback {
|
|
|
13033
13032
|
}
|
|
13034
13033
|
get dvrEnabled() {
|
|
13035
13034
|
if (!this._dash) {
|
|
13036
|
-
trace(`${T$
|
|
13035
|
+
trace(`${T$k} dvrEnable no dash player instance`);
|
|
13037
13036
|
return false;
|
|
13038
13037
|
}
|
|
13039
|
-
trace(`${T$
|
|
13038
|
+
trace(`${T$k} get.dvrEnabled`, {
|
|
13040
13039
|
dvrWindowSize: this._dash?.getDVRWindowSize(),
|
|
13041
13040
|
minDvrSize: this._minDvrSize,
|
|
13042
13041
|
playbackType: this.getPlaybackType(),
|
|
@@ -13058,7 +13057,7 @@ class DashPlayback extends BasePlayback {
|
|
|
13058
13057
|
this.trigger(Events$1.PLAYBACK_PROGRESS, progress, {});
|
|
13059
13058
|
}
|
|
13060
13059
|
play() {
|
|
13061
|
-
trace(`${T$
|
|
13060
|
+
trace(`${T$k} play`, { dash: !!this._dash });
|
|
13062
13061
|
if (!this._dash) {
|
|
13063
13062
|
this._setup();
|
|
13064
13063
|
}
|
|
@@ -13144,7 +13143,7 @@ class DashPlayback extends BasePlayback {
|
|
|
13144
13143
|
}
|
|
13145
13144
|
// @ts-expect-error
|
|
13146
13145
|
get currentAudioTrack() {
|
|
13147
|
-
trace(`${T$
|
|
13146
|
+
trace(`${T$k} get currentAudioTrack`);
|
|
13148
13147
|
assert.ok(this._dash, 'DASH.js MediaPlayer is not initialized');
|
|
13149
13148
|
const t = this._dash.getCurrentTrackFor('audio');
|
|
13150
13149
|
if (!t) {
|
|
@@ -41845,7 +41844,7 @@ const AUTO = -1;
|
|
|
41845
41844
|
const DEFAULT_RECOVER_ATTEMPTS = 16;
|
|
41846
41845
|
Events$1.register('PLAYBACK_FRAGMENT_CHANGED');
|
|
41847
41846
|
Events$1.register('PLAYBACK_FRAGMENT_PARSING_METADATA');
|
|
41848
|
-
const T$
|
|
41847
|
+
const T$j = 'playback.hls';
|
|
41849
41848
|
class HlsPlayback extends BasePlayback {
|
|
41850
41849
|
_ccIsSetup = false;
|
|
41851
41850
|
_ccTracksUpdated = false;
|
|
@@ -42074,7 +42073,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
42074
42073
|
maxBufferLength: 2,
|
|
42075
42074
|
maxMaxBufferLength: 4,
|
|
42076
42075
|
}, this.options.playback.hlsjsConfig);
|
|
42077
|
-
trace(`${T$
|
|
42076
|
+
trace(`${T$j} _createHLSInstance`, { config });
|
|
42078
42077
|
this._hls = new Hls(config);
|
|
42079
42078
|
}
|
|
42080
42079
|
_attachHLSMedia() {
|
|
@@ -42165,7 +42164,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
42165
42164
|
}
|
|
42166
42165
|
else {
|
|
42167
42166
|
Log.error('hlsjs: failed to recover', { evt, data });
|
|
42168
|
-
trace(`${T$
|
|
42167
|
+
trace(`${T$j} _recover failed to recover`, {
|
|
42169
42168
|
type: data.type,
|
|
42170
42169
|
details: data.details,
|
|
42171
42170
|
});
|
|
@@ -42251,7 +42250,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
42251
42250
|
this.trigger(Events$1.PLAYBACK_SETTINGSUPDATE);
|
|
42252
42251
|
}
|
|
42253
42252
|
_onHLSJSError(evt, data) {
|
|
42254
|
-
trace(`${T$
|
|
42253
|
+
trace(`${T$j} _onHLSJSError`, {
|
|
42255
42254
|
fatal: data.fatal,
|
|
42256
42255
|
type: data.type,
|
|
42257
42256
|
details: data.details,
|
|
@@ -42299,7 +42298,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
42299
42298
|
evt,
|
|
42300
42299
|
data,
|
|
42301
42300
|
});
|
|
42302
|
-
trace(`${T$
|
|
42301
|
+
trace(`${T$j} _onHLSJSError trying to recover from network error`, {
|
|
42303
42302
|
details: data.details,
|
|
42304
42303
|
});
|
|
42305
42304
|
error.level = PlayerError.Levels.WARN;
|
|
@@ -42312,7 +42311,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
42312
42311
|
evt,
|
|
42313
42312
|
data,
|
|
42314
42313
|
});
|
|
42315
|
-
trace(`${T$
|
|
42314
|
+
trace(`${T$j} _onHLSJSError trying to recover from media error`, {
|
|
42316
42315
|
details: data.details,
|
|
42317
42316
|
});
|
|
42318
42317
|
error.level = PlayerError.Levels.WARN;
|
|
@@ -42342,7 +42341,7 @@ class HlsPlayback extends BasePlayback {
|
|
|
42342
42341
|
return;
|
|
42343
42342
|
}
|
|
42344
42343
|
Log.warn('hlsjs: non-fatal error occurred', { evt, data });
|
|
42345
|
-
trace(`${T$
|
|
42344
|
+
trace(`${T$j} _onHLSJSError non-fatal error occurred`, {
|
|
42346
42345
|
type: data.type,
|
|
42347
42346
|
details: data.details,
|
|
42348
42347
|
});
|
|
@@ -42359,7 +42358,6 @@ class HlsPlayback extends BasePlayback {
|
|
|
42359
42358
|
const update = {
|
|
42360
42359
|
current: this.getCurrentTime(),
|
|
42361
42360
|
total: this.getDuration(),
|
|
42362
|
-
firstFragDateTime: this.getProgramDateTime(),
|
|
42363
42361
|
};
|
|
42364
42362
|
const isSame = this._lastTimeUpdate &&
|
|
42365
42363
|
update.current === this._lastTimeUpdate.current &&
|
|
@@ -42677,11 +42675,11 @@ class HlsPlayback extends BasePlayback {
|
|
|
42677
42675
|
this._hls.audioTrack = Number(id); // TODO or find index by .id == id?
|
|
42678
42676
|
}
|
|
42679
42677
|
_onAudioTracksUpdated(_, data) {
|
|
42680
|
-
trace(`${T$
|
|
42678
|
+
trace(`${T$j} onAudioTracksUpdated`);
|
|
42681
42679
|
this.trigger(Events$1.PLAYBACK_AUDIO_AVAILABLE, data.audioTracks.map(toClapprTrack));
|
|
42682
42680
|
}
|
|
42683
42681
|
_onAudioTrackSwitched(_, data) {
|
|
42684
|
-
trace(`${T$
|
|
42682
|
+
trace(`${T$j} onAudioTrackSwitched`);
|
|
42685
42683
|
// @ts-ignore
|
|
42686
42684
|
const track = this._hls.audioTracks[data.id];
|
|
42687
42685
|
this.trigger(Events$1.PLAYBACK_AUDIO_CHANGED, toClapprTrack(track));
|
|
@@ -42702,7 +42700,7 @@ function toClapprTrack(t) {
|
|
|
42702
42700
|
};
|
|
42703
42701
|
}
|
|
42704
42702
|
|
|
42705
|
-
const T$
|
|
42703
|
+
const T$i = 'playback.html5_video';
|
|
42706
42704
|
const STALL_TIMEOUT = 15000;
|
|
42707
42705
|
class HTML5Video extends BasePlayback {
|
|
42708
42706
|
stallTimerId = null;
|
|
@@ -42710,7 +42708,7 @@ class HTML5Video extends BasePlayback {
|
|
|
42710
42708
|
* @internal
|
|
42711
42709
|
*/
|
|
42712
42710
|
createError(errorData, options) {
|
|
42713
|
-
trace(`${T$
|
|
42711
|
+
trace(`${T$i} createError`, {
|
|
42714
42712
|
errorData: { ...errorData },
|
|
42715
42713
|
});
|
|
42716
42714
|
const i18n = this.i18n ||
|
|
@@ -42726,11 +42724,11 @@ class HTML5Video extends BasePlayback {
|
|
|
42726
42724
|
return super.createError(errorData, { ...options, useCodePrefix: false });
|
|
42727
42725
|
}
|
|
42728
42726
|
_onWaiting() {
|
|
42729
|
-
trace(`${T$
|
|
42727
|
+
trace(`${T$i} _onWaiting`);
|
|
42730
42728
|
super._onWaiting();
|
|
42731
42729
|
}
|
|
42732
42730
|
_onEnded() {
|
|
42733
|
-
trace(`${T$
|
|
42731
|
+
trace(`${T$i} _onEnded`);
|
|
42734
42732
|
if (this.stallTimerId) {
|
|
42735
42733
|
clearTimeout(this.stallTimerId);
|
|
42736
42734
|
this.stallTimerId = null;
|
|
@@ -42738,12 +42736,12 @@ class HTML5Video extends BasePlayback {
|
|
|
42738
42736
|
super._onEnded();
|
|
42739
42737
|
}
|
|
42740
42738
|
_handleBufferingEvents() {
|
|
42741
|
-
trace(`${T$
|
|
42739
|
+
trace(`${T$i} _handleBufferingEvents`, {
|
|
42742
42740
|
networkState: this.el.networkState,
|
|
42743
42741
|
});
|
|
42744
42742
|
if (!this.stallTimerId) {
|
|
42745
42743
|
this.stallTimerId = setTimeout(() => {
|
|
42746
|
-
trace(`${T$
|
|
42744
|
+
trace(`${T$i} _handleBufferingEvents stall timeout`, {
|
|
42747
42745
|
buffering: this.buffering,
|
|
42748
42746
|
ended: this.ended,
|
|
42749
42747
|
});
|
|
@@ -42761,7 +42759,7 @@ class HTML5Video extends BasePlayback {
|
|
|
42761
42759
|
super._handleBufferingEvents();
|
|
42762
42760
|
}
|
|
42763
42761
|
_onPlaying() {
|
|
42764
|
-
trace(`${T$
|
|
42762
|
+
trace(`${T$i} _onPlaying`);
|
|
42765
42763
|
if (this.stallTimerId) {
|
|
42766
42764
|
clearTimeout(this.stallTimerId);
|
|
42767
42765
|
this.stallTimerId = null;
|
|
@@ -42769,7 +42767,7 @@ class HTML5Video extends BasePlayback {
|
|
|
42769
42767
|
super._onPlaying();
|
|
42770
42768
|
}
|
|
42771
42769
|
_onPause() {
|
|
42772
|
-
trace(`${T$
|
|
42770
|
+
trace(`${T$i} _onPause`);
|
|
42773
42771
|
super._onPause();
|
|
42774
42772
|
if (this.stallTimerId) {
|
|
42775
42773
|
clearTimeout(this.stallTimerId);
|
|
@@ -42779,7 +42777,7 @@ class HTML5Video extends BasePlayback {
|
|
|
42779
42777
|
get audioTracks() {
|
|
42780
42778
|
const tracks = this.el.audioTracks;
|
|
42781
42779
|
const supported = !!tracks;
|
|
42782
|
-
trace(`${T$
|
|
42780
|
+
trace(`${T$i} get audioTracks`, { supported });
|
|
42783
42781
|
const retval = [];
|
|
42784
42782
|
if (supported) {
|
|
42785
42783
|
for (let i = 0; i < tracks.length; i++) {
|
|
@@ -42798,7 +42796,7 @@ class HTML5Video extends BasePlayback {
|
|
|
42798
42796
|
get currentAudioTrack() {
|
|
42799
42797
|
const tracks = this.el.audioTracks;
|
|
42800
42798
|
const supported = !!tracks;
|
|
42801
|
-
trace(`${T$
|
|
42799
|
+
trace(`${T$i} get currentAudioTrack`, {
|
|
42802
42800
|
supported,
|
|
42803
42801
|
});
|
|
42804
42802
|
if (supported) {
|
|
@@ -42819,7 +42817,7 @@ class HTML5Video extends BasePlayback {
|
|
|
42819
42817
|
switchAudioTrack(id) {
|
|
42820
42818
|
const tracks = this.el.audioTracks;
|
|
42821
42819
|
const supported = !!tracks;
|
|
42822
|
-
trace(`${T$
|
|
42820
|
+
trace(`${T$i} switchAudioTrack`, {
|
|
42823
42821
|
supported,
|
|
42824
42822
|
});
|
|
42825
42823
|
if (supported) {
|
|
@@ -42838,7 +42836,7 @@ function registerPlaybacks() {
|
|
|
42838
42836
|
Loader.registerPlayback(DashPlayback);
|
|
42839
42837
|
}
|
|
42840
42838
|
|
|
42841
|
-
const T$
|
|
42839
|
+
const T$h = 'GPlayer';
|
|
42842
42840
|
const DEFAULT_OPTIONS = {
|
|
42843
42841
|
autoPlay: false,
|
|
42844
42842
|
debug: 'none',
|
|
@@ -42926,7 +42924,7 @@ class Player {
|
|
|
42926
42924
|
* ```
|
|
42927
42925
|
*/
|
|
42928
42926
|
attachTo(playerElement) {
|
|
42929
|
-
trace(`${T$
|
|
42927
|
+
trace(`${T$h} attachTo`, {
|
|
42930
42928
|
player: !!this.player,
|
|
42931
42929
|
});
|
|
42932
42930
|
assert.ok(!this.player, 'Player already initialized');
|
|
@@ -42936,7 +42934,7 @@ class Player {
|
|
|
42936
42934
|
}
|
|
42937
42935
|
const coreOpts = this.buildCoreOptions(playerElement);
|
|
42938
42936
|
const { core, container } = Player.getRegisteredPlugins();
|
|
42939
|
-
trace(`${T$
|
|
42937
|
+
trace(`${T$h} init`, {
|
|
42940
42938
|
registeredPlaybacks: Loader.registeredPlaybacks.map((p) => p.prototype.name),
|
|
42941
42939
|
});
|
|
42942
42940
|
coreOpts.plugins = {
|
|
@@ -42950,7 +42948,7 @@ class Player {
|
|
|
42950
42948
|
* Destroys the player, releasing all resources and unmounting its UI from the DOM.
|
|
42951
42949
|
*/
|
|
42952
42950
|
destroy() {
|
|
42953
|
-
trace(`${T$
|
|
42951
|
+
trace(`${T$h} destroy`, {
|
|
42954
42952
|
player: !!this.player,
|
|
42955
42953
|
});
|
|
42956
42954
|
if (this.player) {
|
|
@@ -43137,7 +43135,7 @@ class Player {
|
|
|
43137
43135
|
this.config = $.extend(true, this.config, config);
|
|
43138
43136
|
}
|
|
43139
43137
|
initPlayer(coreOptions) {
|
|
43140
|
-
trace(`${T$
|
|
43138
|
+
trace(`${T$h} initPlayer`, {
|
|
43141
43139
|
autoPlay: coreOptions.autoPlay,
|
|
43142
43140
|
sources: coreOptions.sources,
|
|
43143
43141
|
player: !!this.player,
|
|
@@ -43162,7 +43160,7 @@ class Player {
|
|
|
43162
43160
|
}
|
|
43163
43161
|
}
|
|
43164
43162
|
triggerAutoPlay() {
|
|
43165
|
-
trace(`${T$
|
|
43163
|
+
trace(`${T$h} triggerAutoPlay`);
|
|
43166
43164
|
setTimeout(() => {
|
|
43167
43165
|
this.player?.play({
|
|
43168
43166
|
autoPlay: true,
|
|
@@ -43180,7 +43178,7 @@ class Player {
|
|
|
43180
43178
|
// TODO test
|
|
43181
43179
|
events = {
|
|
43182
43180
|
onReady: () => {
|
|
43183
|
-
trace(`${T$
|
|
43181
|
+
trace(`${T$h} onReady`, {
|
|
43184
43182
|
ready: this.ready,
|
|
43185
43183
|
});
|
|
43186
43184
|
if (this.ready) {
|
|
@@ -43214,7 +43212,7 @@ class Player {
|
|
|
43214
43212
|
buildCoreOptions(rootNode) {
|
|
43215
43213
|
const sources = this.buildMediaSourcesList();
|
|
43216
43214
|
const source = sources[0];
|
|
43217
|
-
trace(`${T$
|
|
43215
|
+
trace(`${T$h} buildCoreOptions`, {
|
|
43218
43216
|
source,
|
|
43219
43217
|
sources,
|
|
43220
43218
|
});
|
|
@@ -43275,7 +43273,7 @@ class Player {
|
|
|
43275
43273
|
assert.ok(this.player, 'Player is not initialized');
|
|
43276
43274
|
const core = this.player.core;
|
|
43277
43275
|
core.on(Events$1.CORE_SCREEN_ORIENTATION_CHANGED, ({ orientation }) => {
|
|
43278
|
-
trace(`${T$
|
|
43276
|
+
trace(`${T$h} on CORE_SCREEN_ORIENTATION_CHANGED`, {
|
|
43279
43277
|
orientation,
|
|
43280
43278
|
rootNode: {
|
|
43281
43279
|
width: this.rootNode?.clientWidth,
|
|
@@ -43290,14 +43288,14 @@ class Player {
|
|
|
43290
43288
|
}
|
|
43291
43289
|
}, null);
|
|
43292
43290
|
core.on(Events$1.CORE_RESIZE, ({ width, height }) => {
|
|
43293
|
-
trace(`${T$
|
|
43291
|
+
trace(`${T$h} on CORE_RESIZE`, {
|
|
43294
43292
|
width,
|
|
43295
43293
|
height,
|
|
43296
43294
|
});
|
|
43297
43295
|
this.safeTriggerEvent(PlayerEvent.Resize, { width, height });
|
|
43298
43296
|
}, null);
|
|
43299
43297
|
core.on(Events$1.CORE_FULLSCREEN, (isFullscreen) => {
|
|
43300
|
-
trace(`${T$
|
|
43298
|
+
trace(`${T$h} CORE_FULLSCREEN`, {
|
|
43301
43299
|
isFullscreen,
|
|
43302
43300
|
});
|
|
43303
43301
|
this.safeTriggerEvent(PlayerEvent.Fullscreen, isFullscreen);
|
|
@@ -43305,7 +43303,7 @@ class Player {
|
|
|
43305
43303
|
}
|
|
43306
43304
|
}
|
|
43307
43305
|
|
|
43308
|
-
var version$1 = "2.22.
|
|
43306
|
+
var version$1 = "2.22.20";
|
|
43309
43307
|
|
|
43310
43308
|
var packages = {
|
|
43311
43309
|
"node_modules/@clappr/core": {
|
|
@@ -43329,10 +43327,11 @@ function version() {
|
|
|
43329
43327
|
};
|
|
43330
43328
|
}
|
|
43331
43329
|
|
|
43332
|
-
const pluginHtml$7 = "<button data-audiotracks-button class='gcore-skin-button-color' id=\"audiotracks-button\">\n <span class='audio-text'><%= title %></span> <span class=\"audio-arrow\"><%= icon %></span>\n</button>\n<ul class='gcore-skin-bg-color menu hidden' id=\"audiotracks-select\">\n <% for (const track of tracks) { %>\n <li>\n <a href=\"#\" class='gcore-skin-text-color' data-audiotracks-select=\"<%= track.id %>\">\n <%= track.label %>\n </a>\n </li>\n <% }; %>\n</ul>\n";
|
|
43330
|
+
const pluginHtml$7 = "<button data-audiotracks-button class='gcore-skin-button-color' id=\"audiotracks-button\" aria-haspopup=\"menu\" aria-expanded=\"false\">\n <span class='audio-text'><%= title %></span> <span class=\"audio-arrow\"><%= icon %></span>\n</button>\n<ul class='gcore-skin-bg-color menu hidden' id=\"audiotracks-select\" role=\"menu\">\n <% for (const track of tracks) { %>\n <li>\n <a href=\"#\" class='gcore-skin-text-color' data-audiotracks-select=\"<%= track.id %>\" role=\"menuitemradio\" aria-checked=\"<%= track.id === current %>\">\n <%= track.label %>\n </a>\n </li>\n <% }; %>\n</ul>\n";
|
|
43333
43331
|
|
|
43334
43332
|
const audioArrow = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg width=\"9px\" height=\"6px\" viewBox=\"0 0 9 6\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n <!-- Generator: Sketch 49 (51002) - http://www.bohemiancoding.com/sketch -->\n <title>quality-arrow</title>\n <desc>Created with Sketch.</desc>\n <defs></defs>\n <g id=\"quality-arrow\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path\n d=\"M5.07079194,5.78553848 C4.91457318,5.94277844 4.70551573,6.00941824 4.50028717,5.99893557 C4.2950586,6.00941824 4.08676693,5.94277844 3.92978239,5.78553848 L0.221118462,1.2997069 C-0.0737061539,1.00469478 -0.0737061539,0.526236029 0.221118462,0.231972666 C0.515177299,-0.0630394586 1.23500883,0.00734414472 1.64852907,0.00734414472 L7.77475484,0.00734414472 C8.21201421,0.00734414472 8.48539703,-0.0630394586 8.77945587,0.231972666 C9.07351471,0.526236029 9.07351471,1.00469478 8.77945587,1.2997069 L5.07079194,5.78553848 Z\"\n fill=\"#FFFFFE\"></path>\n </g>\n</svg>\n";
|
|
43335
43333
|
|
|
43334
|
+
// import { trace } from '@gcorevideo/utils'
|
|
43336
43335
|
const VERSION$7 = '2.22.4';
|
|
43337
43336
|
// const T = 'plugins.audiotracks'
|
|
43338
43337
|
/**
|
|
@@ -43395,7 +43394,7 @@ class AudioTracks extends UICorePlugin {
|
|
|
43395
43394
|
const mediaControl = this.core.getPlugin('media_control');
|
|
43396
43395
|
assert(mediaControl, 'media_control plugin is required');
|
|
43397
43396
|
this.listenTo(mediaControl, Events$1.MEDIACONTROL_RENDERED, () => {
|
|
43398
|
-
mediaControl.
|
|
43397
|
+
mediaControl.mount('audiotracks', this.$el);
|
|
43399
43398
|
});
|
|
43400
43399
|
this.listenTo(mediaControl, Events$1.MEDIACONTROL_HIDE, this.hideMenu);
|
|
43401
43400
|
}
|
|
@@ -43426,18 +43425,18 @@ class AudioTracks extends UICorePlugin {
|
|
|
43426
43425
|
if (!this.shouldRender()) {
|
|
43427
43426
|
return this;
|
|
43428
43427
|
}
|
|
43429
|
-
this.core.getPlugin('media_control');
|
|
43430
43428
|
this.$el.html(AudioTracks.template({
|
|
43431
43429
|
tracks: this.tracks,
|
|
43432
43430
|
title: this.getTitle(),
|
|
43433
43431
|
icon: audioArrow,
|
|
43432
|
+
current: this.currentTrack?.id,
|
|
43434
43433
|
}));
|
|
43435
43434
|
this.updateText();
|
|
43436
43435
|
this.highlightCurrentTrack();
|
|
43437
43436
|
return this;
|
|
43438
43437
|
}
|
|
43439
43438
|
onTrackSelect(event) {
|
|
43440
|
-
const id = event.
|
|
43439
|
+
const id = event.currentTarget?.dataset?.audiotracksSelect;
|
|
43441
43440
|
if (id) {
|
|
43442
43441
|
this.selectAudioTrack(id);
|
|
43443
43442
|
}
|
|
@@ -43446,7 +43445,7 @@ class AudioTracks extends UICorePlugin {
|
|
|
43446
43445
|
return false;
|
|
43447
43446
|
}
|
|
43448
43447
|
selectAudioTrack(id) {
|
|
43449
|
-
this.
|
|
43448
|
+
this.startTrackSwitching();
|
|
43450
43449
|
this.core.activeContainer.switchAudioTrack(id);
|
|
43451
43450
|
this.updateText();
|
|
43452
43451
|
}
|
|
@@ -43454,7 +43453,9 @@ class AudioTracks extends UICorePlugin {
|
|
|
43454
43453
|
this.$el.find('#audiotracks-select').addClass('hidden');
|
|
43455
43454
|
}
|
|
43456
43455
|
toggleContextMenu() {
|
|
43457
|
-
this.$el.find('#audiotracks-select').toggleClass('hidden');
|
|
43456
|
+
this.$el.find('#audiotracks-select').toggleClass('hidden'); // TODO use plain CSS display: none
|
|
43457
|
+
const open = !this.$el.find('#audiotracks-select').hasClass('hidden'); // TODO hold state
|
|
43458
|
+
this.$el.find('#audiotracks-button').attr('aria-expanded', open);
|
|
43458
43459
|
}
|
|
43459
43460
|
buttonElement() {
|
|
43460
43461
|
return this.$('button');
|
|
@@ -43472,7 +43473,7 @@ class AudioTracks extends UICorePlugin {
|
|
|
43472
43473
|
}
|
|
43473
43474
|
return this.currentTrack.label || this.currentTrack.language;
|
|
43474
43475
|
}
|
|
43475
|
-
|
|
43476
|
+
startTrackSwitching() {
|
|
43476
43477
|
this.buttonElement().addClass('changing');
|
|
43477
43478
|
}
|
|
43478
43479
|
updateText() {
|
|
@@ -43483,12 +43484,16 @@ class AudioTracks extends UICorePlugin {
|
|
|
43483
43484
|
}
|
|
43484
43485
|
highlightCurrentTrack() {
|
|
43485
43486
|
this.trackElement().removeClass('current');
|
|
43486
|
-
this.trackElement()
|
|
43487
|
+
this.trackElement()
|
|
43488
|
+
.find('a')
|
|
43489
|
+
.removeClass('gcore-skin-active')
|
|
43490
|
+
.attr('aria-checked', 'false');
|
|
43487
43491
|
if (this.currentTrack) {
|
|
43488
43492
|
this.trackElement(this.currentTrack.id)
|
|
43489
43493
|
.addClass('current')
|
|
43490
43494
|
.find('a')
|
|
43491
|
-
.addClass('gcore-skin-active')
|
|
43495
|
+
.addClass('gcore-skin-active')
|
|
43496
|
+
.attr('aria-checked', 'true');
|
|
43492
43497
|
}
|
|
43493
43498
|
}
|
|
43494
43499
|
}
|
|
@@ -43497,7 +43502,7 @@ const volumeOffIcon = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fil
|
|
|
43497
43502
|
|
|
43498
43503
|
const pluginHtml$6 = "<div class=\"big-mute-icon-wrapper\" data-big-mute>\n <div class=\"big-mute-icon gcore-skin-border-color\" data-big-mute-icon></div>\n</div>\n";
|
|
43499
43504
|
|
|
43500
|
-
const T$
|
|
43505
|
+
const T$g = 'plugins.big_mute_button';
|
|
43501
43506
|
// TODO rewrite as a container plugin
|
|
43502
43507
|
/**
|
|
43503
43508
|
* `PLUGIN` that displays a big mute button over the video when it's muted.
|
|
@@ -43538,7 +43543,7 @@ class BigMuteButton extends UICorePlugin {
|
|
|
43538
43543
|
this.listenTo(this.core, Events$1.CORE_READY, this.onCoreReady);
|
|
43539
43544
|
this.listenTo(this.core, 'core:advertisement:start', this.onStartAd);
|
|
43540
43545
|
this.listenTo(this.core, 'core:advertisement:finish', this.onFinishAd);
|
|
43541
|
-
trace(`${T$
|
|
43546
|
+
trace(`${T$g} bindEvents`, {
|
|
43542
43547
|
mediacontrol: !!this.core.mediaControl,
|
|
43543
43548
|
});
|
|
43544
43549
|
this.listenTo(this.core.mediaControl, Events$1.MEDIACONTROL_RENDERED, this.mediaControlRendered);
|
|
@@ -43563,12 +43568,12 @@ class BigMuteButton extends UICorePlugin {
|
|
|
43563
43568
|
}
|
|
43564
43569
|
mediaControlRendered() {
|
|
43565
43570
|
const container = this.core.activeContainer;
|
|
43566
|
-
trace(`${T$
|
|
43571
|
+
trace(`${T$g} mediaControlRendered`, {
|
|
43567
43572
|
container: !!container,
|
|
43568
43573
|
});
|
|
43569
43574
|
if (container) {
|
|
43570
43575
|
this.listenTo(container.playback, Events$1.PLAYBACK_PLAY, () => {
|
|
43571
|
-
trace(`${T$
|
|
43576
|
+
trace(`${T$g} PLAYBACK_PLAY`);
|
|
43572
43577
|
this.render();
|
|
43573
43578
|
});
|
|
43574
43579
|
}
|
|
@@ -43592,7 +43597,7 @@ class BigMuteButton extends UICorePlugin {
|
|
|
43592
43597
|
}
|
|
43593
43598
|
const { autoPlay, wasMuted } = this.options;
|
|
43594
43599
|
const volume = container.volume;
|
|
43595
|
-
trace(`${T$
|
|
43600
|
+
trace(`${T$g} shouldRender`, {
|
|
43596
43601
|
autoPlay,
|
|
43597
43602
|
wasMuted,
|
|
43598
43603
|
volume,
|
|
@@ -43604,7 +43609,7 @@ class BigMuteButton extends UICorePlugin {
|
|
|
43604
43609
|
*/
|
|
43605
43610
|
render() {
|
|
43606
43611
|
if (this.shouldRender()) {
|
|
43607
|
-
trace(`${T$
|
|
43612
|
+
trace(`${T$g} render`, {
|
|
43608
43613
|
el: !!this.$el,
|
|
43609
43614
|
});
|
|
43610
43615
|
this.$el.html(BigMuteButton.template());
|
|
@@ -43643,14 +43648,14 @@ class BigMuteButton extends UICorePlugin {
|
|
|
43643
43648
|
}
|
|
43644
43649
|
}
|
|
43645
43650
|
|
|
43646
|
-
const pluginHtml$5 = "<button
|
|
43651
|
+
const pluginHtml$5 = "<button class=\"media-control-button gplayer-lite-btn gcore-skin-button-color gear-icon\" id=\"gear-button\">\n <%= icon %>\n</button>\n<div class=\"gear-wrapper gcore-skin-bg-color\" id=\"gear-options-wrapper\" style=\"display:none\">\n <ul class=\"gear-options-list\" id=\"gear-options\" role=\"menu\"></ul>\n</div>\n";
|
|
43647
43652
|
|
|
43648
43653
|
const gearIcon = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <g clip-path=\"url(#clip0_660_1503)\">\n <path\n d=\"M19.14 12.94C19.18 12.64 19.2 12.33 19.2 12C19.2 11.68 19.18 11.36 19.13 11.06L21.16 9.47999C21.34 9.33999 21.39 9.06999 21.28 8.86999L19.36 5.54999C19.24 5.32999 18.99 5.25999 18.77 5.32999L16.38 6.28999C15.88 5.90999 15.35 5.58999 14.76 5.34999L14.4 2.80999C14.36 2.56999 14.16 2.39999 13.92 2.39999H10.08C9.83999 2.39999 9.64999 2.56999 9.60999 2.80999L9.24999 5.34999C8.65999 5.58999 8.11999 5.91999 7.62999 6.28999L5.23999 5.32999C5.01999 5.24999 4.76999 5.32999 4.64999 5.54999L2.73999 8.86999C2.61999 9.07999 2.65999 9.33999 2.85999 9.47999L4.88999 11.06C4.83999 11.36 4.79999 11.69 4.79999 12C4.79999 12.31 4.81999 12.64 4.86999 12.94L2.83999 14.52C2.65999 14.66 2.60999 14.93 2.71999 15.13L4.63999 18.45C4.75999 18.67 5.00999 18.74 5.22999 18.67L7.61999 17.71C8.11999 18.09 8.64999 18.41 9.23999 18.65L9.59999 21.19C9.64999 21.43 9.83999 21.6 10.08 21.6H13.92C14.16 21.6 14.36 21.43 14.39 21.19L14.75 18.65C15.34 18.41 15.88 18.09 16.37 17.71L18.76 18.67C18.98 18.75 19.23 18.67 19.35 18.45L21.27 15.13C21.39 14.91 21.34 14.66 21.15 14.52L19.14 12.94ZM12 15.6C10.02 15.6 8.39999 13.98 8.39999 12C8.39999 10.02 10.02 8.39999 12 8.39999C13.98 8.39999 15.6 10.02 15.6 12C15.6 13.98 13.98 15.6 12 15.6Z\"\n fill=\"#C9C9C9\"/>\n </g>\n <defs>\n <clipPath id=\"clip0_660_1503\">\n <rect width=\"24\" height=\"24\" fill=\"white\"/>\n </clipPath>\n </defs>\n</svg>\n";
|
|
43649
43654
|
|
|
43650
43655
|
const gearHdIcon = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <g clip-path=\"url(#clip0_28_1567)\">\n <path\n d=\"M19.14 12.94C19.18 12.64 19.2 12.33 19.2 12C19.2 11.68 19.18 11.36 19.13 11.06L21.16 9.47999C21.34 9.33999 21.39 9.06999 21.28 8.86999L19.36 5.54999C19.24 5.32999 18.99 5.25999 18.77 5.32999L16.38 6.28999C15.88 5.90999 15.35 5.58999 14.76 5.34999L14.4 2.80999C14.36 2.56999 14.16 2.39999 13.92 2.39999H10.08C9.83999 2.39999 9.64999 2.56999 9.60999 2.80999L9.24999 5.34999C8.65999 5.58999 8.11999 5.91999 7.62999 6.28999L5.23999 5.32999C5.01999 5.24999 4.76999 5.32999 4.64999 5.54999L2.73999 8.86999C2.61999 9.07999 2.65999 9.33999 2.85999 9.47999L4.88999 11.06C4.83999 11.36 4.79999 11.69 4.79999 12C4.79999 12.31 4.81999 12.64 4.86999 12.94L2.83999 14.52C2.65999 14.66 2.60999 14.93 2.71999 15.13L4.63999 18.45C4.75999 18.67 5.00999 18.74 5.22999 18.67L7.61999 17.71C8.11999 18.09 8.64999 18.41 9.23999 18.65L9.59999 21.19C9.64999 21.43 9.83999 21.6 10.08 21.6H13.92C14.16 21.6 14.36 21.43 14.39 21.19L14.75 18.65C15.34 18.41 15.88 18.09 16.37 17.71L18.76 18.67C18.98 18.75 19.23 18.67 19.35 18.45L21.27 15.13C21.39 14.91 21.34 14.66 21.15 14.52L19.14 12.94ZM12 15.6C10.02 15.6 8.39999 13.98 8.39999 12C8.39999 10.02 10.02 8.39999 12 8.39999C13.98 8.39999 15.6 10.02 15.6 12C15.6 13.98 13.98 15.6 12 15.6Z\"\n fill=\"#C9C9C9\"/>\n <rect x=\"13\" width=\"11\" height=\"7\" rx=\"1\" fill=\"#F6413B\"/>\n <path\n d=\"M14.6962 6V1.63636H15.3546V3.53267H17.53V1.63636H18.1905V6H17.53V4.0973H15.3546V6H14.6962ZM20.562 6H19.1493V1.63636H20.6067C21.0343 1.63636 21.4015 1.72372 21.7083 1.89844C22.0151 2.07173 22.2502 2.32102 22.4135 2.64631C22.5783 2.97017 22.6607 3.35866 22.6607 3.81179C22.6607 4.26634 22.5776 4.65696 22.4114 4.98366C22.2466 5.31037 22.008 5.56179 21.6955 5.73793C21.383 5.91264 21.0051 6 20.562 6ZM19.8077 5.42472H20.5257C20.8581 5.42472 21.1344 5.36222 21.3546 5.23722C21.5748 5.1108 21.7395 4.92827 21.8489 4.68963C21.9583 4.44957 22.013 4.15696 22.013 3.81179C22.013 3.46946 21.9583 3.17898 21.8489 2.94034C21.7409 2.7017 21.5797 2.5206 21.3652 2.39702C21.1507 2.27344 20.8844 2.21165 20.5662 2.21165H19.8077V5.42472Z\"\n fill=\"#C9C9C9\"/>\n </g>\n <defs>\n <clipPath id=\"clip0_28_1567\">\n <rect width=\"24\" height=\"24\" fill=\"white\"/>\n </clipPath>\n </defs>\n</svg>\n";
|
|
43651
43656
|
|
|
43652
43657
|
const VERSION$6 = '2.19.12';
|
|
43653
|
-
const T$
|
|
43658
|
+
const T$f = 'plugins.bottom_gear';
|
|
43654
43659
|
/**
|
|
43655
43660
|
* Events triggered by the plugin
|
|
43656
43661
|
* @beta
|
|
@@ -43658,7 +43663,7 @@ const T$g = 'plugins.bottom_gear';
|
|
|
43658
43663
|
var GearEvents;
|
|
43659
43664
|
(function (GearEvents) {
|
|
43660
43665
|
/**
|
|
43661
|
-
*
|
|
43666
|
+
* Subscribe to this event to accurately attach an item to the gear menu
|
|
43662
43667
|
*/
|
|
43663
43668
|
GearEvents["RENDERED"] = "rendered";
|
|
43664
43669
|
})(GearEvents || (GearEvents = {}));
|
|
@@ -43800,20 +43805,20 @@ class BottomGear extends UICorePlugin {
|
|
|
43800
43805
|
addItem(name, $subMenu) {
|
|
43801
43806
|
const $existingItem = this.$el.find(`#gear-options li[data-${name}`);
|
|
43802
43807
|
if ($existingItem.length) {
|
|
43803
|
-
trace(`${T$
|
|
43808
|
+
trace(`${T$f} addItem already exists`, { name });
|
|
43804
43809
|
return $existingItem;
|
|
43805
43810
|
}
|
|
43806
43811
|
const $item = $('<li></li>')
|
|
43807
43812
|
.attr(`data-${name}`, '')
|
|
43808
43813
|
.appendTo(this.$el.find('#gear-options'));
|
|
43809
43814
|
if ($subMenu) {
|
|
43810
|
-
trace(`${T$
|
|
43815
|
+
trace(`${T$f} addItem adding submenu`, { name });
|
|
43811
43816
|
$subMenu
|
|
43812
43817
|
.addClass('gear-sub-menu-wrapper')
|
|
43813
43818
|
.hide()
|
|
43814
43819
|
.appendTo(this.$el.find('#gear-options-wrapper'));
|
|
43815
43820
|
$item.on('click', (e) => {
|
|
43816
|
-
trace(`${T$
|
|
43821
|
+
trace(`${T$f} addItem submenu clicked`, { name });
|
|
43817
43822
|
e.stopPropagation();
|
|
43818
43823
|
$subMenu.show();
|
|
43819
43824
|
this.$el.find('#gear-options').hide();
|
|
@@ -43822,15 +43827,15 @@ class BottomGear extends UICorePlugin {
|
|
|
43822
43827
|
return $item;
|
|
43823
43828
|
}
|
|
43824
43829
|
onActiveContainerChanged() {
|
|
43825
|
-
trace(`${T$
|
|
43830
|
+
trace(`${T$f} onActiveContainerChanged`);
|
|
43826
43831
|
this.bindContainerEvents();
|
|
43827
43832
|
}
|
|
43828
43833
|
bindContainerEvents() {
|
|
43829
|
-
trace(`${T$
|
|
43834
|
+
trace(`${T$f} bindContainerEvents`);
|
|
43830
43835
|
this.listenTo(this.core.activeContainer, Events$1.CONTAINER_HIGHDEFINITIONUPDATE, this.highDefinitionUpdate);
|
|
43831
43836
|
}
|
|
43832
43837
|
highDefinitionUpdate(isHd) {
|
|
43833
|
-
trace(`${T$
|
|
43838
|
+
trace(`${T$f} highDefinitionUpdate`, { isHd });
|
|
43834
43839
|
this.isHd = isHd;
|
|
43835
43840
|
this.$el.find('.gear-icon').html(isHd ? gearHdIcon : gearIcon);
|
|
43836
43841
|
}
|
|
@@ -43838,7 +43843,7 @@ class BottomGear extends UICorePlugin {
|
|
|
43838
43843
|
* @internal
|
|
43839
43844
|
*/
|
|
43840
43845
|
render() {
|
|
43841
|
-
trace(`${T$
|
|
43846
|
+
trace(`${T$f} render`);
|
|
43842
43847
|
const mediaControl = this.core.getPlugin('media_control');
|
|
43843
43848
|
if (!mediaControl) {
|
|
43844
43849
|
return this; // TODO test
|
|
@@ -43870,48 +43875,48 @@ class BottomGear extends UICorePlugin {
|
|
|
43870
43875
|
this.$el.find('#gear-options-wrapper').hide();
|
|
43871
43876
|
}
|
|
43872
43877
|
onCoreReady() {
|
|
43873
|
-
trace(`${T$
|
|
43878
|
+
trace(`${T$f} onCoreReady`);
|
|
43874
43879
|
const mediaControl = this.core.getPlugin('media_control');
|
|
43875
43880
|
assert(mediaControl, 'media_control plugin is required');
|
|
43876
43881
|
this.listenTo(mediaControl, Events$1.MEDIACONTROL_RENDERED, this.onMediaControlRendered);
|
|
43877
43882
|
this.listenTo(mediaControl, Events$1.MEDIACONTROL_HIDE, this.hide);
|
|
43878
43883
|
}
|
|
43879
43884
|
onMediaControlRendered() {
|
|
43880
|
-
trace(`${T$
|
|
43885
|
+
trace(`${T$f} onMediaControlRendered`);
|
|
43881
43886
|
const mediaControl = this.core.getPlugin('media_control');
|
|
43882
|
-
mediaControl.
|
|
43887
|
+
mediaControl.mount('gear', this.$el);
|
|
43883
43888
|
}
|
|
43884
43889
|
}
|
|
43885
43890
|
|
|
43886
43891
|
/**
|
|
43887
43892
|
* @beta
|
|
43888
43893
|
*/
|
|
43889
|
-
var
|
|
43890
|
-
(function (
|
|
43891
|
-
|
|
43892
|
-
|
|
43893
|
-
|
|
43894
|
-
|
|
43895
|
-
|
|
43894
|
+
var ClapprStatsChronograph;
|
|
43895
|
+
(function (ClapprStatsChronograph) {
|
|
43896
|
+
ClapprStatsChronograph["Startup"] = "startup";
|
|
43897
|
+
ClapprStatsChronograph["Watch"] = "watch";
|
|
43898
|
+
ClapprStatsChronograph["Pause"] = "pause";
|
|
43899
|
+
ClapprStatsChronograph["Buffering"] = "buffering";
|
|
43900
|
+
ClapprStatsChronograph["Session"] = "session";
|
|
43896
43901
|
// Latency = 'latency',
|
|
43897
|
-
})(
|
|
43902
|
+
})(ClapprStatsChronograph || (ClapprStatsChronograph = {}));
|
|
43898
43903
|
/**
|
|
43899
43904
|
* @beta
|
|
43900
43905
|
*/
|
|
43901
|
-
var
|
|
43902
|
-
(function (
|
|
43903
|
-
|
|
43904
|
-
|
|
43905
|
-
|
|
43906
|
-
|
|
43907
|
-
|
|
43908
|
-
|
|
43909
|
-
|
|
43910
|
-
|
|
43911
|
-
|
|
43912
|
-
|
|
43913
|
-
|
|
43914
|
-
})(
|
|
43906
|
+
var ClapprStatsCounter;
|
|
43907
|
+
(function (ClapprStatsCounter) {
|
|
43908
|
+
ClapprStatsCounter["Play"] = "play";
|
|
43909
|
+
ClapprStatsCounter["Pause"] = "pause";
|
|
43910
|
+
ClapprStatsCounter["Error"] = "error";
|
|
43911
|
+
ClapprStatsCounter["Buffering"] = "buffering";
|
|
43912
|
+
ClapprStatsCounter["DecodedFrames"] = "decodedFrames";
|
|
43913
|
+
ClapprStatsCounter["DroppedFrames"] = "droppedFrames";
|
|
43914
|
+
ClapprStatsCounter["Fps"] = "fps";
|
|
43915
|
+
ClapprStatsCounter["ChangeLevel"] = "changeLevel";
|
|
43916
|
+
ClapprStatsCounter["Seek"] = "seek";
|
|
43917
|
+
ClapprStatsCounter["Fullscreen"] = "fullscreen";
|
|
43918
|
+
ClapprStatsCounter["DvrUsage"] = "dvrUsage";
|
|
43919
|
+
})(ClapprStatsCounter || (ClapprStatsCounter = {}));
|
|
43915
43920
|
/**
|
|
43916
43921
|
* @beta
|
|
43917
43922
|
*/
|
|
@@ -43963,7 +43968,6 @@ function newMetrics$1() {
|
|
|
43963
43968
|
duration: 0,
|
|
43964
43969
|
currentTime: 0,
|
|
43965
43970
|
},
|
|
43966
|
-
custom: {},
|
|
43967
43971
|
};
|
|
43968
43972
|
}
|
|
43969
43973
|
|
|
@@ -43973,6 +43977,8 @@ function newMetrics$1() {
|
|
|
43973
43977
|
* @remarks
|
|
43974
43978
|
* This plugin does not render anything and is supposed to be extended or used together with other plugins that actually render something.
|
|
43975
43979
|
*
|
|
43980
|
+
* @see {@link NerdStats} - a plugin that visualises the playback metrics
|
|
43981
|
+
*
|
|
43976
43982
|
* Configuration options - {@link ClapprStatsSettings}
|
|
43977
43983
|
*
|
|
43978
43984
|
* Events - {@link ClapprStatsEvents}
|
|
@@ -43982,11 +43988,11 @@ class ClapprStats extends ContainerPlugin {
|
|
|
43982
43988
|
lastDecodedFramesCount = 0;
|
|
43983
43989
|
metrics = newMetrics$1();
|
|
43984
43990
|
timers = {
|
|
43985
|
-
[
|
|
43986
|
-
[
|
|
43987
|
-
[
|
|
43988
|
-
[
|
|
43989
|
-
[
|
|
43991
|
+
[ClapprStatsChronograph.Startup]: 0,
|
|
43992
|
+
[ClapprStatsChronograph.Watch]: 0,
|
|
43993
|
+
[ClapprStatsChronograph.Pause]: 0,
|
|
43994
|
+
[ClapprStatsChronograph.Buffering]: 0,
|
|
43995
|
+
[ClapprStatsChronograph.Session]: 0,
|
|
43990
43996
|
};
|
|
43991
43997
|
runEach;
|
|
43992
43998
|
/**
|
|
@@ -44016,15 +44022,10 @@ class ClapprStats extends ContainerPlugin {
|
|
|
44016
44022
|
inc(counter) {
|
|
44017
44023
|
this.metrics.counters[counter] += 1;
|
|
44018
44024
|
}
|
|
44019
|
-
// _timerHasStarted(timer) {
|
|
44020
|
-
// return this[`_start${timer}`] !== undefined;
|
|
44021
|
-
// }
|
|
44022
44025
|
start(timer) {
|
|
44023
|
-
// this[`_start${timer}`] = this._now();
|
|
44024
44026
|
this.timers[timer] = this.now();
|
|
44025
44027
|
}
|
|
44026
44028
|
stop(timer) {
|
|
44027
|
-
// this._metrics.timers[timer] += this._now() - this[`_start${timer}`];
|
|
44028
44029
|
this.metrics.chrono[timer] += this.now() - this.timers[timer];
|
|
44029
44030
|
}
|
|
44030
44031
|
constructor(container) {
|
|
@@ -44044,10 +44045,10 @@ class ClapprStats extends ContainerPlugin {
|
|
|
44044
44045
|
this.listenTo(this.container, Events$1.CONTAINER_PAUSE, this.onPause);
|
|
44045
44046
|
this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERING, this.onBuffering);
|
|
44046
44047
|
this.listenTo(this.container, Events$1.CONTAINER_SEEK, this.onSeek);
|
|
44047
|
-
this.listenTo(this.container, Events$1.CONTAINER_ERROR, () => this.inc(
|
|
44048
|
-
this.listenTo(this.container, Events$1.CONTAINER_FULLSCREEN, () => this.inc(
|
|
44048
|
+
this.listenTo(this.container, Events$1.CONTAINER_ERROR, () => this.inc(ClapprStatsCounter.Error));
|
|
44049
|
+
this.listenTo(this.container, Events$1.CONTAINER_FULLSCREEN, () => this.inc(ClapprStatsCounter.Fullscreen));
|
|
44049
44050
|
this.listenTo(this.container, Events$1.CONTAINER_PLAYBACKDVRSTATECHANGED, (dvrInUse) => {
|
|
44050
|
-
dvrInUse && this.inc(
|
|
44051
|
+
dvrInUse && this.inc(ClapprStatsCounter.DvrUsage);
|
|
44051
44052
|
});
|
|
44052
44053
|
this.listenTo(this.container.playback, Events$1.PLAYBACK_PROGRESS, this.onProgress);
|
|
44053
44054
|
this.listenTo(this.container.playback, Events$1.PLAYBACK_TIMEUPDATE, this.onTimeUpdate);
|
|
@@ -44075,7 +44076,7 @@ class ClapprStats extends ContainerPlugin {
|
|
|
44075
44076
|
last.time = now - last.start;
|
|
44076
44077
|
}
|
|
44077
44078
|
this.metrics.extra.bitratesHistory.push({ start: this.now(), bitrate });
|
|
44078
|
-
this.inc(
|
|
44079
|
+
this.inc(ClapprStatsCounter.ChangeLevel);
|
|
44079
44080
|
}
|
|
44080
44081
|
stopReporting() {
|
|
44081
44082
|
this.buildReport();
|
|
@@ -44086,31 +44087,31 @@ class ClapprStats extends ContainerPlugin {
|
|
|
44086
44087
|
}
|
|
44087
44088
|
startTimers() {
|
|
44088
44089
|
this.timerId = setInterval(this.buildReport.bind(this), this.runEach);
|
|
44089
|
-
this.start(
|
|
44090
|
-
this.start(
|
|
44090
|
+
this.start(ClapprStatsChronograph.Session);
|
|
44091
|
+
this.start(ClapprStatsChronograph.Startup);
|
|
44091
44092
|
}
|
|
44092
44093
|
onFirstPlaying() {
|
|
44093
44094
|
this.listenTo(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
44094
|
-
this.start(
|
|
44095
|
-
this.stop(
|
|
44095
|
+
this.start(ClapprStatsChronograph.Watch);
|
|
44096
|
+
this.stop(ClapprStatsChronograph.Startup);
|
|
44096
44097
|
}
|
|
44097
44098
|
playAfterPause() {
|
|
44098
44099
|
this.listenTo(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
44099
|
-
this.stop(
|
|
44100
|
-
this.start(
|
|
44100
|
+
this.stop(ClapprStatsChronograph.Pause);
|
|
44101
|
+
this.start(ClapprStatsChronograph.Watch);
|
|
44101
44102
|
}
|
|
44102
44103
|
onPlay() {
|
|
44103
|
-
this.inc(
|
|
44104
|
+
this.inc(ClapprStatsCounter.Play);
|
|
44104
44105
|
}
|
|
44105
44106
|
onPause() {
|
|
44106
|
-
this.stop(
|
|
44107
|
-
this.start(
|
|
44108
|
-
this.inc(
|
|
44107
|
+
this.stop(ClapprStatsChronograph.Watch);
|
|
44108
|
+
this.start(ClapprStatsChronograph.Pause);
|
|
44109
|
+
this.inc(ClapprStatsCounter.Pause);
|
|
44109
44110
|
this.listenToOnce(this.container, Events$1.CONTAINER_PLAY, this.playAfterPause);
|
|
44110
44111
|
this.stopListening(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
44111
44112
|
}
|
|
44112
44113
|
onSeek(e) {
|
|
44113
|
-
this.inc(
|
|
44114
|
+
this.inc(ClapprStatsCounter.Seek);
|
|
44114
44115
|
this.metrics.extra.watchHistory.push([e * 1000, e * 1000]);
|
|
44115
44116
|
}
|
|
44116
44117
|
onTimeUpdate(e) {
|
|
@@ -44135,17 +44136,17 @@ class ClapprStats extends ContainerPlugin {
|
|
|
44135
44136
|
}
|
|
44136
44137
|
onContainerUpdateWhilePlaying() {
|
|
44137
44138
|
if (this.container.playback.isPlaying()) {
|
|
44138
|
-
this.stop(
|
|
44139
|
-
this.start(
|
|
44139
|
+
this.stop(ClapprStatsChronograph.Watch);
|
|
44140
|
+
this.start(ClapprStatsChronograph.Watch);
|
|
44140
44141
|
}
|
|
44141
44142
|
}
|
|
44142
44143
|
onBuffering() {
|
|
44143
|
-
this.inc(
|
|
44144
|
-
this.start(
|
|
44144
|
+
this.inc(ClapprStatsCounter.Buffering);
|
|
44145
|
+
this.start(ClapprStatsChronograph.Buffering);
|
|
44145
44146
|
this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERFULL, this.onBufferfull);
|
|
44146
44147
|
}
|
|
44147
44148
|
onBufferfull() {
|
|
44148
|
-
this.stop(
|
|
44149
|
+
this.stop(ClapprStatsChronograph.Buffering);
|
|
44149
44150
|
this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERING, this.onBuffering);
|
|
44150
44151
|
}
|
|
44151
44152
|
onProgress(progress) {
|
|
@@ -44157,8 +44158,8 @@ class ClapprStats extends ContainerPlugin {
|
|
|
44157
44158
|
// this.trigger(ClapprStatsEvents.PERCENTAGE, currentPercentage);
|
|
44158
44159
|
}
|
|
44159
44160
|
buildReport() {
|
|
44160
|
-
this.stop(
|
|
44161
|
-
this.start(
|
|
44161
|
+
this.stop(ClapprStatsChronograph.Session);
|
|
44162
|
+
this.start(ClapprStatsChronograph.Session);
|
|
44162
44163
|
this.metrics.extra.playbackName = this.playbackName;
|
|
44163
44164
|
this.metrics.extra.playbackType = this.playbackType;
|
|
44164
44165
|
this.calcBitrates();
|
|
@@ -45657,63 +45658,72 @@ const timeScale = new humanFormat.Scale({
|
|
|
45657
45658
|
ms: 1,
|
|
45658
45659
|
sec: 1000,
|
|
45659
45660
|
min: 60000,
|
|
45660
|
-
hours: 3600000
|
|
45661
|
+
hours: 3600000,
|
|
45661
45662
|
});
|
|
45662
45663
|
const percentScale = new humanFormat.Scale({
|
|
45663
|
-
'%': 1
|
|
45664
|
+
'%': 1,
|
|
45664
45665
|
});
|
|
45666
|
+
const metricTemplates = {
|
|
45667
|
+
fps: {
|
|
45668
|
+
scale: 'SI',
|
|
45669
|
+
decimals: 0,
|
|
45670
|
+
},
|
|
45671
|
+
volume: {
|
|
45672
|
+
scale: percentScale,
|
|
45673
|
+
},
|
|
45674
|
+
};
|
|
45665
45675
|
const formattingTemplate = {
|
|
45666
45676
|
general: {
|
|
45667
45677
|
volume: {
|
|
45668
|
-
scale: percentScale
|
|
45669
|
-
}
|
|
45678
|
+
scale: percentScale,
|
|
45679
|
+
},
|
|
45670
45680
|
},
|
|
45671
45681
|
timers: {
|
|
45672
45682
|
startup: {
|
|
45673
|
-
scale: timeScale
|
|
45683
|
+
scale: timeScale,
|
|
45674
45684
|
},
|
|
45675
45685
|
watch: {
|
|
45676
|
-
scale: timeScale
|
|
45686
|
+
scale: timeScale,
|
|
45677
45687
|
},
|
|
45678
45688
|
pause: {
|
|
45679
|
-
scale: timeScale
|
|
45689
|
+
scale: timeScale,
|
|
45680
45690
|
},
|
|
45681
45691
|
buffering: {
|
|
45682
|
-
scale: timeScale
|
|
45692
|
+
scale: timeScale,
|
|
45683
45693
|
},
|
|
45684
45694
|
session: {
|
|
45685
|
-
scale: timeScale
|
|
45695
|
+
scale: timeScale,
|
|
45686
45696
|
},
|
|
45687
45697
|
latency: {
|
|
45688
|
-
scale: timeScale
|
|
45689
|
-
}
|
|
45698
|
+
scale: timeScale,
|
|
45699
|
+
},
|
|
45690
45700
|
},
|
|
45691
45701
|
extra: {
|
|
45692
45702
|
buffersize: {
|
|
45693
|
-
scale: timeScale
|
|
45703
|
+
scale: timeScale,
|
|
45694
45704
|
},
|
|
45695
45705
|
duration: {
|
|
45696
|
-
scale: timeScale
|
|
45706
|
+
scale: timeScale,
|
|
45697
45707
|
},
|
|
45698
45708
|
currentTime: {
|
|
45699
|
-
scale: timeScale
|
|
45709
|
+
scale: timeScale,
|
|
45700
45710
|
},
|
|
45701
45711
|
bitrateWeightedMean: {
|
|
45702
|
-
unit: 'bps'
|
|
45712
|
+
unit: 'bps',
|
|
45703
45713
|
},
|
|
45704
45714
|
bitrateMostUsed: {
|
|
45705
|
-
unit: 'bps'
|
|
45715
|
+
unit: 'bps',
|
|
45706
45716
|
},
|
|
45707
45717
|
bandwidth: {
|
|
45708
|
-
unit: 'bps'
|
|
45718
|
+
unit: 'bps',
|
|
45709
45719
|
},
|
|
45710
45720
|
watchedPercentage: {
|
|
45711
|
-
scale: percentScale
|
|
45721
|
+
scale: percentScale,
|
|
45712
45722
|
},
|
|
45713
45723
|
bufferingPercentage: {
|
|
45714
|
-
scale: percentScale
|
|
45715
|
-
}
|
|
45716
|
-
}
|
|
45724
|
+
scale: percentScale,
|
|
45725
|
+
},
|
|
45726
|
+
},
|
|
45717
45727
|
};
|
|
45718
45728
|
class Formatter {
|
|
45719
45729
|
static format(metrics) {
|
|
@@ -45723,8 +45733,10 @@ class Formatter {
|
|
|
45723
45733
|
formattedMetrics[type] = fmt;
|
|
45724
45734
|
const typeTemplate = formattingTemplate[type];
|
|
45725
45735
|
Object.entries(mm).forEach(([name, value]) => {
|
|
45726
|
-
|
|
45727
|
-
|
|
45736
|
+
if (typeTemplate &&
|
|
45737
|
+
typeTemplate[name] &&
|
|
45738
|
+
typeof value === 'number' &&
|
|
45739
|
+
!isNaN(value)) {
|
|
45728
45740
|
// @ts-ignore
|
|
45729
45741
|
const templateScale = typeTemplate[name].scale || 'SI';
|
|
45730
45742
|
// @ts-ignore
|
|
@@ -45732,7 +45744,7 @@ class Formatter {
|
|
|
45732
45744
|
fmt[name] = humanFormat(value, {
|
|
45733
45745
|
scale: templateScale,
|
|
45734
45746
|
unit: templateUnit,
|
|
45735
|
-
decimals: 2
|
|
45747
|
+
decimals: 2,
|
|
45736
45748
|
});
|
|
45737
45749
|
}
|
|
45738
45750
|
else {
|
|
@@ -45742,6 +45754,27 @@ class Formatter {
|
|
|
45742
45754
|
});
|
|
45743
45755
|
return formattedMetrics;
|
|
45744
45756
|
}
|
|
45757
|
+
static formatVolume(volume) {
|
|
45758
|
+
return humanFormat(volume, metricTemplates.volume);
|
|
45759
|
+
}
|
|
45760
|
+
static formatTime(time) {
|
|
45761
|
+
return humanFormat(time, {
|
|
45762
|
+
scale: timeScale,
|
|
45763
|
+
});
|
|
45764
|
+
}
|
|
45765
|
+
static formatFps(fps) {
|
|
45766
|
+
return humanFormat(fps, metricTemplates.fps);
|
|
45767
|
+
}
|
|
45768
|
+
static formatPercentage(percentage) {
|
|
45769
|
+
return humanFormat(percentage, {
|
|
45770
|
+
scale: percentScale,
|
|
45771
|
+
});
|
|
45772
|
+
}
|
|
45773
|
+
static formatBitrate(bitrate) {
|
|
45774
|
+
return humanFormat(bitrate, {
|
|
45775
|
+
unit: 'bps',
|
|
45776
|
+
});
|
|
45777
|
+
}
|
|
45745
45778
|
}
|
|
45746
45779
|
|
|
45747
45780
|
const SpeedtestWorkerModule = "// data reported to main thread\n\n// -1=not started, 0=starting, 1=download test, 2=ping+jitter test, 3=upload test, 4=finished, 5=abort\nlet testState = -1;\n// download speed in megabit/s with 2 decimal digits\nlet dlStatus = 0;\n// upload speed in megabit/s with 2 decimal digits\nlet ulStatus = '';\n// ping in milliseconds with 2 decimal digits\nlet pingStatus = '';\n// jitter in milliseconds with 2 decimal digits\nlet jitterStatus = '';\n// client's IP address as reported by getIP.php\nlet clientIp = '';\nlet serverHostName = '';\n//progress of download test 0-1\nlet dlProgress = 0;\n//progress of upload test 0-1\nlet ulProgress = 0;\n//progress of ping+jitter test 0-1\nlet pingProgress = 0;\n//test ID (sent back by telemetry if used, null otherwise)\nlet testId = null;\n\nlet log = ''; //telemetry log\n\nfunction tlog(s) {\n if (settings.telemetry_level >= 2) {\n log += Date.now() + ': ' + s + '\\n';\n }\n}\n\nfunction tverb(s) {\n if (settings.telemetry_level >= 3) {\n log += Date.now() + ': ' + s + '\\n';\n }\n}\n\nfunction twarn(s) {\n if (settings.telemetry_level >= 2) {\n log += Date.now() + ' WARN: ' + s + '\\n';\n }\n\n console.warn(s);\n}\n\n// test settings. can be overridden by sending specific values with the start command\nconst settings = {\n //set to true when in MPOT mode\n mpot: false,\n //order in which tests will be performed as a string. D=Download, U=Upload, P=Ping+Jitter, I=IP, _=1 second delay\n test_order: 'P_D',\n // max duration of upload test in seconds\n time_ul_max: 0,\n // max duration of download test in seconds\n time_dl_max: 15,\n // if set to true, tests will take less time on faster connections\n time_auto: true,\n //time to wait in seconds before actually measuring ul speed (wait for buffers to fill)\n time_ulGraceTime: 3,\n //time to wait in seconds before actually measuring dl speed (wait for TCP window to increase)\n time_dlGraceTime: 1.5,\n // number of pings to perform in ping test\n count_ping: 10,\n // path to a large file or garbage.php, used for download test. must be relative to this js file\n url_dl: 'backend/garbage.php',\n // path to an empty file, used for upload test. must be relative to this js file\n url_ul: 'backend/empty.php',\n // path to an empty file, used for ping test. must be relative to this js file\n url_ping: 'backend/empty.php',\n // path to getIP.php relative to this js file, or a similar thing that outputs the client's ip\n url_getIp: 'backend/getIP.php',\n // if set to true, the server will include ISP info with the IP address\n getIp_ispInfo: true,\n // km or mi=estimate distance from server in km/mi; set to false to disable distance estimation.\n // getIp_ispInfo must be enabled in order for this to work\n getIp_ispInfo_distance: false,\n // number of download streams to use (can be different if enable_quirks is active)\n xhr_dlMultistream: 6,\n // number of upload streams to use (can be different if enable_quirks is active)\n xhr_ulMultistream: 3,\n // how much concurrent requests should be delayed\n xhr_multistreamDelay: 300,\n // 0=fail on errors, 1=attempt to restart a stream if it fails, 2=ignore all errors\n xhr_ignoreErrors: 1,\n // if set to true, it reduces ram usage but uses the hard drive (useful with large garbagePhp_chunkSize\n // and/or high xhr_dlMultistream)\n xhr_dlUseBlob: false,\n // size in megabytes of the upload blobs sent in the upload test (forced to 4 on chrome mobile)\n xhr_ul_blob_megabytes: 20,\n // size of chunks sent by garbage.php (can be different if enable_quirks is active)\n garbagePhp_chunkSize: 100,\n // enable quirks for specific browsers. currently it overrides settings to optimize for specific browsers,\n // unless they are already being overridden with the start command\n enable_quirks: true,\n // if enabled, the ping test will attempt to calculate the ping more precisely using the Performance API.\n // Currently works perfectly in Chrome, badly in Edge, and not at all in Firefox.\n // If Performance API is not supported or the result is obviously wrong, a fallback is provided.\n ping_allowPerformanceApi: true,\n // can be changed to compensatie for transport overhead. (see doc.md for some other values)\n overheadCompensationFactor: 1.06,\n //if set to true, speed will be reported in mebibits/s instead of megabits/s\n useMebibits: false,\n // 0=disabled, 1=basic (results only), 2=full (results and timing) 3=debug (results+log)\n telemetry_level: 0,\n // path to the script that adds telemetry data to the database\n url_telemetry: 'results/telemetry.php',\n //extra data that can be passed to the telemetry through the settings\n telemetry_extra: ''\n};\n\nlet xhr = null; // array of currently active xhr requests\nlet interval = null; // timer used in tests\nlet test_pointer = 0; //pointer to the next test to run inside settings.test_order\n\n/*\n this function is used on URLs passed in the settings to determine whether we need a ? or an & as a separator\n*/\nfunction url_sep(url) {\n return url.match(/\\?/) ? '&' : '?';\n}\n\n/*\n listener for commands from main thread to this worker.\n commands:\n -status: returns the current status as a JSON string containing testState,\n dlStatus, ulStatus, pingStatus, clientIp, jitterStatus, dlProgress, ulProgress, pingProgress\n -abort: aborts the current test\n -start: starts the test. optionally, settings can be passed as JSON.\n example: start {\"time_ul_max\":\"10\", \"time_dl_max\":\"10\", \"count_ping\":\"50\"}\n*/\nself.addEventListener('message', function (e) {\n const params = e.data.split(' ');\n\n if (params[0] === 'status') {\n // return status\n postMessage(\n {\n testState: testState,\n dlStatus: dlStatus,\n ulStatus: ulStatus,\n pingStatus: pingStatus,\n clientIp: clientIp,\n serverHostName: serverHostName,\n jitterStatus: jitterStatus,\n dlProgress: dlProgress,\n ulProgress: ulProgress,\n pingProgress: pingProgress,\n testId: testId\n }\n );\n }\n if (params[0] === 'start' && testState === -1) {\n const ua = navigator.userAgent;\n\n // start new test\n testState = 0;\n try {\n // parse settings, if present\n let s = {};\n\n try {\n const ss = e.data.substring(5);\n\n if (ss) {\n s = JSON.parse(ss);\n }\n } catch (e) {\n twarn('Error parsing custom settings JSON. Please check your syntax');\n }\n //copy custom settings\n for (const key in s) {\n if (typeof settings[key] !== 'undefined') {\n settings[key] = s[key];\n } else {\n twarn('Unknown setting ignored: ' + key);\n }\n }\n // quirks for specific browsers. apply only if not overridden. more may be added in future releases\n if (settings.enable_quirks || (typeof s.enable_quirks !== 'undefined' && s.enable_quirks)) {\n if (/Firefox.(\\d+\\.\\d+)/i.test(ua)) {\n if (typeof s.ping_allowPerformanceApi === 'undefined') {\n // ff performance API sucks\n settings.ping_allowPerformanceApi = false;\n }\n }\n if (/Edge.(\\d+\\.\\d+)/i.test(ua)) {\n if (typeof s.xhr_dlMultistream === 'undefined') {\n // edge more precise with 3 download streams\n settings.xhr_dlMultistream = 3;\n }\n }\n if (/Chrome.(\\d+)/i.test(ua) && !!self.fetch) {\n if (typeof s.xhr_dlMultistream === 'undefined') {\n // chrome more precise with 5 streams\n settings.xhr_dlMultistream = 5;\n }\n }\n }\n if (/Edge.(\\d+\\.\\d+)/i.test(ua)) {\n //Edge 15 introduced a bug that causes onprogress events to not get fired,\n // we have to use the \"small chunks\" workaround that reduces accuracy\n settings.forceIE11Workaround = true;\n }\n if (/PlayStation 4.(\\d+\\.\\d+)/i.test(ua)) {\n //PS4 browser has the same bug as IE11/Edge\n settings.forceIE11Workaround = true;\n }\n if (/Chrome.(\\d+)/i.test(ua) && /Android|iPhone|iPad|iPod|Windows Phone/i.test(ua)) {\n // cheap af\n // Chrome mobile introduced a limitation somewhere around version 65,\n // we have to limit XHR upload size to 4 megabytes\n settings.xhr_ul_blob_megabytes = 4;\n }\n if (/^((?!chrome|android|crios|fxios).)*safari/i.test(ua)) {\n //Safari also needs the IE11 workaround but only for the MPOT version\n settings.forceIE11Workaround = true;\n }\n // telemetry_level has to be parsed and not just copied\n if (typeof s.telemetry_level !== 'undefined') {\n const telemetryLevels = {\n 'basic': 1,\n 'full': 2,\n 'debug': 3\n };\n\n settings.telemetry_level = telemetryLevels[s.telemetry_level] || 0;\n } // telemetry level\n // transform test_order to uppercase, just in case\n settings.test_order = settings.test_order.toUpperCase();\n } catch (e) {\n twarn('Possible error in custom test settings. Some settings might not have been applied. Exception: ' + e);\n }\n // run the tests\n tverb(JSON.stringify(settings));\n test_pointer = 0;\n let iRun = false,\n dRun = false,\n // uRun = false,\n pRun = false;\n // eslint-disable-next-line no-var\n var runNextTest = function () {\n if (testState === 5) {\n return;\n }\n if (test_pointer >= settings.test_order.length) {\n //test is finished\n if (settings.telemetry_level > 0) {\n sendTelemetry(function (id) {\n testState = 4;\n if (id !== null || id !== undefined) {\n testId = id;\n }\n });\n } else {\n testState = 4;\n }\n\n return;\n }\n switch (settings.test_order.charAt(test_pointer)) {\n case 'I': {\n test_pointer++;\n if (iRun) {\n runNextTest();\n\n return;\n } else {\n iRun = true;\n }\n getIp(runNextTest);\n }\n break;\n case 'D': {\n test_pointer++;\n if (dRun) {\n runNextTest();\n\n return;\n } else {\n dRun = true;\n }\n testState = 1;\n dlTest(runNextTest);\n }\n break;\n case 'U': {\n // test_pointer++;\n // if (uRun) {\n // runNextTest();\n // return;\n // } else uRun = true;\n // testState = 3;\n // ulTest(runNextTest);\n }\n break;\n case 'P': {\n test_pointer++;\n if (pRun) {\n runNextTest();\n\n return;\n } else {\n pRun = true;\n }\n testState = 2;\n pingTest(runNextTest);\n }\n break;\n case '_': {\n test_pointer++;\n setTimeout(runNextTest, 1000);\n }\n break;\n default:\n test_pointer++;\n }\n };\n\n runNextTest();\n }\n if (params[0] === 'abort') {\n // abort command\n if (testState >= 4) {\n return;\n }\n tlog('manually aborted');\n clearRequests(); // stop all xhr activity\n runNextTest = null;\n if (interval) {\n clearInterval(interval);\n } // clear timer if present\n if (settings.telemetry_level > 1) {\n sendTelemetry(function () {\n });\n }\n testState = 5; //set test as aborted\n dlStatus = 0;\n ulStatus = '';\n pingStatus = '';\n jitterStatus = '';\n clientIp = '';\n serverHostName = '';\n dlProgress = 0;\n ulProgress = 0;\n pingProgress = 0;\n }\n});\n\n// stops all XHR activity, aggressively\nfunction clearRequests() {\n tverb('stopping pending XHRs');\n if (xhr) {\n for (let i = 0; i < xhr.length; i++) {\n try {\n xhr[i].onprogress = null;\n xhr[i].onload = null;\n xhr[i].onerror = null;\n } catch (e) {\n console.warn(e);\n }\n try {\n xhr[i].upload.onprogress = null;\n xhr[i].upload.onload = null;\n xhr[i].upload.onerror = null;\n } catch (e) {\n console.warn(e);\n }\n try {\n xhr[i].abort();\n } catch (e) {\n console.warn(e);\n }\n try {\n delete xhr[i];\n } catch (e) {\n console.warn(e);\n }\n }\n xhr = null;\n }\n}\n\n// gets client's IP using url_getIp, then calls the done function\nlet ipCalled = false; // used to prevent multiple accidental calls to getIp\nlet ispInfo = ''; //used for telemetry\n\nfunction getIp(done) {\n tverb('getIp');\n if (ipCalled) {\n return;\n } else {\n ipCalled = true;\n } // getIp already called?\n const startT = new Date().getTime();\n\n xhr = new XMLHttpRequest();\n xhr.onload = function () {\n tlog('IP: ' + xhr.responseText + ', took ' + (new Date().getTime() - startT) + 'ms');\n try {\n const data = JSON.parse(xhr.responseText);\n\n clientIp = data.processedString;\n serverHostName = data.serverHostName;\n ispInfo = data.rawIspInfo;\n } catch (e) {\n clientIp = xhr.responseText;\n ispInfo = '';\n }\n done();\n };\n xhr.onerror = function () {\n tlog('getIp failed, took ' + (new Date().getTime() - startT) + 'ms');\n done();\n };\n const queryParams = [\n settings.mpot ? 'cors=true' : '',\n settings.getIp_ispInfo ?\n `isp=true${settings.getIp_ispInfo_distance ? '&distance=' + settings.getIp_ispInfo_distance : ''}` :\n '',\n 'r=' + Math.random()\n ].filter(Boolean).join('&');\n\n const url = `${settings.url_getIp}${url_sep(settings.url_getIp)}${queryParams}`;\n\n xhr.open(\n 'GET',\n url,\n true\n );\n xhr.send();\n}\n\n// download test, calls done function when it's over\nlet dlCalled = false; // used to prevent multiple accidental calls to dlTest\n\nfunction dlTest(done) {\n tverb('dlTest');\n if (dlCalled) {\n return;\n } else {\n dlCalled = true;\n } // dlTest already called?\n let totLoaded = 0.0, // total number of loaded bytes\n startT = new Date().getTime(), // timestamp when test was started\n bonusT = 0, //how many milliseconds the test has been shortened by (higher on faster connections)\n graceTimeDone = false, //set to true after the grace time is past\n failed = false; // set to true if a stream fails\n\n xhr = [];\n // function to create a download stream. streams are slightly delayed so that they will not end at the same time\n const testStream = function (i, delay) {\n setTimeout(\n function () {\n if (testState !== 1) {\n return;\n } // delayed stream ended up starting after the end of the download test\n tverb('dl test stream started ' + i + ' ' + delay);\n let prevLoaded = 0; // number of bytes loaded last time onprogress was called\n const x = new XMLHttpRequest();\n\n xhr[i] = x;\n xhr[i].onprogress = function (event) {\n tverb('dl stream progress event ' + i + ' ' + event.loaded);\n if (testState !== 1) {\n try {\n x.abort();\n } catch (e) {\n console.warn(e);\n }\n } // just in case this XHR is still running after the download test\n // progress event, add number of new loaded bytes to totLoaded\n const loadDiff = event.loaded <= 0 ? 0 : event.loaded - prevLoaded;\n\n if (isNaN(loadDiff) || !isFinite(loadDiff) || loadDiff < 0) {\n return;\n } // just in case\n totLoaded += loadDiff;\n prevLoaded = event.loaded;\n }.bind(this);\n xhr[i].onload = function () {\n // the large file has been loaded entirely, start again\n tverb('dl stream finished ' + i);\n try {\n xhr[i].abort();\n } catch (e) {\n console.warn(e);\n } // reset the stream data to empty ram\n testStream(i, 0);\n }.bind(this);\n xhr[i].onerror = function () {\n // error\n tverb('dl stream failed ' + i);\n if (settings.xhr_ignoreErrors === 0) {\n failed = true;\n } //abort\n try {\n xhr[i].abort();\n } catch (e) {\n console.warn(e);\n }\n delete xhr[i];\n if (settings.xhr_ignoreErrors === 1) {\n testStream(i, 0);\n } //restart stream\n }.bind(this);\n // send xhr\n try {\n if (settings.xhr_dlUseBlob) {\n xhr[i].responseType = 'blob';\n } else {\n xhr[i].responseType = 'arraybuffer';\n }\n } catch (e) {\n console.warn(e);\n }\n\n const queryParams = [\n settings.mpot ? 'cors=true' : '',\n 'r=' + Math.random(),\n 'ckSize=' + settings.garbagePhp_chunkSize\n ].join('&');\n\n const url = `${settings.url_dl}${url_sep(settings.url_dl)}${queryParams}`;\n\n // random string to prevent caching\n xhr[i].open('GET', url, true);\n xhr[i].send();\n }.bind(this),\n 1 + delay\n );\n }.bind(this);\n\n // open streams\n for (let i = 0; i < settings.xhr_dlMultistream; i++) {\n testStream(i, settings.xhr_multistreamDelay * i);\n }\n // every 200ms, update dlStatus\n interval = setInterval(\n function () {\n tverb('DL: ' + dlStatus + (graceTimeDone ? '' : ' (in grace time)'));\n const t = new Date().getTime() - startT;\n\n if (graceTimeDone) {\n dlProgress = (t + bonusT) / (settings.time_dl_max * 1000);\n }\n if (t < 200) {\n return;\n }\n if (!graceTimeDone) {\n if (t > 1000 * settings.time_dlGraceTime) {\n if (totLoaded > 0) {\n // if the connection is so slow that we didn't get a single chunk yet, do not reset\n startT = new Date().getTime();\n bonusT = 0;\n totLoaded = 0.0;\n }\n graceTimeDone = true;\n }\n } else {\n const speed = totLoaded / (t / 1000.0);\n\n if (settings.time_auto) {\n //decide how much to shorten the test. Every 200ms, the test is shortened by the bonusT calculated here\n const bonus = (6.4 * speed) / 100000;\n\n bonusT += bonus > 800 ? 800 : bonus;\n }\n // update status\n // speed is multiplied by 8 to go from bytes to bits, overhead compensation is applied,\n // then everything is divided by 1048576 or 1000000 to go to megabits/mebibits\n dlStatus = ((speed * 8 * settings.overheadCompensationFactor) / (settings.useMebibits ? 1048576 : 1000000));\n if ((t + bonusT) / 1000.0 > settings.time_dl_max || failed) {\n // test is over, stop streams and timer\n if (failed || isNaN(dlStatus)) {\n dlStatus = 'Fail';\n }\n clearRequests();\n clearInterval(interval);\n dlProgress = 1;\n tlog('dlTest: ' + dlStatus + ', took ' + (new Date().getTime() - startT) + 'ms');\n done();\n }\n }\n }.bind(this),\n 200\n );\n}\n\n// ping+jitter test, function done is called when it's over\nlet ptCalled = false; // used to prevent multiple accidental calls to pingTest\n\nfunction pingTest(done) {\n tverb('pingTest');\n if (ptCalled) {\n return;\n } else {\n ptCalled = true;\n } // pingTest already called?\n const startT = new Date().getTime(); //when the test was started\n let prevT = null; // last time a pong was received\n let ping = 0.0; // current ping value\n let jitter = 0.0; // current jitter value\n let i = 0; // counter of pongs received\n let prevInstspd = 0; // last ping time, used for jitter calculation\n\n xhr = [];\n // ping function\n const doPing = function () {\n tverb('ping');\n pingProgress = i / settings.count_ping;\n prevT = new Date().getTime();\n xhr[0] = new XMLHttpRequest();\n xhr[0].onload = function () {\n // pong\n tverb('pong');\n if (i === 0) {\n prevT = new Date().getTime(); // first pong\n } else {\n let instspd = new Date().getTime() - prevT;\n\n if (settings.ping_allowPerformanceApi) {\n try {\n //try to get accurate performance timing using performance api\n let p = performance.getEntries();\n\n p = p[p.length - 1];\n let d = p.responseStart - p.requestStart;\n\n if (d <= 0) {\n d = p.duration;\n }\n if (d > 0 && d < instspd) {\n instspd = d;\n }\n } catch (e) {\n //if not possible, keep the estimate\n tverb('Performance API not supported, using estimate');\n }\n }\n //noticed that some browsers randomly have 0ms ping\n if (instspd < 1) {\n instspd = prevInstspd;\n }\n if (instspd < 1) {\n instspd = 1;\n }\n const instjitter = Math.abs(instspd - prevInstspd);\n\n if (i === 1) {\n ping = instspd;\n }/* first ping, can't tell jitter yet*/ else {\n if (instspd < ping) {\n ping = instspd;\n } // update ping, if the instant ping is lower\n if (i === 2) {\n jitter = instjitter;\n } else {\n //discard the first jitter measurement because it might be much higher than it should be\n jitter = instjitter > jitter ? jitter * 0.3 + instjitter * 0.7 : jitter * 0.8 + instjitter * 0.2;\n } // update jitter, weighted average. spikes in ping values are given more weight.\n }\n prevInstspd = instspd;\n }\n pingStatus = ping.toFixed(2);\n jitterStatus = jitter.toFixed(2);\n i++;\n tverb('ping: ' + pingStatus + ' jitter: ' + jitterStatus);\n if (i < settings.count_ping) {\n doPing();\n } else {\n // more pings to do?\n pingProgress = 1;\n tlog('ping: ' + pingStatus + ' jitter: ' + jitterStatus + ', took ' + (new Date().getTime() - startT) + 'ms');\n done();\n }\n }.bind(this);\n xhr[0].onerror = function () {\n // a ping failed, cancel test\n tverb('ping failed');\n if (settings.xhr_ignoreErrors === 0) {\n //abort\n pingStatus = 'Fail';\n jitterStatus = 'Fail';\n clearRequests();\n tlog('ping test failed, took ' + (new Date().getTime() - startT) + 'ms');\n pingProgress = 1;\n done();\n }\n if (settings.xhr_ignoreErrors === 1) {\n doPing();\n } //retry ping\n if (settings.xhr_ignoreErrors === 2) {\n //ignore failed ping\n i++;\n if (i < settings.count_ping) {\n doPing();\n } else {\n // more pings to do?\n pingProgress = 1;\n tlog('ping: ' + pingStatus + ' jitter: ' + jitterStatus + ', took ' + (new Date().getTime() - startT) + 'ms');\n done();\n }\n }\n }.bind(this);\n // send xhr\n const queryString = [\n settings.mpot ? 'cors=true' : '',\n `r=${Math.random()}`\n ].filter(part => part !== '').join('&');\n\n const url = `${settings.url_ping}${url_sep(settings.url_ping)}${queryString}`;\n\n // random string to prevent caching\n xhr[0].open('GET', url, true);\n xhr[0].send();\n }.bind(this);\n\n doPing(); // start first ping\n}\n\n// telemetry\nfunction sendTelemetry(done) {\n if (settings.telemetry_level < 1) {\n return;\n }\n xhr = new XMLHttpRequest();\n xhr.onload = function () {\n try {\n const parts = xhr.responseText.split(' ');\n\n if (parts[0] === 'id') {\n try {\n const id = parts[1];\n\n done(id);\n } catch (e) {\n done(null);\n }\n } else {\n done(null);\n }\n } catch (e) {\n done(null);\n }\n };\n xhr.onerror = function () {\n console.warn('TELEMETRY ERROR ' + xhr.status);\n done(null);\n };\n xhr.open('POST', settings.url_telemetry + url_sep(settings.url_telemetry) + (settings.mpot ? 'cors=true&' : '') + 'r=' + Math.random(), true);\n const telemetryIspInfo = {\n processedString: clientIp,\n serverHostName: serverHostName,\n rawIspInfo: typeof ispInfo === 'object' ? ispInfo : ''\n };\n\n try {\n const fd = new FormData();\n\n fd.append('ispinfo', JSON.stringify(telemetryIspInfo));\n fd.append('dl', dlStatus);\n fd.append('ul', ulStatus);\n fd.append('ping', pingStatus);\n fd.append('jitter', jitterStatus);\n fd.append('log', settings.telemetry_level > 1 ? log : '');\n fd.append('extra', settings.telemetry_extra);\n xhr.send(fd);\n } catch (ex) {\n const postData = 'extra=' + encodeURIComponent(settings.telemetry_extra) + '&ispinfo=' + encodeURIComponent(JSON.stringify(telemetryIspInfo)) + '&dl=' + encodeURIComponent(dlStatus) + '&ul=' + encodeURIComponent(ulStatus) + '&ping=' + encodeURIComponent(pingStatus) + '&jitter=' + encodeURIComponent(jitterStatus) + '&log=' + encodeURIComponent(settings.telemetry_level > 1 ? log : '');\n\n xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n xhr.send(postData);\n }\n}\n";
|
|
@@ -46234,7 +46267,7 @@ function rankConnectionSpeed(dlSpeed) {
|
|
|
46234
46267
|
return 0;
|
|
46235
46268
|
}
|
|
46236
46269
|
|
|
46237
|
-
const pluginHtml$4 = "<% general = metrics.general %>\n<% counters = metrics.counters %>\n<% timers = metrics.timers %>\n<% extra = metrics.extra %>\n<% custom = metrics.custom %>\n\n<div class=\"stats-box\">\n <div class=\"stats-box-top\">\n <a class=\"close-button gplayer-lite-btn\" data-close-button>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <g clip-path=\"url(#clip0_184_1489)\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M7.41376 6.00013L13.7068 -0.292872C14.0978 -0.683872 14.0978 -1.31587 13.7068 -1.70687C13.3158 -2.09787 12.6838 -2.09787 12.2928 -1.70687L5.99976 4.58613L-0.293238 -1.70687C-0.684238 -2.09787 -1.31624 -2.09787 -1.70724 -1.70687C-2.09824 -1.31587 -2.09824 -0.683872 -1.70724 -0.292872L4.58576 6.00013L-1.70724 12.2931C-2.09824 12.6841 -2.09824 13.3161 -1.70724 13.7071C-1.51224 13.9021 -1.25624 14.0001 -1.00024 14.0001C-0.744238 14.0001 -0.488238 13.9021 -0.293238 13.7071L5.99976 7.41413L12.2928 13.7071C12.4878 13.9021 12.7438 14.0001 12.9998 14.0001C13.2558 14.0001 13.5118 13.9021 13.7068 13.7071C14.0978 13.3161 14.0978 12.6841 13.7068 12.2931L7.41376 6.00013Z\"\n fill=\"white\"/>\n </g>\n <defs>\n <clipPath id=\"clip0_184_1489\">\n <rect width=\"12\" height=\"12\" fill=\"white\"/>\n </clipPath>\n </defs>\n </svg>\n </a>\n </div>\n <div class=\"stats-box-main\">\n <ul>\n <li class=\"title\"><span>General</span></li>\n <li>\n Display resolution:\n <div><span><%= general.displayResolution %></span></div>\n </li>\n <li>\n Volume:\n <div><span><%= general.volume %></span></div>\n </li>\n <li>\n Connection speed:\n <div><span id=\"dlText\"><%= custom.connectionSpeed %></span> Mbps</div>\n </li>\n <li class=\"canvas-wrapper\">\n <canvas id=\"speedTestCanvas\" width=\"190\" height=\"20\"></canvas>\n </li>\n <li>\n Ping:\n <div><span id=\"pingText\"><%= custom.ping %></span> ms</div>\n </li>\n <li>\n Jitter:\n <div><span id=\"jitterText\"><%= custom.jitter %></span> ms</div>\n </li>\n </ul>\n\n <ul>\n <li class=\"title\"><span>Counters</span></li>\n <li>\n Plays:\n <div><span><%= counters.play %></span></div>\n </li>\n <li>\n Pauses:\n <div><span><%= counters.pause %></span></div>\n </li>\n <li>\n Errors:\n <div><span><%= counters.error %></span></div>\n </li>\n <li>\n Bufferings:\n <div><span><%= counters.buffering %></span></div>\n </li>\n <li>\n Decoded frames:\n <div><span><%= counters.decodedFrames %></span></div>\n </li>\n <li>\n Dropped frames:\n <div><span><%= counters.droppedFrames %></span></div>\n </li>\n <li>\n Frames per second:\n <div><span><%= counters.fps %></span></div>\n </li>\n <li>\n Bitrate changes:\n <div><span><%= counters.changeLevel %></span></div>\n </li>\n <li>\n Seeks:\n <div><span><%= counters.seek %></span></div>\n </li>\n <li>\n Fullscreen:\n <div><span><%= counters.fullscreen %></span></div>\n </li>\n <li>\n DVR seeks:\n <div><span><%= counters.dvrUsage %></span></div>\n </li>\n </ul>\n\n <ul>\n <li class=\"title\"><span>Timers</span></li>\n <li>\n Startup time:\n <div><span><%= timers.startup %></span></div>\n </li>\n <li>\n Watching time:\n <div><span><%= timers.watch %></span></div>\n </li>\n <li>\n Pause time:\n <div><span><%= timers.pause %></span></div>\n </li>\n <li>\n Buffering time:\n <div><span><%= timers.buffering %></span></div>\n </li>\n <li>\n Session time:\n <div><span><%= timers.session %></span></div>\n </li>\n <!-- <li>-->\n <!-- Latency:-->\n <!-- <div><span><%= timers.latency %></span></div>-->\n <!-- </li>-->\n </ul>\n\n <ul>\n <li class=\"title\"><span>Extra</span></li>\n <li>\n Playback:\n <div><span><%= extra.playbackName %></span></div>\n </li>\n <li>\n Playback type:\n <div><span><%= extra.playbackType %></span></div>\n </li>\n <li>\n Buffer size:\n <div><span><%= extra.buffersize %></span></div>\n </li>\n <li>\n Video duration:\n <div><span><%= extra.duration %></span></div>\n </li>\n <li>\n Current time:\n <div><span><%= extra.currentTime %></span></div>\n </li>\n <li>\n Bitrate weighted mean:\n <div><span><%= extra.bitrateWeightedMean %></span></div>\n </li>\n <li>\n Bitrate most used:\n <div><span><%= extra.bitrateMostUsed %></span></div>\n </li>\n <li>\n % Watched:\n <div><span><%= extra.watchedPercentage %></span></div>\n </li>\n <li>\n % Buffering:\n <div><span><%= extra.bufferingPercentage %></span></div>\n </li>\n </ul>\n </div>\n <div class=\"speedtest-summary\">\n <div class=\"speedtest-summary-header\">Your internet quality summary</div>\n <div class=\"speedtest-summary-block\">\n <div class=\"speedtest-summary-subblock\">\n <div class=\"speedtest-summary-subblock-content\">\n <div class=\"speedtest-quality\">\n <div class=\"speedtest-quality-header\">VOD: <%= custom.vodQuality %></div>\n <div class=\"speedtest-quality-content\" data-streaming-type=\"vod\">\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"speedtest-summary-subblock\">\n <div class=\"speedtest-summary-subblock-content\">\n <div class=\"speedtest-quality\">\n <div class=\"speedtest-quality-header\">Live: <%= custom.liveQuality %></div>\n <div class=\"speedtest-quality-content\" data-streaming-type=\"live\">\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"speedtest-footer\">\n <!-- <a class=\"speedtest-footer-about-link\" href=\"\" target=\"_blank\">I am not a nerd, what's this all about?</a>-->\n <button class=\"gplayer-lite-btn speedtest-btn speedtest-footer-refresh\" data-refresh-button type=\"button\">\n <svg width=\"12\" height=\"10\" viewBox=\"0 0 12 10\" fill=\"none\">\n <path\n d=\"M6.03968 0.124998C3.64268 0.124998 1.67268 1.9565 1.48068 4.2915H1.00018C0.925833 4.29146 0.853156 4.31353 0.791378 4.35489C0.729601 4.39625 0.681511 4.45503 0.653218 4.52378C0.624925 4.59253 0.617705 4.66814 0.632476 4.74101C0.647248 4.81387 0.683343 4.88069 0.736177 4.933L1.57618 5.766C1.64641 5.83561 1.74129 5.87467 1.84018 5.87467C1.93906 5.87467 2.03395 5.83561 2.10418 5.766L2.94418 4.933C2.99701 4.88069 3.03311 4.81387 3.04788 4.74101C3.06265 4.66814 3.05543 4.59253 3.02714 4.52378C2.99884 4.45503 2.95075 4.39625 2.88898 4.35489C2.8272 4.31353 2.75452 4.29146 2.68018 4.2915H2.23368C2.42368 2.376 4.05268 0.874998 6.03968 0.874998C6.6948 0.873639 7.33932 1.04039 7.91158 1.35931C8.48384 1.67822 8.9647 2.13863 9.30818 2.6965C9.33331 2.73978 9.36686 2.7776 9.40684 2.80771C9.44682 2.83783 9.49243 2.85963 9.54097 2.87184C9.58951 2.88405 9.64001 2.88643 9.68948 2.87881C9.73895 2.8712 9.7864 2.85377 9.82902 2.82753C9.87165 2.80129 9.90859 2.76679 9.93767 2.72605C9.96675 2.68531 9.98739 2.63916 9.99835 2.59032C10.0093 2.54148 10.0104 2.49095 10.0015 2.44168C9.99264 2.39242 9.974 2.34544 9.94668 2.3035C9.53615 1.63664 8.96146 1.08621 8.27752 0.704805C7.59359 0.323402 6.82277 0.123774 6.03968 0.124998ZM10.4207 4.2335C10.3505 4.16419 10.2558 4.12532 10.1572 4.12532C10.0585 4.12532 9.96386 4.16419 9.89368 4.2335L9.05018 5.0665C8.9972 5.11874 8.96096 5.18557 8.94608 5.25847C8.93119 5.33137 8.93833 5.40705 8.96658 5.47588C8.99483 5.54472 9.04292 5.60359 9.10473 5.64501C9.16654 5.68644 9.23927 5.70853 9.31368 5.7085H9.76318C9.57218 7.6235 7.93768 9.125 5.94118 9.125C5.28399 9.12683 4.63729 8.96035 4.06269 8.64141C3.48808 8.32247 3.00473 7.86169 2.65868 7.303C2.63281 7.26107 2.59893 7.22465 2.55899 7.19582C2.51904 7.16699 2.47381 7.14631 2.42587 7.13495C2.37793 7.1236 2.32823 7.1218 2.27959 7.12966C2.23096 7.13752 2.18435 7.15488 2.14243 7.18075C2.05776 7.233 1.99731 7.31674 1.97438 7.41355C1.95146 7.51037 1.96793 7.61233 2.02018 7.697C2.43345 8.36457 3.01076 8.91521 3.69713 9.29647C4.38349 9.67772 5.15604 9.87689 5.94118 9.875C8.34518 9.875 10.3237 8.045 10.5162 5.7085H11.0002C11.0746 5.70853 11.1473 5.68644 11.2091 5.64501C11.2709 5.60359 11.319 5.54472 11.3473 5.47588C11.3755 5.40705 11.3827 5.33137 11.3678 5.25847C11.3529 5.18557 11.3167 5.11874 11.2637 5.0665L10.4207 4.2335Z\"\n fill=\"white\"/>\n </svg>\n Refresh\n </button>\n </div>\n</div>\n";
|
|
46270
|
+
const pluginHtml$4 = "<% general = metrics.general %>\n<% counters = metrics.counters %>\n<% timers = metrics.chrono %>\n<% extra = metrics.extra %>\n<% custom = metrics.custom %>\n\n<div class=\"stats-box\" id=\"nerd-stats-box\">\n <div class=\"stats-box-top\">\n <a class=\"close-button gplayer-lite-btn\" id=\"nerd-stats-close\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <g clip-path=\"url(#clip0_184_1489)\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M7.41376 6.00013L13.7068 -0.292872C14.0978 -0.683872 14.0978 -1.31587 13.7068 -1.70687C13.3158 -2.09787 12.6838 -2.09787 12.2928 -1.70687L5.99976 4.58613L-0.293238 -1.70687C-0.684238 -2.09787 -1.31624 -2.09787 -1.70724 -1.70687C-2.09824 -1.31587 -2.09824 -0.683872 -1.70724 -0.292872L4.58576 6.00013L-1.70724 12.2931C-2.09824 12.6841 -2.09824 13.3161 -1.70724 13.7071C-1.51224 13.9021 -1.25624 14.0001 -1.00024 14.0001C-0.744238 14.0001 -0.488238 13.9021 -0.293238 13.7071L5.99976 7.41413L12.2928 13.7071C12.4878 13.9021 12.7438 14.0001 12.9998 14.0001C13.2558 14.0001 13.5118 13.9021 13.7068 13.7071C14.0978 13.3161 14.0978 12.6841 13.7068 12.2931L7.41376 6.00013Z\"\n fill=\"white\"/>\n </g>\n <defs>\n <clipPath id=\"clip0_184_1489\">\n <rect width=\"12\" height=\"12\" fill=\"white\"/>\n </clipPath>\n </defs>\n </svg>\n </a>\n </div>\n <div class=\"stats-box-main\">\n <ul>\n <li class=\"title\"><span><%= i18n.t('stats.general') %></span></li>\n <li>\n <%= i18n.t('stats.display_resolution') %>\n <div><span><span id=\"nerd-stats-resolution-width\"><%= general.resolution.width %></span>×<span id=\"nerd-stats-resolution-height\"><%= general.resolution.height %></span></span></div>\n </li>\n <li>\n <%= i18n.t('stats.volume') %>\n <div id=\"nerd-stats-volume\"><span><%= general.volume %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.connection_speed') %>\n <div><span id=\"dlText\"><%= custom.connectionSpeed %></span> <%= i18n.t('mbps') %></div>\n </li>\n <li class=\"canvas-wrapper\">\n <canvas id=\"speedTestCanvas\" width=\"190\" height=\"20\"></canvas>\n </li>\n <li>\n <%= i18n.t('stats.ping') %>\n <div><span id=\"pingText\"><%= custom.ping %></span> <%= i18n.t('ms') %></div>\n </li>\n <li>\n <%= i18n.t('stats.jitter') %>\n <div><span id=\"jitterText\"><%= custom.jitter %></span> <%= i18n.t('ms') %></div>\n </li>\n </ul>\n\n <ul>\n <li class=\"title\"><span><%= i18n.t('stats.counters') %></span></li>\n <li>\n <%= i18n.t('stats.plays') %>\n <div><span id=\"nerd-stats-plays\"><%= counters.play %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.pauses') %>\n <div><span id=\"nerd-stats-pauses\"><%= counters.pause %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.errors') %>\n <div><span id=\"nerd-stats-errors\"><%= counters.error %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.bufferings') %>\n <div><span id=\"nerd-stats-bufferings\"><%= counters.buffering %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.decoded_frames') %>\n <div><span id=\"nerd-stats-decoded-frames\"><%= counters.decodedFrames %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.dropped_frames') %>\n <div><span id=\"nerd-stats-dropped-frames\"><%= counters.droppedFrames %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.fps') %>\n <div><span id=\"nerd-stats-fps\"><%= counters.fps %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.bitrate_changes') %>\n <div><span id=\"nerd-stats-bitrate-changes\"><%= counters.changeLevel %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.seeks') %>\n <div><span id=\"nerd-stats-seeks\"><%= counters.seek %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.fullscreen') %>\n <div><span id=\"nerd-stats-fullscreen\"><%= counters.fullscreen %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.dvr_seeks') %>\n <div><span id=\"nerd-stats-dvr-usage\"><%= counters.dvrUsage %></span></div>\n </li>\n </ul>\n\n <ul>\n <li class=\"title\"><span><%= i18n.t('stats.duration') %></span></li>\n <li>\n <%= i18n.t('stats.startup') %>\n <div><span id=\"nerd-stats-startup-time\"><%= timers.startup %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.watching') %>\n <div><span id=\"nerd-stats-watch-time\"><%= timers.watch %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.paused') %>\n <div><span id=\"nerd-stats-pause-time\"><%= timers.pause %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.buffering') %>\n <div><span id=\"nerd-stats-buffering-time\"><%= timers.buffering %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.session') %>\n <div><span id=\"nerd-stats-session-time\"><%= timers.session %></span></div>\n </li>\n </ul>\n\n <ul>\n <li class=\"title\"><span><%= i18n.t('stats.extra') %></span></li>\n <li>\n <%= i18n.t('stats.playback') %>\n <div><span id=\"nerd-stats-playback-name\"><%= extra.playbackName %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.playback_type') %>\n <div><span id=\"nerd-stats-playback-type\"><%= extra.playbackType %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.buffer_size') %>\n <div><span id=\"nerd-stats-buffer-size\"><%= extra.buffersize %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.video_duration') %>\n <div><span id=\"nerd-stats-video-duration\"><%= extra.duration %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.current_time') %>\n <div><span id=\"nerd-stats-current-time\"><%= extra.currentTime %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.bitrate_weighted_mean') %>\n <div><span id=\"nerd-stats-bitrate-weighted-mean\"><%= extra.bitrateWeightedMean %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.bitrate_most_used') %>\n <div><span id=\"nerd-stats-bitrate-most-used\"><%= extra.bitrateMostUsed %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.watched_percentage') %>\n <div><span id=\"nerd-stats-watched-percentage\"><%= extra.watchedPercentage %></span></div>\n </li>\n <li>\n <%= i18n.t('stats.buffering_percentage') %>\n <div><span id=\"nerd-stats-buffering-percentage\"><%= extra.bufferingPercentage %></span></div>\n </li>\n </ul>\n </div>\n <div class=\"speedtest-summary\">\n <div class=\"speedtest-summary-header\"><%= i18n.t('stats.your_internet_quality_summary') %>:</div>\n <div class=\"speedtest-summary-block\">\n <div class=\"speedtest-summary-subblock\">\n <div class=\"speedtest-summary-subblock-content\">\n <div class=\"speedtest-quality\">\n <div class=\"speedtest-quality-header\"><%= i18n.t('vod') %>: \n <span id=\"nerd-stats-quality-vod-text\"><%= custom.vodQuality %></span></div>\n <div class=\"speedtest-quality-content\" data-streaming-type=\"vod\" id=\"nerd-stats-quality-vod\">\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"speedtest-summary-subblock\">\n <div class=\"speedtest-summary-subblock-content\">\n <div class=\"speedtest-quality\">\n <div class=\"speedtest-quality-header\"><%= i18n.t('live') %>: \n <span id=\"nerd-stats-quality-live-text\"><%= custom.liveQuality %></span></div>\n <div class=\"speedtest-quality-content\" data-streaming-type=\"live\" id=\"nerd-stats-quality-live\">\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n <div class=\"speedtest-quality-content-item\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"speedtest-footer\">\n <!-- <a class=\"speedtest-footer-about-link\" href=\"\" target=\"_blank\">I am not a nerd, what's this all about?</a>-->\n <button class=\"gplayer-lite-btn speedtest-btn speedtest-footer-refresh\" type=\"button\" id=\"nerd-stats-refresh\">\n <svg width=\"12\" height=\"10\" viewBox=\"0 0 12 10\" fill=\"none\">\n <path\n d=\"M6.03968 0.124998C3.64268 0.124998 1.67268 1.9565 1.48068 4.2915H1.00018C0.925833 4.29146 0.853156 4.31353 0.791378 4.35489C0.729601 4.39625 0.681511 4.45503 0.653218 4.52378C0.624925 4.59253 0.617705 4.66814 0.632476 4.74101C0.647248 4.81387 0.683343 4.88069 0.736177 4.933L1.57618 5.766C1.64641 5.83561 1.74129 5.87467 1.84018 5.87467C1.93906 5.87467 2.03395 5.83561 2.10418 5.766L2.94418 4.933C2.99701 4.88069 3.03311 4.81387 3.04788 4.74101C3.06265 4.66814 3.05543 4.59253 3.02714 4.52378C2.99884 4.45503 2.95075 4.39625 2.88898 4.35489C2.8272 4.31353 2.75452 4.29146 2.68018 4.2915H2.23368C2.42368 2.376 4.05268 0.874998 6.03968 0.874998C6.6948 0.873639 7.33932 1.04039 7.91158 1.35931C8.48384 1.67822 8.9647 2.13863 9.30818 2.6965C9.33331 2.73978 9.36686 2.7776 9.40684 2.80771C9.44682 2.83783 9.49243 2.85963 9.54097 2.87184C9.58951 2.88405 9.64001 2.88643 9.68948 2.87881C9.73895 2.8712 9.7864 2.85377 9.82902 2.82753C9.87165 2.80129 9.90859 2.76679 9.93767 2.72605C9.96675 2.68531 9.98739 2.63916 9.99835 2.59032C10.0093 2.54148 10.0104 2.49095 10.0015 2.44168C9.99264 2.39242 9.974 2.34544 9.94668 2.3035C9.53615 1.63664 8.96146 1.08621 8.27752 0.704805C7.59359 0.323402 6.82277 0.123774 6.03968 0.124998ZM10.4207 4.2335C10.3505 4.16419 10.2558 4.12532 10.1572 4.12532C10.0585 4.12532 9.96386 4.16419 9.89368 4.2335L9.05018 5.0665C8.9972 5.11874 8.96096 5.18557 8.94608 5.25847C8.93119 5.33137 8.93833 5.40705 8.96658 5.47588C8.99483 5.54472 9.04292 5.60359 9.10473 5.64501C9.16654 5.68644 9.23927 5.70853 9.31368 5.7085H9.76318C9.57218 7.6235 7.93768 9.125 5.94118 9.125C5.28399 9.12683 4.63729 8.96035 4.06269 8.64141C3.48808 8.32247 3.00473 7.86169 2.65868 7.303C2.63281 7.26107 2.59893 7.22465 2.55899 7.19582C2.51904 7.16699 2.47381 7.14631 2.42587 7.13495C2.37793 7.1236 2.32823 7.1218 2.27959 7.12966C2.23096 7.13752 2.18435 7.15488 2.14243 7.18075C2.05776 7.233 1.99731 7.31674 1.97438 7.41355C1.95146 7.51037 1.96793 7.61233 2.02018 7.697C2.43345 8.36457 3.01076 8.91521 3.69713 9.29647C4.38349 9.67772 5.15604 9.87689 5.94118 9.875C8.34518 9.875 10.3237 8.045 10.5162 5.7085H11.0002C11.0746 5.70853 11.1473 5.68644 11.2091 5.64501C11.2709 5.60359 11.319 5.54472 11.3473 5.47588C11.3755 5.40705 11.3827 5.33137 11.3678 5.25847C11.3529 5.18557 11.3167 5.11874 11.2637 5.0665L10.4207 4.2335Z\"\n fill=\"white\"/>\n </svg>\n <%= i18n.t('stats.refresh') %>\n </button>\n </div>\n</div>\n";
|
|
46238
46271
|
|
|
46239
46272
|
const buttonHtml$3 = "<button class='nerd-button gplayer-lite-btn gcore-skin-text-color gear-option' id=\"nerd-stats-button\">\n <span class=\"gear-option_icon\"><%= icon %></span>\n <span class=\"gear-option_label\"><%= i18n.t('statistics') %></span>\n</button>\n";
|
|
46240
46273
|
|
|
@@ -46307,18 +46340,24 @@ const drawSummary = (customMetrics, vodContainer, liveContainer) => {
|
|
|
46307
46340
|
vodContainer.html(vodHtml);
|
|
46308
46341
|
liveContainer.html(liveHtml);
|
|
46309
46342
|
};
|
|
46310
|
-
|
|
46343
|
+
|
|
46344
|
+
const PLAYBACK_NAMES = {
|
|
46345
|
+
dash: 'DASH.js',
|
|
46346
|
+
hls: 'HLS.js',
|
|
46347
|
+
html5_video: 'Native',
|
|
46348
|
+
};
|
|
46349
|
+
const T$e = 'plugins.nerd_stats';
|
|
46311
46350
|
/**
|
|
46312
|
-
* `PLUGIN` that displays useful network
|
|
46351
|
+
* `PLUGIN` that displays useful statistics regarding the playback as well as the network quality estimation.
|
|
46313
46352
|
* @beta
|
|
46314
46353
|
*
|
|
46315
46354
|
* @remarks
|
|
46316
46355
|
* Depends on:
|
|
46317
46356
|
*
|
|
46318
|
-
* - {@link BottomGear}
|
|
46319
|
-
*
|
|
46320
|
-
* - {@link ClapprStats}
|
|
46357
|
+
* - {@link BottomGear} - where the button is attached
|
|
46321
46358
|
*
|
|
46359
|
+
* - {@link ClapprStats} - to get the metrics from
|
|
46360
|
+
*
|
|
46322
46361
|
* The plugin is rendered as an item in the gear menu.
|
|
46323
46362
|
*
|
|
46324
46363
|
* When clicked, it shows an overlay window with the information about the network speed, latency, etc,
|
|
@@ -46326,13 +46365,13 @@ const T$f = 'plugins.nerd_stats';
|
|
|
46326
46365
|
*/
|
|
46327
46366
|
class NerdStats extends UICorePlugin {
|
|
46328
46367
|
container = null;
|
|
46329
|
-
|
|
46368
|
+
speedtestMetrics = {
|
|
46330
46369
|
connectionSpeed: 0,
|
|
46331
46370
|
ping: 0,
|
|
46332
46371
|
jitter: 0,
|
|
46333
46372
|
};
|
|
46334
46373
|
metrics = newMetrics();
|
|
46335
|
-
|
|
46374
|
+
open = false;
|
|
46336
46375
|
shortcut;
|
|
46337
46376
|
iconPosition;
|
|
46338
46377
|
static buttonTemplate = tmpl(buttonHtml$3);
|
|
@@ -46354,7 +46393,6 @@ class NerdStats extends UICorePlugin {
|
|
|
46354
46393
|
*/
|
|
46355
46394
|
get attributes() {
|
|
46356
46395
|
return {
|
|
46357
|
-
'data-clappr-nerd-stats': '',
|
|
46358
46396
|
class: 'clappr-nerd-stats',
|
|
46359
46397
|
};
|
|
46360
46398
|
}
|
|
@@ -46363,13 +46401,17 @@ class NerdStats extends UICorePlugin {
|
|
|
46363
46401
|
*/
|
|
46364
46402
|
get events() {
|
|
46365
46403
|
return {
|
|
46366
|
-
|
|
46367
|
-
'click
|
|
46368
|
-
'click
|
|
46404
|
+
click: 'clicked',
|
|
46405
|
+
'click #nerd-stats-close': 'hide',
|
|
46406
|
+
'click #nerd-stats-refresh': 'refreshSpeedTest',
|
|
46369
46407
|
};
|
|
46370
46408
|
}
|
|
46409
|
+
clicked(e) {
|
|
46410
|
+
e.stopPropagation();
|
|
46411
|
+
e.preventDefault();
|
|
46412
|
+
}
|
|
46371
46413
|
get statsBoxElem() {
|
|
46372
|
-
return '
|
|
46414
|
+
return this.$el.find('#nerd-stats-box');
|
|
46373
46415
|
}
|
|
46374
46416
|
get statsBoxWidthThreshold() {
|
|
46375
46417
|
return 720;
|
|
@@ -46388,7 +46430,7 @@ class NerdStats extends UICorePlugin {
|
|
|
46388
46430
|
];
|
|
46389
46431
|
this.iconPosition =
|
|
46390
46432
|
core.options.clapprNerdStats?.iconPosition ?? 'bottom-right';
|
|
46391
|
-
this.
|
|
46433
|
+
this.speedtestMetrics = {
|
|
46392
46434
|
connectionSpeed: 0,
|
|
46393
46435
|
ping: 0,
|
|
46394
46436
|
jitter: 0,
|
|
@@ -46400,20 +46442,38 @@ class NerdStats extends UICorePlugin {
|
|
|
46400
46442
|
*/
|
|
46401
46443
|
bindEvents() {
|
|
46402
46444
|
this.listenToOnce(this.core, Events$1.CORE_READY, this.onCoreReady);
|
|
46445
|
+
this.listenTo(this.core, Events$1.CORE_RESIZE, this.onPlayerResize);
|
|
46446
|
+
this.listenTo(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
|
|
46403
46447
|
}
|
|
46404
46448
|
onCoreReady() {
|
|
46405
46449
|
const bottomGear = this.core.getPlugin('bottom_gear');
|
|
46406
46450
|
assert(bottomGear, 'bottom_gear plugin is required');
|
|
46407
|
-
this.listenTo(bottomGear, GearEvents.RENDERED, this.
|
|
46451
|
+
this.listenTo(bottomGear, GearEvents.RENDERED, this.attach);
|
|
46452
|
+
Mousetrap.bind(this.shortcut, this.toggle);
|
|
46453
|
+
this.updateResolution();
|
|
46454
|
+
}
|
|
46455
|
+
onActiveContainerChanged() {
|
|
46408
46456
|
this.container = this.core.activeContainer;
|
|
46409
46457
|
const clapprStats = this.container?.getPlugin('clappr_stats');
|
|
46410
46458
|
assert(clapprStats, 'clappr-stats not available. Please, include it as a plugin of your Clappr instance.\n' +
|
|
46411
46459
|
'For more info, visit: https://github.com/clappr/clappr-stats.');
|
|
46412
|
-
Mousetrap.bind(this.shortcut, this.toggle);
|
|
46413
|
-
this.listenTo(this.core, Events$1.CORE_RESIZE, this.onPlayerResize);
|
|
46414
46460
|
this.listenTo(clapprStats, ClapprStatsEvents.REPORT, this.updateMetrics);
|
|
46461
|
+
this.listenTo(this.core.activeContainer, Events$1.CONTAINER_VOLUME, () => {
|
|
46462
|
+
this.metrics.general.volume = this.container?.volume ?? 0;
|
|
46463
|
+
this.$el
|
|
46464
|
+
.find('#nerd-stats-volume')
|
|
46465
|
+
.text(Formatter.formatVolume(this.metrics.general.volume));
|
|
46466
|
+
});
|
|
46467
|
+
this.listenTo(this.core.activePlayback, Events$1.PLAYBACK_LOADEDMETADATA, () => {
|
|
46468
|
+
this.$el
|
|
46469
|
+
.find('#nerd-stats-playback-type')
|
|
46470
|
+
.text(this.formatPlaybackName(this.core.activePlayback.getPlaybackType()));
|
|
46471
|
+
});
|
|
46415
46472
|
this.updateMetrics(clapprStats.exportMetrics());
|
|
46416
|
-
this
|
|
46473
|
+
this.$el
|
|
46474
|
+
.find('#nerd-stats-playback-name')
|
|
46475
|
+
.text(PLAYBACK_NAMES[this.core.activePlayback.name] ?? '-');
|
|
46476
|
+
this.core.activeContainer.$el.append(this.$el);
|
|
46417
46477
|
}
|
|
46418
46478
|
/**
|
|
46419
46479
|
* @internal
|
|
@@ -46423,7 +46483,7 @@ class NerdStats extends UICorePlugin {
|
|
|
46423
46483
|
return super.destroy();
|
|
46424
46484
|
}
|
|
46425
46485
|
toggle = () => {
|
|
46426
|
-
if (this.
|
|
46486
|
+
if (this.open) {
|
|
46427
46487
|
this.hide();
|
|
46428
46488
|
}
|
|
46429
46489
|
else {
|
|
@@ -46431,10 +46491,11 @@ class NerdStats extends UICorePlugin {
|
|
|
46431
46491
|
}
|
|
46432
46492
|
};
|
|
46433
46493
|
show() {
|
|
46434
|
-
this
|
|
46435
|
-
this.
|
|
46494
|
+
this.$el.show();
|
|
46495
|
+
this.statsBoxElem.scrollTop(this.statsBoxElem.scrollTop());
|
|
46496
|
+
this.open = true;
|
|
46436
46497
|
this.refreshSpeedTest();
|
|
46437
|
-
initSpeedTest(this.
|
|
46498
|
+
initSpeedTest(this.speedtestMetrics)
|
|
46438
46499
|
.then(() => {
|
|
46439
46500
|
startSpeedtest();
|
|
46440
46501
|
})
|
|
@@ -46444,21 +46505,28 @@ class NerdStats extends UICorePlugin {
|
|
|
46444
46505
|
});
|
|
46445
46506
|
}
|
|
46446
46507
|
hide() {
|
|
46447
|
-
this
|
|
46448
|
-
this.
|
|
46508
|
+
this.$el.hide();
|
|
46509
|
+
this.open = false;
|
|
46449
46510
|
stopSpeedtest();
|
|
46450
46511
|
}
|
|
46451
46512
|
onPlayerResize() {
|
|
46452
46513
|
this.setStatsBoxSize();
|
|
46514
|
+
this.updateResolution();
|
|
46453
46515
|
}
|
|
46454
|
-
|
|
46455
|
-
this.metrics.general = {
|
|
46456
|
-
|
|
46457
|
-
|
|
46516
|
+
updateResolution() {
|
|
46517
|
+
this.metrics.general.resolution = {
|
|
46518
|
+
width: this.playerWidth,
|
|
46519
|
+
height: this.playerHeight,
|
|
46458
46520
|
};
|
|
46521
|
+
this.$el
|
|
46522
|
+
.find('#nerd-stats-resolution-width')
|
|
46523
|
+
.text(this.metrics.general.resolution.width);
|
|
46524
|
+
this.$el
|
|
46525
|
+
.find('#nerd-stats-resolution-height')
|
|
46526
|
+
.text(this.metrics.general.resolution.height);
|
|
46459
46527
|
}
|
|
46460
|
-
|
|
46461
|
-
|
|
46528
|
+
estimateQuality() {
|
|
46529
|
+
trace(`${T$e} estimateQuality`);
|
|
46462
46530
|
const videoQualityNames = [
|
|
46463
46531
|
'SD (480p)',
|
|
46464
46532
|
'HD (720p)',
|
|
@@ -46466,9 +46534,9 @@ class NerdStats extends UICorePlugin {
|
|
|
46466
46534
|
'2K (1440p)',
|
|
46467
46535
|
'4K (2160p)',
|
|
46468
46536
|
];
|
|
46469
|
-
const { connectionSpeed, ping } = this.
|
|
46537
|
+
const { connectionSpeed, ping } = this.speedtestMetrics;
|
|
46470
46538
|
if (!connectionSpeed || !ping) {
|
|
46471
|
-
const calculatingText = '
|
|
46539
|
+
const calculatingText = this.core.i18n.t('stats.calculating');
|
|
46472
46540
|
this.metrics.custom.vodQuality = calculatingText;
|
|
46473
46541
|
this.metrics.custom.liveQuality = calculatingText;
|
|
46474
46542
|
return;
|
|
@@ -46483,44 +46551,109 @@ class NerdStats extends UICorePlugin {
|
|
|
46483
46551
|
prefix + videoQualityNames[liveQuality - 1];
|
|
46484
46552
|
}
|
|
46485
46553
|
updateMetrics(metrics) {
|
|
46554
|
+
trace(`${T$e} updateMetrics`, { custom: this.speedtestMetrics });
|
|
46486
46555
|
Object.assign(this.metrics, metrics);
|
|
46487
|
-
this.
|
|
46488
|
-
this
|
|
46489
|
-
|
|
46490
|
-
|
|
46491
|
-
|
|
46492
|
-
|
|
46493
|
-
|
|
46556
|
+
this.updateEstimatedQuality();
|
|
46557
|
+
this.$el
|
|
46558
|
+
.find('#nerd-stats-current-time')
|
|
46559
|
+
.text(Formatter.formatTime(this.metrics.extra.currentTime));
|
|
46560
|
+
this.$el
|
|
46561
|
+
.find('#nerd-stats-video-duration')
|
|
46562
|
+
.text(Formatter.formatTime(this.metrics.extra.duration));
|
|
46563
|
+
this.$el
|
|
46564
|
+
.find('#nerd-stats-buffer-size')
|
|
46565
|
+
.text(Formatter.formatTime(this.metrics.extra.buffersize));
|
|
46566
|
+
this.$el
|
|
46567
|
+
.find('#nerd-stats-bitrate-weighted-mean')
|
|
46568
|
+
.text(Formatter.formatBitrate(this.metrics.extra.bitrateWeightedMean));
|
|
46569
|
+
this.$el
|
|
46570
|
+
.find('#nerd-stats-bitrate-most-used')
|
|
46571
|
+
.text(Formatter.formatBitrate(this.metrics.extra.bitrateMostUsed));
|
|
46572
|
+
this.$el
|
|
46573
|
+
.find('#nerd-stats-watched-percentage')
|
|
46574
|
+
.text(Formatter.formatPercentage(this.metrics.extra.watchedPercentage));
|
|
46575
|
+
this.$el
|
|
46576
|
+
.find('#nerd-stats-buffering-percentage')
|
|
46577
|
+
.text(Formatter.formatPercentage(this.metrics.extra.bufferingPercentage));
|
|
46578
|
+
this.$el
|
|
46579
|
+
.find('#nerd-stats-startup-time')
|
|
46580
|
+
.text(Formatter.formatTime(this.metrics.chrono.startup));
|
|
46581
|
+
this.$el
|
|
46582
|
+
.find('#nerd-stats-watch-time')
|
|
46583
|
+
.text(Formatter.formatTime(this.metrics.chrono.watch));
|
|
46584
|
+
this.$el
|
|
46585
|
+
.find('#nerd-stats-pause-time')
|
|
46586
|
+
.text(Formatter.formatTime(this.metrics.chrono.pause));
|
|
46587
|
+
this.$el
|
|
46588
|
+
.find('#nerd-stats-buffering-time')
|
|
46589
|
+
.text(Formatter.formatTime(this.metrics.chrono.buffering));
|
|
46590
|
+
this.$el
|
|
46591
|
+
.find('#nerd-stats-session-time')
|
|
46592
|
+
.text(Formatter.formatTime(this.metrics.chrono.session));
|
|
46593
|
+
this.$el.find('#nerd-stats-plays').text(this.metrics.counters.play);
|
|
46594
|
+
this.$el.find('#nerd-stats-pauses').text(this.metrics.counters.pause);
|
|
46595
|
+
this.$el.find('#nerd-stats-errors').text(this.metrics.counters.error);
|
|
46596
|
+
this.$el
|
|
46597
|
+
.find('#nerd-stats-bufferings')
|
|
46598
|
+
.text(this.metrics.counters.buffering);
|
|
46599
|
+
this.$el
|
|
46600
|
+
.find('#nerd-stats-decoded-frames')
|
|
46601
|
+
.text(this.metrics.counters.decodedFrames);
|
|
46602
|
+
this.$el
|
|
46603
|
+
.find('#nerd-stats-dropped-frames')
|
|
46604
|
+
.text(this.metrics.counters.droppedFrames);
|
|
46605
|
+
this.$el
|
|
46606
|
+
.find('#nerd-stats-bitrate-changes')
|
|
46607
|
+
.text(this.metrics.counters.changeLevel);
|
|
46608
|
+
this.$el.find('#nerd-stats-seeks').text(this.metrics.counters.seek);
|
|
46609
|
+
this.$el
|
|
46610
|
+
.find('#nerd-stats-fullscreen')
|
|
46611
|
+
.text(this.metrics.counters.fullscreen);
|
|
46612
|
+
this.$el.find('#nerd-stats-dvr-usage').text(this.metrics.counters.dvrUsage);
|
|
46613
|
+
this.$el
|
|
46614
|
+
.find('#nerd-stats-fps')
|
|
46615
|
+
.text(Formatter.formatFps(this.metrics.counters.fps));
|
|
46494
46616
|
this.setStatsBoxSize();
|
|
46495
46617
|
drawSpeedTestResults();
|
|
46496
|
-
drawSummary(this.
|
|
46497
|
-
|
|
46498
|
-
if (!this.showing) {
|
|
46618
|
+
drawSummary(this.speedtestMetrics, this.$el.find('#nerd-stats-quality-vod'), this.$el.find('#nerd-stats-quality-live'));
|
|
46619
|
+
if (!this.open) {
|
|
46499
46620
|
this.hide();
|
|
46500
46621
|
}
|
|
46501
46622
|
}
|
|
46623
|
+
updateEstimatedQuality() {
|
|
46624
|
+
this.estimateQuality();
|
|
46625
|
+
this.$el
|
|
46626
|
+
.find('#nerd-stats-quality-vod-text')
|
|
46627
|
+
.html(this.metrics.custom.vodQuality);
|
|
46628
|
+
this.$el
|
|
46629
|
+
.find('#nerd-stats-quality-live-text')
|
|
46630
|
+
.html(this.metrics.custom.liveQuality);
|
|
46631
|
+
}
|
|
46502
46632
|
setStatsBoxSize() {
|
|
46503
46633
|
if (this.playerWidth >= this.statsBoxWidthThreshold) {
|
|
46504
|
-
this
|
|
46505
|
-
this
|
|
46634
|
+
this.statsBoxElem.addClass('wide');
|
|
46635
|
+
this.statsBoxElem.removeClass('narrow');
|
|
46506
46636
|
}
|
|
46507
46637
|
else {
|
|
46508
|
-
this
|
|
46509
|
-
this
|
|
46638
|
+
this.statsBoxElem.removeClass('wide');
|
|
46639
|
+
this.statsBoxElem.addClass('narrow');
|
|
46510
46640
|
}
|
|
46511
46641
|
}
|
|
46512
46642
|
/**
|
|
46513
46643
|
* @internal
|
|
46514
46644
|
*/
|
|
46515
46645
|
render() {
|
|
46516
|
-
|
|
46517
|
-
|
|
46518
|
-
|
|
46519
|
-
|
|
46646
|
+
this.$el
|
|
46647
|
+
.html(NerdStats.template({
|
|
46648
|
+
metrics: Formatter.format(this.metrics ?? newMetrics()),
|
|
46649
|
+
iconPosition: this.iconPosition,
|
|
46650
|
+
i18n: this.core.i18n,
|
|
46651
|
+
}))
|
|
46652
|
+
.hide();
|
|
46520
46653
|
return this;
|
|
46521
46654
|
}
|
|
46522
|
-
|
|
46523
|
-
trace(`${T$
|
|
46655
|
+
attach() {
|
|
46656
|
+
trace(`${T$e} attach`);
|
|
46524
46657
|
const gear = this.core.getPlugin('bottom_gear');
|
|
46525
46658
|
gear
|
|
46526
46659
|
.addItem('nerd_stats')
|
|
@@ -46533,11 +46666,11 @@ class NerdStats extends UICorePlugin {
|
|
|
46533
46666
|
this.toggle();
|
|
46534
46667
|
});
|
|
46535
46668
|
}
|
|
46536
|
-
|
|
46669
|
+
clearSpeedtestMetrics() {
|
|
46537
46670
|
const clapprStats = this.container?.getPlugin('clappr_stats');
|
|
46538
|
-
this.
|
|
46539
|
-
this.
|
|
46540
|
-
this.
|
|
46671
|
+
this.speedtestMetrics.connectionSpeed = 0;
|
|
46672
|
+
this.speedtestMetrics.ping = 0;
|
|
46673
|
+
this.speedtestMetrics.jitter = 0;
|
|
46541
46674
|
if (clapprStats) {
|
|
46542
46675
|
this.updateMetrics(clapprStats.exportMetrics());
|
|
46543
46676
|
}
|
|
@@ -46545,7 +46678,7 @@ class NerdStats extends UICorePlugin {
|
|
|
46545
46678
|
refreshSpeedTest() {
|
|
46546
46679
|
stopSpeedtest();
|
|
46547
46680
|
setTimeout(() => {
|
|
46548
|
-
this.
|
|
46681
|
+
this.clearSpeedtestMetrics();
|
|
46549
46682
|
clearSpeedTestResults();
|
|
46550
46683
|
drawSpeedTestResults();
|
|
46551
46684
|
}, 200);
|
|
@@ -46553,11 +46686,28 @@ class NerdStats extends UICorePlugin {
|
|
|
46553
46686
|
startSpeedtest();
|
|
46554
46687
|
}, 800);
|
|
46555
46688
|
}
|
|
46689
|
+
formatPlaybackName(playbackType) {
|
|
46690
|
+
switch (playbackType) {
|
|
46691
|
+
case Playback.VOD:
|
|
46692
|
+
return this.core.i18n.t('vod');
|
|
46693
|
+
case Playback.LIVE:
|
|
46694
|
+
return this.core.i18n.t('live');
|
|
46695
|
+
default:
|
|
46696
|
+
return '-';
|
|
46697
|
+
}
|
|
46698
|
+
}
|
|
46556
46699
|
}
|
|
46557
46700
|
function newMetrics() {
|
|
46558
46701
|
return {
|
|
46559
46702
|
...newMetrics$1(),
|
|
46560
|
-
general: {
|
|
46703
|
+
general: {
|
|
46704
|
+
displayResolution: '',
|
|
46705
|
+
resolution: {
|
|
46706
|
+
width: 0,
|
|
46707
|
+
height: 0,
|
|
46708
|
+
},
|
|
46709
|
+
volume: 0,
|
|
46710
|
+
},
|
|
46561
46711
|
custom: {
|
|
46562
46712
|
connectionSpeed: 0,
|
|
46563
46713
|
ping: 0,
|
|
@@ -46570,7 +46720,7 @@ function newMetrics() {
|
|
|
46570
46720
|
// Copyright 2014 Globo.com Player authors. All rights reserved.
|
|
46571
46721
|
// Use of this source code is governed by a BSD-style
|
|
46572
46722
|
// license that can be found at https://github.com/clappr/clappr-plugins/blob/master/LICENSE.
|
|
46573
|
-
const T$
|
|
46723
|
+
const T$d = 'plugins.click_to_pause';
|
|
46574
46724
|
/**
|
|
46575
46725
|
* A small `PLUGIN` that toggles the playback state on click over the video container
|
|
46576
46726
|
* @beta
|
|
@@ -46582,7 +46732,7 @@ class ClickToPause extends ContainerPlugin {
|
|
|
46582
46732
|
* @internal
|
|
46583
46733
|
*/
|
|
46584
46734
|
get name() {
|
|
46585
|
-
return '
|
|
46735
|
+
return 'click_to_pause';
|
|
46586
46736
|
}
|
|
46587
46737
|
/**
|
|
46588
46738
|
* @internal
|
|
@@ -46600,7 +46750,7 @@ class ClickToPause extends ContainerPlugin {
|
|
|
46600
46750
|
click() {
|
|
46601
46751
|
const isLivePlayback = this.container.getPlaybackType() === Playback.LIVE;
|
|
46602
46752
|
const isDvrEnabled = this.container.isDvrEnabled();
|
|
46603
|
-
trace(`${T$
|
|
46753
|
+
trace(`${T$d} click`, {
|
|
46604
46754
|
isLivePlayback,
|
|
46605
46755
|
isDvrEnabled,
|
|
46606
46756
|
});
|
|
@@ -46715,7 +46865,7 @@ function buildSvg(clips, duration, barWidth) {
|
|
|
46715
46865
|
|
|
46716
46866
|
const clipsHTML = "<div class=\"media-clip-text\" id=\"clips-text\"></div>";
|
|
46717
46867
|
|
|
46718
|
-
const T$
|
|
46868
|
+
const T$c = 'plugins.clips';
|
|
46719
46869
|
const VERSION$5 = '2.22.16';
|
|
46720
46870
|
const CLAPPR_VERSION = '0.11.4';
|
|
46721
46871
|
/**
|
|
@@ -46765,7 +46915,7 @@ class Clips extends UICorePlugin {
|
|
|
46765
46915
|
this.listenTo(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onContainerChanged);
|
|
46766
46916
|
}
|
|
46767
46917
|
render() {
|
|
46768
|
-
trace(`${T$
|
|
46918
|
+
trace(`${T$c} render`);
|
|
46769
46919
|
if (!this.options.clips) {
|
|
46770
46920
|
return this;
|
|
46771
46921
|
}
|
|
@@ -46792,19 +46942,19 @@ class Clips extends UICorePlugin {
|
|
|
46792
46942
|
return super.enable();
|
|
46793
46943
|
}
|
|
46794
46944
|
onCoreReady() {
|
|
46795
|
-
trace(`${T$
|
|
46945
|
+
trace(`${T$c} onCoreReady`);
|
|
46796
46946
|
const mediaControl = this.core.getPlugin('media_control');
|
|
46797
46947
|
assert(mediaControl, 'media_control plugin is required');
|
|
46798
46948
|
this.parseClips(this.options.clips.text);
|
|
46799
46949
|
this.listenTo(mediaControl, Events$1.MEDIACONTROL_RENDERED, this.onMcRender);
|
|
46800
46950
|
}
|
|
46801
46951
|
onMcRender() {
|
|
46802
|
-
trace(`${T$
|
|
46952
|
+
trace(`${T$c} onMcRender`);
|
|
46803
46953
|
const mediaControl = this.core.getPlugin('media_control');
|
|
46804
46954
|
mediaControl.mount('clips', this.$el);
|
|
46805
46955
|
}
|
|
46806
46956
|
onContainerChanged() {
|
|
46807
|
-
trace(`${T$
|
|
46957
|
+
trace(`${T$c} onContainerChanged`);
|
|
46808
46958
|
// TODO figure out the conditions of changing the container (without destroying the previous one)
|
|
46809
46959
|
if (this.oldContainer) {
|
|
46810
46960
|
this.stopListening(this.oldContainer, Events$1.CONTAINER_TIMEUPDATE, this.onTimeUpdate);
|
|
@@ -46982,7 +47132,7 @@ class ContextMenu extends UIContainerPlugin {
|
|
|
46982
47132
|
|
|
46983
47133
|
const dvrHTML = "<div class=\"live-info\" id=\"media-control-live\"><%= i18n.t('live') %></div>\n<button type=\"button\" class=\"live-button\" aria-label=\"<%= i18n.t('back_to_live') %>\" id=\"media-control-back-to-live\"><%= i18n.t('back_to_live') %></button>\n";
|
|
46984
47134
|
|
|
46985
|
-
const T
|
|
47135
|
+
// const T = 'plugins.dvr_controls'
|
|
46986
47136
|
/**
|
|
46987
47137
|
* `PLUGIN` that adds the DVR controls to the media control UI
|
|
46988
47138
|
*
|
|
@@ -47031,19 +47181,17 @@ class DvrControls extends UICorePlugin {
|
|
|
47031
47181
|
* @internal
|
|
47032
47182
|
*/
|
|
47033
47183
|
bindEvents() {
|
|
47034
|
-
this.
|
|
47035
|
-
this.listenTo(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.
|
|
47184
|
+
this.listenToOnce(this.core, Events$1.CORE_READY, this.onCoreReady);
|
|
47185
|
+
this.listenTo(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
|
|
47036
47186
|
}
|
|
47037
47187
|
onCoreReady() {
|
|
47038
47188
|
const mediaControl = this.core.getPlugin('media_control');
|
|
47039
47189
|
assert(mediaControl, 'media_control plugin is required');
|
|
47040
|
-
this.listenTo(mediaControl, Events$1.MEDIACONTROL_RENDERED, this.
|
|
47041
|
-
// MediaControl has been rendered
|
|
47042
|
-
this.render();
|
|
47190
|
+
this.listenTo(mediaControl, Events$1.MEDIACONTROL_RENDERED, this.mount);
|
|
47043
47191
|
}
|
|
47044
|
-
|
|
47045
|
-
|
|
47046
|
-
this.
|
|
47192
|
+
onActiveContainerChanged() {
|
|
47193
|
+
this.listenTo(this.core.activeContainer, Events$1.CONTAINER_LOADEDMETADATA, this.onMetadataLoaded);
|
|
47194
|
+
this.listenTo(this.core.activeContainer, Events$1.CONTAINER_PLAYBACKDVRSTATECHANGED, this.onDvrStateChanged);
|
|
47047
47195
|
}
|
|
47048
47196
|
click() {
|
|
47049
47197
|
const container = this.core.activeContainer;
|
|
@@ -47052,32 +47200,47 @@ class DvrControls extends UICorePlugin {
|
|
|
47052
47200
|
}
|
|
47053
47201
|
container.seek(container.getDuration());
|
|
47054
47202
|
}
|
|
47055
|
-
shouldRender() {
|
|
47056
|
-
return this.core.getPlaybackType() === Playback.LIVE;
|
|
47057
|
-
}
|
|
47058
47203
|
/**
|
|
47059
47204
|
* @internal
|
|
47060
47205
|
*/
|
|
47061
47206
|
render() {
|
|
47062
|
-
trace(`${T$c} render`, {
|
|
47063
|
-
dvrEnabled: this.core.activePlayback?.dvrEnabled,
|
|
47064
|
-
playbackType: this.core.getPlaybackType(),
|
|
47065
|
-
});
|
|
47066
|
-
const mediaControl = this.core.getPlugin('media_control');
|
|
47067
|
-
if (!mediaControl) {
|
|
47068
|
-
return this;
|
|
47069
|
-
}
|
|
47070
|
-
if (!this.shouldRender()) {
|
|
47071
|
-
return this;
|
|
47072
|
-
}
|
|
47073
|
-
mediaControl.toggleElement('duration', false);
|
|
47074
|
-
mediaControl.toggleElement('position', false);
|
|
47075
47207
|
this.$el.html(DvrControls.template({
|
|
47076
47208
|
i18n: this.core.i18n,
|
|
47077
47209
|
}));
|
|
47078
|
-
mediaControl.putElement('dvr', this.$el);
|
|
47079
47210
|
return this;
|
|
47080
47211
|
}
|
|
47212
|
+
onMediacontrolRendered() {
|
|
47213
|
+
this.render();
|
|
47214
|
+
}
|
|
47215
|
+
onMetadataLoaded() {
|
|
47216
|
+
this.mount();
|
|
47217
|
+
this.toggleState(this.core.activeContainer.isDvrInUse());
|
|
47218
|
+
}
|
|
47219
|
+
mount() {
|
|
47220
|
+
// TODO move mount point management logic to MediaControl
|
|
47221
|
+
if (this.core.getPlaybackType() !== Playback.LIVE) {
|
|
47222
|
+
return;
|
|
47223
|
+
}
|
|
47224
|
+
const mediaControl = this.core.getPlugin('media_control');
|
|
47225
|
+
assert(mediaControl, 'media_control plugin is required');
|
|
47226
|
+
// TODO -> to MediaControl
|
|
47227
|
+
mediaControl.toggleElement('duration', false);
|
|
47228
|
+
mediaControl.toggleElement('position', false);
|
|
47229
|
+
mediaControl.mount('dvr', this.$el);
|
|
47230
|
+
}
|
|
47231
|
+
onDvrStateChanged(dvrInUse) {
|
|
47232
|
+
this.toggleState(dvrInUse);
|
|
47233
|
+
}
|
|
47234
|
+
toggleState(dvrInUse) {
|
|
47235
|
+
if (dvrInUse) {
|
|
47236
|
+
this.$el.find('#media-control-back-to-live').show();
|
|
47237
|
+
this.$el.find('#media-control-live').hide();
|
|
47238
|
+
}
|
|
47239
|
+
else {
|
|
47240
|
+
this.$el.find('#media-control-back-to-live').hide();
|
|
47241
|
+
this.$el.find('#media-control-live').show();
|
|
47242
|
+
}
|
|
47243
|
+
}
|
|
47081
47244
|
}
|
|
47082
47245
|
|
|
47083
47246
|
const reloadIcon = "<svg fill=\"#FFFFFF\" height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"/>\n <path d=\"M0 0h24v24H0z\" fill=\"none\"/>\n</svg>";
|
|
@@ -47887,8 +48050,6 @@ const DEFAULT_SETTINGS = {
|
|
|
47887
48050
|
right: [
|
|
47888
48051
|
'audiotracks',
|
|
47889
48052
|
'cc',
|
|
47890
|
-
// 'dvr',
|
|
47891
|
-
// 'duration',
|
|
47892
48053
|
'fullscreen',
|
|
47893
48054
|
'gear',
|
|
47894
48055
|
'multicamera',
|
|
@@ -47905,10 +48066,10 @@ const T$a = 'plugins.media_control';
|
|
|
47905
48066
|
const LEFT_ORDER = [
|
|
47906
48067
|
'playpause',
|
|
47907
48068
|
'playstop',
|
|
47908
|
-
'dvr',
|
|
47909
48069
|
'volume',
|
|
47910
48070
|
'position',
|
|
47911
48071
|
'duration',
|
|
48072
|
+
'dvr',
|
|
47912
48073
|
];
|
|
47913
48074
|
const { Config, Fullscreen, formatTime: formatTime$1, extend, removeArrayItem } = Utils;
|
|
47914
48075
|
function orderByOrderPattern(arr, order) {
|
|
@@ -48555,8 +48716,7 @@ class MediaControl extends UICorePlugin {
|
|
|
48555
48716
|
}
|
|
48556
48717
|
this.$el.show();
|
|
48557
48718
|
this.trigger(Events$1.MEDIACONTROL_SHOW, this.name);
|
|
48558
|
-
this.
|
|
48559
|
-
this.container.trigger(Events$1.CONTAINER_MEDIACONTROL_SHOW, this.name);
|
|
48719
|
+
this.core.activeContainer?.trigger(Events$1.CONTAINER_MEDIACONTROL_SHOW, this.name);
|
|
48560
48720
|
this.$el.removeClass('media-control-hide');
|
|
48561
48721
|
this.hideId = setTimeout(() => this.hide(), timeout);
|
|
48562
48722
|
if (event) {
|
|
@@ -48610,7 +48770,7 @@ class MediaControl extends UICorePlugin {
|
|
|
48610
48770
|
right: [],
|
|
48611
48771
|
}, this.core.activeContainer.settings);
|
|
48612
48772
|
trace(`${T$a} updateSettings`, { newSettings });
|
|
48613
|
-
newSettings.left.push('clips'); // TODO
|
|
48773
|
+
newSettings.left.push('clips'); // TODO settings
|
|
48614
48774
|
// TODO make order controlled via CSS
|
|
48615
48775
|
newSettings.left = orderByOrderPattern([...newSettings.left, 'volume', 'clips'], LEFT_ORDER);
|
|
48616
48776
|
if (this.core.activePlayback.getPlaybackType() === Playback.LIVE &&
|
|
@@ -48673,7 +48833,6 @@ class MediaControl extends UICorePlugin {
|
|
|
48673
48833
|
* Get a media control element DOM node
|
|
48674
48834
|
* @param name - The name of the media control element
|
|
48675
48835
|
* @returns The DOM node to render to or extend
|
|
48676
|
-
* @deprecated Use {@link MediaControl.putElement} instead
|
|
48677
48836
|
* @remarks
|
|
48678
48837
|
* Use this method to render custom media control UI in a plugin
|
|
48679
48838
|
* @example
|
|
@@ -48689,7 +48848,7 @@ class MediaControl extends UICorePlugin {
|
|
|
48689
48848
|
*/
|
|
48690
48849
|
mount(name, element) {
|
|
48691
48850
|
const panel = this.getElementLocation(name);
|
|
48692
|
-
trace(`${T$a}
|
|
48851
|
+
trace(`${T$a} mount`, { name, panel: !!panel });
|
|
48693
48852
|
if (panel) {
|
|
48694
48853
|
const current = panel.find(`[data-${name}]`);
|
|
48695
48854
|
element.attr(`data-${name}`, '');
|
|
@@ -48706,13 +48865,18 @@ class MediaControl extends UICorePlugin {
|
|
|
48706
48865
|
return;
|
|
48707
48866
|
}
|
|
48708
48867
|
}
|
|
48868
|
+
/**
|
|
48869
|
+
* @deprecated Use {@link MediaControl.mount} instead
|
|
48870
|
+
* @param name
|
|
48871
|
+
* @param element
|
|
48872
|
+
*/
|
|
48709
48873
|
putElement(name, element) {
|
|
48710
48874
|
this.mount(name, element);
|
|
48711
48875
|
}
|
|
48712
48876
|
/**
|
|
48713
48877
|
* Toggle the visibility of a media control element
|
|
48714
48878
|
* @param name - The name of the media control element
|
|
48715
|
-
* @param show -
|
|
48879
|
+
* @param show - Visibility state
|
|
48716
48880
|
*/
|
|
48717
48881
|
toggleElement(area, show) {
|
|
48718
48882
|
this.$el.find(`[data-${area}]`).toggle(show);
|
|
@@ -48928,6 +49092,7 @@ class MediaControl extends UICorePlugin {
|
|
|
48928
49092
|
width: this.options.width,
|
|
48929
49093
|
height: this.options.height,
|
|
48930
49094
|
});
|
|
49095
|
+
// TODO check out
|
|
48931
49096
|
this.hideVolumeBar(0);
|
|
48932
49097
|
}, 0);
|
|
48933
49098
|
this.parseColors();
|
|
@@ -49483,7 +49648,7 @@ class PictureInPicture extends UICorePlugin {
|
|
|
49483
49648
|
this.$el.html(PictureInPicture.buttonTemplate({ pipIcon }));
|
|
49484
49649
|
const mediaControl = this.core.getPlugin('media_control');
|
|
49485
49650
|
if (mediaControl) {
|
|
49486
|
-
mediaControl.
|
|
49651
|
+
mediaControl.mount('pip', this.$el);
|
|
49487
49652
|
}
|
|
49488
49653
|
return this;
|
|
49489
49654
|
}
|
|
@@ -50416,7 +50581,7 @@ class SeekTime extends UICorePlugin {
|
|
|
50416
50581
|
this.listenTo(this.mediaControl, Events$1.MEDIACONTROL_CONTAINERCHANGED, this.onContainerChanged);
|
|
50417
50582
|
if (this.mediaControlContainer) {
|
|
50418
50583
|
this.listenTo(this.mediaControlContainer, Events$1.CONTAINER_PLAYBACKDVRSTATECHANGED, this.update);
|
|
50419
|
-
this.listenTo(this.mediaControlContainer, Events$1.CONTAINER_TIMEUPDATE, this.
|
|
50584
|
+
this.listenTo(this.mediaControlContainer, Events$1.CONTAINER_TIMEUPDATE, this.onTimeUpdate);
|
|
50420
50585
|
}
|
|
50421
50586
|
}
|
|
50422
50587
|
onContainerChanged() {
|
|
@@ -50424,9 +50589,8 @@ class SeekTime extends UICorePlugin {
|
|
|
50424
50589
|
this.stopListening();
|
|
50425
50590
|
this.bindEvents();
|
|
50426
50591
|
}
|
|
50427
|
-
|
|
50428
|
-
this.duration =
|
|
50429
|
-
// this.firstFragDateTime = timeProgress.firstFragDateTime;
|
|
50592
|
+
onTimeUpdate({ total }) {
|
|
50593
|
+
this.duration = total;
|
|
50430
50594
|
this.update();
|
|
50431
50595
|
}
|
|
50432
50596
|
showTime(event) {
|
|
@@ -51388,7 +51552,7 @@ class ClosedCaptions extends UICorePlugin {
|
|
|
51388
51552
|
this.$line = $(ClosedCaptions.templateString());
|
|
51389
51553
|
this.resizeFont();
|
|
51390
51554
|
this.core.activeContainer.$el.append(this.$line);
|
|
51391
|
-
mediaControl.
|
|
51555
|
+
mediaControl.mount('cc', this.$el);
|
|
51392
51556
|
this.updateSelection();
|
|
51393
51557
|
this.renderIcon();
|
|
51394
51558
|
return this;
|
|
@@ -52326,4 +52490,4 @@ class VolumeFade extends UICorePlugin {
|
|
|
52326
52490
|
}
|
|
52327
52491
|
}
|
|
52328
52492
|
|
|
52329
|
-
export { AudioTracks as AudioSelector, AudioTracks, BigMuteButton, BottomGear, NerdStats as ClapprNerdStats, ClapprStats, ClickToPause, Clips, ClosedCaptions, ContextMenu, DvrControls, ErrorScreen, Favicon, GearEvents, GoogleAnalytics, QualityLevels as LevelSelector, LogTracer, Logger, Logo, MediaControl, MultiCamera, NerdStats, PictureInPicture, PlaybackErrorCode, PlaybackRate, Player, PlayerEvent, Poster, QualityLevels, SeekTime, SentryTracer, Share, SkipTime, SourceController, SpinnerThreeBounce as Spinner, SpinnerEvents, SpinnerThreeBounce, ClosedCaptions as Subtitles, Telemetry, TelemetryEvent, Thumbnails, VolumeFade, VolumeFadeEvents, reportError, setTracer, trace, version };
|
|
52493
|
+
export { AudioTracks as AudioSelector, AudioTracks, BigMuteButton, BottomGear, NerdStats as ClapprNerdStats, ClapprStats, ClapprStatsChronograph, ClapprStatsCounter, ClapprStatsEvents, ClickToPause, Clips, ClosedCaptions, ContextMenu, DvrControls, ErrorScreen, Favicon, GearEvents, GoogleAnalytics, QualityLevels as LevelSelector, LogTracer, Logger, Logo, MediaControl, MultiCamera, NerdStats, PictureInPicture, PlaybackErrorCode, PlaybackRate, Player, PlayerEvent, Poster, QualityLevels, SeekTime, SentryTracer, Share, SkipTime, SourceController, SpinnerThreeBounce as Spinner, SpinnerEvents, SpinnerThreeBounce, ClosedCaptions as Subtitles, Telemetry, TelemetryEvent, Thumbnails, VolumeFade, VolumeFadeEvents, reportError, setTracer, trace, version };
|