@npo/player 1.25.0 → 1.26.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 (127) hide show
  1. package/README.md +1 -1
  2. package/lib/js/api/getstreamobject.d.ts +1 -1
  3. package/lib/js/api/getstreamobject.js +4 -4
  4. package/lib/js/api/getstreamobject.test.js +12 -12
  5. package/lib/js/playeractions/handlers/handleoffsets.js +9 -7
  6. package/lib/js/playeractions/handlers/handleoffsets.test.js +1 -1
  7. package/lib/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
  8. package/lib/js/playeractions/handlers/processplayerconfig.js +4 -4
  9. package/lib/js/playeractions/handlers/processsourceconfig.d.ts +1 -0
  10. package/lib/js/playeractions/handlers/processsourceconfig.js +4 -5
  11. package/lib/js/playeractions/handlers/processsourceconfig.test.js +25 -0
  12. package/lib/js/tracking/handlers/playertrackerstart.js +1 -1
  13. package/lib/lang/nl.json +1 -1
  14. package/lib/lang/subtitleLabels/nl.json +14 -0
  15. package/lib/npoplayer.d.ts +2 -3
  16. package/lib/npoplayer.js +24 -32
  17. package/lib/npoplayer.test.js +1 -1
  18. package/lib/package.json +2 -2
  19. package/lib/services/a11y/setup.js +2 -5
  20. package/lib/services/a11y/setup.test.js +2 -19
  21. package/lib/services/advertHandlers/discardAdBreak.js +4 -4
  22. package/lib/services/advertHandlers/discardAdBreak.test.js +25 -13
  23. package/lib/services/advertHandlers/handlePreRolls.js +19 -19
  24. package/lib/services/advertHandlers/handlePrerolls.test.js +4 -4
  25. package/lib/services/drmHandlers/decideprofile.js +1 -1
  26. package/lib/services/drmHandlers/decideprofile.test.js +1 -1
  27. package/lib/services/drmHandlers/verifydrm.js +6 -6
  28. package/lib/services/drmHandlers/verifydrm.test.js +5 -5
  29. package/lib/services/eventListenerHandlers/removeEventListeners.js +2 -2
  30. package/lib/services/eventListenerHandlers/removeEventListeners.test.js +9 -9
  31. package/lib/services/keyboardHandlers/resolvekeypress.js +5 -5
  32. package/lib/services/keyboardHandlers/resolvekeypress.test.js +1 -1
  33. package/lib/services/liveStreamHandlers/handleLiveStreamControls.js +2 -2
  34. package/lib/services/liveStreamHandlers/handleLiveStreamControls.test.js +2 -2
  35. package/lib/services/localStorageHandlers/localStorageHandlers.js +2 -2
  36. package/lib/services/localStorageHandlers/localStorageHandlers.test.js +2 -5
  37. package/lib/services/nicamHandlers/nicamhandler.d.ts +1 -2
  38. package/lib/services/nicamHandlers/nicamhandler.js +17 -16
  39. package/lib/services/nicamHandlers/nicamhandler.test.js +72 -9
  40. package/lib/services/npoPlayerAPI/npoPlayerAPI.d.ts +2 -2
  41. package/lib/services/npoPlayerAPI/npoPlayerAPI.js +16 -23
  42. package/lib/services/preferences/handlePreferences.d.ts +2 -0
  43. package/lib/services/preferences/handlePreferences.js +42 -0
  44. package/lib/services/preferences/handlePreferences.test.js +102 -0
  45. package/lib/services/segmentHandlers/addSegmentEventListeners.js +2 -2
  46. package/lib/services/segmentHandlers/addSegmentEventListeners.test.js +1 -1
  47. package/lib/services/services.d.ts +6 -2
  48. package/lib/services/services.js +21 -2
  49. package/lib/services/streamoptionsHandlers/{steamOptionsHandler.js → streamOptionsHandler.js} +11 -11
  50. package/lib/services/streamoptionsHandlers/streamOptionsHandler.test.js +20 -20
  51. package/lib/services/uiHandlers/uiVisiblityHandler.d.ts +3 -0
  52. package/lib/services/uiHandlers/uiVisiblityHandler.js +26 -0
  53. package/lib/services/uiHandlers/uiVisiblityHandler.test.d.ts +1 -0
  54. package/lib/services/uiHandlers/uiVisiblityHandler.test.js +62 -0
  55. package/lib/src/js/api/getstreamobject.d.ts +1 -1
  56. package/lib/src/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
  57. package/lib/src/js/playeractions/handlers/processsourceconfig.d.ts +1 -0
  58. package/lib/src/js/playeractions/handlers/processsourceconfig.test.d.ts +1 -0
  59. package/lib/src/npoplayer.d.ts +2 -3
  60. package/lib/src/services/nicamHandlers/nicamhandler.d.ts +1 -2
  61. package/lib/src/services/npoPlayerAPI/npoPlayerAPI.d.ts +2 -2
  62. package/lib/src/services/preferences/handlePreferences.d.ts +2 -0
  63. package/lib/src/services/preferences/handlePreferences.test.d.ts +1 -0
  64. package/lib/src/services/services.d.ts +6 -2
  65. package/lib/src/services/uiHandlers/uiVisiblityHandler.d.ts +3 -0
  66. package/lib/src/services/uiHandlers/uiVisiblityHandler.test.d.ts +1 -0
  67. package/lib/src/types/classes.d.ts +6 -0
  68. package/lib/src/types/interfaces.d.ts +24 -3
  69. package/lib/src/ui/components/adbutton.d.ts +1 -1
  70. package/lib/src/ui/components/adlabel.d.ts +1 -1
  71. package/lib/src/ui/components/buttons.d.ts +6 -16
  72. package/lib/src/ui/components/controlbar.d.ts +2 -2
  73. package/lib/src/ui/components/ctabar.d.ts +1 -1
  74. package/lib/src/ui/components/playnext.d.ts +1 -4
  75. package/lib/src/ui/components/seekbar.d.ts +1 -1
  76. package/lib/src/ui/components/titlebar.d.ts +1 -1
  77. package/lib/src/ui/handlers/playnextscreen.test.d.ts +1 -0
  78. package/lib/src/ui/uicontainer.test.d.ts +1 -0
  79. package/lib/tests/mocks/mockLogEmitter.d.ts +2 -0
  80. package/lib/tests/mocks/mockLogEmitter.js +20 -0
  81. package/lib/tests/mocks/mockNpoplayer.js +1 -2
  82. package/lib/tests/mocks/playerContextMock.d.ts +5 -3
  83. package/lib/tests/mocks/playerContextMock.js +7 -5
  84. package/lib/types/classes.d.ts +6 -0
  85. package/lib/types/classes.js +12 -0
  86. package/lib/types/interfaces.d.ts +24 -3
  87. package/lib/types/interfaces.js +1 -0
  88. package/lib/ui/components/adbutton.d.ts +1 -1
  89. package/lib/ui/components/adbutton.js +3 -3
  90. package/lib/ui/components/adlabel.d.ts +1 -1
  91. package/lib/ui/components/adlabel.js +3 -3
  92. package/lib/ui/components/buttons.d.ts +6 -16
  93. package/lib/ui/components/buttons.js +27 -10
  94. package/lib/ui/components/controlbar.d.ts +2 -2
  95. package/lib/ui/components/controlbar.js +20 -37
  96. package/lib/ui/components/ctabar.d.ts +1 -1
  97. package/lib/ui/components/ctabar.js +4 -4
  98. package/lib/ui/components/nativemobile/topbar.js +2 -2
  99. package/lib/ui/components/playnext.d.ts +1 -4
  100. package/lib/ui/components/playnext.js +3 -3
  101. package/lib/ui/components/seekbar.d.ts +1 -1
  102. package/lib/ui/components/seekbar.js +5 -3
  103. package/lib/ui/components/settingspanel.js +9 -9
  104. package/lib/ui/components/titlebar.d.ts +1 -1
  105. package/lib/ui/components/titlebar.js +2 -2
  106. package/lib/ui/components/topbar.js +6 -20
  107. package/lib/ui/components/verticalvideo/controlbar.js +1 -1
  108. package/lib/ui/handlers/playnextscreen.test.d.ts +1 -0
  109. package/lib/ui/nativemobileuifactory.js +1 -1
  110. package/lib/ui/nativemobileuifactory.test.js +2 -1
  111. package/lib/ui/uicontainer.js +11 -30
  112. package/lib/ui/uicontainer.test.d.ts +1 -0
  113. package/lib/ui/uicontainer.test.js +80 -0
  114. package/package.json +2 -2
  115. package/src/style/components/_advert.scss +0 -9
  116. package/src/style/components/_nicam.scss +5 -4
  117. package/src/style/components/_settingspanel.scss +48 -17
  118. package/src/style/components/vertical-video/_settingspanel.scss +1 -1
  119. package/src/style/npoplayer.css +25 -20
  120. package/src/style/variants/_player-base.scss +4 -0
  121. package/src/style/variants/_player-large.scss +5 -1
  122. package/src/style/variants/_player-small.scss +11 -8
  123. /package/lib/{src/ui/handlers/playnextstreen.test.d.ts → js/playeractions/handlers/processsourceconfig.test.d.ts} +0 -0
  124. /package/lib/{ui/handlers/playnextstreen.test.d.ts → services/preferences/handlePreferences.test.d.ts} +0 -0
  125. /package/lib/services/streamoptionsHandlers/{steamOptionsHandler.d.ts → streamOptionsHandler.d.ts} +0 -0
  126. /package/lib/src/services/streamoptionsHandlers/{steamOptionsHandler.d.ts → streamOptionsHandler.d.ts} +0 -0
  127. /package/lib/ui/handlers/{playnextstreen.test.js → playnextscreen.test.js} +0 -0
@@ -3,12 +3,12 @@ import { NpoPlayerUIVariants } from '../../types/interfaces';
3
3
  import { NpoPlayerEvent } from '../../types/events';
4
4
  export async function handlePreRolls(playerContext) {
5
5
  return new Promise((resolve) => {
6
- if (playerContext.npoplayer.streamObject.metadata.hasPreroll == 'false' ||
7
- playerContext.npoplayer.streamObject.assets.preroll == undefined) {
6
+ if (playerContext.npoPlayer.streamObject.metadata.hasPreroll == 'false' ||
7
+ playerContext.npoPlayer.streamObject.assets.preroll == undefined) {
8
8
  resolve();
9
9
  return;
10
10
  }
11
- const prerollUrl = playerContext.npoplayer.streamObject.assets.preroll;
11
+ const prerollUrl = playerContext.npoPlayer.streamObject.assets.preroll;
12
12
  let adIndex = 0;
13
13
  let totalAds = 0;
14
14
  let currentClickListener;
@@ -35,13 +35,13 @@ export async function handlePreRolls(playerContext) {
35
35
  const activeAdBreak = playerContext.player.getActiveAdBreak();
36
36
  if (!activeAdBreak || !activeAdBreak.ads)
37
37
  return false;
38
- playerContext.npoplayer.uiManager?.release();
39
- playerContext.npoplayer.uiManager = undefined;
40
- if (playerContext.npoplayer.playerContext) {
41
- playerContext.player.createUIManager(playerContext, NpoPlayerUIVariants.AD);
38
+ playerContext.npoPlayer.uiManager?.release();
39
+ playerContext.npoPlayer.uiManager = undefined;
40
+ if (playerContext.npoPlayer.playerContext) {
41
+ void playerContext.player.createUIManager(playerContext, NpoPlayerUIVariants.AD);
42
42
  }
43
43
  adUiSet = true;
44
- const adButton = playerContext.npoplayer.uiComponents.adbutton;
44
+ const adButton = playerContext.npoPlayer.uiComponents.adbutton;
45
45
  const currentAd = activeAdBreak.ads[0];
46
46
  adIndex = 1;
47
47
  totalAds = activeAdBreak.ads.length;
@@ -49,7 +49,7 @@ export async function handlePreRolls(playerContext) {
49
49
  adButton.show();
50
50
  adClickHandler(currentAd, adButton);
51
51
  }
52
- playerContext.npoplayer.uiComponents.adlabel?.setText(`Advertentie 1 van ${activeAdBreak.ads.length}`);
52
+ playerContext.npoPlayer.uiComponents.adlabel?.setText(`Advertentie 1 van ${activeAdBreak.ads.length}`);
53
53
  return true;
54
54
  }
55
55
  function attemptSetAdUi(attemptsLeft = 10) {
@@ -71,7 +71,7 @@ export async function handlePreRolls(playerContext) {
71
71
  }
72
72
  if (!adUiSet)
73
73
  attemptSetAdUi();
74
- playerContext.npoplayer.adBreakActive = true;
74
+ playerContext.npoPlayer.adBreakActive = true;
75
75
  }
76
76
  playerContext.player.on(NpoPlayerEvent.AdStarted, handleAdStarted);
77
77
  function adClickHandler(ad, button) {
@@ -102,26 +102,26 @@ export async function handlePreRolls(playerContext) {
102
102
  handleAdBreakFinished();
103
103
  return;
104
104
  }
105
- const adButton = playerContext.npoplayer.uiComponents.adbutton;
105
+ const adButton = playerContext.npoPlayer.uiComponents.adbutton;
106
106
  const nextAd = activeAdBreak.ads[adIndex];
107
107
  adIndex += 1;
108
108
  if (adButton) {
109
109
  adButton.show();
110
110
  adClickHandler(nextAd, adButton);
111
111
  }
112
- playerContext.npoplayer.uiComponents.adlabel?.setText(`Advertentie ${adIndex} van ${activeAdBreak.ads.length}`);
112
+ playerContext.npoPlayer.uiComponents.adlabel?.setText(`Advertentie ${adIndex} van ${activeAdBreak.ads.length}`);
113
113
  }
114
114
  playerContext.player.on(NpoPlayerEvent.AdFinished, handleAdFinished);
115
115
  function handleAdBreakFinished() {
116
116
  playerContext.player.off(NpoPlayerEvent.AdBreakFinished, handleAdBreakFinished);
117
117
  playerContext.player.off(NpoPlayerEvent.AdError, handleAdBreakFinished);
118
- playerContext.npoplayer.adBreakActive = false;
119
- playerContext.npoplayer.uiComponents.adbutton?.hide();
120
- playerContext.npoplayer.uiComponents.adlabel?.hide();
121
- playerContext.npoplayer.uiManager?.release();
122
- playerContext.npoplayer.uiManager = undefined;
123
- if (playerContext.npoplayer.playerContext) {
124
- playerContext.player.createUIManager(playerContext, NpoPlayerUIVariants.DEFAULT);
118
+ playerContext.npoPlayer.adBreakActive = false;
119
+ playerContext.npoPlayer.uiComponents.adbutton?.hide();
120
+ playerContext.npoPlayer.uiComponents.adlabel?.hide();
121
+ playerContext.npoPlayer.uiManager?.release();
122
+ playerContext.npoPlayer.uiManager = undefined;
123
+ if (playerContext.npoPlayer.playerContext) {
124
+ void playerContext.player.createUIManager(playerContext, NpoPlayerUIVariants.DEFAULT);
125
125
  }
126
126
  adUiSet = false;
127
127
  resolve();
@@ -15,7 +15,7 @@ describe('handlePreRolls', () => {
15
15
  };
16
16
  });
17
17
  it('should not schedule ads when hasPreroll is false', async () => {
18
- const npoplayerMock = createMockNpoPlayer({
18
+ const npoPlayerMock = createMockNpoPlayer({
19
19
  streamObject: {
20
20
  metadata: {
21
21
  hasPreroll: 'false'
@@ -26,13 +26,13 @@ describe('handlePreRolls', () => {
26
26
  }
27
27
  });
28
28
  const playerContextMock = createPlayerContextMock({
29
- npoplayer: npoplayerMock
29
+ npoPlayer: npoPlayerMock
30
30
  });
31
31
  await handlePreRolls(playerContextMock);
32
32
  expect(mockPlayerAPI.ads.schedule).not.toHaveBeenCalled();
33
33
  });
34
34
  it('should not schedule ads if preroll URL is missing', async () => {
35
- const npoplayerMock = createMockNpoPlayer({
35
+ const npoPlayerMock = createMockNpoPlayer({
36
36
  streamObject: {
37
37
  metadata: {
38
38
  hasPreroll: 'true'
@@ -41,7 +41,7 @@ describe('handlePreRolls', () => {
41
41
  }
42
42
  });
43
43
  const playerContextMock = createPlayerContextMock({
44
- npoplayer: npoplayerMock
44
+ npoPlayer: npoPlayerMock
45
45
  });
46
46
  await handlePreRolls(playerContextMock);
47
47
  expect(mockPlayerAPI.ads.schedule).not.toHaveBeenCalled();
@@ -5,7 +5,7 @@ export async function decideProfile(playerContext, preferredDRM = '') {
5
5
  console.error('No player detected');
6
6
  return { profileName: '', drm: '' };
7
7
  }
8
- const player = playerContext.player;
8
+ const { player } = playerContext;
9
9
  const supportedTech = player.getSupportedTech();
10
10
  const supportedDRM = await player.getSupportedDRM();
11
11
  const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
@@ -13,7 +13,7 @@ describe('decideProfile', () => {
13
13
  .fn()
14
14
  .mockResolvedValue(['com.widevine.alpha', 'com.microsoft.playready', 'com.apple.fps.1_0'])
15
15
  };
16
- mockPlayerContext = { player: mockPlayer, npoplayer: mockNpoplayer };
16
+ mockPlayerContext = { player: mockPlayer, npoPlayer: mockNpoplayer };
17
17
  });
18
18
  afterEach(() => {
19
19
  jest.clearAllMocks();
@@ -2,7 +2,7 @@ import { convertJwtToBase64, convertBase64ToObject } from '../../js/utilities/ut
2
2
  import { getStreamObject } from '../../js/api/getstreamobject';
3
3
  export async function verifyDRM(playerContext, payload) {
4
4
  try {
5
- const { player, npoplayer: { streamObject, sourceConfig } } = playerContext;
5
+ const { player, npoPlayer: { streamObject, sourceConfig } } = playerContext;
6
6
  const { stream } = streamObject;
7
7
  if (stream.drmToken) {
8
8
  const drmJsonTimestamp = getDRMTokenTimestamp(stream.drmToken);
@@ -29,12 +29,12 @@ function getDRMTokenTimestamp(drmToken) {
29
29
  return convertBase64ToObject(drmBase64).iat;
30
30
  }
31
31
  async function refreshDRMToken(playerContext, payload) {
32
- const backupStreamObject = await getStreamObject(playerContext.npoplayer, payload);
32
+ const backupStreamObject = await getStreamObject(playerContext.npoPlayer, payload);
33
33
  const newDrmToken = backupStreamObject.stream.drmToken;
34
34
  const clonedStreamObject = {
35
- ...playerContext.npoplayer.streamObject,
36
- stream: { ...playerContext.npoplayer.streamObject.stream, drmToken: newDrmToken }
35
+ ...playerContext.npoPlayer.streamObject,
36
+ stream: { ...playerContext.npoPlayer.streamObject.stream, drmToken: newDrmToken }
37
37
  };
38
- playerContext.npoplayer.streamObject = clonedStreamObject;
39
- await loadPlayer(playerContext, playerContext.npoplayer.sourceConfig);
38
+ playerContext.npoPlayer.streamObject = clonedStreamObject;
39
+ await loadPlayer(playerContext, playerContext.npoPlayer.sourceConfig);
40
40
  }
@@ -18,7 +18,7 @@ beforeEach(() => {
18
18
  streamObject: { stream: { drmToken: undefined } },
19
19
  load: jest.fn()
20
20
  };
21
- mockPlayerContext = { player: mockPlayer, npoplayer: mockNpoplayer };
21
+ mockPlayerContext = { player: mockPlayer, npoPlayer: mockNpoplayer };
22
22
  });
23
23
  afterEach(() => {
24
24
  jest.clearAllMocks();
@@ -42,7 +42,7 @@ describe('Test DRM verification', () => {
42
42
  streamURL: '',
43
43
  drmToken: drmToken
44
44
  };
45
- mockPlayerContext.npoplayer.sourceConfig = sourceConfig;
45
+ mockPlayerContext.npoPlayer.sourceConfig = sourceConfig;
46
46
  jest.spyOn(global.Date, 'now').mockImplementation(() => currentTime * 1000);
47
47
  convertJwtToBase64.mockReturnValue(JSON.stringify({ iat: drmJsonTimestamp }));
48
48
  convertBase64ToObject.mockReturnValue({ iat: drmJsonTimestamp });
@@ -62,14 +62,14 @@ describe('Test DRM verification', () => {
62
62
  streamURL: '',
63
63
  drmToken: drmToken
64
64
  };
65
- mockPlayerContext.npoplayer.sourceConfig = sourceConfig;
65
+ mockPlayerContext.npoPlayer.sourceConfig = sourceConfig;
66
66
  jest.spyOn(global.Date, 'now').mockImplementation(() => currentTime * 1000);
67
67
  convertJwtToBase64.mockReturnValue(JSON.stringify({ iat: drmJsonTimestamp }));
68
68
  convertBase64ToObject.mockReturnValue({ iat: drmJsonTimestamp });
69
69
  getStreamObject.mockResolvedValue({ stream: { drmToken: 'newToken' } });
70
70
  jest.spyOn(mockPlayerContext.player, 'load').mockResolvedValue(undefined);
71
71
  await verifyDRM(mockPlayerContext, payload);
72
- expect(getStreamObject).toHaveBeenCalledWith(mockPlayerContext.npoplayer, payload);
72
+ expect(getStreamObject).toHaveBeenCalledWith(mockPlayerContext.npoPlayer, payload);
73
73
  expect(mockPlayerContext.player.load).toHaveBeenCalledWith(sourceConfig);
74
74
  });
75
75
  it('should call loadPlayer when the drmToken is null', async () => {
@@ -82,7 +82,7 @@ describe('Test DRM verification', () => {
82
82
  streamURL: '',
83
83
  drmToken: undefined
84
84
  };
85
- mockPlayerContext.npoplayer.sourceConfig = sourceConfig;
85
+ mockPlayerContext.npoPlayer.sourceConfig = sourceConfig;
86
86
  await verifyDRM(mockPlayerContext, payload);
87
87
  expect(mockPlayerContext.player.load).toHaveBeenCalledWith(sourceConfig);
88
88
  });
@@ -1,6 +1,6 @@
1
1
  import { NpoPlayerEvent } from '../../types/events';
2
2
  export const removeEventListeners = (playerContext) => {
3
- const { eventListeners } = playerContext.npoplayer;
3
+ const { eventListeners } = playerContext.npoPlayer;
4
4
  if (eventListeners) {
5
5
  const { segmentHandleTimeChangedCallback, segmentSeekFunctionCallback, liveStreamHandleTimeChangedCallback } = eventListeners;
6
6
  const eventMapping = [
@@ -13,6 +13,6 @@ export const removeEventListeners = (playerContext) => {
13
13
  playerContext.player.off(event, callback);
14
14
  }
15
15
  }
16
- playerContext.npoplayer.eventListeners = undefined;
16
+ playerContext.npoPlayer.eventListeners = undefined;
17
17
  }
18
18
  };
@@ -8,35 +8,35 @@ describe('removeEventListeners', () => {
8
8
  mockPlayerContext = createPlayerContextMock();
9
9
  });
10
10
  it('should remove TimeChanged event listener if exists', () => {
11
- mockPlayerContext.npoplayer.eventListeners = {
11
+ mockPlayerContext.npoPlayer.eventListeners = {
12
12
  segmentHandleTimeChangedCallback: jest.fn(),
13
13
  liveStreamHandleTimeChangedCallback: jest.fn(),
14
14
  segmentSeekFunctionCallback: jest.fn()
15
15
  };
16
16
  removeEventListeners(mockPlayerContext);
17
- if (mockPlayerContext.npoplayer.eventListeners) {
18
- expect(mockPlayerContext.player.off).toHaveBeenCalledWith(NpoPlayerEvent.TimeChanged, mockPlayerContext.npoplayer.eventListeners.segmentHandleTimeChangedCallback);
19
- expect(mockPlayerContext.player.off).toHaveBeenCalledWith(NpoPlayerEvent.TimeChanged, mockPlayerContext.npoplayer.eventListeners.liveStreamHandleTimeChangedCallback);
17
+ if (mockPlayerContext.npoPlayer.eventListeners) {
18
+ expect(mockPlayerContext.player.off).toHaveBeenCalledWith(NpoPlayerEvent.TimeChanged, mockPlayerContext.npoPlayer.eventListeners.segmentHandleTimeChangedCallback);
19
+ expect(mockPlayerContext.player.off).toHaveBeenCalledWith(NpoPlayerEvent.TimeChanged, mockPlayerContext.npoPlayer.eventListeners.liveStreamHandleTimeChangedCallback);
20
20
  }
21
21
  });
22
22
  it('should remove Seek event listener if exists', () => {
23
- mockPlayerContext.npoplayer.eventListeners = {
23
+ mockPlayerContext.npoPlayer.eventListeners = {
24
24
  segmentHandleTimeChangedCallback: jest.fn(),
25
25
  liveStreamHandleTimeChangedCallback: jest.fn(),
26
26
  segmentSeekFunctionCallback: jest.fn()
27
27
  };
28
28
  removeEventListeners(mockPlayerContext);
29
- if (mockPlayerContext.npoplayer.eventListeners) {
30
- expect(mockPlayerContext.player.off).toHaveBeenCalledWith(NpoPlayerEvent.Seek, mockPlayerContext.npoplayer.eventListeners.segmentSeekFunctionCallback);
29
+ if (mockPlayerContext.npoPlayer.eventListeners) {
30
+ expect(mockPlayerContext.player.off).toHaveBeenCalledWith(NpoPlayerEvent.Seek, mockPlayerContext.npoPlayer.eventListeners.segmentSeekFunctionCallback);
31
31
  }
32
32
  });
33
33
  it('should reset EventListeners in playerContext', () => {
34
- mockPlayerContext.npoplayer.eventListeners = {
34
+ mockPlayerContext.npoPlayer.eventListeners = {
35
35
  segmentHandleTimeChangedCallback: jest.fn(),
36
36
  liveStreamHandleTimeChangedCallback: jest.fn(),
37
37
  segmentSeekFunctionCallback: jest.fn()
38
38
  };
39
39
  removeEventListeners(mockPlayerContext);
40
- expect(mockPlayerContext.npoplayer.eventListeners).toBeUndefined();
40
+ expect(mockPlayerContext.npoPlayer.eventListeners).toBeUndefined();
41
41
  });
42
42
  });
@@ -23,17 +23,17 @@ export function resolveKeyPress(playerContext, e) {
23
23
  ArrowUp: () => {
24
24
  if (isMuted)
25
25
  playerContext.player.unmute();
26
- playerContext.npoplayer.increaseVolume();
26
+ playerContext.npoPlayer.increaseVolume();
27
27
  },
28
28
  ArrowDown: () => {
29
29
  if (isMuted)
30
30
  playerContext.player.unmute();
31
- playerContext.npoplayer.decreaseVolume();
31
+ playerContext.npoPlayer.decreaseVolume();
32
32
  },
33
- ArrowLeft: () => playerContext.npoplayer.goBackwards(10),
34
- ArrowRight: () => playerContext.npoplayer.goForward(10),
33
+ ArrowLeft: () => playerContext.npoPlayer.goBackwards(10),
34
+ ArrowRight: () => playerContext.npoPlayer.goForward(10),
35
35
  Escape: () => {
36
- const { settingsPanels } = playerContext.npoplayer.uiComponents;
36
+ const { settingsPanels } = playerContext.npoPlayer.uiComponents;
37
37
  if (settingsPanels && settingsPanels.length > 0) {
38
38
  for (const panel of settingsPanels) {
39
39
  if (panel.isShown()) {
@@ -32,7 +32,7 @@ describe('resolveKeyPress', () => {
32
32
  })
33
33
  };
34
34
  e = new KeyboardEvent('keydown');
35
- mockPlayerContext = { player: mockPlayer, npoplayer: mockNpoplayer };
35
+ mockPlayerContext = { player: mockPlayer, npoPlayer: mockNpoplayer };
36
36
  });
37
37
  it('should mute/unmute the player when "KeyM" is pressed', () => {
38
38
  mockPlayer.isMuted.mockReturnValue(true);
@@ -1,9 +1,9 @@
1
1
  import { NpoPlayerEvent } from '../../types/events';
2
2
  export const handleLiveStreamControls = (playerContext) => {
3
3
  const liveStreamHandleTimeChangedCallback = () => updateForwardButtonState(playerContext.player);
4
- const { player, npoplayer } = playerContext;
4
+ const { player, npoPlayer } = playerContext;
5
5
  player.on(NpoPlayerEvent.TimeChanged, liveStreamHandleTimeChangedCallback);
6
- npoplayer.eventListeners = {
6
+ npoPlayer.eventListeners = {
7
7
  liveStreamHandleTimeChangedCallback
8
8
  };
9
9
  };
@@ -11,8 +11,8 @@ describe('handleLiveStreamControls', () => {
11
11
  });
12
12
  it('should add TimeChanged event listener and store it in eventListeners', () => {
13
13
  handleLiveStreamControls(mockPlayerContext);
14
- expect(mockPlayerContext.player.on).toHaveBeenCalledWith(NpoPlayerEvent.TimeChanged, mockPlayerContext.npoplayer.eventListeners?.liveStreamHandleTimeChangedCallback);
15
- expect(mockPlayerContext.npoplayer.eventListeners?.liveStreamHandleTimeChangedCallback).toBeDefined();
14
+ expect(mockPlayerContext.player.on).toHaveBeenCalledWith(NpoPlayerEvent.TimeChanged, mockPlayerContext.npoPlayer.eventListeners?.liveStreamHandleTimeChangedCallback);
15
+ expect(mockPlayerContext.npoPlayer.eventListeners?.liveStreamHandleTimeChangedCallback).toBeDefined();
16
16
  });
17
17
  });
18
18
  describe('updateForwardButtonState', () => {
@@ -18,7 +18,7 @@ export function getLocalStorage() {
18
18
  }
19
19
  export function setValuesBasedOnLocalStorage(playerContext) {
20
20
  const localStorageData = getLocalStorage();
21
- const player = playerContext.player;
21
+ const { player } = playerContext;
22
22
  if (!player) {
23
23
  console.error('Player is undefined in playerContext');
24
24
  return;
@@ -28,6 +28,6 @@ export function setValuesBasedOnLocalStorage(playerContext) {
28
28
  player.mute();
29
29
  }
30
30
  if (localStorageData.subtitles_enabled === 'true') {
31
- playerContext.npoplayer.streamOptions.enableSubtitles = true;
31
+ playerContext.npoPlayer.streamOptions.enableSubtitles = true;
32
32
  }
33
33
  }
@@ -54,14 +54,11 @@ describe('localStorageHandler', () => {
54
54
  };
55
55
  playerContext = {
56
56
  player: mockPlayerAPI,
57
- npoplayer: {
57
+ npoPlayer: {
58
58
  ...mockNpoPlayer,
59
59
  streamOptions: {
60
60
  enableSubtitles: false
61
61
  },
62
- userPreferences: {
63
- subtitles_enabled: 'false'
64
- },
65
62
  container: document.createElement('div'),
66
63
  streamObject: {},
67
64
  playerConfig: {},
@@ -102,7 +99,7 @@ describe('localStorageHandler', () => {
102
99
  it('should enable subtitles if localStorage subtitles_enabled is true', () => {
103
100
  localStorage.setItem('npoplayer-subtitles_enabled', JSON.stringify('true'));
104
101
  setValuesBasedOnLocalStorage(playerContext);
105
- expect(playerContext.npoplayer.streamOptions.enableSubtitles).toBe(true);
102
+ expect(playerContext.npoPlayer.streamOptions.enableSubtitles).toBe(true);
106
103
  });
107
104
  });
108
105
  });
@@ -1,6 +1,5 @@
1
- import { UIManager } from 'bitmovin-player-ui';
2
1
  import { PlayerContext } from '../../types/interfaces';
3
2
  export declare function processNicam(playerContext: PlayerContext, nicamElement: HTMLElement | undefined): void;
4
3
  export declare function addNicamIcon(character: string, nicamElement: Element): void;
5
- export declare function showNicamAfterUiDelay(playerContext: PlayerContext, uiManager: UIManager | undefined): void;
4
+ export declare function showNicamAfterUiDelay(playerContext: PlayerContext): void;
6
5
  export declare function setupNicamKijkwijzerIcons(playerContext: PlayerContext): void;
@@ -1,7 +1,7 @@
1
1
  import { NpoPlayerEvent } from '../../types/events';
2
2
  export function processNicam(playerContext, nicamElement) {
3
- const streamOptions = playerContext.npoplayer.streamOptions;
4
- const metadata = playerContext?.npoplayer?.streamObject?.metadata ?? {};
3
+ const streamOptions = playerContext.npoPlayer.streamOptions;
4
+ const metadata = playerContext?.npoPlayer?.streamObject?.metadata ?? {};
5
5
  const effectiveMetadata = { ...metadata, ...streamOptions };
6
6
  if (nicamElement) {
7
7
  nicamElement.innerHTML = '';
@@ -45,27 +45,28 @@ export function addNicamIcon(character, nicamElement) {
45
45
  span.classList.add('nicam-icon', iconClass);
46
46
  nicamElement.appendChild(span);
47
47
  }
48
- export function showNicamAfterUiDelay(playerContext, uiManager) {
49
- const player = playerContext.player;
50
- player.off(NpoPlayerEvent.Play, () => {
51
- showNicamAfterUiDelay(playerContext, uiManager);
48
+ export function showNicamAfterUiDelay(playerContext) {
49
+ const { player, npoPlayer } = playerContext;
50
+ const { uiManager } = npoPlayer;
51
+ const showNicamClassName = 'bmpui-show-nicam';
52
+ const playerContainer = player.getNpoPlayerElement();
53
+ player.off(NpoPlayerEvent.Ready, () => {
54
+ npoPlayer.npoPlayerServices.showNicamAfterUiDelay(playerContext);
52
55
  });
53
- if (uiManager === null)
56
+ if (!playerContainer || !uiManager)
54
57
  return;
55
- const playerContainer = player.getContainer().querySelector('.bmpui-npo-player.bmpui-layout-max-width-400') ||
56
- player.getContainer().querySelector('.bmpui-npo-player.bmpui-layout-max-width-600');
57
- if (!playerContainer)
58
- return;
59
- uiManager?.activeUi.onControlsHide.subscribeOnce(() => {
60
- const className = 'bmpui-show-nicam';
61
- playerContainer.classList.add(className);
58
+ uiManager.activeUi.onControlsHide.subscribe(() => {
59
+ playerContainer.classList.add(showNicamClassName);
62
60
  setTimeout(() => {
63
- playerContainer.classList.remove(className);
61
+ playerContainer.classList.remove(showNicamClassName);
64
62
  }, 3000);
65
63
  });
64
+ uiManager?.activeUi.onControlsShow.subscribe(() => {
65
+ playerContainer.classList.remove(showNicamClassName);
66
+ });
66
67
  }
67
68
  export function setupNicamKijkwijzerIcons(playerContext) {
68
- const { container } = playerContext.npoplayer;
69
+ const { container } = playerContext.npoPlayer;
69
70
  const nicamElement = container.querySelector('.bmpui-nicam');
70
71
  processNicam(playerContext, nicamElement);
71
72
  }
@@ -1,6 +1,7 @@
1
- import { processNicam } from './nicamhandler';
1
+ import { processNicam, showNicamAfterUiDelay } from './nicamhandler';
2
2
  import '@testing-library/jest-dom';
3
3
  import { createMockNpoPlayer, createPlayerContextMock } from '../../../tests/mocks/playerContextMock';
4
+ import { NpoPlayerEvent } from '../../types/events';
4
5
  describe('NICAM Processing', () => {
5
6
  let mockElement;
6
7
  beforeEach(() => {
@@ -9,7 +10,7 @@ describe('NICAM Processing', () => {
9
10
  });
10
11
  it('processes NICAM from the streamObject', () => {
11
12
  const mockElement = document.createElement('div');
12
- const npoplayerMock = createMockNpoPlayer({
13
+ const npoPlayerMock = createMockNpoPlayer({
13
14
  streamObject: {
14
15
  metadata: {
15
16
  ageRating: '12',
@@ -18,14 +19,14 @@ describe('NICAM Processing', () => {
18
19
  }
19
20
  });
20
21
  const playerContextMock = createPlayerContextMock({
21
- npoplayer: npoplayerMock
22
+ npoPlayer: npoPlayerMock
22
23
  });
23
24
  processNicam(playerContextMock, mockElement);
24
25
  expect(mockElement.children).toHaveLength(5);
25
26
  });
26
27
  it('processes NICAM and age rating with streamOptions taking priority', () => {
27
28
  const mockElement = document.createElement('div');
28
- const npoplayerMock = createMockNpoPlayer({
29
+ const npoPlayerMock = createMockNpoPlayer({
29
30
  streamObject: {
30
31
  metadata: {
31
32
  ageRating: '12',
@@ -38,14 +39,14 @@ describe('NICAM Processing', () => {
38
39
  }
39
40
  });
40
41
  const playerContextMock = createPlayerContextMock({
41
- npoplayer: npoplayerMock
42
+ npoPlayer: npoPlayerMock
42
43
  });
43
44
  processNicam(playerContextMock, mockElement);
44
45
  expect(mockElement.children).toHaveLength(2);
45
46
  });
46
47
  it('does nothing if no NICAM element found', () => {
47
48
  document.querySelector = jest.fn().mockReturnValue(undefined);
48
- const npoplayerMock = createMockNpoPlayer({
49
+ const npoPlayerMock = createMockNpoPlayer({
49
50
  streamObject: {
50
51
  metadata: {
51
52
  ageRating: '12',
@@ -54,16 +55,78 @@ describe('NICAM Processing', () => {
54
55
  }
55
56
  });
56
57
  const playerContextMock = createPlayerContextMock({
57
- npoplayer: npoplayerMock
58
+ npoPlayer: npoPlayerMock
58
59
  });
59
60
  processNicam(playerContextMock, mockElement);
60
61
  });
61
62
  it('does nothing if no metadata and no streamOptions', () => {
62
- const npoplayerMock = createMockNpoPlayer({});
63
+ const npoPlayerMock = createMockNpoPlayer({});
63
64
  const playerContextMock = createPlayerContextMock({
64
- npoplayer: npoplayerMock
65
+ npoPlayer: npoPlayerMock
65
66
  });
66
67
  processNicam(playerContextMock, mockElement);
67
68
  expect(mockElement.appendChild).not.toHaveBeenCalled();
68
69
  });
69
70
  });
71
+ describe('NICAM Visibility Management', () => {
72
+ let mockPlayerContext;
73
+ let mockContainer;
74
+ let mockPlayer;
75
+ let mockUiManager;
76
+ beforeEach(() => {
77
+ mockContainer = document.createElement('div');
78
+ mockPlayer = {
79
+ getNpoPlayerElement: jest.fn().mockReturnValue(mockContainer),
80
+ off: jest.fn()
81
+ };
82
+ mockUiManager = {
83
+ activeUi: {
84
+ onControlsHide: {
85
+ subscribe: jest.fn(),
86
+ unsubscribe: jest.fn()
87
+ },
88
+ onControlsShow: {
89
+ subscribe: jest.fn(),
90
+ unsubscribe: jest.fn()
91
+ }
92
+ }
93
+ };
94
+ mockPlayerContext = createPlayerContextMock({
95
+ player: mockPlayer,
96
+ npoPlayer: {
97
+ uiManager: mockUiManager,
98
+ container: mockContainer
99
+ }
100
+ });
101
+ });
102
+ describe('showNicamAfterUiDelay', () => {
103
+ it('should add showNicam class when controls are hidden', () => {
104
+ jest.useFakeTimers();
105
+ const showNicamClass = 'bmpui-show-nicam';
106
+ showNicamAfterUiDelay(mockPlayerContext);
107
+ mockUiManager.activeUi.onControlsHide.subscribe.mock.calls[0][0]();
108
+ expect(mockContainer).toHaveClass(showNicamClass);
109
+ jest.advanceTimersByTime(3000);
110
+ expect(mockContainer).not.toHaveClass(showNicamClass);
111
+ jest.useRealTimers();
112
+ });
113
+ it('should remove showNicam class when controls are shown', () => {
114
+ showNicamAfterUiDelay(mockPlayerContext);
115
+ const showNicamClass = 'bmpui-show-nicam';
116
+ mockUiManager.activeUi.onControlsHide.subscribe.mock.calls[0][0]();
117
+ expect(mockContainer).toHaveClass(showNicamClass);
118
+ mockUiManager.activeUi.onControlsShow.subscribe.mock.calls[0][0]();
119
+ expect(mockContainer).not.toHaveClass(showNicamClass);
120
+ });
121
+ it('should not execute if player container or uiManager is undefined', () => {
122
+ mockPlayerContext.npoPlayer.uiManager = undefined;
123
+ showNicamAfterUiDelay(mockPlayerContext);
124
+ expect(mockUiManager.activeUi.onControlsHide.subscribe).not.toHaveBeenCalled();
125
+ expect(mockUiManager.activeUi.onControlsShow.subscribe).not.toHaveBeenCalled();
126
+ });
127
+ it('should clean up event listeners when the player is ready', () => {
128
+ showNicamAfterUiDelay(mockPlayerContext);
129
+ expect(mockPlayer.off).toHaveBeenCalledWith(NpoPlayerEvent.Ready, expect.any(Function));
130
+ });
131
+ });
132
+ });
@@ -17,7 +17,8 @@ export declare class NpoPlayerAPI {
17
17
  setViewMode(viewMode: ViewMode): void;
18
18
  getViewMode(): ViewMode;
19
19
  areSubtitlesEnabled(): boolean;
20
- enableSubtitles(): void;
20
+ getCurrentSubtitle(): string | undefined;
21
+ enableSubtitles(selectedLang?: string): void;
21
22
  isPaused(): boolean;
22
23
  isMuted(): boolean;
23
24
  isLive(): boolean;
@@ -38,7 +39,6 @@ export declare class NpoPlayerAPI {
38
39
  getTimeShift(): number;
39
40
  scheduleAds(adConfig: AdConfig): Promise<AdBreak[]>;
40
41
  getActiveAdBreak(): AdBreak | null;
41
- discardAdBreak(adBreakId: string): void;
42
42
  getConfig(mergedConfig?: boolean): PlayerConfig;
43
43
  createUIManager(playerContext: PlayerContext, variant: NpoPlayerUIVariants): Promise<void | UIManager>;
44
44
  }