@npo/player 1.25.0 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/js/api/getstreamobject.d.ts +1 -1
- package/lib/js/api/getstreamobject.js +4 -4
- package/lib/js/api/getstreamobject.test.js +12 -12
- package/lib/js/playeractions/handlers/handleoffsets.js +9 -7
- package/lib/js/playeractions/handlers/handleoffsets.test.js +1 -1
- package/lib/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
- package/lib/js/playeractions/handlers/processplayerconfig.js +4 -4
- package/lib/js/playeractions/handlers/processsourceconfig.d.ts +1 -0
- package/lib/js/playeractions/handlers/processsourceconfig.js +4 -5
- package/lib/js/playeractions/handlers/processsourceconfig.test.js +25 -0
- package/lib/js/tracking/handlers/playertrackerstart.js +1 -1
- package/lib/lang/nl.json +1 -1
- package/lib/lang/subtitleLabels/nl.json +14 -0
- package/lib/npoplayer.d.ts +2 -3
- package/lib/npoplayer.js +24 -32
- package/lib/npoplayer.test.js +1 -1
- package/lib/package.json +2 -2
- package/lib/services/a11y/setup.js +2 -5
- package/lib/services/a11y/setup.test.js +2 -19
- package/lib/services/advertHandlers/discardAdBreak.js +4 -4
- package/lib/services/advertHandlers/discardAdBreak.test.js +25 -13
- package/lib/services/advertHandlers/handlePreRolls.js +19 -19
- package/lib/services/advertHandlers/handlePrerolls.test.js +4 -4
- package/lib/services/drmHandlers/decideprofile.js +1 -1
- package/lib/services/drmHandlers/decideprofile.test.js +1 -1
- package/lib/services/drmHandlers/verifydrm.js +6 -6
- package/lib/services/drmHandlers/verifydrm.test.js +5 -5
- package/lib/services/eventListenerHandlers/removeEventListeners.js +2 -2
- package/lib/services/eventListenerHandlers/removeEventListeners.test.js +9 -9
- package/lib/services/keyboardHandlers/resolvekeypress.js +5 -5
- package/lib/services/keyboardHandlers/resolvekeypress.test.js +1 -1
- package/lib/services/liveStreamHandlers/handleLiveStreamControls.js +2 -2
- package/lib/services/liveStreamHandlers/handleLiveStreamControls.test.js +2 -2
- package/lib/services/localStorageHandlers/localStorageHandlers.js +2 -2
- package/lib/services/localStorageHandlers/localStorageHandlers.test.js +2 -5
- package/lib/services/nicamHandlers/nicamhandler.d.ts +1 -2
- package/lib/services/nicamHandlers/nicamhandler.js +17 -16
- package/lib/services/nicamHandlers/nicamhandler.test.js +72 -9
- package/lib/services/npoPlayerAPI/npoPlayerAPI.d.ts +2 -2
- package/lib/services/npoPlayerAPI/npoPlayerAPI.js +16 -23
- package/lib/services/preferences/handlePreferences.d.ts +2 -0
- package/lib/services/preferences/handlePreferences.js +42 -0
- package/lib/services/preferences/handlePreferences.test.js +102 -0
- package/lib/services/segmentHandlers/addSegmentEventListeners.js +2 -2
- package/lib/services/segmentHandlers/addSegmentEventListeners.test.js +1 -1
- package/lib/services/services.d.ts +6 -2
- package/lib/services/services.js +21 -2
- package/lib/services/streamoptionsHandlers/{steamOptionsHandler.js → streamOptionsHandler.js} +11 -11
- package/lib/services/streamoptionsHandlers/streamOptionsHandler.test.js +20 -20
- package/lib/services/uiHandlers/uiVisiblityHandler.d.ts +3 -0
- package/lib/services/uiHandlers/uiVisiblityHandler.js +26 -0
- package/lib/services/uiHandlers/uiVisiblityHandler.test.d.ts +1 -0
- package/lib/services/uiHandlers/uiVisiblityHandler.test.js +62 -0
- package/lib/src/js/api/getstreamobject.d.ts +1 -1
- package/lib/src/js/playeractions/handlers/processplayerconfig.d.ts +1 -1
- package/lib/src/js/playeractions/handlers/processsourceconfig.d.ts +1 -0
- package/lib/src/js/playeractions/handlers/processsourceconfig.test.d.ts +1 -0
- package/lib/src/npoplayer.d.ts +2 -3
- package/lib/src/services/nicamHandlers/nicamhandler.d.ts +1 -2
- package/lib/src/services/npoPlayerAPI/npoPlayerAPI.d.ts +2 -2
- package/lib/src/services/preferences/handlePreferences.d.ts +2 -0
- package/lib/src/services/preferences/handlePreferences.test.d.ts +1 -0
- package/lib/src/services/services.d.ts +6 -2
- package/lib/src/services/uiHandlers/uiVisiblityHandler.d.ts +3 -0
- package/lib/src/services/uiHandlers/uiVisiblityHandler.test.d.ts +1 -0
- package/lib/src/types/classes.d.ts +6 -0
- package/lib/src/types/interfaces.d.ts +24 -3
- package/lib/src/ui/components/adbutton.d.ts +1 -1
- package/lib/src/ui/components/adlabel.d.ts +1 -1
- package/lib/src/ui/components/buttons.d.ts +6 -16
- package/lib/src/ui/components/controlbar.d.ts +2 -2
- package/lib/src/ui/components/ctabar.d.ts +1 -1
- package/lib/src/ui/components/playnext.d.ts +1 -4
- package/lib/src/ui/components/seekbar.d.ts +1 -1
- package/lib/src/ui/components/titlebar.d.ts +1 -1
- package/lib/src/ui/handlers/playnextscreen.test.d.ts +1 -0
- package/lib/src/ui/uicontainer.test.d.ts +1 -0
- package/lib/tests/mocks/mockLogEmitter.d.ts +2 -0
- package/lib/tests/mocks/mockLogEmitter.js +20 -0
- package/lib/tests/mocks/mockNpoplayer.js +1 -2
- package/lib/tests/mocks/playerContextMock.d.ts +5 -3
- package/lib/tests/mocks/playerContextMock.js +7 -5
- package/lib/types/classes.d.ts +6 -0
- package/lib/types/classes.js +12 -0
- package/lib/types/interfaces.d.ts +24 -3
- package/lib/types/interfaces.js +1 -0
- package/lib/ui/components/adbutton.d.ts +1 -1
- package/lib/ui/components/adbutton.js +3 -3
- package/lib/ui/components/adlabel.d.ts +1 -1
- package/lib/ui/components/adlabel.js +3 -3
- package/lib/ui/components/buttons.d.ts +6 -16
- package/lib/ui/components/buttons.js +27 -10
- package/lib/ui/components/controlbar.d.ts +2 -2
- package/lib/ui/components/controlbar.js +20 -37
- package/lib/ui/components/ctabar.d.ts +1 -1
- package/lib/ui/components/ctabar.js +4 -4
- package/lib/ui/components/nativemobile/topbar.js +2 -2
- package/lib/ui/components/playnext.d.ts +1 -4
- package/lib/ui/components/playnext.js +3 -3
- package/lib/ui/components/seekbar.d.ts +1 -1
- package/lib/ui/components/seekbar.js +5 -3
- package/lib/ui/components/settingspanel.js +9 -9
- package/lib/ui/components/titlebar.d.ts +1 -1
- package/lib/ui/components/titlebar.js +2 -2
- package/lib/ui/components/topbar.js +6 -20
- package/lib/ui/components/verticalvideo/controlbar.js +1 -1
- package/lib/ui/handlers/playnextscreen.test.d.ts +1 -0
- package/lib/ui/nativemobileuifactory.js +1 -1
- package/lib/ui/nativemobileuifactory.test.js +2 -1
- package/lib/ui/uicontainer.js +11 -30
- package/lib/ui/uicontainer.test.d.ts +1 -0
- package/lib/ui/uicontainer.test.js +80 -0
- package/package.json +2 -2
- package/src/style/components/_advert.scss +0 -9
- package/src/style/components/_nicam.scss +5 -4
- package/src/style/components/_settingspanel.scss +48 -17
- package/src/style/components/vertical-video/_settingspanel.scss +1 -1
- package/src/style/npoplayer.css +25 -20
- package/src/style/variants/_player-base.scss +4 -0
- package/src/style/variants/_player-large.scss +5 -1
- package/src/style/variants/_player-small.scss +11 -8
- /package/lib/{src/ui/handlers/playnextstreen.test.d.ts → js/playeractions/handlers/processsourceconfig.test.d.ts} +0 -0
- /package/lib/{ui/handlers/playnextstreen.test.d.ts → services/preferences/handlePreferences.test.d.ts} +0 -0
- /package/lib/services/streamoptionsHandlers/{steamOptionsHandler.d.ts → streamOptionsHandler.d.ts} +0 -0
- /package/lib/src/services/streamoptionsHandlers/{steamOptionsHandler.d.ts → streamOptionsHandler.d.ts} +0 -0
- /package/lib/ui/handlers/{playnextstreen.test.js → playnextscreen.test.js} +0 -0
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Extensive and up-to-date documentation is available at https://docs.npoplayer.nl
|
|
|
11
11
|
Code quality is analysed by SonarCloud. The project can be found at https://sonarcloud.io/project/overview?id=NPOstart_npo-player
|
|
12
12
|
|
|
13
13
|
# Changelog
|
|
14
|
-
Current version: v1.
|
|
14
|
+
Current version: v1.26.0
|
|
15
15
|
|
|
16
16
|
The changelog is available at https://docs.npoplayer.nl/implementation/web/changelog/
|
|
17
17
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type ApiPayload } from '../../types/interfaces';
|
|
2
2
|
import type NpoPlayer from '../../npoplayer';
|
|
3
|
-
export declare function getStreamObject(
|
|
3
|
+
export declare function getStreamObject(npoPlayer: NpoPlayer, payload: ApiPayload): Promise<any>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { removeTrailingSlash } from '../utilities/utilities.url';
|
|
2
|
-
export async function getStreamObject(
|
|
2
|
+
export async function getStreamObject(npoPlayer, payload) {
|
|
3
3
|
try {
|
|
4
4
|
const controller = new AbortController();
|
|
5
5
|
const { signal } = controller;
|
|
@@ -22,16 +22,16 @@ export async function getStreamObject(npoplayer, payload) {
|
|
|
22
22
|
return streamApiResponse;
|
|
23
23
|
}
|
|
24
24
|
else {
|
|
25
|
-
|
|
25
|
+
npoPlayer.doError('Het is niet gelukt de stream op te halen.', response.status);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
catch (error) {
|
|
29
29
|
if (error instanceof Error) {
|
|
30
30
|
if (error.message === 'AbortError') {
|
|
31
|
-
|
|
31
|
+
npoPlayer.doError('Het ophalen van de stream duurde te lang.', 408);
|
|
32
32
|
}
|
|
33
33
|
else {
|
|
34
|
-
|
|
34
|
+
npoPlayer.doError(`Het is niet gelukt de stream op te halen: \n ${error.message}`, 500);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -2,18 +2,18 @@ import { getStreamObject } from './getstreamobject';
|
|
|
2
2
|
import NpoPlayer from '../../npoplayer';
|
|
3
3
|
import fetchMock from 'jest-fetch-mock';
|
|
4
4
|
fetchMock.enableMocks();
|
|
5
|
-
jest.mock('../../services/streamoptionsHandlers/
|
|
5
|
+
jest.mock('../../services/streamoptionsHandlers/streamOptionsHandler', () => ({
|
|
6
6
|
handleStreamOptions: jest.fn()
|
|
7
7
|
}));
|
|
8
8
|
describe('getStreamObject', () => {
|
|
9
|
-
let
|
|
9
|
+
let npoPlayer;
|
|
10
10
|
let apiPayload;
|
|
11
11
|
const testPlayerConfig = {
|
|
12
12
|
key: 'dummy key'
|
|
13
13
|
};
|
|
14
14
|
const div = document.createElement('div');
|
|
15
15
|
beforeEach(() => {
|
|
16
|
-
|
|
16
|
+
npoPlayer = new NpoPlayer(div, testPlayerConfig);
|
|
17
17
|
apiPayload = {
|
|
18
18
|
baseURL: 'http://example.com',
|
|
19
19
|
jwt: 'someToken',
|
|
@@ -24,25 +24,25 @@ describe('getStreamObject', () => {
|
|
|
24
24
|
});
|
|
25
25
|
it('should handle successful fetch', async () => {
|
|
26
26
|
fetchMock.mockResponseOnce(JSON.stringify({ foo: 'bar' }));
|
|
27
|
-
const result = await getStreamObject(
|
|
27
|
+
const result = await getStreamObject(npoPlayer, apiPayload);
|
|
28
28
|
expect(result).toEqual({ foo: 'bar' });
|
|
29
29
|
});
|
|
30
30
|
it('should handle fetch with bad response', async () => {
|
|
31
31
|
fetchMock.mockResponseOnce(JSON.stringify({ body: 'Bad Request' }), { status: 400 });
|
|
32
|
-
const doErrorSpy = jest.spyOn(
|
|
33
|
-
await getStreamObject(
|
|
34
|
-
expect(doErrorSpy).toHaveBeenCalledWith(expect.
|
|
32
|
+
const doErrorSpy = jest.spyOn(npoPlayer, 'doError');
|
|
33
|
+
await getStreamObject(npoPlayer, apiPayload);
|
|
34
|
+
expect(doErrorSpy).toHaveBeenCalledWith(expect.stringMatching('Het is niet gelukt de stream op te halen.'), 400);
|
|
35
35
|
});
|
|
36
36
|
it('should handle fetch timeout', async () => {
|
|
37
37
|
fetchMock.mockRejectOnce(new Error('AbortError'));
|
|
38
|
-
const doErrorSpy = jest.spyOn(
|
|
39
|
-
await getStreamObject(
|
|
40
|
-
expect(doErrorSpy).toHaveBeenCalledWith(expect.
|
|
38
|
+
const doErrorSpy = jest.spyOn(npoPlayer, 'doError');
|
|
39
|
+
await getStreamObject(npoPlayer, apiPayload);
|
|
40
|
+
expect(doErrorSpy).toHaveBeenCalledWith(expect.stringMatching('Het ophalen van de stream duurde te lang.'), 408);
|
|
41
41
|
});
|
|
42
42
|
it('should handle fetch with other errors', async () => {
|
|
43
43
|
fetchMock.mockRejectOnce(new Error('SomeError'));
|
|
44
|
-
const doErrorSpy = jest.spyOn(
|
|
45
|
-
await getStreamObject(
|
|
44
|
+
const doErrorSpy = jest.spyOn(npoPlayer, 'doError');
|
|
45
|
+
await getStreamObject(npoPlayer, apiPayload);
|
|
46
46
|
expect(doErrorSpy).toHaveBeenCalledWith(expect.stringContaining('SomeError'), 500);
|
|
47
47
|
});
|
|
48
48
|
});
|
|
@@ -8,11 +8,13 @@ export function handleStartOffset(playerContext, offset) {
|
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
10
|
const seek = () => {
|
|
11
|
+
player.off(NpoPlayerEvent.Ready, seek);
|
|
11
12
|
player.off(NpoPlayerEvent.SourceLoaded, seek);
|
|
12
13
|
player.off(NpoPlayerEvent.AdBreakFinished, seek);
|
|
13
14
|
player.off(NpoPlayerEvent.AdError, seek);
|
|
14
15
|
player.seek(offset);
|
|
15
16
|
};
|
|
17
|
+
player.on(NpoPlayerEvent.Ready, seek);
|
|
16
18
|
player.on(NpoPlayerEvent.SourceLoaded, seek);
|
|
17
19
|
player.on(NpoPlayerEvent.AdBreakFinished, seek);
|
|
18
20
|
player.on(NpoPlayerEvent.AdError, seek);
|
|
@@ -28,22 +30,22 @@ export function shiftToProgramStart(playerContext, timestamp) {
|
|
|
28
30
|
player.timeShift(timestamp);
|
|
29
31
|
}
|
|
30
32
|
export function handleLiveOffsetLogic(playerContext, options) {
|
|
31
|
-
const { player,
|
|
32
|
-
if (
|
|
33
|
+
const { player, npoPlayer } = playerContext;
|
|
34
|
+
if (npoPlayer.uiComponents.watchFromStartButton == undefined)
|
|
33
35
|
return;
|
|
34
36
|
if (options?.liveProgramTime == undefined) {
|
|
35
|
-
|
|
37
|
+
npoPlayer.uiComponents.watchFromStartButton.hide();
|
|
36
38
|
return;
|
|
37
39
|
}
|
|
38
|
-
|
|
40
|
+
npoPlayer.streamOptions.liveProgramTime = options.liveProgramTime;
|
|
39
41
|
if (player.isLive() && options.liveProgramTime > 0) {
|
|
40
|
-
|
|
42
|
+
npoPlayer.uiComponents.watchFromStartButton.show();
|
|
41
43
|
}
|
|
42
44
|
else {
|
|
43
|
-
|
|
45
|
+
npoPlayer.uiComponents.watchFromStartButton.hide();
|
|
44
46
|
}
|
|
45
47
|
if (options.liveOffset !== null && options.liveOffset !== false && options.liveProgramTime > 0) {
|
|
46
|
-
|
|
48
|
+
npoPlayer.uiComponents.watchFromStartButton.hide();
|
|
47
49
|
shiftToProgramStart(playerContext, options.liveProgramTime);
|
|
48
50
|
}
|
|
49
51
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type PlayerConfig } from 'bitmovin-player';
|
|
2
2
|
import NpoPlayer from 'npoplayer';
|
|
3
|
-
export declare function processPlayerConfig(
|
|
3
|
+
export declare function processPlayerConfig(npoPlayer: NpoPlayer, playerConfig: PlayerConfig): PlayerConfig;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LogLevel } from 'bitmovin-player';
|
|
2
2
|
import { isSafari } from '../../utilities/utilities.user-agent';
|
|
3
|
-
export function processPlayerConfig(
|
|
3
|
+
export function processPlayerConfig(npoPlayer, playerConfig) {
|
|
4
4
|
const processedConfig = playerConfig;
|
|
5
5
|
if (isSafari()) {
|
|
6
6
|
processedConfig.playback = {
|
|
@@ -17,9 +17,9 @@ export function processPlayerConfig(npoplayer, playerConfig) {
|
|
|
17
17
|
receiverVersion: 'v3',
|
|
18
18
|
messageNamespace: 'urn:x-cast:com.bitmovin.player.caf',
|
|
19
19
|
customReceiverConfig: {
|
|
20
|
-
drm:
|
|
21
|
-
profileName:
|
|
22
|
-
jwt:
|
|
20
|
+
drm: npoPlayer.drmProfile.drm,
|
|
21
|
+
profileName: npoPlayer.drmProfile.profileName,
|
|
22
|
+
jwt: npoPlayer.jwt
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
25
|
const userRemoteControlConfig = processedConfig.remotecontrol || defaultRemoteControlConfig;
|
|
@@ -2,4 +2,5 @@ import { StreamObject, StreamOptions } from 'types/interfaces';
|
|
|
2
2
|
import { SourceConfig } from 'bitmovin-player';
|
|
3
3
|
import { NpoPlayerServices } from '../../../services/services';
|
|
4
4
|
import { NPOTag } from '@npotag/tag';
|
|
5
|
+
export declare const getSubtitleLabels: (data: any) => string;
|
|
5
6
|
export declare function processSourceConfig(npoPlayerServices: NpoPlayerServices, source: string, _sourceConfig: SourceConfig | undefined, _streamObject: StreamObject, drm: string | undefined, streamOptions: StreamOptions, version: string, npoTagInstance: NPOTag | undefined): Promise<SourceConfig>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HttpResponseType } from 'bitmovin-player';
|
|
2
2
|
import { npoCdnProviders } from '../../../services/cdnProviders/cdnProviders';
|
|
3
3
|
import { replaceSpecialCharacters } from '../../utilities/utilities.text';
|
|
4
|
+
import subtitleLabelMap from '../../../lang/subtitleLabels/nl.json';
|
|
4
5
|
async function setDrm(sourceConfig, drm, _streamObject, useWidevineServerCertificate) {
|
|
5
6
|
const npoDrmGateway = 'https://npo-drm-gateway.samgcloud.nepworldwide.nl/authentication?custom_data=';
|
|
6
7
|
switch (drm) {
|
|
@@ -66,11 +67,9 @@ async function getServerCertificate(url) {
|
|
|
66
67
|
const response = await fetch(url);
|
|
67
68
|
return response.arrayBuffer();
|
|
68
69
|
}
|
|
69
|
-
const getSubtitleLabels = function (data) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
return data.label;
|
|
70
|
+
export const getSubtitleLabels = function (data) {
|
|
71
|
+
const langKey = data.lang.toLowerCase();
|
|
72
|
+
return subtitleLabelMap[langKey] || data.label || langKey;
|
|
74
73
|
};
|
|
75
74
|
const getQualityLabels = function (data) {
|
|
76
75
|
return data.height + 'p';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getSubtitleLabels } from './processsourceconfig';
|
|
2
|
+
describe('getSubtitleLabels', () => {
|
|
3
|
+
it('should return the correct language label for known lang codes', () => {
|
|
4
|
+
expect(getSubtitleLabels({ lang: 'ar' })).toBe('Arabisch');
|
|
5
|
+
expect(getSubtitleLabels({ lang: 'bg' })).toBe('Bulgaars');
|
|
6
|
+
expect(getSubtitleLabels({ lang: 'de' })).toBe('Duits');
|
|
7
|
+
expect(getSubtitleLabels({ lang: 'en' })).toBe('Engels');
|
|
8
|
+
expect(getSubtitleLabels({ lang: 'es' })).toBe('Spaans');
|
|
9
|
+
expect(getSubtitleLabels({ lang: 'fr' })).toBe('Frans');
|
|
10
|
+
expect(getSubtitleLabels({ lang: 'it' })).toBe('Italiaans');
|
|
11
|
+
expect(getSubtitleLabels({ lang: 'nl' })).toBe('Nederlands');
|
|
12
|
+
expect(getSubtitleLabels({ lang: 'ma' })).toBe('Marokkaans');
|
|
13
|
+
expect(getSubtitleLabels({ lang: 'pl' })).toBe('Pools');
|
|
14
|
+
expect(getSubtitleLabels({ lang: 'ua' })).toBe('Oekraïens');
|
|
15
|
+
expect(getSubtitleLabels({ lang: 'tr' })).toBe('Turks');
|
|
16
|
+
});
|
|
17
|
+
it('should return the original label if the lang code is unknown', () => {
|
|
18
|
+
expect(getSubtitleLabels({ lang: 'jp', label: 'Japanese' })).toBe('Japanese');
|
|
19
|
+
expect(getSubtitleLabels({ lang: 'jp' })).toBe('jp');
|
|
20
|
+
});
|
|
21
|
+
it('should handle mixed case lang codes', () => {
|
|
22
|
+
expect(getSubtitleLabels({ lang: 'EN' })).toBe('Engels');
|
|
23
|
+
expect(getSubtitleLabels({ lang: 'Fr' })).toBe('Frans');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -12,7 +12,7 @@ export function startPlayerTracker(playerInstance, duration, version, source) {
|
|
|
12
12
|
stream_length: duration,
|
|
13
13
|
stream_id: validatePrid(source),
|
|
14
14
|
player_id: 'npoplayer-web',
|
|
15
|
-
av_type: playerInstance.
|
|
15
|
+
av_type: playerInstance.npoPlayerServices.getAVType(playerInstance.streamObject.stream.avType),
|
|
16
16
|
player_version: version,
|
|
17
17
|
sko_player_version: '1.0.0'
|
|
18
18
|
};
|
package/lib/lang/nl.json
CHANGED
package/lib/npoplayer.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { type InitialisationProps } from '@npotag/tag/dist/types/src/npoTag';
|
|
|
4
4
|
import { type PlayerAPI, type PlayerConfig, type SourceConfig } from 'bitmovin-player';
|
|
5
5
|
import { UIManager } from 'bitmovin-player-ui';
|
|
6
6
|
import { LogEmitter } from './types/classes';
|
|
7
|
-
import { type DRMProfile, type ApiPayload, type NPOTagObject, type StreamObject, type StreamOptions, type UIComponents, type TimeLineMarker, type
|
|
7
|
+
import { type DRMProfile, type ApiPayload, type NPOTagObject, type StreamObject, type StreamOptions, type UIComponents, type TimeLineMarker, type PlayerContext, type EventListeners, NpoPlayerUIVariants } from './types/interfaces';
|
|
8
8
|
export { type PlayerConfig, type InitialisationProps, type NPOTagObject, type StreamOptions, NpoPlayerUIVariants };
|
|
9
9
|
export default class NpoPlayer {
|
|
10
10
|
playerConfig: PlayerConfig | undefined;
|
|
@@ -30,10 +30,9 @@ export default class NpoPlayer {
|
|
|
30
30
|
isShowingPlayNextScreen: boolean;
|
|
31
31
|
canceledPlayNextScreen: boolean;
|
|
32
32
|
playerContext: PlayerContext | undefined;
|
|
33
|
-
|
|
33
|
+
npoPlayerServices: NpoPlayerServices;
|
|
34
34
|
eventListeners: EventListeners | undefined;
|
|
35
35
|
mockNpoPlayer: any;
|
|
36
|
-
userPreferences: LocalStorageData;
|
|
37
36
|
constructor(container: HTMLElement | {
|
|
38
37
|
container: HTMLElement;
|
|
39
38
|
playerConfig: PlayerConfig;
|
package/lib/npoplayer.js
CHANGED
|
@@ -12,7 +12,7 @@ import { logVersion } from './js/utilities/utilities.version';
|
|
|
12
12
|
import { getStreamDurationInSeconds } from './js/utilities/utilities.stream';
|
|
13
13
|
import { LogEmitter } from './types/classes';
|
|
14
14
|
import pkg from '../package.json';
|
|
15
|
-
import { NpoPlayerUIVariants
|
|
15
|
+
import { NpoPlayerUIVariants } from './types/interfaces';
|
|
16
16
|
import { nativeMobileUiFactory } from './ui/nativemobileuifactory';
|
|
17
17
|
import { setupMediaSessionActionHandlers } from './js/playeractions/handlers/mediasessionactions';
|
|
18
18
|
import { removeReplayClass } from './js/playeractions/handlers/removereplayclass';
|
|
@@ -45,9 +45,8 @@ export default class NpoPlayer {
|
|
|
45
45
|
this.isShowingPlayNextScreen = false;
|
|
46
46
|
this.canceledPlayNextScreen = false;
|
|
47
47
|
this.playerContext = undefined;
|
|
48
|
-
this.
|
|
48
|
+
this.npoPlayerServices = new NpoPlayerServices();
|
|
49
49
|
this.eventListeners = undefined;
|
|
50
|
-
this.userPreferences = {};
|
|
51
50
|
if (typeof container === 'object' && !(container instanceof HTMLElement)) {
|
|
52
51
|
const params = container;
|
|
53
52
|
this.container = params.container;
|
|
@@ -80,35 +79,25 @@ export default class NpoPlayer {
|
|
|
80
79
|
this.player = new Player(_container, processedPlayerConfig);
|
|
81
80
|
Player.addModule(getModuleExport(AdsModuleBM));
|
|
82
81
|
const npoPlayerAPI = new NpoPlayerAPI(this.player);
|
|
83
|
-
this.playerContext = { player: npoPlayerAPI,
|
|
84
|
-
this.
|
|
85
|
-
this.
|
|
86
|
-
this.
|
|
87
|
-
window.addEventListener('beforeunload', () => {
|
|
88
|
-
if (this.player) {
|
|
89
|
-
this.npoplayerServices.setStoredUserPrefs(LocalStorageValues.SUBTITLES_ENABLED, npoPlayerAPI.areSubtitlesEnabled().toString());
|
|
90
|
-
this.npoplayerServices.setStoredUserPrefs(LocalStorageValues.VOLUME, npoPlayerAPI.getVolume());
|
|
91
|
-
this.npoplayerServices.setStoredUserPrefs(LocalStorageValues.IS_MUTED, npoPlayerAPI.isMuted().toString());
|
|
92
|
-
}
|
|
93
|
-
});
|
|
82
|
+
this.playerContext = { player: npoPlayerAPI, npoPlayer: this };
|
|
83
|
+
this.npoPlayerServices.handleUserPrefs(this.playerContext);
|
|
84
|
+
this.npoPlayerServices.setAccessibilityAttributes(this.playerContext);
|
|
85
|
+
this.npoPlayerServices.handlePreferences(this.playerContext);
|
|
94
86
|
this.container.addEventListener('keydown', (e) => {
|
|
95
87
|
if (!this.playerContext)
|
|
96
88
|
return;
|
|
97
|
-
this.
|
|
89
|
+
this.npoPlayerServices.keyboardHandler(this.playerContext, e);
|
|
98
90
|
}, true);
|
|
99
91
|
}
|
|
100
92
|
async loadStream(source, options = {}) {
|
|
101
93
|
if (!this.playerContext)
|
|
102
94
|
return;
|
|
103
95
|
this.streamOptions = options;
|
|
104
|
-
if (this.player
|
|
96
|
+
if (!this.player) {
|
|
105
97
|
console.error('Er is nog geen player geladen.');
|
|
106
98
|
return;
|
|
107
99
|
}
|
|
108
|
-
|
|
109
|
-
const currentAd = this.player.ads.getActiveAdBreak().id;
|
|
110
|
-
this.player.ads.discardAdBreak(currentAd);
|
|
111
|
-
}
|
|
100
|
+
this.npoPlayerServices.discardAdBreak(this.playerContext);
|
|
112
101
|
let _streamObject;
|
|
113
102
|
const sourceIsUrl = isUrl(source);
|
|
114
103
|
const sourceIsMedia = await isMediaUrl(source);
|
|
@@ -131,12 +120,13 @@ export default class NpoPlayer {
|
|
|
131
120
|
customData5: this.version
|
|
132
121
|
}
|
|
133
122
|
};
|
|
123
|
+
await this.playerContext.player.createUIManager(this.playerContext, this.variant);
|
|
134
124
|
await this.playerContext.player?.load(this.sourceConfig);
|
|
135
125
|
getDurationAndStartPlayerTracker();
|
|
136
126
|
}
|
|
137
127
|
else if (sourceIsJWTToken) {
|
|
138
128
|
this.jwt = source;
|
|
139
|
-
const profile = await this.
|
|
129
|
+
const profile = await this.npoPlayerServices.decideProfile(this.playerContext, options?.preferredDRM ?? '');
|
|
140
130
|
const defaultEndpoint = 'https://prod.npoplayer.nl/';
|
|
141
131
|
const endpoint = options?.endpoint ?? defaultEndpoint;
|
|
142
132
|
const payload = {
|
|
@@ -153,12 +143,10 @@ export default class NpoPlayer {
|
|
|
153
143
|
}
|
|
154
144
|
}
|
|
155
145
|
};
|
|
146
|
+
await this.playerContext.player.createUIManager(this.playerContext, this.variant);
|
|
156
147
|
try {
|
|
157
148
|
_streamObject = await getStreamObject(this, payload);
|
|
158
149
|
this.streamObject = _streamObject;
|
|
159
|
-
if (_streamObject) {
|
|
160
|
-
await this.playerContext.player.createUIManager(this.playerContext, this.variant);
|
|
161
|
-
}
|
|
162
150
|
}
|
|
163
151
|
catch (error) {
|
|
164
152
|
this.doError('Het is niet gelukt de stream op te halen. \n' + error);
|
|
@@ -168,8 +156,8 @@ export default class NpoPlayer {
|
|
|
168
156
|
if (this.streamObject?.stream == undefined)
|
|
169
157
|
return;
|
|
170
158
|
const drmType = this.streamObject.stream.drmType ?? undefined;
|
|
171
|
-
this.sourceConfig = await playerAction.processSourceConfig(this.
|
|
172
|
-
await this.
|
|
159
|
+
this.sourceConfig = await playerAction.processSourceConfig(this.npoPlayerServices, source, options.sourceConfig ?? {}, this.streamObject, drmType && drmType.length > 0 ? profile.drm : undefined, this.streamOptions, this.version, this.npoTag?.npoTagInstance);
|
|
160
|
+
await this.npoPlayerServices.verifyDRM(this.playerContext, payload);
|
|
173
161
|
setupMediaSessionActionHandlers(this.player, this.sourceConfig, _streamObject);
|
|
174
162
|
logEvent(this, 'load');
|
|
175
163
|
let streamDuration = _streamObject.metadata.duration;
|
|
@@ -192,7 +180,7 @@ export default class NpoPlayer {
|
|
|
192
180
|
this.streamObject.assets.preroll) {
|
|
193
181
|
this.player.on(PlayerEvent.AdBreakFinished, initAndStartTracker);
|
|
194
182
|
this.player.on(PlayerEvent.AdError, initAndStartTracker);
|
|
195
|
-
await this.
|
|
183
|
+
await this.npoPlayerServices.schedulePreRolls(this.playerContext);
|
|
196
184
|
}
|
|
197
185
|
else {
|
|
198
186
|
initAndStartTracker();
|
|
@@ -201,11 +189,12 @@ export default class NpoPlayer {
|
|
|
201
189
|
else {
|
|
202
190
|
this.doError(`Het is niet gelukt de stream op te halen: \n Input is geen valide token of media object.`, 500);
|
|
203
191
|
}
|
|
204
|
-
this.
|
|
205
|
-
this.
|
|
206
|
-
|
|
192
|
+
this.npoPlayerServices.handleStreamOptions(this.playerContext);
|
|
193
|
+
this.npoPlayerServices.setupNicamKijkwijzerIcons(this.playerContext);
|
|
194
|
+
this.player.on(PlayerEvent.Ready, () => {
|
|
195
|
+
this.npoPlayerServices.showNicamAfterUiDelay(this.playerContext);
|
|
207
196
|
});
|
|
208
|
-
this.
|
|
197
|
+
this.npoPlayerServices.handleVerticalVideoControls(this.playerContext, this.variant);
|
|
209
198
|
this.player.on(PlayerEvent.Seek, () => {
|
|
210
199
|
removeReplayClass(this.player);
|
|
211
200
|
});
|
|
@@ -226,7 +215,7 @@ export default class NpoPlayer {
|
|
|
226
215
|
this.player.on(PlayerEvent.Ready, setLiveOffsetListener);
|
|
227
216
|
}
|
|
228
217
|
doError(input, status) {
|
|
229
|
-
if (this.player
|
|
218
|
+
if (!this.player)
|
|
230
219
|
return;
|
|
231
220
|
if (status) {
|
|
232
221
|
this.logEmitter.emit('logError', status);
|
|
@@ -328,6 +317,9 @@ export default class NpoPlayer {
|
|
|
328
317
|
clearInterval(this.npoTag?.heartbeatInterval);
|
|
329
318
|
}
|
|
330
319
|
logEvent(this, 'stop');
|
|
320
|
+
if (this.playerContext) {
|
|
321
|
+
this.npoPlayerServices.removeUivisiblityHandlers(this.playerContext);
|
|
322
|
+
}
|
|
331
323
|
this.uiManager?.release();
|
|
332
324
|
this.uiManager = undefined;
|
|
333
325
|
await this.player?.destroy();
|
package/lib/npoplayer.test.js
CHANGED
|
@@ -3,7 +3,7 @@ const div = document.createElement('div');
|
|
|
3
3
|
const testPlayerConfig = {
|
|
4
4
|
key: 'dummy-key'
|
|
5
5
|
};
|
|
6
|
-
jest.mock('./services/streamoptionsHandlers/
|
|
6
|
+
jest.mock('./services/streamoptionsHandlers/streamOptionsHandler', () => ({
|
|
7
7
|
handleStreamOptions: jest.fn()
|
|
8
8
|
}));
|
|
9
9
|
let player;
|
package/lib/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npo/player",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"description": "NPO Player",
|
|
5
5
|
"author": "Publieke Omroep <player@npo.nl>",
|
|
6
6
|
"contributors": [
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"webpack-dev-server": "^4.11.1"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@npotag/tag": "3.2.
|
|
92
|
+
"@npotag/tag": "3.2.4",
|
|
93
93
|
"bitmovin-player": "^8.166.0",
|
|
94
94
|
"bitmovin-player-ui": "3.67.0"
|
|
95
95
|
},
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { NpoPlayerEvent } from '../../types/events';
|
|
2
2
|
import { addAccessibilityAttributes } from '../../ui/handlers/accessibilityhandler';
|
|
3
3
|
export function setupAccessibilityAttributes(playerContext) {
|
|
4
|
-
const { player,
|
|
4
|
+
const { player, npoPlayer } = playerContext;
|
|
5
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);
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
player?.enableSubtitles();
|
|
12
|
-
}
|
|
13
|
-
addAccessibilityAttributes(npoplayer.container, npoplayer.streamObject.metadata);
|
|
10
|
+
addAccessibilityAttributes(npoPlayer.container, npoPlayer.streamObject.metadata);
|
|
14
11
|
};
|
|
15
12
|
for (const event of events) {
|
|
16
13
|
player?.on(event, triggerAddAccessibilityAttributes);
|
|
@@ -31,14 +31,11 @@ describe('setupAccessibilityAttributes', () => {
|
|
|
31
31
|
};
|
|
32
32
|
playerContext = {
|
|
33
33
|
player: mockPlayerAPI,
|
|
34
|
-
|
|
34
|
+
npoPlayer: {
|
|
35
35
|
...mockNpoPlayer,
|
|
36
36
|
streamOptions: {
|
|
37
37
|
enableSubtitles: false
|
|
38
38
|
},
|
|
39
|
-
userPreferences: {
|
|
40
|
-
subtitles_enabled: 'false'
|
|
41
|
-
},
|
|
42
39
|
container: document.createElement('div'),
|
|
43
40
|
streamObject: {},
|
|
44
41
|
playerConfig: {},
|
|
@@ -69,20 +66,6 @@ describe('setupAccessibilityAttributes', () => {
|
|
|
69
66
|
afterEach(() => {
|
|
70
67
|
jest.clearAllMocks();
|
|
71
68
|
});
|
|
72
|
-
it('should enable subtitles if playerContext.npoplayer.userPreferences.subtitles_enabled is "true"', () => {
|
|
73
|
-
playerContext.npoplayer.userPreferences.subtitles_enabled = 'true';
|
|
74
|
-
setupAccessibilityAttributes(playerContext);
|
|
75
|
-
const triggerFunction = mockAddEventListener.mock.calls[0][1];
|
|
76
|
-
triggerFunction();
|
|
77
|
-
expect(mockEnableSubtitles).toHaveBeenCalled();
|
|
78
|
-
});
|
|
79
|
-
it('should enable subtitles if streamOptions.enableSubtitles is true', () => {
|
|
80
|
-
playerContext.npoplayer.streamOptions.enableSubtitles = true;
|
|
81
|
-
setupAccessibilityAttributes(playerContext);
|
|
82
|
-
const triggerFunction = mockAddEventListener.mock.calls[0][1];
|
|
83
|
-
triggerFunction();
|
|
84
|
-
expect(mockEnableSubtitles).toHaveBeenCalled();
|
|
85
|
-
});
|
|
86
69
|
it('should set up event listeners for specified events', () => {
|
|
87
70
|
setupAccessibilityAttributes(playerContext);
|
|
88
71
|
expect(mockAddEventListener).toHaveBeenCalledTimes(3);
|
|
@@ -103,6 +86,6 @@ describe('setupAccessibilityAttributes', () => {
|
|
|
103
86
|
setupAccessibilityAttributes(playerContext);
|
|
104
87
|
const triggerFunction = mockAddEventListener.mock.calls[0][1];
|
|
105
88
|
triggerFunction();
|
|
106
|
-
expect(addAccessibilityAttributes).toHaveBeenCalledWith(playerContext.
|
|
89
|
+
expect(addAccessibilityAttributes).toHaveBeenCalledWith(playerContext.npoPlayer.container, playerContext.npoPlayer.streamObject.metadata);
|
|
107
90
|
});
|
|
108
91
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export function discardAdBreak(playerContext) {
|
|
2
|
-
const {
|
|
3
|
-
const { adBreakActive } =
|
|
2
|
+
const { npoPlayer, player } = playerContext;
|
|
3
|
+
const { adBreakActive } = npoPlayer;
|
|
4
4
|
if (!player || adBreakActive === false)
|
|
5
5
|
return;
|
|
6
6
|
const activeAdBreak = player.getActiveAdBreak();
|
|
7
7
|
if (activeAdBreak?.id) {
|
|
8
|
-
player.discardAdBreak(activeAdBreak.id);
|
|
8
|
+
player.playerAPI.ads.discardAdBreak(activeAdBreak.id);
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
npoPlayer.adBreakActive = false;
|
|
11
11
|
}
|
|
@@ -2,59 +2,71 @@ import createPlayerContextMock, { createMockNpoPlayer, createMockNpoPlayerAPI }
|
|
|
2
2
|
import { discardAdBreak } from './discardAdBreak';
|
|
3
3
|
describe('discardAdBreak', () => {
|
|
4
4
|
let mockNpoPlayerAPI;
|
|
5
|
-
let
|
|
5
|
+
let npoPlayerMock;
|
|
6
6
|
const activeAdBreakMock = { id: 'ad-break-id' };
|
|
7
7
|
afterEach(() => {
|
|
8
8
|
jest.resetAllMocks();
|
|
9
9
|
});
|
|
10
|
+
it('should not discard ad break if player is undefined', () => {
|
|
11
|
+
npoPlayerMock = createMockNpoPlayer({
|
|
12
|
+
adBreakActive: true
|
|
13
|
+
});
|
|
14
|
+
const playerContextMock = createPlayerContextMock({
|
|
15
|
+
player: undefined,
|
|
16
|
+
npoPlayer: npoPlayerMock
|
|
17
|
+
});
|
|
18
|
+
discardAdBreak(playerContextMock);
|
|
19
|
+
expect(npoPlayerMock.adBreakActive).toBe(true);
|
|
20
|
+
});
|
|
10
21
|
it('should not discard ad break if adBreakActive is false', () => {
|
|
11
22
|
mockNpoPlayerAPI = createMockNpoPlayerAPI({
|
|
12
|
-
getActiveAdBreak: jest.fn().mockReturnValue(
|
|
23
|
+
getActiveAdBreak: jest.fn().mockReturnValue(activeAdBreakMock),
|
|
13
24
|
discardAdBreak: jest.fn()
|
|
14
25
|
});
|
|
15
|
-
|
|
26
|
+
npoPlayerMock = createMockNpoPlayer({
|
|
16
27
|
adBreakActive: false
|
|
17
28
|
});
|
|
18
29
|
const playerContextMock = createPlayerContextMock({
|
|
19
30
|
player: mockNpoPlayerAPI,
|
|
20
|
-
|
|
31
|
+
npoPlayer: npoPlayerMock
|
|
21
32
|
});
|
|
22
33
|
discardAdBreak(playerContextMock);
|
|
23
34
|
expect(mockNpoPlayerAPI.getActiveAdBreak).not.toHaveBeenCalled();
|
|
24
|
-
expect(mockNpoPlayerAPI.discardAdBreak).not.toHaveBeenCalled();
|
|
35
|
+
expect(mockNpoPlayerAPI.playerAPI.ads.discardAdBreak).not.toHaveBeenCalled();
|
|
36
|
+
expect(npoPlayerMock.adBreakActive).toBe(false);
|
|
25
37
|
});
|
|
26
38
|
it('should discard active ad break if adBreakActive is true and ad break exists', () => {
|
|
27
39
|
mockNpoPlayerAPI = createMockNpoPlayerAPI({
|
|
28
40
|
getActiveAdBreak: jest.fn().mockReturnValue(activeAdBreakMock),
|
|
29
41
|
discardAdBreak: jest.fn()
|
|
30
42
|
});
|
|
31
|
-
|
|
43
|
+
npoPlayerMock = createMockNpoPlayer({
|
|
32
44
|
adBreakActive: true
|
|
33
45
|
});
|
|
34
46
|
const playerContextMock = createPlayerContextMock({
|
|
35
47
|
player: mockNpoPlayerAPI,
|
|
36
|
-
|
|
48
|
+
npoPlayer: npoPlayerMock
|
|
37
49
|
});
|
|
38
50
|
discardAdBreak(playerContextMock);
|
|
39
51
|
expect(mockNpoPlayerAPI.getActiveAdBreak).toHaveBeenCalled();
|
|
40
|
-
expect(mockNpoPlayerAPI.discardAdBreak).toHaveBeenCalledWith(activeAdBreakMock.id);
|
|
41
|
-
expect(
|
|
52
|
+
expect(mockNpoPlayerAPI.playerAPI.ads.discardAdBreak).toHaveBeenCalledWith(activeAdBreakMock.id);
|
|
53
|
+
expect(npoPlayerMock.adBreakActive).toBe(false);
|
|
42
54
|
});
|
|
43
55
|
it('should not discard ad break if active ad break does not exist', () => {
|
|
44
56
|
mockNpoPlayerAPI = createMockNpoPlayerAPI({
|
|
45
57
|
getActiveAdBreak: jest.fn().mockReturnValue(undefined),
|
|
46
58
|
discardAdBreak: jest.fn()
|
|
47
59
|
});
|
|
48
|
-
|
|
60
|
+
npoPlayerMock = createMockNpoPlayer({
|
|
49
61
|
adBreakActive: true
|
|
50
62
|
});
|
|
51
63
|
const playerContextMock = createPlayerContextMock({
|
|
52
64
|
player: mockNpoPlayerAPI,
|
|
53
|
-
|
|
65
|
+
npoPlayer: npoPlayerMock
|
|
54
66
|
});
|
|
55
67
|
discardAdBreak(playerContextMock);
|
|
56
68
|
expect(mockNpoPlayerAPI.getActiveAdBreak).toHaveBeenCalled();
|
|
57
|
-
expect(mockNpoPlayerAPI.discardAdBreak).not.toHaveBeenCalled();
|
|
58
|
-
expect(
|
|
69
|
+
expect(mockNpoPlayerAPI.playerAPI.ads.discardAdBreak).not.toHaveBeenCalled();
|
|
70
|
+
expect(npoPlayerMock.adBreakActive).toBe(false);
|
|
59
71
|
});
|
|
60
72
|
});
|