@gcorevideo/player 2.28.30 → 2.28.36

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 (37) hide show
  1. package/README.md +22 -1
  2. package/assets/{subtitles → cc}/style.scss +5 -0
  3. package/dist/core.js +17 -23
  4. package/dist/index.css +241 -237
  5. package/dist/index.embed.js +79 -59
  6. package/dist/index.js +137 -119
  7. package/docs/api/player.closedcaptionspluginsettings.md +1 -0
  8. package/docs/api/player.md +9 -0
  9. package/docs/api/player.mediacontrol.md +16 -0
  10. package/docs/api/player.thumbnails.md +1 -1
  11. package/lib/Player.d.ts.map +1 -1
  12. package/lib/playback/BasePlayback.d.ts +1 -0
  13. package/lib/playback/BasePlayback.d.ts.map +1 -1
  14. package/lib/playback/BasePlayback.js +3 -0
  15. package/lib/playback/dash-playback/DashPlayback.d.ts +1 -0
  16. package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
  17. package/lib/playback/dash-playback/DashPlayback.js +9 -22
  18. package/lib/playback/hls-playback/HlsPlayback.d.ts.map +1 -1
  19. package/lib/playback/hls-playback/HlsPlayback.js +4 -0
  20. package/lib/plugins/subtitles/ClosedCaptions.d.ts +7 -3
  21. package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -1
  22. package/lib/plugins/subtitles/ClosedCaptions.js +66 -42
  23. package/lib/testUtils.d.ts +1 -0
  24. package/lib/testUtils.d.ts.map +1 -1
  25. package/lib/testUtils.js +3 -0
  26. package/package.json +4 -1
  27. package/src/Player.ts +12 -12
  28. package/src/playback/BasePlayback.ts +4 -0
  29. package/src/playback/dash-playback/DashPlayback.ts +10 -27
  30. package/src/playback/hls-playback/HlsPlayback.ts +4 -0
  31. package/src/plugins/subtitles/ClosedCaptions.ts +75 -47
  32. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +277 -29
  33. package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +3 -3
  34. package/src/testUtils.ts +3 -0
  35. package/tsconfig.tsbuildinfo +1 -1
  36. /package/assets/{subtitles → cc}/combobox.ejs +0 -0
  37. /package/assets/{subtitles → cc}/string.ejs +0 -0
package/dist/index.js CHANGED
@@ -12899,6 +12899,9 @@ class BasePlayback extends HTML5Video$1 {
12899
12899
  super._onPlaying();
12900
12900
  this.trigger(Events$1.PLAYBACK_MEDIACONTROL_ENABLE);
12901
12901
  }
12902
+ setTextTrack(id) {
12903
+ // noop
12904
+ }
12902
12905
  }
12903
12906
 
12904
12907
  var PlaybackEvents;
@@ -12917,10 +12920,11 @@ var PlaybackEvents;
12917
12920
  // https://github.com/clappr/clappr/blob/8752995ea439321ac7ca3cd35e8c64de7a3c3d17/LICENSE
12918
12921
  const AUTO$1 = -1;
12919
12922
  const { now: now$2 } = Utils;
12920
- const T$f = 'playback.dash';
12923
+ const T$e = 'playback.dash';
12921
12924
  class DashPlayback extends BasePlayback {
12922
12925
  _levels = [];
12923
12926
  _currentLevel = AUTO$1;
12927
+ _currentTextTrackId = -1;
12924
12928
  // true when the actual duration is longer than hlsjs's live sync point
12925
12929
  // when this is false playableRegionDuration will be the actual duration
12926
12930
  // when this is true playableRegionDuration will exclude the time after the sync point
@@ -13053,7 +13057,11 @@ class DashPlayback extends BasePlayback {
13053
13057
  streaming: {
13054
13058
  text: {
13055
13059
  defaultEnabled: false,
13056
- dispatchForManualRendering: true,
13060
+ // NOTE: dispatchForManualRendering is not correctly implemented in DASH.js;
13061
+ // it does not work when there are multiple text tracks.
13062
+ // CUE_ENTER and CUE_EXIT events might be dispatched additionally
13063
+ // for a track, other than the currently active one.
13064
+ // dispatchForManualRendering: true, // TODO only when useNativeSubtitles is not true?
13057
13065
  },
13058
13066
  },
13059
13067
  }, this.options.dash);
@@ -13097,24 +13105,6 @@ class DashPlayback extends BasePlayback {
13097
13105
  this._dash.on(_.events.PLAYBACK_RATE_CHANGED, (e) => {
13098
13106
  this.trigger(PlaybackEvents.PLAYBACK_RATE_CHANGED, e.playbackRate);
13099
13107
  });
13100
- this._dash.on(_.events.TRACK_CHANGE_RENDERED, (e) => {
13101
- if (e.mediaType === 'audio') {
13102
- this.trigger(Events$1.PLAYBACK_AUDIO_CHANGED, toClapprTrack$1(e.newMediaInfo));
13103
- }
13104
- });
13105
- this._dash.on(_.events.CUE_ENTER, (e) => {
13106
- this.oncueenter?.({
13107
- end: e.end,
13108
- id: e.id,
13109
- start: e.start,
13110
- text: e.text,
13111
- });
13112
- });
13113
- this._dash.on(_.events.CUE_EXIT, (e) => {
13114
- this.oncueexit?.({
13115
- id: e.id,
13116
- });
13117
- });
13118
13108
  }
13119
13109
  render() {
13120
13110
  this._ready();
@@ -13203,7 +13193,7 @@ class DashPlayback extends BasePlayback {
13203
13193
  this.trigger(Events$1.PLAYBACK_SETTINGSUPDATE);
13204
13194
  }
13205
13195
  _onPlaybackError = (event) => {
13206
- trace(`${T$f} _onPlaybackError`, { type: event.type, code: event.error.code, message: event.error.message });
13196
+ trace(`${T$e} _onPlaybackError`, { type: event.type, code: event.error.code, message: event.error.message });
13207
13197
  };
13208
13198
  _onDASHJSSError = (event) => {
13209
13199
  this._stopTimeUpdateTimer();
@@ -13424,14 +13414,14 @@ class DashPlayback extends BasePlayback {
13424
13414
  this._dash?.setTextTrack(this.closedCaptionsTrackId);
13425
13415
  }
13426
13416
  setTextTrack(id) {
13417
+ this._currentTextTrackId = id;
13427
13418
  this._dash?.setTextTrack(id);
13428
13419
  }
13429
13420
  /**
13430
13421
  * @override
13431
13422
  */
13432
13423
  get closedCaptionsTracks() {
13433
- const tt = this.getTextTracks();
13434
- return tt;
13424
+ return this.getTextTracks();
13435
13425
  }
13436
13426
  getTextTracks() {
13437
13427
  return this._dash?.getTracksFor('text').map((t, index) => ({
@@ -13441,7 +13431,7 @@ class DashPlayback extends BasePlayback {
13441
13431
  id: index,
13442
13432
  label: getTextTrackLabel(t) || "",
13443
13433
  language: t.lang,
13444
- mode: "hidden",
13434
+ mode: this._currentTextTrackId === index ? "showing" : "hidden",
13445
13435
  },
13446
13436
  })) || [];
13447
13437
  }
@@ -50103,7 +50093,7 @@ const { now } = Utils;
50103
50093
  const AUTO = -1;
50104
50094
  const DEFAULT_RECOVER_ATTEMPTS = 16;
50105
50095
  Events$1.register('PLAYBACK_FRAGMENT_PARSING_METADATA');
50106
- const T$e = 'playback.hls';
50096
+ const T$d = 'playback.hls';
50107
50097
  class HlsPlayback extends BasePlayback {
50108
50098
  _ccTracksUpdated = false;
50109
50099
  _currentFragment = null;
@@ -50428,7 +50418,7 @@ class HlsPlayback extends BasePlayback {
50428
50418
  }
50429
50419
  else {
50430
50420
  Log.error('hlsjs: failed to recover', { evt, data });
50431
- trace(`${T$e} _recover failed to recover`, {
50421
+ trace(`${T$d} _recover failed to recover`, {
50432
50422
  type: data.type,
50433
50423
  details: data.details,
50434
50424
  });
@@ -50515,7 +50505,7 @@ class HlsPlayback extends BasePlayback {
50515
50505
  this.trigger(Events$1.PLAYBACK_SETTINGSUPDATE);
50516
50506
  }
50517
50507
  _onHLSJSError(evt, data) {
50518
- trace(`${T$e} _onHLSJSError`, {
50508
+ trace(`${T$d} _onHLSJSError`, {
50519
50509
  fatal: data.fatal,
50520
50510
  type: data.type,
50521
50511
  details: data.details,
@@ -50563,7 +50553,7 @@ class HlsPlayback extends BasePlayback {
50563
50553
  evt,
50564
50554
  data,
50565
50555
  });
50566
- trace(`${T$e} _onHLSJSError trying to recover from network error`, {
50556
+ trace(`${T$d} _onHLSJSError trying to recover from network error`, {
50567
50557
  details: data.details,
50568
50558
  });
50569
50559
  error.level = PlayerError.Levels.WARN;
@@ -50576,7 +50566,7 @@ class HlsPlayback extends BasePlayback {
50576
50566
  evt,
50577
50567
  data,
50578
50568
  });
50579
- trace(`${T$e} _onHLSJSError trying to recover from media error`, {
50569
+ trace(`${T$d} _onHLSJSError trying to recover from media error`, {
50580
50570
  details: data.details,
50581
50571
  });
50582
50572
  error.level = PlayerError.Levels.WARN;
@@ -50606,7 +50596,7 @@ class HlsPlayback extends BasePlayback {
50606
50596
  return;
50607
50597
  }
50608
50598
  Log.warn('hlsjs: non-fatal error occurred', { evt, data });
50609
- trace(`${T$e} _onHLSJSError non-fatal error occurred`, {
50599
+ trace(`${T$d} _onHLSJSError non-fatal error occurred`, {
50610
50600
  type: data.type,
50611
50601
  details: data.details,
50612
50602
  });
@@ -50947,13 +50937,17 @@ class HlsPlayback extends BasePlayback {
50947
50937
  this.trigger(Events$1.PLAYBACK_AUDIO_AVAILABLE, data.audioTracks.map(toClapprTrack));
50948
50938
  }
50949
50939
  _onAudioTrackSwitched(_, data) {
50950
- trace(`${T$e} onAudioTrackSwitched`);
50940
+ trace(`${T$d} onAudioTrackSwitched`);
50951
50941
  // @ts-ignore
50952
50942
  const track = this._hls.audioTracks[data.id];
50953
50943
  this.trigger(Events$1.PLAYBACK_AUDIO_CHANGED, toClapprTrack(track));
50954
50944
  }
50955
50945
  setTextTrack(id) {
50946
+ if (id === this._hls.subtitleTrack) {
50947
+ return;
50948
+ }
50956
50949
  this._hls.subtitleTrack = id;
50950
+ this.cues = [];
50957
50951
  }
50958
50952
  /**
50959
50953
  * @override
@@ -50988,7 +50982,7 @@ function toClapprTrack(t) {
50988
50982
  };
50989
50983
  }
50990
50984
 
50991
- const T$d = 'playback.html5_video';
50985
+ const T$c = 'playback.html5_video';
50992
50986
  const STALL_TIMEOUT = 15000;
50993
50987
  class HTML5Video extends BasePlayback {
50994
50988
  stallTimerId = null;
@@ -51089,7 +51083,7 @@ class HTML5Video extends BasePlayback {
51089
51083
  switchAudioTrack(id) {
51090
51084
  const tracks = this.el.audioTracks;
51091
51085
  const supported = !!tracks;
51092
- trace(`${T$d} switchAudioTrack`, {
51086
+ trace(`${T$c} switchAudioTrack`, {
51093
51087
  supported,
51094
51088
  });
51095
51089
  if (supported) {
@@ -51108,7 +51102,7 @@ function registerPlaybacks() {
51108
51102
  Loader.registerPlayback(DashPlayback);
51109
51103
  }
51110
51104
 
51111
- const T$c = 'gplayer';
51105
+ const T$b = 'gplayer';
51112
51106
  const DEFAULT_OPTIONS = {
51113
51107
  autoPlay: false,
51114
51108
  debug: 'none',
@@ -51444,7 +51438,7 @@ class Player {
51444
51438
  }
51445
51439
  }
51446
51440
  triggerAutoPlay() {
51447
- trace(`${T$c} triggerAutoPlay`);
51441
+ trace(`${T$b} triggerAutoPlay`);
51448
51442
  setTimeout(() => {
51449
51443
  this.player?.play({
51450
51444
  autoPlay: true,
@@ -51462,7 +51456,7 @@ class Player {
51462
51456
  // TODO test
51463
51457
  events = {
51464
51458
  onReady: () => {
51465
- trace(`${T$c} onReady`, {
51459
+ trace(`${T$b} onReady`, {
51466
51460
  ready: this.ready,
51467
51461
  });
51468
51462
  if (this.ready) {
@@ -51496,7 +51490,7 @@ class Player {
51496
51490
  buildCoreOptions(rootNode) {
51497
51491
  const sources = this.buildMediaSourcesList();
51498
51492
  const source = sources[0];
51499
- trace(`${T$c} buildCoreOptions`, {
51493
+ trace(`${T$b} buildCoreOptions`, {
51500
51494
  source,
51501
51495
  sources,
51502
51496
  });
@@ -51573,7 +51567,7 @@ class Player {
51573
51567
  }
51574
51568
  }
51575
51569
 
51576
- var version$1 = "2.28.30";
51570
+ var version$1 = "2.28.36";
51577
51571
 
51578
51572
  var packages = {
51579
51573
  "node_modules/@clappr/core": {
@@ -52006,7 +52000,7 @@ const INITIAL_SETTINGS = {
52006
52000
  default: [],
52007
52001
  seekEnabled: false,
52008
52002
  };
52009
- const T$b = 'plugins.media_control';
52003
+ const T$a = 'plugins.media_control';
52010
52004
  /**
52011
52005
  * Extended events for the {@link MediaControl} plugin
52012
52006
  * @public
@@ -52299,7 +52293,7 @@ class MediaControl extends UICorePlugin {
52299
52293
  * Reenables the plugin disabled earlier with the {@link MediaControl.disable} method
52300
52294
  */
52301
52295
  enable() {
52302
- trace(`${T$b} enable`, {
52296
+ trace(`${T$a} enable`, {
52303
52297
  chromeless: this.options.chromeless,
52304
52298
  userDisabled: this.userDisabled,
52305
52299
  });
@@ -52456,7 +52450,7 @@ class MediaControl extends UICorePlugin {
52456
52450
  this.$el.removeClass('w370');
52457
52451
  this.$el.removeClass('w270');
52458
52452
  this.verticalVolume = false;
52459
- trace(`${T$b} playerResize`, {
52453
+ trace(`${T$a} playerResize`, {
52460
52454
  size,
52461
52455
  width: this.container.$el.width(),
52462
52456
  height: this.container.$el.height(),
@@ -53458,7 +53452,7 @@ class AudioTracks extends UICorePlugin {
53458
53452
 
53459
53453
  const templateHtml$2 = "<div class=\"big-mute-icon-wrapper\" data-big-mute id=\"gplayer-big-mute-button\">\n <div class=\"big-mute-icon gcore-skin-border-color\" data-big-mute-icon id=\"gplayer-big-mute-icon\"></div>\n</div>\n";
53460
53454
 
53461
- const T$a = 'plugins.big_mute_button';
53455
+ const T$9 = 'plugins.big_mute_button';
53462
53456
  // TODO rewrite as a container plugin
53463
53457
  /**
53464
53458
  * `PLUGIN` that displays a big mute button over the video when it's being played muted.
@@ -53521,7 +53515,7 @@ class BigMuteButton extends UICorePlugin {
53521
53515
  if (autoPlay) {
53522
53516
  this.autoPlay = true;
53523
53517
  }
53524
- trace(`${T$a} onPlay`, {
53518
+ trace(`${T$9} onPlay`, {
53525
53519
  autoPlay: this.autoPlay,
53526
53520
  wasMuted,
53527
53521
  volume,
@@ -53535,7 +53529,7 @@ class BigMuteButton extends UICorePlugin {
53535
53529
  }
53536
53530
  onStop(_, metadata) {
53537
53531
  const ui = metadata?.ui;
53538
- trace(`${T$a} onStop`, { ui });
53532
+ trace(`${T$9} onStop`, { ui });
53539
53533
  if (ui) {
53540
53534
  this.destroy();
53541
53535
  }
@@ -56499,7 +56493,7 @@ const PLAYBACK_NAMES = {
56499
56493
  hls: 'HLS.js',
56500
56494
  html5_video: 'Native',
56501
56495
  };
56502
- const T$9 = 'plugins.nerd_stats';
56496
+ const T$8 = 'plugins.nerd_stats';
56503
56497
  /**
56504
56498
  * `PLUGIN` that displays useful statistics regarding the playback as well as the network quality estimation.
56505
56499
  * @public
@@ -56636,7 +56630,7 @@ class NerdStats extends UICorePlugin {
56636
56630
  return super.destroy();
56637
56631
  }
56638
56632
  toggle = () => {
56639
- trace(`${T$9} toggle`, {
56633
+ trace(`${T$8} toggle`, {
56640
56634
  open: this.open,
56641
56635
  });
56642
56636
  if (this.open) {
@@ -56656,14 +56650,14 @@ class NerdStats extends UICorePlugin {
56656
56650
  })
56657
56651
  .catch((e) => {
56658
56652
  reportError(e);
56659
- trace(`${T$9} speedtest error`, {
56653
+ trace(`${T$8} speedtest error`, {
56660
56654
  error: e,
56661
56655
  });
56662
56656
  this.disable();
56663
56657
  });
56664
56658
  }
56665
56659
  hide() {
56666
- trace(`${T$9} hide`);
56660
+ trace(`${T$8} hide`);
56667
56661
  this.$el.hide();
56668
56662
  this.open = false;
56669
56663
  stopSpeedtest();
@@ -57396,7 +57390,7 @@ const reloadIcon = "<svg fill=\"#FFFFFF\" height=\"24\" viewBox=\"0 0 24 24\" wi
57396
57390
 
57397
57391
  const templateHtml = "<div class=\"player-error-screen__content\" data-error-screen>\n <% if (icon) { %>\n <div class=\"player-error-screen__icon\" data-error-screen><%= icon %></div>\n <% } %>\n <div class=\"player-error-screen__title\" data-error-screen><%= title %></div>\n <% if (message) { %>\n <div class=\"player-error-screen__message\" data-error-screen><%= message %></div>\n <% } %>\n <% if (code) { %>\n <div class=\"player-error-screen__code\" data-error-screen><%= i18n.t('error_code') %>: <%= code %></div>\n <% } %>\n <% if (reloadIcon) { %>\n <div class=\"player-error-screen__reload\" data-error-screen><%= reloadIcon %></div>\n <% } %>\n</div>\n";
57398
57392
 
57399
- const T$8 = 'plugins.error_screen';
57393
+ const T$7 = 'plugins.error_screen';
57400
57394
  /**
57401
57395
  * `PLUGIN` that displays fatal errors nicely in the overlay on top of the player.
57402
57396
  * @public
@@ -57448,11 +57442,11 @@ class ErrorScreen extends UICorePlugin {
57448
57442
  this.listenTo(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
57449
57443
  }
57450
57444
  onPlay() {
57451
- trace(`${T$8} onPlay`);
57445
+ trace(`${T$7} onPlay`);
57452
57446
  this.unmount();
57453
57447
  }
57454
57448
  unmount() {
57455
- trace(`${T$8} unmount`);
57449
+ trace(`${T$7} unmount`);
57456
57450
  this.err = null;
57457
57451
  this.$el.remove();
57458
57452
  }
@@ -57465,7 +57459,7 @@ class ErrorScreen extends UICorePlugin {
57465
57459
  };
57466
57460
  }
57467
57461
  reload() {
57468
- trace(`${T$8} reload`);
57462
+ trace(`${T$7} reload`);
57469
57463
  setTimeout(() => {
57470
57464
  this.core.configure({
57471
57465
  reloading: true,
@@ -57488,7 +57482,7 @@ class ErrorScreen extends UICorePlugin {
57488
57482
  }
57489
57483
  }
57490
57484
  onError(err) {
57491
- trace(`${T$8} onError`, { err });
57485
+ trace(`${T$7} onError`, { err });
57492
57486
  if (err.UI) {
57493
57487
  if (this.err) {
57494
57488
  this.unmount();
@@ -57973,7 +57967,7 @@ const streamsMomentoIcon = "<svg id=\"Слой_1\" data-name=\"Слой 1\" xmln
57973
57967
  const streamsWhiteNightsIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"50\" height=\"50\" viewBox=\"0 0 50 50\">\n <defs>\n <clipPath id=\"clip-Icon\">\n <rect width=\"50\" height=\"50\"/>\n </clipPath>\n </defs>\n <g id=\"Icon\" clip-path=\"url(#clip-Icon)\">\n <g id=\"icon2\" transform=\"translate(-0.041 0)\">\n <path id=\"Контур_77\" data-name=\"Контур 77\" d=\"M6.493,13v8.266h6.275V19.74H8.31V17.714h4.006V16.3H8.31V14.53h4.365V13Zm7.5,0v8.266h1.7V15.732h.023l3.438,5.534h1.818V13h-1.7v5.545h-.023L15.8,13Z\" fill=\"#fff\"/>\n <path id=\"Контур_76\" data-name=\"Контур 76\" d=\"M29.949,29.1V26.774H31.94a1.4,1.4,0,0,1,.938.272,1.1,1.1,0,0,1,.313.874,1.155,1.155,0,0,1-.313.9,1.375,1.375,0,0,1-.938.278ZM28.132,25.36v8.266h1.817V30.4h1.818a1.353,1.353,0,0,1,.984.3,1.637,1.637,0,0,1,.394.949c.046.333.079.681.1,1.042a3.2,3.2,0,0,0,.185.938h1.819a1.218,1.218,0,0,1-.191-.423,3.611,3.611,0,0,1-.093-.527c-.019-.185-.033-.367-.041-.544s-.016-.332-.023-.463a5.052,5.052,0,0,0-.087-.625,2.109,2.109,0,0,0-.2-.573,1.586,1.586,0,0,0-.359-.451,1.414,1.414,0,0,0-.556-.284v-.023a1.926,1.926,0,0,0,1-.81,2.494,2.494,0,0,0,.307-1.262,2.308,2.308,0,0,0-.165-.88,2.128,2.128,0,0,0-.486-.724,2.3,2.3,0,0,0-.764-.492,2.67,2.67,0,0,0-1-.179ZM43.506,30.5V25.36H41.689V30.5a2.065,2.065,0,0,1-.37,1.36,1.7,1.7,0,0,1-1.343.434,2.086,2.086,0,0,1-.886-.156,1.283,1.283,0,0,1-.758-.978,3.748,3.748,0,0,1-.058-.66V25.36H36.456V30.5a3.16,3.16,0,0,0,.92,2.5,3.807,3.807,0,0,0,2.6.81,3.82,3.82,0,0,0,2.593-.816,3.132,3.132,0,0,0,.937-2.492Z\" fill=\"#fff\"/>\n <path id=\"Контур_80\" data-name=\"Контур 80\" d=\"M22.646,31.2H4.689a4.505,4.505,0,0,1-4.5-4.5V8.5A4.505,4.505,0,0,1,4.689,4h18.2a4.505,4.505,0,0,1,4.5,4.5v8.445l-.893.1a3.184,3.184,0,0,0-2.846,3.177V30.5l-.465.7ZM4.689,6a2.5,2.5,0,0,0-2.5,2.5V26.7a2.5,2.5,0,0,0,2.5,2.5H21.65V20.22a5.18,5.18,0,0,1,3.739-4.992V8.5a2.5,2.5,0,0,0-2.5-2.5Z\" fill=\"#fff\"/>\n <path id=\"Контур_81\" data-name=\"Контур 81\" d=\"M30.127,47.884a1,1,0,0,1-1-1V43.267H26.846a5.206,5.206,0,0,1-5.2-5.2V20.222a5.206,5.206,0,0,1,5.2-5.2H44.692a5.206,5.206,0,0,1,5.2,5.2V38.068a5.206,5.206,0,0,1-5.2,5.2H35.058l-4.216,4.316A1,1,0,0,1,30.127,47.884ZM26.846,17.022a3.2,3.2,0,0,0-3.2,3.2V38.067a3.2,3.2,0,0,0,3.2,3.2h3.281a1,1,0,0,1,1,1v2.162l2.8-2.86a1,1,0,0,1,.715-.3H44.692a3.2,3.2,0,0,0,3.2-3.2V20.222a3.2,3.2,0,0,0-3.2-3.2Z\" fill=\"#fff\"/>\n </g>\n </g>\n</svg>\n";
57974
57968
 
57975
57969
  const VERSION$4 = '0.0.1';
57976
- const T$7 = 'plugins.multicamera';
57970
+ const T$6 = 'plugins.multicamera';
57977
57971
  /**
57978
57972
  * `PLUGIN` that adds support for loading multiple streams and switching between them using the media control UI.
57979
57973
  * @beta
@@ -58130,7 +58124,7 @@ class MultiCamera extends UICorePlugin {
58130
58124
  onCameraSelect(event) {
58131
58125
  const value = event.currentTarget.dataset
58132
58126
  .multicameraSelectorSelect;
58133
- trace(`${T$7} onCameraSelect`, { value });
58127
+ trace(`${T$6} onCameraSelect`, { value });
58134
58128
  if (value !== undefined) {
58135
58129
  this.changeById(parseInt(value, 10));
58136
58130
  }
@@ -58256,13 +58250,13 @@ class MultiCamera extends UICorePlugin {
58256
58250
  }
58257
58251
  }
58258
58252
  changeById(id) {
58259
- trace(`${T$7} changeById`, { id });
58253
+ trace(`${T$6} changeById`, { id });
58260
58254
  queueMicrotask(() => {
58261
58255
  const playbackOptions = this.core.options.playback || {};
58262
58256
  // TODO figure out what this does
58263
58257
  playbackOptions.recycleVideo = Browser.isMobile;
58264
58258
  this.currentCamera = this.findElementById(id) ?? null;
58265
- trace(`${T$7} changeById`, {
58259
+ trace(`${T$6} changeById`, {
58266
58260
  id,
58267
58261
  currentCamera: this.currentCamera,
58268
58262
  multicamera: this.multicamera,
@@ -58283,7 +58277,7 @@ class MultiCamera extends UICorePlugin {
58283
58277
  // TODO remove?
58284
58278
  // for html5 playback:
58285
58279
  this.options.dvrEnabled = this.currentCamera.dvr;
58286
- trace(`${T$7} changeById`, { currentCamera: this.currentCamera });
58280
+ trace(`${T$6} changeById`, { currentCamera: this.currentCamera });
58287
58281
  // TODO
58288
58282
  this.core.configure({
58289
58283
  playback: playbackOptions,
@@ -58346,7 +58340,7 @@ const pipIcon = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"no
58346
58340
  const buttonHtml$2 = "<button class=\"gplayer-lite-btn gcore-skin-button-color\">\n <%= pipIcon %>\n</button>\n";
58347
58341
 
58348
58342
  const VERSION$3 = '0.0.1';
58349
- const T$6 = `plugins.pip`;
58343
+ const T$5 = `plugins.pip`;
58350
58344
  /**
58351
58345
  * `PLUGIN` that enables picture-in-picture mode.
58352
58346
  * @public
@@ -58404,7 +58398,7 @@ class PictureInPicture extends UICorePlugin {
58404
58398
  });
58405
58399
  }
58406
58400
  isPiPSupported() {
58407
- trace(`${T$6} isPiPSupported`, {
58401
+ trace(`${T$5} isPiPSupported`, {
58408
58402
  pictureInPictureEnabled: !!document.pictureInPictureEnabled,
58409
58403
  requestPictureInPicture: !!HTMLVideoElement.prototype.requestPictureInPicture,
58410
58404
  });
@@ -58426,7 +58420,7 @@ class PictureInPicture extends UICorePlugin {
58426
58420
  return this;
58427
58421
  }
58428
58422
  togglePictureInPicture() {
58429
- trace(`${T$6} togglePictureInPicture`);
58423
+ trace(`${T$5} togglePictureInPicture`);
58430
58424
  if (this.videoElement !== document.pictureInPictureElement) {
58431
58425
  this.requestPictureInPicture();
58432
58426
  }
@@ -58435,13 +58429,13 @@ class PictureInPicture extends UICorePlugin {
58435
58429
  }
58436
58430
  }
58437
58431
  requestPictureInPicture() {
58438
- trace(`${T$6} requestPictureInPicture`, {
58432
+ trace(`${T$5} requestPictureInPicture`, {
58439
58433
  videoElement: !!this.videoElement,
58440
58434
  });
58441
58435
  this.videoElement.requestPictureInPicture();
58442
58436
  }
58443
58437
  exitPictureInPicture() {
58444
- trace(`${T$6} exitPictureInPicture`);
58438
+ trace(`${T$5} exitPictureInPicture`);
58445
58439
  document.exitPictureInPicture();
58446
58440
  }
58447
58441
  }
@@ -58468,7 +58462,7 @@ const DEFAULT_PLAYBACK_RATES = [
58468
58462
  { value: 2.0, label: '2x' },
58469
58463
  ];
58470
58464
  const DEFAULT_PLAYBACK_RATE = 1;
58471
- const T$5 = 'plugins.playback_rate';
58465
+ const T$4 = 'plugins.playback_rate';
58472
58466
  /**
58473
58467
  * `PLUGIN` that allows changing the playback speed of the video.
58474
58468
  * @public
@@ -58554,7 +58548,7 @@ class PlaybackRate extends UICorePlugin {
58554
58548
  this.listenTo(this.core, Events$1.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChange);
58555
58549
  }
58556
58550
  onCoreReady() {
58557
- trace(`${T$5} onCoreReady`);
58551
+ trace(`${T$4} onCoreReady`);
58558
58552
  const mediaControl = this.core.getPlugin('media_control');
58559
58553
  assert(mediaControl, 'media_control plugin is required');
58560
58554
  const gear = this.core.getPlugin('bottom_gear');
@@ -58563,7 +58557,7 @@ class PlaybackRate extends UICorePlugin {
58563
58557
  this.listenTo(gear, GearEvents.RENDERED, this.onGearRendered);
58564
58558
  }
58565
58559
  onActiveContainerChange() {
58566
- trace(`${T$5} onActiveContainerChange`);
58560
+ trace(`${T$4} onActiveContainerChange`);
58567
58561
  this.metadataLoaded = false;
58568
58562
  this.listenTo(this.core.activePlayback, Events$1.PLAYBACK_STOP, this.onStop);
58569
58563
  this.listenTo(this.core.activePlayback, Events$1.PLAYBACK_PLAY, this.onPlay);
@@ -58571,15 +58565,15 @@ class PlaybackRate extends UICorePlugin {
58571
58565
  this.listenTo(this.core.activeContainer, Events$1.CONTAINER_LOADEDMETADATA, this.onMetaDataLoaded);
58572
58566
  }
58573
58567
  onMediaControlRendered() {
58574
- trace(`${T$5} onMediaControlRendered`);
58568
+ trace(`${T$4} onMediaControlRendered`);
58575
58569
  this.render();
58576
58570
  }
58577
58571
  onGearRendered() {
58578
- trace(`${T$5} onGearRendered`);
58572
+ trace(`${T$4} onGearRendered`);
58579
58573
  this.mount();
58580
58574
  }
58581
58575
  mount() {
58582
- trace(`${T$5} mount`, {
58576
+ trace(`${T$4} mount`, {
58583
58577
  shouldMount: this.shouldMount(),
58584
58578
  });
58585
58579
  if (!this.shouldMount()) {
@@ -58596,7 +58590,7 @@ class PlaybackRate extends UICorePlugin {
58596
58590
  })));
58597
58591
  }
58598
58592
  onMetaDataLoaded() {
58599
- trace(`${T$5} onMetaDataLoaded`, {
58593
+ trace(`${T$4} onMetaDataLoaded`, {
58600
58594
  playbackType: this.core.activePlayback.getPlaybackType(),
58601
58595
  dvrEnabled: this.core.activePlayback.dvrEnabled,
58602
58596
  });
@@ -58618,7 +58612,7 @@ class PlaybackRate extends UICorePlugin {
58618
58612
  this.core.activePlayback?.setPlaybackRate(this.selectedRate);
58619
58613
  }
58620
58614
  else {
58621
- trace(`${T$5} onPlaybackRateChange not steering to the selected rate, it is seemingly a catchup algorithm working`, {
58615
+ trace(`${T$4} onPlaybackRateChange not steering to the selected rate, it is seemingly a catchup algorithm working`, {
58622
58616
  playbackRate,
58623
58617
  selectedRate: this.selectedRate,
58624
58618
  });
@@ -58681,13 +58675,13 @@ class PlaybackRate extends UICorePlugin {
58681
58675
  }
58682
58676
  }
58683
58677
  syncRate() {
58684
- trace(`${T$5} syncRate`, {
58678
+ trace(`${T$4} syncRate`, {
58685
58679
  selectedRate: this.selectedRate,
58686
58680
  });
58687
58681
  this.core.activePlayback?.setPlaybackRate(this.selectedRate);
58688
58682
  }
58689
58683
  resetPlaybackRate() {
58690
- trace(`${T$5} resetPlaybackRate`, {
58684
+ trace(`${T$4} resetPlaybackRate`, {
58691
58685
  selectedRate: this.selectedRate,
58692
58686
  });
58693
58687
  this.core.activePlayback?.setPlaybackRate(DEFAULT_PLAYBACK_RATE);
@@ -58722,7 +58716,7 @@ class PlaybackRate extends UICorePlugin {
58722
58716
  ?.label || `x${rate}`);
58723
58717
  }
58724
58718
  highlightCurrentRate() {
58725
- trace(`${T$5} highlightCurrentRate`, {
58719
+ trace(`${T$4} highlightCurrentRate`, {
58726
58720
  selectedRate: this.selectedRate,
58727
58721
  });
58728
58722
  this.allRateElements().removeClass('current');
@@ -59758,7 +59752,7 @@ class SpinnerThreeBounce extends UIContainerPlugin {
59758
59752
  }
59759
59753
  }
59760
59754
 
59761
- const T$4 = 'plugins.source_controller';
59755
+ const T$3 = 'plugins.source_controller';
59762
59756
  const INITIAL_RETRY_DELAY = 1000;
59763
59757
  const MAX_RETRY_DELAY = 5000;
59764
59758
  const RETRY_DELAY_BLUR = 500;
@@ -59934,7 +59928,7 @@ class SourceController extends CorePlugin {
59934
59928
  }
59935
59929
  bindContainerEventListeners() {
59936
59930
  this.core.activePlayback.on(Events$1.PLAYBACK_ERROR, (error) => {
59937
- trace(`${T$4} on PLAYBACK_ERROR`, {
59931
+ trace(`${T$3} on PLAYBACK_ERROR`, {
59938
59932
  error: {
59939
59933
  code: error?.code,
59940
59934
  description: error?.description,
@@ -59958,7 +59952,7 @@ class SourceController extends CorePlugin {
59958
59952
  }
59959
59953
  });
59960
59954
  this.listenTo(this.core.activeContainer, Events$1.CONTAINER_PLAY, (_, { autoPlay }) => {
59961
- trace(`${T$4} onContainerPlay`, {
59955
+ trace(`${T$3} onContainerPlay`, {
59962
59956
  autoPlay,
59963
59957
  currentSource: this.sourcesList[this.currentSourceIndex],
59964
59958
  retrying: this.active,
@@ -59976,7 +59970,7 @@ class SourceController extends CorePlugin {
59976
59970
  this.sourcesDelay = {};
59977
59971
  }
59978
59972
  retryPlayback() {
59979
- trace(`${T$4} retryPlayback enter`, {
59973
+ trace(`${T$3} retryPlayback enter`, {
59980
59974
  currentSourceIndex: this.currentSourceIndex,
59981
59975
  currentSource: this.sourcesList[this.currentSourceIndex],
59982
59976
  });
@@ -59984,18 +59978,18 @@ class SourceController extends CorePlugin {
59984
59978
  this.switching = true;
59985
59979
  this.core.activeContainer?.getPlugin('spinner')?.show(0);
59986
59980
  this.getNextMediaSource().then((nextSource) => {
59987
- trace(`${T$4} retryPlayback syncing...`, {
59981
+ trace(`${T$3} retryPlayback syncing...`, {
59988
59982
  nextSource,
59989
59983
  });
59990
59984
  const rnd = Math.round(RETRY_DELAY_BLUR * Math.random());
59991
59985
  this.sync(() => {
59992
59986
  this.switching = false;
59993
59987
  this.core.load(nextSource.source, nextSource.mimeType);
59994
- trace(`${T$4} retryPlayback loaded`, {
59988
+ trace(`${T$3} retryPlayback loaded`, {
59995
59989
  nextSource,
59996
59990
  });
59997
59991
  setTimeout(() => {
59998
- trace(`${T$4} retryPlayback playing`, {
59992
+ trace(`${T$3} retryPlayback playing`, {
59999
59993
  autoPlay: this.autoPlay,
60000
59994
  nextSource,
60001
59995
  });
@@ -60033,8 +60027,6 @@ const comboboxHTML = "<button\n class='media-control-button media-control-ico
60033
60027
  const stringHTML = "<div class=\"gplayer-cc-line\" id=\"gplayer-cc-line\">\n <p></p>\n</div>\n";
60034
60028
 
60035
60029
  const VERSION = '2.19.14';
60036
- const LOCAL_STORAGE_CC_ID = 'gplayer.plugins.cc.selected';
60037
- const T$3 = 'plugins.cc';
60038
60030
  /**
60039
60031
  * `PLUGIN` that provides a UI to select the subtitles when available.
60040
60032
  * @public
@@ -60071,9 +60063,10 @@ const T$3 = 'plugins.cc';
60071
60063
  * ```
60072
60064
  */
60073
60065
  class ClosedCaptions extends UICorePlugin {
60074
- isPreselectedApplied = false;
60066
+ isSelectedApplied = false;
60075
60067
  active = false;
60076
60068
  open = false;
60069
+ userSelectedItemId = -1;
60077
60070
  track = null;
60078
60071
  tracks = [];
60079
60072
  $line = null;
@@ -60135,8 +60128,12 @@ class ClosedCaptions extends UICorePlugin {
60135
60128
  const mediaControl = this.core.getPlugin('media_control');
60136
60129
  assert(mediaControl, 'media_control plugin is required');
60137
60130
  this.listenTo(mediaControl, Events$1.MEDIACONTROL_RENDERED, this.mount);
60131
+ this.listenTo(mediaControl, Events$1.MEDIACONTROL_SHOW, () => {
60132
+ this.$line?.removeClass('media-control-cc-pulled');
60133
+ });
60138
60134
  this.listenTo(mediaControl, Events$1.MEDIACONTROL_HIDE, () => {
60139
60135
  this.hideMenu();
60136
+ this.$line?.addClass('media-control-cc-pulled');
60140
60137
  });
60141
60138
  this.listenTo(mediaControl, ExtendedEvents.MEDIACONTROL_MENU_COLLAPSE, (from) => {
60142
60139
  if (from !== this.name) {
@@ -60171,10 +60168,9 @@ class ClosedCaptions extends UICorePlugin {
60171
60168
  video.classList.remove('ios-fullscreen');
60172
60169
  }
60173
60170
  });
60174
- this.isPreselectedApplied = false;
60171
+ this.isSelectedApplied = false;
60175
60172
  }
60176
60173
  onPlaybackReady() {
60177
- trace(`${T$3} onPlaybackReady`);
60178
60174
  this.core.activePlayback.oncueenter = (e) => {
60179
60175
  this.setSubtitleText(e.text);
60180
60176
  };
@@ -60195,23 +60191,27 @@ class ClosedCaptions extends UICorePlugin {
60195
60191
  this.activateTrack(id);
60196
60192
  }
60197
60193
  activateTrack(id) {
60198
- if (['dash', 'hls'].includes(this.core.activePlayback?.name)) {
60199
- this.core.activePlayback.setTextTrack(id);
60194
+ const isManaged = this.core.activePlayback?.name === 'hls';
60195
+ this.core.activePlayback.setTextTrack(id);
60196
+ if (isManaged) {
60197
+ return;
60198
+ }
60199
+ if (!this.core.activePlayback?.el.textTracks) {
60200
60200
  return;
60201
60201
  }
60202
- for (const track of this.currentTracks) {
60203
- if (track.id === id) {
60202
+ for (const [index, track] of Array.from(this.core.activePlayback?.el.textTracks ?? []).entries()) {
60203
+ if (index === id) {
60204
60204
  if (this.useNativeSubtitles) {
60205
- track.track.mode = 'showing';
60205
+ track.mode = 'showing';
60206
60206
  }
60207
60207
  else {
60208
- track.track.mode = 'hidden';
60208
+ track.mode = 'hidden';
60209
60209
  }
60210
- this.setSubtitleText(this.getSubtitleText(track.track));
60211
- track.track.oncuechange = (e) => {
60210
+ this.setSubtitleText(this.getSubtitleText(track));
60211
+ track.oncuechange = () => {
60212
60212
  try {
60213
- if (track.track.activeCues?.length) {
60214
- const html = track.track.activeCues[0].getCueAsHTML();
60213
+ if (track.activeCues?.length) {
60214
+ const html = track.activeCues[0].getCueAsHTML();
60215
60215
  this.setSubtitleText(html);
60216
60216
  }
60217
60217
  else {
@@ -60224,8 +60224,8 @@ class ClosedCaptions extends UICorePlugin {
60224
60224
  };
60225
60225
  }
60226
60226
  else {
60227
- track.track.oncuechange = () => { };
60228
- track.track.mode = 'disabled';
60227
+ track.oncuechange = () => { };
60228
+ track.mode = 'disabled';
60229
60229
  }
60230
60230
  }
60231
60231
  }
@@ -60233,7 +60233,7 @@ class ClosedCaptions extends UICorePlugin {
60233
60233
  try {
60234
60234
  // TODO ensure to apply only once
60235
60235
  this.currentTracks = this.core.activePlayback.closedCaptionsTracks;
60236
- this.applyPreselectedSubtitles();
60236
+ this.applySelectedSubtitles();
60237
60237
  this.render();
60238
60238
  }
60239
60239
  catch (error) {
@@ -60268,8 +60268,10 @@ class ClosedCaptions extends UICorePlugin {
60268
60268
  this.$el.find('#gplayer-cc-menu').hide();
60269
60269
  this.$el.find('#gplayer-cc-button').attr('aria-expanded', 'false');
60270
60270
  this.$line.hide();
60271
- for (const track of this.currentTracks) {
60272
- track.track.mode = 'hidden';
60271
+ for (const track of this.core.activePlayback.el.textTracks) {
60272
+ if (track.mode === 'showing') {
60273
+ track.mode = 'hidden';
60274
+ }
60273
60275
  }
60274
60276
  }
60275
60277
  /**
@@ -60281,7 +60283,6 @@ class ClosedCaptions extends UICorePlugin {
60281
60283
  if (this.core.activeContainer &&
60282
60284
  isFullscreen(this.core.activeContainer.el) &&
60283
60285
  this.currentTrack &&
60284
- // this.currentTrack.track.mode &&
60285
60286
  (Browser.isiOS || this.useNativeSubtitles)) {
60286
60287
  this.$line.hide();
60287
60288
  this.currentTrack.track.mode = 'showing';
@@ -60323,6 +60324,10 @@ class ClosedCaptions extends UICorePlugin {
60323
60324
  this.resizeFont();
60324
60325
  this.clampPopup();
60325
60326
  this.core.activeContainer.$el.append(this.$line);
60327
+ const mc = this.core.getPlugin('media_control');
60328
+ if (!mc?.isVisible()) {
60329
+ this.$line?.addClass('media-control-cc-pulled');
60330
+ }
60326
60331
  this.updateSelection();
60327
60332
  this.renderIcon();
60328
60333
  return this;
@@ -60340,22 +60345,36 @@ class ClosedCaptions extends UICorePlugin {
60340
60345
  }
60341
60346
  onItemSelect(event) {
60342
60347
  // event.target does not exist for some reason in tests
60343
- const id = (event.target ?? event.currentTarget).dataset?.item ??
60344
- '-1';
60345
- localStorage.setItem(LOCAL_STORAGE_CC_ID, id); // TODO store language instead?
60346
- this.selectItem(this.findById(Number(id)));
60348
+ const id = Number((event.target ?? event.currentTarget).dataset?.item ??
60349
+ '-1');
60350
+ // TODO review, make configurable, and emit event in addition
60351
+ // localStorage.setItem(LOCAL_STORAGE_CC_ID, id) // TODO store language instead?
60352
+ this.userSelectedItemId = id;
60353
+ this.selectItem(this.findById(id));
60347
60354
  this.hideMenu();
60348
60355
  return false;
60349
60356
  }
60350
- applyPreselectedSubtitles() {
60351
- if (!this.isPreselectedApplied) {
60352
- this.isPreselectedApplied = true;
60353
- // if the language is undefined, then let the engine decide
60354
- // to hide the subtitles forcefully, set the language to 'none'
60355
- setTimeout(() => {
60356
- this.selectItem(this.tracks.find((t) => this.isPreselectedLanguage(t.track.language)) ?? null);
60357
- }, 0);
60357
+ applySelectedSubtitles() {
60358
+ if (this.isSelectedApplied) {
60359
+ return;
60358
60360
  }
60361
+ this.isSelectedApplied = true;
60362
+ // If user selected a language, activate that
60363
+ // Otherwise, if there is no configured language, then let the engine decide
60364
+ // To hide the subtitles initially forcefully, set the language to 'none'
60365
+ let matcher;
60366
+ if (this.userSelectedItemId !== -1) {
60367
+ matcher = (track) => track.id === this.userSelectedItemId;
60368
+ }
60369
+ else if (this.preselectedLanguage) {
60370
+ matcher = (track) => this.isPreselectedLanguage(track.track.language);
60371
+ }
60372
+ else {
60373
+ return;
60374
+ }
60375
+ setTimeout(() => {
60376
+ this.selectItem(this.tracks.find(matcher) ?? null);
60377
+ }, 0);
60359
60378
  }
60360
60379
  hideMenu() {
60361
60380
  this.open = false;
@@ -60389,10 +60408,9 @@ class ClosedCaptions extends UICorePlugin {
60389
60408
  return this.$el.find('#gplayer-cc-menu li'); // TODO fix semantically
60390
60409
  }
60391
60410
  selectSubtitles() {
60392
- const trackId = this.currentTrack?.id ?? -1;
60393
- // TODO find out if this is needed
60394
- this.core.activePlayback.closedCaptionsTrackId = trackId;
60395
- // this.core.activePlayback.closedCaptionsTrackId = -1
60411
+ if (this.currentTrack) {
60412
+ this.core.activePlayback.closedCaptionsTrackId = this.currentTrack.id;
60413
+ }
60396
60414
  }
60397
60415
  getSubtitleText(track) {
60398
60416
  const currentTime = this.core.activePlayback?.getCurrentTime() ?? 0;
@@ -60415,7 +60433,7 @@ class ClosedCaptions extends UICorePlugin {
60415
60433
  this.setSubtitleText('');
60416
60434
  }
60417
60435
  updateSelection() {
60418
- if (!this.currentTrack) {
60436
+ if (this.core.activePlayback.closedCaptionsTrackId === -1) {
60419
60437
  this.hide();
60420
60438
  }
60421
60439
  else {