rx-player 4.3.0-dev.2024112900 → 4.3.0-dev.2025012900

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 (174) hide show
  1. package/CHANGELOG.md +30 -8
  2. package/VERSION +1 -1
  3. package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.d.ts +1 -1
  4. package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
  5. package/dist/commonjs/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
  6. package/dist/commonjs/__GENERATED_CODE/embedded_worker.js +1 -1
  7. package/dist/commonjs/compat/browser_compatibility_types.d.ts +7 -2
  8. package/dist/commonjs/compat/browser_compatibility_types.d.ts.map +1 -1
  9. package/dist/commonjs/compat/browser_compatibility_types.js +0 -1
  10. package/dist/commonjs/compat/browser_detection.js +1 -1
  11. package/dist/commonjs/compat/event_listeners.d.ts.map +1 -1
  12. package/dist/commonjs/compat/event_listeners.js +2 -4
  13. package/dist/commonjs/compat/has_mse_in_worker.d.ts.map +1 -1
  14. package/dist/commonjs/core/cmcd/cmcd_data_builder.d.ts.map +1 -1
  15. package/dist/commonjs/core/cmcd/cmcd_data_builder.js +1 -2
  16. package/dist/commonjs/core/main/worker/send_message.d.ts.map +1 -1
  17. package/dist/commonjs/core/main/worker/send_message.js +0 -1
  18. package/dist/commonjs/core/main/worker/worker_main.js +1 -1
  19. package/dist/commonjs/core/stream/adaptation/adaptation_stream.d.ts.map +1 -1
  20. package/dist/commonjs/core/stream/adaptation/adaptation_stream.js +4 -8
  21. package/dist/commonjs/core/stream/period/period_stream.js +1 -3
  22. package/dist/commonjs/core/stream/period/utils/get_adaptation_switch_strategy.js +1 -2
  23. package/dist/commonjs/experimental/tools/mediaCapabilitiesProber/api/index.d.ts.map +1 -1
  24. package/dist/commonjs/main_thread/api/public_api.js +4 -4
  25. package/dist/commonjs/main_thread/decrypt/clear_on_stop.d.ts.map +1 -1
  26. package/dist/commonjs/main_thread/decrypt/clear_on_stop.js +60 -14
  27. package/dist/commonjs/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
  28. package/dist/commonjs/main_thread/decrypt/content_decryptor.js +21 -9
  29. package/dist/commonjs/main_thread/decrypt/dispose_decryption_resources.d.ts.map +1 -1
  30. package/dist/commonjs/main_thread/decrypt/dispose_decryption_resources.js +2 -18
  31. package/dist/commonjs/main_thread/decrypt/find_key_system.d.ts.map +1 -1
  32. package/dist/commonjs/main_thread/decrypt/find_key_system.js +134 -68
  33. package/dist/commonjs/main_thread/decrypt/get_key_system_configuration.js +2 -2
  34. package/dist/commonjs/main_thread/decrypt/get_media_keys.js +5 -3
  35. package/dist/commonjs/main_thread/decrypt/init_media_keys.d.ts.map +1 -1
  36. package/dist/commonjs/main_thread/decrypt/init_media_keys.js +2 -2
  37. package/dist/{es2017/main_thread/decrypt/utils/media_keys_infos_store.d.ts → commonjs/main_thread/decrypt/utils/media_keys_attacher.d.ts} +31 -9
  38. package/dist/commonjs/main_thread/decrypt/utils/media_keys_attacher.d.ts.map +1 -0
  39. package/dist/commonjs/main_thread/decrypt/utils/media_keys_attacher.js +282 -0
  40. package/dist/commonjs/main_thread/init/utils/rebuffering_controller.d.ts.map +1 -1
  41. package/dist/commonjs/main_thread/init/utils/rebuffering_controller.js +20 -9
  42. package/dist/commonjs/main_thread/text_displayer/html/text_track_cues_store.js +1 -1
  43. package/dist/commonjs/main_thread/tracks_store/track_dispatcher.d.ts.map +1 -1
  44. package/dist/commonjs/main_thread/tracks_store/track_dispatcher.js +3 -4
  45. package/dist/commonjs/main_thread/tracks_store/tracks_store.d.ts.map +1 -1
  46. package/dist/commonjs/main_thread/tracks_store/tracks_store.js +1 -1
  47. package/dist/commonjs/manifest/classes/representation.d.ts +15 -1
  48. package/dist/commonjs/manifest/classes/representation.d.ts.map +1 -1
  49. package/dist/commonjs/manifest/classes/representation.js +17 -0
  50. package/dist/commonjs/manifest/utils.d.ts +15 -0
  51. package/dist/commonjs/manifest/utils.d.ts.map +1 -1
  52. package/dist/commonjs/manifest/utils.js +28 -5
  53. package/dist/commonjs/parsers/manifest/dash/common/parse_representations.js +2 -2
  54. package/dist/commonjs/playback_observer/media_element_playback_observer.js +1 -1
  55. package/dist/commonjs/public_types.d.ts +44 -0
  56. package/dist/commonjs/public_types.d.ts.map +1 -1
  57. package/dist/commonjs/utils/flat_map.d.ts +2 -2
  58. package/dist/commonjs/utils/flat_map.js +2 -2
  59. package/dist/commonjs/utils/url-utils.d.ts.map +1 -1
  60. package/dist/commonjs/utils/url-utils.js +11 -10
  61. package/dist/commonjs/utils/xml-parser.d.ts.map +1 -1
  62. package/dist/commonjs/utils/xml-parser.js +10 -8
  63. package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.d.ts +1 -1
  64. package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
  65. package/dist/es2017/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
  66. package/dist/es2017/__GENERATED_CODE/embedded_worker.js +1 -1
  67. package/dist/es2017/compat/browser_compatibility_types.d.ts +7 -2
  68. package/dist/es2017/compat/browser_compatibility_types.d.ts.map +1 -1
  69. package/dist/es2017/compat/browser_compatibility_types.js +0 -1
  70. package/dist/es2017/compat/browser_detection.js +1 -1
  71. package/dist/es2017/compat/event_listeners.d.ts.map +1 -1
  72. package/dist/es2017/compat/event_listeners.js +2 -4
  73. package/dist/es2017/compat/has_mse_in_worker.d.ts.map +1 -1
  74. package/dist/es2017/core/cmcd/cmcd_data_builder.d.ts.map +1 -1
  75. package/dist/es2017/core/cmcd/cmcd_data_builder.js +1 -2
  76. package/dist/es2017/core/main/worker/send_message.d.ts.map +1 -1
  77. package/dist/es2017/core/main/worker/send_message.js +0 -1
  78. package/dist/es2017/core/main/worker/worker_main.js +1 -1
  79. package/dist/es2017/core/stream/adaptation/adaptation_stream.d.ts.map +1 -1
  80. package/dist/es2017/core/stream/adaptation/adaptation_stream.js +4 -6
  81. package/dist/es2017/core/stream/period/period_stream.js +1 -3
  82. package/dist/es2017/core/stream/period/utils/get_adaptation_switch_strategy.js +1 -2
  83. package/dist/es2017/experimental/tools/mediaCapabilitiesProber/api/index.d.ts.map +1 -1
  84. package/dist/es2017/main_thread/api/public_api.js +4 -4
  85. package/dist/es2017/main_thread/decrypt/clear_on_stop.d.ts.map +1 -1
  86. package/dist/es2017/main_thread/decrypt/clear_on_stop.js +3 -3
  87. package/dist/es2017/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
  88. package/dist/es2017/main_thread/decrypt/content_decryptor.js +21 -9
  89. package/dist/es2017/main_thread/decrypt/dispose_decryption_resources.d.ts.map +1 -1
  90. package/dist/es2017/main_thread/decrypt/dispose_decryption_resources.js +2 -12
  91. package/dist/es2017/main_thread/decrypt/find_key_system.d.ts.map +1 -1
  92. package/dist/es2017/main_thread/decrypt/find_key_system.js +102 -56
  93. package/dist/es2017/main_thread/decrypt/get_key_system_configuration.js +2 -2
  94. package/dist/es2017/main_thread/decrypt/get_media_keys.js +2 -2
  95. package/dist/es2017/main_thread/decrypt/init_media_keys.d.ts.map +1 -1
  96. package/dist/es2017/main_thread/decrypt/init_media_keys.js +2 -2
  97. package/dist/{commonjs/main_thread/decrypt/utils/media_keys_infos_store.d.ts → es2017/main_thread/decrypt/utils/media_keys_attacher.d.ts} +31 -9
  98. package/dist/es2017/main_thread/decrypt/utils/media_keys_attacher.d.ts.map +1 -0
  99. package/dist/es2017/main_thread/decrypt/utils/media_keys_attacher.js +180 -0
  100. package/dist/es2017/main_thread/init/utils/rebuffering_controller.d.ts.map +1 -1
  101. package/dist/es2017/main_thread/init/utils/rebuffering_controller.js +20 -9
  102. package/dist/es2017/main_thread/text_displayer/html/text_track_cues_store.js +1 -1
  103. package/dist/es2017/main_thread/tracks_store/track_dispatcher.d.ts.map +1 -1
  104. package/dist/es2017/main_thread/tracks_store/track_dispatcher.js +3 -4
  105. package/dist/es2017/main_thread/tracks_store/tracks_store.d.ts.map +1 -1
  106. package/dist/es2017/main_thread/tracks_store/tracks_store.js +2 -2
  107. package/dist/es2017/manifest/classes/representation.d.ts +15 -1
  108. package/dist/es2017/manifest/classes/representation.d.ts.map +1 -1
  109. package/dist/es2017/manifest/classes/representation.js +17 -0
  110. package/dist/es2017/manifest/utils.d.ts +15 -0
  111. package/dist/es2017/manifest/utils.d.ts.map +1 -1
  112. package/dist/es2017/manifest/utils.js +27 -5
  113. package/dist/es2017/parsers/manifest/dash/common/parse_representations.js +2 -2
  114. package/dist/es2017/playback_observer/media_element_playback_observer.js +1 -1
  115. package/dist/es2017/public_types.d.ts +44 -0
  116. package/dist/es2017/public_types.d.ts.map +1 -1
  117. package/dist/es2017/utils/flat_map.d.ts +2 -2
  118. package/dist/es2017/utils/flat_map.js +2 -2
  119. package/dist/es2017/utils/url-utils.d.ts.map +1 -1
  120. package/dist/es2017/utils/url-utils.js +11 -10
  121. package/dist/es2017/utils/xml-parser.d.ts.map +1 -1
  122. package/dist/es2017/utils/xml-parser.js +10 -8
  123. package/dist/rx-player.js +505 -372
  124. package/dist/rx-player.min.js +18 -18
  125. package/dist/worker.js +6 -6
  126. package/package.json +21 -19
  127. package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
  128. package/src/compat/browser_compatibility_types.ts +22 -4
  129. package/src/compat/browser_detection.ts +1 -1
  130. package/src/compat/event_listeners.ts +2 -4
  131. package/src/compat/has_mse_in_worker.ts +1 -1
  132. package/src/core/cmcd/cmcd_data_builder.ts +1 -4
  133. package/src/core/main/worker/send_message.ts +4 -2
  134. package/src/core/main/worker/worker_main.ts +1 -1
  135. package/src/core/stream/adaptation/adaptation_stream.ts +4 -7
  136. package/src/core/stream/period/period_stream.ts +3 -3
  137. package/src/core/stream/period/utils/get_adaptation_switch_strategy.ts +1 -2
  138. package/src/main_thread/api/public_api.ts +4 -4
  139. package/src/main_thread/decrypt/__tests__/__global__/media_key_system_access.test.ts +239 -6
  140. package/src/main_thread/decrypt/__tests__/find_key_system.test.ts +325 -0
  141. package/src/main_thread/decrypt/clear_on_stop.ts +3 -3
  142. package/src/main_thread/decrypt/content_decryptor.ts +26 -8
  143. package/src/main_thread/decrypt/dispose_decryption_resources.ts +2 -13
  144. package/src/main_thread/decrypt/find_key_system.ts +120 -81
  145. package/src/main_thread/decrypt/get_key_system_configuration.ts +2 -2
  146. package/src/main_thread/decrypt/get_media_keys.ts +2 -2
  147. package/src/main_thread/decrypt/init_media_keys.ts +2 -2
  148. package/src/main_thread/decrypt/utils/media_keys_attacher.ts +284 -0
  149. package/src/main_thread/init/utils/rebuffering_controller.ts +20 -10
  150. package/src/main_thread/text_displayer/html/text_track_cues_store.ts +1 -1
  151. package/src/main_thread/tracks_store/track_dispatcher.ts +3 -6
  152. package/src/main_thread/tracks_store/tracks_store.ts +2 -1
  153. package/src/manifest/classes/representation.ts +18 -1
  154. package/src/manifest/utils.ts +30 -9
  155. package/src/parsers/manifest/dash/common/parse_representations.ts +2 -2
  156. package/src/playback_observer/media_element_playback_observer.ts +1 -1
  157. package/src/public_types.ts +45 -0
  158. package/src/utils/__tests__/flat_map.test.ts +7 -20
  159. package/src/utils/flat_map.ts +2 -2
  160. package/src/utils/url-utils.ts +11 -10
  161. package/src/utils/xml-parser.ts +13 -8
  162. package/vitest.config.mjs +9 -23
  163. package/dist/commonjs/main_thread/decrypt/attach_media_keys.d.ts +0 -60
  164. package/dist/commonjs/main_thread/decrypt/attach_media_keys.d.ts.map +0 -1
  165. package/dist/commonjs/main_thread/decrypt/attach_media_keys.js +0 -124
  166. package/dist/commonjs/main_thread/decrypt/utils/media_keys_infos_store.d.ts.map +0 -1
  167. package/dist/commonjs/main_thread/decrypt/utils/media_keys_infos_store.js +0 -45
  168. package/dist/es2017/main_thread/decrypt/attach_media_keys.d.ts +0 -60
  169. package/dist/es2017/main_thread/decrypt/attach_media_keys.d.ts.map +0 -1
  170. package/dist/es2017/main_thread/decrypt/attach_media_keys.js +0 -73
  171. package/dist/es2017/main_thread/decrypt/utils/media_keys_infos_store.d.ts.map +0 -1
  172. package/dist/es2017/main_thread/decrypt/utils/media_keys_infos_store.js +0 -43
  173. package/src/main_thread/decrypt/attach_media_keys.ts +0 -125
  174. package/src/main_thread/decrypt/utils/media_keys_infos_store.ts +0 -88
@@ -358,7 +358,7 @@ export default class TextTrackCuesStore {
358
358
  }
359
359
  }
360
360
 
361
- if (cuesBuffer.length) {
361
+ if (cuesBuffer.length > 0) {
362
362
  const lastCue = cuesBuffer[cuesBuffer.length - 1];
363
363
  if (areNearlyEqual(lastCue.end, start, relativeDelta)) {
364
364
  // Match the end of the previous cue to the start of the following one
@@ -4,6 +4,7 @@ import type {
4
4
  ITrackSwitchingMode,
5
5
  } from "../../core/types";
6
6
  import type { IAdaptationMetadata, IRepresentationMetadata } from "../../manifest";
7
+ import { isRepresentationPlayable } from "../../manifest";
7
8
  import type {
8
9
  IAudioRepresentationsSwitchingMode,
9
10
  IVideoRepresentationsSwitchingMode,
@@ -184,11 +185,7 @@ export default class TrackDispatcher extends EventEmitter<ITrackDispatcherEvent>
184
185
  if (repSettings === null) {
185
186
  // unlocking
186
187
  playableRepresentations = trackInfo.adaptation.representations.filter(
187
- (representation) => {
188
- return (
189
- representation.isSupported === true && representation.decipherable !== false
190
- );
191
- },
188
+ (representation) => isRepresentationPlayable(representation) === true,
192
189
  );
193
190
 
194
191
  // No need to remove the previous content when unlocking
@@ -200,7 +197,7 @@ export default class TrackDispatcher extends EventEmitter<ITrackDispatcherEvent>
200
197
  arrayIncludes(representationIds, r.id),
201
198
  );
202
199
  playableRepresentations = representations.filter(
203
- (r) => r.isSupported === true && r.decipherable !== false,
200
+ (representation) => isRepresentationPlayable(representation) === true,
204
201
  );
205
202
  if (playableRepresentations.length === 0) {
206
203
  self.trigger("noPlayableLockedRepresentation", null);
@@ -30,6 +30,7 @@ import type {
30
30
  } from "../../manifest";
31
31
  import {
32
32
  getSupportedAdaptations,
33
+ isRepresentationPlayable,
33
34
  toAudioTrack,
34
35
  toTextTrack,
35
36
  toVideoTrack,
@@ -399,7 +400,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
399
400
  return false;
400
401
  }
401
402
  const playableRepresentations = adaptation.representations.filter(
402
- (r) => r.isSupported === true && r.decipherable !== false,
403
+ (r) => isRepresentationPlayable(r) === true,
403
404
  );
404
405
  return playableRepresentations.length > 0;
405
406
  },
@@ -15,7 +15,7 @@
15
15
  */
16
16
 
17
17
  import log from "../../log";
18
- import type { IRepresentationMetadata } from "../../manifest";
18
+ import { isRepresentationPlayable, type IRepresentationMetadata } from "../../manifest";
19
19
  import type {
20
20
  ICdnMetadata,
21
21
  IContentProtections,
@@ -429,6 +429,23 @@ class Representation implements IRepresentationMetadata {
429
429
  return true;
430
430
  }
431
431
 
432
+ /**
433
+ * Returns `true` if the `Representation` has a high chance of being playable on
434
+ * the current device (its codec seems supported and we don't consider it to be
435
+ * un-decipherable).
436
+ *
437
+ * Returns `false` if the `Representation` has a high chance of being unplayable
438
+ * on the current device (its codec seems unsupported and/or we consider it to
439
+ * be un-decipherable).
440
+ *
441
+ * Returns `undefined` if we don't know as the codec has not been checked yet.
442
+ *
443
+ * @returns {boolean|undefined}
444
+ */
445
+ public isPlayable(): boolean | undefined {
446
+ return isRepresentationPlayable(this);
447
+ }
448
+
432
449
  /**
433
450
  * Format the current `Representation`'s properties into a
434
451
  * `IRepresentationMetadata` format which can better be communicated through
@@ -237,9 +237,7 @@ export function toAudioTrack(
237
237
  audioDescription: adaptation.isAudioDescription === true,
238
238
  id: adaptation.id,
239
239
  representations: (filterPlayable
240
- ? adaptation.representations.filter(
241
- (r) => r.isSupported === true && r.decipherable !== false,
242
- )
240
+ ? adaptation.representations.filter((r) => isRepresentationPlayable(r))
243
241
  : adaptation.representations
244
242
  ).map(toAudioRepresentation),
245
243
  label: adaptation.label,
@@ -283,7 +281,7 @@ export function toVideoTrack(
283
281
  const representations = (
284
282
  filterPlayable
285
283
  ? trickModeAdaptation.representations.filter(
286
- (r) => r.isSupported === true && r.decipherable !== false,
284
+ (r) => isRepresentationPlayable(r) === true,
287
285
  )
288
286
  : trickModeAdaptation.representations
289
287
  ).map(toVideoRepresentation);
@@ -302,9 +300,7 @@ export function toVideoTrack(
302
300
  const videoTrack: IVideoTrack = {
303
301
  id: adaptation.id,
304
302
  representations: (filterPlayable
305
- ? adaptation.representations.filter(
306
- (r) => r.isSupported === true && r.decipherable !== false,
307
- )
303
+ ? adaptation.representations.filter((r) => isRepresentationPlayable(r) === true)
308
304
  : adaptation.representations
309
305
  ).map(toVideoRepresentation),
310
306
  label: adaptation.label,
@@ -389,6 +385,29 @@ export function toTaggedTrack(adaptation: IAdaptation): ITaggedTrack {
389
385
  }
390
386
  }
391
387
 
388
+ /**
389
+ * Returns `true` if the `Representation` has a high chance of being playable on
390
+ * the current device (its codec seems supported and we don't consider it to be
391
+ * un-decipherable).
392
+ *
393
+ * Returns `false` if the `Representation` has a high chance of being unplayable
394
+ * on the current device (its codec seems unsupported and/or we consider it to
395
+ * be un-decipherable).
396
+ *
397
+ * Returns `undefined` if we don't know as the codec has not been checked yet.
398
+ *
399
+ * @param {Object} representation
400
+ * @returns {boolean|undefined}
401
+ */
402
+ export function isRepresentationPlayable(
403
+ representation: IRepresentationMetadata,
404
+ ): boolean | undefined {
405
+ if (representation.decipherable === false) {
406
+ return false;
407
+ }
408
+ return representation.isSupported;
409
+ }
410
+
392
411
  /**
393
412
  * Information on a Representation affected by a `decipherabilityUpdates` event.
394
413
  */
@@ -558,7 +577,8 @@ export function replicateUpdatesOnManifestMetadata(
558
577
  ) {
559
578
  for (const prop of Object.keys(newManifest)) {
560
579
  if (prop !== "periods") {
561
- // eslint-disable-next-line
580
+ // trust me bro
581
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
562
582
  (baseManifest as any)[prop] = (newManifest as any)[prop];
563
583
  }
564
584
  }
@@ -579,7 +599,8 @@ export function replicateUpdatesOnManifestMetadata(
579
599
  const basePeriod = baseManifest.periods[periodIdx];
580
600
  for (const prop of Object.keys(newPeriod)) {
581
601
  if (prop !== "adaptations") {
582
- // eslint-disable-next-line
602
+ // trust me bro
603
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
583
604
  (basePeriod as any)[prop] = (newPeriod as any)[prop];
584
605
  }
585
606
  }
@@ -94,7 +94,7 @@ function getHDRInformation({
94
94
  return { eotf: "hlg" };
95
95
  }
96
96
  }
97
- if (codecs !== undefined && /^vp(08|09|10)/.exec(codecs)) {
97
+ if (codecs !== undefined && /^vp(08|09|10)/.test(codecs)) {
98
98
  return getWEBMHDRInformation(codecs);
99
99
  }
100
100
  }
@@ -205,7 +205,7 @@ export default function parseRepresentations(
205
205
  (r) =>
206
206
  r.schemeIdUri === "tag:dolby.com,2018:dash:EC3_ExtensionType:2018" &&
207
207
  r.value === "JOC",
208
- )
208
+ ) !== undefined
209
209
  ) {
210
210
  parsedRepresentation.isSpatialAudio = true;
211
211
  }
@@ -837,7 +837,7 @@ function getFreezingStatus(
837
837
  bufferGap: number | undefined,
838
838
  ): IFreezingStatus | null {
839
839
  const { MINIMUM_BUFFER_AMOUNT_BEFORE_FREEZING } = config.getCurrent();
840
- if (prevObservation.freezing) {
840
+ if (prevObservation.freezing !== null) {
841
841
  if (
842
842
  currentInfo.ended ||
843
843
  currentInfo.paused ||
@@ -558,6 +558,51 @@ export interface IKeySystemOption {
558
558
  * `MediaKeySystemConfiguration` according to the EME API.
559
559
  */
560
560
  distinctiveIdentifier?: MediaKeysRequirement | undefined;
561
+
562
+ /**
563
+ * Force a `sessionTypes` value for the corresponding
564
+ * `MediaKeySystemConfiguration` asked when creating a
565
+ * `MediaKeySystemAccess` (the EME API concept).
566
+ *
567
+ * If not set, the RxPlayer will automatically ask for the most adapted
568
+ * `sessionTypes` based on your configuration for the current content. As
569
+ * such, this option is only needed for very specific usages.
570
+ *
571
+ * A case where you might want to set this value is if for example you want
572
+ * the ability to be able to load both temporary and persistent licenses,
573
+ * regardless of the configuration applied to the current content.
574
+ * Setting in that case `wantedSessionTypes` to
575
+ * `["temporary", "persistent-license"]` will lead, if compatible, to the
576
+ * creation of a `MediaKeySystemAccess` able to handle both:
577
+ * - contents relying on temporary licenses, and:
578
+ * - contents relying on persistent licenses
579
+ *
580
+ * The RxPlayer will then be able to keep that same `MediaKeySystemAccess` on
581
+ * future `loadVideo` calls as long as they rely on either all or a subset of
582
+ * those session types - and as long as the rest of the new wanted
583
+ * configuration is also considered compatible with that `MediaKeySystemAccess`.
584
+ *
585
+ * Moreover, because our `MediaKeySession` cache (see `maxSessionCacheSize`)
586
+ * is linked to a `MediaKeySystemAccess`, keeping the same one allows the
587
+ * RxPlayer to also keep the same cache (whereas changing
588
+ * `MediaKeySystemAccess` when changing contents resets that cache).
589
+ *
590
+ * Note that the current device has to be compatible to _ALL_ `sessionTypes`
591
+ * for that configuration to go through.
592
+ *
593
+ * Notes
594
+ * -----
595
+ *
596
+ * If this value is set to an array which does not contain
597
+ * `"persistent-license"`, we will assume that no persistent license will be
598
+ * requested for the current content, regardless of the
599
+ * `persistentLicenseConfig` option.
600
+ *
601
+ * If this value only contains `"persistent-license"` but the
602
+ * `persistentLicenseConfig` option is not set, we will load persistent
603
+ * licenses yet not persist them.
604
+ */
605
+ wantedSessionTypes?: string[] | undefined;
561
606
  /**
562
607
  * If true, all open `MediaKeySession` (JavaScript Objects linked to the keys
563
608
  * used to decrypt the content) will be closed when the current playback
@@ -1,23 +1,12 @@
1
1
  import { describe, beforeEach, afterEach, it, expect, vi } from "vitest";
2
2
  import flatMap from "../flat_map";
3
3
 
4
- interface IProtoWithFlatMap {
5
- flatMap?:
6
- | (<U, This = undefined>(
7
- callback: (
8
- this: This,
9
- value: unknown,
10
- index: number,
11
- array: unknown[],
12
- ) => U | U[],
13
- thisArg?: This | undefined,
14
- ) => U[])
15
- | undefined;
16
- }
17
-
18
- const proto = Array.prototype as unknown as IProtoWithFlatMap;
19
-
20
- // eslint-disable-next-line @typescript-eslint/unbound-method
4
+ type ICustomArrayProto = Omit<typeof Array.prototype, "flatMap"> & {
5
+ flatMap?: typeof Array.prototype.flatMap | undefined;
6
+ };
7
+
8
+ const proto: ICustomArrayProto = Array.prototype;
9
+
21
10
  const initialFlatMap = proto.flatMap;
22
11
 
23
12
  describe("utils - starts-with", () => {
@@ -39,9 +28,7 @@ describe("utils - starts-with", () => {
39
28
  if (typeof initialFlatMap === "function") {
40
29
  it("should call the original flatMap function if available", () => {
41
30
  proto.flatMap = initialFlatMap;
42
- // TODO find what bother typescript here instead of adding "as any"
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
- const mockFlatMap = vi.spyOn(proto as any, "flatMap");
31
+ const mockFlatMap = vi.spyOn(Array.prototype, "flatMap");
45
32
  const func1 = (x: number): number[] => [x, x + 1, x - 1];
46
33
  const func2 = (x: number): string => String(x) + "a";
47
34
  expect(flatMap([1, 2, 3], func1)).toEqual([1, 2, 0, 2, 3, 1, 3, 4, 2]);
@@ -25,8 +25,8 @@ type ArrayWithFlatMap<T> = T[] & {
25
25
  /**
26
26
  * Map each element using a mapping function, then flat the result into
27
27
  * a new array.
28
- * @param {Array.<*>} originalArray
29
- * @param {Function} fn
28
+ * @param {Array.<*>} originalArray
29
+ * @param {Function} fn
30
30
  */
31
31
  export default function flatMap<T, U>(originalArray: T[], fn: (arg: T) => U[] | U): U[] {
32
32
  // eslint-disable-next-line @typescript-eslint/unbound-method
@@ -14,6 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
+ import isNonEmptyString from "./is_non_empty_string";
17
18
  import startsWith from "./starts_with";
18
19
 
19
20
  // Scheme part of an url (e.g. "http://").
@@ -135,12 +136,12 @@ function getRelativeUrl(baseUrl: string, newUrl: string): string | null {
135
136
  let result = relativePath;
136
137
  if (relativePath === "" && newParts.query === baseParts.query) {
137
138
  // path and query is the same, we don't need to rewrite it
138
- } else if (newParts.query) {
139
+ } else if (isNonEmptyString(newParts.query)) {
139
140
  result += "?";
140
141
  result += newParts.query;
141
142
  }
142
143
 
143
- if (newParts.fragment) {
144
+ if (isNonEmptyString(newParts.fragment)) {
144
145
  result += "#";
145
146
  result += newParts.fragment;
146
147
  }
@@ -160,7 +161,7 @@ function _resolveURL(base: string, relative: string) {
160
161
  const baseParts = parseURL(base);
161
162
  const relativeParts = parseURL(relative);
162
163
 
163
- if (relativeParts.scheme) {
164
+ if (isNonEmptyString(relativeParts.scheme)) {
164
165
  return formatURL(relativeParts);
165
166
  }
166
167
 
@@ -172,7 +173,7 @@ function _resolveURL(base: string, relative: string) {
172
173
  fragment: relativeParts.fragment,
173
174
  };
174
175
 
175
- if (relativeParts.authority) {
176
+ if (isNonEmptyString(relativeParts.authority)) {
176
177
  target.authority = relativeParts.authority;
177
178
  target.path = removeDotSegment(relativeParts.path);
178
179
  return formatURL(target);
@@ -180,7 +181,7 @@ function _resolveURL(base: string, relative: string) {
180
181
 
181
182
  if (relativeParts.path === "") {
182
183
  target.path = baseParts.path;
183
- if (!relativeParts.query) {
184
+ if (!isNonEmptyString(relativeParts.query)) {
184
185
  target.query = baseParts.query;
185
186
  }
186
187
  } else {
@@ -255,20 +256,20 @@ function parseURL(url: string): IParsedURL {
255
256
  */
256
257
  function formatURL(parts: IParsedURL): string {
257
258
  let url = "";
258
- if (parts.scheme) {
259
+ if (isNonEmptyString(parts.scheme)) {
259
260
  url += parts.scheme + ":";
260
261
  }
261
262
 
262
- if (parts.authority) {
263
+ if (isNonEmptyString(parts.authority)) {
263
264
  url += "//" + parts.authority;
264
265
  }
265
266
  url += parts.path;
266
267
 
267
- if (parts.query) {
268
+ if (isNonEmptyString(parts.query)) {
268
269
  url += "?" + parts.query;
269
270
  }
270
271
 
271
- if (parts.fragment) {
272
+ if (isNonEmptyString(parts.fragment)) {
272
273
  url += "#" + parts.fragment;
273
274
  }
274
275
  return url;
@@ -321,7 +322,7 @@ function removeDotSegment(path: string): string {
321
322
  * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.3
322
323
  */
323
324
  function mergePaths(baseParts: IParsedURL, relativePath: string): string {
324
- if (baseParts.authority && baseParts.path === "") {
325
+ if (isNonEmptyString(baseParts.authority) && baseParts.path === "") {
325
326
  return "/" + relativePath;
326
327
  }
327
328
  const basePath = baseParts.path;
@@ -6,6 +6,8 @@
6
6
  * https://github.com/TobiasNickel/tXml
7
7
  */
8
8
 
9
+ import isNonEmptyString from "./is_non_empty_string";
10
+
9
11
  // import arrayIncludes from "./array_includes";
10
12
 
11
13
  /**
@@ -94,7 +96,7 @@ function parseXml(src: string, options: ITParseOptions = {}): Array<ITNode | str
94
96
  out = parseChildren("");
95
97
  }
96
98
 
97
- if (options.filter) {
99
+ if (options.filter !== undefined) {
98
100
  out = filter(out, options.filter);
99
101
  }
100
102
  return out;
@@ -106,7 +108,7 @@ function parseXml(src: string, options: ITParseOptions = {}): Array<ITNode | str
106
108
  */
107
109
  function parseChildren(tagName: string): Array<ITNode | string> {
108
110
  const children: Array<ITNode | string> = [];
109
- while (src[pos]) {
111
+ while (src[pos] !== undefined) {
110
112
  if (src.charCodeAt(pos) === openBracketCC) {
111
113
  if (src.charCodeAt(pos + 1) === slashCC) {
112
114
  const closeStart = pos + 2;
@@ -170,7 +172,10 @@ function parseXml(src: string, options: ITParseOptions = {}): Array<ITNode | str
170
172
  const startDoctype = pos + 1;
171
173
  pos += 2;
172
174
  let encapsuled = false;
173
- while ((src.charCodeAt(pos) !== closeBracketCC || encapsuled) && src[pos]) {
175
+ while (
176
+ (src.charCodeAt(pos) !== closeBracketCC || encapsuled) &&
177
+ src[pos] !== undefined
178
+ ) {
174
179
  if (src.charCodeAt(pos) === openCornerBracketCC) {
175
180
  encapsuled = true;
176
181
  } else if (encapsuled && src.charCodeAt(pos) === closeCornerBracketCC) {
@@ -221,7 +226,7 @@ function parseXml(src: string, options: ITParseOptions = {}): Array<ITNode | str
221
226
 
222
227
  function parseName(): string {
223
228
  const start = pos;
224
- while (nameSpacer.indexOf(src[pos]) === -1 && src[pos]) {
229
+ while (nameSpacer.indexOf(src[pos]) === -1 && src[pos] !== undefined) {
225
230
  pos++;
226
231
  }
227
232
  return src.slice(start, pos);
@@ -235,7 +240,7 @@ function parseXml(src: string, options: ITParseOptions = {}): Array<ITNode | str
235
240
  let children: Array<ITNode | string> = [];
236
241
 
237
242
  // parsing attributes
238
- while (src.charCodeAt(pos) !== closeBracketCC && src[pos]) {
243
+ while (src.charCodeAt(pos) !== closeBracketCC && src[pos] !== undefined) {
239
244
  const c = src.charCodeAt(pos);
240
245
  if ((c > 64 && c < 91) || (c > 96 && c < 123)) {
241
246
  // if('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.indexOf(src[pos])!==-1 ){
@@ -243,7 +248,7 @@ function parseXml(src: string, options: ITParseOptions = {}): Array<ITNode | str
243
248
  // search beginning of the string
244
249
  let code = src.charCodeAt(pos);
245
250
  while (
246
- code &&
251
+ !isNaN(code) &&
247
252
  code !== singleQuoteCC &&
248
253
  code !== doubleQuoteCC &&
249
254
  !((code > 64 && code < 91) || (code > 96 && code < 123)) &&
@@ -298,7 +303,7 @@ function parseXml(src: string, options: ITParseOptions = {}): Array<ITNode | str
298
303
  const r = new RegExp(
299
304
  "\\s" + options.attrName + "\\s*=['\"]" + options.attrValue + "['\"]",
300
305
  ).exec(src);
301
- if (r) {
306
+ if (r !== null) {
302
307
  return r.index;
303
308
  } else {
304
309
  return -1;
@@ -328,7 +333,7 @@ function filter(
328
333
  child.children,
329
334
  f,
330
335
  dept + 1,
331
- (path ? path + "." : "") + i + "." + child.tagName,
336
+ (isNonEmptyString(path) ? path + "." : "") + i + "." + child.tagName,
332
337
  );
333
338
  out = out.concat(kids);
334
339
  }
package/vitest.config.mjs CHANGED
@@ -1,22 +1,4 @@
1
1
  import { defineConfig } from "vitest/config";
2
- import { promises as fs } from "fs";
3
-
4
- // https://github.com/tachibana-shin/vite-plugin-arraybuffer/blob/main/src/main.ts
5
- function vitePluginArraybuffer() {
6
- return {
7
- name: "array-buffer-loader",
8
- async load(id) {
9
- if (id.endsWith("?arraybuffer")) {
10
- const filePath = id.replace(/\?arraybuffer$/, "");
11
- const fileBuffer = await fs.readFile(filePath);
12
- return {
13
- code: `export default new Uint8Array([${new Uint8Array(fileBuffer).join(",")}]).buffer`,
14
- map: { mappings: "" },
15
- };
16
- }
17
- },
18
- };
19
- }
20
2
 
21
3
  function getBrowserConfig(browser) {
22
4
  switch (browser) {
@@ -69,7 +51,6 @@ function getBrowserConfig(browser) {
69
51
  }
70
52
 
71
53
  export default defineConfig({
72
- plugins: [vitePluginArraybuffer()],
73
54
  define: {
74
55
  // global variables
75
56
  __TEST_CONTENT_SERVER__: {
@@ -90,9 +71,14 @@ export default defineConfig({
90
71
  watch: false,
91
72
  globals: false,
92
73
  reporters: "dot",
93
- include: ["tests/**/*.[jt]s?(x)"],
94
- exclude: ["tests/performance/**/*.[jt]s?(x)"],
95
- globalSetup: "tests/contents/server.mjs",
96
- browser: getBrowserConfig(process.env.BROWSER_CONFIG),
74
+ include: [
75
+ // integration tests
76
+ "tests/integration/scenarios/**/*.[jt]s?(x)",
77
+ "tests/integration/**/*.test.[jt]s?(x)",
78
+ // memory tests
79
+ "tests/memory/**/*.[jt]s?(x)",
80
+ ],
81
+ globalSetup: "tests/globalSetup.mjs",
82
+ browser: getBrowserConfig(process.env.BROWSER_CONFIG ?? "chrome"),
97
83
  },
98
84
  });
@@ -1,60 +0,0 @@
1
- /**
2
- * Copyright 2015 CANAL+ Group
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
- import type { IMediaElement } from "../../compat/browser_compatibility_types";
17
- import type { ICustomMediaKeys, ICustomMediaKeySystemAccess, IEmeApiImplementation } from "../../compat/eme";
18
- import type { IKeySystemOption } from "../../public_types";
19
- import type { CancellationSignal } from "../../utils/task_canceller";
20
- import type LoadedSessionsStore from "./utils/loaded_sessions_store";
21
- /**
22
- * Dispose of the MediaKeys instance attached to the given media element, if
23
- * one.
24
- * @param {Object} mediaElement
25
- * @returns {Promise}
26
- */
27
- export declare function disableMediaKeys(mediaElement: IMediaElement): Promise<unknown>;
28
- /**
29
- * Attach MediaKeys and its associated state to an HTMLMediaElement.
30
- *
31
- * /!\ Mutates heavily MediaKeysInfosStore
32
- * @param {HTMLMediaElement} mediaElement
33
- * @param {Object} mediaKeysInfos
34
- * @param {Object} cancelSignal
35
- * @returns {Promise}
36
- */
37
- export default function attachMediaKeys(mediaElement: IMediaElement, { emeImplementation, keySystemOptions, askedConfiguration, loadedSessionsStore, mediaKeySystemAccess, mediaKeys, }: IMediaKeysState, cancelSignal: CancellationSignal): Promise<void>;
38
- /** MediaKeys and associated state attached to a media element. */
39
- export interface IMediaKeysState {
40
- /** Options set when the MediaKeys has been attached. */
41
- keySystemOptions: IKeySystemOption;
42
- /** LoadedSessionsStore associated to the MediaKeys instance. */
43
- loadedSessionsStore: LoadedSessionsStore;
44
- /** The MediaKeySystemAccess allowing to create MediaKeys instances. */
45
- mediaKeySystemAccess: MediaKeySystemAccess | ICustomMediaKeySystemAccess;
46
- /** The MediaKeys instance to attach to the media element. */
47
- mediaKeys: MediaKeys | ICustomMediaKeys;
48
- /**
49
- * The MediaKeySystemConfiguration that has been provided to the
50
- * `requestMediaKeySystemAccess` API.
51
- */
52
- askedConfiguration: MediaKeySystemConfiguration;
53
- /**
54
- * The chosen EME implementation abstraction linked to `mediaKeys`.
55
- * Different EME implementation might for example be used while debugging or
56
- * work-arounding EME-linked device issues.
57
- */
58
- emeImplementation: IEmeApiImplementation;
59
- }
60
- //# sourceMappingURL=attach_media_keys.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"attach_media_keys.d.ts","sourceRoot":"","sources":["../../../../src/main_thread/decrypt/attach_media_keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAC9E,OAAO,KAAK,EACV,gBAAgB,EAChB,2BAA2B,EAC3B,qBAAqB,EACtB,MAAM,kBAAkB,CAAC;AAK1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,mBAAmB,MAAM,+BAA+B,CAAC;AAGrE;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAI9E;AAED;;;;;;;;GAQG;AACH,wBAA8B,eAAe,CAC3C,YAAY,EAAE,aAAa,EAC3B,EACE,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,SAAS,GACV,EAAE,eAAe,EAClB,YAAY,EAAE,kBAAkB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,gEAAgE;IAChE,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,uEAAuE;IACvE,oBAAoB,EAAE,oBAAoB,GAAG,2BAA2B,CAAC;IACzE,6DAA6D;IAC7D,SAAS,EAAE,SAAS,GAAG,gBAAgB,CAAC;IACxC;;;OAGG;IACH,kBAAkB,EAAE,2BAA2B,CAAC;IAChD;;;;OAIG;IACH,iBAAiB,EAAE,qBAAqB,CAAC;CAC1C"}