@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/plugins/index.js
CHANGED
|
@@ -9767,10 +9767,11 @@ function ifError(err) {
|
|
|
9767
9767
|
// export const CLAPPR_VERSION: string = process.env.CLAPPR_VERSION || '0.11.3';
|
|
9768
9768
|
const CLAPPR_VERSION$1 = '0.11.3';
|
|
9769
9769
|
|
|
9770
|
-
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";
|
|
9770
|
+
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";
|
|
9771
9771
|
|
|
9772
9772
|
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";
|
|
9773
9773
|
|
|
9774
|
+
// import { trace } from '@gcorevideo/utils'
|
|
9774
9775
|
const VERSION$7 = '2.22.4';
|
|
9775
9776
|
// const T = 'plugins.audiotracks'
|
|
9776
9777
|
/**
|
|
@@ -9833,7 +9834,7 @@ class AudioTracks extends UICorePlugin {
|
|
|
9833
9834
|
const mediaControl = this.core.getPlugin('media_control');
|
|
9834
9835
|
assert(mediaControl, 'media_control plugin is required');
|
|
9835
9836
|
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, () => {
|
|
9836
|
-
mediaControl.
|
|
9837
|
+
mediaControl.mount('audiotracks', this.$el);
|
|
9837
9838
|
});
|
|
9838
9839
|
this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideMenu);
|
|
9839
9840
|
}
|
|
@@ -9864,18 +9865,18 @@ class AudioTracks extends UICorePlugin {
|
|
|
9864
9865
|
if (!this.shouldRender()) {
|
|
9865
9866
|
return this;
|
|
9866
9867
|
}
|
|
9867
|
-
this.core.getPlugin('media_control');
|
|
9868
9868
|
this.$el.html(AudioTracks.template({
|
|
9869
9869
|
tracks: this.tracks,
|
|
9870
9870
|
title: this.getTitle(),
|
|
9871
9871
|
icon: audioArrow,
|
|
9872
|
+
current: this.currentTrack?.id,
|
|
9872
9873
|
}));
|
|
9873
9874
|
this.updateText();
|
|
9874
9875
|
this.highlightCurrentTrack();
|
|
9875
9876
|
return this;
|
|
9876
9877
|
}
|
|
9877
9878
|
onTrackSelect(event) {
|
|
9878
|
-
const id = event.
|
|
9879
|
+
const id = event.currentTarget?.dataset?.audiotracksSelect;
|
|
9879
9880
|
if (id) {
|
|
9880
9881
|
this.selectAudioTrack(id);
|
|
9881
9882
|
}
|
|
@@ -9884,7 +9885,7 @@ class AudioTracks extends UICorePlugin {
|
|
|
9884
9885
|
return false;
|
|
9885
9886
|
}
|
|
9886
9887
|
selectAudioTrack(id) {
|
|
9887
|
-
this.
|
|
9888
|
+
this.startTrackSwitching();
|
|
9888
9889
|
this.core.activeContainer.switchAudioTrack(id);
|
|
9889
9890
|
this.updateText();
|
|
9890
9891
|
}
|
|
@@ -9892,7 +9893,9 @@ class AudioTracks extends UICorePlugin {
|
|
|
9892
9893
|
this.$el.find('#audiotracks-select').addClass('hidden');
|
|
9893
9894
|
}
|
|
9894
9895
|
toggleContextMenu() {
|
|
9895
|
-
this.$el.find('#audiotracks-select').toggleClass('hidden');
|
|
9896
|
+
this.$el.find('#audiotracks-select').toggleClass('hidden'); // TODO use plain CSS display: none
|
|
9897
|
+
const open = !this.$el.find('#audiotracks-select').hasClass('hidden'); // TODO hold state
|
|
9898
|
+
this.$el.find('#audiotracks-button').attr('aria-expanded', open);
|
|
9896
9899
|
}
|
|
9897
9900
|
buttonElement() {
|
|
9898
9901
|
return this.$('button');
|
|
@@ -9910,7 +9913,7 @@ class AudioTracks extends UICorePlugin {
|
|
|
9910
9913
|
}
|
|
9911
9914
|
return this.currentTrack.label || this.currentTrack.language;
|
|
9912
9915
|
}
|
|
9913
|
-
|
|
9916
|
+
startTrackSwitching() {
|
|
9914
9917
|
this.buttonElement().addClass('changing');
|
|
9915
9918
|
}
|
|
9916
9919
|
updateText() {
|
|
@@ -9921,12 +9924,16 @@ class AudioTracks extends UICorePlugin {
|
|
|
9921
9924
|
}
|
|
9922
9925
|
highlightCurrentTrack() {
|
|
9923
9926
|
this.trackElement().removeClass('current');
|
|
9924
|
-
this.trackElement()
|
|
9927
|
+
this.trackElement()
|
|
9928
|
+
.find('a')
|
|
9929
|
+
.removeClass('gcore-skin-active')
|
|
9930
|
+
.attr('aria-checked', 'false');
|
|
9925
9931
|
if (this.currentTrack) {
|
|
9926
9932
|
this.trackElement(this.currentTrack.id)
|
|
9927
9933
|
.addClass('current')
|
|
9928
9934
|
.find('a')
|
|
9929
|
-
.addClass('gcore-skin-active')
|
|
9935
|
+
.addClass('gcore-skin-active')
|
|
9936
|
+
.attr('aria-checked', 'true');
|
|
9930
9937
|
}
|
|
9931
9938
|
}
|
|
9932
9939
|
}
|
|
@@ -10080,7 +10087,7 @@ class BigMuteButton extends UICorePlugin {
|
|
|
10080
10087
|
}
|
|
10081
10088
|
}
|
|
10082
10089
|
|
|
10083
|
-
const pluginHtml$5 = "<button
|
|
10090
|
+
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";
|
|
10084
10091
|
|
|
10085
10092
|
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";
|
|
10086
10093
|
|
|
@@ -10094,7 +10101,7 @@ const VERSION$6 = '2.19.12';
|
|
|
10094
10101
|
var GearEvents;
|
|
10095
10102
|
(function (GearEvents) {
|
|
10096
10103
|
/**
|
|
10097
|
-
*
|
|
10104
|
+
* Subscribe to this event to accurately attach an item to the gear menu
|
|
10098
10105
|
*/
|
|
10099
10106
|
GearEvents["RENDERED"] = "rendered";
|
|
10100
10107
|
})(GearEvents || (GearEvents = {}));
|
|
@@ -10306,39 +10313,39 @@ class BottomGear extends UICorePlugin {
|
|
|
10306
10313
|
}
|
|
10307
10314
|
onMediaControlRendered() {
|
|
10308
10315
|
const mediaControl = this.core.getPlugin('media_control');
|
|
10309
|
-
mediaControl.
|
|
10316
|
+
mediaControl.mount('gear', this.$el);
|
|
10310
10317
|
}
|
|
10311
10318
|
}
|
|
10312
10319
|
|
|
10313
10320
|
/**
|
|
10314
10321
|
* @beta
|
|
10315
10322
|
*/
|
|
10316
|
-
var
|
|
10317
|
-
(function (
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
+
var ClapprStatsChronograph;
|
|
10324
|
+
(function (ClapprStatsChronograph) {
|
|
10325
|
+
ClapprStatsChronograph["Startup"] = "startup";
|
|
10326
|
+
ClapprStatsChronograph["Watch"] = "watch";
|
|
10327
|
+
ClapprStatsChronograph["Pause"] = "pause";
|
|
10328
|
+
ClapprStatsChronograph["Buffering"] = "buffering";
|
|
10329
|
+
ClapprStatsChronograph["Session"] = "session";
|
|
10323
10330
|
// Latency = 'latency',
|
|
10324
|
-
})(
|
|
10331
|
+
})(ClapprStatsChronograph || (ClapprStatsChronograph = {}));
|
|
10325
10332
|
/**
|
|
10326
10333
|
* @beta
|
|
10327
10334
|
*/
|
|
10328
|
-
var
|
|
10329
|
-
(function (
|
|
10330
|
-
|
|
10331
|
-
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
|
|
10341
|
-
})(
|
|
10335
|
+
var ClapprStatsCounter;
|
|
10336
|
+
(function (ClapprStatsCounter) {
|
|
10337
|
+
ClapprStatsCounter["Play"] = "play";
|
|
10338
|
+
ClapprStatsCounter["Pause"] = "pause";
|
|
10339
|
+
ClapprStatsCounter["Error"] = "error";
|
|
10340
|
+
ClapprStatsCounter["Buffering"] = "buffering";
|
|
10341
|
+
ClapprStatsCounter["DecodedFrames"] = "decodedFrames";
|
|
10342
|
+
ClapprStatsCounter["DroppedFrames"] = "droppedFrames";
|
|
10343
|
+
ClapprStatsCounter["Fps"] = "fps";
|
|
10344
|
+
ClapprStatsCounter["ChangeLevel"] = "changeLevel";
|
|
10345
|
+
ClapprStatsCounter["Seek"] = "seek";
|
|
10346
|
+
ClapprStatsCounter["Fullscreen"] = "fullscreen";
|
|
10347
|
+
ClapprStatsCounter["DvrUsage"] = "dvrUsage";
|
|
10348
|
+
})(ClapprStatsCounter || (ClapprStatsCounter = {}));
|
|
10342
10349
|
/**
|
|
10343
10350
|
* @beta
|
|
10344
10351
|
*/
|
|
@@ -10390,7 +10397,6 @@ function newMetrics$1() {
|
|
|
10390
10397
|
duration: 0,
|
|
10391
10398
|
currentTime: 0,
|
|
10392
10399
|
},
|
|
10393
|
-
custom: {},
|
|
10394
10400
|
};
|
|
10395
10401
|
}
|
|
10396
10402
|
|
|
@@ -10400,6 +10406,8 @@ function newMetrics$1() {
|
|
|
10400
10406
|
* @remarks
|
|
10401
10407
|
* This plugin does not render anything and is supposed to be extended or used together with other plugins that actually render something.
|
|
10402
10408
|
*
|
|
10409
|
+
* @see {@link NerdStats} - a plugin that visualises the playback metrics
|
|
10410
|
+
*
|
|
10403
10411
|
* Configuration options - {@link ClapprStatsSettings}
|
|
10404
10412
|
*
|
|
10405
10413
|
* Events - {@link ClapprStatsEvents}
|
|
@@ -10409,11 +10417,11 @@ class ClapprStats extends ContainerPlugin {
|
|
|
10409
10417
|
lastDecodedFramesCount = 0;
|
|
10410
10418
|
metrics = newMetrics$1();
|
|
10411
10419
|
timers = {
|
|
10412
|
-
[
|
|
10413
|
-
[
|
|
10414
|
-
[
|
|
10415
|
-
[
|
|
10416
|
-
[
|
|
10420
|
+
[ClapprStatsChronograph.Startup]: 0,
|
|
10421
|
+
[ClapprStatsChronograph.Watch]: 0,
|
|
10422
|
+
[ClapprStatsChronograph.Pause]: 0,
|
|
10423
|
+
[ClapprStatsChronograph.Buffering]: 0,
|
|
10424
|
+
[ClapprStatsChronograph.Session]: 0,
|
|
10417
10425
|
};
|
|
10418
10426
|
runEach;
|
|
10419
10427
|
/**
|
|
@@ -10443,15 +10451,10 @@ class ClapprStats extends ContainerPlugin {
|
|
|
10443
10451
|
inc(counter) {
|
|
10444
10452
|
this.metrics.counters[counter] += 1;
|
|
10445
10453
|
}
|
|
10446
|
-
// _timerHasStarted(timer) {
|
|
10447
|
-
// return this[`_start${timer}`] !== undefined;
|
|
10448
|
-
// }
|
|
10449
10454
|
start(timer) {
|
|
10450
|
-
// this[`_start${timer}`] = this._now();
|
|
10451
10455
|
this.timers[timer] = this.now();
|
|
10452
10456
|
}
|
|
10453
10457
|
stop(timer) {
|
|
10454
|
-
// this._metrics.timers[timer] += this._now() - this[`_start${timer}`];
|
|
10455
10458
|
this.metrics.chrono[timer] += this.now() - this.timers[timer];
|
|
10456
10459
|
}
|
|
10457
10460
|
constructor(container) {
|
|
@@ -10471,10 +10474,10 @@ class ClapprStats extends ContainerPlugin {
|
|
|
10471
10474
|
this.listenTo(this.container, Events.CONTAINER_PAUSE, this.onPause);
|
|
10472
10475
|
this.listenToOnce(this.container, Events.CONTAINER_STATE_BUFFERING, this.onBuffering);
|
|
10473
10476
|
this.listenTo(this.container, Events.CONTAINER_SEEK, this.onSeek);
|
|
10474
|
-
this.listenTo(this.container, Events.CONTAINER_ERROR, () => this.inc(
|
|
10475
|
-
this.listenTo(this.container, Events.CONTAINER_FULLSCREEN, () => this.inc(
|
|
10477
|
+
this.listenTo(this.container, Events.CONTAINER_ERROR, () => this.inc(ClapprStatsCounter.Error));
|
|
10478
|
+
this.listenTo(this.container, Events.CONTAINER_FULLSCREEN, () => this.inc(ClapprStatsCounter.Fullscreen));
|
|
10476
10479
|
this.listenTo(this.container, Events.CONTAINER_PLAYBACKDVRSTATECHANGED, (dvrInUse) => {
|
|
10477
|
-
dvrInUse && this.inc(
|
|
10480
|
+
dvrInUse && this.inc(ClapprStatsCounter.DvrUsage);
|
|
10478
10481
|
});
|
|
10479
10482
|
this.listenTo(this.container.playback, Events.PLAYBACK_PROGRESS, this.onProgress);
|
|
10480
10483
|
this.listenTo(this.container.playback, Events.PLAYBACK_TIMEUPDATE, this.onTimeUpdate);
|
|
@@ -10502,7 +10505,7 @@ class ClapprStats extends ContainerPlugin {
|
|
|
10502
10505
|
last.time = now - last.start;
|
|
10503
10506
|
}
|
|
10504
10507
|
this.metrics.extra.bitratesHistory.push({ start: this.now(), bitrate });
|
|
10505
|
-
this.inc(
|
|
10508
|
+
this.inc(ClapprStatsCounter.ChangeLevel);
|
|
10506
10509
|
}
|
|
10507
10510
|
stopReporting() {
|
|
10508
10511
|
this.buildReport();
|
|
@@ -10513,31 +10516,31 @@ class ClapprStats extends ContainerPlugin {
|
|
|
10513
10516
|
}
|
|
10514
10517
|
startTimers() {
|
|
10515
10518
|
this.timerId = setInterval(this.buildReport.bind(this), this.runEach);
|
|
10516
|
-
this.start(
|
|
10517
|
-
this.start(
|
|
10519
|
+
this.start(ClapprStatsChronograph.Session);
|
|
10520
|
+
this.start(ClapprStatsChronograph.Startup);
|
|
10518
10521
|
}
|
|
10519
10522
|
onFirstPlaying() {
|
|
10520
10523
|
this.listenTo(this.container, Events.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
10521
|
-
this.start(
|
|
10522
|
-
this.stop(
|
|
10524
|
+
this.start(ClapprStatsChronograph.Watch);
|
|
10525
|
+
this.stop(ClapprStatsChronograph.Startup);
|
|
10523
10526
|
}
|
|
10524
10527
|
playAfterPause() {
|
|
10525
10528
|
this.listenTo(this.container, Events.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
10526
|
-
this.stop(
|
|
10527
|
-
this.start(
|
|
10529
|
+
this.stop(ClapprStatsChronograph.Pause);
|
|
10530
|
+
this.start(ClapprStatsChronograph.Watch);
|
|
10528
10531
|
}
|
|
10529
10532
|
onPlay() {
|
|
10530
|
-
this.inc(
|
|
10533
|
+
this.inc(ClapprStatsCounter.Play);
|
|
10531
10534
|
}
|
|
10532
10535
|
onPause() {
|
|
10533
|
-
this.stop(
|
|
10534
|
-
this.start(
|
|
10535
|
-
this.inc(
|
|
10536
|
+
this.stop(ClapprStatsChronograph.Watch);
|
|
10537
|
+
this.start(ClapprStatsChronograph.Pause);
|
|
10538
|
+
this.inc(ClapprStatsCounter.Pause);
|
|
10536
10539
|
this.listenToOnce(this.container, Events.CONTAINER_PLAY, this.playAfterPause);
|
|
10537
10540
|
this.stopListening(this.container, Events.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
|
|
10538
10541
|
}
|
|
10539
10542
|
onSeek(e) {
|
|
10540
|
-
this.inc(
|
|
10543
|
+
this.inc(ClapprStatsCounter.Seek);
|
|
10541
10544
|
this.metrics.extra.watchHistory.push([e * 1000, e * 1000]);
|
|
10542
10545
|
}
|
|
10543
10546
|
onTimeUpdate(e) {
|
|
@@ -10562,17 +10565,17 @@ class ClapprStats extends ContainerPlugin {
|
|
|
10562
10565
|
}
|
|
10563
10566
|
onContainerUpdateWhilePlaying() {
|
|
10564
10567
|
if (this.container.playback.isPlaying()) {
|
|
10565
|
-
this.stop(
|
|
10566
|
-
this.start(
|
|
10568
|
+
this.stop(ClapprStatsChronograph.Watch);
|
|
10569
|
+
this.start(ClapprStatsChronograph.Watch);
|
|
10567
10570
|
}
|
|
10568
10571
|
}
|
|
10569
10572
|
onBuffering() {
|
|
10570
|
-
this.inc(
|
|
10571
|
-
this.start(
|
|
10573
|
+
this.inc(ClapprStatsCounter.Buffering);
|
|
10574
|
+
this.start(ClapprStatsChronograph.Buffering);
|
|
10572
10575
|
this.listenToOnce(this.container, Events.CONTAINER_STATE_BUFFERFULL, this.onBufferfull);
|
|
10573
10576
|
}
|
|
10574
10577
|
onBufferfull() {
|
|
10575
|
-
this.stop(
|
|
10578
|
+
this.stop(ClapprStatsChronograph.Buffering);
|
|
10576
10579
|
this.listenToOnce(this.container, Events.CONTAINER_STATE_BUFFERING, this.onBuffering);
|
|
10577
10580
|
}
|
|
10578
10581
|
onProgress(progress) {
|
|
@@ -10584,8 +10587,8 @@ class ClapprStats extends ContainerPlugin {
|
|
|
10584
10587
|
// this.trigger(ClapprStatsEvents.PERCENTAGE, currentPercentage);
|
|
10585
10588
|
}
|
|
10586
10589
|
buildReport() {
|
|
10587
|
-
this.stop(
|
|
10588
|
-
this.start(
|
|
10590
|
+
this.stop(ClapprStatsChronograph.Session);
|
|
10591
|
+
this.start(ClapprStatsChronograph.Session);
|
|
10589
10592
|
this.metrics.extra.playbackName = this.playbackName;
|
|
10590
10593
|
this.metrics.extra.playbackType = this.playbackType;
|
|
10591
10594
|
this.calcBitrates();
|
|
@@ -12088,63 +12091,72 @@ const timeScale = new humanFormat.Scale({
|
|
|
12088
12091
|
ms: 1,
|
|
12089
12092
|
sec: 1000,
|
|
12090
12093
|
min: 60000,
|
|
12091
|
-
hours: 3600000
|
|
12094
|
+
hours: 3600000,
|
|
12092
12095
|
});
|
|
12093
12096
|
const percentScale = new humanFormat.Scale({
|
|
12094
|
-
'%': 1
|
|
12097
|
+
'%': 1,
|
|
12095
12098
|
});
|
|
12099
|
+
const metricTemplates = {
|
|
12100
|
+
fps: {
|
|
12101
|
+
scale: 'SI',
|
|
12102
|
+
decimals: 0,
|
|
12103
|
+
},
|
|
12104
|
+
volume: {
|
|
12105
|
+
scale: percentScale,
|
|
12106
|
+
},
|
|
12107
|
+
};
|
|
12096
12108
|
const formattingTemplate = {
|
|
12097
12109
|
general: {
|
|
12098
12110
|
volume: {
|
|
12099
|
-
scale: percentScale
|
|
12100
|
-
}
|
|
12111
|
+
scale: percentScale,
|
|
12112
|
+
},
|
|
12101
12113
|
},
|
|
12102
12114
|
timers: {
|
|
12103
12115
|
startup: {
|
|
12104
|
-
scale: timeScale
|
|
12116
|
+
scale: timeScale,
|
|
12105
12117
|
},
|
|
12106
12118
|
watch: {
|
|
12107
|
-
scale: timeScale
|
|
12119
|
+
scale: timeScale,
|
|
12108
12120
|
},
|
|
12109
12121
|
pause: {
|
|
12110
|
-
scale: timeScale
|
|
12122
|
+
scale: timeScale,
|
|
12111
12123
|
},
|
|
12112
12124
|
buffering: {
|
|
12113
|
-
scale: timeScale
|
|
12125
|
+
scale: timeScale,
|
|
12114
12126
|
},
|
|
12115
12127
|
session: {
|
|
12116
|
-
scale: timeScale
|
|
12128
|
+
scale: timeScale,
|
|
12117
12129
|
},
|
|
12118
12130
|
latency: {
|
|
12119
|
-
scale: timeScale
|
|
12120
|
-
}
|
|
12131
|
+
scale: timeScale,
|
|
12132
|
+
},
|
|
12121
12133
|
},
|
|
12122
12134
|
extra: {
|
|
12123
12135
|
buffersize: {
|
|
12124
|
-
scale: timeScale
|
|
12136
|
+
scale: timeScale,
|
|
12125
12137
|
},
|
|
12126
12138
|
duration: {
|
|
12127
|
-
scale: timeScale
|
|
12139
|
+
scale: timeScale,
|
|
12128
12140
|
},
|
|
12129
12141
|
currentTime: {
|
|
12130
|
-
scale: timeScale
|
|
12142
|
+
scale: timeScale,
|
|
12131
12143
|
},
|
|
12132
12144
|
bitrateWeightedMean: {
|
|
12133
|
-
unit: 'bps'
|
|
12145
|
+
unit: 'bps',
|
|
12134
12146
|
},
|
|
12135
12147
|
bitrateMostUsed: {
|
|
12136
|
-
unit: 'bps'
|
|
12148
|
+
unit: 'bps',
|
|
12137
12149
|
},
|
|
12138
12150
|
bandwidth: {
|
|
12139
|
-
unit: 'bps'
|
|
12151
|
+
unit: 'bps',
|
|
12140
12152
|
},
|
|
12141
12153
|
watchedPercentage: {
|
|
12142
|
-
scale: percentScale
|
|
12154
|
+
scale: percentScale,
|
|
12143
12155
|
},
|
|
12144
12156
|
bufferingPercentage: {
|
|
12145
|
-
scale: percentScale
|
|
12146
|
-
}
|
|
12147
|
-
}
|
|
12157
|
+
scale: percentScale,
|
|
12158
|
+
},
|
|
12159
|
+
},
|
|
12148
12160
|
};
|
|
12149
12161
|
class Formatter {
|
|
12150
12162
|
static format(metrics) {
|
|
@@ -12154,8 +12166,10 @@ class Formatter {
|
|
|
12154
12166
|
formattedMetrics[type] = fmt;
|
|
12155
12167
|
const typeTemplate = formattingTemplate[type];
|
|
12156
12168
|
Object.entries(mm).forEach(([name, value]) => {
|
|
12157
|
-
|
|
12158
|
-
|
|
12169
|
+
if (typeTemplate &&
|
|
12170
|
+
typeTemplate[name] &&
|
|
12171
|
+
typeof value === 'number' &&
|
|
12172
|
+
!isNaN(value)) {
|
|
12159
12173
|
// @ts-ignore
|
|
12160
12174
|
const templateScale = typeTemplate[name].scale || 'SI';
|
|
12161
12175
|
// @ts-ignore
|
|
@@ -12163,7 +12177,7 @@ class Formatter {
|
|
|
12163
12177
|
fmt[name] = humanFormat(value, {
|
|
12164
12178
|
scale: templateScale,
|
|
12165
12179
|
unit: templateUnit,
|
|
12166
|
-
decimals: 2
|
|
12180
|
+
decimals: 2,
|
|
12167
12181
|
});
|
|
12168
12182
|
}
|
|
12169
12183
|
else {
|
|
@@ -12173,6 +12187,27 @@ class Formatter {
|
|
|
12173
12187
|
});
|
|
12174
12188
|
return formattedMetrics;
|
|
12175
12189
|
}
|
|
12190
|
+
static formatVolume(volume) {
|
|
12191
|
+
return humanFormat(volume, metricTemplates.volume);
|
|
12192
|
+
}
|
|
12193
|
+
static formatTime(time) {
|
|
12194
|
+
return humanFormat(time, {
|
|
12195
|
+
scale: timeScale,
|
|
12196
|
+
});
|
|
12197
|
+
}
|
|
12198
|
+
static formatFps(fps) {
|
|
12199
|
+
return humanFormat(fps, metricTemplates.fps);
|
|
12200
|
+
}
|
|
12201
|
+
static formatPercentage(percentage) {
|
|
12202
|
+
return humanFormat(percentage, {
|
|
12203
|
+
scale: percentScale,
|
|
12204
|
+
});
|
|
12205
|
+
}
|
|
12206
|
+
static formatBitrate(bitrate) {
|
|
12207
|
+
return humanFormat(bitrate, {
|
|
12208
|
+
unit: 'bps',
|
|
12209
|
+
});
|
|
12210
|
+
}
|
|
12176
12211
|
}
|
|
12177
12212
|
|
|
12178
12213
|
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";
|
|
@@ -12655,7 +12690,7 @@ function rankConnectionSpeed(dlSpeed) {
|
|
|
12655
12690
|
return 0;
|
|
12656
12691
|
}
|
|
12657
12692
|
|
|
12658
|
-
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";
|
|
12693
|
+
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";
|
|
12659
12694
|
|
|
12660
12695
|
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";
|
|
12661
12696
|
|
|
@@ -12728,17 +12763,24 @@ const drawSummary = (customMetrics, vodContainer, liveContainer) => {
|
|
|
12728
12763
|
vodContainer.html(vodHtml);
|
|
12729
12764
|
liveContainer.html(liveHtml);
|
|
12730
12765
|
};
|
|
12766
|
+
|
|
12767
|
+
const PLAYBACK_NAMES = {
|
|
12768
|
+
dash: 'DASH.js',
|
|
12769
|
+
hls: 'HLS.js',
|
|
12770
|
+
html5_video: 'Native',
|
|
12771
|
+
};
|
|
12772
|
+
const T$c = 'plugins.nerd_stats';
|
|
12731
12773
|
/**
|
|
12732
|
-
* `PLUGIN` that displays useful network
|
|
12774
|
+
* `PLUGIN` that displays useful statistics regarding the playback as well as the network quality estimation.
|
|
12733
12775
|
* @beta
|
|
12734
12776
|
*
|
|
12735
12777
|
* @remarks
|
|
12736
12778
|
* Depends on:
|
|
12737
12779
|
*
|
|
12738
|
-
* - {@link BottomGear}
|
|
12739
|
-
*
|
|
12740
|
-
* - {@link ClapprStats}
|
|
12780
|
+
* - {@link BottomGear} - where the button is attached
|
|
12741
12781
|
*
|
|
12782
|
+
* - {@link ClapprStats} - to get the metrics from
|
|
12783
|
+
*
|
|
12742
12784
|
* The plugin is rendered as an item in the gear menu.
|
|
12743
12785
|
*
|
|
12744
12786
|
* When clicked, it shows an overlay window with the information about the network speed, latency, etc,
|
|
@@ -12746,13 +12788,13 @@ const drawSummary = (customMetrics, vodContainer, liveContainer) => {
|
|
|
12746
12788
|
*/
|
|
12747
12789
|
class NerdStats extends UICorePlugin {
|
|
12748
12790
|
container = null;
|
|
12749
|
-
|
|
12791
|
+
speedtestMetrics = {
|
|
12750
12792
|
connectionSpeed: 0,
|
|
12751
12793
|
ping: 0,
|
|
12752
12794
|
jitter: 0,
|
|
12753
12795
|
};
|
|
12754
12796
|
metrics = newMetrics();
|
|
12755
|
-
|
|
12797
|
+
open = false;
|
|
12756
12798
|
shortcut;
|
|
12757
12799
|
iconPosition;
|
|
12758
12800
|
static buttonTemplate = tmpl(buttonHtml$3);
|
|
@@ -12774,7 +12816,6 @@ class NerdStats extends UICorePlugin {
|
|
|
12774
12816
|
*/
|
|
12775
12817
|
get attributes() {
|
|
12776
12818
|
return {
|
|
12777
|
-
'data-clappr-nerd-stats': '',
|
|
12778
12819
|
class: 'clappr-nerd-stats',
|
|
12779
12820
|
};
|
|
12780
12821
|
}
|
|
@@ -12783,13 +12824,17 @@ class NerdStats extends UICorePlugin {
|
|
|
12783
12824
|
*/
|
|
12784
12825
|
get events() {
|
|
12785
12826
|
return {
|
|
12786
|
-
|
|
12787
|
-
'click
|
|
12788
|
-
'click
|
|
12827
|
+
click: 'clicked',
|
|
12828
|
+
'click #nerd-stats-close': 'hide',
|
|
12829
|
+
'click #nerd-stats-refresh': 'refreshSpeedTest',
|
|
12789
12830
|
};
|
|
12790
12831
|
}
|
|
12832
|
+
clicked(e) {
|
|
12833
|
+
e.stopPropagation();
|
|
12834
|
+
e.preventDefault();
|
|
12835
|
+
}
|
|
12791
12836
|
get statsBoxElem() {
|
|
12792
|
-
return '
|
|
12837
|
+
return this.$el.find('#nerd-stats-box');
|
|
12793
12838
|
}
|
|
12794
12839
|
get statsBoxWidthThreshold() {
|
|
12795
12840
|
return 720;
|
|
@@ -12808,7 +12853,7 @@ class NerdStats extends UICorePlugin {
|
|
|
12808
12853
|
];
|
|
12809
12854
|
this.iconPosition =
|
|
12810
12855
|
core.options.clapprNerdStats?.iconPosition ?? 'bottom-right';
|
|
12811
|
-
this.
|
|
12856
|
+
this.speedtestMetrics = {
|
|
12812
12857
|
connectionSpeed: 0,
|
|
12813
12858
|
ping: 0,
|
|
12814
12859
|
jitter: 0,
|
|
@@ -12820,20 +12865,38 @@ class NerdStats extends UICorePlugin {
|
|
|
12820
12865
|
*/
|
|
12821
12866
|
bindEvents() {
|
|
12822
12867
|
this.listenToOnce(this.core, Events.CORE_READY, this.onCoreReady);
|
|
12868
|
+
this.listenTo(this.core, Events.CORE_RESIZE, this.onPlayerResize);
|
|
12869
|
+
this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
|
|
12823
12870
|
}
|
|
12824
12871
|
onCoreReady() {
|
|
12825
12872
|
const bottomGear = this.core.getPlugin('bottom_gear');
|
|
12826
12873
|
assert(bottomGear, 'bottom_gear plugin is required');
|
|
12827
|
-
this.listenTo(bottomGear, GearEvents.RENDERED, this.
|
|
12874
|
+
this.listenTo(bottomGear, GearEvents.RENDERED, this.attach);
|
|
12875
|
+
Mousetrap.bind(this.shortcut, this.toggle);
|
|
12876
|
+
this.updateResolution();
|
|
12877
|
+
}
|
|
12878
|
+
onActiveContainerChanged() {
|
|
12828
12879
|
this.container = this.core.activeContainer;
|
|
12829
12880
|
const clapprStats = this.container?.getPlugin('clappr_stats');
|
|
12830
12881
|
assert(clapprStats, 'clappr-stats not available. Please, include it as a plugin of your Clappr instance.\n' +
|
|
12831
12882
|
'For more info, visit: https://github.com/clappr/clappr-stats.');
|
|
12832
|
-
Mousetrap.bind(this.shortcut, this.toggle);
|
|
12833
|
-
this.listenTo(this.core, Events.CORE_RESIZE, this.onPlayerResize);
|
|
12834
12883
|
this.listenTo(clapprStats, ClapprStatsEvents.REPORT, this.updateMetrics);
|
|
12884
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_VOLUME, () => {
|
|
12885
|
+
this.metrics.general.volume = this.container?.volume ?? 0;
|
|
12886
|
+
this.$el
|
|
12887
|
+
.find('#nerd-stats-volume')
|
|
12888
|
+
.text(Formatter.formatVolume(this.metrics.general.volume));
|
|
12889
|
+
});
|
|
12890
|
+
this.listenTo(this.core.activePlayback, Events.PLAYBACK_LOADEDMETADATA, () => {
|
|
12891
|
+
this.$el
|
|
12892
|
+
.find('#nerd-stats-playback-type')
|
|
12893
|
+
.text(this.formatPlaybackName(this.core.activePlayback.getPlaybackType()));
|
|
12894
|
+
});
|
|
12835
12895
|
this.updateMetrics(clapprStats.exportMetrics());
|
|
12836
|
-
this
|
|
12896
|
+
this.$el
|
|
12897
|
+
.find('#nerd-stats-playback-name')
|
|
12898
|
+
.text(PLAYBACK_NAMES[this.core.activePlayback.name] ?? '-');
|
|
12899
|
+
this.core.activeContainer.$el.append(this.$el);
|
|
12837
12900
|
}
|
|
12838
12901
|
/**
|
|
12839
12902
|
* @internal
|
|
@@ -12843,7 +12906,7 @@ class NerdStats extends UICorePlugin {
|
|
|
12843
12906
|
return super.destroy();
|
|
12844
12907
|
}
|
|
12845
12908
|
toggle = () => {
|
|
12846
|
-
if (this.
|
|
12909
|
+
if (this.open) {
|
|
12847
12910
|
this.hide();
|
|
12848
12911
|
}
|
|
12849
12912
|
else {
|
|
@@ -12851,10 +12914,11 @@ class NerdStats extends UICorePlugin {
|
|
|
12851
12914
|
}
|
|
12852
12915
|
};
|
|
12853
12916
|
show() {
|
|
12854
|
-
this
|
|
12855
|
-
this.
|
|
12917
|
+
this.$el.show();
|
|
12918
|
+
this.statsBoxElem.scrollTop(this.statsBoxElem.scrollTop());
|
|
12919
|
+
this.open = true;
|
|
12856
12920
|
this.refreshSpeedTest();
|
|
12857
|
-
initSpeedTest(this.
|
|
12921
|
+
initSpeedTest(this.speedtestMetrics)
|
|
12858
12922
|
.then(() => {
|
|
12859
12923
|
startSpeedtest();
|
|
12860
12924
|
})
|
|
@@ -12863,21 +12927,27 @@ class NerdStats extends UICorePlugin {
|
|
|
12863
12927
|
});
|
|
12864
12928
|
}
|
|
12865
12929
|
hide() {
|
|
12866
|
-
this
|
|
12867
|
-
this.
|
|
12930
|
+
this.$el.hide();
|
|
12931
|
+
this.open = false;
|
|
12868
12932
|
stopSpeedtest();
|
|
12869
12933
|
}
|
|
12870
12934
|
onPlayerResize() {
|
|
12871
12935
|
this.setStatsBoxSize();
|
|
12936
|
+
this.updateResolution();
|
|
12872
12937
|
}
|
|
12873
|
-
|
|
12874
|
-
this.metrics.general = {
|
|
12875
|
-
|
|
12876
|
-
|
|
12938
|
+
updateResolution() {
|
|
12939
|
+
this.metrics.general.resolution = {
|
|
12940
|
+
width: this.playerWidth,
|
|
12941
|
+
height: this.playerHeight,
|
|
12877
12942
|
};
|
|
12943
|
+
this.$el
|
|
12944
|
+
.find('#nerd-stats-resolution-width')
|
|
12945
|
+
.text(this.metrics.general.resolution.width);
|
|
12946
|
+
this.$el
|
|
12947
|
+
.find('#nerd-stats-resolution-height')
|
|
12948
|
+
.text(this.metrics.general.resolution.height);
|
|
12878
12949
|
}
|
|
12879
|
-
|
|
12880
|
-
this.metrics.custom = this.customMetrics;
|
|
12950
|
+
estimateQuality() {
|
|
12881
12951
|
const videoQualityNames = [
|
|
12882
12952
|
'SD (480p)',
|
|
12883
12953
|
'HD (720p)',
|
|
@@ -12885,9 +12955,9 @@ class NerdStats extends UICorePlugin {
|
|
|
12885
12955
|
'2K (1440p)',
|
|
12886
12956
|
'4K (2160p)',
|
|
12887
12957
|
];
|
|
12888
|
-
const { connectionSpeed, ping } = this.
|
|
12958
|
+
const { connectionSpeed, ping } = this.speedtestMetrics;
|
|
12889
12959
|
if (!connectionSpeed || !ping) {
|
|
12890
|
-
const calculatingText = '
|
|
12960
|
+
const calculatingText = this.core.i18n.t('stats.calculating');
|
|
12891
12961
|
this.metrics.custom.vodQuality = calculatingText;
|
|
12892
12962
|
this.metrics.custom.liveQuality = calculatingText;
|
|
12893
12963
|
return;
|
|
@@ -12902,42 +12972,108 @@ class NerdStats extends UICorePlugin {
|
|
|
12902
12972
|
prefix + videoQualityNames[liveQuality - 1];
|
|
12903
12973
|
}
|
|
12904
12974
|
updateMetrics(metrics) {
|
|
12975
|
+
trace(`${T$c} updateMetrics`, { custom: this.speedtestMetrics });
|
|
12905
12976
|
Object.assign(this.metrics, metrics);
|
|
12906
|
-
this.
|
|
12907
|
-
this
|
|
12908
|
-
|
|
12909
|
-
|
|
12910
|
-
|
|
12911
|
-
|
|
12912
|
-
|
|
12977
|
+
this.updateEstimatedQuality();
|
|
12978
|
+
this.$el
|
|
12979
|
+
.find('#nerd-stats-current-time')
|
|
12980
|
+
.text(Formatter.formatTime(this.metrics.extra.currentTime));
|
|
12981
|
+
this.$el
|
|
12982
|
+
.find('#nerd-stats-video-duration')
|
|
12983
|
+
.text(Formatter.formatTime(this.metrics.extra.duration));
|
|
12984
|
+
this.$el
|
|
12985
|
+
.find('#nerd-stats-buffer-size')
|
|
12986
|
+
.text(Formatter.formatTime(this.metrics.extra.buffersize));
|
|
12987
|
+
this.$el
|
|
12988
|
+
.find('#nerd-stats-bitrate-weighted-mean')
|
|
12989
|
+
.text(Formatter.formatBitrate(this.metrics.extra.bitrateWeightedMean));
|
|
12990
|
+
this.$el
|
|
12991
|
+
.find('#nerd-stats-bitrate-most-used')
|
|
12992
|
+
.text(Formatter.formatBitrate(this.metrics.extra.bitrateMostUsed));
|
|
12993
|
+
this.$el
|
|
12994
|
+
.find('#nerd-stats-watched-percentage')
|
|
12995
|
+
.text(Formatter.formatPercentage(this.metrics.extra.watchedPercentage));
|
|
12996
|
+
this.$el
|
|
12997
|
+
.find('#nerd-stats-buffering-percentage')
|
|
12998
|
+
.text(Formatter.formatPercentage(this.metrics.extra.bufferingPercentage));
|
|
12999
|
+
this.$el
|
|
13000
|
+
.find('#nerd-stats-startup-time')
|
|
13001
|
+
.text(Formatter.formatTime(this.metrics.chrono.startup));
|
|
13002
|
+
this.$el
|
|
13003
|
+
.find('#nerd-stats-watch-time')
|
|
13004
|
+
.text(Formatter.formatTime(this.metrics.chrono.watch));
|
|
13005
|
+
this.$el
|
|
13006
|
+
.find('#nerd-stats-pause-time')
|
|
13007
|
+
.text(Formatter.formatTime(this.metrics.chrono.pause));
|
|
13008
|
+
this.$el
|
|
13009
|
+
.find('#nerd-stats-buffering-time')
|
|
13010
|
+
.text(Formatter.formatTime(this.metrics.chrono.buffering));
|
|
13011
|
+
this.$el
|
|
13012
|
+
.find('#nerd-stats-session-time')
|
|
13013
|
+
.text(Formatter.formatTime(this.metrics.chrono.session));
|
|
13014
|
+
this.$el.find('#nerd-stats-plays').text(this.metrics.counters.play);
|
|
13015
|
+
this.$el.find('#nerd-stats-pauses').text(this.metrics.counters.pause);
|
|
13016
|
+
this.$el.find('#nerd-stats-errors').text(this.metrics.counters.error);
|
|
13017
|
+
this.$el
|
|
13018
|
+
.find('#nerd-stats-bufferings')
|
|
13019
|
+
.text(this.metrics.counters.buffering);
|
|
13020
|
+
this.$el
|
|
13021
|
+
.find('#nerd-stats-decoded-frames')
|
|
13022
|
+
.text(this.metrics.counters.decodedFrames);
|
|
13023
|
+
this.$el
|
|
13024
|
+
.find('#nerd-stats-dropped-frames')
|
|
13025
|
+
.text(this.metrics.counters.droppedFrames);
|
|
13026
|
+
this.$el
|
|
13027
|
+
.find('#nerd-stats-bitrate-changes')
|
|
13028
|
+
.text(this.metrics.counters.changeLevel);
|
|
13029
|
+
this.$el.find('#nerd-stats-seeks').text(this.metrics.counters.seek);
|
|
13030
|
+
this.$el
|
|
13031
|
+
.find('#nerd-stats-fullscreen')
|
|
13032
|
+
.text(this.metrics.counters.fullscreen);
|
|
13033
|
+
this.$el.find('#nerd-stats-dvr-usage').text(this.metrics.counters.dvrUsage);
|
|
13034
|
+
this.$el
|
|
13035
|
+
.find('#nerd-stats-fps')
|
|
13036
|
+
.text(Formatter.formatFps(this.metrics.counters.fps));
|
|
12913
13037
|
this.setStatsBoxSize();
|
|
12914
13038
|
drawSpeedTestResults();
|
|
12915
|
-
drawSummary(this.
|
|
12916
|
-
|
|
12917
|
-
if (!this.showing) {
|
|
13039
|
+
drawSummary(this.speedtestMetrics, this.$el.find('#nerd-stats-quality-vod'), this.$el.find('#nerd-stats-quality-live'));
|
|
13040
|
+
if (!this.open) {
|
|
12918
13041
|
this.hide();
|
|
12919
13042
|
}
|
|
12920
13043
|
}
|
|
13044
|
+
updateEstimatedQuality() {
|
|
13045
|
+
this.estimateQuality();
|
|
13046
|
+
this.$el
|
|
13047
|
+
.find('#nerd-stats-quality-vod-text')
|
|
13048
|
+
.html(this.metrics.custom.vodQuality);
|
|
13049
|
+
this.$el
|
|
13050
|
+
.find('#nerd-stats-quality-live-text')
|
|
13051
|
+
.html(this.metrics.custom.liveQuality);
|
|
13052
|
+
}
|
|
12921
13053
|
setStatsBoxSize() {
|
|
12922
13054
|
if (this.playerWidth >= this.statsBoxWidthThreshold) {
|
|
12923
|
-
this
|
|
12924
|
-
this
|
|
13055
|
+
this.statsBoxElem.addClass('wide');
|
|
13056
|
+
this.statsBoxElem.removeClass('narrow');
|
|
12925
13057
|
}
|
|
12926
13058
|
else {
|
|
12927
|
-
this
|
|
12928
|
-
this
|
|
13059
|
+
this.statsBoxElem.removeClass('wide');
|
|
13060
|
+
this.statsBoxElem.addClass('narrow');
|
|
12929
13061
|
}
|
|
12930
13062
|
}
|
|
12931
13063
|
/**
|
|
12932
13064
|
* @internal
|
|
12933
13065
|
*/
|
|
12934
13066
|
render() {
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
|
|
13067
|
+
this.$el
|
|
13068
|
+
.html(NerdStats.template({
|
|
13069
|
+
metrics: Formatter.format(this.metrics ?? newMetrics()),
|
|
13070
|
+
iconPosition: this.iconPosition,
|
|
13071
|
+
i18n: this.core.i18n,
|
|
13072
|
+
}))
|
|
13073
|
+
.hide();
|
|
12938
13074
|
return this;
|
|
12939
13075
|
}
|
|
12940
|
-
|
|
13076
|
+
attach() {
|
|
12941
13077
|
const gear = this.core.getPlugin('bottom_gear');
|
|
12942
13078
|
gear
|
|
12943
13079
|
.addItem('nerd_stats')
|
|
@@ -12950,11 +13086,11 @@ class NerdStats extends UICorePlugin {
|
|
|
12950
13086
|
this.toggle();
|
|
12951
13087
|
});
|
|
12952
13088
|
}
|
|
12953
|
-
|
|
13089
|
+
clearSpeedtestMetrics() {
|
|
12954
13090
|
const clapprStats = this.container?.getPlugin('clappr_stats');
|
|
12955
|
-
this.
|
|
12956
|
-
this.
|
|
12957
|
-
this.
|
|
13091
|
+
this.speedtestMetrics.connectionSpeed = 0;
|
|
13092
|
+
this.speedtestMetrics.ping = 0;
|
|
13093
|
+
this.speedtestMetrics.jitter = 0;
|
|
12958
13094
|
if (clapprStats) {
|
|
12959
13095
|
this.updateMetrics(clapprStats.exportMetrics());
|
|
12960
13096
|
}
|
|
@@ -12962,7 +13098,7 @@ class NerdStats extends UICorePlugin {
|
|
|
12962
13098
|
refreshSpeedTest() {
|
|
12963
13099
|
stopSpeedtest();
|
|
12964
13100
|
setTimeout(() => {
|
|
12965
|
-
this.
|
|
13101
|
+
this.clearSpeedtestMetrics();
|
|
12966
13102
|
clearSpeedTestResults();
|
|
12967
13103
|
drawSpeedTestResults();
|
|
12968
13104
|
}, 200);
|
|
@@ -12970,11 +13106,28 @@ class NerdStats extends UICorePlugin {
|
|
|
12970
13106
|
startSpeedtest();
|
|
12971
13107
|
}, 800);
|
|
12972
13108
|
}
|
|
13109
|
+
formatPlaybackName(playbackType) {
|
|
13110
|
+
switch (playbackType) {
|
|
13111
|
+
case Playback.VOD:
|
|
13112
|
+
return this.core.i18n.t('vod');
|
|
13113
|
+
case Playback.LIVE:
|
|
13114
|
+
return this.core.i18n.t('live');
|
|
13115
|
+
default:
|
|
13116
|
+
return '-';
|
|
13117
|
+
}
|
|
13118
|
+
}
|
|
12973
13119
|
}
|
|
12974
13120
|
function newMetrics() {
|
|
12975
13121
|
return {
|
|
12976
13122
|
...newMetrics$1(),
|
|
12977
|
-
general: {
|
|
13123
|
+
general: {
|
|
13124
|
+
displayResolution: '',
|
|
13125
|
+
resolution: {
|
|
13126
|
+
width: 0,
|
|
13127
|
+
height: 0,
|
|
13128
|
+
},
|
|
13129
|
+
volume: 0,
|
|
13130
|
+
},
|
|
12978
13131
|
custom: {
|
|
12979
13132
|
connectionSpeed: 0,
|
|
12980
13133
|
ping: 0,
|
|
@@ -12998,7 +13151,7 @@ class ClickToPause extends ContainerPlugin {
|
|
|
12998
13151
|
* @internal
|
|
12999
13152
|
*/
|
|
13000
13153
|
get name() {
|
|
13001
|
-
return '
|
|
13154
|
+
return 'click_to_pause';
|
|
13002
13155
|
}
|
|
13003
13156
|
/**
|
|
13004
13157
|
* @internal
|
|
@@ -13389,7 +13542,7 @@ class ContextMenu extends UIContainerPlugin {
|
|
|
13389
13542
|
|
|
13390
13543
|
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";
|
|
13391
13544
|
|
|
13392
|
-
const T
|
|
13545
|
+
// const T = 'plugins.dvr_controls'
|
|
13393
13546
|
/**
|
|
13394
13547
|
* `PLUGIN` that adds the DVR controls to the media control UI
|
|
13395
13548
|
*
|
|
@@ -13438,18 +13591,17 @@ class DvrControls extends UICorePlugin {
|
|
|
13438
13591
|
* @internal
|
|
13439
13592
|
*/
|
|
13440
13593
|
bindEvents() {
|
|
13441
|
-
this.
|
|
13442
|
-
this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.
|
|
13594
|
+
this.listenToOnce(this.core, Events.CORE_READY, this.onCoreReady);
|
|
13595
|
+
this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
|
|
13443
13596
|
}
|
|
13444
13597
|
onCoreReady() {
|
|
13445
13598
|
const mediaControl = this.core.getPlugin('media_control');
|
|
13446
13599
|
assert(mediaControl, 'media_control plugin is required');
|
|
13447
|
-
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.
|
|
13448
|
-
// MediaControl has been rendered
|
|
13449
|
-
this.render();
|
|
13600
|
+
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.mount);
|
|
13450
13601
|
}
|
|
13451
|
-
|
|
13452
|
-
this.
|
|
13602
|
+
onActiveContainerChanged() {
|
|
13603
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_LOADEDMETADATA, this.onMetadataLoaded);
|
|
13604
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_PLAYBACKDVRSTATECHANGED, this.onDvrStateChanged);
|
|
13453
13605
|
}
|
|
13454
13606
|
click() {
|
|
13455
13607
|
const container = this.core.activeContainer;
|
|
@@ -13458,32 +13610,47 @@ class DvrControls extends UICorePlugin {
|
|
|
13458
13610
|
}
|
|
13459
13611
|
container.seek(container.getDuration());
|
|
13460
13612
|
}
|
|
13461
|
-
shouldRender() {
|
|
13462
|
-
return this.core.getPlaybackType() === Playback.LIVE;
|
|
13463
|
-
}
|
|
13464
13613
|
/**
|
|
13465
13614
|
* @internal
|
|
13466
13615
|
*/
|
|
13467
13616
|
render() {
|
|
13468
|
-
trace(`${T$c} render`, {
|
|
13469
|
-
dvrEnabled: this.core.activePlayback?.dvrEnabled,
|
|
13470
|
-
playbackType: this.core.getPlaybackType(),
|
|
13471
|
-
});
|
|
13472
|
-
const mediaControl = this.core.getPlugin('media_control');
|
|
13473
|
-
if (!mediaControl) {
|
|
13474
|
-
return this;
|
|
13475
|
-
}
|
|
13476
|
-
if (!this.shouldRender()) {
|
|
13477
|
-
return this;
|
|
13478
|
-
}
|
|
13479
|
-
mediaControl.toggleElement('duration', false);
|
|
13480
|
-
mediaControl.toggleElement('position', false);
|
|
13481
13617
|
this.$el.html(DvrControls.template({
|
|
13482
13618
|
i18n: this.core.i18n,
|
|
13483
13619
|
}));
|
|
13484
|
-
mediaControl.putElement('dvr', this.$el);
|
|
13485
13620
|
return this;
|
|
13486
13621
|
}
|
|
13622
|
+
onMediacontrolRendered() {
|
|
13623
|
+
this.render();
|
|
13624
|
+
}
|
|
13625
|
+
onMetadataLoaded() {
|
|
13626
|
+
this.mount();
|
|
13627
|
+
this.toggleState(this.core.activeContainer.isDvrInUse());
|
|
13628
|
+
}
|
|
13629
|
+
mount() {
|
|
13630
|
+
// TODO move mount point management logic to MediaControl
|
|
13631
|
+
if (this.core.getPlaybackType() !== Playback.LIVE) {
|
|
13632
|
+
return;
|
|
13633
|
+
}
|
|
13634
|
+
const mediaControl = this.core.getPlugin('media_control');
|
|
13635
|
+
assert(mediaControl, 'media_control plugin is required');
|
|
13636
|
+
// TODO -> to MediaControl
|
|
13637
|
+
mediaControl.toggleElement('duration', false);
|
|
13638
|
+
mediaControl.toggleElement('position', false);
|
|
13639
|
+
mediaControl.mount('dvr', this.$el);
|
|
13640
|
+
}
|
|
13641
|
+
onDvrStateChanged(dvrInUse) {
|
|
13642
|
+
this.toggleState(dvrInUse);
|
|
13643
|
+
}
|
|
13644
|
+
toggleState(dvrInUse) {
|
|
13645
|
+
if (dvrInUse) {
|
|
13646
|
+
this.$el.find('#media-control-back-to-live').show();
|
|
13647
|
+
this.$el.find('#media-control-live').hide();
|
|
13648
|
+
}
|
|
13649
|
+
else {
|
|
13650
|
+
this.$el.find('#media-control-back-to-live').hide();
|
|
13651
|
+
this.$el.find('#media-control-live').show();
|
|
13652
|
+
}
|
|
13653
|
+
}
|
|
13487
13654
|
}
|
|
13488
13655
|
|
|
13489
13656
|
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>";
|
|
@@ -14288,8 +14455,6 @@ const DEFAULT_SETTINGS = {
|
|
|
14288
14455
|
right: [
|
|
14289
14456
|
'audiotracks',
|
|
14290
14457
|
'cc',
|
|
14291
|
-
// 'dvr',
|
|
14292
|
-
// 'duration',
|
|
14293
14458
|
'fullscreen',
|
|
14294
14459
|
'gear',
|
|
14295
14460
|
'multicamera',
|
|
@@ -14306,10 +14471,10 @@ const T$a = 'plugins.media_control';
|
|
|
14306
14471
|
const LEFT_ORDER = [
|
|
14307
14472
|
'playpause',
|
|
14308
14473
|
'playstop',
|
|
14309
|
-
'dvr',
|
|
14310
14474
|
'volume',
|
|
14311
14475
|
'position',
|
|
14312
14476
|
'duration',
|
|
14477
|
+
'dvr',
|
|
14313
14478
|
];
|
|
14314
14479
|
const { Config, Fullscreen, formatTime: formatTime$1, extend, removeArrayItem } = Utils;
|
|
14315
14480
|
function orderByOrderPattern(arr, order) {
|
|
@@ -14953,8 +15118,7 @@ class MediaControl extends UICorePlugin {
|
|
|
14953
15118
|
}
|
|
14954
15119
|
this.$el.show();
|
|
14955
15120
|
this.trigger(Events.MEDIACONTROL_SHOW, this.name);
|
|
14956
|
-
this.
|
|
14957
|
-
this.container.trigger(Events.CONTAINER_MEDIACONTROL_SHOW, this.name);
|
|
15121
|
+
this.core.activeContainer?.trigger(Events.CONTAINER_MEDIACONTROL_SHOW, this.name);
|
|
14958
15122
|
this.$el.removeClass('media-control-hide');
|
|
14959
15123
|
this.hideId = setTimeout(() => this.hide(), timeout);
|
|
14960
15124
|
if (event) {
|
|
@@ -15007,7 +15171,7 @@ class MediaControl extends UICorePlugin {
|
|
|
15007
15171
|
default: [],
|
|
15008
15172
|
right: [],
|
|
15009
15173
|
}, this.core.activeContainer.settings);
|
|
15010
|
-
newSettings.left.push('clips'); // TODO
|
|
15174
|
+
newSettings.left.push('clips'); // TODO settings
|
|
15011
15175
|
// TODO make order controlled via CSS
|
|
15012
15176
|
newSettings.left = orderByOrderPattern([...newSettings.left, 'volume', 'clips'], LEFT_ORDER);
|
|
15013
15177
|
if (this.core.activePlayback.getPlaybackType() === Playback.LIVE &&
|
|
@@ -15069,7 +15233,6 @@ class MediaControl extends UICorePlugin {
|
|
|
15069
15233
|
* Get a media control element DOM node
|
|
15070
15234
|
* @param name - The name of the media control element
|
|
15071
15235
|
* @returns The DOM node to render to or extend
|
|
15072
|
-
* @deprecated Use {@link MediaControl.putElement} instead
|
|
15073
15236
|
* @remarks
|
|
15074
15237
|
* Use this method to render custom media control UI in a plugin
|
|
15075
15238
|
* @example
|
|
@@ -15101,13 +15264,18 @@ class MediaControl extends UICorePlugin {
|
|
|
15101
15264
|
return;
|
|
15102
15265
|
}
|
|
15103
15266
|
}
|
|
15267
|
+
/**
|
|
15268
|
+
* @deprecated Use {@link MediaControl.mount} instead
|
|
15269
|
+
* @param name
|
|
15270
|
+
* @param element
|
|
15271
|
+
*/
|
|
15104
15272
|
putElement(name, element) {
|
|
15105
15273
|
this.mount(name, element);
|
|
15106
15274
|
}
|
|
15107
15275
|
/**
|
|
15108
15276
|
* Toggle the visibility of a media control element
|
|
15109
15277
|
* @param name - The name of the media control element
|
|
15110
|
-
* @param show -
|
|
15278
|
+
* @param show - Visibility state
|
|
15111
15279
|
*/
|
|
15112
15280
|
toggleElement(area, show) {
|
|
15113
15281
|
this.$el.find(`[data-${area}]`).toggle(show);
|
|
@@ -15323,6 +15491,7 @@ class MediaControl extends UICorePlugin {
|
|
|
15323
15491
|
width: this.options.width,
|
|
15324
15492
|
height: this.options.height,
|
|
15325
15493
|
});
|
|
15494
|
+
// TODO check out
|
|
15326
15495
|
this.hideVolumeBar(0);
|
|
15327
15496
|
}, 0);
|
|
15328
15497
|
this.parseColors();
|
|
@@ -15866,7 +16035,7 @@ class PictureInPicture extends UICorePlugin {
|
|
|
15866
16035
|
this.$el.html(PictureInPicture.buttonTemplate({ pipIcon }));
|
|
15867
16036
|
const mediaControl = this.core.getPlugin('media_control');
|
|
15868
16037
|
if (mediaControl) {
|
|
15869
|
-
mediaControl.
|
|
16038
|
+
mediaControl.mount('pip', this.$el);
|
|
15870
16039
|
}
|
|
15871
16040
|
return this;
|
|
15872
16041
|
}
|
|
@@ -16792,7 +16961,7 @@ class SeekTime extends UICorePlugin {
|
|
|
16792
16961
|
this.listenTo(this.mediaControl, Events.MEDIACONTROL_CONTAINERCHANGED, this.onContainerChanged);
|
|
16793
16962
|
if (this.mediaControlContainer) {
|
|
16794
16963
|
this.listenTo(this.mediaControlContainer, Events.CONTAINER_PLAYBACKDVRSTATECHANGED, this.update);
|
|
16795
|
-
this.listenTo(this.mediaControlContainer, Events.CONTAINER_TIMEUPDATE, this.
|
|
16964
|
+
this.listenTo(this.mediaControlContainer, Events.CONTAINER_TIMEUPDATE, this.onTimeUpdate);
|
|
16796
16965
|
}
|
|
16797
16966
|
}
|
|
16798
16967
|
onContainerChanged() {
|
|
@@ -16800,9 +16969,8 @@ class SeekTime extends UICorePlugin {
|
|
|
16800
16969
|
this.stopListening();
|
|
16801
16970
|
this.bindEvents();
|
|
16802
16971
|
}
|
|
16803
|
-
|
|
16804
|
-
this.duration =
|
|
16805
|
-
// this.firstFragDateTime = timeProgress.firstFragDateTime;
|
|
16972
|
+
onTimeUpdate({ total }) {
|
|
16973
|
+
this.duration = total;
|
|
16806
16974
|
this.update();
|
|
16807
16975
|
}
|
|
16808
16976
|
showTime(event) {
|
|
@@ -17764,7 +17932,7 @@ class ClosedCaptions extends UICorePlugin {
|
|
|
17764
17932
|
this.$line = $(ClosedCaptions.templateString());
|
|
17765
17933
|
this.resizeFont();
|
|
17766
17934
|
this.core.activeContainer.$el.append(this.$line);
|
|
17767
|
-
mediaControl.
|
|
17935
|
+
mediaControl.mount('cc', this.$el);
|
|
17768
17936
|
this.updateSelection();
|
|
17769
17937
|
this.renderIcon();
|
|
17770
17938
|
return this;
|
|
@@ -18695,4 +18863,4 @@ class VolumeFade extends UICorePlugin {
|
|
|
18695
18863
|
}
|
|
18696
18864
|
}
|
|
18697
18865
|
|
|
18698
|
-
export { AudioTracks as AudioSelector, AudioTracks, BigMuteButton, BottomGear, NerdStats as ClapprNerdStats, ClapprStats, ClickToPause, Clips, ClosedCaptions, ContextMenu, DvrControls, ErrorScreen, Favicon, GearEvents, GoogleAnalytics, QualityLevels as LevelSelector, Logo, MediaControl, MultiCamera, NerdStats, PictureInPicture, PlaybackRate, Poster, QualityLevels, SeekTime, Share, SkipTime, SourceController, SpinnerThreeBounce as Spinner, SpinnerEvents, SpinnerThreeBounce, ClosedCaptions as Subtitles, Telemetry, TelemetryEvent, Thumbnails, VolumeFade, VolumeFadeEvents };
|
|
18866
|
+
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, Logo, MediaControl, MultiCamera, NerdStats, PictureInPicture, PlaybackRate, Poster, QualityLevels, SeekTime, Share, SkipTime, SourceController, SpinnerThreeBounce as Spinner, SpinnerEvents, SpinnerThreeBounce, ClosedCaptions as Subtitles, Telemetry, TelemetryEvent, Thumbnails, VolumeFade, VolumeFadeEvents };
|