@npo/player 1.23.1 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/js/playeractions/handlers/error.js +2 -2
- package/lib/js/playeractions/handlers/error.test.js +2 -2
- package/lib/js/playeractions/handlers/handleoffsets.d.ts +4 -6
- package/lib/js/playeractions/handlers/handleoffsets.js +16 -17
- package/lib/js/playeractions/handlers/handleoffsets.test.js +73 -29
- package/lib/js/playeractions/handlers/mediasessionactions.js +24 -12
- package/lib/js/playeractions/handlers/processsourceconfig.js +16 -3
- package/lib/js/tracking/handlers/eventbinding.d.ts +1 -1
- package/lib/js/tracking/handlers/eventbinding.js +17 -23
- package/lib/js/tracking/handlers/eventlogging.d.ts +1 -1
- package/lib/js/tracking/handlers/eventlogging.js +18 -18
- package/lib/js/tracking/handlers/eventlogging.test.js +24 -24
- package/lib/js/tracking/handlers/playertrackerstart.js +4 -2
- package/lib/lang/nl.json +3 -1
- package/lib/npoplayer.d.ts +1 -2
- package/lib/npoplayer.js +27 -46
- package/lib/package.json +5 -5
- package/lib/services/a11y/setup.js +2 -2
- package/lib/services/a11y/setup.test.js +7 -8
- package/lib/services/advertHandlers/handlePreRolls.d.ts +2 -0
- package/lib/services/advertHandlers/handlePreRolls.js +132 -0
- package/lib/services/advertHandlers/handlePrerolls.test.js +52 -0
- package/lib/services/cdnProviders/cdnProviders.d.ts +4 -0
- package/lib/services/cdnProviders/cdnProviders.js +22 -0
- package/lib/services/cdnProviders/cndProviders.test.js +22 -0
- package/lib/services/eventListenerHandlers/removeEventListeners.d.ts +1 -1
- package/lib/services/eventListenerHandlers/removeEventListeners.js +4 -4
- package/lib/services/eventListenerHandlers/removeEventListeners.test.js +28 -13
- package/lib/services/liveStreamHandlers/handleLiveStreamControls.d.ts +1 -1
- package/lib/services/liveStreamHandlers/handleLiveStreamControls.js +3 -3
- package/lib/services/liveStreamHandlers/handleLiveStreamControls.test.d.ts +2 -0
- package/lib/services/liveStreamHandlers/handleLiveStreamControls.test.js +65 -0
- package/lib/services/localStorageHandlers/localStorageHandlers.d.ts +1 -1
- package/lib/services/localStorageHandlers/localStorageHandlers.test.js +0 -1
- package/lib/services/npoPlayerAPI/contants.d.ts +5 -0
- package/lib/services/npoPlayerAPI/contants.js +5 -0
- package/lib/services/npoPlayerAPI/npoPlayerAPI.d.ts +16 -4
- package/lib/services/npoPlayerAPI/npoPlayerAPI.js +65 -3
- package/lib/services/npoPlayerAPI/npoPlayerAPI.test.js +66 -1
- package/lib/services/segmentHandlers/addSegmentEventListeners.js +3 -3
- package/lib/services/segmentHandlers/addSegmentEventListeners.test.js +10 -9
- package/lib/services/segmentHandlers/convertFragmentToSegment.d.ts +1 -1
- package/lib/services/segmentHandlers/handleSegmentSeek.d.ts +1 -1
- package/lib/services/segmentHandlers/handleSegmentSeek.test.js +4 -4
- package/lib/services/segmentHandlers/handleSegmentTimeChanged.d.ts +1 -1
- package/lib/services/segmentHandlers/handleSegmentTimeChanged.test.js +33 -24
- package/lib/services/segmentHandlers/initSegment.d.ts +1 -1
- package/lib/services/segmentHandlers/initSegment.test.js +3 -1
- package/lib/services/segmentHandlers/setSegmentMarkers.d.ts +1 -1
- package/lib/services/services.d.ts +3 -1
- package/lib/services/services.js +8 -0
- package/lib/services/verticalVideoHandlers/handleVerticalVideoControls.d.ts +2 -0
- package/lib/services/verticalVideoHandlers/handleVerticalVideoControls.js +8 -0
- package/lib/services/verticalVideoHandlers/handleVerticalVideoControls.test.d.ts +1 -0
- package/lib/services/verticalVideoHandlers/handleVerticalVideoControls.test.js +36 -0
- package/lib/src/js/playeractions/handlers/handleoffsets.d.ts +4 -6
- package/lib/src/js/tracking/handlers/eventbinding.d.ts +1 -1
- package/lib/src/js/tracking/handlers/eventlogging.d.ts +1 -1
- package/lib/src/npoplayer.d.ts +1 -2
- package/lib/src/services/advertHandlers/handlePreRolls.d.ts +2 -0
- package/lib/src/services/advertHandlers/handlePrerolls.test.d.ts +1 -0
- package/lib/src/services/cdnProviders/cdnProviders.d.ts +4 -0
- package/lib/src/services/cdnProviders/cndProviders.test.d.ts +1 -0
- package/lib/src/services/eventListenerHandlers/removeEventListeners.d.ts +1 -1
- package/lib/src/services/liveStreamHandlers/handleLiveStreamControls.d.ts +1 -1
- package/lib/src/services/liveStreamHandlers/handleLiveStreamControls.test.d.ts +2 -0
- package/lib/src/services/localStorageHandlers/localStorageHandlers.d.ts +1 -1
- package/lib/src/services/npoPlayerAPI/contants.d.ts +5 -0
- package/lib/src/services/npoPlayerAPI/npoPlayerAPI.d.ts +16 -4
- package/lib/src/services/segmentHandlers/convertFragmentToSegment.d.ts +1 -1
- package/lib/src/services/segmentHandlers/handleSegmentSeek.d.ts +1 -1
- package/lib/src/services/segmentHandlers/handleSegmentTimeChanged.d.ts +1 -1
- package/lib/src/services/segmentHandlers/initSegment.d.ts +1 -1
- package/lib/src/services/segmentHandlers/setSegmentMarkers.d.ts +1 -1
- package/lib/src/services/services.d.ts +3 -1
- package/lib/src/services/verticalVideoHandlers/handleVerticalVideoControls.d.ts +2 -0
- package/lib/src/services/verticalVideoHandlers/handleVerticalVideoControls.test.d.ts +1 -0
- package/lib/src/types/events.d.ts +8 -1
- package/lib/src/types/interfaces.d.ts +8 -12
- package/lib/src/ui/components/audio/controlbar.d.ts +1 -1
- package/lib/src/ui/components/controlbar.d.ts +1 -1
- package/lib/src/ui/components/seekbar.d.ts +1 -1
- package/lib/src/ui/components/settingspanel.d.ts +1 -1
- package/lib/src/ui/components/verticalvideo/controlbar.d.ts +3 -0
- package/lib/src/ui/handlers/streamhandler.d.ts +2 -4
- package/lib/src/ui/uicontainer.d.ts +2 -2
- package/lib/tests/mocks/mockNpoplayer.js +0 -1
- package/lib/tests/mocks/playerContextMock.d.ts +67 -0
- package/lib/tests/mocks/playerContextMock.js +117 -0
- package/lib/types/events.d.ts +8 -1
- package/lib/types/events.js +184 -1
- package/lib/types/interfaces.d.ts +8 -12
- package/lib/types/interfaces.js +1 -0
- package/lib/ui/components/audio/controlbar.d.ts +1 -1
- package/lib/ui/components/audio/controlbar.js +6 -6
- package/lib/ui/components/controlbar.d.ts +1 -1
- package/lib/ui/components/controlbar.js +13 -11
- package/lib/ui/components/nativemobile/controlbar.js +0 -1
- package/lib/ui/components/seekbar.js +1 -1
- package/lib/ui/components/settingspanel.d.ts +1 -1
- package/lib/ui/components/settingspanel.js +68 -84
- package/lib/ui/components/topbar.js +6 -3
- package/lib/ui/components/verticalvideo/controlbar.d.ts +3 -0
- package/lib/ui/components/verticalvideo/controlbar.js +34 -0
- package/lib/ui/handlers/streamhandler.d.ts +2 -4
- package/lib/ui/handlers/streamhandler.js +16 -7
- package/lib/ui/nativemobileuifactory.js +2 -0
- package/lib/ui/uicontainer.d.ts +2 -2
- package/lib/ui/uicontainer.js +35 -29
- package/package.json +5 -5
- package/src/style/components/_settingspanel.scss +35 -3
- package/src/style/components/_subtitles.scss +29 -25
- package/src/style/components/_textbuttons.scss +2 -2
- package/src/style/components/_volumeslider.scss +1 -0
- package/src/style/components/vertical-video/_bottombar.scss +19 -0
- package/src/style/components/vertical-video/_buttons.scss +23 -0
- package/src/style/components/vertical-video/_hugeplaybacktogglebutton.scss +14 -0
- package/src/style/components/vertical-video/_seekbar.scss +19 -0
- package/src/style/components/vertical-video/_settingsbutton.scss +7 -0
- package/src/style/components/vertical-video/_settingspanel.scss +14 -0
- package/src/style/components/vertical-video/_shortvideo.scss +14 -0
- package/src/style/components/vertical-video/_subtitles.scss +3 -0
- package/src/style/components/vertical-video/_topbar.scss +17 -0
- package/src/style/components/vertical-video/_volumeslider.scss +9 -0
- package/src/style/npoplayer.css +74 -34
- package/src/style/npoplayer.scss +2 -1
- package/src/style/variants/_player-small.scss +18 -10
- package/src/style/variants/_player-vertical.scss +23 -0
- package/lib/js/ads/ster.d.ts +0 -4
- package/lib/js/ads/ster.js +0 -126
- package/lib/js/ads/ster.test.js +0 -63
- package/lib/js/cdnproviders.d.ts +0 -1
- package/lib/js/cdnproviders.js +0 -16
- package/lib/src/js/ads/ster.d.ts +0 -4
- package/lib/src/js/cdnproviders.d.ts +0 -1
- package/lib/tests/mocks/mockPlayerContext.d.ts +0 -2
- package/lib/tests/mocks/mockPlayerContext.js +0 -40
- /package/lib/{js/ads/ster.test.d.ts → services/advertHandlers/handlePrerolls.test.d.ts} +0 -0
- /package/lib/{src/js/ads/ster.test.d.ts → services/cdnProviders/cndProviders.test.d.ts} +0 -0
package/lib/npoplayer.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { NpoPlayerServices } from './services/services';
|
|
2
2
|
import { Player, PlayerEvent } from 'bitmovin-player';
|
|
3
|
-
import { UIManager } from 'bitmovin-player-ui';
|
|
4
3
|
import AdsModuleBM from 'bitmovin-player/modules/bitmovinplayer-advertising-bitmovin';
|
|
5
4
|
import { logEvent, initPlayerTracker, startPlayerTracker } from './js/tracking/playertracker';
|
|
6
5
|
import { hidePlayNextScreen, showPlayNextScreenIfNeeded } from './ui/handlers/playnextscreen';
|
|
@@ -11,15 +10,12 @@ import { isJWTToken } from './js/utilities/utilities.jwt';
|
|
|
11
10
|
import { isMediaUrl, isUrl } from './js/utilities/utilities.url';
|
|
12
11
|
import { logVersion } from './js/utilities/utilities.version';
|
|
13
12
|
import { getStreamDurationInSeconds } from './js/utilities/utilities.stream';
|
|
14
|
-
import { customSpecificErrorMessageOverlayConfig } from './js/playeractions/handlers/customerrors';
|
|
15
|
-
import { createUIContainer } from './ui/uicontainer';
|
|
16
13
|
import { LogEmitter } from './types/classes';
|
|
17
|
-
import { handlePreRolls } from './
|
|
14
|
+
import { handlePreRolls } from './services/advertHandlers/handlePreRolls';
|
|
18
15
|
import pkg from '../package.json';
|
|
19
16
|
import { NpoPlayerUIVariants, LocalStorageValues } from './types/interfaces';
|
|
20
17
|
import { nativeMobileUiFactory } from './ui/nativemobileuifactory';
|
|
21
18
|
import { setupMediaSessionActionHandlers } from './js/playeractions/handlers/mediasessionactions';
|
|
22
|
-
import { processStream } from './ui/handlers/streamhandler';
|
|
23
19
|
import { removeReplayClass } from './js/playeractions/handlers/removereplayclass';
|
|
24
20
|
import { showNicamAfterUiDelay } from './ui/handlers/nicamhandler';
|
|
25
21
|
import { updateLiveMarkers } from './js/markers/updateLiveMarkers';
|
|
@@ -55,14 +51,17 @@ export default class NpoPlayer {
|
|
|
55
51
|
this.container = _container;
|
|
56
52
|
this.variant = _variant || NpoPlayerUIVariants.DEFAULT;
|
|
57
53
|
initPlayerTracker(this, _npotag, _npotaginstance);
|
|
58
|
-
this.initPlayer(this.container, _playerConfig
|
|
54
|
+
this.initPlayer(this.container, _playerConfig);
|
|
59
55
|
}
|
|
60
|
-
initPlayer(_container, playerConfig
|
|
56
|
+
initPlayer(_container, playerConfig) {
|
|
61
57
|
const processedPlayerConfig = playerAction.processPlayerConfig(this, playerConfig);
|
|
62
|
-
Player.addModule(getModuleExport(AdsModuleBM));
|
|
63
|
-
this.userPreferences = this.npoplayerServices.getStoredUserPrefs();
|
|
64
58
|
this.player = new Player(_container, processedPlayerConfig);
|
|
59
|
+
Player.addModule(getModuleExport(AdsModuleBM));
|
|
65
60
|
const npoPlayerAPI = new NpoPlayerAPI(this.player);
|
|
61
|
+
this.playerContext = { player: npoPlayerAPI, npoplayer: this };
|
|
62
|
+
this.userPreferences = this.npoplayerServices.getStoredUserPrefs();
|
|
63
|
+
this.npoplayerServices.handleUserPrefs(this.playerContext);
|
|
64
|
+
this.npoplayerServices.setAccessibilityAttributes(this.playerContext);
|
|
66
65
|
window.addEventListener('beforeunload', () => {
|
|
67
66
|
if (this.player) {
|
|
68
67
|
this.npoplayerServices.setStoredUserPrefs(LocalStorageValues.SUBTITLES_ENABLED, npoPlayerAPI.areSubtitlesEnabled().toString());
|
|
@@ -70,10 +69,6 @@ export default class NpoPlayer {
|
|
|
70
69
|
this.npoplayerServices.setStoredUserPrefs(LocalStorageValues.IS_MUTED, npoPlayerAPI.isMuted().toString());
|
|
71
70
|
}
|
|
72
71
|
});
|
|
73
|
-
this.playerContext = { player: npoPlayerAPI, npoplayer: this };
|
|
74
|
-
this.createUIManager(this.player, this.playerContext, variant);
|
|
75
|
-
this.npoplayerServices.handleUserPrefs(this.playerContext);
|
|
76
|
-
this.npoplayerServices.setAccessibilityAttributes(this.playerContext);
|
|
77
72
|
this.container.addEventListener('keydown', (e) => {
|
|
78
73
|
if (!this.playerContext)
|
|
79
74
|
return;
|
|
@@ -89,8 +84,8 @@ export default class NpoPlayer {
|
|
|
89
84
|
return;
|
|
90
85
|
}
|
|
91
86
|
if (this.adBreakActive) {
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
const currentAd = this.player.ads.getActiveAdBreak().id;
|
|
88
|
+
this.player.ads.discardAdBreak(currentAd);
|
|
94
89
|
}
|
|
95
90
|
let _streamObject;
|
|
96
91
|
const sourceIsUrl = isUrl(source);
|
|
@@ -140,7 +135,7 @@ export default class NpoPlayer {
|
|
|
140
135
|
_streamObject = await getStreamObject(this, payload);
|
|
141
136
|
this.streamObject = _streamObject;
|
|
142
137
|
if (_streamObject) {
|
|
143
|
-
await this.createUIManager(this.
|
|
138
|
+
await this.playerContext.player.createUIManager(this.playerContext, this.variant);
|
|
144
139
|
}
|
|
145
140
|
}
|
|
146
141
|
catch (error) {
|
|
@@ -163,28 +158,28 @@ export default class NpoPlayer {
|
|
|
163
158
|
const initAndStartTracker = () => {
|
|
164
159
|
if (this.player === null)
|
|
165
160
|
return;
|
|
166
|
-
this.player?.off(PlayerEvent.SourceLoaded, initAndStartTracker);
|
|
167
161
|
this.player?.off(PlayerEvent.AdBreakFinished, initAndStartTracker);
|
|
168
162
|
this.player?.off(PlayerEvent.AdError, initAndStartTracker);
|
|
169
163
|
streamDuration =
|
|
170
164
|
streamDuration == undefined
|
|
171
|
-
?
|
|
165
|
+
? getDurationAndStartPlayerTracker()
|
|
172
166
|
: startPlayerTracker(this, getStreamDurationInSeconds({ duration: streamDuration, durationIsInMs: true }), this.version, streamPrid);
|
|
173
167
|
};
|
|
174
|
-
if (this.variant
|
|
168
|
+
if (this.variant === NpoPlayerUIVariants.DEFAULT &&
|
|
175
169
|
this.streamObject.metadata.hasPreroll === 'true' &&
|
|
176
170
|
this.streamObject.assets.preroll) {
|
|
177
171
|
this.player.on(PlayerEvent.AdBreakFinished, initAndStartTracker);
|
|
178
172
|
this.player.on(PlayerEvent.AdError, initAndStartTracker);
|
|
179
|
-
await handlePreRolls(this.
|
|
173
|
+
await handlePreRolls(this.playerContext);
|
|
180
174
|
}
|
|
181
175
|
else {
|
|
182
|
-
|
|
176
|
+
initAndStartTracker();
|
|
183
177
|
}
|
|
184
178
|
}
|
|
185
179
|
else {
|
|
186
180
|
this.doError(`Het is niet gelukt de stream op te halen: \n Input is geen valide token of media object.`, 500);
|
|
187
181
|
}
|
|
182
|
+
this.npoplayerServices.handleVerticalVideoControls(this.playerContext, this.variant);
|
|
188
183
|
if (this.sourceConfig?.metadata) {
|
|
189
184
|
this.sourceConfig.metadata.jwt = source;
|
|
190
185
|
this.sourceConfig.metadata.streamLinkAsJsonString = JSON.stringify(this.streamObject);
|
|
@@ -205,26 +200,12 @@ export default class NpoPlayer {
|
|
|
205
200
|
showNicamAfterUiDelay(this.player, this.uiManager);
|
|
206
201
|
});
|
|
207
202
|
const setLiveOffsetListener = function () {
|
|
208
|
-
if (this.
|
|
203
|
+
if (this.playerContext === undefined)
|
|
209
204
|
return;
|
|
210
205
|
this.player?.off(PlayerEvent.SourceLoaded, setLiveOffsetListener);
|
|
211
|
-
playerAction.handleLiveOffsetLogic(this
|
|
206
|
+
playerAction.handleLiveOffsetLogic(this.playerContext, options);
|
|
212
207
|
}.bind(this);
|
|
213
|
-
this.player.on(PlayerEvent.
|
|
214
|
-
}
|
|
215
|
-
async createUIManager(player, playerContext, variant) {
|
|
216
|
-
if (this.uiManager === undefined || variant !== this.variant) {
|
|
217
|
-
const uiConfig = {
|
|
218
|
-
errorMessages: customSpecificErrorMessageOverlayConfig,
|
|
219
|
-
disableAutoHideWhenHovered: true,
|
|
220
|
-
seekbarSnappingEnabled: false
|
|
221
|
-
};
|
|
222
|
-
this.uiManager = new UIManager(player, createUIContainer(this, player, variant, this.container), uiConfig);
|
|
223
|
-
this.variant = variant;
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
processStream(this.streamObject, this.container, this.streamOptions, player, this.uiManager, this.sourceConfig, playerContext);
|
|
227
|
-
}
|
|
208
|
+
this.player.on(PlayerEvent.SourceLoaded, setLiveOffsetListener);
|
|
228
209
|
}
|
|
229
210
|
doError(input, status) {
|
|
230
211
|
if (this.player == undefined)
|
|
@@ -241,19 +222,19 @@ export default class NpoPlayer {
|
|
|
241
222
|
this.playerContext?.player.pause();
|
|
242
223
|
}
|
|
243
224
|
setVolume(volume) {
|
|
244
|
-
if (this.
|
|
225
|
+
if (this.playerContext === undefined)
|
|
245
226
|
return;
|
|
246
|
-
this.player.setVolume(volume);
|
|
227
|
+
this.playerContext.player.setVolume(volume);
|
|
247
228
|
}
|
|
248
229
|
increaseVolume() {
|
|
249
|
-
if (this.
|
|
230
|
+
if (this.playerContext === undefined)
|
|
250
231
|
return;
|
|
251
|
-
this.
|
|
232
|
+
this.playerContext.player.increaseVolume();
|
|
252
233
|
}
|
|
253
234
|
decreaseVolume() {
|
|
254
|
-
if (this.
|
|
235
|
+
if (this.playerContext === undefined)
|
|
255
236
|
return;
|
|
256
|
-
this.
|
|
237
|
+
this.playerContext.player.decreaseVolume();
|
|
257
238
|
}
|
|
258
239
|
goForward(seconds) {
|
|
259
240
|
if (this.player == undefined)
|
|
@@ -276,9 +257,9 @@ export default class NpoPlayer {
|
|
|
276
257
|
}
|
|
277
258
|
}
|
|
278
259
|
watchFromStart() {
|
|
279
|
-
if (this.
|
|
260
|
+
if (this.playerContext == undefined)
|
|
280
261
|
return;
|
|
281
|
-
playerAction.shiftToProgramStart(this.
|
|
262
|
+
playerAction.shiftToProgramStart(this.playerContext, this.streamOptions.liveProgramTime);
|
|
282
263
|
}
|
|
283
264
|
showPlayNextScreen() {
|
|
284
265
|
if (this.player == undefined || !this.streamOptions.playNext?.showPlayNext || this.adBreakActive)
|
package/lib/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npo/player",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
4
|
"description": "NPO Player",
|
|
5
5
|
"author": "Publieke Omroep <player@npo.nl>",
|
|
6
6
|
"contributors": [
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"types": "./lib/npoplayer.d.ts",
|
|
17
17
|
"scripts": {
|
|
18
18
|
"build": "webpack --hot",
|
|
19
|
-
"build:scss": "npm run build:web-styles && npm run build:mobile-styles && mkdir -p dist && cp src/style/*.css dist &&
|
|
19
|
+
"build:scss": "npm run build:web-styles && npm run build:mobile-styles && mkdir -p dist && cp src/style/*.css dist && cp src/style/*.css.map dist && mkdir -p src/scss && cp src/style/*.css src/scss && cp src/style/*.css.map src/scss",
|
|
20
20
|
"build:web-styles": "sass src/style/npoplayer.scss:src/style/npoplayer.css --style=compressed && postcss src/style/npoplayer.css --use autoprefixer postcss-import -o src/style/npoplayer.css",
|
|
21
21
|
"build:mobile-styles": "sass src/style/npoplayer-mobile.scss:src/style/npoplayer-mobile.css --style=compressed && postcss src/style/npoplayer-mobile.css --use autoprefixer postcss-import -o src/style/npoplayer-mobile.css",
|
|
22
22
|
"build:cdn": "npm run build && bash build-cdn.sh",
|
|
@@ -89,9 +89,9 @@
|
|
|
89
89
|
"webpack-dev-server": "^4.11.1"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@npotag/tag": "3.1
|
|
93
|
-
"bitmovin-player": "8.
|
|
94
|
-
"bitmovin-player-ui": "3.
|
|
92
|
+
"@npotag/tag": "3.2.1",
|
|
93
|
+
"bitmovin-player": "8.173.0",
|
|
94
|
+
"bitmovin-player-ui": "3.67.0"
|
|
95
95
|
},
|
|
96
96
|
"browserslist": [
|
|
97
97
|
"defaults",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NpoPlayerEvent } from '../../types/events';
|
|
2
2
|
import { addAccessibilityAttributes } from '../../ui/handlers/accessibilityhandler';
|
|
3
3
|
export function setupAccessibilityAttributes(playerContext) {
|
|
4
4
|
const { player, npoplayer } = playerContext;
|
|
5
|
-
const events = [
|
|
5
|
+
const events = [NpoPlayerEvent.SourceLoaded, NpoPlayerEvent.AdBreakFinished, NpoPlayerEvent.AdError];
|
|
6
6
|
const triggerAddAccessibilityAttributes = () => {
|
|
7
7
|
for (const event of events) {
|
|
8
8
|
player?.off(event, triggerAddAccessibilityAttributes);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NpoPlayerEvent } from '../../types/events';
|
|
2
2
|
import { addAccessibilityAttributes } from '../../ui/handlers/accessibilityhandler';
|
|
3
3
|
import { setupAccessibilityAttributes } from './setup';
|
|
4
4
|
import { mockNpoPlayer } from '../../../tests/mocks/mockNpoplayer';
|
|
@@ -44,7 +44,6 @@ describe('setupAccessibilityAttributes', () => {
|
|
|
44
44
|
playerConfig: {},
|
|
45
45
|
initPlayer: () => { },
|
|
46
46
|
loadStream: () => Promise.resolve(),
|
|
47
|
-
createUIManager: async () => { },
|
|
48
47
|
doError: () => { },
|
|
49
48
|
play: async () => { },
|
|
50
49
|
pause: () => { },
|
|
@@ -87,18 +86,18 @@ describe('setupAccessibilityAttributes', () => {
|
|
|
87
86
|
it('should set up event listeners for specified events', () => {
|
|
88
87
|
setupAccessibilityAttributes(playerContext);
|
|
89
88
|
expect(mockAddEventListener).toHaveBeenCalledTimes(3);
|
|
90
|
-
expect(mockAddEventListener).toHaveBeenCalledWith(
|
|
91
|
-
expect(mockAddEventListener).toHaveBeenCalledWith(
|
|
92
|
-
expect(mockAddEventListener).toHaveBeenCalledWith(
|
|
89
|
+
expect(mockAddEventListener).toHaveBeenCalledWith(NpoPlayerEvent.SourceLoaded, expect.any(Function));
|
|
90
|
+
expect(mockAddEventListener).toHaveBeenCalledWith(NpoPlayerEvent.AdBreakFinished, expect.any(Function));
|
|
91
|
+
expect(mockAddEventListener).toHaveBeenCalledWith(NpoPlayerEvent.AdError, expect.any(Function));
|
|
93
92
|
});
|
|
94
93
|
it('should remove event listeners after they are triggered', () => {
|
|
95
94
|
setupAccessibilityAttributes(playerContext);
|
|
96
95
|
const triggerFunction = mockAddEventListener.mock.calls[0][1];
|
|
97
96
|
triggerFunction();
|
|
98
97
|
expect(mockRemoveEventListener).toHaveBeenCalledTimes(3);
|
|
99
|
-
expect(mockRemoveEventListener).toHaveBeenCalledWith(
|
|
100
|
-
expect(mockRemoveEventListener).toHaveBeenCalledWith(
|
|
101
|
-
expect(mockRemoveEventListener).toHaveBeenCalledWith(
|
|
98
|
+
expect(mockRemoveEventListener).toHaveBeenCalledWith(NpoPlayerEvent.SourceLoaded, triggerFunction);
|
|
99
|
+
expect(mockRemoveEventListener).toHaveBeenCalledWith(NpoPlayerEvent.AdBreakFinished, triggerFunction);
|
|
100
|
+
expect(mockRemoveEventListener).toHaveBeenCalledWith(NpoPlayerEvent.AdError, triggerFunction);
|
|
102
101
|
});
|
|
103
102
|
it('should call addAccessibilityAttributes with the correct parameters', () => {
|
|
104
103
|
setupAccessibilityAttributes(playerContext);
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { AdTagType } from 'bitmovin-player';
|
|
2
|
+
import { NpoPlayerUIVariants } from '../../types/interfaces';
|
|
3
|
+
import { NpoPlayerEvent } from '../../types/events';
|
|
4
|
+
export async function handlePreRolls(playerContext) {
|
|
5
|
+
return new Promise((resolve) => {
|
|
6
|
+
if (playerContext.npoplayer.streamObject.metadata.hasPreroll == 'false' ||
|
|
7
|
+
playerContext.npoplayer.streamObject.assets.preroll == undefined) {
|
|
8
|
+
resolve();
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const prerollUrl = playerContext.npoplayer.streamObject.assets.preroll;
|
|
12
|
+
let adIndex = 0;
|
|
13
|
+
let totalAds = 0;
|
|
14
|
+
let currentClickListener;
|
|
15
|
+
let adUiSet = false;
|
|
16
|
+
async function handleReady() {
|
|
17
|
+
playerContext.player.off(NpoPlayerEvent.Ready, handleReady);
|
|
18
|
+
const advertConfig = {
|
|
19
|
+
tag: {
|
|
20
|
+
url: String(prerollUrl),
|
|
21
|
+
type: AdTagType.VAST
|
|
22
|
+
},
|
|
23
|
+
id: 'Ad',
|
|
24
|
+
position: 'pre'
|
|
25
|
+
};
|
|
26
|
+
await playerContext.player.scheduleAds(advertConfig);
|
|
27
|
+
}
|
|
28
|
+
playerContext.player.on(NpoPlayerEvent.Ready, handleReady);
|
|
29
|
+
async function handlePlay() {
|
|
30
|
+
playerContext.player.off(NpoPlayerEvent.Play, handlePlay);
|
|
31
|
+
attemptSetAdUi();
|
|
32
|
+
}
|
|
33
|
+
playerContext.player.on(NpoPlayerEvent.Play, handlePlay);
|
|
34
|
+
function setAdUi() {
|
|
35
|
+
const activeAdBreak = playerContext.player.getActiveAdBreak();
|
|
36
|
+
if (!activeAdBreak || !activeAdBreak.ads)
|
|
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);
|
|
42
|
+
}
|
|
43
|
+
adUiSet = true;
|
|
44
|
+
const adButton = playerContext.npoplayer.uiComponents.adbutton;
|
|
45
|
+
const currentAd = activeAdBreak.ads[0];
|
|
46
|
+
adIndex = 1;
|
|
47
|
+
totalAds = activeAdBreak.ads.length;
|
|
48
|
+
if (adButton) {
|
|
49
|
+
adButton.show();
|
|
50
|
+
adClickHandler(currentAd, adButton);
|
|
51
|
+
}
|
|
52
|
+
playerContext.npoplayer.uiComponents.adlabel?.setText(`Advertentie 1 van ${activeAdBreak.ads.length}`);
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
function attemptSetAdUi(attemptsLeft = 10) {
|
|
56
|
+
if (attemptsLeft <= 0)
|
|
57
|
+
return;
|
|
58
|
+
if (!adUiSet) {
|
|
59
|
+
setAdUi();
|
|
60
|
+
setTimeout(() => {
|
|
61
|
+
attemptSetAdUi(attemptsLeft - 1);
|
|
62
|
+
}, 200);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function handleAdStarted() {
|
|
66
|
+
playerContext.player.off(NpoPlayerEvent.AdStarted, handleAdStarted);
|
|
67
|
+
const activeAdBreak = playerContext.player.getActiveAdBreak();
|
|
68
|
+
if (!activeAdBreak || !activeAdBreak.ads) {
|
|
69
|
+
console.error('No active ad break data found');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (!adUiSet)
|
|
73
|
+
attemptSetAdUi();
|
|
74
|
+
playerContext.npoplayer.adBreakActive = true;
|
|
75
|
+
}
|
|
76
|
+
playerContext.player.on(NpoPlayerEvent.AdStarted, handleAdStarted);
|
|
77
|
+
function adClickHandler(ad, button) {
|
|
78
|
+
const clickThroughCallback = ad.clickThroughUrlOpened;
|
|
79
|
+
if (currentClickListener)
|
|
80
|
+
button.onClick.unsubscribe(currentClickListener);
|
|
81
|
+
currentClickListener = () => {
|
|
82
|
+
try {
|
|
83
|
+
window.open(ad.clickThroughUrl, '_blank');
|
|
84
|
+
playerContext.player.pause();
|
|
85
|
+
if (clickThroughCallback)
|
|
86
|
+
clickThroughCallback();
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
console.log(error);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
button.onClick.subscribe(currentClickListener);
|
|
93
|
+
}
|
|
94
|
+
function handleAdFinished() {
|
|
95
|
+
playerContext.player.off(NpoPlayerEvent.AdFinished, handleAdFinished);
|
|
96
|
+
const activeAdBreak = playerContext.player.getActiveAdBreak();
|
|
97
|
+
if (!activeAdBreak || !activeAdBreak.ads) {
|
|
98
|
+
console.error('No active ad break data found');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (adIndex >= totalAds) {
|
|
102
|
+
handleAdBreakFinished();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const adButton = playerContext.npoplayer.uiComponents.adbutton;
|
|
106
|
+
const nextAd = activeAdBreak.ads[adIndex];
|
|
107
|
+
adIndex += 1;
|
|
108
|
+
if (adButton) {
|
|
109
|
+
adButton.show();
|
|
110
|
+
adClickHandler(nextAd, adButton);
|
|
111
|
+
}
|
|
112
|
+
playerContext.npoplayer.uiComponents.adlabel?.setText(`Advertentie ${adIndex} van ${activeAdBreak.ads.length}`);
|
|
113
|
+
}
|
|
114
|
+
playerContext.player.on(NpoPlayerEvent.AdFinished, handleAdFinished);
|
|
115
|
+
function handleAdBreakFinished() {
|
|
116
|
+
playerContext.player.off(NpoPlayerEvent.AdBreakFinished, handleAdBreakFinished);
|
|
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);
|
|
125
|
+
}
|
|
126
|
+
adUiSet = false;
|
|
127
|
+
resolve();
|
|
128
|
+
}
|
|
129
|
+
playerContext.player.on(NpoPlayerEvent.AdBreakFinished, handleAdBreakFinished);
|
|
130
|
+
playerContext.player.on(NpoPlayerEvent.AdError, handleAdBreakFinished);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { handlePreRolls } from './handlePreRolls';
|
|
2
|
+
import { createMockNpoPlayer, createPlayerContextMock } from '../../../tests/mocks/playerContextMock';
|
|
3
|
+
jest.mock('bitmovin-player');
|
|
4
|
+
jest.mock('../../npoplayer');
|
|
5
|
+
describe('handlePreRolls', () => {
|
|
6
|
+
let mockPlayerAPI;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
mockPlayerAPI = {
|
|
9
|
+
ads: {
|
|
10
|
+
schedule: jest.fn().mockResolvedValue(true),
|
|
11
|
+
getActiveAdBreak: jest.fn()
|
|
12
|
+
},
|
|
13
|
+
on: jest.fn(),
|
|
14
|
+
off: jest.fn()
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
it('should not schedule ads when hasPreroll is false', async () => {
|
|
18
|
+
const npoplayerMock = createMockNpoPlayer({
|
|
19
|
+
streamObject: {
|
|
20
|
+
metadata: {
|
|
21
|
+
hasPreroll: 'false'
|
|
22
|
+
},
|
|
23
|
+
assets: {
|
|
24
|
+
preroll: 'sample_url'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const playerContextMock = createPlayerContextMock({
|
|
29
|
+
npoplayer: npoplayerMock
|
|
30
|
+
});
|
|
31
|
+
await handlePreRolls(playerContextMock);
|
|
32
|
+
expect(mockPlayerAPI.ads.schedule).not.toHaveBeenCalled();
|
|
33
|
+
});
|
|
34
|
+
it('should not schedule ads if preroll URL is missing', async () => {
|
|
35
|
+
const npoplayerMock = createMockNpoPlayer({
|
|
36
|
+
streamObject: {
|
|
37
|
+
metadata: {
|
|
38
|
+
hasPreroll: 'true'
|
|
39
|
+
},
|
|
40
|
+
assets: {}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const playerContextMock = createPlayerContextMock({
|
|
44
|
+
npoplayer: npoplayerMock
|
|
45
|
+
});
|
|
46
|
+
await handlePreRolls(playerContextMock);
|
|
47
|
+
expect(mockPlayerAPI.ads.schedule).not.toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
jest.clearAllMocks();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type CdnProvider = 'NEP-FASTLY' | 'NEP' | 'NEP-LSW' | 'EUROVISION' | 'KPN' | 'AKEMAI' | 'OMROEP-ICECAST' | 'OMROEP-CONTENT' | 'OMROEP-PODCAST' | 'OMROEP-VIDEO' | 'OMROEP-DOWNLOAD' | 'NOS' | 'NPOAUDIO';
|
|
2
|
+
export declare function createImmutableMap(entries: [string, CdnProvider][]): ReadonlyMap<string, CdnProvider>;
|
|
3
|
+
export declare const npoCdnProvidersData: [string, CdnProvider][];
|
|
4
|
+
export declare const npoCdnProviders: ReadonlyMap<string, CdnProvider>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function createImmutableMap(entries) {
|
|
2
|
+
const map = new Map(entries);
|
|
3
|
+
return Object.freeze(map);
|
|
4
|
+
}
|
|
5
|
+
export const npoCdnProvidersData = [
|
|
6
|
+
['nep.global.ssl.fastly.net', 'NEP-FASTLY'],
|
|
7
|
+
['npo-fsly.cdn.streamgate.io', 'NEP-FASTLY'],
|
|
8
|
+
['cdn.streamgate.nl', 'NEP'],
|
|
9
|
+
['pr.lswcdn.net', 'NEP-LSW'],
|
|
10
|
+
['cdn.eurovisioncdn.net', 'EUROVISION'],
|
|
11
|
+
['npo.prd.cdn.bcms.kpn.com', 'KPN'],
|
|
12
|
+
['cdn.bcms.kpn.com', 'KPN'],
|
|
13
|
+
['Akamai', 'AKEMAI'],
|
|
14
|
+
['icecast.omroep.nl', 'OMROEP-ICECAST'],
|
|
15
|
+
['content.omroep.nl', 'OMROEP-CONTENT'],
|
|
16
|
+
['podcast.npo.nl', 'OMROEP-PODCAST'],
|
|
17
|
+
['video.omroep.nl', 'OMROEP-VIDEO'],
|
|
18
|
+
['download.omroep.nl', 'OMROEP-DOWNLOAD'],
|
|
19
|
+
['download.nos.nl', 'NOS'],
|
|
20
|
+
['entry.cdn.npoaudio.nl', 'NPOAUDIO']
|
|
21
|
+
];
|
|
22
|
+
export const npoCdnProviders = createImmutableMap(npoCdnProvidersData);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createImmutableMap, npoCdnProviders, npoCdnProvidersData } from './cdnProviders';
|
|
2
|
+
describe('createImmutableMap function', () => {
|
|
3
|
+
it('should create an immutable map with correct entries', () => {
|
|
4
|
+
const testEntries = [
|
|
5
|
+
['test1.com', 'AKEMAI'],
|
|
6
|
+
['test2.com', 'EUROVISION'],
|
|
7
|
+
['test3.com', 'KPN']
|
|
8
|
+
];
|
|
9
|
+
const immutableMap = createImmutableMap(testEntries);
|
|
10
|
+
for (const [key, value] of testEntries) {
|
|
11
|
+
expect(immutableMap.get(key)).toBe(value);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
describe('npoCdnProviders map', () => {
|
|
16
|
+
it('should match the expected contents', () => {
|
|
17
|
+
expect(npoCdnProviders.size).toBe(npoCdnProvidersData.length);
|
|
18
|
+
for (const [key, value] of npoCdnProvidersData) {
|
|
19
|
+
expect(npoCdnProviders.get(key)).toBe(value);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { PlayerContext } from 'types/interfaces';
|
|
1
|
+
import { PlayerContext } from '../../types/interfaces';
|
|
2
2
|
export declare const removeEventListeners: (playerContext: PlayerContext) => void;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NpoPlayerEvent } from '../../types/events';
|
|
2
2
|
export const removeEventListeners = (playerContext) => {
|
|
3
3
|
const { eventListeners } = playerContext.npoplayer;
|
|
4
4
|
if (eventListeners) {
|
|
5
5
|
const { segmentHandleTimeChangedCallback, segmentSeekFunctionCallback, liveStreamHandleTimeChangedCallback } = eventListeners;
|
|
6
6
|
const eventMapping = [
|
|
7
|
-
{ event:
|
|
8
|
-
{ event:
|
|
9
|
-
{ event:
|
|
7
|
+
{ event: NpoPlayerEvent.TimeChanged, callback: liveStreamHandleTimeChangedCallback },
|
|
8
|
+
{ event: NpoPlayerEvent.TimeChanged, callback: segmentHandleTimeChangedCallback },
|
|
9
|
+
{ event: NpoPlayerEvent.Seek, callback: segmentSeekFunctionCallback }
|
|
10
10
|
];
|
|
11
11
|
for (const { event, callback } of eventMapping) {
|
|
12
12
|
if (callback) {
|
|
@@ -1,27 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mockPlayerContext } from '../../../tests/mocks/mockPlayerContext';
|
|
1
|
+
import { NpoPlayerEvent } from '../../types/events';
|
|
3
2
|
import { removeEventListeners } from './removeEventListeners';
|
|
3
|
+
import createPlayerContextMock from '../../../tests/mocks/playerContextMock';
|
|
4
4
|
describe('removeEventListeners', () => {
|
|
5
|
-
let
|
|
5
|
+
let mockPlayerContext;
|
|
6
6
|
beforeEach(() => {
|
|
7
|
-
context = { ...mockPlayerContext };
|
|
8
7
|
jest.clearAllMocks();
|
|
8
|
+
mockPlayerContext = createPlayerContextMock();
|
|
9
9
|
});
|
|
10
10
|
it('should remove TimeChanged event listener if exists', () => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
mockPlayerContext.npoplayer.eventListeners = {
|
|
12
|
+
segmentHandleTimeChangedCallback: jest.fn(),
|
|
13
|
+
liveStreamHandleTimeChangedCallback: jest.fn(),
|
|
14
|
+
segmentSeekFunctionCallback: jest.fn()
|
|
15
|
+
};
|
|
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);
|
|
15
20
|
}
|
|
16
21
|
});
|
|
17
22
|
it('should remove Seek event listener if exists', () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
mockPlayerContext.npoplayer.eventListeners = {
|
|
24
|
+
segmentHandleTimeChangedCallback: jest.fn(),
|
|
25
|
+
liveStreamHandleTimeChangedCallback: jest.fn(),
|
|
26
|
+
segmentSeekFunctionCallback: jest.fn()
|
|
27
|
+
};
|
|
28
|
+
removeEventListeners(mockPlayerContext);
|
|
29
|
+
if (mockPlayerContext.npoplayer.eventListeners) {
|
|
30
|
+
expect(mockPlayerContext.player.off).toHaveBeenCalledWith(NpoPlayerEvent.Seek, mockPlayerContext.npoplayer.eventListeners.segmentSeekFunctionCallback);
|
|
21
31
|
}
|
|
22
32
|
});
|
|
23
33
|
it('should reset EventListeners in playerContext', () => {
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
mockPlayerContext.npoplayer.eventListeners = {
|
|
35
|
+
segmentHandleTimeChangedCallback: jest.fn(),
|
|
36
|
+
liveStreamHandleTimeChangedCallback: jest.fn(),
|
|
37
|
+
segmentSeekFunctionCallback: jest.fn()
|
|
38
|
+
};
|
|
39
|
+
removeEventListeners(mockPlayerContext);
|
|
40
|
+
expect(mockPlayerContext.npoplayer.eventListeners).toBeUndefined();
|
|
26
41
|
});
|
|
27
42
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PlayerContext } from 'types/interfaces';
|
|
1
|
+
import { PlayerContext } from '../../types/interfaces';
|
|
2
2
|
export declare const handleLiveStreamControls: (playerContext: PlayerContext) => void;
|
|
3
3
|
export declare function updateForwardButtonState(player: any): void;
|
|
4
4
|
export declare function toggleForwardButtons(forwardButtons: NodeListOf<Element>, timeShift: number): void;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NpoPlayerEvent } from '../../types/events';
|
|
2
2
|
export const handleLiveStreamControls = (playerContext) => {
|
|
3
3
|
const liveStreamHandleTimeChangedCallback = () => updateForwardButtonState(playerContext.player);
|
|
4
4
|
const { player, npoplayer } = playerContext;
|
|
5
|
-
player.on(
|
|
5
|
+
player.on(NpoPlayerEvent.TimeChanged, liveStreamHandleTimeChangedCallback);
|
|
6
6
|
npoplayer.eventListeners = {
|
|
7
7
|
liveStreamHandleTimeChangedCallback
|
|
8
8
|
};
|
|
@@ -10,7 +10,7 @@ export const handleLiveStreamControls = (playerContext) => {
|
|
|
10
10
|
export function updateForwardButtonState(player) {
|
|
11
11
|
const timeShift = player?.getTimeShift();
|
|
12
12
|
const forwardButtons = player?.getContainer().querySelectorAll('.bmpui-ui-forwardbutton');
|
|
13
|
-
player.off(
|
|
13
|
+
player.off(NpoPlayerEvent.TimeChanged, () => {
|
|
14
14
|
updateForwardButtonState(player);
|
|
15
15
|
});
|
|
16
16
|
if (forwardButtons && timeShift !== undefined) {
|