@npo/player 1.24.7 → 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 (170) 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 +13 -13
  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 +18 -4
  9. package/lib/js/playeractions/handlers/processplayerconfig.test.js +116 -0
  10. package/lib/js/playeractions/handlers/processsourceconfig.d.ts +3 -1
  11. package/lib/js/playeractions/handlers/processsourceconfig.js +20 -10
  12. package/lib/js/playeractions/handlers/processsourceconfig.test.js +25 -0
  13. package/lib/js/settings/localization.d.ts +76 -1
  14. package/lib/js/settings/localization.js +2 -2
  15. package/lib/js/tracking/handlers/eventbinding.js +25 -17
  16. package/lib/js/tracking/handlers/eventlogging.js +3 -8
  17. package/lib/js/tracking/handlers/playertrackerinit.d.ts +2 -2
  18. package/lib/js/tracking/handlers/playertrackerinit.js +8 -6
  19. package/lib/js/tracking/handlers/playertrackerinit.test.d.ts +1 -0
  20. package/lib/js/tracking/handlers/playertrackerinit.test.js +74 -0
  21. package/lib/js/tracking/handlers/playertrackerstart.js +1 -1
  22. package/lib/js/utilities/utilities.element.d.ts +6 -0
  23. package/lib/js/utilities/utilities.element.js +10 -0
  24. package/lib/js/utilities/utilities.element.test.js +18 -5
  25. package/lib/lang/nl.json +1 -1
  26. package/lib/lang/subtitleLabels/nl.json +14 -0
  27. package/lib/npoplayer.d.ts +15 -6
  28. package/lib/npoplayer.js +57 -50
  29. package/lib/npoplayer.test.js +12 -4
  30. package/lib/package.json +3 -3
  31. package/lib/services/a11y/setup.js +2 -5
  32. package/lib/services/a11y/setup.test.js +2 -19
  33. package/lib/services/advertHandlers/discardAdBreak.js +4 -4
  34. package/lib/services/advertHandlers/discardAdBreak.test.js +25 -13
  35. package/lib/services/advertHandlers/handlePreRolls.js +19 -19
  36. package/lib/services/advertHandlers/handlePrerolls.test.js +4 -4
  37. package/lib/services/cdnProviders/cdnProviders.js +4 -2
  38. package/lib/services/drmHandlers/decideprofile.js +1 -1
  39. package/lib/services/drmHandlers/decideprofile.test.js +1 -1
  40. package/lib/services/drmHandlers/verifydrm.js +6 -6
  41. package/lib/services/drmHandlers/verifydrm.test.js +5 -5
  42. package/lib/services/eventListenerHandlers/removeEventListeners.js +2 -2
  43. package/lib/services/eventListenerHandlers/removeEventListeners.test.js +9 -9
  44. package/lib/services/keyboardHandlers/resolvekeypress.js +5 -5
  45. package/lib/services/keyboardHandlers/resolvekeypress.test.js +1 -1
  46. package/lib/services/liveStreamHandlers/handleLiveStreamControls.js +2 -2
  47. package/lib/services/liveStreamHandlers/handleLiveStreamControls.test.js +2 -2
  48. package/lib/services/localStorageHandlers/localStorageHandlers.js +2 -2
  49. package/lib/services/localStorageHandlers/localStorageHandlers.test.js +2 -5
  50. package/lib/services/nicamHandlers/nicamhandler.d.ts +5 -0
  51. package/lib/{ui/handlers → services/nicamHandlers}/nicamhandler.js +24 -15
  52. package/lib/services/nicamHandlers/nicamhandler.test.js +132 -0
  53. package/lib/services/npoPlayerAPI/npoPlayerAPI.d.ts +3 -2
  54. package/lib/services/npoPlayerAPI/npoPlayerAPI.js +19 -23
  55. package/lib/services/preferences/handlePreferences.d.ts +2 -0
  56. package/lib/services/preferences/handlePreferences.js +42 -0
  57. package/lib/services/preferences/handlePreferences.test.d.ts +1 -0
  58. package/lib/services/preferences/handlePreferences.test.js +102 -0
  59. package/lib/services/segmentHandlers/addSegmentEventListeners.js +2 -2
  60. package/lib/services/segmentHandlers/addSegmentEventListeners.test.js +1 -1
  61. package/lib/services/segmentHandlers/setSegmentMarkers.js +1 -1
  62. package/lib/services/services.d.ts +7 -0
  63. package/lib/services/services.js +26 -0
  64. package/lib/services/streamoptionsHandlers/streamOptionsHandler.d.ts +6 -0
  65. package/lib/services/streamoptionsHandlers/streamOptionsHandler.js +78 -0
  66. package/lib/services/streamoptionsHandlers/streamOptionsHandler.test.js +187 -0
  67. package/lib/services/uiHandlers/uiVisiblityHandler.d.ts +3 -0
  68. package/lib/services/uiHandlers/uiVisiblityHandler.js +26 -0
  69. package/lib/services/uiHandlers/uiVisiblityHandler.test.d.ts +1 -0
  70. package/lib/services/uiHandlers/uiVisiblityHandler.test.js +62 -0
  71. package/lib/src/js/api/getstreamobject.d.ts +1 -1
  72. package/lib/src/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
  73. package/lib/src/js/playeractions/handlers/processplayerconfig.test.d.ts +1 -0
  74. package/lib/src/js/playeractions/handlers/processsourceconfig.d.ts +3 -1
  75. package/lib/src/js/playeractions/handlers/processsourceconfig.test.d.ts +1 -0
  76. package/lib/src/js/settings/localization.d.ts +76 -1
  77. package/lib/src/js/tracking/handlers/playertrackerinit.d.ts +2 -2
  78. package/lib/src/js/tracking/handlers/playertrackerinit.test.d.ts +1 -0
  79. package/lib/src/js/utilities/utilities.element.d.ts +6 -0
  80. package/lib/src/npoplayer.d.ts +15 -6
  81. package/lib/src/services/nicamHandlers/nicamhandler.d.ts +5 -0
  82. package/lib/src/services/nicamHandlers/nicamhandler.test.d.ts +1 -0
  83. package/lib/src/services/npoPlayerAPI/npoPlayerAPI.d.ts +3 -2
  84. package/lib/src/services/preferences/handlePreferences.d.ts +2 -0
  85. package/lib/src/services/preferences/handlePreferences.test.d.ts +1 -0
  86. package/lib/src/services/services.d.ts +7 -0
  87. package/lib/src/services/streamoptionsHandlers/streamOptionsHandler.d.ts +6 -0
  88. package/lib/src/services/streamoptionsHandlers/streamOptionsHandler.test.d.ts +1 -0
  89. package/lib/src/services/uiHandlers/uiVisiblityHandler.d.ts +3 -0
  90. package/lib/src/services/uiHandlers/uiVisiblityHandler.test.d.ts +1 -0
  91. package/lib/src/types/classes.d.ts +6 -0
  92. package/lib/src/types/interfaces.d.ts +25 -3
  93. package/lib/src/ui/components/adbutton.d.ts +1 -1
  94. package/lib/src/ui/components/adlabel.d.ts +1 -1
  95. package/lib/src/ui/components/buttons.d.ts +10 -17
  96. package/lib/src/ui/components/controlbar.d.ts +2 -2
  97. package/lib/src/ui/components/ctabar.d.ts +1 -1
  98. package/lib/src/ui/components/nativemobile/buttons.d.ts +8 -0
  99. package/lib/src/ui/components/playnext.d.ts +1 -3
  100. package/lib/src/ui/components/seekbar.d.ts +1 -1
  101. package/lib/src/ui/components/titlebar.d.ts +1 -1
  102. package/lib/src/ui/components/topbar.d.ts +2 -2
  103. package/lib/src/ui/components/verticalvideo/controlbar.d.ts +2 -2
  104. package/lib/src/ui/handlers/playnextscreen.test.d.ts +1 -0
  105. package/lib/src/ui/handlers/timecontrolhandlers.d.ts +3 -3
  106. package/lib/src/ui/uicontainer.d.ts +2 -3
  107. package/lib/src/ui/uicontainer.test.d.ts +1 -0
  108. package/lib/tests/mocks/mockLogEmitter.d.ts +2 -0
  109. package/lib/tests/mocks/mockLogEmitter.js +20 -0
  110. package/lib/tests/mocks/mockNpoplayer.js +4 -2
  111. package/lib/tests/mocks/playerContextMock.d.ts +5 -3
  112. package/lib/tests/mocks/playerContextMock.js +8 -5
  113. package/lib/types/classes.d.ts +6 -0
  114. package/lib/types/classes.js +12 -0
  115. package/lib/types/interfaces.d.ts +25 -3
  116. package/lib/types/interfaces.js +1 -0
  117. package/lib/ui/components/adbutton.d.ts +1 -1
  118. package/lib/ui/components/adbutton.js +3 -3
  119. package/lib/ui/components/adlabel.d.ts +1 -1
  120. package/lib/ui/components/adlabel.js +3 -3
  121. package/lib/ui/components/buttons.d.ts +10 -17
  122. package/lib/ui/components/buttons.js +44 -27
  123. package/lib/ui/components/controlbar.d.ts +2 -2
  124. package/lib/ui/components/controlbar.js +20 -32
  125. package/lib/ui/components/ctabar.d.ts +1 -1
  126. package/lib/ui/components/ctabar.js +4 -4
  127. package/lib/ui/components/nativemobile/buttons.d.ts +8 -0
  128. package/lib/ui/components/nativemobile/buttons.js +41 -1
  129. package/lib/ui/components/nativemobile/controlbar.js +1 -2
  130. package/lib/ui/components/nativemobile/topbar.js +2 -2
  131. package/lib/ui/components/playnext.d.ts +1 -3
  132. package/lib/ui/components/playnext.js +3 -3
  133. package/lib/ui/components/seekbar.d.ts +1 -1
  134. package/lib/ui/components/seekbar.js +5 -3
  135. package/lib/ui/components/settingspanel.js +9 -9
  136. package/lib/ui/components/titlebar.d.ts +1 -1
  137. package/lib/ui/components/titlebar.js +2 -2
  138. package/lib/ui/components/topbar.d.ts +2 -2
  139. package/lib/ui/components/topbar.js +8 -17
  140. package/lib/ui/components/verticalvideo/controlbar.d.ts +2 -2
  141. package/lib/ui/components/verticalvideo/controlbar.js +4 -4
  142. package/lib/ui/handlers/playnextscreen.test.d.ts +1 -0
  143. package/lib/ui/handlers/timecontrolhandlers.d.ts +3 -3
  144. package/lib/ui/nativemobileuifactory.js +20 -24
  145. package/lib/ui/nativemobileuifactory.test.js +2 -6
  146. package/lib/ui/uicontainer.d.ts +2 -3
  147. package/lib/ui/uicontainer.js +13 -30
  148. package/lib/ui/uicontainer.test.d.ts +1 -0
  149. package/lib/ui/uicontainer.test.js +80 -0
  150. package/package.json +3 -3
  151. package/src/style/components/_advert.scss +0 -9
  152. package/src/style/components/_icons.scss +5 -0
  153. package/src/style/components/_nicam.scss +5 -4
  154. package/src/style/components/_settingspanel.scss +48 -17
  155. package/src/style/components/vertical-video/_settingspanel.scss +1 -1
  156. package/src/style/npoplayer.css +26 -20
  157. package/src/style/variants/_player-base.scss +4 -0
  158. package/src/style/variants/_player-large.scss +5 -1
  159. package/src/style/variants/_player-small.scss +11 -8
  160. package/lib/src/ui/handlers/nicamhandler.d.ts +0 -6
  161. package/lib/src/ui/handlers/streamhandler.d.ts +0 -2
  162. package/lib/ui/handlers/nicamhandler.d.ts +0 -6
  163. package/lib/ui/handlers/nicamhandler.test.js +0 -36
  164. package/lib/ui/handlers/streamhandler.d.ts +0 -2
  165. package/lib/ui/handlers/streamhandler.js +0 -60
  166. /package/lib/{src/ui/handlers/playnextstreen.test.d.ts → js/playeractions/handlers/processplayerconfig.test.d.ts} +0 -0
  167. /package/lib/{ui/handlers/playnextstreen.test.d.ts → js/playeractions/handlers/processsourceconfig.test.d.ts} +0 -0
  168. /package/lib/{src/ui/handlers → services/nicamHandlers}/nicamhandler.test.d.ts +0 -0
  169. /package/lib/{ui/handlers/nicamhandler.test.d.ts → services/streamoptionsHandlers/streamOptionsHandler.test.d.ts} +0 -0
  170. /package/lib/ui/handlers/{playnextstreen.test.js → playnextscreen.test.js} +0 -0
@@ -0,0 +1,132 @@
1
+ import { processNicam, showNicamAfterUiDelay } from './nicamhandler';
2
+ import '@testing-library/jest-dom';
3
+ import { createMockNpoPlayer, createPlayerContextMock } from '../../../tests/mocks/playerContextMock';
4
+ import { NpoPlayerEvent } from '../../types/events';
5
+ describe('NICAM Processing', () => {
6
+ let mockElement;
7
+ beforeEach(() => {
8
+ mockElement = { innerHTML: '', appendChild: jest.fn() };
9
+ document.querySelector = jest.fn().mockReturnValue(mockElement);
10
+ });
11
+ it('processes NICAM from the streamObject', () => {
12
+ const mockElement = document.createElement('div');
13
+ const npoPlayerMock = createMockNpoPlayer({
14
+ streamObject: {
15
+ metadata: {
16
+ ageRating: '12',
17
+ nicam: ['GEWELD', 'ANGST', 'DRUGS_EN_ALCOHOL', 'GROF_TAALGEBRUIK']
18
+ }
19
+ }
20
+ });
21
+ const playerContextMock = createPlayerContextMock({
22
+ npoPlayer: npoPlayerMock
23
+ });
24
+ processNicam(playerContextMock, mockElement);
25
+ expect(mockElement.children).toHaveLength(5);
26
+ });
27
+ it('processes NICAM and age rating with streamOptions taking priority', () => {
28
+ const mockElement = document.createElement('div');
29
+ const npoPlayerMock = createMockNpoPlayer({
30
+ streamObject: {
31
+ metadata: {
32
+ ageRating: '12',
33
+ nicam: ['GEWELD', 'ANGST', 'GROF_TAALGEBRUIK']
34
+ }
35
+ },
36
+ streamOptions: {
37
+ ageRating: '16',
38
+ nicam: ['DRUGS_EN_ALCOHOL']
39
+ }
40
+ });
41
+ const playerContextMock = createPlayerContextMock({
42
+ npoPlayer: npoPlayerMock
43
+ });
44
+ processNicam(playerContextMock, mockElement);
45
+ expect(mockElement.children).toHaveLength(2);
46
+ });
47
+ it('does nothing if no NICAM element found', () => {
48
+ document.querySelector = jest.fn().mockReturnValue(undefined);
49
+ const npoPlayerMock = createMockNpoPlayer({
50
+ streamObject: {
51
+ metadata: {
52
+ ageRating: '12',
53
+ nicam: ['GEWELD', 'ANGST', 'GROF_TAALGEBRUIK']
54
+ }
55
+ }
56
+ });
57
+ const playerContextMock = createPlayerContextMock({
58
+ npoPlayer: npoPlayerMock
59
+ });
60
+ processNicam(playerContextMock, mockElement);
61
+ });
62
+ it('does nothing if no metadata and no streamOptions', () => {
63
+ const npoPlayerMock = createMockNpoPlayer({});
64
+ const playerContextMock = createPlayerContextMock({
65
+ npoPlayer: npoPlayerMock
66
+ });
67
+ processNicam(playerContextMock, mockElement);
68
+ expect(mockElement.appendChild).not.toHaveBeenCalled();
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;
@@ -25,6 +26,7 @@ export declare class NpoPlayerAPI {
25
26
  getSupportedTech(): Technology[];
26
27
  off(eventType: NpoPlayerEvent, callback: NpoPlayerEventCallback): void;
27
28
  on(eventType: NpoPlayerEvent, callback: NpoPlayerEventCallback): void;
29
+ isCastAvailable(): boolean;
28
30
  seek(time: number): void;
29
31
  timeShift(time: number): void;
30
32
  getContainer(): HTMLElement;
@@ -37,7 +39,6 @@ export declare class NpoPlayerAPI {
37
39
  getTimeShift(): number;
38
40
  scheduleAds(adConfig: AdConfig): Promise<AdBreak[]>;
39
41
  getActiveAdBreak(): AdBreak | null;
40
- discardAdBreak(adBreakId: string): void;
41
42
  getConfig(mergedConfig?: boolean): PlayerConfig;
42
43
  createUIManager(playerContext: PlayerContext, variant: NpoPlayerUIVariants): Promise<void | UIManager>;
43
44
  }
@@ -1,6 +1,5 @@
1
1
  import { UIManager } from 'bitmovin-player-ui';
2
2
  import { customSpecificErrorMessageOverlayConfig } from '../../js/playeractions/handlers/customerrors';
3
- import { processStream } from '../../ui/handlers/streamhandler';
4
3
  import { createUIContainer } from '../../ui/uicontainer';
5
4
  import { playerEventMap } from '../../types/events';
6
5
  import { VOLUME_MAX, VOLUME_MIN, VOLUME_STEP } from './contants';
@@ -46,23 +45,17 @@ export class NpoPlayerAPI {
46
45
  return this.playerAPI.getViewMode();
47
46
  }
48
47
  areSubtitlesEnabled() {
49
- let subsEnabled = false;
50
- const currentSubtitleTrack = this.playerAPI.subtitles.list();
51
- for (const subtitle of currentSubtitleTrack) {
52
- if (subtitle.enabled) {
53
- subsEnabled = true;
54
- break;
55
- }
56
- }
57
- return subsEnabled;
48
+ return this.playerAPI.subtitles.list().some((subtitle) => subtitle.enabled);
49
+ }
50
+ getCurrentSubtitle() {
51
+ const currentSubtitle = this.playerAPI.subtitles.list().find((subtitle) => subtitle.enabled);
52
+ return currentSubtitle ? currentSubtitle.lang : undefined;
58
53
  }
59
- enableSubtitles() {
54
+ enableSubtitles(selectedLang = 'nl') {
60
55
  const subtitleTracks = this.playerAPI.subtitles.list();
61
- for (const subtitle of subtitleTracks) {
62
- if (!subtitle.enabled) {
63
- this.playerAPI.subtitles.enable(subtitle.id);
64
- break;
65
- }
56
+ const subtitleToEnable = subtitleTracks.find((subtitle) => subtitle.lang === selectedLang);
57
+ if (subtitleToEnable && !subtitleToEnable.enabled) {
58
+ this.playerAPI.subtitles.enable(subtitleToEnable.id);
66
59
  }
67
60
  }
68
61
  isPaused() {
@@ -99,6 +92,9 @@ export class NpoPlayerAPI {
99
92
  }
100
93
  this.playerAPI.on(externalEventType, externalCallback);
101
94
  }
95
+ isCastAvailable() {
96
+ return this.playerAPI.isCastAvailable();
97
+ }
102
98
  seek(time) {
103
99
  this.playerAPI.seek(time);
104
100
  }
@@ -135,22 +131,22 @@ export class NpoPlayerAPI {
135
131
  getActiveAdBreak() {
136
132
  return this.playerAPI.ads.getActiveAdBreak();
137
133
  }
138
- discardAdBreak(adBreakId) {
139
- return this.playerAPI.ads.discardAdBreak(adBreakId);
140
- }
141
134
  getConfig(mergedConfig) {
142
135
  return this.playerAPI.getConfig(mergedConfig);
143
136
  }
144
137
  async createUIManager(playerContext, variant) {
145
- if (playerContext.npoplayer.uiManager === undefined || variant !== playerContext.npoplayer.variant) {
138
+ const { npoPlayerServices } = playerContext.npoPlayer;
139
+ npoPlayerServices.removeUivisiblityHandlers(playerContext);
140
+ if (playerContext.npoPlayer.uiManager === undefined || variant !== playerContext.npoPlayer.variant) {
146
141
  const uiConfig = {
147
142
  errorMessages: customSpecificErrorMessageOverlayConfig,
148
143
  disableAutoHideWhenHovered: true,
149
144
  seekbarSnappingEnabled: false
150
145
  };
151
- playerContext.npoplayer.uiManager = new UIManager(this.playerAPI, createUIContainer(playerContext.npoplayer, this.playerAPI, variant, playerContext.npoplayer.container), uiConfig);
152
- playerContext.npoplayer.variant = variant;
146
+ playerContext.npoPlayer.variant = variant;
147
+ const uiManager = new UIManager(this.playerAPI, createUIContainer(playerContext, this.playerAPI, variant), uiConfig);
148
+ playerContext.npoPlayer.uiManager = uiManager;
149
+ npoPlayerServices.addUivisiblityHandlers(playerContext);
153
150
  }
154
- processStream(playerContext);
155
151
  }
156
152
  }
@@ -0,0 +1,2 @@
1
+ import { PlayerContext } from '../../types/interfaces';
2
+ export declare function handlePreferences(playerContext: PlayerContext): void;
@@ -0,0 +1,42 @@
1
+ import { NpoPlayerEvent } from '../../types/events';
2
+ import { LocalStorageValues } from '../../types/interfaces';
3
+ export function handlePreferences(playerContext) {
4
+ const { player, npoPlayer } = playerContext;
5
+ const { npoPlayerServices } = npoPlayer;
6
+ const handleSourceLoaded = () => {
7
+ const storedUserPrefs = npoPlayerServices.getStoredUserPrefs();
8
+ const subtitlesEnabledInPrefs = storedUserPrefs?.subtitles_enabled === 'true';
9
+ const preferredSubtitleLang = storedUserPrefs?.subtitles_language?.toString();
10
+ const shouldEnableSubtitles = npoPlayer.streamOptions.enableSubtitles || subtitlesEnabledInPrefs;
11
+ if (shouldEnableSubtitles) {
12
+ player.enableSubtitles(preferredSubtitleLang);
13
+ }
14
+ };
15
+ const handleSubtitleEnabled = () => {
16
+ const currentSubtitleTrack = player.playerAPI.subtitles.list();
17
+ const enabledSubtitle = currentSubtitleTrack.find((subtitle) => subtitle.enabled);
18
+ if (enabledSubtitle) {
19
+ npoPlayerServices.setStoredUserPrefs(LocalStorageValues.SUBTITLES_LANGUAGE, enabledSubtitle.lang);
20
+ npoPlayerServices.setStoredUserPrefs(LocalStorageValues.SUBTITLES_ENABLED, 'true');
21
+ }
22
+ };
23
+ const handleSubtitleDisabled = () => {
24
+ npoPlayerServices.setStoredUserPrefs(LocalStorageValues.SUBTITLES_ENABLED, 'false');
25
+ };
26
+ const handleVolumeChanged = () => {
27
+ const volume = player.getVolume();
28
+ npoPlayerServices.setStoredUserPrefs(LocalStorageValues.VOLUME, volume);
29
+ };
30
+ const handleMuted = () => {
31
+ npoPlayerServices.setStoredUserPrefs(LocalStorageValues.IS_MUTED, 'true');
32
+ };
33
+ const handleUnmuted = () => {
34
+ npoPlayerServices.setStoredUserPrefs(LocalStorageValues.IS_MUTED, 'false');
35
+ };
36
+ player.on(NpoPlayerEvent.SourceLoaded, handleSourceLoaded);
37
+ player.on(NpoPlayerEvent.SubtitleEnabled, handleSubtitleEnabled);
38
+ player.on(NpoPlayerEvent.SubtitleDisabled, handleSubtitleDisabled);
39
+ player.on(NpoPlayerEvent.VolumeChanged, handleVolumeChanged);
40
+ player.on(NpoPlayerEvent.Muted, handleMuted);
41
+ player.on(NpoPlayerEvent.Unmuted, handleUnmuted);
42
+ }
@@ -0,0 +1,102 @@
1
+ import createPlayerContextMock, { createMockNpoPlayer, createMockNpoPlayerAPI } from '../../../tests/mocks/playerContextMock';
2
+ import { handlePreferences } from './handlePreferences';
3
+ import { NpoPlayerEvent } from '../../types/events';
4
+ import { LocalStorageValues } from '../../types/interfaces';
5
+ describe('handlePreferences', () => {
6
+ let mockPlayerAPI;
7
+ let mockNpoPlayer;
8
+ beforeEach(() => {
9
+ mockPlayerAPI = createMockNpoPlayerAPI({
10
+ getVolume: jest.fn().mockReturnValue(50),
11
+ on: jest.fn(),
12
+ enableSubtitles: jest.fn(),
13
+ playerAPI: {
14
+ subtitles: {
15
+ list: jest.fn()
16
+ }
17
+ }
18
+ });
19
+ mockNpoPlayer = createMockNpoPlayer({
20
+ streamOptions: {
21
+ enableSubtitles: false
22
+ },
23
+ npoPlayerServices: {
24
+ getStoredUserPrefs: jest.fn().mockReturnValue({
25
+ subtitles_enabled: 'false',
26
+ subtitles_language: 'nl'
27
+ }),
28
+ setStoredUserPrefs: jest.fn()
29
+ }
30
+ });
31
+ const playerContextMock = createPlayerContextMock({
32
+ player: mockPlayerAPI,
33
+ npoPlayer: mockNpoPlayer
34
+ });
35
+ handlePreferences(playerContextMock);
36
+ });
37
+ test('should enable subtitles if streamOptions.enableSubtitles is true', () => {
38
+ mockNpoPlayer.streamOptions.enableSubtitles = true;
39
+ for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
40
+ if (event === NpoPlayerEvent.SourceLoaded) {
41
+ callback(NpoPlayerEvent.SourceLoaded);
42
+ }
43
+ }
44
+ expect(mockPlayerAPI.enableSubtitles).toHaveBeenCalledWith('nl');
45
+ });
46
+ test('should enable subtitles if subtitles_enabled in preferences is true', () => {
47
+ mockNpoPlayer.streamOptions.enableSubtitles = false;
48
+ mockNpoPlayer.npoPlayerServices.getStoredUserPrefs.mockReturnValueOnce({
49
+ subtitles_enabled: 'true',
50
+ subtitles_language: 'nl'
51
+ });
52
+ for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
53
+ if (event === NpoPlayerEvent.SourceLoaded) {
54
+ callback(NpoPlayerEvent.SourceLoaded);
55
+ }
56
+ }
57
+ expect(mockPlayerAPI.enableSubtitles).toHaveBeenCalledWith('nl');
58
+ });
59
+ test('should disable subtitles and set the preferences', () => {
60
+ ;
61
+ mockPlayerAPI.playerAPI.subtitles.list.mockReturnValueOnce([{ lang: 'nl', enabled: true }]);
62
+ for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
63
+ if (event === NpoPlayerEvent.SubtitleEnabled) {
64
+ callback(NpoPlayerEvent.SubtitleEnable);
65
+ }
66
+ }
67
+ expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.SUBTITLES_LANGUAGE, 'nl');
68
+ expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.SUBTITLES_ENABLED, 'true');
69
+ });
70
+ test('should disable subtitles and set preferences to false', () => {
71
+ for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
72
+ if (event === NpoPlayerEvent.SubtitleDisabled) {
73
+ callback(NpoPlayerEvent.SubtitleDisabled);
74
+ }
75
+ }
76
+ expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.SUBTITLES_ENABLED, 'false');
77
+ });
78
+ test('should set volume preferences', () => {
79
+ for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
80
+ if (event === NpoPlayerEvent.VolumeChanged) {
81
+ callback(NpoPlayerEvent.VolumeChanged);
82
+ }
83
+ }
84
+ expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.VOLUME, 50);
85
+ });
86
+ test('should set muted preferences', () => {
87
+ for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
88
+ if (event === NpoPlayerEvent.Muted) {
89
+ callback(NpoPlayerEvent.Muted);
90
+ }
91
+ }
92
+ expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.IS_MUTED, 'true');
93
+ });
94
+ test('should set unmuted preferences', () => {
95
+ for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
96
+ if (event === NpoPlayerEvent.Unmuted) {
97
+ callback(NpoPlayerEvent.Unmuted);
98
+ }
99
+ }
100
+ expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.IS_MUTED, 'false');
101
+ });
102
+ });
@@ -4,10 +4,10 @@ import { handleSegmentSeek } from './handleSegmentSeek';
4
4
  export const addSegmentEventListeners = (playerContext, segment) => {
5
5
  const segmentHandleTimeChangedCallback = handleSegmentTimeChanged(playerContext, segment);
6
6
  const segmentSeekFunctionCallback = handleSegmentSeek(playerContext, segment);
7
- const { player, npoplayer } = playerContext;
7
+ const { player, npoPlayer } = playerContext;
8
8
  player.on(NpoPlayerEvent.TimeChanged, segmentHandleTimeChangedCallback);
9
9
  player.on(NpoPlayerEvent.Seek, segmentSeekFunctionCallback);
10
- npoplayer.eventListeners = {
10
+ npoPlayer.eventListeners = {
11
11
  segmentHandleTimeChangedCallback,
12
12
  segmentSeekFunctionCallback
13
13
  };
@@ -36,7 +36,7 @@ describe('addSegmentEventListeners', () => {
36
36
  handleSegmentTimeChanged.mockReturnValue(segmentHandleTimeChangedCallback);
37
37
  handleSegmentSeek.mockReturnValue(segmentSeekFunctionCallback);
38
38
  addSegmentEventListeners(mockPlayerContext, segment);
39
- expect(mockPlayerContext.npoplayer.eventListeners).toEqual({
39
+ expect(mockPlayerContext.npoPlayer.eventListeners).toEqual({
40
40
  segmentHandleTimeChangedCallback,
41
41
  segmentSeekFunctionCallback
42
42
  });
@@ -1,4 +1,4 @@
1
- import * as nlJson from '../../lang/nl.json';
1
+ import nlJson from '../../lang/nl.json';
2
2
  export function setSegmentMarkers(segment, title) {
3
3
  const unplayableClass = 'seekbar-marker-unplayable';
4
4
  const unplayableTitle = nlJson['segment.unplayableTitle'];
@@ -12,5 +12,12 @@ export declare class NpoPlayerServices {
12
12
  handleUserPrefs(playerContext: PlayerContext): void;
13
13
  setAccessibilityAttributes(playerContext: PlayerContext): void;
14
14
  schedulePreRolls(playerContext: PlayerContext): Promise<void>;
15
+ discardAdBreak(playerContext: PlayerContext): void;
15
16
  handleVerticalVideoControls(playerContext: PlayerContext, variant: NpoPlayerUIVariants): void;
17
+ showNicamAfterUiDelay(playerContext: PlayerContext | undefined): void;
18
+ setupNicamKijkwijzerIcons(playerContext: PlayerContext): void;
19
+ handlePreferences(playerContext: PlayerContext): void;
20
+ addUivisiblityHandlers(playerContext: PlayerContext): void;
21
+ removeUivisiblityHandlers(playerContext: PlayerContext): void;
22
+ handleStreamOptions(playerContext: PlayerContext): void;
16
23
  }
@@ -7,6 +7,11 @@ import { getLocalStorage, setLocalStorage, setValuesBasedOnLocalStorage } from '
7
7
  import { getAVType } from './avTypeHandlers/getAVType';
8
8
  import { handlePreRolls } from './advertHandlers/handlePreRolls';
9
9
  import { handleVerticalVideoControls } from './verticalVideoHandlers/handleVerticalVideoControls';
10
+ import { setupNicamKijkwijzerIcons, showNicamAfterUiDelay } from './nicamHandlers/nicamhandler';
11
+ import { handlePreferences } from './preferences/handlePreferences';
12
+ import { addUivisiblityHandlers, removeUivisiblityHandlers } from './uiHandlers/uiVisiblityHandler';
13
+ import { discardAdBreak } from './advertHandlers/discardAdBreak';
14
+ import { handleStreamOptions } from './streamoptionsHandlers/streamOptionsHandler';
10
15
  export class NpoPlayerServices {
11
16
  getAVType(avType) {
12
17
  return getAVType(avType);
@@ -49,7 +54,28 @@ export class NpoPlayerServices {
49
54
  async schedulePreRolls(playerContext) {
50
55
  await handlePreRolls(playerContext);
51
56
  }
57
+ discardAdBreak(playerContext) {
58
+ discardAdBreak(playerContext);
59
+ }
52
60
  handleVerticalVideoControls(playerContext, variant) {
53
61
  return handleVerticalVideoControls(playerContext, variant);
54
62
  }
63
+ showNicamAfterUiDelay(playerContext) {
64
+ return showNicamAfterUiDelay(playerContext);
65
+ }
66
+ setupNicamKijkwijzerIcons(playerContext) {
67
+ return setupNicamKijkwijzerIcons(playerContext);
68
+ }
69
+ handlePreferences(playerContext) {
70
+ handlePreferences(playerContext);
71
+ }
72
+ addUivisiblityHandlers(playerContext) {
73
+ addUivisiblityHandlers(playerContext);
74
+ }
75
+ removeUivisiblityHandlers(playerContext) {
76
+ removeUivisiblityHandlers(playerContext);
77
+ }
78
+ handleStreamOptions(playerContext) {
79
+ handleStreamOptions(playerContext);
80
+ }
55
81
  }
@@ -0,0 +1,6 @@
1
+ import { PlayerContext } from '../../types/interfaces';
2
+ export declare function handleStreamOptions(playerContext: PlayerContext): void;
3
+ export declare function initializeFragment(playerContext: PlayerContext): void;
4
+ export declare function handleStartOffset(playerContext: PlayerContext): void;
5
+ export declare function updateStreamClasses(playerContext: PlayerContext): void;
6
+ export declare function setupAutoplay(playerContext: PlayerContext): void;
@@ -0,0 +1,78 @@
1
+ import * as playerAction from '../../js/playeractions/playeractions';
2
+ import { initSegment } from '../segmentHandlers/initSegment';
3
+ import { handleLiveStreamControls } from '../liveStreamHandlers/handleLiveStreamControls';
4
+ import { removeEventListeners } from '../eventListenerHandlers/removeEventListeners';
5
+ import { NpoPlayerEvent } from '../../types/events';
6
+ import { updateClassFromElementByQuery } from '../../js/utilities/utilities.element';
7
+ export function handleStreamOptions(playerContext) {
8
+ const { streamObject, uiManager } = playerContext.npoPlayer;
9
+ if (!streamObject || !uiManager)
10
+ return;
11
+ removeEventListeners(playerContext);
12
+ initializeFragment(playerContext);
13
+ handleStartOffset(playerContext);
14
+ updateStreamClasses(playerContext);
15
+ const isAutoplayEnabled = getAutoplayStatus(playerContext);
16
+ if (isAutoplayEnabled) {
17
+ setupAutoplay(playerContext);
18
+ }
19
+ }
20
+ export function initializeFragment(playerContext) {
21
+ const { streamObject, streamOptions } = playerContext.npoPlayer;
22
+ initSegment(playerContext, {
23
+ segment: streamObject.segment,
24
+ fragment: streamOptions?.fragments
25
+ });
26
+ }
27
+ export function handleStartOffset(playerContext) {
28
+ const streamOptions = playerContext.npoPlayer.streamOptions;
29
+ if (streamOptions?.startOffset) {
30
+ playerAction.handleStartOffset(playerContext, streamOptions.startOffset);
31
+ }
32
+ }
33
+ export function updateStreamClasses(playerContext) {
34
+ const { streamObject, container } = playerContext.npoPlayer;
35
+ const containerClassString = '.bmpui-ui-uicontainer';
36
+ const playerContainer = container;
37
+ const queries = [
38
+ {
39
+ container: playerContainer,
40
+ query: containerClassString,
41
+ className: 'livestream-no-dvr',
42
+ condition: !!(streamObject.stream.isLiveStream && !streamObject.stream.hasDvrWindow)
43
+ },
44
+ {
45
+ container: playerContainer,
46
+ query: containerClassString,
47
+ className: 'audio-only',
48
+ condition: !!(streamObject.stream.avType === 'aod' || streamObject.stream.avType === 'audio')
49
+ },
50
+ {
51
+ container: playerContainer,
52
+ query: '.bitmovinplayer-poster',
53
+ className: 'audio-only',
54
+ condition: !!(streamObject.stream.avType === 'aod' || streamObject.stream.avType === 'audio')
55
+ }
56
+ ];
57
+ for (const query of queries)
58
+ updateClassFromElementByQuery(query);
59
+ if (streamObject.stream.isLiveStream && streamObject.stream.hasDvrWindow) {
60
+ handleLiveStreamControls(playerContext);
61
+ }
62
+ }
63
+ function getAutoplayStatus(playerContext) {
64
+ return (playerContext.npoPlayer.streamOptions?.autoplay ?? playerContext.player.getConfig()?.playback?.autoplay ?? false);
65
+ }
66
+ export function setupAutoplay(playerContext) {
67
+ const { player } = playerContext;
68
+ const handleAutoPlay = () => {
69
+ doAutoPlay().catch((error) => {
70
+ console.error('Error attempting to autoplay:', error);
71
+ });
72
+ };
73
+ const doAutoPlay = async () => {
74
+ player.off(NpoPlayerEvent.Ready, handleAutoPlay);
75
+ await player.play();
76
+ };
77
+ player.on(NpoPlayerEvent.Ready, handleAutoPlay);
78
+ }