@npo/player 1.23.1 → 1.24.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 (140) hide show
  1. package/README.md +1 -1
  2. package/lib/js/playeractions/handlers/error.js +2 -2
  3. package/lib/js/playeractions/handlers/error.test.js +2 -2
  4. package/lib/js/playeractions/handlers/handleoffsets.d.ts +4 -6
  5. package/lib/js/playeractions/handlers/handleoffsets.js +16 -17
  6. package/lib/js/playeractions/handlers/handleoffsets.test.js +73 -29
  7. package/lib/js/playeractions/handlers/mediasessionactions.js +24 -12
  8. package/lib/js/playeractions/handlers/processsourceconfig.js +16 -3
  9. package/lib/js/tracking/handlers/eventbinding.d.ts +1 -1
  10. package/lib/js/tracking/handlers/eventbinding.js +17 -23
  11. package/lib/js/tracking/handlers/eventlogging.d.ts +1 -1
  12. package/lib/js/tracking/handlers/eventlogging.js +18 -18
  13. package/lib/js/tracking/handlers/eventlogging.test.js +24 -24
  14. package/lib/js/tracking/handlers/playertrackerstart.js +4 -2
  15. package/lib/lang/nl.json +3 -1
  16. package/lib/npoplayer.d.ts +1 -2
  17. package/lib/npoplayer.js +27 -46
  18. package/lib/package.json +5 -5
  19. package/lib/services/a11y/setup.js +2 -2
  20. package/lib/services/a11y/setup.test.js +7 -8
  21. package/lib/services/advertHandlers/handlePreRolls.d.ts +2 -0
  22. package/lib/services/advertHandlers/handlePreRolls.js +132 -0
  23. package/lib/services/advertHandlers/handlePrerolls.test.js +52 -0
  24. package/lib/services/cdnProviders/cdnProviders.d.ts +4 -0
  25. package/lib/services/cdnProviders/cdnProviders.js +22 -0
  26. package/lib/services/cdnProviders/cndProviders.test.js +22 -0
  27. package/lib/services/eventListenerHandlers/removeEventListeners.d.ts +1 -1
  28. package/lib/services/eventListenerHandlers/removeEventListeners.js +4 -4
  29. package/lib/services/eventListenerHandlers/removeEventListeners.test.js +28 -13
  30. package/lib/services/liveStreamHandlers/handleLiveStreamControls.d.ts +1 -1
  31. package/lib/services/liveStreamHandlers/handleLiveStreamControls.js +3 -3
  32. package/lib/services/liveStreamHandlers/handleLiveStreamControls.test.d.ts +2 -0
  33. package/lib/services/liveStreamHandlers/handleLiveStreamControls.test.js +65 -0
  34. package/lib/services/localStorageHandlers/localStorageHandlers.d.ts +1 -1
  35. package/lib/services/localStorageHandlers/localStorageHandlers.test.js +0 -1
  36. package/lib/services/npoPlayerAPI/contants.d.ts +5 -0
  37. package/lib/services/npoPlayerAPI/contants.js +5 -0
  38. package/lib/services/npoPlayerAPI/npoPlayerAPI.d.ts +16 -4
  39. package/lib/services/npoPlayerAPI/npoPlayerAPI.js +65 -3
  40. package/lib/services/npoPlayerAPI/npoPlayerAPI.test.js +66 -1
  41. package/lib/services/segmentHandlers/addSegmentEventListeners.js +3 -3
  42. package/lib/services/segmentHandlers/addSegmentEventListeners.test.js +10 -9
  43. package/lib/services/segmentHandlers/convertFragmentToSegment.d.ts +1 -1
  44. package/lib/services/segmentHandlers/handleSegmentSeek.d.ts +1 -1
  45. package/lib/services/segmentHandlers/handleSegmentSeek.test.js +4 -4
  46. package/lib/services/segmentHandlers/handleSegmentTimeChanged.d.ts +1 -1
  47. package/lib/services/segmentHandlers/handleSegmentTimeChanged.test.js +33 -24
  48. package/lib/services/segmentHandlers/initSegment.d.ts +1 -1
  49. package/lib/services/segmentHandlers/initSegment.test.js +3 -1
  50. package/lib/services/segmentHandlers/setSegmentMarkers.d.ts +1 -1
  51. package/lib/services/services.d.ts +3 -1
  52. package/lib/services/services.js +8 -0
  53. package/lib/services/verticalVideoHandlers/handleVerticalVideoControls.d.ts +2 -0
  54. package/lib/services/verticalVideoHandlers/handleVerticalVideoControls.js +8 -0
  55. package/lib/services/verticalVideoHandlers/handleVerticalVideoControls.test.d.ts +1 -0
  56. package/lib/services/verticalVideoHandlers/handleVerticalVideoControls.test.js +36 -0
  57. package/lib/src/js/playeractions/handlers/handleoffsets.d.ts +4 -6
  58. package/lib/src/js/tracking/handlers/eventbinding.d.ts +1 -1
  59. package/lib/src/js/tracking/handlers/eventlogging.d.ts +1 -1
  60. package/lib/src/npoplayer.d.ts +1 -2
  61. package/lib/src/services/advertHandlers/handlePreRolls.d.ts +2 -0
  62. package/lib/src/services/advertHandlers/handlePrerolls.test.d.ts +1 -0
  63. package/lib/src/services/cdnProviders/cdnProviders.d.ts +4 -0
  64. package/lib/src/services/cdnProviders/cndProviders.test.d.ts +1 -0
  65. package/lib/src/services/eventListenerHandlers/removeEventListeners.d.ts +1 -1
  66. package/lib/src/services/liveStreamHandlers/handleLiveStreamControls.d.ts +1 -1
  67. package/lib/src/services/liveStreamHandlers/handleLiveStreamControls.test.d.ts +2 -0
  68. package/lib/src/services/localStorageHandlers/localStorageHandlers.d.ts +1 -1
  69. package/lib/src/services/npoPlayerAPI/contants.d.ts +5 -0
  70. package/lib/src/services/npoPlayerAPI/npoPlayerAPI.d.ts +16 -4
  71. package/lib/src/services/segmentHandlers/convertFragmentToSegment.d.ts +1 -1
  72. package/lib/src/services/segmentHandlers/handleSegmentSeek.d.ts +1 -1
  73. package/lib/src/services/segmentHandlers/handleSegmentTimeChanged.d.ts +1 -1
  74. package/lib/src/services/segmentHandlers/initSegment.d.ts +1 -1
  75. package/lib/src/services/segmentHandlers/setSegmentMarkers.d.ts +1 -1
  76. package/lib/src/services/services.d.ts +3 -1
  77. package/lib/src/services/verticalVideoHandlers/handleVerticalVideoControls.d.ts +2 -0
  78. package/lib/src/services/verticalVideoHandlers/handleVerticalVideoControls.test.d.ts +1 -0
  79. package/lib/src/types/events.d.ts +8 -1
  80. package/lib/src/types/interfaces.d.ts +8 -12
  81. package/lib/src/ui/components/audio/controlbar.d.ts +1 -1
  82. package/lib/src/ui/components/controlbar.d.ts +1 -1
  83. package/lib/src/ui/components/seekbar.d.ts +1 -1
  84. package/lib/src/ui/components/settingspanel.d.ts +1 -1
  85. package/lib/src/ui/components/verticalvideo/controlbar.d.ts +3 -0
  86. package/lib/src/ui/handlers/streamhandler.d.ts +2 -4
  87. package/lib/src/ui/uicontainer.d.ts +2 -2
  88. package/lib/tests/mocks/mockNpoplayer.js +0 -1
  89. package/lib/tests/mocks/playerContextMock.d.ts +67 -0
  90. package/lib/tests/mocks/playerContextMock.js +117 -0
  91. package/lib/types/events.d.ts +8 -1
  92. package/lib/types/events.js +184 -1
  93. package/lib/types/interfaces.d.ts +8 -12
  94. package/lib/types/interfaces.js +1 -0
  95. package/lib/ui/components/audio/controlbar.d.ts +1 -1
  96. package/lib/ui/components/audio/controlbar.js +6 -6
  97. package/lib/ui/components/controlbar.d.ts +1 -1
  98. package/lib/ui/components/controlbar.js +13 -11
  99. package/lib/ui/components/nativemobile/controlbar.js +0 -1
  100. package/lib/ui/components/seekbar.js +1 -1
  101. package/lib/ui/components/settingspanel.d.ts +1 -1
  102. package/lib/ui/components/settingspanel.js +68 -84
  103. package/lib/ui/components/topbar.js +6 -3
  104. package/lib/ui/components/verticalvideo/controlbar.d.ts +3 -0
  105. package/lib/ui/components/verticalvideo/controlbar.js +34 -0
  106. package/lib/ui/handlers/streamhandler.d.ts +2 -4
  107. package/lib/ui/handlers/streamhandler.js +16 -7
  108. package/lib/ui/nativemobileuifactory.js +2 -0
  109. package/lib/ui/uicontainer.d.ts +2 -2
  110. package/lib/ui/uicontainer.js +35 -29
  111. package/package.json +5 -5
  112. package/src/style/components/_settingspanel.scss +35 -3
  113. package/src/style/components/_subtitles.scss +29 -25
  114. package/src/style/components/_textbuttons.scss +2 -2
  115. package/src/style/components/_volumeslider.scss +1 -0
  116. package/src/style/components/vertical-video/_bottombar.scss +19 -0
  117. package/src/style/components/vertical-video/_buttons.scss +23 -0
  118. package/src/style/components/vertical-video/_hugeplaybacktogglebutton.scss +14 -0
  119. package/src/style/components/vertical-video/_seekbar.scss +19 -0
  120. package/src/style/components/vertical-video/_settingsbutton.scss +7 -0
  121. package/src/style/components/vertical-video/_settingspanel.scss +14 -0
  122. package/src/style/components/vertical-video/_shortvideo.scss +14 -0
  123. package/src/style/components/vertical-video/_subtitles.scss +3 -0
  124. package/src/style/components/vertical-video/_topbar.scss +17 -0
  125. package/src/style/components/vertical-video/_volumeslider.scss +9 -0
  126. package/src/style/npoplayer.css +74 -34
  127. package/src/style/npoplayer.scss +2 -1
  128. package/src/style/variants/_player-small.scss +18 -10
  129. package/src/style/variants/_player-vertical.scss +23 -0
  130. package/lib/js/ads/ster.d.ts +0 -4
  131. package/lib/js/ads/ster.js +0 -126
  132. package/lib/js/ads/ster.test.js +0 -63
  133. package/lib/js/cdnproviders.d.ts +0 -1
  134. package/lib/js/cdnproviders.js +0 -16
  135. package/lib/src/js/ads/ster.d.ts +0 -4
  136. package/lib/src/js/cdnproviders.d.ts +0 -1
  137. package/lib/tests/mocks/mockPlayerContext.d.ts +0 -2
  138. package/lib/tests/mocks/mockPlayerContext.js +0 -40
  139. /package/lib/{js/ads/ster.test.d.ts → services/advertHandlers/handlePrerolls.test.d.ts} +0 -0
  140. /package/lib/{src/js/ads/ster.test.d.ts → services/cdnProviders/cndProviders.test.d.ts} +0 -0
package/README.md CHANGED
@@ -11,7 +11,7 @@ Extensive and up-to-date documentation is available at https://docs.npoplayer.nl
11
11
  Code quality is analysed by SonarCloud. The project can be found at https://sonarcloud.io/project/overview?id=NPOstart_npo-player
12
12
 
13
13
  # Changelog
14
- Current version: v1.23.0
14
+ Current version: v1.24.0
15
15
 
16
16
  The changelog is available at https://docs.npoplayer.nl/implementation/web/changelog/
17
17
 
@@ -5,8 +5,8 @@ export function handlePlayerError(player, uiComponents, input) {
5
5
  }
6
6
  console.error('Er is iets mis met het ophalen van de stream.', input);
7
7
  player.unload();
8
- if (uiComponents.controlbar)
9
- uiComponents.controlbar.hide();
8
+ if (uiComponents.controlBar)
9
+ uiComponents.controlBar.hide();
10
10
  if (uiComponents.errorMessageOverlay == undefined)
11
11
  return;
12
12
  uiComponents.errorMessageOverlay.show();
@@ -6,7 +6,7 @@ const show = jest.fn();
6
6
  const input = 'string';
7
7
  const player = { unload };
8
8
  const uiComponents = {
9
- controlbar: { hide },
9
+ controlBar: { hide },
10
10
  errorMessageOverlay: {
11
11
  errorLabel: { setText },
12
12
  show
@@ -27,7 +27,7 @@ describe('Test DRM verification', () => {
27
27
  it('should not hide the controlbar', () => {
28
28
  const components = {
29
29
  ...uiComponents,
30
- controlbar: undefined
30
+ controlBar: undefined
31
31
  };
32
32
  handlePlayerError(player, components, input);
33
33
  expect(hide).not.toHaveBeenCalled();
@@ -1,6 +1,4 @@
1
- import { type PlayerAPI } from 'bitmovin-player';
2
- import type NpoPlayer from '../../../npoplayer';
3
- import { type StreamOptions } from 'types/interfaces';
4
- export declare function handleStartOffset(player: PlayerAPI, offset?: number): void;
5
- export declare function shiftToProgramStart(player: PlayerAPI | undefined, timestamp?: number): void;
6
- export declare function handleLiveOffsetLogic(npoplayer: NpoPlayer, player: PlayerAPI | undefined, options: StreamOptions): void;
1
+ import { PlayerContext, type StreamOptions } from '../../../types/interfaces';
2
+ export declare function handleStartOffset(playerContext: PlayerContext, offset?: number): void;
3
+ export declare function shiftToProgramStart(playerContext: PlayerContext, timestamp?: number): void;
4
+ export declare function handleLiveOffsetLogic(playerContext: PlayerContext, options: StreamOptions): void;
@@ -1,24 +1,24 @@
1
- import { PlayerEvent } from 'bitmovin-player';
2
- export function handleStartOffset(player, offset) {
3
- if (offset == undefined || player.isLive()) {
4
- if (player.isLive()) {
1
+ import { NpoPlayerEvent } from '../../../types/events';
2
+ export function handleStartOffset(playerContext, offset) {
3
+ const { player } = playerContext;
4
+ if (offset == undefined || playerContext.player.isLive()) {
5
+ if (playerContext.player.isLive()) {
5
6
  console.warn('handleStartOffset was called but the player is playing live content.');
6
7
  }
7
8
  return;
8
9
  }
9
10
  const seek = () => {
10
- player.off(PlayerEvent.SourceLoaded, seek);
11
- player.off(PlayerEvent.AdBreakFinished, seek);
12
- player.off(PlayerEvent.AdError, seek);
11
+ player.off(NpoPlayerEvent.SourceLoaded, seek);
12
+ player.off(NpoPlayerEvent.AdBreakFinished, seek);
13
+ player.off(NpoPlayerEvent.AdError, seek);
13
14
  player.seek(offset);
14
15
  };
15
- player.on(PlayerEvent.SourceLoaded, seek);
16
- player.on(PlayerEvent.AdBreakFinished, seek);
17
- player.on(PlayerEvent.AdError, seek);
16
+ player.on(NpoPlayerEvent.SourceLoaded, seek);
17
+ player.on(NpoPlayerEvent.AdBreakFinished, seek);
18
+ player.on(NpoPlayerEvent.AdError, seek);
18
19
  }
19
- export function shiftToProgramStart(player, timestamp) {
20
- if (player == undefined)
21
- return;
20
+ export function shiftToProgramStart(playerContext, timestamp) {
21
+ const { player } = playerContext;
22
22
  if (timestamp == undefined || !player.isLive()) {
23
23
  if (!player.isLive()) {
24
24
  console.warn('shiftToProgramStart was called but the player is playing VOD content.');
@@ -27,9 +27,8 @@ export function shiftToProgramStart(player, timestamp) {
27
27
  }
28
28
  player.timeShift(timestamp);
29
29
  }
30
- export function handleLiveOffsetLogic(npoplayer, player, options) {
31
- if (player == undefined)
32
- return;
30
+ export function handleLiveOffsetLogic(playerContext, options) {
31
+ const { player, npoplayer } = playerContext;
33
32
  if (npoplayer.uiComponents.watchFromStartButton == undefined)
34
33
  return;
35
34
  if (options?.liveProgramTime == undefined) {
@@ -45,6 +44,6 @@ export function handleLiveOffsetLogic(npoplayer, player, options) {
45
44
  }
46
45
  if (options.liveOffset !== null && options.liveOffset !== false && options.liveProgramTime > 0) {
47
46
  npoplayer.uiComponents.watchFromStartButton.hide();
48
- shiftToProgramStart(player, options.liveProgramTime);
47
+ shiftToProgramStart(playerContext, options.liveProgramTime);
49
48
  }
50
49
  }
@@ -1,49 +1,93 @@
1
+ import { PlayerEvent } from 'bitmovin-player';
2
+ import { createPlayerContextMock, createMockNpoPlayerAPI } from '../../../../tests/mocks/playerContextMock';
1
3
  import { handleStartOffset, shiftToProgramStart } from './handleoffsets';
2
- const isLive = () => true;
3
- const onReady = jest.fn();
4
- const timeShift = jest.fn();
5
- const offset = 10;
6
- const timestamp = 10;
7
- const player = {
8
- isLive,
9
- on: onReady,
10
- timeShift
11
- };
12
4
  describe('Test offset handling', () => {
5
+ const offset = 10;
13
6
  afterEach(() => {
14
7
  jest.resetAllMocks();
15
8
  });
16
9
  it('should not seek when player is live', () => {
17
- handleStartOffset(player, offset);
18
- expect(onReady).not.toHaveBeenCalled();
10
+ const mockNpoPlayerAPI = createMockNpoPlayerAPI({
11
+ isLive: jest.fn().mockReturnValue(true),
12
+ seek: jest.fn(),
13
+ on: jest.fn(),
14
+ off: jest.fn()
15
+ });
16
+ const playerContextMock = createPlayerContextMock({
17
+ player: mockNpoPlayerAPI
18
+ });
19
+ handleStartOffset(playerContextMock, offset);
20
+ expect(mockNpoPlayerAPI.seek).not.toHaveBeenCalled();
19
21
  });
20
22
  it('should not seek when offset is undefined', () => {
21
- handleStartOffset({ ...player, isLive: () => false });
22
- expect(onReady).not.toHaveBeenCalled();
23
+ const mockNpoPlayerAPI = createMockNpoPlayerAPI({
24
+ isLive: jest.fn().mockReturnValue(false),
25
+ seek: jest.fn(),
26
+ on: jest.fn(),
27
+ off: jest.fn()
28
+ });
29
+ const playerContextMock = createPlayerContextMock({
30
+ player: mockNpoPlayerAPI
31
+ });
32
+ handleStartOffset(playerContextMock);
33
+ expect(mockNpoPlayerAPI.seek).not.toHaveBeenCalled();
23
34
  });
24
35
  it('should seek when player is not live and offset is defined', () => {
25
- handleStartOffset({ ...player, isLive: () => false }, offset);
26
- expect(onReady).toHaveBeenCalled();
36
+ const seekMock = jest.fn();
37
+ const mockNpoPlayerAPI = createMockNpoPlayerAPI({
38
+ isLive: jest.fn().mockReturnValue(false),
39
+ seek: seekMock,
40
+ off: jest.fn(),
41
+ on: jest.fn((event, callback) => {
42
+ if (event === PlayerEvent.SourceLoaded) {
43
+ callback();
44
+ }
45
+ })
46
+ });
47
+ const playerContextMock = createPlayerContextMock({
48
+ player: mockNpoPlayerAPI
49
+ });
50
+ handleStartOffset(playerContextMock, offset);
51
+ expect(seekMock).toHaveBeenCalledWith(offset);
27
52
  });
28
53
  });
29
54
  describe('Test programStart shift', () => {
55
+ const timestamp = 30;
30
56
  afterEach(() => {
31
57
  jest.resetAllMocks();
32
58
  });
33
- it('should not call timeshift when player is null', () => {
34
- shiftToProgramStart(undefined, timestamp);
35
- expect(timeShift).not.toHaveBeenCalled();
59
+ it('should not call timeShift when timestamp is undefined', () => {
60
+ const mockNpoPlayerAPI = createMockNpoPlayerAPI({
61
+ isLive: jest.fn().mockReturnValue(true),
62
+ timeShift: jest.fn()
63
+ });
64
+ const playerContextMock = createPlayerContextMock({
65
+ player: mockNpoPlayerAPI
66
+ });
67
+ shiftToProgramStart(playerContextMock);
68
+ expect(mockNpoPlayerAPI.timeShift).not.toHaveBeenCalled();
36
69
  });
37
- it('should not call timeshift when timestamp is undefined', () => {
38
- shiftToProgramStart(player);
39
- expect(timeShift).not.toHaveBeenCalled();
70
+ it('should not call timeShift when player is not live', () => {
71
+ const mockNpoPlayerAPI = createMockNpoPlayerAPI({
72
+ isLive: jest.fn().mockReturnValue(false),
73
+ timeShift: jest.fn()
74
+ });
75
+ const playerContextMock = createPlayerContextMock({
76
+ player: mockNpoPlayerAPI
77
+ });
78
+ shiftToProgramStart(playerContextMock, timestamp);
79
+ expect(mockNpoPlayerAPI.timeShift).not.toHaveBeenCalled();
40
80
  });
41
- it('should not call timeshift when player is not live', () => {
42
- shiftToProgramStart({ ...player, isLive: () => false }, timestamp);
43
- expect(timeShift).not.toHaveBeenCalled();
44
- });
45
- it('should not call timeshift when player is live and timestamp is set', () => {
46
- shiftToProgramStart(player, timestamp);
47
- expect(timeShift).toHaveBeenCalled();
81
+ it('should call timeShift when player is live and timestamp is set', () => {
82
+ const timeShiftMock = jest.fn();
83
+ const mockNpoPlayerAPI = createMockNpoPlayerAPI({
84
+ isLive: jest.fn().mockReturnValue(true),
85
+ timeShift: timeShiftMock
86
+ });
87
+ const playerContextMock = createPlayerContextMock({
88
+ player: mockNpoPlayerAPI
89
+ });
90
+ shiftToProgramStart(playerContextMock, timestamp);
91
+ expect(timeShiftMock).toHaveBeenCalledWith(timestamp);
48
92
  });
49
93
  });
@@ -1,40 +1,52 @@
1
1
  import { PlayerEvent } from 'bitmovin-player';
2
2
  export function setupMediaSessionActionHandlers(player, sourceConfig, _streamObject) {
3
- player.on(PlayerEvent.Playing, () => {
3
+ function handlePlaying() {
4
+ player.off(PlayerEvent.Playing, handlePlaying);
4
5
  if (!('mediaSession' in navigator)) {
5
6
  return;
6
7
  }
7
8
  setMediaSessionMetadata();
8
9
  setupMediaSessionActionHandlers();
9
10
  updatePositionState();
10
- });
11
- player.on(PlayerEvent.Paused, () => {
11
+ }
12
+ function handlePaused() {
13
+ player.off(PlayerEvent.Paused, handlePaused);
12
14
  if (!('mediaSession' in navigator)) {
13
15
  return;
14
16
  }
15
17
  navigator.mediaSession.playbackState = 'paused';
16
- });
17
- player.on(PlayerEvent.Play, () => {
18
+ }
19
+ function handlePlay() {
20
+ player.off(PlayerEvent.Play, handlePlay);
18
21
  if (!('mediaSession' in navigator)) {
19
22
  return;
20
23
  }
21
24
  navigator.mediaSession.playbackState = 'playing';
22
- });
23
- player.on(PlayerEvent.SourceUnloaded, () => {
25
+ }
26
+ function handleSourceUnloaded() {
27
+ player.off(PlayerEvent.SourceUnloaded, handleSourceUnloaded);
24
28
  if (!('mediaSession' in navigator)) {
25
29
  return;
26
30
  }
27
31
  navigator.mediaSession.setPositionState(undefined);
28
- });
29
- player.on(PlayerEvent.Destroy, () => {
32
+ }
33
+ function handleDestroy() {
34
+ player.off(PlayerEvent.Destroy, handleDestroy);
30
35
  if (!('mediaSession' in navigator)) {
31
36
  return;
32
37
  }
33
38
  navigator.mediaSession.setPositionState(undefined);
34
- });
35
- player.on(PlayerEvent.PlaybackSpeedChanged, () => {
39
+ }
40
+ function handlePlaybackSpeedChanged() {
41
+ player.off(PlayerEvent.PlaybackSpeedChanged, handlePlaybackSpeedChanged);
36
42
  updatePositionState();
37
- });
43
+ }
44
+ player.on(PlayerEvent.Playing, handlePlaying);
45
+ player.on(PlayerEvent.Paused, handlePaused);
46
+ player.on(PlayerEvent.Play, handlePlay);
47
+ player.on(PlayerEvent.SourceUnloaded, handleSourceUnloaded);
48
+ player.on(PlayerEvent.Destroy, handleDestroy);
49
+ player.on(PlayerEvent.PlaybackSpeedChanged, handlePlaybackSpeedChanged);
38
50
  function setMediaSessionMetadata() {
39
51
  const metadata = {
40
52
  title: sourceConfig.title,
@@ -1,5 +1,5 @@
1
1
  import { HttpResponseType } from 'bitmovin-player';
2
- import { npoCdnProviders } from '../../cdnproviders';
2
+ import { npoCdnProviders } from '../../../services/cdnProviders/cdnProviders';
3
3
  import { replaceSpecialCharacters } from '../../utilities/utilities.text';
4
4
  async function setDrm(sourceConfig, drm, _streamObject, useWidevineServerCertificate) {
5
5
  const npoDrmGateway = 'https://npo-drm-gateway.samgcloud.nepworldwide.nl/authentication?custom_data=';
@@ -104,8 +104,12 @@ function setStreamProfile(sourceConfig, _sourceConfig, _streamObject) {
104
104
  }
105
105
  export async function processSourceConfig(NpoPlayerServices, _sourceConfig = {}, _streamObject, drm = undefined, streamOptions, version, npoTagPartyId, npoPlayerServices) {
106
106
  let sourceConfig = {};
107
- sourceConfig.title = _sourceConfig.title ?? _streamObject.metadata.title ?? '';
108
- sourceConfig.description = _sourceConfig.description ?? _streamObject.metadata.description ?? '';
107
+ sourceConfig.title = _sourceConfig.title
108
+ ? replacePlaceholders(_sourceConfig.title, _streamObject.metadata)
109
+ : _streamObject.metadata.title ?? '';
110
+ sourceConfig.description = _sourceConfig.description
111
+ ? replacePlaceholders(_sourceConfig.description, _streamObject.metadata)
112
+ : _streamObject.metadata.description ?? '';
109
113
  sourceConfig.poster = decidePoster(_streamObject, _sourceConfig, streamOptions);
110
114
  sourceConfig.metadata = {
111
115
  title: sourceConfig.title,
@@ -190,3 +194,12 @@ function decidePoster(streamObject, sourceConfig, streamOptions) {
190
194
  }
191
195
  return streamObject.metadata.poster ?? '';
192
196
  }
197
+ function replacePlaceholders(template, metadata) {
198
+ return template.replace(/{([^{}]*)}/g, (match, key) => {
199
+ const value = metadata[key];
200
+ if (Array.isArray(value)) {
201
+ return value.map((item) => item.trim()).join(', ');
202
+ }
203
+ return value === undefined ? '' : String(value);
204
+ });
205
+ }
@@ -1,3 +1,3 @@
1
1
  import { type PlayerAPI } from 'bitmovin-player';
2
2
  import type NpoPlayer from '../../../npoplayer';
3
- export declare function bindPlayerEvents(npoplayer: NpoPlayer, player: PlayerAPI): void;
3
+ export declare function bindPlayerEvents(npoPlayer: NpoPlayer, player: PlayerAPI): void;
@@ -1,11 +1,10 @@
1
1
  import { PlayerEvent, ViewMode } from 'bitmovin-player';
2
2
  import { logEvent } from './eventlogging';
3
3
  const logEventHandlers = new Map();
4
- export function bindPlayerEvents(npoplayer, player) {
4
+ export function bindPlayerEvents(npoPlayer, player) {
5
5
  if (player == undefined)
6
6
  return;
7
- let isSeeking = false;
8
- const isLiveStream = npoplayer.streamObject.stream.isLiveStream;
7
+ const isLiveStream = npoPlayer.streamObject.stream.isLiveStream;
9
8
  let currentTime = 0;
10
9
  let isNewSource = true;
11
10
  const timeDifference = (time) => {
@@ -17,11 +16,10 @@ export function bindPlayerEvents(npoplayer, player) {
17
16
  const logEventHandler = (eventName) => {
18
17
  return (e) => {
19
18
  const eventTime = e.time === undefined ? undefined : timeDifference(e.time);
20
- logEvent(npoplayer, eventName, eventTime);
19
+ logEvent(npoPlayer, eventName, eventTime);
21
20
  };
22
21
  };
23
22
  const seekHandler = (e) => {
24
- isSeeking = true;
25
23
  let data = {};
26
24
  if (e.type === 'timeshift') {
27
25
  const timeDifferencePosition = -1 * (Date.now() / 1000 - e.position);
@@ -37,44 +35,44 @@ export function bindPlayerEvents(npoplayer, player) {
37
35
  stream_position: e.seekTarget
38
36
  };
39
37
  }
40
- logEvent(npoplayer, e.type, data);
38
+ logEvent(npoPlayer, 'seek', data);
41
39
  };
42
40
  const handleSourceLoaded = () => {
43
41
  isNewSource = true;
44
42
  if (isLiveStream) {
45
- logEvent(npoplayer, 'stop');
43
+ logEvent(npoPlayer, 'stop');
46
44
  }
47
45
  };
48
46
  const handlePlay = (e) => {
49
- if (!isNewSource && !isSeeking) {
50
- logEvent(npoplayer, 'resume', timeDifference(e.time));
47
+ if (!isNewSource && e.issuer !== 'ui-seek') {
48
+ logEvent(npoPlayer, 'resume', timeDifference(e.time));
51
49
  }
52
50
  };
53
- const handlePlaying = () => {
54
- if (isSeeking) {
55
- isSeeking = false;
51
+ const pausedHandler = (e) => {
52
+ if (e.issuer !== 'ui-seek') {
53
+ logEvent(npoPlayer, 'pause', timeDifference(e.time));
56
54
  }
57
55
  };
58
56
  const handleTime = (e) => {
59
- if (isNewSource && !npoplayer.adBreakActive) {
60
- logEvent(npoplayer, 'start', timeDifference(e.time));
57
+ if (isNewSource && !npoPlayer.adBreakActive) {
58
+ logEvent(npoPlayer, 'start', timeDifference(e.time));
61
59
  isNewSource = false;
62
60
  }
63
61
  else {
64
- logEvent(npoplayer, 'time', timeDifference(e.time));
62
+ logEvent(npoPlayer, 'time', timeDifference(e.time));
65
63
  }
66
64
  };
67
65
  const handleViewModeChange = () => {
68
66
  const newViewMode = player.getViewMode();
69
67
  if (newViewMode === ViewMode.Fullscreen) {
70
- logEvent(npoplayer, 'fullscreen', currentTime);
68
+ logEvent(npoPlayer, 'fullscreen', currentTime);
71
69
  }
72
70
  else {
73
- logEvent(npoplayer, 'windowed', currentTime);
71
+ logEvent(npoPlayer, 'windowed', currentTime);
74
72
  }
75
73
  };
76
74
  const stopBeforeUnload = () => {
77
- logEvent(npoplayer, 'stop');
75
+ logEvent(npoPlayer, 'stop');
78
76
  };
79
77
  for (const [key, value] of logEventHandlers) {
80
78
  player.off(key, value);
@@ -83,7 +81,7 @@ export function bindPlayerEvents(npoplayer, player) {
83
81
  logEventHandlers.clear();
84
82
  const playerEvents = [
85
83
  { event: PlayerEvent.Ready, name: 'load_complete' },
86
- { event: PlayerEvent.Paused, name: 'pause' },
84
+ { event: PlayerEvent.Paused, handler: pausedHandler },
87
85
  { event: PlayerEvent.Play, handler: handlePlay },
88
86
  { event: PlayerEvent.SourceLoaded, handler: handleSourceLoaded },
89
87
  { event: PlayerEvent.StallStarted, name: 'buffering' },
@@ -101,10 +99,6 @@ export function bindPlayerEvents(npoplayer, player) {
101
99
  logEventHandlers.set(event, eventHandler);
102
100
  player.on(event, eventHandler);
103
101
  }
104
- if (npoplayer.streamObject.assets.preroll === null) {
105
- logEventHandlers.set(PlayerEvent.Playing, handlePlaying);
106
- player.on(PlayerEvent.Playing, handlePlaying);
107
- }
108
102
  logEventHandlers.set('beforeunload', stopBeforeUnload);
109
103
  window.addEventListener('beforeunload', stopBeforeUnload);
110
104
  }
@@ -1,2 +1,2 @@
1
1
  import NpoPlayer from '../../../npoplayer';
2
- export declare function logEvent(npoplayer: NpoPlayer, event: string, data?: any): void;
2
+ export declare function logEvent(npoPlayer: NpoPlayer, event: string, data?: any): void;
@@ -1,31 +1,31 @@
1
- export function logEvent(npoplayer, event, data) {
2
- if (!npoplayer.player || !npoplayer.streamTracker || npoplayer.adBreakActive)
1
+ export function logEvent(npoPlayer, event, data) {
2
+ if (!npoPlayer.player || !npoPlayer.streamTracker || npoPlayer.adBreakActive || npoPlayer.player.isCasting())
3
3
  return;
4
4
  try {
5
- npoplayer.player.getCurrentTime();
5
+ npoPlayer.player.getCurrentTime();
6
6
  }
7
7
  catch (error) {
8
8
  console.warn('Er gaat iets mis met de player API', error);
9
9
  }
10
- const streamOptions = { stream_position: npoplayer.player.getCurrentTime() };
10
+ const streamOptions = { stream_position: npoPlayer.player.getCurrentTime() };
11
11
  const eventHandlers = {
12
- start: npoplayer.streamTracker.start,
13
- buffering: npoplayer.streamTracker.buffering,
14
- buffering_complete: npoplayer.streamTracker.buffering_complete,
15
- complete: npoplayer.streamTracker.complete,
16
- fullscreen: npoplayer.streamTracker.fullscreen,
17
- load: npoplayer.streamTracker.load,
18
- load_complete: npoplayer.streamTracker.load_complete,
19
- pause: npoplayer.streamTracker.pause,
20
- resume: npoplayer.streamTracker.resume,
21
- stop: npoplayer.streamTracker.stop,
22
- windowed: npoplayer.streamTracker.windowed,
23
- time: npoplayer.streamTracker.time,
12
+ start: npoPlayer.streamTracker.start,
13
+ buffering: npoPlayer.streamTracker.buffering,
14
+ buffering_complete: npoPlayer.streamTracker.buffering_complete,
15
+ complete: npoPlayer.streamTracker.complete,
16
+ fullscreen: npoPlayer.streamTracker.fullscreen,
17
+ load: npoPlayer.streamTracker.load,
18
+ load_complete: npoPlayer.streamTracker.load_complete,
19
+ pause: npoPlayer.streamTracker.pause,
20
+ resume: npoPlayer.streamTracker.resume,
21
+ stop: npoPlayer.streamTracker.stop,
22
+ windowed: npoPlayer.streamTracker.windowed,
23
+ time: npoPlayer.streamTracker.time,
24
24
  seek: () => {
25
- npoplayer.streamTracker?.seek(data);
25
+ npoPlayer.streamTracker?.seek(data);
26
26
  }
27
27
  };
28
28
  const streamTrackerHandler = eventHandlers[event];
29
- npoplayer.logEmitter.emit('logEvent', event, data);
29
+ npoPlayer.logEmitter.emit('logEvent', event, data);
30
30
  streamTrackerHandler(streamOptions);
31
31
  }
@@ -1,46 +1,46 @@
1
1
  import { logEvent } from './eventlogging';
2
2
  import { mockNpoPlayer } from '../../../../tests/mocks/mockNpoplayer';
3
3
  describe('logEvent', () => {
4
- let npoplayer;
4
+ let npoPlayer;
5
5
  beforeEach(() => {
6
- npoplayer = mockNpoPlayer;
6
+ npoPlayer = mockNpoPlayer;
7
7
  });
8
8
  it('should not log event if player is not available', () => {
9
- npoplayer.player = undefined;
10
- if (npoplayer.streamTracker && npoplayer.player) {
11
- logEvent(npoplayer, 'start');
12
- expect(npoplayer.streamTracker.start).not.toHaveBeenCalled();
13
- expect(npoplayer.logEmitter.emit).not.toHaveBeenCalled();
9
+ npoPlayer.player = undefined;
10
+ if (npoPlayer.streamTracker && npoPlayer.player) {
11
+ logEvent(npoPlayer, 'start');
12
+ expect(npoPlayer.streamTracker.start).not.toHaveBeenCalled();
13
+ expect(npoPlayer.logEmitter.emit).not.toHaveBeenCalled();
14
14
  }
15
15
  });
16
16
  it('should not log event if streamTracker is not available', () => {
17
- npoplayer.streamTracker = undefined;
18
- if (npoplayer.streamTracker) {
19
- logEvent(npoplayer, 'start');
20
- expect(npoplayer.logEmitter.emit).not.toHaveBeenCalled();
17
+ npoPlayer.streamTracker = undefined;
18
+ if (npoPlayer.streamTracker) {
19
+ logEvent(npoPlayer, 'start');
20
+ expect(npoPlayer.logEmitter.emit).not.toHaveBeenCalled();
21
21
  }
22
22
  });
23
23
  it('should not log event if adBreakActive is true', () => {
24
- npoplayer.adBreakActive = true;
25
- if (npoplayer.streamTracker) {
26
- logEvent(npoplayer, 'start');
27
- expect(npoplayer.streamTracker.start).not.toHaveBeenCalled();
28
- expect(npoplayer.logEmitter.emit).not.toHaveBeenCalled();
24
+ npoPlayer.adBreakActive = true;
25
+ if (npoPlayer.streamTracker) {
26
+ logEvent(npoPlayer, 'start');
27
+ expect(npoPlayer.streamTracker.start).not.toHaveBeenCalled();
28
+ expect(npoPlayer.logEmitter.emit).not.toHaveBeenCalled();
29
29
  }
30
30
  });
31
31
  it('should log event and call the corresponding streamTracker handler', () => {
32
- if (npoplayer.streamTracker) {
33
- logEvent(npoplayer, 'start');
34
- expect(npoplayer.streamTracker.start).toHaveBeenCalledWith({ stream_position: 10 });
35
- expect(npoplayer.logEmitter.emit).toHaveBeenCalledWith('logEvent', 'start');
32
+ if (npoPlayer.streamTracker) {
33
+ logEvent(npoPlayer, 'start');
34
+ expect(npoPlayer.streamTracker.start).toHaveBeenCalledWith({ stream_position: 10 });
35
+ expect(npoPlayer.logEmitter.emit).toHaveBeenCalledWith('logEvent', 'start');
36
36
  }
37
37
  });
38
38
  it('should log event and call the seek streamTracker handler with data', () => {
39
39
  const data = { position: 20 };
40
- if (npoplayer.streamTracker) {
41
- logEvent(npoplayer, 'seek', data);
42
- expect(npoplayer.streamTracker.seek).toHaveBeenCalledWith(data);
43
- expect(npoplayer.logEmitter.emit).toHaveBeenCalledWith('logEvent', 'seek');
40
+ if (npoPlayer.streamTracker) {
41
+ logEvent(npoPlayer, 'seek', data);
42
+ expect(npoPlayer.streamTracker.seek).toHaveBeenCalledWith(data);
43
+ expect(npoPlayer.logEmitter.emit).toHaveBeenCalledWith('logEvent', 'seek');
44
44
  }
45
45
  });
46
46
  });
@@ -16,8 +16,10 @@ export function startPlayerTracker(playerInstance, duration, version, source) {
16
16
  player_version: version,
17
17
  sko_player_version: '1.0.0'
18
18
  };
19
- const isLiveConfig = playerInstance.streamObject.stream.isLiveStream ? { isLive: true } : {};
20
- playerInstance.streamTracker = newStreamTracker(playerInstance.npoTag.pageTracker, streamTrackerConfig, isLiveConfig);
19
+ const isLiveStream = playerInstance.streamObject.stream.isLiveStream || false;
20
+ playerInstance.streamTracker = newStreamTracker(playerInstance.npoTag.pageTracker, streamTrackerConfig, {
21
+ isLive: isLiveStream
22
+ });
21
23
  bindPlayerEvents(playerInstance, playerInstance.player);
22
24
  }
23
25
  }
package/lib/lang/nl.json CHANGED
@@ -51,7 +51,7 @@
51
51
  "appleAirplay": "Apple AirPlay",
52
52
  "googleCast": "Google Cast",
53
53
  "vr": "VR",
54
- "off": "Geen",
54
+ "off": "Uit",
55
55
  "auto": "automatisch",
56
56
  "back": "Terug",
57
57
  "reset": "Herstellen",
@@ -66,6 +66,8 @@
66
66
  "watermarkLink": "Link to Homepage",
67
67
  "controlBar": "Video speler bedieningselementen",
68
68
  "player": "Video speler",
69
+ "videoPlayer": "Video speler",
70
+ "audioPlayer": "Audio speler",
69
71
  "seekBar": "Video tijdlijn",
70
72
  "seekBar.value": "Waarde",
71
73
  "seekBar.timeshift": "Timeshift",
@@ -32,9 +32,8 @@ export default class NpoPlayer {
32
32
  mockNpoPlayer: any;
33
33
  userPreferences: LocalStorageData;
34
34
  constructor(_container: HTMLElement, _playerConfig: PlayerConfig, _npotag?: InitialisationProps | undefined, _npotaginstance?: NPOTag | undefined, _variant?: NpoPlayerUIVariants);
35
- initPlayer(_container: HTMLElement, playerConfig: PlayerConfig, variant: NpoPlayerUIVariants): void;
35
+ initPlayer(_container: HTMLElement, playerConfig: PlayerConfig): void;
36
36
  loadStream(source: string, options?: StreamOptions): Promise<void>;
37
- createUIManager(player: PlayerAPI, playerContext: PlayerContext, variant: NpoPlayerUIVariants): Promise<void>;
38
37
  doError(input: any, status?: number): void;
39
38
  play(): Promise<void>;
40
39
  pause(): void;