@npo/player 1.27.7 → 1.28.0

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 (214) hide show
  1. package/README.md +4 -7
  2. package/lib/js/markers/updateLiveMarkers.d.ts +7 -2
  3. package/lib/js/markers/updateLiveMarkers.js +11 -4
  4. package/lib/js/markers/updateLiveMarkers.test.js +13 -3
  5. package/lib/js/playeractions/handlers/handleoffsets.test.js +1 -1
  6. package/lib/js/playeractions/handlers/mediasessionactions.d.ts +7 -2
  7. package/lib/js/playeractions/handlers/mediasessionactions.js +7 -7
  8. package/lib/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
  9. package/lib/js/playeractions/handlers/processplayerconfig.js +1 -1
  10. package/lib/js/playeractions/handlers/processplayerconfig.test.js +1 -1
  11. package/lib/js/playeractions/handlers/processsourceconfig.d.ts +11 -2
  12. package/lib/js/playeractions/handlers/processsourceconfig.js +35 -18
  13. package/lib/js/playeractions/handlers/removereplayclass.d.ts +1 -1
  14. package/lib/js/playeractions/handlers/removereplayclass.js +1 -1
  15. package/lib/js/playeractions/handlers/removereplayclass.test.js +1 -1
  16. package/lib/js/settings/localization.d.ts +1 -0
  17. package/lib/js/utilities/utilities.jwt.d.ts +2 -0
  18. package/lib/js/utilities/utilities.jwt.js +22 -0
  19. package/lib/js/utilities/utilities.stream.js +11 -2
  20. package/lib/js/utilities/utilities.url.js +2 -2
  21. package/lib/js/utilities/utilities.version.js +1 -1
  22. package/lib/js/utilities/utilities.version.test.js +1 -1
  23. package/lib/lang/nl.json +2 -1
  24. package/lib/npoplayer.d.ts +6 -5
  25. package/lib/npoplayer.js +81 -28
  26. package/lib/package.json +7 -9
  27. package/lib/services/a11y/setup.test.js +2 -4
  28. package/lib/services/advertHandlers/handlePreRolls.js +3 -4
  29. package/lib/services/advertHandlers/handlePrerolls.test.js +2 -3
  30. package/lib/services/chapterHandlers/chapterHandler.d.ts +35 -0
  31. package/lib/services/chapterHandlers/chapterHandler.js +230 -0
  32. package/lib/services/errors/errorBackground.test.js +1 -1
  33. package/lib/services/errors/errorHandler.d.ts +4 -2
  34. package/lib/services/errors/errorHandler.js +27 -14
  35. package/lib/services/errors/errorHandler.test.js +148 -0
  36. package/lib/services/errors/errorRetryHandler.d.ts +2 -0
  37. package/lib/services/errors/errorRetryHandler.js +14 -0
  38. package/lib/services/errors/errorRetryHandler.test.d.ts +1 -0
  39. package/lib/services/errors/errorRetryHandler.test.js +62 -0
  40. package/lib/services/errors/errorText.js +8 -5
  41. package/lib/services/errors/errorText.test.js +3 -3
  42. package/lib/services/infoPanel/infoPanel.d.ts +3 -0
  43. package/lib/services/infoPanel/infoPanel.js +35 -0
  44. package/lib/services/infoPanel/infoPanel.test.d.ts +1 -0
  45. package/lib/services/infoPanel/infoPanel.test.js +70 -0
  46. package/lib/services/keyboardHandlers/resolvekeypress.js +11 -1
  47. package/lib/services/keyboardHandlers/resolvekeypress.test.js +6 -2
  48. package/lib/services/nicamHandlers/nicamhandler.d.ts +1 -0
  49. package/lib/services/nicamHandlers/nicamhandler.js +2 -1
  50. package/lib/services/nicamHandlers/nicamhandler.test.js +2 -2
  51. package/lib/services/npoPlayerAPI/npoPlayerAPI.d.ts +8 -2
  52. package/lib/services/npoPlayerAPI/npoPlayerAPI.js +25 -12
  53. package/lib/services/npoPlayerAPI/playerModules.d.ts +1 -0
  54. package/lib/services/npoPlayerAPI/playerModules.js +46 -0
  55. package/lib/services/preferences/handlePreferences.js +9 -4
  56. package/lib/services/preferences/handlePreferences.test.js +53 -17
  57. package/lib/services/segmentHandlers/addSegmentEventListeners.test.js +1 -1
  58. package/lib/services/segmentHandlers/isSegmentInBounds.d.ts +2 -0
  59. package/lib/services/segmentHandlers/isSegmentInBounds.js +5 -0
  60. package/lib/services/segmentHandlers/isSegmentInBounds.test.d.ts +1 -0
  61. package/lib/services/segmentHandlers/isSegmentInBounds.test.js +27 -0
  62. package/lib/services/services.d.ts +5 -2
  63. package/lib/services/services.js +15 -2
  64. package/lib/services/streamFetchHandler/fetchStream.js +5 -4
  65. package/lib/services/streamFetchHandler/fetchstream.test.js +25 -3
  66. package/lib/services/streamoptionsHandlers/streamOptionsHandler.js +11 -9
  67. package/lib/services/streamoptionsHandlers/streamOptionsHandler.test.js +14 -2
  68. package/lib/services/trackingHandlers/eventBinding.js +48 -33
  69. package/lib/services/trackingHandlers/eventBinding.test.js +57 -1
  70. package/lib/services/trackingHandlers/playerTrackerStart.js +1 -1
  71. package/lib/services/uiHandlers/uiVisiblityHandler.js +6 -0
  72. package/lib/services/verticalVideoHandlers/handleVerticalVideoSettings.test.js +0 -9
  73. package/lib/src/js/markers/updateLiveMarkers.d.ts +7 -2
  74. package/lib/src/js/playeractions/handlers/mediasessionactions.d.ts +7 -2
  75. package/lib/src/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
  76. package/lib/src/js/playeractions/handlers/processsourceconfig.d.ts +11 -2
  77. package/lib/src/js/playeractions/handlers/removereplayclass.d.ts +1 -1
  78. package/lib/src/js/settings/localization.d.ts +1 -0
  79. package/lib/src/js/utilities/utilities.jwt.d.ts +2 -0
  80. package/lib/src/npoplayer.d.ts +6 -5
  81. package/lib/src/services/chapterHandlers/chapterHandler.d.ts +35 -0
  82. package/lib/src/services/errors/errorHandler.d.ts +4 -2
  83. package/lib/src/services/errors/errorRetryHandler.d.ts +2 -0
  84. package/lib/src/services/errors/errorRetryHandler.test.d.ts +1 -0
  85. package/lib/src/services/infoPanel/infoPanel.d.ts +3 -0
  86. package/lib/src/services/infoPanel/infoPanel.test.d.ts +1 -0
  87. package/lib/src/services/nicamHandlers/nicamhandler.d.ts +1 -0
  88. package/lib/src/services/npoPlayerAPI/npoPlayerAPI.d.ts +8 -2
  89. package/lib/src/services/npoPlayerAPI/playerModules.d.ts +1 -0
  90. package/lib/src/services/segmentHandlers/isSegmentInBounds.d.ts +2 -0
  91. package/lib/src/services/segmentHandlers/isSegmentInBounds.test.d.ts +1 -0
  92. package/lib/src/services/services.d.ts +5 -2
  93. package/lib/src/types/events.d.ts +1 -1
  94. package/lib/src/types/interfaces.d.ts +39 -43
  95. package/lib/src/ui/components/adbutton.d.ts +3 -6
  96. package/lib/src/ui/components/adlabel.d.ts +3 -6
  97. package/lib/src/ui/components/audio/controlbar.d.ts +2 -2
  98. package/lib/src/ui/components/buttons.d.ts +18 -11
  99. package/lib/src/ui/components/ctabar.d.ts +4 -10
  100. package/lib/src/ui/components/infopanel/infopanel.d.ts +3 -0
  101. package/lib/src/ui/components/infopanel/togglebutton.d.ts +3 -0
  102. package/lib/src/ui/components/playnext.d.ts +3 -9
  103. package/lib/src/ui/components/seekbar.d.ts +2 -3
  104. package/lib/src/ui/components/settingspanel.d.ts +2 -3
  105. package/lib/src/ui/components/titlebar.d.ts +2 -2
  106. package/lib/src/ui/handlers/domhandlers.d.ts +2 -2
  107. package/lib/src/ui/handlers/listboxhandlers.d.ts +18 -4
  108. package/lib/src/ui/handlers/playnextscreen.d.ts +6 -2
  109. package/lib/src/ui/uicontainer.d.ts +1 -2
  110. package/lib/tests/jest.setup-files-after-env.d.ts +0 -0
  111. package/lib/tests/jest.setup-files-after-env.js +6 -0
  112. package/lib/tests/jest.setup-tests.d.ts +1 -0
  113. package/lib/tests/jest.setup-tests.js +2 -0
  114. package/lib/tests/mocks/mockNpoplayer.js +27 -44
  115. package/lib/tests/mocks/mockPlayerAPI.d.ts +1 -1
  116. package/lib/tests/mocks/mockPlayerAPI.js +15 -1
  117. package/lib/tests/mocks/mockPlayerUi.d.ts +64 -0
  118. package/lib/tests/mocks/mockPlayerUi.js +251 -0
  119. package/lib/tests/mocks/playerContextMock.d.ts +3 -66
  120. package/lib/tests/mocks/playerContextMock.js +34 -7
  121. package/lib/types/events.d.ts +1 -1
  122. package/lib/types/events.js +1 -1
  123. package/lib/types/interfaces.d.ts +39 -43
  124. package/lib/types/interfaces.js +0 -27
  125. package/lib/ui/components/adbutton.d.ts +3 -6
  126. package/lib/ui/components/adbutton.js +2 -1
  127. package/lib/ui/components/adlabel.d.ts +3 -6
  128. package/lib/ui/components/adlabel.js +2 -1
  129. package/lib/ui/components/audio/controlbar.d.ts +2 -2
  130. package/lib/ui/components/audio/controlbar.js +6 -6
  131. package/lib/ui/components/buttons.d.ts +18 -11
  132. package/lib/ui/components/buttons.js +44 -26
  133. package/lib/ui/components/controlbar.js +13 -9
  134. package/lib/ui/components/ctabar.d.ts +4 -10
  135. package/lib/ui/components/ctabar.js +8 -7
  136. package/lib/ui/components/infopanel/infopanel.d.ts +3 -0
  137. package/lib/ui/components/infopanel/infopanel.js +40 -0
  138. package/lib/ui/components/infopanel/togglebutton.d.ts +3 -0
  139. package/lib/ui/components/infopanel/togglebutton.js +18 -0
  140. package/lib/ui/components/playnext.d.ts +3 -9
  141. package/lib/ui/components/playnext.js +3 -3
  142. package/lib/ui/components/seekbar.d.ts +2 -3
  143. package/lib/ui/components/seekbar.js +7 -3
  144. package/lib/ui/components/settingspanel.d.ts +2 -3
  145. package/lib/ui/components/settingspanel.js +79 -53
  146. package/lib/ui/components/titlebar.d.ts +2 -2
  147. package/lib/ui/components/titlebar.js +2 -1
  148. package/lib/ui/components/topbar.js +8 -5
  149. package/lib/ui/components/verticalvideo/controlbar.js +5 -2
  150. package/lib/ui/components/verticalvideo/settingspanel.js +9 -5
  151. package/lib/ui/handlers/accessibilityhandler.js +11 -22
  152. package/lib/ui/handlers/accessibilityhandler.test.js +25 -34
  153. package/lib/ui/handlers/domhandlers.d.ts +2 -2
  154. package/lib/ui/handlers/listboxhandlers.d.ts +18 -4
  155. package/lib/ui/handlers/listboxhandlers.js +5 -3
  156. package/lib/ui/handlers/playnextscreen.d.ts +6 -2
  157. package/lib/ui/handlers/playnextscreen.js +4 -4
  158. package/lib/ui/handlers/playnextscreen.test.js +15 -3
  159. package/lib/ui/uicontainer.d.ts +1 -2
  160. package/lib/ui/uicontainer.js +24 -8
  161. package/lib/ui/uicontainer.test.js +6 -5
  162. package/package.json +7 -9
  163. package/src/style/components/_advert.scss +0 -4
  164. package/src/style/components/_buffering.scss +18 -22
  165. package/src/style/components/_controlbars.scss +0 -4
  166. package/src/style/components/_icons.scss +18 -4
  167. package/src/style/components/_infopanel.scss +99 -0
  168. package/src/style/components/_nicam.scss +6 -2
  169. package/src/style/components/_seekbarthumbnail.scss +5 -0
  170. package/src/style/components/_settingspanel.scss +1 -1
  171. package/src/style/components/_subtitles.scss +0 -1
  172. package/src/style/components/_textbuttons.scss +30 -1
  173. package/src/style/components/_volumeslider.scss +0 -1
  174. package/src/style/components/audio/_bottombar.scss +6 -0
  175. package/src/style/components/audio/_metadata.scss +25 -9
  176. package/src/style/components/audio/_topbar.scss +6 -1
  177. package/src/style/npoplayer.css +166 -83
  178. package/src/style/npoplayer.scss +10 -2
  179. package/src/style/variants/_player-audio-only.scss +32 -0
  180. package/src/style/variants/_player-base.scss +5 -1
  181. package/src/style/variants/_player-large.scss +3 -3
  182. package/src/style/variants/_player-medium.scss +5 -1
  183. package/src/style/variants/_player-small.scss +6 -1
  184. package/src/style/vars/_colors.scss +1 -1
  185. package/src/style/vars/_icons.scss +5 -4
  186. package/src/style/vars/_z-index.scss +1 -1
  187. package/lib/npoplayer-bridge.test.js +0 -24
  188. package/lib/src/ui/components/nativemobile/buttons.d.ts +0 -30
  189. package/lib/src/ui/components/nativemobile/controlbar.d.ts +0 -3
  190. package/lib/src/ui/components/nativemobile/ctabar.d.ts +0 -11
  191. package/lib/src/ui/components/nativemobile/titlebar.d.ts +0 -2
  192. package/lib/src/ui/components/nativemobile/topbar.d.ts +0 -3
  193. package/lib/src/ui/nativemobileuicontainer.d.ts +0 -5
  194. package/lib/src/ui/nativemobileuifactory.d.ts +0 -3
  195. package/lib/src/ui/nativemobileuifactory.test.d.ts +0 -1
  196. package/lib/ui/components/nativemobile/buttons.d.ts +0 -30
  197. package/lib/ui/components/nativemobile/buttons.js +0 -233
  198. package/lib/ui/components/nativemobile/controlbar.d.ts +0 -3
  199. package/lib/ui/components/nativemobile/controlbar.js +0 -43
  200. package/lib/ui/components/nativemobile/ctabar.d.ts +0 -11
  201. package/lib/ui/components/nativemobile/ctabar.js +0 -10
  202. package/lib/ui/components/nativemobile/titlebar.d.ts +0 -2
  203. package/lib/ui/components/nativemobile/titlebar.js +0 -7
  204. package/lib/ui/components/nativemobile/topbar.d.ts +0 -3
  205. package/lib/ui/components/nativemobile/topbar.js +0 -23
  206. package/lib/ui/nativemobileuicontainer.d.ts +0 -5
  207. package/lib/ui/nativemobileuicontainer.js +0 -42
  208. package/lib/ui/nativemobileuifactory.d.ts +0 -3
  209. package/lib/ui/nativemobileuifactory.js +0 -112
  210. package/lib/ui/nativemobileuifactory.test.d.ts +0 -1
  211. package/lib/ui/nativemobileuifactory.test.js +0 -64
  212. package/src/style/variants/_player-native-mobile.scss +0 -13
  213. /package/lib/{npoplayer-bridge.test.d.ts → services/errors/errorHandler.test.d.ts} +0 -0
  214. /package/lib/src/{npoplayer-bridge.test.d.ts → services/errors/errorHandler.test.d.ts} +0 -0
package/README.md CHANGED
@@ -1,4 +1,5 @@
1
- [![NPO](https://objectstorage.nl-ams-1.scalia.io/npostart-npoplayer-test/assets/player/npo_player.png 'NPO Player Logo')](https://npo.nl)
1
+
2
+ ![npoplayer](https://github.com/user-attachments/assets/d03de645-572c-499e-9481-60f73fbf49aa)
2
3
 
3
4
  # NPO Player
4
5
 
@@ -11,7 +12,7 @@ Extensive and up-to-date documentation is available at https://docs.npoplayer.nl
11
12
  Code quality is analysed by SonarCloud. The project can be found at https://sonarcloud.io/project/overview?id=NPOstart_npo-player
12
13
 
13
14
  # Changelog
14
- Current version: v1.27.0
15
+ Current version: v1.28.0
15
16
 
16
17
  The changelog is available at https://docs.npoplayer.nl/implementation/web/changelog/
17
18
 
@@ -20,8 +21,4 @@ The changelog is available at https://docs.npoplayer.nl/implementation/web/chang
20
21
  MIT
21
22
 
22
23
  [JWT.IO - JSON Web Tokens Introduction]: https://jwt.io/introduction
23
- [self generated JWT]: https://www.npmjs.com/package/jsonwebtoken
24
-
25
- ## Native mobile development
26
-
27
- For detailed information on the JavaScript player integration for ios and Android, including custom message handling, UI customization, and interaction with native mobile SDKs, see the [Bitmovin Player Integration for Native Mobile SDKs](src/js/ui/README.md) located in the `src/js/ui` directory.
24
+ [self generated JWT]: https://www.npmjs.com/package/jsonwebtoken
@@ -1,4 +1,9 @@
1
- import { PlayerAPI } from 'bitmovin-player';
1
+ import { PlayerAPI } from 'bitmovin-player/modules/bitmovinplayer-core';
2
2
  import { UIManager } from 'bitmovin-player-ui';
3
3
  import { TimeLineMarker } from 'types/interfaces';
4
- export declare function updateLiveMarkers(timeLineMarkers: TimeLineMarker[], player: PlayerAPI, uiManager: UIManager, autoFillTimeLineMarkerDuration: boolean): void;
4
+ export declare function updateLiveMarkers({ timeLineMarkers, player, uiManager, autoFillTimeLineMarkerDuration }: {
5
+ timeLineMarkers: TimeLineMarker[];
6
+ player: PlayerAPI;
7
+ uiManager: UIManager;
8
+ autoFillTimeLineMarkerDuration: boolean;
9
+ }): void;
@@ -1,4 +1,4 @@
1
- export function updateLiveMarkers(timeLineMarkers, player, uiManager, autoFillTimeLineMarkerDuration) {
1
+ export function updateLiveMarkers({ timeLineMarkers, player, uiManager, autoFillTimeLineMarkerDuration }) {
2
2
  if (!player || !uiManager) {
3
3
  console.error('Player or UIManager is null');
4
4
  return;
@@ -6,14 +6,21 @@ export function updateLiveMarkers(timeLineMarkers, player, uiManager, autoFillTi
6
6
  removeAllMarkers(uiManager);
7
7
  const currentTimeEpoch = Math.floor(Date.now() / 1000);
8
8
  timeLineMarkers.sort((a, b) => a.time - b.time);
9
- const relativeTimeMarkers = timeLineMarkers.map((marker, index) => transformMarker(marker, index, timeLineMarkers, currentTimeEpoch, player, autoFillTimeLineMarkerDuration));
9
+ const relativeTimeMarkers = timeLineMarkers.map((marker, index) => transformMarker({
10
+ marker,
11
+ index,
12
+ timeLineMarkers,
13
+ currentTimeEpoch,
14
+ player,
15
+ autoFillTimeLineMarkerDuration
16
+ }));
10
17
  for (const marker of relativeTimeMarkers) {
11
18
  uiManager?.addTimelineMarker(marker);
12
19
  }
13
20
  }
14
- function transformMarker(marker, index, timeLineMarkers, currentTimeEpoch, player, autoFillTimeLineMarkerDuration) {
21
+ function transformMarker({ marker, index, timeLineMarkers, currentTimeEpoch, player, autoFillTimeLineMarkerDuration }) {
15
22
  const DVR_WINDOW_LENGTH = Math.abs(player.getMaxTimeShift());
16
- let duration = marker.duration === undefined ? 0 : marker.duration;
23
+ let duration = marker.duration ?? 0;
17
24
  let startTimeRelativeToCurrent = marker.time - currentTimeEpoch;
18
25
  if (autoFillTimeLineMarkerDuration) {
19
26
  duration =
@@ -9,7 +9,7 @@ jest.mock('bitmovin-player-ui', () => {
9
9
  }))
10
10
  };
11
11
  });
12
- jest.mock('bitmovin-player', () => ({
12
+ jest.mock('bitmovin-player/modules/bitmovinplayer-core', () => ({
13
13
  PlayerAPI: jest.fn()
14
14
  }));
15
15
  describe('updateLiveMarkers', () => {
@@ -27,7 +27,12 @@ describe('updateLiveMarkers', () => {
27
27
  { time: 3000, title: 'Marker 2' },
28
28
  { time: 1000, title: 'Marker 1' }
29
29
  ];
30
- updateLiveMarkers(timeLineMarkers, player, uiManager, true);
30
+ updateLiveMarkers({
31
+ timeLineMarkers,
32
+ player,
33
+ uiManager,
34
+ autoFillTimeLineMarkerDuration: true
35
+ });
31
36
  expect(uiManager.getTimelineMarkers).toHaveBeenCalled();
32
37
  expect(uiManager.removeTimelineMarker).toHaveBeenCalledTimes(0);
33
38
  expect(uiManager.addTimelineMarker).toHaveBeenCalledTimes(2);
@@ -46,7 +51,12 @@ describe('updateLiveMarkers', () => {
46
51
  ;
47
52
  uiManager.getTimelineMarkers.mockReturnValue([{ time: 2000, title: 'Existing Marker' }]);
48
53
  const timeLineMarkers = [{ time: 1000, title: 'New Marker' }];
49
- updateLiveMarkers(timeLineMarkers, player, uiManager, true);
54
+ updateLiveMarkers({
55
+ timeLineMarkers,
56
+ player,
57
+ uiManager,
58
+ autoFillTimeLineMarkerDuration: true
59
+ });
50
60
  expect(uiManager.removeTimelineMarker).toHaveBeenCalledTimes(1);
51
61
  expect(uiManager.addTimelineMarker).toHaveBeenCalledTimes(1);
52
62
  });
@@ -1,4 +1,4 @@
1
- import { PlayerEvent } from 'bitmovin-player';
1
+ import { PlayerEvent } from 'bitmovin-player/modules/bitmovinplayer-core';
2
2
  import { createPlayerContextMock, createMockNpoPlayerAPI } from '../../../../tests/mocks/playerContextMock';
3
3
  import { handleStartOffset, shiftToProgramStart } from './handleoffsets';
4
4
  describe('Test offset handling', () => {
@@ -1,2 +1,7 @@
1
- import { PlayerAPI, SourceConfig } from 'bitmovin-player';
2
- export declare function setupMediaSessionActionHandlers(player: PlayerAPI, sourceConfig: SourceConfig, _streamObject: any): void;
1
+ import { PlayerAPI, SourceConfig } from 'bitmovin-player/modules/bitmovinplayer-core';
2
+ import { StreamObject } from 'types/interfaces';
3
+ export declare function setupMediaSessionActionHandlers({ player, sourceConfig, streamObject }: {
4
+ player: PlayerAPI;
5
+ sourceConfig: SourceConfig;
6
+ streamObject: StreamObject;
7
+ }): void;
@@ -1,5 +1,5 @@
1
- import { PlayerEvent } from 'bitmovin-player';
2
- export function setupMediaSessionActionHandlers(player, sourceConfig, _streamObject) {
1
+ import { PlayerEvent } from 'bitmovin-player/modules/bitmovinplayer-core';
2
+ export function setupMediaSessionActionHandlers({ player, sourceConfig, streamObject }) {
3
3
  function handlePlaying() {
4
4
  player.off(PlayerEvent.Playing, handlePlaying);
5
5
  if (!('mediaSession' in navigator)) {
@@ -50,12 +50,12 @@ export function setupMediaSessionActionHandlers(player, sourceConfig, _streamObj
50
50
  function setMediaSessionMetadata() {
51
51
  const metadata = {
52
52
  title: sourceConfig.title,
53
- artist: _streamObject.metadata.broadcaster || ''
53
+ artist: streamObject.metadata.broadcaster || ''
54
54
  };
55
- if (sourceConfig.poster || _streamObject.metadata.poster) {
55
+ if (sourceConfig.poster || streamObject.metadata.poster) {
56
56
  metadata.artwork = [
57
57
  {
58
- src: sourceConfig.poster || _streamObject.metadata.poster
58
+ src: sourceConfig.poster ?? streamObject.metadata.poster ?? ''
59
59
  }
60
60
  ];
61
61
  }
@@ -67,7 +67,7 @@ export function setupMediaSessionActionHandlers(player, sourceConfig, _streamObj
67
67
  {
68
68
  action: 'seekbackward',
69
69
  handler: (details) => {
70
- const skipTime = details.seekOffset || defaultSkipTime;
70
+ const skipTime = details.seekOffset ?? defaultSkipTime;
71
71
  player.seek(Math.max(player.getCurrentTime() - skipTime, 0));
72
72
  updatePositionState();
73
73
  }
@@ -75,7 +75,7 @@ export function setupMediaSessionActionHandlers(player, sourceConfig, _streamObj
75
75
  {
76
76
  action: 'seekforward',
77
77
  handler: (details) => {
78
- const skipTime = details.seekOffset || defaultSkipTime;
78
+ const skipTime = details.seekOffset ?? defaultSkipTime;
79
79
  player.seek(Math.min(player.getCurrentTime() + skipTime, player.getDuration()));
80
80
  updatePositionState();
81
81
  }
@@ -1,3 +1,3 @@
1
- import { type PlayerConfig } from 'bitmovin-player';
1
+ import { type PlayerConfig } from 'bitmovin-player/modules/bitmovinplayer-core';
2
2
  import NpoPlayer from 'npoplayer';
3
3
  export declare function processPlayerConfig(npoPlayer: NpoPlayer, playerConfig: PlayerConfig): PlayerConfig;
@@ -1,4 +1,4 @@
1
- import { LogLevel } from 'bitmovin-player';
1
+ import { LogLevel } from 'bitmovin-player/modules/bitmovinplayer-core';
2
2
  import { isSafari } from '../../utilities/utilities.user-agent';
3
3
  export function processPlayerConfig(npoPlayer, playerConfig) {
4
4
  const processedConfig = playerConfig;
@@ -1,4 +1,4 @@
1
- import { LogLevel } from 'bitmovin-player';
1
+ import { LogLevel } from 'bitmovin-player/modules/bitmovinplayer-core';
2
2
  import { isSafari } from '../../utilities/utilities.user-agent';
3
3
  import { processPlayerConfig } from './processplayerconfig';
4
4
  jest.mock('../../utilities/utilities.user-agent', () => ({
@@ -1,6 +1,15 @@
1
1
  import { StreamObject, StreamOptions } from 'types/interfaces';
2
- import { SourceConfig } from 'bitmovin-player';
2
+ import { SourceConfig } from 'bitmovin-player/modules/bitmovinplayer-core';
3
3
  import { NpoPlayerServices } from '../../../services/services';
4
4
  import { NPOTag } from '@npotag/tag';
5
5
  export declare const getSubtitleLabels: (data: any) => string;
6
- export declare function processSourceConfig(npoPlayerServices: NpoPlayerServices, source: string, _sourceConfig: SourceConfig | undefined, _streamObject: StreamObject, drm: string | undefined, streamOptions: StreamOptions, version: string, npoTagInstance: NPOTag | undefined): Promise<SourceConfig>;
6
+ export declare function processSourceConfig({ npoPlayerServices, source, _sourceConfig, _streamObject, drm, streamOptions, version, npoTagInstance }: {
7
+ npoPlayerServices: NpoPlayerServices;
8
+ source: string;
9
+ _sourceConfig: SourceConfig;
10
+ _streamObject: StreamObject;
11
+ drm: string | undefined;
12
+ streamOptions: StreamOptions;
13
+ version: string;
14
+ npoTagInstance: NPOTag | undefined;
15
+ }): Promise<SourceConfig>;
@@ -1,21 +1,21 @@
1
- import { HttpResponseType } from 'bitmovin-player';
1
+ import { HttpResponseType } from 'bitmovin-player/modules/bitmovinplayer-core';
2
2
  import { npoCdnProviders } from '../../../services/cdnProviders/cdnProviders';
3
3
  import { replaceSpecialCharacters } from '../../utilities/utilities.text';
4
4
  import subtitleLabelMap from '../../../lang/subtitleLabels/nl.json';
5
- async function setDrm(sourceConfig, drm, _streamObject, useWidevineServerCertificate) {
5
+ async function setDrm({ sourceConfig, drm, streamObject, useWidevineServerCertificate }) {
6
6
  const npoDrmGateway = 'https://npo-drm-gateway.samgcloud.nepworldwide.nl/authentication?custom_data=';
7
7
  switch (drm) {
8
8
  case 'fairplay': {
9
9
  sourceConfig.drm = {
10
10
  fairplay: {
11
11
  certificateURL: 'https://fairplay.npo.nl/certificate/fairplay.cer',
12
- LA_URL: npoDrmGateway + _streamObject.stream.drmToken,
12
+ LA_URL: npoDrmGateway + streamObject.stream.drmToken,
13
13
  prepareMessage: (event) => {
14
14
  return new Uint8Array(event.message);
15
15
  },
16
16
  prepareContentId: (url) => {
17
17
  const link = document.createElement('a');
18
- const trimmedUrl = [...url].filter((char) => !(char.codePointAt(0) == undefined)).join('');
18
+ const trimmedUrl = [...url].filter((char) => char.codePointAt(0) !== undefined).join('');
19
19
  link.href = trimmedUrl.replace('T', '');
20
20
  return link.hostname;
21
21
  },
@@ -38,7 +38,7 @@ async function setDrm(sourceConfig, drm, _streamObject, useWidevineServerCertifi
38
38
  try {
39
39
  sourceConfig.drm = {
40
40
  widevine: {
41
- LA_URL: npoDrmGateway + _streamObject.stream.drmToken,
41
+ LA_URL: npoDrmGateway + streamObject.stream.drmToken,
42
42
  audioRobustness: 'SW_SECURE_CRYPTO',
43
43
  videoRobustness: 'SW_SECURE_CRYPTO',
44
44
  serverCertificate: useWidevineServerCertificate
@@ -55,12 +55,16 @@ async function setDrm(sourceConfig, drm, _streamObject, useWidevineServerCertifi
55
55
  case 'playready': {
56
56
  sourceConfig.drm = {
57
57
  playready: {
58
- LA_URL: npoDrmGateway + _streamObject.stream.drmToken
58
+ LA_URL: npoDrmGateway + streamObject.stream.drmToken
59
59
  }
60
60
  };
61
61
  break;
62
62
  }
63
63
  }
64
+ sourceConfig.drm = {
65
+ ...sourceConfig.drm,
66
+ immediateLicenseRequest: true
67
+ };
64
68
  return sourceConfig;
65
69
  }
66
70
  async function getServerCertificate(url) {
@@ -74,9 +78,9 @@ export const getSubtitleLabels = function (data) {
74
78
  const getQualityLabels = function (data) {
75
79
  return data.height + 'p';
76
80
  };
77
- function setStreamProfile(sourceConfig, _sourceConfig, _streamObject) {
78
- const streamProfile = _streamObject.stream.streamProfile;
79
- const streamURL = _streamObject.stream.streamURL;
81
+ function setStreamProfile({ sourceConfig, _sourceConfig, streamObject }) {
82
+ const streamProfile = streamObject.stream.streamProfile;
83
+ const streamURL = streamObject.stream.streamURL;
80
84
  const configMapping = {
81
85
  hls: _sourceConfig.hls,
82
86
  dash: _sourceConfig.dash,
@@ -101,7 +105,7 @@ function setStreamProfile(sourceConfig, _sourceConfig, _streamObject) {
101
105
  }
102
106
  return sourceConfig;
103
107
  }
104
- export async function processSourceConfig(npoPlayerServices, source, _sourceConfig = {}, _streamObject, drm = undefined, streamOptions, version, npoTagInstance) {
108
+ export async function processSourceConfig({ npoPlayerServices, source, _sourceConfig, _streamObject, drm, streamOptions, version, npoTagInstance }) {
105
109
  let sourceConfig = {};
106
110
  sourceConfig.title = _sourceConfig.title
107
111
  ? replacePlaceholders(_sourceConfig.title, _streamObject.metadata)
@@ -109,7 +113,11 @@ export async function processSourceConfig(npoPlayerServices, source, _sourceConf
109
113
  sourceConfig.description = _sourceConfig.description
110
114
  ? replacePlaceholders(_sourceConfig.description, _streamObject.metadata)
111
115
  : _streamObject.metadata.description ?? '';
112
- sourceConfig.poster = decidePoster(_streamObject, _sourceConfig, streamOptions);
116
+ sourceConfig.poster = decidePoster({
117
+ streamObject: _streamObject,
118
+ sourceConfig: _sourceConfig,
119
+ streamOptions
120
+ });
113
121
  sourceConfig.metadata = {
114
122
  title: sourceConfig.title,
115
123
  description: sourceConfig.description,
@@ -139,8 +147,13 @@ export async function processSourceConfig(npoPlayerServices, source, _sourceConf
139
147
  _sourceConfig.thumbnailTrack ?? _streamObject.assets.scrubbingThumbnail
140
148
  ? { url: _streamObject.assets.scrubbingThumbnail }
141
149
  : undefined;
142
- sourceConfig = setStreamProfile(sourceConfig, _sourceConfig, _streamObject);
143
- sourceConfig = await setDrm(sourceConfig, drm, _streamObject, streamOptions.useWidevineServerCertificate ?? true);
150
+ sourceConfig = setStreamProfile({ sourceConfig, _sourceConfig, streamObject: _streamObject });
151
+ sourceConfig = await setDrm({
152
+ sourceConfig,
153
+ drm,
154
+ streamObject: _streamObject,
155
+ useWidevineServerCertificate: streamOptions.useWidevineServerCertificate ?? true
156
+ });
144
157
  const streamSource = _streamObject.stream.streamURL;
145
158
  let cdnString = streamSource;
146
159
  if (streamSource.startsWith('file:///')) {
@@ -184,15 +197,15 @@ export async function processSourceConfig(npoPlayerServices, source, _sourceConf
184
197
  sourceConfig.metadata.jwt = source;
185
198
  sourceConfig.metadata.streamLinkAsJsonString = JSON.stringify(_streamObject);
186
199
  sourceConfig.metadata.npoTagSession = String(npoTagInstance?.getSerializedSessionInfo());
187
- sourceConfig.metadata.hasPreroll = _streamObject.metadata.hasPreroll || 'false';
188
- sourceConfig.metadata.prerollUrl = _streamObject.assets.preroll || '';
200
+ sourceConfig.metadata.hasPreroll = _streamObject.metadata.hasPreroll ?? 'false';
201
+ sourceConfig.metadata.prerollUrl = _streamObject.assets.preroll ?? '';
189
202
  sourceConfig.metadata.onScreenDebug = 'false';
190
203
  sourceConfig.metadata.frameworkLevelDebug = 'false';
191
- sourceConfig.metadata.description = sourceConfig.description || '';
204
+ sourceConfig.metadata.description = sourceConfig.description ?? '';
192
205
  sourceConfig.metadata.avType = npoPlayerServices.getAVType(_streamObject.stream.avType);
193
206
  return sourceConfig;
194
207
  }
195
- function decidePoster(streamObject, sourceConfig, streamOptions) {
208
+ function decidePoster({ streamObject, sourceConfig, streamOptions }) {
196
209
  if (sourceConfig.poster) {
197
210
  return replaceSpecialCharacters(sourceConfig.poster);
198
211
  }
@@ -208,7 +221,11 @@ function replacePlaceholders(template, metadata) {
208
221
  return template.replace(/{([^{}]*)}/g, (match, key) => {
209
222
  const value = metadata[key];
210
223
  if (Array.isArray(value)) {
211
- return value.map((item) => item.trim()).join(', ');
224
+ return value
225
+ .map((item) => {
226
+ return typeof item === 'string' ? item.trim() : String(item);
227
+ })
228
+ .join(', ');
212
229
  }
213
230
  return value === undefined ? '' : String(value);
214
231
  });
@@ -1,2 +1,2 @@
1
- import { PlayerAPI } from 'bitmovin-player';
1
+ import { PlayerAPI } from 'bitmovin-player/modules/bitmovinplayer-core';
2
2
  export declare function removeReplayClass(player: PlayerAPI | undefined): void;
@@ -1,4 +1,4 @@
1
- import { PlayerEvent } from 'bitmovin-player';
1
+ import { PlayerEvent } from 'bitmovin-player/modules/bitmovinplayer-core';
2
2
  export function removeReplayClass(player) {
3
3
  if (!player)
4
4
  return;
@@ -1,6 +1,6 @@
1
1
  import '@testing-library/jest-dom';
2
2
  import { removeReplayClass } from './removereplayclass';
3
- import { PlayerEvent } from 'bitmovin-player';
3
+ import { PlayerEvent } from 'bitmovin-player/modules/bitmovinplayer-core';
4
4
  describe('removeReplayClass', () => {
5
5
  let mockPlayer;
6
6
  let mockPlayerContainer;
@@ -68,6 +68,7 @@ export declare const localizationConfig: {
68
68
  connectingTo: string;
69
69
  watermarkLink: string;
70
70
  controlBar: string;
71
+ "controlBar.bottom": string;
71
72
  player: string;
72
73
  videoPlayer: string;
73
74
  audioPlayer: string;
@@ -1,3 +1,5 @@
1
1
  export declare const convertBase64ToObject: (value: string) => Record<string, any>;
2
2
  export declare const convertJwtToBase64: (jwt: string) => string;
3
3
  export declare function isJWTToken(token: string): boolean;
4
+ export declare function getJwtIat(jwt: string): number;
5
+ export declare function isJwtFresh(jwt: string, maxAgeSeconds?: number): boolean;
@@ -20,3 +20,25 @@ export function isJWTToken(token) {
20
20
  const JWT_REGEX = /^(?:[\w=-]+\.){2}[\w+./=-]+$/;
21
21
  return JWT_REGEX.test(token);
22
22
  }
23
+ export function getJwtIat(jwt) {
24
+ const parts = jwt.split('.');
25
+ if (parts.length !== 3) {
26
+ throw new Error('Invalid JWT format');
27
+ }
28
+ const payloadJson = Buffer.from(parts[1], 'base64').toString('utf8');
29
+ const payload = JSON.parse(payloadJson);
30
+ if (typeof payload.iat !== 'number') {
31
+ throw new TypeError('JWT `iat` claim missing or not a number');
32
+ }
33
+ return payload.iat;
34
+ }
35
+ export function isJwtFresh(jwt, maxAgeSeconds = 3600) {
36
+ try {
37
+ const issuedAt = getJwtIat(jwt);
38
+ const ageSeconds = Date.now() / 1000 - issuedAt;
39
+ return ageSeconds <= maxAgeSeconds;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
@@ -1,9 +1,18 @@
1
1
  import { convertMsToSeconds } from './utilities.time';
2
2
  export function getStreamDurationInSeconds(params) {
3
3
  const { duration, durationIsInMs } = params;
4
- if (duration === undefined || duration === Number.POSITIVE_INFINITY)
4
+ if (duration === undefined || duration === Number.POSITIVE_INFINITY) {
5
5
  return -1;
6
- return durationIsInMs ? convertMsToSeconds(Number(duration)) : Number.isFinite(+duration) ? Number(duration) : -1;
6
+ }
7
+ if (durationIsInMs) {
8
+ return convertMsToSeconds(Number(duration));
9
+ }
10
+ else if (Number.isFinite(+duration)) {
11
+ return Number(duration);
12
+ }
13
+ else {
14
+ return -1;
15
+ }
7
16
  }
8
17
  export function validatePrid(prid) {
9
18
  return prid !== '' && prid !== undefined ? prid : 'unknown';
@@ -12,7 +12,7 @@ export async function isMediaUrl(url) {
12
12
  return false;
13
13
  try {
14
14
  const response = await fetch(url, { method: 'HEAD' });
15
- const header = response.headers.get('Content-Type') || '';
15
+ const header = response.headers.get('Content-Type') ?? '';
16
16
  return supportedMediaTypes.some((mediaType) => header.startsWith(mediaType));
17
17
  }
18
18
  catch (error) {
@@ -25,5 +25,5 @@ export function isUrl(url) {
25
25
  return URL_REGEX.test(url);
26
26
  }
27
27
  export const removeTrailingSlash = (url) => {
28
- return url.slice(-1) === '/' ? (url = url.slice(0, -1)) : url;
28
+ return url.endsWith('/') ? url.slice(0, -1) : url;
29
29
  };
@@ -17,7 +17,7 @@ export function logVersion(version) {
17
17
  \`╝╠╠╠╠╠╩\`
18
18
  \`╙╙╙
19
19
  `;
20
- const COLOR_CODE = '#ff6d00';
20
+ const COLOR_CODE = '#f56A00';
21
21
  const TITLE = 'NPO Player';
22
22
  const TITLE_STYLE = `font-size: 24px; font-weight: bold; color: ${COLOR_CODE}; padding: 2px 4px;`;
23
23
  const VERSION_STRING = 'v' + String(version);
@@ -21,6 +21,6 @@ describe('logVersion', () => {
21
21
  \`╝╠╠╠╠╠╩\`
22
22
  \`╙╙╙
23
23
  `;
24
- expect(logSpy).toHaveBeenCalledWith(`%c${ASCII_ART}%cNPO Player %cv1.0.0`, 'color: #ff6d00; background-color: rgb(11, 28, 54);', 'font-size: 24px; font-weight: bold; color: #ff6d00; padding: 2px 4px;', 'font-size: 24px; font-weight: bold; padding: 2px 4px;');
24
+ expect(logSpy).toHaveBeenCalledWith(`%c${ASCII_ART}%cNPO Player %cv1.0.0`, 'color: #f56A00; background-color: rgb(11, 28, 54);', 'font-size: 24px; font-weight: bold; color: #f56A00; padding: 2px 4px;', 'font-size: 24px; font-weight: bold; padding: 2px 4px;');
25
25
  });
26
26
  });
package/lib/lang/nl.json CHANGED
@@ -65,12 +65,13 @@
65
65
  "connectingTo": "Maakt verbinding met <strong>{castDeviceName}</strong>...",
66
66
  "watermarkLink": "Link to Homepage",
67
67
  "controlBar": "Video speler bedieningselementen",
68
+ "controlBar.bottom": "Tijdlijn en navigatie video speler",
68
69
  "player": "Video speler",
69
70
  "videoPlayer": "Video speler",
70
71
  "audioPlayer": "Audio speler",
71
72
  "seekBar": "Video tijdlijn",
72
73
  "seekBar.value": "Waarde",
73
74
  "seekBar.timeshift": "Timeshift",
74
- "seekBar.durationText": "out of",
75
+ "seekBar.durationText": "van",
75
76
  "segment.unplayableTitle": "Niet beschikbaar"
76
77
  }
@@ -1,10 +1,11 @@
1
1
  import { NpoPlayerServices } from './services/services';
2
2
  import { type StreamTracker, type NPOTag, type PageTracker } from '@npotag/tag';
3
3
  import { type InitialisationProps } from '@npotag/tag/dist/types/src/npoTag';
4
- import { type PlayerAPI, type PlayerConfig, type SourceConfig } from 'bitmovin-player';
4
+ import { type PlayerAPI, type PlayerConfig, type SourceConfig } from 'bitmovin-player/modules/bitmovinplayer-core';
5
5
  import { UIManager } from 'bitmovin-player-ui';
6
6
  import { LogEmitter } from './types/classes';
7
7
  import { type DRMProfile, type ApiPayload, type NPOTagObject, type StreamObject, type StreamOptions, type UIComponents, type TimeLineMarker, type PlayerContext, type EventListeners, NpoPlayerUIVariants } from './types/interfaces';
8
+ import { ChapterHandler } from './services/chapterHandlers/chapterHandler';
8
9
  export { type PlayerConfig, type InitialisationProps, type NPOTagObject, type StreamOptions, NpoPlayerUIVariants };
9
10
  export default class NpoPlayer {
10
11
  playerConfig: PlayerConfig | undefined;
@@ -32,14 +33,14 @@ export default class NpoPlayer {
32
33
  playerContext: PlayerContext | undefined;
33
34
  npoPlayerServices: NpoPlayerServices;
34
35
  eventListeners: EventListeners | undefined;
35
- mockNpoPlayer: any;
36
+ chapterHandler: ChapterHandler | undefined;
36
37
  constructor(container: HTMLElement | {
37
38
  container: HTMLElement;
38
39
  playerConfig: PlayerConfig;
39
- npoTag?: InitialisationProps | undefined;
40
- npoTagInstance?: NPOTag | undefined;
40
+ npoTag?: InitialisationProps;
41
+ npoTagInstance?: NPOTag;
41
42
  variant?: NpoPlayerUIVariants;
42
- npoTagPageTracker?: PageTracker | undefined;
43
+ npoTagPageTracker?: PageTracker;
43
44
  }, playerConfig?: PlayerConfig | undefined, npoTag?: InitialisationProps | undefined, npoTagInstance?: NPOTag | undefined, variant?: NpoPlayerUIVariants, npoTagPageTracker?: PageTracker | undefined);
44
45
  keydownHandler: (e: KeyboardEvent) => void;
45
46
  initPlayer(_container: HTMLElement, playerConfig: PlayerConfig): void;