eb-player 2.0.0 → 2.0.2

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/dist/build/eb-player.css +661 -5
  2. package/dist/build/ebplayer.bundle.js +95 -33
  3. package/dist/build/ebplayer.bundle.js.map +1 -1
  4. package/dist/build/theme-forja.css +1 -1
  5. package/dist/build/theme-lequipe.css +655 -0
  6. package/dist/build/theme-modern.css +1 -1
  7. package/dist/build/theme-v2.css +1 -1
  8. package/dist/build/types/core/config.d.ts +14 -2
  9. package/dist/build/types/core/config.d.ts.map +1 -1
  10. package/dist/build/types/core/index.d.ts +1 -1
  11. package/dist/build/types/core/index.d.ts.map +1 -1
  12. package/dist/build/types/core/lifecycle.d.ts.map +1 -1
  13. package/dist/build/types/eb-player.d.ts.map +1 -1
  14. package/dist/build/types/engines/hls.d.ts +1 -0
  15. package/dist/build/types/engines/hls.d.ts.map +1 -1
  16. package/dist/build/types/engines/snapshot/hls.d.ts +6 -2
  17. package/dist/build/types/engines/snapshot/hls.d.ts.map +1 -1
  18. package/dist/build/types/integrations/p2p-manager.d.ts.map +1 -1
  19. package/dist/build/types/skin/controls/seekbar.d.ts.map +1 -1
  20. package/dist/dev/default.js +734 -508
  21. package/dist/dev/default.js.map +1 -1
  22. package/dist/dev/easybroadcast.js +103 -38
  23. package/dist/dev/easybroadcast.js.map +1 -1
  24. package/dist/dev/equipe.js +6683 -0
  25. package/dist/dev/equipe.js.map +1 -0
  26. package/dist/eb-player.css +661 -5
  27. package/dist/players/easybroadcast/easybroadcast.js +397 -0
  28. package/dist/players/easybroadcast/index.html +1 -0
  29. package/dist/players/equipe/equipe.js +397 -0
  30. package/dist/players/equipe/index.html +1 -0
  31. package/dist/players/forja/forja.js +198 -111
  32. package/dist/players/forja/index.html +1 -1
  33. package/dist/theme-forja.css +1 -1
  34. package/dist/theme-lequipe.css +655 -0
  35. package/dist/theme-modern.css +1 -1
  36. package/dist/theme-v2.css +1 -1
  37. package/package.json +8 -73
@@ -274,28 +274,45 @@
274
274
  right: ['forward']
275
275
  }
276
276
  };
277
+ /**
278
+ * Available themes — single source of truth for all theme names and labels.
279
+ * The test player reads this to populate the skin selector dynamically.
280
+ * Add new entries here when creating a new theme-*.css file.
281
+ */
282
+ const AVAILABLE_THEMES = [
283
+ { value: 'default', label: 'Default' },
284
+ { value: 'forja', label: 'Forja', primaryColor: '#FC013B' },
285
+ { value: 'radio', label: 'Radio', primaryColor: '#F4A261' },
286
+ { value: 'snrt', label: 'SNRT', primaryColor: '#006633' },
287
+ { value: 'modern', label: 'Modern', primaryColor: '#7c3aed' },
288
+ { value: 'v2', label: 'V2', primaryColor: '#ff841f' },
289
+ { value: 'lequipe', label: "L'Equipe", primaryColor: '#d61e00' },
290
+ ];
277
291
  /**
278
292
  * Theme-specific default layouts.
279
293
  * Used when config.layout is not explicitly provided but a theme is set.
280
294
  */
281
- const THEME_LAYOUTS = {
282
- v2: {
283
- topBar: {
284
- left: [],
285
- right: ['settings', 'pip', 'cast']
286
- },
287
- bottomBar: {
288
- left: ['play-pause', 'live-sync', 'time'],
289
- center: ['seekbar'],
290
- right: ['volume', 'fullscreen']
291
- },
292
- middleBar: {
293
- left: ['rewind'],
294
- center: [],
295
- right: ['forward']
296
- }
295
+ const V2_LAYOUT = {
296
+ topBar: {
297
+ left: [],
298
+ right: ['settings', 'pip', 'cast']
299
+ },
300
+ bottomBar: {
301
+ left: ['play-pause', 'live-sync', 'time'],
302
+ center: ['seekbar'],
303
+ right: ['volume', 'fullscreen']
304
+ },
305
+ middleBar: {
306
+ left: ['rewind'],
307
+ center: [],
308
+ right: ['forward']
297
309
  }
298
310
  };
311
+ const THEME_LAYOUTS = {
312
+ v2: V2_LAYOUT,
313
+ lequipe: V2_LAYOUT,
314
+ modern: V2_LAYOUT,
315
+ };
299
316
  /**
300
317
  * Returns the effective layout for a given config.
301
318
  * Priority: explicit config.layout > theme default > DEFAULT_LAYOUT
@@ -1347,7 +1364,6 @@
1347
1364
  if (this.snapshotTake !== null) {
1348
1365
  this.snapshotTake(this.tooltipTime);
1349
1366
  }
1350
- // Preview video element is set via 'snapshot-handler-ready' event — no creation needed here
1351
1367
  this.render();
1352
1368
  }
1353
1369
  // ---- Chapter helpers ----
@@ -3643,6 +3659,13 @@
3643
3659
  */
3644
3660
  mount(container) {
3645
3661
  this._container = container;
3662
+ // Clear container DOM so a fresh <video> element is created on each mount.
3663
+ // This prevents EME/MediaKeys conflicts — setMediaKeys(null) is async and
3664
+ // hls.js destroy() doesn't wait for it, so reusing the same <video> element
3665
+ // causes "The existing ContentDecryptor" errors on skin switch.
3666
+ container.textContent = '';
3667
+ // Clear lit-html's internal render state so render() treats the container as fresh
3668
+ delete container['_$litPart$'];
3646
3669
  // Clear any stale theme/style from a previous mount cycle
3647
3670
  container.removeAttribute('data-theme');
3648
3671
  container.removeAttribute('style');
@@ -4858,6 +4881,7 @@
4858
4881
  // Private — NEVER in PlayerState (Pitfall 2)
4859
4882
  this.driver = null;
4860
4883
  this.tokenManager = null;
4884
+ this.autoQuality = true;
4861
4885
  // Holds state reference for named driver event handlers
4862
4886
  this.eventState = null;
4863
4887
  this.liveSyncDisabled = false;
@@ -4917,6 +4941,14 @@
4917
4941
  if (this.driver === null)
4918
4942
  return;
4919
4943
  this.driver.currentLevel = index;
4944
+ // When index is -1 (Auto/ABR), hls.js will fire LEVEL_SWITCHED with the
4945
+ // actual resolved level. We need to keep currentQuality as -1 so the UI
4946
+ // shows "Auto" as selected. Track ABR mode to prevent LEVEL_SWITCHED
4947
+ // from overwriting it.
4948
+ this.autoQuality = index === -1;
4949
+ if (this.state !== null) {
4950
+ this.state.currentQuality = index;
4951
+ }
4920
4952
  }
4921
4953
  setAudioTrack(index) {
4922
4954
  if (this.driver === null)
@@ -4978,7 +5010,7 @@
4978
5010
  token: config.token,
4979
5011
  tokenType: config.tokenType,
4980
5012
  srcInTokenRequest: config.srcInTokenRequest,
4981
- extraParamsCallback: config.extraParamsCallback,
5013
+ extraParamsCallback: (config.engineSettings.extraParamsCallback ?? config.extraParamsCallback),
4982
5014
  onCDNTokenError: config.engineSettings.onCDNTokenError
4983
5015
  });
4984
5016
  // Fetch initial token
@@ -4989,7 +5021,7 @@
4989
5021
  if (this.detached)
4990
5022
  return;
4991
5023
  }
4992
- console.info('HlsEngine: loading hls.js from', hlsjsUrl);
5024
+ // console.info('HlsEngine: loading hls.js from', hlsjsUrl)
4993
5025
  const Hls = await loadScript(hlsjsUrl, 'Hls');
4994
5026
  // Guard: abort if detached during CDN script load
4995
5027
  if (this.detached)
@@ -5146,8 +5178,12 @@
5146
5178
  const state = this.eventState;
5147
5179
  if (!state)
5148
5180
  return;
5149
- const switchedData = data;
5150
- state.currentQuality = switchedData.level;
5181
+ // In ABR mode (autoQuality), keep currentQuality as -1 so the UI shows "Auto".
5182
+ // Only update to the actual level index when the user picked a specific quality.
5183
+ if (!this.autoQuality) {
5184
+ const switchedData = data;
5185
+ state.currentQuality = switchedData.level;
5186
+ }
5151
5187
  }
5152
5188
  _onAudioTracksUpdated(_event, data) {
5153
5189
  const state = this.eventState;
@@ -5526,7 +5562,7 @@
5526
5562
  };
5527
5563
  // Register with AbortSignal so it auto-removes when engine is detached
5528
5564
  window.addEventListener('unhandledrejection', this.dvrErrorHandler, { signal });
5529
- console.info('DashEngine: loading dashjs from', dashjsUrl);
5565
+ // console.info('DashEngine: loading dashjs from', dashjsUrl)
5530
5566
  const dashjs = await loadScript(dashjsUrl, 'dashjs');
5531
5567
  const player = dashjs.MediaPlayer().create();
5532
5568
  if (!player) {
@@ -5692,7 +5728,9 @@
5692
5728
  this.lib.start();
5693
5729
  // Clean up on abort
5694
5730
  signal.addEventListener('abort', () => {
5695
- this.lib.stop();
5731
+ if (this.lib !== null && typeof this.lib.stop === 'function') {
5732
+ this.lib.stop();
5733
+ }
5696
5734
  this.lib = null;
5697
5735
  }, { once: true });
5698
5736
  }
@@ -5725,6 +5763,10 @@
5725
5763
  /**
5726
5764
  * Initialize the snapshot Hls instance using the CDN-loaded Hls constructor.
5727
5765
  * Creates a separate Hls instance with minimal buffering for thumbnail generation.
5766
+ *
5767
+ * Returns a promise that resolves once the manifest is loaded and the snapshot
5768
+ * handler is ready to serve seek thumbnails — matching the legacy Vue 2 behaviour
5769
+ * where the handler only resolved after MANIFEST_LOADED.
5728
5770
  */
5729
5771
  init(HlsConstructor) {
5730
5772
  // Create an off-screen video element for the snapshot player
@@ -5775,6 +5817,16 @@
5775
5817
  if (this.config.src) {
5776
5818
  driver.loadSource(this.config.src);
5777
5819
  }
5820
+ // Wait for the manifest to load before resolving — the snapshot handler is only
5821
+ // useful once hls.js knows about the available levels and can seek to segments.
5822
+ // This matches the legacy Vue 2 code which resolved after MANIFEST_LOADED and
5823
+ // forced loadLevel = 0 to pin the lowest quality for thumbnails.
5824
+ return new Promise((resolve) => {
5825
+ driver.once(HlsConstructor.Events.MANIFEST_LOADED, () => {
5826
+ driver['loadLevel'] = 0;
5827
+ resolve();
5828
+ });
5829
+ });
5778
5830
  }
5779
5831
  /**
5780
5832
  * Seek the snapshot player to the specified time.
@@ -6066,8 +6118,8 @@
6066
6118
  activeSnapshotDestroy = null;
6067
6119
  }
6068
6120
  const isDash = src.includes('.mpd') && mergedConfig.dashjs !== false;
6069
- // Defer init until CDN script is loaded (engine's onAttach loads CDN script async)
6070
- setTimeout(() => {
6121
+ // Wait for engine driver to be ready (CDN script loaded) before initializing snapshot
6122
+ engine.driverReady.then(() => {
6071
6123
  if (isDash) {
6072
6124
  const win = window;
6073
6125
  if (win.dashjs) {
@@ -6086,15 +6138,25 @@
6086
6138
  const win = window;
6087
6139
  if (win.Hls) {
6088
6140
  const handler = new HlsSnapshotHandler({ src, engineSettings: mergedConfig.engineSettings }, null);
6089
- handler.init(win.Hls);
6090
- activeSnapshotDestroy = () => handler.destroy();
6091
- const snapshotVideo = handler.getVideo();
6092
- if (snapshotVideo !== null) {
6093
- controller.bus.emit('snapshot-handler-ready', { take: (time) => handler.take(time), video: snapshotVideo });
6094
- }
6141
+ handler.init(win.Hls)
6142
+ .then(() => {
6143
+ activeSnapshotDestroy = () => handler.destroy();
6144
+ const snapshotVideo = handler.getVideo();
6145
+ if (snapshotVideo !== null) {
6146
+ controller.bus.emit('snapshot-handler-ready', { take: (time) => handler.take(time), video: snapshotVideo });
6147
+ }
6148
+ })
6149
+ .catch((error) => {
6150
+ console.warn('EBPlayer: HlsSnapshotHandler init failed:', error);
6151
+ });
6152
+ }
6153
+ else {
6154
+ console.warn('EBPlayer: window.Hls not available after driverReady — snapshot preview disabled');
6095
6155
  }
6096
6156
  }
6097
- }, 500);
6157
+ }).catch((error) => {
6158
+ console.warn('EBPlayer: Snapshot handler init failed:', error);
6159
+ });
6098
6160
  }
6099
6161
  },
6100
6162
  close() {
@@ -6167,7 +6229,7 @@
6167
6229
  // window.EBPlayer assignment
6168
6230
  // ---------------------------------------------------------------------------
6169
6231
  if (typeof window !== 'undefined') {
6170
- window.EBPlayer = { start, stop, destroy };
6232
+ window.EBPlayer = { start, stop, destroy, AVAILABLE_THEMES, THEME_LAYOUTS };
6171
6233
  }
6172
6234
 
6173
6235
  /**