@gcorevideo/player 2.22.16 → 2.22.17

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.
Files changed (74) hide show
  1. package/dist/core.js +6 -8
  2. package/dist/index.css +1338 -1338
  3. package/dist/index.js +361 -439
  4. package/dist/player.d.ts +216 -159
  5. package/dist/plugins/index.css +1463 -1463
  6. package/dist/plugins/index.js +354 -427
  7. package/docs/api/player.clapprstats.exportmetrics.md +1 -1
  8. package/docs/api/player.clapprstats.md +5 -15
  9. package/docs/api/player.clapprstatssettings.md +13 -0
  10. package/docs/api/player.clips.destroy.md +18 -0
  11. package/docs/api/player.clips.disable.md +18 -0
  12. package/docs/api/player.clips.enable.md +18 -0
  13. package/docs/api/player.clips.md +170 -0
  14. package/docs/api/player.clips.render.md +18 -0
  15. package/docs/api/player.clips.supportedversion.md +16 -0
  16. package/docs/api/player.clips.version.md +14 -0
  17. package/docs/api/player.clipspluginsettings.md +2 -2
  18. package/docs/api/player.clipspluginsettings.text.md +1 -1
  19. package/docs/api/player.md +27 -18
  20. package/docs/api/player.mediacontrol.md +1 -1
  21. package/docs/api/{player.mediacontrol.getelement.md → player.mediacontrol.mount.md} +20 -7
  22. package/docs/api/player.mediacontrolleftelement.md +1 -1
  23. package/docs/api/{player.clapprnerdstats._constructor_.md → player.nerdstats._constructor_.md} +3 -3
  24. package/docs/api/{player.clapprnerdstats.md → player.nerdstats.md} +5 -5
  25. package/docs/api/player.qualitylevel.height.md +1 -1
  26. package/docs/api/player.qualitylevel.level.md +1 -1
  27. package/docs/api/player.qualitylevel.md +4 -4
  28. package/docs/api/player.qualitylevel.width.md +1 -1
  29. package/docs/api/player.timeposition.current.md +1 -1
  30. package/docs/api/player.timeposition.md +2 -2
  31. package/docs/api/player.timeposition.total.md +1 -1
  32. package/docs/api/player.timeprogress.md +6 -4
  33. package/docs/api/player.timevalue.md +1 -1
  34. package/lib/index.plugins.d.ts +2 -1
  35. package/lib/index.plugins.d.ts.map +1 -1
  36. package/lib/index.plugins.js +2 -1
  37. package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
  38. package/lib/playback/dash-playback/DashPlayback.js +5 -7
  39. package/lib/playback.types.d.ts +22 -9
  40. package/lib/playback.types.d.ts.map +1 -1
  41. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts +4 -0
  42. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts.map +1 -1
  43. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.js +20 -23
  44. package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts +83 -0
  45. package/lib/plugins/clappr-nerd-stats/NerdStats.d.ts.map +1 -0
  46. package/lib/plugins/clappr-nerd-stats/NerdStats.js +339 -0
  47. package/lib/plugins/clappr-stats/ClapprStats.d.ts +27 -32
  48. package/lib/plugins/clappr-stats/ClapprStats.d.ts.map +1 -1
  49. package/lib/plugins/clappr-stats/ClapprStats.js +94 -202
  50. package/lib/plugins/clappr-stats/types.d.ts +65 -24
  51. package/lib/plugins/clappr-stats/types.d.ts.map +1 -1
  52. package/lib/plugins/clappr-stats/types.js +37 -2
  53. package/lib/plugins/clappr-stats/utils.d.ts.map +1 -1
  54. package/lib/plugins/clappr-stats/utils.js +1 -2
  55. package/lib/testUtils.d.ts +2 -1
  56. package/lib/testUtils.d.ts.map +1 -1
  57. package/lib/testUtils.js +3 -2
  58. package/package.json +1 -1
  59. package/src/index.plugins.ts +2 -1
  60. package/src/playback/dash-playback/DashPlayback.ts +5 -8
  61. package/src/playback.types.ts +23 -8
  62. package/src/plugins/clappr-nerd-stats/{ClapprNerdStats.ts → NerdStats.ts} +25 -30
  63. package/src/plugins/clappr-stats/ClapprStats.ts +242 -306
  64. package/src/plugins/clappr-stats/__tests__/ClapprStats.test.ts +133 -0
  65. package/src/plugins/clappr-stats/types.ts +72 -25
  66. package/src/plugins/clappr-stats/utils.ts +1 -2
  67. package/src/plugins/error-screen/__tests__/ErrorScreen.test.ts +3 -4
  68. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +1 -0
  69. package/src/testUtils.ts +3 -2
  70. package/temp/player.api.json +311 -159
  71. package/tsconfig.tsbuildinfo +1 -1
  72. package/docs/api/player.clapprstats.setupdatemetrics.md +0 -56
  73. package/docs/api/player.clipsplugin.gettext.md +0 -58
  74. package/docs/api/player.clipsplugin.md +0 -59
package/dist/index.js CHANGED
@@ -13045,13 +13045,11 @@ class DashPlayback extends BasePlayback {
13045
13045
  this.getPlaybackType() === Playback.LIVE);
13046
13046
  }
13047
13047
  _onProgress() {
13048
- if (!this._dash) {
13049
- return;
13050
- }
13051
- let buffer = this._dash.getDashMetrics().getCurrentBufferLevel('video');
13052
- if (!buffer) {
13053
- buffer = this._dash.getDashMetrics().getCurrentBufferLevel('audio');
13054
- }
13048
+ const buffer =
13049
+ // @ts-expect-error
13050
+ this._dash.getDashMetrics().getCurrentBufferLevel('video') ||
13051
+ // @ts-expect-error
13052
+ this._dash.getDashMetrics().getCurrentBufferLevel('audio');
13055
13053
  const progress = {
13056
13054
  start: this.getCurrentTime(),
13057
13055
  current: this.getCurrentTime() + buffer,
@@ -43307,7 +43305,7 @@ class Player {
43307
43305
  }
43308
43306
  }
43309
43307
 
43310
- var version$1 = "2.22.16";
43308
+ var version$1 = "2.22.17";
43311
43309
 
43312
43310
  var packages = {
43313
43311
  "node_modules/@clappr/core": {
@@ -43885,6 +43883,339 @@ class BottomGear extends UICorePlugin {
43885
43883
  }
43886
43884
  }
43887
43885
 
43886
+ /**
43887
+ * @beta
43888
+ */
43889
+ var Chronograph;
43890
+ (function (Chronograph) {
43891
+ Chronograph["Startup"] = "startup";
43892
+ Chronograph["Watch"] = "watch";
43893
+ Chronograph["Pause"] = "pause";
43894
+ Chronograph["Buffering"] = "buffering";
43895
+ Chronograph["Session"] = "session";
43896
+ // Latency = 'latency',
43897
+ })(Chronograph || (Chronograph = {}));
43898
+ /**
43899
+ * @beta
43900
+ */
43901
+ var Counter;
43902
+ (function (Counter) {
43903
+ Counter["Play"] = "play";
43904
+ Counter["Pause"] = "pause";
43905
+ Counter["Error"] = "error";
43906
+ Counter["Buffering"] = "buffering";
43907
+ Counter["DecodedFrames"] = "decodedFrames";
43908
+ Counter["DroppedFrames"] = "droppedFrames";
43909
+ Counter["Fps"] = "fps";
43910
+ Counter["ChangeLevel"] = "changeLevel";
43911
+ Counter["Seek"] = "seek";
43912
+ Counter["Fullscreen"] = "fullscreen";
43913
+ Counter["DvrUsage"] = "dvrUsage";
43914
+ })(Counter || (Counter = {}));
43915
+ /**
43916
+ * @beta
43917
+ */
43918
+ var ClapprStatsEvents;
43919
+ (function (ClapprStatsEvents) {
43920
+ /**
43921
+ * Emitted periodically with current measurements.
43922
+ */
43923
+ ClapprStatsEvents["REPORT"] = "clappr:stats:report";
43924
+ /**
43925
+ * Emitted when the playback reaches a certain percentage of the total duration.
43926
+ */
43927
+ // PERCENTAGE = 'clappr:stats:percentage',
43928
+ })(ClapprStatsEvents || (ClapprStatsEvents = {}));
43929
+
43930
+ function newMetrics$1() {
43931
+ return {
43932
+ counters: {
43933
+ play: 0,
43934
+ pause: 0,
43935
+ error: 0,
43936
+ buffering: 0,
43937
+ decodedFrames: 0,
43938
+ droppedFrames: 0,
43939
+ fps: 0,
43940
+ changeLevel: 0,
43941
+ seek: 0,
43942
+ fullscreen: 0,
43943
+ dvrUsage: 0,
43944
+ },
43945
+ chrono: {
43946
+ startup: 0,
43947
+ watch: 0,
43948
+ pause: 0,
43949
+ buffering: 0,
43950
+ session: 0,
43951
+ },
43952
+ extra: {
43953
+ playbackName: '',
43954
+ playbackType: '',
43955
+ bitratesHistory: [],
43956
+ bitrateWeightedMean: 0,
43957
+ bitrateMostUsed: 0,
43958
+ buffersize: 0,
43959
+ watchHistory: [],
43960
+ watchedPercentage: 0,
43961
+ bufferingPercentage: 0,
43962
+ bandwidth: 0,
43963
+ duration: 0,
43964
+ currentTime: 0,
43965
+ },
43966
+ custom: {},
43967
+ };
43968
+ }
43969
+
43970
+ /**
43971
+ * `PLUGIN` that measures data about playback, which can be useful for analyzing performance and UX.
43972
+ * @beta
43973
+ * @remarks
43974
+ * This plugin does not render anything and is supposed to be extended or used together with other plugins that actually render something.
43975
+ *
43976
+ * Configuration options - {@link ClapprStatsSettings}
43977
+ *
43978
+ * Events - {@link ClapprStatsEvents}
43979
+ */
43980
+ class ClapprStats extends ContainerPlugin {
43981
+ timerId = null;
43982
+ lastDecodedFramesCount = 0;
43983
+ metrics = newMetrics$1();
43984
+ timers = {
43985
+ [Chronograph.Startup]: 0,
43986
+ [Chronograph.Watch]: 0,
43987
+ [Chronograph.Pause]: 0,
43988
+ [Chronograph.Buffering]: 0,
43989
+ [Chronograph.Session]: 0,
43990
+ };
43991
+ runEach;
43992
+ /**
43993
+ * @internal
43994
+ */
43995
+ get name() {
43996
+ return 'clappr_stats';
43997
+ }
43998
+ /**
43999
+ * @internal
44000
+ */
44001
+ get supportedVersion() {
44002
+ return { min: CLAPPR_VERSION$1 };
44003
+ }
44004
+ get playbackName() {
44005
+ return String(this.container.playback.name || '');
44006
+ }
44007
+ get playbackType() {
44008
+ return this.container.getPlaybackType();
44009
+ }
44010
+ now() {
44011
+ const hasPerformanceSupport = window.performance && typeof window.performance.now === 'function';
44012
+ return hasPerformanceSupport
44013
+ ? window.performance.now()
44014
+ : new Date().getTime();
44015
+ }
44016
+ inc(counter) {
44017
+ this.metrics.counters[counter] += 1;
44018
+ }
44019
+ // _timerHasStarted(timer) {
44020
+ // return this[`_start${timer}`] !== undefined;
44021
+ // }
44022
+ start(timer) {
44023
+ // this[`_start${timer}`] = this._now();
44024
+ this.timers[timer] = this.now();
44025
+ }
44026
+ stop(timer) {
44027
+ // this._metrics.timers[timer] += this._now() - this[`_start${timer}`];
44028
+ this.metrics.chrono[timer] += this.now() - this.timers[timer];
44029
+ }
44030
+ constructor(container) {
44031
+ super(container);
44032
+ this.runEach = container.options.clapprStats?.runEach ?? 5000;
44033
+ }
44034
+ /**
44035
+ * @internal
44036
+ */
44037
+ bindEvents() {
44038
+ this.listenTo(this.container, Events$1.CONTAINER_BITRATE, this.onBitrate);
44039
+ this.listenTo(this.container, Events$1.CONTAINER_STOP, this.stopReporting);
44040
+ this.listenTo(this.container, Events$1.CONTAINER_ENDED, this.stopReporting);
44041
+ this.listenToOnce(this.container.playback, Events$1.PLAYBACK_PLAY_INTENT, this.startTimers);
44042
+ this.listenToOnce(this.container, Events$1.CONTAINER_PLAY, this.onFirstPlaying);
44043
+ this.listenTo(this.container, Events$1.CONTAINER_PLAY, this.onPlay);
44044
+ this.listenTo(this.container, Events$1.CONTAINER_PAUSE, this.onPause);
44045
+ this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERING, this.onBuffering);
44046
+ this.listenTo(this.container, Events$1.CONTAINER_SEEK, this.onSeek);
44047
+ this.listenTo(this.container, Events$1.CONTAINER_ERROR, () => this.inc(Counter.Error));
44048
+ this.listenTo(this.container, Events$1.CONTAINER_FULLSCREEN, () => this.inc(Counter.Fullscreen));
44049
+ this.listenTo(this.container, Events$1.CONTAINER_PLAYBACKDVRSTATECHANGED, (dvrInUse) => {
44050
+ dvrInUse && this.inc(Counter.DvrUsage);
44051
+ });
44052
+ this.listenTo(this.container.playback, Events$1.PLAYBACK_PROGRESS, this.onProgress);
44053
+ this.listenTo(this.container.playback, Events$1.PLAYBACK_TIMEUPDATE, this.onTimeUpdate);
44054
+ }
44055
+ /**
44056
+ * @internal
44057
+ */
44058
+ destroy() {
44059
+ this.stopReporting();
44060
+ super.destroy();
44061
+ }
44062
+ /**
44063
+ * Returns the collected metrics.
44064
+ * @returns Measurements collected so far
44065
+ */
44066
+ exportMetrics() {
44067
+ return structuredClone(this.metrics);
44068
+ }
44069
+ onBitrate(newBitrate) {
44070
+ const bitrate = newBitrate.bitrate;
44071
+ const now = this.now();
44072
+ if (this.metrics.extra.bitratesHistory.length > 0) {
44073
+ const last = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
44074
+ last.end = now;
44075
+ last.time = now - last.start;
44076
+ }
44077
+ this.metrics.extra.bitratesHistory.push({ start: this.now(), bitrate });
44078
+ this.inc(Counter.ChangeLevel);
44079
+ }
44080
+ stopReporting() {
44081
+ this.buildReport();
44082
+ if (this.timerId !== null) {
44083
+ clearInterval(this.timerId);
44084
+ this.timerId = null;
44085
+ }
44086
+ }
44087
+ startTimers() {
44088
+ this.timerId = setInterval(this.buildReport.bind(this), this.runEach);
44089
+ this.start(Chronograph.Session);
44090
+ this.start(Chronograph.Startup);
44091
+ }
44092
+ onFirstPlaying() {
44093
+ this.listenTo(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
44094
+ this.start(Chronograph.Watch);
44095
+ this.stop(Chronograph.Startup);
44096
+ }
44097
+ playAfterPause() {
44098
+ this.listenTo(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
44099
+ this.stop(Chronograph.Pause);
44100
+ this.start(Chronograph.Watch);
44101
+ }
44102
+ onPlay() {
44103
+ this.inc(Counter.Play);
44104
+ }
44105
+ onPause() {
44106
+ this.stop(Chronograph.Watch);
44107
+ this.start(Chronograph.Pause);
44108
+ this.inc(Counter.Pause);
44109
+ this.listenToOnce(this.container, Events$1.CONTAINER_PLAY, this.playAfterPause);
44110
+ this.stopListening(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
44111
+ }
44112
+ onSeek(e) {
44113
+ this.inc(Counter.Seek);
44114
+ this.metrics.extra.watchHistory.push([e * 1000, e * 1000]);
44115
+ }
44116
+ onTimeUpdate(e) {
44117
+ const current = e.current * 1000, total = e.total * 1000, l = this.metrics.extra.watchHistory.length;
44118
+ this.metrics.extra.duration = total;
44119
+ this.metrics.extra.currentTime = current;
44120
+ // TODO what if it's a live stream?
44121
+ this.metrics.extra.watchedPercentage = (current / total) * 100;
44122
+ if (l === 0) {
44123
+ this.metrics.extra.watchHistory.push([current, current]);
44124
+ }
44125
+ else {
44126
+ this.metrics.extra.watchHistory[l - 1][1] = current;
44127
+ }
44128
+ if (this.metrics.extra.bitratesHistory.length > 0) {
44129
+ const lastBitrate = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
44130
+ if (!lastBitrate.end) {
44131
+ lastBitrate.time = this.now() - lastBitrate.start;
44132
+ }
44133
+ }
44134
+ this.onCompletion();
44135
+ }
44136
+ onContainerUpdateWhilePlaying() {
44137
+ if (this.container.playback.isPlaying()) {
44138
+ this.stop(Chronograph.Watch);
44139
+ this.start(Chronograph.Watch);
44140
+ }
44141
+ }
44142
+ onBuffering() {
44143
+ this.inc(Counter.Buffering);
44144
+ this.start(Chronograph.Buffering);
44145
+ this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERFULL, this.onBufferfull);
44146
+ }
44147
+ onBufferfull() {
44148
+ this.stop(Chronograph.Buffering);
44149
+ this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERING, this.onBuffering);
44150
+ }
44151
+ onProgress(progress) {
44152
+ this.metrics.extra.buffersize = progress.current * 1000;
44153
+ }
44154
+ onCompletion() {
44155
+ // Decide if this is needed
44156
+ // const currentPercentage = this.metrics.extra.watchedPercentage;
44157
+ // this.trigger(ClapprStatsEvents.PERCENTAGE, currentPercentage);
44158
+ }
44159
+ buildReport() {
44160
+ this.stop(Chronograph.Session);
44161
+ this.start(Chronograph.Session);
44162
+ this.metrics.extra.playbackName = this.playbackName;
44163
+ this.metrics.extra.playbackType = this.playbackType;
44164
+ this.calcBitrates();
44165
+ this.calcBufferingPercentage();
44166
+ // TODO calc FPS properly, e.g., on TIMEUPDATE event
44167
+ this.fetchFPS();
44168
+ this.trigger(ClapprStatsEvents.REPORT, structuredClone(this.metrics));
44169
+ }
44170
+ fetchFPS() {
44171
+ // TODO check if the playback and media sources support video, then use the common method
44172
+ // flashls ??? - hls.droppedFramesl hls.stream.bufferLength (seconds)
44173
+ // hls ??? (use the same?)
44174
+ const fetchFPS = {
44175
+ html5_video: this.html5FetchFPS,
44176
+ hls: this.html5FetchFPS,
44177
+ dash: this.html5FetchFPS,
44178
+ };
44179
+ if (this.playbackName in fetchFPS) {
44180
+ fetchFPS[this.playbackName].call(this);
44181
+ }
44182
+ }
44183
+ // TODO sort out
44184
+ calcBitrates() {
44185
+ const { bitratesHistory } = this.metrics.extra;
44186
+ if (bitratesHistory.length === 0) {
44187
+ return;
44188
+ }
44189
+ let totalTime = 0;
44190
+ let weightedTotal = 0;
44191
+ for (const { bitrate, time = 0 } of bitratesHistory) {
44192
+ totalTime += time;
44193
+ weightedTotal += bitrate * time;
44194
+ }
44195
+ this.metrics.extra.bitrateWeightedMean = weightedTotal / totalTime;
44196
+ this.metrics.extra.bitrateMostUsed = bitratesHistory.reduce((mostUsed, current) => (current.time || 0) > (mostUsed.time || 0) ? current : mostUsed, { time: 0, bitrate: 0, start: 0, end: 0 }).bitrate;
44197
+ }
44198
+ calcBufferingPercentage() {
44199
+ if (this.metrics.extra.duration > 0) {
44200
+ this.metrics.extra.bufferingPercentage =
44201
+ (this.metrics.chrono.buffering / this.metrics.extra.duration) * 100;
44202
+ }
44203
+ }
44204
+ html5FetchFPS() {
44205
+ const videoTag = this.container.playback.el;
44206
+ const getFirstValidValue = (...args) => args.find((val) => val !== undefined);
44207
+ const decodedFrames = getFirstValidValue(videoTag.webkitDecodedFrameCount, videoTag.mozDecodedFrames, 0);
44208
+ const droppedFrames = getFirstValidValue(videoTag.webkitDroppedFrameCount, videoTag.mozParsedFrames && videoTag.mozDecodedFrames
44209
+ ? videoTag.mozParsedFrames - videoTag.mozDecodedFrames
44210
+ : 0, 0);
44211
+ const delta = decodedFrames - (this.lastDecodedFramesCount || 0);
44212
+ this.metrics.counters.decodedFrames = decodedFrames;
44213
+ this.metrics.counters.droppedFrames = droppedFrames;
44214
+ this.metrics.counters.fps = delta / (this.runEach / 1000); // TODO use time delta instead of runEach
44215
+ this.lastDecodedFramesCount = decodedFrames;
44216
+ }
44217
+ }
44218
+
43888
44219
  var mousetrap = {exports: {}};
43889
44220
 
43890
44221
  /*global define:false */
@@ -44952,56 +45283,6 @@ function requireMousetrap () {
44952
45283
  var mousetrapExports = requireMousetrap();
44953
45284
  const Mousetrap = /*@__PURE__*/getDefaultExportFromCjs$1(mousetrapExports);
44954
45285
 
44955
- /**
44956
- * @beta
44957
- */
44958
- var ClapprStatsEvents;
44959
- (function (ClapprStatsEvents) {
44960
- ClapprStatsEvents["REPORT_EVENT"] = "clappr:stats:report";
44961
- ClapprStatsEvents["PERCENTAGE_EVENT"] = "clappr:stats:percentage";
44962
- })(ClapprStatsEvents || (ClapprStatsEvents = {}));
44963
-
44964
- function newMetrics$1() {
44965
- return {
44966
- counters: {
44967
- play: 0,
44968
- pause: 0,
44969
- error: 0,
44970
- buffering: 0,
44971
- decodedFrames: 0,
44972
- droppedFrames: 0,
44973
- fps: 0,
44974
- changeLevel: 0,
44975
- seek: 0,
44976
- fullscreen: 0,
44977
- dvrUsage: 0,
44978
- },
44979
- timers: {
44980
- startup: 0,
44981
- watch: 0,
44982
- pause: 0,
44983
- buffering: 0,
44984
- session: 0,
44985
- latency: 0,
44986
- },
44987
- extra: {
44988
- playbackName: '',
44989
- playbackType: '',
44990
- bitratesHistory: [],
44991
- bitrateWeightedMean: 0,
44992
- bitrateMostUsed: 0,
44993
- buffersize: 0,
44994
- watchHistory: [],
44995
- watchedPercentage: 0,
44996
- bufferingPercentage: 0,
44997
- bandwidth: 0,
44998
- duration: 0,
44999
- currentTime: 0,
45000
- },
45001
- custom: {},
45002
- };
45003
- }
45004
-
45005
45286
  var humanFormat$2 = {exports: {}};
45006
45287
 
45007
45288
  var humanFormat$1 = humanFormat$2.exports;
@@ -46026,7 +46307,7 @@ const drawSummary = (customMetrics, vodContainer, liveContainer) => {
46026
46307
  vodContainer.html(vodHtml);
46027
46308
  liveContainer.html(liveHtml);
46028
46309
  };
46029
- const T$f = 'plugins.clappr_nerd_stats';
46310
+ const T$f = 'plugins.nerd_stats';
46030
46311
  /**
46031
46312
  * `PLUGIN` that displays useful network-related statistics.
46032
46313
  * @beta
@@ -46043,7 +46324,7 @@ const T$f = 'plugins.clappr_nerd_stats';
46043
46324
  * When clicked, it shows an overlay window with the information about the network speed, latency, etc,
46044
46325
  * and recommended quality level.
46045
46326
  */
46046
- class ClapprNerdStats extends UICorePlugin {
46327
+ class NerdStats extends UICorePlugin {
46047
46328
  container = null;
46048
46329
  customMetrics = {
46049
46330
  connectionSpeed: 0,
@@ -46126,32 +46407,29 @@ class ClapprNerdStats extends UICorePlugin {
46126
46407
  this.listenTo(bottomGear, GearEvents.RENDERED, this.addToBottomGear);
46127
46408
  this.container = this.core.activeContainer;
46128
46409
  const clapprStats = this.container?.getPlugin('clappr_stats');
46129
- if (!clapprStats) {
46130
- reportError({
46131
- message: 'clappr_stats plugin is not available',
46132
- });
46133
- console.error('clappr-stats not available. Please, include it as a plugin of your Clappr instance.\n' +
46134
- 'For more info, visit: https://github.com/clappr/clappr-stats.');
46135
- this.disable();
46136
- }
46137
- else {
46138
- Mousetrap.bind(this.shortcut, () => this.toggle());
46139
- this.listenTo(this.core, Events$1.CORE_RESIZE, this.onPlayerResize);
46140
- // TODO: fix
46141
- this.listenTo(clapprStats, ClapprStatsEvents.REPORT_EVENT, this.updateMetrics);
46142
- clapprStats.setUpdateMetrics(this.updateMetrics.bind(this));
46143
- this.updateMetrics(clapprStats.exportMetrics());
46144
- this.render();
46145
- }
46410
+ assert(clapprStats, 'clappr-stats not available. Please, include it as a plugin of your Clappr instance.\n' +
46411
+ 'For more info, visit: https://github.com/clappr/clappr-stats.');
46412
+ Mousetrap.bind(this.shortcut, this.toggle);
46413
+ this.listenTo(this.core, Events$1.CORE_RESIZE, this.onPlayerResize);
46414
+ this.listenTo(clapprStats, ClapprStatsEvents.REPORT, this.updateMetrics);
46415
+ this.updateMetrics(clapprStats.exportMetrics());
46416
+ this.render();
46146
46417
  }
46147
- toggle() {
46418
+ /**
46419
+ * @internal
46420
+ */
46421
+ destroy() {
46422
+ Mousetrap.unbind(this.shortcut);
46423
+ return super.destroy();
46424
+ }
46425
+ toggle = () => {
46148
46426
  if (this.showing) {
46149
46427
  this.hide();
46150
46428
  }
46151
46429
  else {
46152
46430
  this.show();
46153
46431
  }
46154
- }
46432
+ };
46155
46433
  show() {
46156
46434
  this.core.$el.find(this.statsBoxElem).show();
46157
46435
  this.showing = true;
@@ -46209,7 +46487,7 @@ class ClapprNerdStats extends UICorePlugin {
46209
46487
  this.addGeneralMetrics();
46210
46488
  this.addCustomMetrics();
46211
46489
  const scrollTop = this.core.$el.find(this.statsBoxElem).scrollTop();
46212
- this.$el.html(ClapprNerdStats.template({
46490
+ this.$el.html(NerdStats.template({
46213
46491
  metrics: Formatter.format(this.metrics),
46214
46492
  iconPosition: this.iconPosition,
46215
46493
  }));
@@ -46245,8 +46523,8 @@ class ClapprNerdStats extends UICorePlugin {
46245
46523
  trace(`${T$f} addToBottomGear`);
46246
46524
  const gear = this.core.getPlugin('bottom_gear');
46247
46525
  gear
46248
- .addItem('nerd')
46249
- .html(ClapprNerdStats.buttonTemplate({
46526
+ .addItem('nerd_stats')
46527
+ .html(NerdStats.buttonTemplate({
46250
46528
  icon: statsIcon,
46251
46529
  i18n: this.core.i18n,
46252
46530
  }))
@@ -46288,362 +46566,6 @@ function newMetrics() {
46288
46566
  };
46289
46567
  }
46290
46568
 
46291
- // TODO: fix
46292
- const updateMetrics = () => { };
46293
- /**
46294
- * `PLUGIN` that collects useful statistics about playback performance.
46295
- * @beta
46296
- * @remarks
46297
- * This plugin does not render anything and is supposed to be extended or used together with other plugins that actually render something.
46298
- */
46299
- class ClapprStats extends ContainerPlugin {
46300
- bwMeasureCount = 0;
46301
- intervalId = null;
46302
- lastDecodedFramesCount = 0;
46303
- metrics = newMetrics$1();
46304
- completion;
46305
- _onReport;
46306
- runBandwidthTestEvery;
46307
- runEach;
46308
- timers = {
46309
- startup: 0,
46310
- watch: 0,
46311
- pause: 0,
46312
- buffering: 0,
46313
- session: 0,
46314
- latency: 0,
46315
- };
46316
- updateFn = updateMetrics;
46317
- urisToMeasureBandwidth;
46318
- uriToMeasureLatency;
46319
- /**
46320
- * @internal
46321
- */
46322
- get name() {
46323
- return 'clappr_stats';
46324
- }
46325
- /**
46326
- * @internal
46327
- */
46328
- get supportedVersion() {
46329
- return { min: CLAPPR_VERSION$1 };
46330
- }
46331
- get _playbackName() {
46332
- return String(this.container.playback.name || '');
46333
- }
46334
- get _playbackType() {
46335
- return this.container.getPlaybackType();
46336
- }
46337
- _now() {
46338
- const hasPerformanceSupport = window.performance && typeof (window.performance.now) === 'function';
46339
- return (hasPerformanceSupport) ? window.performance.now() : new Date().getTime();
46340
- }
46341
- _inc(counter) {
46342
- this.metrics.counters[counter] += 1;
46343
- }
46344
- // _timerHasStarted(timer) {
46345
- // return this[`_start${timer}`] !== undefined;
46346
- // }
46347
- start(timer) {
46348
- // this[`_start${timer}`] = this._now();
46349
- this.timers[timer] = this._now();
46350
- }
46351
- _stop(timer) {
46352
- // this._metrics.timers[timer] += this._now() - this[`_start${timer}`];
46353
- this.metrics.timers[timer] += this._now() - this.timers[timer];
46354
- }
46355
- /**
46356
- * Registers a callback to receive the metrics.
46357
- * @param updateMetricsFn - The callback to receive the metrics
46358
- */
46359
- setUpdateMetrics(updateMetricsFn) {
46360
- // TODO use events instead
46361
- this.updateFn = updateMetricsFn;
46362
- }
46363
- _defaultReport(metrics) {
46364
- this.updateFn(metrics);
46365
- }
46366
- constructor(container) {
46367
- super(container);
46368
- this.runEach = container.options.clapprStats?.runEach ?? 5000;
46369
- this._onReport = container.options.clapprStats?.onReport ?? this._defaultReport;
46370
- this.uriToMeasureLatency = container.options.clapprStats?.uriToMeasureLatency;
46371
- this.urisToMeasureBandwidth = container.options.clapprStats?.urisToMeasureBandwidth;
46372
- this.runBandwidthTestEvery = container.options.clapprStats?.runBandwidthTestEvery ?? 10;
46373
- this.completion = {
46374
- watch: container.options.clapprStats?.onCompletion ?? [],
46375
- calls: []
46376
- };
46377
- }
46378
- /**
46379
- * @internal
46380
- */
46381
- bindEvents() {
46382
- this.listenTo(this.container, Events$1.CONTAINER_BITRATE, this.onBitrate);
46383
- this.listenTo(this.container, Events$1.CONTAINER_STOP, this.stopReporting);
46384
- this.listenTo(this.container, Events$1.CONTAINER_ENDED, this.stopReporting);
46385
- this.listenToOnce(this.container.playback, Events$1.PLAYBACK_PLAY_INTENT, this.startTimers);
46386
- this.listenToOnce(this.container, Events$1.CONTAINER_PLAY, this.onFirstPlaying);
46387
- this.listenTo(this.container, Events$1.CONTAINER_PLAY, this.onPlay);
46388
- this.listenTo(this.container, Events$1.CONTAINER_PAUSE, this.onPause);
46389
- this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERING, this.onBuffering);
46390
- this.listenTo(this.container, Events$1.CONTAINER_SEEK, this.onSeek);
46391
- this.listenTo(this.container, Events$1.CONTAINER_ERROR, () => this._inc('error'));
46392
- this.listenTo(this.container, Events$1.CONTAINER_FULLSCREEN, () => this._inc('fullscreen'));
46393
- this.listenTo(this.container, Events$1.CONTAINER_PLAYBACKDVRSTATECHANGED, (dvrInUse) => {
46394
- dvrInUse && this._inc('dvrUsage');
46395
- });
46396
- this.listenTo(this.container.playback, Events$1.PLAYBACK_PROGRESS, this.onProgress);
46397
- this.listenTo(this.container.playback, Events$1.PLAYBACK_TIMEUPDATE, this.onTimeUpdate);
46398
- }
46399
- /**
46400
- * @internal
46401
- */
46402
- destroy() {
46403
- this.stopReporting();
46404
- super.destroy();
46405
- }
46406
- /**
46407
- * Returns the collected metrics.
46408
- * @returns Currently collected metrics
46409
- */
46410
- exportMetrics() {
46411
- return structuredClone(this.metrics);
46412
- }
46413
- onBitrate(newBitrate) {
46414
- const bitrate = newBitrate.bitrate;
46415
- const now = this._now();
46416
- if (this.metrics.extra.bitratesHistory.length > 0) {
46417
- const beforeLast = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
46418
- beforeLast.end = now;
46419
- beforeLast.time = now - beforeLast.start;
46420
- }
46421
- this.metrics.extra.bitratesHistory.push({ start: this._now(), bitrate: bitrate });
46422
- this._inc('changeLevel');
46423
- }
46424
- stopReporting() {
46425
- this._buildReport();
46426
- if (this.intervalId !== null) {
46427
- clearInterval(this.intervalId);
46428
- this.intervalId = null;
46429
- }
46430
- this._newMetrics();
46431
- // TODO
46432
- // @ts-ignore
46433
- this.stopListening();
46434
- this.bindEvents();
46435
- }
46436
- startTimers() {
46437
- this.intervalId = setInterval(this._buildReport.bind(this), this.runEach);
46438
- this.start('session');
46439
- this.start('startup');
46440
- }
46441
- onFirstPlaying() {
46442
- this.listenTo(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
46443
- this.start('watch');
46444
- this._stop('startup');
46445
- }
46446
- playAfterPause() {
46447
- this.listenTo(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
46448
- this._stop('pause');
46449
- this.start('watch');
46450
- }
46451
- onPlay() {
46452
- this._inc('play');
46453
- }
46454
- onPause() {
46455
- this._stop('watch');
46456
- this.start('pause');
46457
- this._inc('pause');
46458
- this.listenToOnce(this.container, Events$1.CONTAINER_PLAY, this.playAfterPause);
46459
- this.stopListening(this.container, Events$1.CONTAINER_TIMEUPDATE, this.onContainerUpdateWhilePlaying);
46460
- }
46461
- onSeek(e) {
46462
- this._inc('seek');
46463
- this.metrics.extra.watchHistory.push([e * 1000, e * 1000]);
46464
- }
46465
- onTimeUpdate(e) {
46466
- const current = e.current * 1000, total = e.total * 1000, l = this.metrics.extra.watchHistory.length;
46467
- this.metrics.extra.duration = total;
46468
- this.metrics.extra.currentTime = current;
46469
- this.metrics.extra.watchedPercentage = (current / total) * 100;
46470
- if (l === 0) {
46471
- this.metrics.extra.watchHistory.push([current, current]);
46472
- }
46473
- else {
46474
- this.metrics.extra.watchHistory[l - 1][1] = current;
46475
- }
46476
- if (this.metrics.extra.bitratesHistory.length > 0) {
46477
- const lastBitrate = this.metrics.extra.bitratesHistory[this.metrics.extra.bitratesHistory.length - 1];
46478
- if (!lastBitrate.end) {
46479
- lastBitrate.time = this._now() - lastBitrate.start;
46480
- }
46481
- }
46482
- this._onCompletion();
46483
- }
46484
- onContainerUpdateWhilePlaying() {
46485
- if (this.container.playback.isPlaying()) {
46486
- this._stop('watch');
46487
- this.start('watch');
46488
- }
46489
- }
46490
- onBuffering() {
46491
- this._inc('buffering');
46492
- this.start('buffering');
46493
- this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERFULL, this.onBufferfull);
46494
- }
46495
- onBufferfull() {
46496
- this._stop('buffering');
46497
- this.listenToOnce(this.container, Events$1.CONTAINER_STATE_BUFFERING, this.onBuffering);
46498
- }
46499
- onProgress(progress) {
46500
- this.metrics.extra.buffersize = progress.current * 1000;
46501
- }
46502
- _newMetrics() {
46503
- this.metrics = newMetrics$1();
46504
- }
46505
- _onCompletion() {
46506
- const currentPercentage = this.metrics.extra.watchedPercentage;
46507
- const allPercentages = this.completion.watch;
46508
- const isCalled = this.completion.calls.indexOf(currentPercentage) !== -1;
46509
- if (allPercentages.indexOf(currentPercentage) !== -1 && !isCalled) {
46510
- Log.info(this.name + ' PERCENTAGE_EVENT: ' + currentPercentage);
46511
- this.completion.calls.push(currentPercentage);
46512
- this.trigger(ClapprStatsEvents.PERCENTAGE_EVENT, currentPercentage);
46513
- }
46514
- }
46515
- _buildReport() {
46516
- this._stop('session');
46517
- this.start('session');
46518
- this.metrics.extra.playbackName = this._playbackName;
46519
- this.metrics.extra.playbackType = this._playbackType;
46520
- this._calculateBitrates();
46521
- this._calculatePercentages();
46522
- this._fetchFPS();
46523
- this._measureLatency();
46524
- this._measureBandwidth();
46525
- this._onReport(this.metrics);
46526
- this.trigger(ClapprStatsEvents.REPORT_EVENT, structuredClone(this.metrics));
46527
- }
46528
- _fetchFPS() {
46529
- // flashls ??? - hls.droppedFramesl hls.stream.bufferLength (seconds)
46530
- // hls ??? (use the same?)
46531
- const fetchFPS = {
46532
- 'html5_video': this._html5FetchFPS,
46533
- 'hls': this._html5FetchFPS,
46534
- 'dash_shaka_playback': this._html5FetchFPS
46535
- };
46536
- if (this._playbackName in fetchFPS) {
46537
- fetchFPS[this._playbackName].call(this);
46538
- }
46539
- }
46540
- _calculateBitrates() {
46541
- const { bitratesHistory } = this.metrics.extra;
46542
- if (bitratesHistory.length === 0) {
46543
- return;
46544
- }
46545
- let totalTime = 0;
46546
- let weightedTotal = 0;
46547
- for (const { bitrate, time = 0 } of bitratesHistory) {
46548
- totalTime += time;
46549
- weightedTotal += bitrate * time;
46550
- }
46551
- this.metrics.extra.bitrateWeightedMean = weightedTotal / totalTime;
46552
- this.metrics.extra.bitrateMostUsed = bitratesHistory.reduce((mostUsed, current) => (current.time || 0) > (mostUsed.time || 0) ? current : mostUsed, { time: 0, bitrate: 0, start: 0, end: 0 }).bitrate;
46553
- }
46554
- _calculatePercentages() {
46555
- if (this.metrics.extra.duration > 0) {
46556
- this.metrics.extra.bufferingPercentage = (this.metrics.timers.buffering / this.metrics.extra.duration) * 100;
46557
- }
46558
- }
46559
- _html5FetchFPS() {
46560
- const videoTag = this.container.playback.el;
46561
- const getFirstValidValue = (...args) => args.find(val => val !== undefined);
46562
- const decodedFrames = getFirstValidValue(videoTag.webkitDecodedFrameCount, videoTag.mozDecodedFrames, 0);
46563
- const droppedFrames = getFirstValidValue(videoTag.webkitDroppedFrameCount, videoTag.mozParsedFrames && videoTag.mozDecodedFrames ? videoTag.mozParsedFrames - videoTag.mozDecodedFrames : 0, 0);
46564
- const decodedFramesLastTime = decodedFrames - (this.lastDecodedFramesCount || 0);
46565
- this.metrics.counters.decodedFrames = decodedFrames;
46566
- this.metrics.counters.droppedFrames = droppedFrames;
46567
- this.metrics.counters.fps = decodedFramesLastTime / (this.runEach / 1000);
46568
- this.lastDecodedFramesCount = decodedFrames;
46569
- }
46570
- // originally from https://www.smashingmagazine.com/2011/11/analyzing-network-characteristics-using-javascript-and-the-dom-part-1/
46571
- _measureLatency() {
46572
- if (this.uriToMeasureLatency) {
46573
- const t = [];
46574
- const n = 2;
46575
- let rtt;
46576
- const ld = () => {
46577
- t.push(this._now());
46578
- if (t.length > n) {
46579
- done();
46580
- }
46581
- else {
46582
- const img = new Image;
46583
- img.onload = ld;
46584
- img.src = this.uriToMeasureLatency + '?' + Math.random()
46585
- + '=' + this._now();
46586
- }
46587
- };
46588
- const done = () => {
46589
- rtt = t[2] - t[1];
46590
- this.metrics.timers.latency = rtt;
46591
- };
46592
- ld();
46593
- }
46594
- }
46595
- // originally from https://www.smashingmagazine.com/2011/11/analyzing-network-characteristics-using-javascript-and-the-dom-part-1/
46596
- _measureBandwidth() {
46597
- if (this.urisToMeasureBandwidth && (this.bwMeasureCount % this.runBandwidthTestEvery === 0)) {
46598
- let i = 0;
46599
- const ld = (e) => {
46600
- if (i > 0) {
46601
- const prev = this.urisToMeasureBandwidth[i - 1];
46602
- prev.end = this._now();
46603
- if (prev.timer !== null) {
46604
- clearTimeout(prev.timer);
46605
- }
46606
- }
46607
- if (i >= this.urisToMeasureBandwidth.length || (i > 0 && this.urisToMeasureBandwidth[i - 1].expired)) {
46608
- assert(e, 'incorrect invocation in _measureBandwidth');
46609
- done(e);
46610
- }
46611
- else {
46612
- const xhr = new XMLHttpRequest();
46613
- xhr.open('GET', this.urisToMeasureBandwidth[i].url, true);
46614
- xhr.responseType = 'arraybuffer';
46615
- xhr.onload = xhr.onabort = ld;
46616
- this.urisToMeasureBandwidth[i].start = this._now();
46617
- this.urisToMeasureBandwidth[i].timer = setTimeout((j) => {
46618
- this.urisToMeasureBandwidth[j].expired = true;
46619
- xhr.abort();
46620
- }, this.urisToMeasureBandwidth[i].timeout, i);
46621
- xhr.send();
46622
- }
46623
- i++;
46624
- };
46625
- const done = (e) => {
46626
- const timeSpent = (this.urisToMeasureBandwidth[i - 1].end - this.urisToMeasureBandwidth[i - 1].start) / 1000;
46627
- const bandwidthBps = (e.loaded * 8) / timeSpent;
46628
- this.metrics.extra.bandwidth = bandwidthBps;
46629
- this.urisToMeasureBandwidth.forEach((x) => {
46630
- x.start = 0;
46631
- x.end = 0;
46632
- x.expired = false;
46633
- if (x.timer !== null) {
46634
- clearTimeout(x.timer);
46635
- x.timer = null;
46636
- }
46637
- });
46638
- };
46639
- ld();
46640
- }
46641
- this.bwMeasureCount++;
46642
- }
46643
- }
46644
- // ClapprStats.REPORT_EVENT = 'clappr:stats:report';
46645
- // ClapprStats.PERCENTAGE_EVENT = 'clappr:stats:percentage';
46646
-
46647
46569
  // This work is based on the original work of the following authors:
46648
46570
  // Copyright 2014 Globo.com Player authors. All rights reserved.
46649
46571
  // Use of this source code is governed by a BSD-style
@@ -52404,4 +52326,4 @@ class VolumeFade extends UICorePlugin {
52404
52326
  }
52405
52327
  }
52406
52328
 
52407
- export { AudioTracks as AudioSelector, AudioTracks, BigMuteButton, BottomGear, ClapprNerdStats, ClapprStats, ClickToPause, Clips, ClosedCaptions, ContextMenu, DvrControls, ErrorScreen, Favicon, GearEvents, GoogleAnalytics, QualityLevels as LevelSelector, LogTracer, Logger, Logo, MediaControl, MultiCamera, PictureInPicture, PlaybackErrorCode, PlaybackRate, Player, PlayerEvent, Poster, QualityLevels, SeekTime, SentryTracer, Share, SkipTime, SourceController, SpinnerThreeBounce as Spinner, SpinnerEvents, SpinnerThreeBounce, ClosedCaptions as Subtitles, Telemetry, TelemetryEvent, Thumbnails, VolumeFade, VolumeFadeEvents, reportError, setTracer, trace, version };
52329
+ export { AudioTracks as AudioSelector, AudioTracks, BigMuteButton, BottomGear, NerdStats as ClapprNerdStats, ClapprStats, ClickToPause, Clips, ClosedCaptions, ContextMenu, DvrControls, ErrorScreen, Favicon, GearEvents, GoogleAnalytics, QualityLevels as LevelSelector, LogTracer, Logger, Logo, MediaControl, MultiCamera, NerdStats, PictureInPicture, PlaybackErrorCode, PlaybackRate, Player, PlayerEvent, Poster, QualityLevels, SeekTime, SentryTracer, Share, SkipTime, SourceController, SpinnerThreeBounce as Spinner, SpinnerEvents, SpinnerThreeBounce, ClosedCaptions as Subtitles, Telemetry, TelemetryEvent, Thumbnails, VolumeFade, VolumeFadeEvents, reportError, setTracer, trace, version };