@npo/player 1.27.7 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/README.md +4 -7
  2. package/lib/js/markers/updateLiveMarkers.d.ts +7 -2
  3. package/lib/js/markers/updateLiveMarkers.js +11 -4
  4. package/lib/js/markers/updateLiveMarkers.test.js +13 -3
  5. package/lib/js/playeractions/handlers/handleoffsets.test.js +1 -1
  6. package/lib/js/playeractions/handlers/mediasessionactions.d.ts +7 -2
  7. package/lib/js/playeractions/handlers/mediasessionactions.js +7 -7
  8. package/lib/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
  9. package/lib/js/playeractions/handlers/processplayerconfig.js +1 -1
  10. package/lib/js/playeractions/handlers/processplayerconfig.test.js +1 -1
  11. package/lib/js/playeractions/handlers/processsourceconfig.d.ts +11 -2
  12. package/lib/js/playeractions/handlers/processsourceconfig.js +35 -18
  13. package/lib/js/playeractions/handlers/removereplayclass.d.ts +1 -1
  14. package/lib/js/playeractions/handlers/removereplayclass.js +1 -1
  15. package/lib/js/playeractions/handlers/removereplayclass.test.js +1 -1
  16. package/lib/js/settings/localization.d.ts +1 -0
  17. package/lib/js/utilities/utilities.jwt.d.ts +2 -0
  18. package/lib/js/utilities/utilities.jwt.js +22 -0
  19. package/lib/js/utilities/utilities.stream.js +11 -2
  20. package/lib/js/utilities/utilities.url.js +2 -2
  21. package/lib/js/utilities/utilities.version.js +1 -1
  22. package/lib/js/utilities/utilities.version.test.js +1 -1
  23. package/lib/lang/nl.json +2 -1
  24. package/lib/npoplayer.d.ts +6 -5
  25. package/lib/npoplayer.js +81 -28
  26. package/lib/package.json +7 -9
  27. package/lib/services/a11y/setup.test.js +2 -4
  28. package/lib/services/advertHandlers/handlePreRolls.js +3 -4
  29. package/lib/services/advertHandlers/handlePrerolls.test.js +2 -3
  30. package/lib/services/chapterHandlers/chapterHandler.d.ts +35 -0
  31. package/lib/services/chapterHandlers/chapterHandler.js +230 -0
  32. package/lib/services/errors/errorBackground.test.js +1 -1
  33. package/lib/services/errors/errorHandler.d.ts +4 -2
  34. package/lib/services/errors/errorHandler.js +27 -14
  35. package/lib/services/errors/errorHandler.test.js +148 -0
  36. package/lib/services/errors/errorRetryHandler.d.ts +2 -0
  37. package/lib/services/errors/errorRetryHandler.js +14 -0
  38. package/lib/services/errors/errorRetryHandler.test.d.ts +1 -0
  39. package/lib/services/errors/errorRetryHandler.test.js +62 -0
  40. package/lib/services/errors/errorText.js +8 -5
  41. package/lib/services/errors/errorText.test.js +3 -3
  42. package/lib/services/infoPanel/infoPanel.d.ts +3 -0
  43. package/lib/services/infoPanel/infoPanel.js +35 -0
  44. package/lib/services/infoPanel/infoPanel.test.d.ts +1 -0
  45. package/lib/services/infoPanel/infoPanel.test.js +70 -0
  46. package/lib/services/keyboardHandlers/resolvekeypress.js +11 -1
  47. package/lib/services/keyboardHandlers/resolvekeypress.test.js +6 -2
  48. package/lib/services/nicamHandlers/nicamhandler.d.ts +1 -0
  49. package/lib/services/nicamHandlers/nicamhandler.js +2 -1
  50. package/lib/services/nicamHandlers/nicamhandler.test.js +2 -2
  51. package/lib/services/npoPlayerAPI/npoPlayerAPI.d.ts +8 -2
  52. package/lib/services/npoPlayerAPI/npoPlayerAPI.js +25 -12
  53. package/lib/services/npoPlayerAPI/playerModules.d.ts +1 -0
  54. package/lib/services/npoPlayerAPI/playerModules.js +46 -0
  55. package/lib/services/preferences/handlePreferences.js +9 -4
  56. package/lib/services/preferences/handlePreferences.test.js +53 -17
  57. package/lib/services/segmentHandlers/addSegmentEventListeners.test.js +1 -1
  58. package/lib/services/segmentHandlers/isSegmentInBounds.d.ts +2 -0
  59. package/lib/services/segmentHandlers/isSegmentInBounds.js +5 -0
  60. package/lib/services/segmentHandlers/isSegmentInBounds.test.d.ts +1 -0
  61. package/lib/services/segmentHandlers/isSegmentInBounds.test.js +27 -0
  62. package/lib/services/services.d.ts +5 -2
  63. package/lib/services/services.js +15 -2
  64. package/lib/services/streamFetchHandler/fetchStream.js +5 -4
  65. package/lib/services/streamFetchHandler/fetchstream.test.js +25 -3
  66. package/lib/services/streamoptionsHandlers/streamOptionsHandler.js +11 -9
  67. package/lib/services/streamoptionsHandlers/streamOptionsHandler.test.js +14 -2
  68. package/lib/services/trackingHandlers/eventBinding.js +48 -33
  69. package/lib/services/trackingHandlers/eventBinding.test.js +57 -1
  70. package/lib/services/trackingHandlers/playerTrackerStart.js +1 -1
  71. package/lib/services/uiHandlers/uiVisiblityHandler.js +6 -0
  72. package/lib/services/verticalVideoHandlers/handleVerticalVideoSettings.test.js +0 -9
  73. package/lib/src/js/markers/updateLiveMarkers.d.ts +7 -2
  74. package/lib/src/js/playeractions/handlers/mediasessionactions.d.ts +7 -2
  75. package/lib/src/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
  76. package/lib/src/js/playeractions/handlers/processsourceconfig.d.ts +11 -2
  77. package/lib/src/js/playeractions/handlers/removereplayclass.d.ts +1 -1
  78. package/lib/src/js/settings/localization.d.ts +1 -0
  79. package/lib/src/js/utilities/utilities.jwt.d.ts +2 -0
  80. package/lib/src/npoplayer.d.ts +6 -5
  81. package/lib/src/services/chapterHandlers/chapterHandler.d.ts +35 -0
  82. package/lib/src/services/errors/errorHandler.d.ts +4 -2
  83. package/lib/src/services/errors/errorRetryHandler.d.ts +2 -0
  84. package/lib/src/services/errors/errorRetryHandler.test.d.ts +1 -0
  85. package/lib/src/services/infoPanel/infoPanel.d.ts +3 -0
  86. package/lib/src/services/infoPanel/infoPanel.test.d.ts +1 -0
  87. package/lib/src/services/nicamHandlers/nicamhandler.d.ts +1 -0
  88. package/lib/src/services/npoPlayerAPI/npoPlayerAPI.d.ts +8 -2
  89. package/lib/src/services/npoPlayerAPI/playerModules.d.ts +1 -0
  90. package/lib/src/services/segmentHandlers/isSegmentInBounds.d.ts +2 -0
  91. package/lib/src/services/segmentHandlers/isSegmentInBounds.test.d.ts +1 -0
  92. package/lib/src/services/services.d.ts +5 -2
  93. package/lib/src/types/events.d.ts +1 -1
  94. package/lib/src/types/interfaces.d.ts +39 -43
  95. package/lib/src/ui/components/adbutton.d.ts +3 -6
  96. package/lib/src/ui/components/adlabel.d.ts +3 -6
  97. package/lib/src/ui/components/audio/controlbar.d.ts +2 -2
  98. package/lib/src/ui/components/buttons.d.ts +18 -11
  99. package/lib/src/ui/components/ctabar.d.ts +4 -10
  100. package/lib/src/ui/components/infopanel/infopanel.d.ts +3 -0
  101. package/lib/src/ui/components/infopanel/togglebutton.d.ts +3 -0
  102. package/lib/src/ui/components/playnext.d.ts +3 -9
  103. package/lib/src/ui/components/seekbar.d.ts +2 -3
  104. package/lib/src/ui/components/settingspanel.d.ts +2 -3
  105. package/lib/src/ui/components/titlebar.d.ts +2 -2
  106. package/lib/src/ui/handlers/domhandlers.d.ts +2 -2
  107. package/lib/src/ui/handlers/listboxhandlers.d.ts +18 -4
  108. package/lib/src/ui/handlers/playnextscreen.d.ts +6 -2
  109. package/lib/src/ui/uicontainer.d.ts +1 -2
  110. package/lib/tests/jest.setup-files-after-env.d.ts +0 -0
  111. package/lib/tests/jest.setup-files-after-env.js +6 -0
  112. package/lib/tests/jest.setup-tests.d.ts +1 -0
  113. package/lib/tests/jest.setup-tests.js +2 -0
  114. package/lib/tests/mocks/mockNpoplayer.js +27 -44
  115. package/lib/tests/mocks/mockPlayerAPI.d.ts +1 -1
  116. package/lib/tests/mocks/mockPlayerAPI.js +15 -1
  117. package/lib/tests/mocks/mockPlayerUi.d.ts +64 -0
  118. package/lib/tests/mocks/mockPlayerUi.js +251 -0
  119. package/lib/tests/mocks/playerContextMock.d.ts +3 -66
  120. package/lib/tests/mocks/playerContextMock.js +34 -7
  121. package/lib/types/events.d.ts +1 -1
  122. package/lib/types/events.js +1 -1
  123. package/lib/types/interfaces.d.ts +39 -43
  124. package/lib/types/interfaces.js +0 -27
  125. package/lib/ui/components/adbutton.d.ts +3 -6
  126. package/lib/ui/components/adbutton.js +2 -1
  127. package/lib/ui/components/adlabel.d.ts +3 -6
  128. package/lib/ui/components/adlabel.js +2 -1
  129. package/lib/ui/components/audio/controlbar.d.ts +2 -2
  130. package/lib/ui/components/audio/controlbar.js +6 -6
  131. package/lib/ui/components/buttons.d.ts +18 -11
  132. package/lib/ui/components/buttons.js +44 -26
  133. package/lib/ui/components/controlbar.js +13 -9
  134. package/lib/ui/components/ctabar.d.ts +4 -10
  135. package/lib/ui/components/ctabar.js +8 -7
  136. package/lib/ui/components/infopanel/infopanel.d.ts +3 -0
  137. package/lib/ui/components/infopanel/infopanel.js +40 -0
  138. package/lib/ui/components/infopanel/togglebutton.d.ts +3 -0
  139. package/lib/ui/components/infopanel/togglebutton.js +18 -0
  140. package/lib/ui/components/playnext.d.ts +3 -9
  141. package/lib/ui/components/playnext.js +3 -3
  142. package/lib/ui/components/seekbar.d.ts +2 -3
  143. package/lib/ui/components/seekbar.js +7 -3
  144. package/lib/ui/components/settingspanel.d.ts +2 -3
  145. package/lib/ui/components/settingspanel.js +79 -53
  146. package/lib/ui/components/titlebar.d.ts +2 -2
  147. package/lib/ui/components/titlebar.js +2 -1
  148. package/lib/ui/components/topbar.js +8 -5
  149. package/lib/ui/components/verticalvideo/controlbar.js +5 -2
  150. package/lib/ui/components/verticalvideo/settingspanel.js +9 -5
  151. package/lib/ui/handlers/accessibilityhandler.js +11 -22
  152. package/lib/ui/handlers/accessibilityhandler.test.js +25 -34
  153. package/lib/ui/handlers/domhandlers.d.ts +2 -2
  154. package/lib/ui/handlers/listboxhandlers.d.ts +18 -4
  155. package/lib/ui/handlers/listboxhandlers.js +5 -3
  156. package/lib/ui/handlers/playnextscreen.d.ts +6 -2
  157. package/lib/ui/handlers/playnextscreen.js +4 -4
  158. package/lib/ui/handlers/playnextscreen.test.js +15 -3
  159. package/lib/ui/uicontainer.d.ts +1 -2
  160. package/lib/ui/uicontainer.js +24 -8
  161. package/lib/ui/uicontainer.test.js +6 -5
  162. package/package.json +7 -9
  163. package/src/style/components/_advert.scss +0 -4
  164. package/src/style/components/_buffering.scss +18 -22
  165. package/src/style/components/_controlbars.scss +0 -4
  166. package/src/style/components/_icons.scss +18 -4
  167. package/src/style/components/_infopanel.scss +99 -0
  168. package/src/style/components/_nicam.scss +6 -2
  169. package/src/style/components/_seekbarthumbnail.scss +5 -0
  170. package/src/style/components/_settingspanel.scss +1 -1
  171. package/src/style/components/_subtitles.scss +0 -1
  172. package/src/style/components/_textbuttons.scss +30 -1
  173. package/src/style/components/_volumeslider.scss +0 -1
  174. package/src/style/components/audio/_bottombar.scss +6 -0
  175. package/src/style/components/audio/_metadata.scss +25 -9
  176. package/src/style/components/audio/_topbar.scss +6 -1
  177. package/src/style/npoplayer.css +166 -83
  178. package/src/style/npoplayer.scss +10 -2
  179. package/src/style/variants/_player-audio-only.scss +32 -0
  180. package/src/style/variants/_player-base.scss +5 -1
  181. package/src/style/variants/_player-large.scss +3 -3
  182. package/src/style/variants/_player-medium.scss +5 -1
  183. package/src/style/variants/_player-small.scss +6 -1
  184. package/src/style/vars/_colors.scss +1 -1
  185. package/src/style/vars/_icons.scss +5 -4
  186. package/src/style/vars/_z-index.scss +1 -1
  187. package/lib/npoplayer-bridge.test.js +0 -24
  188. package/lib/src/ui/components/nativemobile/buttons.d.ts +0 -30
  189. package/lib/src/ui/components/nativemobile/controlbar.d.ts +0 -3
  190. package/lib/src/ui/components/nativemobile/ctabar.d.ts +0 -11
  191. package/lib/src/ui/components/nativemobile/titlebar.d.ts +0 -2
  192. package/lib/src/ui/components/nativemobile/topbar.d.ts +0 -3
  193. package/lib/src/ui/nativemobileuicontainer.d.ts +0 -5
  194. package/lib/src/ui/nativemobileuifactory.d.ts +0 -3
  195. package/lib/src/ui/nativemobileuifactory.test.d.ts +0 -1
  196. package/lib/ui/components/nativemobile/buttons.d.ts +0 -30
  197. package/lib/ui/components/nativemobile/buttons.js +0 -233
  198. package/lib/ui/components/nativemobile/controlbar.d.ts +0 -3
  199. package/lib/ui/components/nativemobile/controlbar.js +0 -43
  200. package/lib/ui/components/nativemobile/ctabar.d.ts +0 -11
  201. package/lib/ui/components/nativemobile/ctabar.js +0 -10
  202. package/lib/ui/components/nativemobile/titlebar.d.ts +0 -2
  203. package/lib/ui/components/nativemobile/titlebar.js +0 -7
  204. package/lib/ui/components/nativemobile/topbar.d.ts +0 -3
  205. package/lib/ui/components/nativemobile/topbar.js +0 -23
  206. package/lib/ui/nativemobileuicontainer.d.ts +0 -5
  207. package/lib/ui/nativemobileuicontainer.js +0 -42
  208. package/lib/ui/nativemobileuifactory.d.ts +0 -3
  209. package/lib/ui/nativemobileuifactory.js +0 -112
  210. package/lib/ui/nativemobileuifactory.test.d.ts +0 -1
  211. package/lib/ui/nativemobileuifactory.test.js +0 -64
  212. package/src/style/variants/_player-native-mobile.scss +0 -13
  213. /package/lib/{npoplayer-bridge.test.d.ts → services/errors/errorHandler.test.d.ts} +0 -0
  214. /package/lib/src/{npoplayer-bridge.test.d.ts → services/errors/errorHandler.test.d.ts} +0 -0
@@ -4,6 +4,7 @@ import { createUIContainer } from '../../ui/uicontainer';
4
4
  import { playerEventMap } from '../../types/events';
5
5
  import { VOLUME_MAX, VOLUME_MIN, VOLUME_STEP } from './contants';
6
6
  import { localizationConfig } from '../../js/settings/localization';
7
+ import { handleErrorRetry } from '../../services/errors/errorRetryHandler';
7
8
  const externalCallbacksMap = new WeakMap();
8
9
  export class NpoPlayerAPI {
9
10
  constructor(playerAPI) {
@@ -57,17 +58,19 @@ export class NpoPlayerAPI {
57
58
  return this.playerAPI.getViewMode();
58
59
  }
59
60
  areSubtitlesEnabled() {
60
- return this.playerAPI.subtitles.list().some((subtitle) => subtitle.enabled);
61
+ const subtitles = this.listSubtitles();
62
+ return subtitles ? subtitles.some((subtitle) => subtitle.enabled) : false;
61
63
  }
62
64
  getCurrentSubtitle() {
63
- const currentSubtitle = this.playerAPI.subtitles.list().find((subtitle) => subtitle.enabled);
65
+ const subtitles = this.listSubtitles();
66
+ const currentSubtitle = subtitles.find((subtitle) => subtitle.enabled);
64
67
  return currentSubtitle ? currentSubtitle.lang : undefined;
65
68
  }
66
69
  enableSubtitles(selectedLang = 'nl') {
67
- const subtitleTracks = this.playerAPI.subtitles.list();
70
+ const subtitleTracks = this.listSubtitles();
68
71
  const subtitleToEnable = subtitleTracks.find((subtitle) => subtitle.lang === selectedLang);
69
72
  if (subtitleToEnable && !subtitleToEnable.enabled) {
70
- this.playerAPI.subtitles.enable(subtitleToEnable.id);
73
+ this.playerAPI.subtitles?.enable(subtitleToEnable.id);
71
74
  }
72
75
  }
73
76
  isPaused() {
@@ -80,7 +83,7 @@ export class NpoPlayerAPI {
80
83
  return this.playerAPI.isLive();
81
84
  }
82
85
  async getSupportedDRM() {
83
- return (await this.playerAPI.getSupportedDRM());
86
+ return await this.playerAPI.getSupportedDRM();
84
87
  }
85
88
  getSupportedTech() {
86
89
  return this.playerAPI.getSupportedTech();
@@ -143,12 +146,8 @@ export class NpoPlayerAPI {
143
146
  async scheduleAds(adConfig) {
144
147
  return this.playerAPI.ads.schedule(adConfig);
145
148
  }
146
- handleErrorRetry(playerContext) {
147
- if (playerContext.npoPlayer.streamOptions.retryCallback === undefined) {
148
- console.error('No retry callback found in stream options');
149
- return;
150
- }
151
- return playerContext.npoPlayer.streamOptions.retryCallback();
149
+ async handleErrorRetry(playerContext) {
150
+ return handleErrorRetry(playerContext);
152
151
  }
153
152
  getActiveAdBreak() {
154
153
  return this.playerAPI.ads.getActiveAdBreak();
@@ -168,12 +167,26 @@ export class NpoPlayerAPI {
168
167
  npoPlayerServices.removeUivisiblityHandlers(playerContext);
169
168
  playerContext.npoPlayer.uiManager?.release();
170
169
  UIManager.setLocalizationConfig(localizationConfig);
171
- const uiManager = new UIManager(this.playerAPI, createUIContainer(playerContext, this.playerAPI, variant), uiConfig);
170
+ const uiContainer = createUIContainer(playerContext, variant);
171
+ const uiManager = new UIManager(this.playerAPI, uiContainer, uiConfig);
172
172
  playerContext.npoPlayer.uiManager = uiManager;
173
173
  playerContext.npoPlayer.variant = variant;
174
174
  npoPlayerServices.addUivisiblityHandlers(playerContext);
175
175
  npoPlayerServices.setupNicamKijkwijzerIcons(playerContext);
176
176
  npoPlayerServices.showNicamAfterUiDelay(playerContext);
177
+ npoPlayerServices.addDataInInfoPanel(playerContext);
177
178
  }
178
179
  }
180
+ getAvailableVideoQualities() {
181
+ return this.playerAPI.getAvailableVideoQualities();
182
+ }
183
+ listSubtitles() {
184
+ return this.playerAPI.subtitles?.list() || [];
185
+ }
186
+ setPlaybackSpeed(speed) {
187
+ this.playerAPI.setPlaybackSpeed(speed);
188
+ }
189
+ setVideoQuality(VideoQualityId) {
190
+ this.playerAPI.setVideoQuality(VideoQualityId);
191
+ }
179
192
  }
@@ -0,0 +1 @@
1
+ export declare const playerModules: any[];
@@ -0,0 +1,46 @@
1
+ import EngineBitmovinModule from 'bitmovin-player/modules/bitmovinplayer-engine-bitmovin';
2
+ import EngineNativeModule from 'bitmovin-player/modules/bitmovinplayer-engine-native';
3
+ import MseRendererModule from 'bitmovin-player/modules/bitmovinplayer-mserenderer';
4
+ import DashModule from 'bitmovin-player/modules/bitmovinplayer-dash';
5
+ import ContainerMP4 from 'bitmovin-player/modules/bitmovinplayer-container-mp4';
6
+ import ContainerTS from 'bitmovin-player/modules/bitmovinplayer-container-ts';
7
+ import AbrModule from 'bitmovin-player/modules/bitmovinplayer-abr';
8
+ import DrmModule from 'bitmovin-player/modules/bitmovinplayer-drm';
9
+ import XmlModule from 'bitmovin-player/modules/bitmovinplayer-xml';
10
+ import Subtitles from 'bitmovin-player/modules/bitmovinplayer-subtitles';
11
+ import SubtitlesWebVTT from 'bitmovin-player/modules/bitmovinplayer-subtitles-vtt';
12
+ import SubtitlesCEA608 from 'bitmovin-player/modules/bitmovinplayer-subtitles-cea608';
13
+ import SubtitlesTTML from 'bitmovin-player/modules/bitmovinplayer-subtitles-ttml';
14
+ import SubtitlesNative from 'bitmovin-player/modules/bitmovinplayer-subtitles-native';
15
+ import AdvertisingCoreModule from 'bitmovin-player/modules/bitmovinplayer-advertising-core';
16
+ import AdvertisingBitmovinModule from 'bitmovin-player/modules/bitmovinplayer-advertising-bitmovin';
17
+ import AnalyticsModule from 'bitmovin-player/modules/bitmovinplayer-analytics';
18
+ import HlsModule from 'bitmovin-player/modules/bitmovinplayer-hls';
19
+ import StyleModule from 'bitmovin-player/modules/bitmovinplayer-style';
20
+ import CryptoModule from 'bitmovin-player/modules/bitmovinplayer-crypto';
21
+ import PatchModule from 'bitmovin-player/modules/bitmovinplayer-patch';
22
+ import ThumbnailModule from 'bitmovin-player/modules/bitmovinplayer-thumbnail';
23
+ export const playerModules = [
24
+ EngineBitmovinModule,
25
+ EngineNativeModule,
26
+ XmlModule,
27
+ MseRendererModule,
28
+ AbrModule,
29
+ HlsModule,
30
+ DrmModule,
31
+ DashModule,
32
+ ContainerMP4,
33
+ ContainerTS,
34
+ CryptoModule,
35
+ PatchModule,
36
+ Subtitles,
37
+ SubtitlesCEA608,
38
+ SubtitlesWebVTT,
39
+ SubtitlesTTML,
40
+ SubtitlesNative,
41
+ StyleModule,
42
+ AdvertisingCoreModule,
43
+ AdvertisingBitmovinModule,
44
+ AnalyticsModule,
45
+ ThumbnailModule
46
+ ];
@@ -3,7 +3,7 @@ import { LocalStorageValues } from '../../types/interfaces';
3
3
  export function handlePreferences(playerContext) {
4
4
  const { player, npoPlayer } = playerContext;
5
5
  const { npoPlayerServices } = npoPlayer;
6
- const handleSourceLoaded = () => {
6
+ const handleReady = () => {
7
7
  const storedUserPrefs = npoPlayerServices.getStoredUserPrefs();
8
8
  const subtitlesEnabledInPrefs = storedUserPrefs?.subtitles_enabled === 'true';
9
9
  const preferredSubtitleLang = storedUserPrefs?.subtitles_language?.toString();
@@ -13,8 +13,8 @@ export function handlePreferences(playerContext) {
13
13
  }
14
14
  };
15
15
  const handleSubtitleEnabled = () => {
16
- const currentSubtitleTrack = player.playerAPI.subtitles.list();
17
- const enabledSubtitle = currentSubtitleTrack.find((subtitle) => subtitle.enabled);
16
+ const subtitlesList = player.listSubtitles();
17
+ const enabledSubtitle = subtitlesList.find((subtitle) => subtitle.enabled);
18
18
  if (enabledSubtitle) {
19
19
  npoPlayerServices.setStoredUserPrefs(LocalStorageValues.SUBTITLES_LANGUAGE, enabledSubtitle.lang);
20
20
  npoPlayerServices.setStoredUserPrefs(LocalStorageValues.SUBTITLES_ENABLED, 'true');
@@ -29,11 +29,16 @@ export function handlePreferences(playerContext) {
29
29
  };
30
30
  const handleMuted = () => {
31
31
  npoPlayerServices.setStoredUserPrefs(LocalStorageValues.IS_MUTED, 'true');
32
+ const volume = player.getVolume();
33
+ if (volume === 0) {
34
+ player.setVolume(100);
35
+ player.mute();
36
+ }
32
37
  };
33
38
  const handleUnmuted = () => {
34
39
  npoPlayerServices.setStoredUserPrefs(LocalStorageValues.IS_MUTED, 'false');
35
40
  };
36
- player.on(NpoPlayerEvent.SourceLoaded, handleSourceLoaded);
41
+ player.on(NpoPlayerEvent.Ready, handleReady);
37
42
  player.on(NpoPlayerEvent.SubtitleEnabled, handleSubtitleEnabled);
38
43
  player.on(NpoPlayerEvent.SubtitleDisabled, handleSubtitleDisabled);
39
44
  player.on(NpoPlayerEvent.VolumeChanged, handleVolumeChanged);
@@ -2,20 +2,14 @@ import createPlayerContextMock, { createMockNpoPlayer, createMockNpoPlayerAPI }
2
2
  import { handlePreferences } from './handlePreferences';
3
3
  import { NpoPlayerEvent } from '../../types/events';
4
4
  import { LocalStorageValues } from '../../types/interfaces';
5
+ const setupServicesErrorMessage = 'mockNpoPlayer.npoPlayerServices is undefined, test setup is incorrect';
6
+ const setupStreamOptionsErrorMessage = 'mockNpoPlayer.streamOptions is undefined, test setup is incorrect';
5
7
  describe('handlePreferences', () => {
6
8
  let mockPlayerAPI;
7
9
  let mockNpoPlayer;
10
+ let playerContextMock;
8
11
  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
- });
12
+ mockPlayerAPI = createMockNpoPlayerAPI();
19
13
  mockNpoPlayer = createMockNpoPlayer({
20
14
  streamOptions: {
21
15
  enableSubtitles: false
@@ -28,42 +22,54 @@ describe('handlePreferences', () => {
28
22
  setStoredUserPrefs: jest.fn()
29
23
  }
30
24
  });
31
- const playerContextMock = createPlayerContextMock({
25
+ playerContextMock = createPlayerContextMock({
32
26
  player: mockPlayerAPI,
33
27
  npoPlayer: mockNpoPlayer
34
28
  });
35
29
  handlePreferences(playerContextMock);
36
30
  });
37
31
  test('should enable subtitles if streamOptions.enableSubtitles is true', () => {
32
+ if (!mockNpoPlayer.streamOptions) {
33
+ throw new Error(setupStreamOptionsErrorMessage);
34
+ }
38
35
  mockNpoPlayer.streamOptions.enableSubtitles = true;
39
36
  for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
40
- if (event === NpoPlayerEvent.SourceLoaded) {
41
- callback(NpoPlayerEvent.SourceLoaded);
37
+ if (event === NpoPlayerEvent.Ready) {
38
+ callback(NpoPlayerEvent.Ready);
42
39
  }
43
40
  }
44
41
  expect(mockPlayerAPI.enableSubtitles).toHaveBeenCalledWith('nl');
45
42
  });
46
43
  test('should enable subtitles if subtitles_enabled in preferences is true', () => {
44
+ if (!mockNpoPlayer.streamOptions) {
45
+ throw new Error(setupStreamOptionsErrorMessage);
46
+ }
47
+ if (!mockNpoPlayer.npoPlayerServices) {
48
+ throw new Error(setupServicesErrorMessage);
49
+ }
47
50
  mockNpoPlayer.streamOptions.enableSubtitles = false;
48
51
  mockNpoPlayer.npoPlayerServices.getStoredUserPrefs.mockReturnValueOnce({
49
52
  subtitles_enabled: 'true',
50
53
  subtitles_language: 'nl'
51
54
  });
52
55
  for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
53
- if (event === NpoPlayerEvent.SourceLoaded) {
54
- callback(NpoPlayerEvent.SourceLoaded);
56
+ if (event === NpoPlayerEvent.Ready) {
57
+ callback(NpoPlayerEvent.Ready);
55
58
  }
56
59
  }
57
60
  expect(mockPlayerAPI.enableSubtitles).toHaveBeenCalledWith('nl');
58
61
  });
59
62
  test('should disable subtitles and set the preferences', () => {
60
63
  ;
61
- mockPlayerAPI.playerAPI.subtitles.list.mockReturnValueOnce([{ lang: 'nl', enabled: true }]);
64
+ mockPlayerAPI.listSubtitles.mockReturnValueOnce([{ lang: 'nl', enabled: true }]);
62
65
  for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
63
66
  if (event === NpoPlayerEvent.SubtitleEnabled) {
64
67
  callback(NpoPlayerEvent.SubtitleEnable);
65
68
  }
66
69
  }
70
+ if (!mockNpoPlayer.npoPlayerServices) {
71
+ throw new Error(setupServicesErrorMessage);
72
+ }
67
73
  expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.SUBTITLES_LANGUAGE, 'nl');
68
74
  expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.SUBTITLES_ENABLED, 'true');
69
75
  });
@@ -73,6 +79,9 @@ describe('handlePreferences', () => {
73
79
  callback(NpoPlayerEvent.SubtitleDisabled);
74
80
  }
75
81
  }
82
+ if (!mockNpoPlayer.npoPlayerServices) {
83
+ throw new Error(setupServicesErrorMessage);
84
+ }
76
85
  expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.SUBTITLES_ENABLED, 'false');
77
86
  });
78
87
  test('should set volume preferences', () => {
@@ -81,15 +90,39 @@ describe('handlePreferences', () => {
81
90
  callback(NpoPlayerEvent.VolumeChanged);
82
91
  }
83
92
  }
93
+ if (!mockNpoPlayer.npoPlayerServices) {
94
+ throw new Error(setupServicesErrorMessage);
95
+ }
84
96
  expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.VOLUME, 50);
85
97
  });
86
- test('should set muted preferences', () => {
98
+ test('should set muted preferences with volume > 0', () => {
87
99
  for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
88
100
  if (event === NpoPlayerEvent.Muted) {
89
101
  callback(NpoPlayerEvent.Muted);
90
102
  }
91
103
  }
104
+ if (!mockNpoPlayer.npoPlayerServices) {
105
+ throw new Error(setupServicesErrorMessage);
106
+ }
92
107
  expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.IS_MUTED, 'true');
108
+ expect(mockPlayerAPI.getVolume).toHaveBeenCalled();
109
+ expect(mockPlayerAPI.setVolume).not.toHaveBeenCalled();
110
+ });
111
+ test('should set muted preferences and reset volume when volume === 0', () => {
112
+ ;
113
+ mockPlayerAPI.getVolume.mockReturnValueOnce(0);
114
+ for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
115
+ if (event === NpoPlayerEvent.Muted) {
116
+ callback(NpoPlayerEvent.Muted);
117
+ }
118
+ }
119
+ if (!mockNpoPlayer.npoPlayerServices) {
120
+ throw new Error(setupServicesErrorMessage);
121
+ }
122
+ expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.IS_MUTED, 'true');
123
+ expect(mockPlayerAPI.getVolume).toHaveBeenCalled();
124
+ expect(mockPlayerAPI.setVolume).toHaveBeenCalledWith(100);
125
+ expect(mockPlayerAPI.mute).toHaveBeenCalled();
93
126
  });
94
127
  test('should set unmuted preferences', () => {
95
128
  for (const [event, callback] of mockPlayerAPI.on.mock.calls) {
@@ -97,6 +130,9 @@ describe('handlePreferences', () => {
97
130
  callback(NpoPlayerEvent.Unmuted);
98
131
  }
99
132
  }
133
+ if (!mockNpoPlayer.npoPlayerServices) {
134
+ throw new Error(setupServicesErrorMessage);
135
+ }
100
136
  expect(mockNpoPlayer.npoPlayerServices.setStoredUserPrefs).toHaveBeenCalledWith(LocalStorageValues.IS_MUTED, 'false');
101
137
  });
102
138
  });
@@ -1,4 +1,4 @@
1
- import { PlayerEvent } from 'bitmovin-player';
1
+ import { PlayerEvent } from 'bitmovin-player/modules/bitmovinplayer-core';
2
2
  import { addSegmentEventListeners } from './addSegmentEventListeners';
3
3
  import { handleSegmentTimeChanged } from './handleSegmentTimeChanged';
4
4
  import { handleSegmentSeek } from './handleSegmentSeek';
@@ -0,0 +1,2 @@
1
+ import { Segment } from 'types/interfaces';
2
+ export declare function isSegmentInBounds(segment: Segment | undefined, duration: number): boolean;
@@ -0,0 +1,5 @@
1
+ export function isSegmentInBounds(segment, duration) {
2
+ if (!segment)
3
+ return true;
4
+ return segment.inpoint < duration && segment.outpoint < duration;
5
+ }
@@ -0,0 +1,27 @@
1
+ import { isSegmentInBounds } from './isSegmentInBounds';
2
+ describe('isSegmentInBounds', () => {
3
+ const DUMMY_DURATION = 100;
4
+ it('returns true if segment is undefined', () => {
5
+ expect(isSegmentInBounds(undefined, DUMMY_DURATION)).toBe(true);
6
+ });
7
+ it('returns true if inpoint and outpoint are within duration', () => {
8
+ const segment = { inpoint: 10, outpoint: 50, duration: 40 };
9
+ expect(isSegmentInBounds(segment, DUMMY_DURATION)).toBe(true);
10
+ });
11
+ it('returns false if inpoint is greater than or equal to duration', () => {
12
+ const segment = { inpoint: 100, outpoint: 110, duration: 10 };
13
+ expect(isSegmentInBounds(segment, DUMMY_DURATION)).toBe(false);
14
+ });
15
+ it('returns false if outpoint is greater than or equal to duration', () => {
16
+ const segment = { inpoint: 10, outpoint: 120, duration: 110 };
17
+ expect(isSegmentInBounds(segment, DUMMY_DURATION)).toBe(false);
18
+ });
19
+ it('returns false if both inpoint and outpoint are greater than duration', () => {
20
+ const segment = { inpoint: 150, outpoint: 200, duration: 50 };
21
+ expect(isSegmentInBounds(segment, DUMMY_DURATION)).toBe(false);
22
+ });
23
+ it('returns false if outpoint is equal to duration', () => {
24
+ const segment = { inpoint: 10, outpoint: 100, duration: 90 };
25
+ expect(isSegmentInBounds(segment, DUMMY_DURATION)).toBe(false);
26
+ });
27
+ });
@@ -1,4 +1,4 @@
1
- import { ApiPayload, Fragment, PlayerContext, Profile, Segment, TimeLineMarker, LocalStorageData, LocalStorageValues, StreamObject, PlayerTrackerParams, LogEventParams } from '../types/interfaces';
1
+ import { ApiPayload, Fragment, PlayerContext, Profile, Segment, TimeLineMarker, LocalStorageData, LocalStorageValues, StreamObject, PlayerTrackerParams, LogEventParams, LogErrorParams } from '../types/interfaces';
2
2
  import { AVType } from '@npotag/tag/dist/types/src/streamTracker';
3
3
  export declare class NpoPlayerServices {
4
4
  getAVType(avType: string): AVType;
@@ -21,10 +21,13 @@ export declare class NpoPlayerServices {
21
21
  addUivisiblityHandlers(playerContext: PlayerContext): void;
22
22
  removeUivisiblityHandlers(playerContext: PlayerContext): void;
23
23
  handleStreamOptions(playerContext: PlayerContext): void;
24
- handleError(playerContext: PlayerContext, input: number): Promise<void>;
24
+ handleError({ playerContext, status: input, context: context }: LogErrorParams): Promise<void>;
25
25
  fetchStream(playerContext: PlayerContext, payload: ApiPayload): Promise<StreamObject>;
26
26
  startPlayerTracker({ playerContext, source, duration }: PlayerTrackerParams): void;
27
27
  initPlayerTracker(playerContext: PlayerContext): void;
28
28
  logEvent({ playerContext, event, data }: LogEventParams): void;
29
29
  removeEventListeners(playerContext: PlayerContext): void;
30
+ isSegmentInBounds(playerContext: PlayerContext): boolean;
31
+ addDataInInfoPanel(playerContext: PlayerContext): void;
32
+ clearInfoPanel(playerContext: PlayerContext): void;
30
33
  }
@@ -17,6 +17,8 @@ import { handlePlayerError } from './errors/errorHandler';
17
17
  import { fetchStream } from './streamFetchHandler/fetchStream';
18
18
  import { startPlayerTracker, initPlayerTracker, logEvent } from './trackingHandlers';
19
19
  import { removeEventListeners } from './eventListenerHandlers/removeEventListeners';
20
+ import { isSegmentInBounds } from './segmentHandlers/isSegmentInBounds';
21
+ import { addDataInInfoPanel, clearInfoPanel } from './infoPanel/infoPanel';
20
22
  export class NpoPlayerServices {
21
23
  getAVType(avType) {
22
24
  return getAVType(avType);
@@ -86,8 +88,8 @@ export class NpoPlayerServices {
86
88
  handleStreamOptions(playerContext) {
87
89
  handleStreamOptions(playerContext);
88
90
  }
89
- async handleError(playerContext, input) {
90
- await handlePlayerError(playerContext, input);
91
+ async handleError({ playerContext, status: input, context: context }) {
92
+ await handlePlayerError({ playerContext, status: input, context: context });
91
93
  }
92
94
  async fetchStream(playerContext, payload) {
93
95
  return await fetchStream(playerContext, payload);
@@ -108,4 +110,15 @@ export class NpoPlayerServices {
108
110
  removeEventListeners(playerContext) {
109
111
  removeEventListeners(playerContext);
110
112
  }
113
+ isSegmentInBounds(playerContext) {
114
+ const segment = playerContext.npoPlayer.streamObject.segment;
115
+ const duration = playerContext.player.getDuration();
116
+ return isSegmentInBounds(segment, duration);
117
+ }
118
+ addDataInInfoPanel(playerContext) {
119
+ addDataInInfoPanel(playerContext);
120
+ }
121
+ clearInfoPanel(playerContext) {
122
+ clearInfoPanel(playerContext);
123
+ }
111
124
  }
@@ -3,10 +3,10 @@ export async function fetchStream(playerContext, payload) {
3
3
  const { npoPlayer } = playerContext;
4
4
  const genericError = 'Dit item on niet worden geladen.';
5
5
  let hasHandledError = false;
6
- const handleStreamError = async (status, message) => {
6
+ const handleStreamError = async ({ status, message, context }) => {
7
7
  if (!hasHandledError) {
8
8
  hasHandledError = true;
9
- await npoPlayer.npoPlayerServices.handleError(playerContext, status);
9
+ await npoPlayer.npoPlayerServices.handleError({ playerContext, status, context });
10
10
  }
11
11
  throw new Error(message);
12
12
  };
@@ -33,7 +33,8 @@ export async function fetchStream(playerContext, payload) {
33
33
  }
34
34
  else {
35
35
  const status = streamApiResponse?.status || 500;
36
- return await handleStreamError(status, genericError);
36
+ const context = streamApiResponse?.context || undefined;
37
+ return await handleStreamError({ status, message: genericError, context });
37
38
  }
38
39
  }
39
40
  catch (error) {
@@ -41,7 +42,7 @@ export async function fetchStream(playerContext, payload) {
41
42
  const errorMessage = error instanceof Error && error.message === 'AbortError'
42
43
  ? 'aborterror'
43
44
  : 'Dit item on niet worden geladen. Het ophalen van de stream duurde te lang.';
44
- return await handleStreamError(500, errorMessage);
45
+ return await handleStreamError({ status: 500, message: errorMessage });
45
46
  }
46
47
  throw error;
47
48
  }
@@ -1,5 +1,6 @@
1
1
  import { fetchStream } from './fetchStream';
2
2
  import { createMockNpoPlayer, createPlayerContextMock } from '../../../tests/mocks/playerContextMock';
3
+ const setupServicesErrorMessage = 'mockNpoPlayer.npoPlayerServices is undefined, test setup is incorrect';
3
4
  describe('fetchStream', () => {
4
5
  let mockPlayerContext;
5
6
  let mockNpoPlayer;
@@ -35,6 +36,9 @@ describe('fetchStream', () => {
35
36
  }),
36
37
  body: JSON.stringify(mockPayload.data)
37
38
  }));
39
+ if (!mockNpoPlayer.npoPlayerServices) {
40
+ throw new Error(setupServicesErrorMessage);
41
+ }
38
42
  expect(mockNpoPlayer.npoPlayerServices.handleError).not.toHaveBeenCalled();
39
43
  });
40
44
  it('calls handleError with 402 status and throws an error', async () => {
@@ -43,17 +47,35 @@ describe('fetchStream', () => {
43
47
  json: jest.fn().mockResolvedValue({ status: 402 })
44
48
  });
45
49
  await expect(fetchStream(mockPlayerContext, mockPayload)).rejects.toThrow('Dit item on niet worden geladen.');
46
- expect(mockNpoPlayer.npoPlayerServices.handleError).toHaveBeenCalledWith(mockPlayerContext, 402);
50
+ if (!mockNpoPlayer.npoPlayerServices) {
51
+ throw new Error(setupServicesErrorMessage);
52
+ }
53
+ expect(mockNpoPlayer.npoPlayerServices.handleError).toHaveBeenCalledWith({
54
+ playerContext: mockPlayerContext,
55
+ status: 402
56
+ });
47
57
  });
48
58
  it('calls handleError with 500 for timeout (AbortError)', async () => {
49
59
  global.fetch = jest.fn().mockImplementation(() => new Promise((_, reject) => reject(new Error('AbortError'))));
50
60
  await expect(fetchStream(mockPlayerContext, mockPayload)).rejects.toThrow('aborterror');
51
- expect(mockNpoPlayer.npoPlayerServices.handleError).toHaveBeenCalledWith(mockPlayerContext, 500);
61
+ if (!mockNpoPlayer.npoPlayerServices) {
62
+ throw new Error(setupServicesErrorMessage);
63
+ }
64
+ expect(mockNpoPlayer.npoPlayerServices.handleError).toHaveBeenCalledWith({
65
+ playerContext: mockPlayerContext,
66
+ status: 500
67
+ });
52
68
  });
53
69
  it('calls handleError with 500 for unexpected errors', async () => {
54
70
  global.fetch = jest.fn().mockRejectedValue(new Error('Unexpected error'));
55
71
  await expect(fetchStream(mockPlayerContext, mockPayload)).rejects.toThrow('Dit item on niet worden geladen. Het ophalen van de stream duurde te lang.');
56
- expect(mockNpoPlayer.npoPlayerServices.handleError).toHaveBeenCalledWith(mockPlayerContext, 500);
72
+ if (!mockNpoPlayer.npoPlayerServices) {
73
+ throw new Error(setupServicesErrorMessage);
74
+ }
75
+ expect(mockNpoPlayer.npoPlayerServices.handleError).toHaveBeenCalledWith({
76
+ playerContext: mockPlayerContext,
77
+ status: 500
78
+ });
57
79
  });
58
80
  it('clears the timeout if fetch resolves before timeout', async () => {
59
81
  jest.useFakeTimers();
@@ -4,12 +4,13 @@ import { handleLiveStreamControls } from '../liveStreamHandlers/handleLiveStream
4
4
  import { NpoPlayerEvent } from '../../types/events';
5
5
  import { updateClassFromElementByQuery } from '../../js/utilities/utilities.element';
6
6
  export function handleStreamOptions(playerContext) {
7
- const { streamObject, uiManager } = playerContext.npoPlayer;
7
+ const { streamObject, uiManager, npoPlayerServices } = playerContext.npoPlayer;
8
8
  if (!streamObject || !uiManager)
9
9
  return;
10
10
  initializeFragment(playerContext);
11
11
  handleStartOffset(playerContext);
12
12
  updateStreamClasses(playerContext);
13
+ npoPlayerServices.addDataInInfoPanel(playerContext);
13
14
  const isAutoplayEnabled = getAutoplayStatus(playerContext);
14
15
  if (isAutoplayEnabled) {
15
16
  setupAutoplay(playerContext);
@@ -29,27 +30,28 @@ export function handleStartOffset(playerContext) {
29
30
  }
30
31
  }
31
32
  export function updateStreamClasses(playerContext) {
32
- const { streamObject, container } = playerContext.npoPlayer;
33
+ const { npoPlayer } = playerContext;
34
+ const { streamObject, container } = npoPlayer;
35
+ const { isLiveStream, hasDvrWindow, avType } = streamObject.stream;
33
36
  const containerClassString = '.bmpui-ui-uicontainer';
34
- const playerContainer = container;
35
37
  const queries = [
36
38
  {
37
- container: playerContainer,
39
+ container,
38
40
  query: containerClassString,
39
41
  className: 'livestream-no-dvr',
40
- condition: !!(streamObject.stream.isLiveStream && !streamObject.stream.hasDvrWindow)
42
+ condition: !!(isLiveStream && !hasDvrWindow)
41
43
  },
42
44
  {
43
- container: playerContainer,
45
+ container,
44
46
  query: containerClassString,
45
47
  className: 'audio-only',
46
- condition: !!(streamObject.stream.avType === 'aod' || streamObject.stream.avType === 'audio')
48
+ condition: avType === 'aod' || avType === 'audio'
47
49
  },
48
50
  {
49
- container: playerContainer,
51
+ container,
50
52
  query: '.bitmovinplayer-poster',
51
53
  className: 'audio-only',
52
- condition: !!(streamObject.stream.avType === 'aod' || streamObject.stream.avType === 'audio')
54
+ condition: avType === 'aod' || avType === 'audio'
53
55
  }
54
56
  ];
55
57
  for (const query of queries)
@@ -47,10 +47,11 @@ describe('handleStreamOptions', () => {
47
47
  expect(handleStartOffset(playerContextMock)).toHaveBeenCalled;
48
48
  expect(updateStreamClasses(playerContextMock)).toHaveBeenCalled;
49
49
  expect(setupAutoplay(playerContextMock)).toHaveBeenCalled;
50
+ expect(playerContextMock.npoPlayer.npoPlayerServices.addDataInInfoPanel(playerContextMock)).toHaveBeenCalled;
50
51
  });
51
52
  it('should return early if uiManager is missing', () => {
52
53
  const npoPlayerMock = createMockNpoPlayer({
53
- UIManager: null
54
+ UIManager: undefined
54
55
  });
55
56
  const playerContextMock = createPlayerContextMock({
56
57
  npoPlayer: npoPlayerMock
@@ -60,7 +61,7 @@ describe('handleStreamOptions', () => {
60
61
  });
61
62
  it('should return early if streamObject is missing', () => {
62
63
  const npoPlayerMock = createMockNpoPlayer({
63
- streamObject: null
64
+ streamObject: undefined
64
65
  });
65
66
  const playerContextMock = createPlayerContextMock({
66
67
  npoPlayer: npoPlayerMock
@@ -119,6 +120,17 @@ describe('handleStreamOptions', () => {
119
120
  });
120
121
  updateStreamClasses(playerContextMock);
121
122
  expect(updateClassFromElementByQuery).toHaveBeenCalledWith(expect.objectContaining({
123
+ query: '.bmpui-ui-uicontainer',
124
+ className: 'livestream-no-dvr',
125
+ condition: false
126
+ }));
127
+ expect(updateClassFromElementByQuery).toHaveBeenCalledWith(expect.objectContaining({
128
+ query: '.bmpui-ui-uicontainer',
129
+ className: 'audio-only',
130
+ condition: true
131
+ }));
132
+ expect(updateClassFromElementByQuery).toHaveBeenCalledWith(expect.objectContaining({
133
+ query: '.bitmovinplayer-poster',
122
134
  className: 'audio-only',
123
135
  condition: true
124
136
  }));