@npo/player 1.24.7 → 1.25.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.test.js +2 -2
- package/lib/js/playeractions/handlers/processplayerconfig.js +14 -0
- package/lib/js/playeractions/handlers/processplayerconfig.test.d.ts +1 -0
- package/lib/js/playeractions/handlers/processplayerconfig.test.js +116 -0
- package/lib/js/playeractions/handlers/processsourceconfig.d.ts +2 -1
- package/lib/js/playeractions/handlers/processsourceconfig.js +16 -5
- package/lib/js/settings/localization.d.ts +76 -1
- package/lib/js/settings/localization.js +2 -2
- package/lib/js/tracking/handlers/eventbinding.js +25 -17
- package/lib/js/tracking/handlers/eventlogging.js +3 -8
- package/lib/js/tracking/handlers/playertrackerinit.d.ts +2 -2
- package/lib/js/tracking/handlers/playertrackerinit.js +8 -6
- package/lib/js/tracking/handlers/playertrackerinit.test.d.ts +1 -0
- package/lib/js/tracking/handlers/playertrackerinit.test.js +74 -0
- package/lib/js/utilities/utilities.element.d.ts +6 -0
- package/lib/js/utilities/utilities.element.js +10 -0
- package/lib/js/utilities/utilities.element.test.js +18 -5
- package/lib/npoplayer.d.ts +13 -3
- package/lib/npoplayer.js +41 -26
- package/lib/npoplayer.test.js +12 -4
- package/lib/package.json +2 -2
- package/lib/services/cdnProviders/cdnProviders.js +4 -2
- package/lib/services/nicamHandlers/nicamhandler.d.ts +6 -0
- package/lib/{ui/handlers → services/nicamHandlers}/nicamhandler.js +14 -6
- package/lib/services/nicamHandlers/nicamhandler.test.js +69 -0
- package/lib/services/npoPlayerAPI/npoPlayerAPI.d.ts +1 -0
- package/lib/services/npoPlayerAPI/npoPlayerAPI.js +6 -3
- package/lib/services/segmentHandlers/setSegmentMarkers.js +1 -1
- package/lib/services/services.d.ts +3 -0
- package/lib/services/services.js +7 -0
- package/lib/services/streamoptionsHandlers/steamOptionsHandler.d.ts +6 -0
- package/lib/services/streamoptionsHandlers/steamOptionsHandler.js +78 -0
- package/lib/services/streamoptionsHandlers/streamOptionsHandler.test.js +187 -0
- package/lib/src/js/playeractions/handlers/processplayerconfig.test.d.ts +1 -0
- package/lib/src/js/playeractions/handlers/processsourceconfig.d.ts +2 -1
- package/lib/src/js/settings/localization.d.ts +76 -1
- package/lib/src/js/tracking/handlers/playertrackerinit.d.ts +2 -2
- package/lib/src/js/tracking/handlers/playertrackerinit.test.d.ts +1 -0
- package/lib/src/js/utilities/utilities.element.d.ts +6 -0
- package/lib/src/npoplayer.d.ts +13 -3
- package/lib/src/services/nicamHandlers/nicamhandler.d.ts +6 -0
- package/lib/src/services/nicamHandlers/nicamhandler.test.d.ts +1 -0
- package/lib/src/services/npoPlayerAPI/npoPlayerAPI.d.ts +1 -0
- package/lib/src/services/services.d.ts +3 -0
- package/lib/src/services/streamoptionsHandlers/steamOptionsHandler.d.ts +6 -0
- package/lib/src/services/streamoptionsHandlers/streamOptionsHandler.test.d.ts +1 -0
- package/lib/src/types/interfaces.d.ts +2 -1
- package/lib/src/ui/components/buttons.d.ts +6 -3
- package/lib/src/ui/components/controlbar.d.ts +2 -2
- package/lib/src/ui/components/nativemobile/buttons.d.ts +8 -0
- package/lib/src/ui/components/playnext.d.ts +1 -0
- package/lib/src/ui/components/topbar.d.ts +2 -2
- package/lib/src/ui/components/verticalvideo/controlbar.d.ts +2 -2
- package/lib/src/ui/handlers/timecontrolhandlers.d.ts +3 -3
- package/lib/src/ui/uicontainer.d.ts +2 -3
- package/lib/tests/mocks/mockNpoplayer.js +3 -0
- package/lib/tests/mocks/playerContextMock.js +1 -0
- package/lib/types/interfaces.d.ts +2 -1
- package/lib/ui/components/buttons.d.ts +6 -3
- package/lib/ui/components/buttons.js +17 -17
- package/lib/ui/components/controlbar.d.ts +2 -2
- package/lib/ui/components/controlbar.js +15 -10
- package/lib/ui/components/nativemobile/buttons.d.ts +8 -0
- package/lib/ui/components/nativemobile/buttons.js +41 -1
- package/lib/ui/components/nativemobile/controlbar.js +1 -2
- package/lib/ui/components/playnext.d.ts +1 -0
- package/lib/ui/components/topbar.d.ts +2 -2
- package/lib/ui/components/topbar.js +14 -9
- package/lib/ui/components/verticalvideo/controlbar.d.ts +2 -2
- package/lib/ui/components/verticalvideo/controlbar.js +4 -4
- package/lib/ui/handlers/timecontrolhandlers.d.ts +3 -3
- package/lib/ui/nativemobileuifactory.js +20 -24
- package/lib/ui/nativemobileuifactory.test.js +0 -5
- package/lib/ui/uicontainer.d.ts +2 -3
- package/lib/ui/uicontainer.js +7 -5
- package/package.json +2 -2
- package/src/style/components/_icons.scss +5 -0
- package/src/style/npoplayer.css +2 -1
- package/lib/src/ui/handlers/nicamhandler.d.ts +0 -6
- package/lib/src/ui/handlers/streamhandler.d.ts +0 -2
- package/lib/ui/handlers/nicamhandler.d.ts +0 -6
- package/lib/ui/handlers/nicamhandler.test.js +0 -36
- package/lib/ui/handlers/streamhandler.d.ts +0 -2
- package/lib/ui/handlers/streamhandler.js +0 -60
- /package/lib/{src/ui/handlers → services/nicamHandlers}/nicamhandler.test.d.ts +0 -0
- /package/lib/{ui/handlers/nicamhandler.test.d.ts → services/streamoptionsHandlers/streamOptionsHandler.test.d.ts} +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.25.0
|
|
15
15
|
|
|
16
16
|
The changelog is available at https://docs.npoplayer.nl/implementation/web/changelog/
|
|
17
17
|
|
|
@@ -2,8 +2,8 @@ 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('../../
|
|
6
|
-
|
|
5
|
+
jest.mock('../../services/streamoptionsHandlers/steamOptionsHandler', () => ({
|
|
6
|
+
handleStreamOptions: jest.fn()
|
|
7
7
|
}));
|
|
8
8
|
describe('getStreamObject', () => {
|
|
9
9
|
let npoplayer;
|
|
@@ -32,6 +32,20 @@ export function processPlayerConfig(npoplayer, playerConfig) {
|
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
34
|
processedConfig.remotecontrol = mergedRemoteControlConfig;
|
|
35
|
+
if (processedConfig.cast) {
|
|
36
|
+
console.warn("'cast' is deprecated in playerConfig. Please use 'remotecontrol' with 'GoogleCastRemoteControlConfig' instead.");
|
|
37
|
+
processedConfig.remotecontrol = {
|
|
38
|
+
...processedConfig.remotecontrol,
|
|
39
|
+
customReceiverConfig: {
|
|
40
|
+
...processedConfig.remotecontrol.customReceiverConfig,
|
|
41
|
+
...processedConfig.cast,
|
|
42
|
+
enable: processedConfig.remotecontrol.customReceiverConfig?.enable ??
|
|
43
|
+
(typeof processedConfig.cast?.enable === 'boolean'
|
|
44
|
+
? processedConfig.cast.enable.toString()
|
|
45
|
+
: processedConfig.cast?.enable)
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
35
49
|
if (!processedConfig.logs)
|
|
36
50
|
processedConfig.logs = {
|
|
37
51
|
level: LogLevel.ERROR
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { LogLevel } from 'bitmovin-player';
|
|
2
|
+
import { isSafari } from '../../utilities/utilities.user-agent';
|
|
3
|
+
import { processPlayerConfig } from './processplayerconfig';
|
|
4
|
+
jest.mock('../../utilities/utilities.user-agent', () => ({
|
|
5
|
+
isSafari: jest.fn()
|
|
6
|
+
}));
|
|
7
|
+
const mockNpoPlayer = {
|
|
8
|
+
drmProfile: {
|
|
9
|
+
drm: 'mockDrm',
|
|
10
|
+
profileName: 'mockProfileName'
|
|
11
|
+
},
|
|
12
|
+
jwt: 'mockJwt'
|
|
13
|
+
};
|
|
14
|
+
describe('processPlayerConfig', () => {
|
|
15
|
+
let playerConfig;
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
playerConfig = {
|
|
18
|
+
key: 'dummy-key'
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
test('should disable autoplay and fix DRM issues on Safari', () => {
|
|
22
|
+
;
|
|
23
|
+
isSafari.mockReturnValue(true);
|
|
24
|
+
const processedConfig = processPlayerConfig(mockNpoPlayer, playerConfig);
|
|
25
|
+
expect(processedConfig.playback?.autoplay).toBe(false);
|
|
26
|
+
expect(processedConfig.tweaks?.fairplay_ignore_duplicate_init_data_key_errors).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
test('should always set bitmovin logging to false', () => {
|
|
29
|
+
playerConfig.logs = { bitmovin: true };
|
|
30
|
+
const processedConfig = processPlayerConfig(mockNpoPlayer, playerConfig);
|
|
31
|
+
expect(processedConfig.logs?.bitmovin).toEqual(false);
|
|
32
|
+
});
|
|
33
|
+
test('make sure there is an (empty) advertising object', () => {
|
|
34
|
+
const processedConfig = processPlayerConfig(mockNpoPlayer, playerConfig);
|
|
35
|
+
expect(processedConfig.advertising).toEqual({});
|
|
36
|
+
});
|
|
37
|
+
test('should set default remoteControlConfig if none is provided', () => {
|
|
38
|
+
const processedConfig = processPlayerConfig(mockNpoPlayer, playerConfig);
|
|
39
|
+
expect(processedConfig.remotecontrol).toEqual({
|
|
40
|
+
type: 'googlecast',
|
|
41
|
+
receiverApplicationId: 'CC38EB17',
|
|
42
|
+
receiverVersion: 'v3',
|
|
43
|
+
messageNamespace: 'urn:x-cast:com.bitmovin.player.caf',
|
|
44
|
+
customReceiverConfig: {
|
|
45
|
+
drm: 'mockDrm',
|
|
46
|
+
profileName: 'mockProfileName',
|
|
47
|
+
jwt: 'mockJwt'
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
test('should merge default remoteControlConfig with user-defined remoteControlConfig', () => {
|
|
52
|
+
playerConfig.remotecontrol = {
|
|
53
|
+
type: 'googlecast',
|
|
54
|
+
receiverApplicationId: 'user-receiver-application-id',
|
|
55
|
+
customReceiverConfig: {
|
|
56
|
+
primaryColor: 'rgb(255, 0, 0)',
|
|
57
|
+
enable: 'false'
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const processedConfig = processPlayerConfig(mockNpoPlayer, playerConfig);
|
|
61
|
+
expect(processedConfig.remotecontrol).toEqual({
|
|
62
|
+
type: 'googlecast',
|
|
63
|
+
receiverApplicationId: 'user-receiver-application-id',
|
|
64
|
+
receiverVersion: 'v3',
|
|
65
|
+
messageNamespace: 'urn:x-cast:com.bitmovin.player.caf',
|
|
66
|
+
customReceiverConfig: {
|
|
67
|
+
drm: 'mockDrm',
|
|
68
|
+
profileName: 'mockProfileName',
|
|
69
|
+
jwt: 'mockJwt',
|
|
70
|
+
primaryColor: 'rgb(255, 0, 0)',
|
|
71
|
+
enable: 'false'
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
test('should convert deprecated cast configuration', () => {
|
|
76
|
+
playerConfig.cast = {
|
|
77
|
+
enable: false
|
|
78
|
+
};
|
|
79
|
+
const processedConfig = processPlayerConfig(mockNpoPlayer, playerConfig);
|
|
80
|
+
expect(processedConfig.remotecontrol?.customReceiverConfig?.enable).toBe('false');
|
|
81
|
+
});
|
|
82
|
+
test('should prefer customReceiverConfig over cast property', () => {
|
|
83
|
+
playerConfig = {
|
|
84
|
+
...playerConfig,
|
|
85
|
+
cast: {
|
|
86
|
+
enable: false
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
playerConfig.remotecontrol = {
|
|
90
|
+
type: 'googlecast',
|
|
91
|
+
customReceiverConfig: {
|
|
92
|
+
enable: 'true'
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const processedConfig = processPlayerConfig(mockNpoPlayer, playerConfig);
|
|
96
|
+
expect(processedConfig.remotecontrol?.customReceiverConfig?.enable).toBe('true');
|
|
97
|
+
});
|
|
98
|
+
test('should set default log level if logs are undefined', () => {
|
|
99
|
+
delete playerConfig.logs;
|
|
100
|
+
const processedConfig = processPlayerConfig(mockNpoPlayer, playerConfig);
|
|
101
|
+
expect(processedConfig.logs).toEqual({
|
|
102
|
+
bitmovin: false,
|
|
103
|
+
level: LogLevel.ERROR
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
test('should not set default log level if logs are defined', () => {
|
|
107
|
+
playerConfig.logs = {
|
|
108
|
+
level: LogLevel.WARN
|
|
109
|
+
};
|
|
110
|
+
const processedConfig = processPlayerConfig(mockNpoPlayer, playerConfig);
|
|
111
|
+
expect(processedConfig.logs).toEqual({
|
|
112
|
+
bitmovin: false,
|
|
113
|
+
level: LogLevel.WARN
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
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 function processSourceConfig(npoPlayerServices: NpoPlayerServices, source: string, _sourceConfig: SourceConfig | undefined, _streamObject: StreamObject, drm: string | undefined, streamOptions: StreamOptions, version: string, npoTagInstance: NPOTag | undefined): Promise<SourceConfig>;
|
|
@@ -102,7 +102,7 @@ function setStreamProfile(sourceConfig, _sourceConfig, _streamObject) {
|
|
|
102
102
|
}
|
|
103
103
|
return sourceConfig;
|
|
104
104
|
}
|
|
105
|
-
export async function processSourceConfig(
|
|
105
|
+
export async function processSourceConfig(npoPlayerServices, source, _sourceConfig = {}, _streamObject, drm = undefined, streamOptions, version, npoTagInstance) {
|
|
106
106
|
let sourceConfig = {};
|
|
107
107
|
sourceConfig.title = _sourceConfig.title
|
|
108
108
|
? replacePlaceholders(_sourceConfig.title, _streamObject.metadata)
|
|
@@ -118,11 +118,11 @@ export async function processSourceConfig(NpoPlayerServices, _sourceConfig = {},
|
|
|
118
118
|
};
|
|
119
119
|
if (streamOptions.fragments || _streamObject.segment) {
|
|
120
120
|
const segment = streamOptions.fragments
|
|
121
|
-
?
|
|
121
|
+
? npoPlayerServices.convertFragmentToSegment(streamOptions.fragments)
|
|
122
122
|
: _streamObject.segment;
|
|
123
123
|
if (segment) {
|
|
124
124
|
;
|
|
125
|
-
sourceConfig.markers =
|
|
125
|
+
sourceConfig.markers = npoPlayerServices.segmentMarkersHandler(segment, sourceConfig.metadata.title);
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
sourceConfig.subtitleTracks =
|
|
@@ -140,7 +140,6 @@ export async function processSourceConfig(NpoPlayerServices, _sourceConfig = {},
|
|
|
140
140
|
_sourceConfig.thumbnailTrack ?? _streamObject.assets.scrubbingThumbnail
|
|
141
141
|
? { url: _streamObject.assets.scrubbingThumbnail }
|
|
142
142
|
: undefined;
|
|
143
|
-
sourceConfig.options = _sourceConfig.options;
|
|
144
143
|
sourceConfig = setStreamProfile(sourceConfig, _sourceConfig, _streamObject);
|
|
145
144
|
sourceConfig = await setDrm(sourceConfig, drm, _streamObject, streamOptions.useWidevineServerCertificate ?? true);
|
|
146
145
|
const streamSource = _streamObject.stream.streamURL;
|
|
@@ -162,7 +161,7 @@ export async function processSourceConfig(NpoPlayerServices, _sourceConfig = {},
|
|
|
162
161
|
sourceConfig.analytics.title = _streamObject.metadata.title;
|
|
163
162
|
sourceConfig.analytics.customData2 = _streamObject.user.type;
|
|
164
163
|
sourceConfig.analytics.customData3 = npoPlayerServices.getAVType(_streamObject.stream.avType);
|
|
165
|
-
sourceConfig.analytics.customData4 =
|
|
164
|
+
sourceConfig.analytics.customData4 = npoTagInstance?.getParty();
|
|
166
165
|
sourceConfig.analytics.customData5 = version;
|
|
167
166
|
sourceConfig.analytics = {
|
|
168
167
|
...sourceConfig.analytics,
|
|
@@ -180,6 +179,18 @@ export async function processSourceConfig(NpoPlayerServices, _sourceConfig = {},
|
|
|
180
179
|
}
|
|
181
180
|
};
|
|
182
181
|
}
|
|
182
|
+
sourceConfig.metadata = {
|
|
183
|
+
...sourceConfig.metadata
|
|
184
|
+
};
|
|
185
|
+
sourceConfig.metadata.jwt = source;
|
|
186
|
+
sourceConfig.metadata.streamLinkAsJsonString = JSON.stringify(_streamObject);
|
|
187
|
+
sourceConfig.metadata.npoTagSession = String(npoTagInstance?.getSerializedSessionInfo());
|
|
188
|
+
sourceConfig.metadata.hasPreroll = _streamObject.metadata.hasPreroll || 'false';
|
|
189
|
+
sourceConfig.metadata.prerollUrl = _streamObject.assets.preroll || '';
|
|
190
|
+
sourceConfig.metadata.onScreenDebug = 'false';
|
|
191
|
+
sourceConfig.metadata.frameworkLevelDebug = 'false';
|
|
192
|
+
sourceConfig.metadata.description = sourceConfig.description || '';
|
|
193
|
+
sourceConfig.metadata.avType = npoPlayerServices.getAVType(_streamObject.stream.avType);
|
|
183
194
|
return sourceConfig;
|
|
184
195
|
}
|
|
185
196
|
function decidePoster(streamObject, sourceConfig, streamOptions) {
|
|
@@ -1,6 +1,81 @@
|
|
|
1
1
|
export declare const localizationConfig: {
|
|
2
2
|
language: string;
|
|
3
3
|
vocabularies: {
|
|
4
|
-
nl:
|
|
4
|
+
nl: {
|
|
5
|
+
"settings.video.quality": string;
|
|
6
|
+
"settings.audio.quality": string;
|
|
7
|
+
"settings.audio.track": string;
|
|
8
|
+
"settings.audio.mute": string;
|
|
9
|
+
"settings.audio.unmute": string;
|
|
10
|
+
"settings.audio.volume": string;
|
|
11
|
+
"settings.subtitles.window.color": string;
|
|
12
|
+
"settings.subtitles.window.opacity": string;
|
|
13
|
+
"settings.subtitles": string;
|
|
14
|
+
"settings.subtitles.font.color": string;
|
|
15
|
+
"settings.subtitles.font.opacity": string;
|
|
16
|
+
"settings.subtitles.background.color": string;
|
|
17
|
+
"settings.subtitles.background.opacity": string;
|
|
18
|
+
"colors.white": string;
|
|
19
|
+
"colors.black": string;
|
|
20
|
+
"colors.red": string;
|
|
21
|
+
"colors.green": string;
|
|
22
|
+
"colors.blue": string;
|
|
23
|
+
"colors.cyan": string;
|
|
24
|
+
"colors.yellow": string;
|
|
25
|
+
"colors.magenta": string;
|
|
26
|
+
percent: string;
|
|
27
|
+
"settings.subtitles.font.size": string;
|
|
28
|
+
"settings.subtitles.characterEdge": string;
|
|
29
|
+
"settings.subtitles.characterEdge.raised": string;
|
|
30
|
+
"settings.subtitles.characterEdge.depressed": string;
|
|
31
|
+
"settings.subtitles.characterEdge.uniform": string;
|
|
32
|
+
"settings.subtitles.characterEdge.dropshadowed": string;
|
|
33
|
+
"settings.subtitles.font.family": string;
|
|
34
|
+
"settings.subtitles.font.family.monospacedserif": string;
|
|
35
|
+
"settings.subtitles.font.family.proportionalserif": string;
|
|
36
|
+
"settings.subtitles.font.family.monospacedsansserif": string;
|
|
37
|
+
"settings.subtitles.font.family.proportionalsansserif": string;
|
|
38
|
+
"settings.subtitles.font.family.casual": string;
|
|
39
|
+
"settings.subtitles.font.family.cursive": string;
|
|
40
|
+
"settings.subtitles.font.family.smallcapital": string;
|
|
41
|
+
"settings.time.hours": string;
|
|
42
|
+
"settings.time.minutes": string;
|
|
43
|
+
"settings.time.seconds": string;
|
|
44
|
+
"ads.remainingTime": string;
|
|
45
|
+
settings: string;
|
|
46
|
+
fullscreen: string;
|
|
47
|
+
speed: string;
|
|
48
|
+
playPause: string;
|
|
49
|
+
play: string;
|
|
50
|
+
pause: string;
|
|
51
|
+
open: string;
|
|
52
|
+
close: string;
|
|
53
|
+
pictureInPicture: string;
|
|
54
|
+
appleAirplay: string;
|
|
55
|
+
googleCast: string;
|
|
56
|
+
vr: string;
|
|
57
|
+
off: string;
|
|
58
|
+
auto: string;
|
|
59
|
+
back: string;
|
|
60
|
+
reset: string;
|
|
61
|
+
replay: string;
|
|
62
|
+
normal: string;
|
|
63
|
+
default: string;
|
|
64
|
+
live: string;
|
|
65
|
+
"subtitle.example": string;
|
|
66
|
+
"subtitle.select": string;
|
|
67
|
+
playingOn: string;
|
|
68
|
+
connectingTo: string;
|
|
69
|
+
watermarkLink: string;
|
|
70
|
+
controlBar: string;
|
|
71
|
+
player: string;
|
|
72
|
+
videoPlayer: string;
|
|
73
|
+
audioPlayer: string;
|
|
74
|
+
seekBar: string;
|
|
75
|
+
"seekBar.value": string;
|
|
76
|
+
"seekBar.timeshift": string;
|
|
77
|
+
"seekBar.durationText": string;
|
|
78
|
+
"segment.unplayableTitle": string;
|
|
79
|
+
};
|
|
5
80
|
};
|
|
6
81
|
};
|
|
@@ -5,22 +5,24 @@ export function bindPlayerEvents(npoPlayer, player) {
|
|
|
5
5
|
if (player == undefined)
|
|
6
6
|
return;
|
|
7
7
|
const isLiveStream = npoPlayer.streamObject.stream.isLiveStream;
|
|
8
|
-
let currentTime = 0;
|
|
9
8
|
let isNewSource = true;
|
|
9
|
+
let data = {};
|
|
10
10
|
const timeDifference = (time) => {
|
|
11
11
|
if (time === undefined || time === null)
|
|
12
12
|
return;
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const currentUnixTime = Date.now() / 1000;
|
|
14
|
+
const timeOffset = (time - currentUnixTime).toFixed(3);
|
|
15
|
+
const threeDecimalTime = time.toFixed(3);
|
|
16
|
+
const currentTime = isLiveStream ? +timeOffset : +threeDecimalTime;
|
|
17
|
+
data = { stream_position: currentTime };
|
|
15
18
|
};
|
|
16
19
|
const logEventHandler = (eventName) => {
|
|
17
20
|
return (e) => {
|
|
18
|
-
|
|
19
|
-
logEvent(npoPlayer, eventName,
|
|
21
|
+
timeDifference(e.time);
|
|
22
|
+
logEvent(npoPlayer, eventName, data);
|
|
20
23
|
};
|
|
21
24
|
};
|
|
22
25
|
const seekHandler = (e) => {
|
|
23
|
-
let data = {};
|
|
24
26
|
if (e.type === 'timeshift') {
|
|
25
27
|
const timeDifferencePosition = -1 * (Date.now() / 1000 - e.position);
|
|
26
28
|
const timeDifferenceTarget = -1 * (Date.now() / 1000 - e.target);
|
|
@@ -37,42 +39,48 @@ export function bindPlayerEvents(npoPlayer, player) {
|
|
|
37
39
|
}
|
|
38
40
|
logEvent(npoPlayer, 'seek', data);
|
|
39
41
|
};
|
|
40
|
-
const handleSourceLoaded = () => {
|
|
42
|
+
const handleSourceLoaded = (e) => {
|
|
43
|
+
timeDifference(e.time);
|
|
41
44
|
isNewSource = true;
|
|
42
45
|
if (isLiveStream) {
|
|
43
|
-
logEvent(npoPlayer, 'stop');
|
|
46
|
+
logEvent(npoPlayer, 'stop', data);
|
|
44
47
|
}
|
|
45
48
|
};
|
|
46
49
|
const handlePlay = (e) => {
|
|
50
|
+
timeDifference(e.time);
|
|
47
51
|
if (!isNewSource && e.issuer !== 'ui-seek') {
|
|
48
|
-
logEvent(npoPlayer, 'resume',
|
|
52
|
+
logEvent(npoPlayer, 'resume', data);
|
|
49
53
|
}
|
|
50
54
|
};
|
|
51
55
|
const pausedHandler = (e) => {
|
|
56
|
+
timeDifference(e.time);
|
|
52
57
|
if (e.issuer !== 'ui-seek') {
|
|
53
|
-
logEvent(npoPlayer, 'pause',
|
|
58
|
+
logEvent(npoPlayer, 'pause', data);
|
|
54
59
|
}
|
|
55
60
|
};
|
|
56
61
|
const handleTime = (e) => {
|
|
62
|
+
timeDifference(e.time);
|
|
57
63
|
if (isNewSource && !npoPlayer.adBreakActive) {
|
|
58
|
-
logEvent(npoPlayer, 'start',
|
|
64
|
+
logEvent(npoPlayer, 'start', data);
|
|
59
65
|
isNewSource = false;
|
|
60
66
|
}
|
|
61
67
|
else {
|
|
62
|
-
logEvent(npoPlayer, 'time',
|
|
68
|
+
logEvent(npoPlayer, 'time', data);
|
|
63
69
|
}
|
|
64
70
|
};
|
|
65
|
-
const handleViewModeChange = () => {
|
|
71
|
+
const handleViewModeChange = (e) => {
|
|
66
72
|
const newViewMode = player.getViewMode();
|
|
73
|
+
timeDifference(e.time);
|
|
67
74
|
if (newViewMode === ViewMode.Fullscreen) {
|
|
68
|
-
logEvent(npoPlayer, 'fullscreen',
|
|
75
|
+
logEvent(npoPlayer, 'fullscreen', data);
|
|
69
76
|
}
|
|
70
77
|
else {
|
|
71
|
-
logEvent(npoPlayer, 'windowed',
|
|
78
|
+
logEvent(npoPlayer, 'windowed', data);
|
|
72
79
|
}
|
|
73
80
|
};
|
|
74
|
-
const stopBeforeUnload = () => {
|
|
75
|
-
|
|
81
|
+
const stopBeforeUnload = (e) => {
|
|
82
|
+
timeDifference(e.time);
|
|
83
|
+
logEvent(npoPlayer, 'stop', data);
|
|
76
84
|
};
|
|
77
85
|
for (const [key, value] of logEventHandlers) {
|
|
78
86
|
player.off(key, value);
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
export function logEvent(npoPlayer, event, data) {
|
|
2
2
|
if (!npoPlayer.player || !npoPlayer.streamTracker || npoPlayer.adBreakActive || npoPlayer.player.isCasting())
|
|
3
3
|
return;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
catch (error) {
|
|
8
|
-
console.warn('Er gaat iets mis met de player API', error);
|
|
9
|
-
}
|
|
10
|
-
const streamOptions = { stream_position: npoPlayer.player.getCurrentTime() };
|
|
4
|
+
if (data === undefined || Object.keys(data).length === 0)
|
|
5
|
+
data = { stream_position: 0 };
|
|
11
6
|
const eventHandlers = {
|
|
12
7
|
start: npoPlayer.streamTracker.start,
|
|
13
8
|
buffering: npoPlayer.streamTracker.buffering,
|
|
@@ -27,5 +22,5 @@ export function logEvent(npoPlayer, event, data) {
|
|
|
27
22
|
};
|
|
28
23
|
const streamTrackerHandler = eventHandlers[event];
|
|
29
24
|
npoPlayer.logEmitter.emit('logEvent', event, data);
|
|
30
|
-
streamTrackerHandler(
|
|
25
|
+
streamTrackerHandler(data);
|
|
31
26
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type NPOTag } from '@npotag/tag';
|
|
1
|
+
import { type NPOTag, type PageTracker } from '@npotag/tag';
|
|
2
2
|
import { type InitialisationProps } from '@npotag/tag/dist/types/src/npoTag';
|
|
3
3
|
import type NpoPlayer from '../../../npoplayer';
|
|
4
|
-
export declare function initPlayerTracker(
|
|
4
|
+
export declare function initPlayerTracker(npoPlayer: NpoPlayer, _npoTag?: InitialisationProps, _npoTagInstance?: NPOTag, _npoTagPageTracker?: PageTracker): void;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { newATInternetPlugin, newGovoltePlugin, newPageTracker, newTag } from '@npotag/tag';
|
|
2
2
|
const npoTagPlugins = [newGovoltePlugin({ maxRetryCount: 5, delayBetweenRetriesInMs: 3000 }), newATInternetPlugin()];
|
|
3
|
-
export function initPlayerTracker(
|
|
4
|
-
if (
|
|
5
|
-
|
|
3
|
+
export function initPlayerTracker(npoPlayer, _npoTag, _npoTagInstance, _npoTagPageTracker) {
|
|
4
|
+
if (!npoPlayer.npoTag) {
|
|
5
|
+
npoPlayer.npoTag = {
|
|
6
6
|
npoTagInstance: undefined,
|
|
7
7
|
pageTracker: undefined,
|
|
8
8
|
heartbeatInterval: undefined
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
if (!npoPlayer.npoTag?.npoTagInstance) {
|
|
12
|
+
npoPlayer.npoTag.npoTagInstance = _npoTagInstance ?? (_npoTag ? newTag(_npoTag, npoTagPlugins) : undefined);
|
|
13
|
+
}
|
|
14
|
+
if (!npoPlayer.npoTag?.pageTracker && npoPlayer.npoTag?.npoTagInstance) {
|
|
15
|
+
npoPlayer.npoTag.pageTracker = _npoTagPageTracker ?? newPageTracker(npoPlayer.npoTag.npoTagInstance);
|
|
14
16
|
}
|
|
15
17
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { newPageTracker, newTag } from '@npotag/tag';
|
|
2
|
+
import { initPlayerTracker } from './playertrackerinit';
|
|
3
|
+
jest.mock('@npotag/tag', () => ({
|
|
4
|
+
newATInternetPlugin: jest.fn(),
|
|
5
|
+
newGovoltePlugin: jest.fn(),
|
|
6
|
+
newPageTracker: jest.fn(),
|
|
7
|
+
newTag: jest.fn()
|
|
8
|
+
}));
|
|
9
|
+
describe('initPlayerTracker', () => {
|
|
10
|
+
let mockNpoPlayer;
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
mockNpoPlayer = {
|
|
13
|
+
npoTag: undefined
|
|
14
|
+
};
|
|
15
|
+
jest.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
it('should initialize npoTag if it is undefined', () => {
|
|
18
|
+
initPlayerTracker(mockNpoPlayer);
|
|
19
|
+
expect(mockNpoPlayer.npoTag).toBeDefined();
|
|
20
|
+
expect(mockNpoPlayer.npoTag?.npoTagInstance).toBeUndefined();
|
|
21
|
+
expect(mockNpoPlayer.npoTag?.pageTracker).toBeUndefined();
|
|
22
|
+
});
|
|
23
|
+
it('should initialize npoTagInstance if _npoTagInstance is provided', () => {
|
|
24
|
+
const mockNpoTagInstance = {};
|
|
25
|
+
initPlayerTracker(mockNpoPlayer, undefined, mockNpoTagInstance);
|
|
26
|
+
expect(mockNpoPlayer.npoTag?.npoTagInstance).toBe(mockNpoTagInstance);
|
|
27
|
+
expect(mockNpoPlayer.npoTag?.pageTracker).toBeUndefined();
|
|
28
|
+
});
|
|
29
|
+
it('should create a new npoTagInstance if _npoTag is provided and _npoTagInstance is undefined', () => {
|
|
30
|
+
const mockNpoTag = {};
|
|
31
|
+
const mockNewTagInstance = {};
|
|
32
|
+
newTag.mockReturnValue(mockNewTagInstance);
|
|
33
|
+
initPlayerTracker(mockNpoPlayer, mockNpoTag);
|
|
34
|
+
expect(newTag).toHaveBeenCalledWith(mockNpoTag, expect.any(Array));
|
|
35
|
+
expect(mockNpoPlayer.npoTag?.npoTagInstance).toBe(mockNewTagInstance);
|
|
36
|
+
expect(mockNpoPlayer.npoTag?.pageTracker).toBeUndefined();
|
|
37
|
+
});
|
|
38
|
+
it('should initialize pageTracker if _npoTagPageTracker is provided', () => {
|
|
39
|
+
const mockPageTracker = {};
|
|
40
|
+
const mockNpoTagInstance = {};
|
|
41
|
+
mockNpoPlayer.npoTag = {
|
|
42
|
+
npoTagInstance: mockNpoTagInstance,
|
|
43
|
+
pageTracker: undefined,
|
|
44
|
+
heartbeatInterval: undefined
|
|
45
|
+
};
|
|
46
|
+
initPlayerTracker(mockNpoPlayer, undefined, mockNpoTagInstance, mockPageTracker);
|
|
47
|
+
expect(mockNpoPlayer.npoTag?.pageTracker).toBe(mockPageTracker);
|
|
48
|
+
});
|
|
49
|
+
it('should create a new pageTracker if _npoTagPageTracker is undefined', () => {
|
|
50
|
+
const mockNpoTagInstance = {};
|
|
51
|
+
const mockNewPageTracker = {};
|
|
52
|
+
newPageTracker.mockReturnValue(mockNewPageTracker);
|
|
53
|
+
mockNpoPlayer.npoTag = {
|
|
54
|
+
npoTagInstance: mockNpoTagInstance,
|
|
55
|
+
pageTracker: undefined,
|
|
56
|
+
heartbeatInterval: undefined
|
|
57
|
+
};
|
|
58
|
+
initPlayerTracker(mockNpoPlayer);
|
|
59
|
+
expect(newPageTracker).toHaveBeenCalledWith(mockNpoTagInstance);
|
|
60
|
+
expect(mockNpoPlayer.npoTag?.pageTracker).toBe(mockNewPageTracker);
|
|
61
|
+
});
|
|
62
|
+
it('should not overwrite existing pageTracker', () => {
|
|
63
|
+
const mockPageTracker = {};
|
|
64
|
+
const mockNpoTagInstance = {};
|
|
65
|
+
mockNpoPlayer.npoTag = {
|
|
66
|
+
npoTagInstance: mockNpoTagInstance,
|
|
67
|
+
pageTracker: mockPageTracker,
|
|
68
|
+
heartbeatInterval: undefined
|
|
69
|
+
};
|
|
70
|
+
initPlayerTracker(mockNpoPlayer);
|
|
71
|
+
expect(mockNpoPlayer.npoTag?.pageTracker).toBe(mockPageTracker);
|
|
72
|
+
expect(newPageTracker).not.toHaveBeenCalled();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -4,7 +4,13 @@ interface ElementByQuery {
|
|
|
4
4
|
}
|
|
5
5
|
interface RemoveClassFromElementByQuery extends ElementByQuery {
|
|
6
6
|
className: string;
|
|
7
|
+
condition: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface UpdateClassFromElementByQuery extends ElementByQuery {
|
|
10
|
+
className: string;
|
|
11
|
+
condition: boolean;
|
|
7
12
|
}
|
|
8
13
|
export declare function getElementByQuery({ container, query }: ElementByQuery): Element | null;
|
|
9
14
|
export declare function removeClassFromElementByQuery(params: RemoveClassFromElementByQuery): void;
|
|
15
|
+
export declare function updateClassFromElementByQuery(params: UpdateClassFromElementByQuery): void;
|
|
10
16
|
export {};
|
|
@@ -6,3 +6,13 @@ export function removeClassFromElementByQuery(params) {
|
|
|
6
6
|
const element = getElementByQuery({ container, query });
|
|
7
7
|
element?.classList.remove(className);
|
|
8
8
|
}
|
|
9
|
+
export function updateClassFromElementByQuery(params) {
|
|
10
|
+
const { className, container, query, condition } = params;
|
|
11
|
+
const element = getElementByQuery({ container, query });
|
|
12
|
+
if (condition && element) {
|
|
13
|
+
element.classList.add(className);
|
|
14
|
+
}
|
|
15
|
+
else if (element) {
|
|
16
|
+
element.classList.remove(className);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { getElementByQuery,
|
|
1
|
+
import { getElementByQuery, updateClassFromElementByQuery } from './utilities.element';
|
|
2
2
|
const CLASS = 'element-class';
|
|
3
|
+
const NEW_CLASS = 'new-class';
|
|
3
4
|
const ID = 'element-id';
|
|
4
5
|
const PARENT_ELEMENT = document.createElement('div');
|
|
5
6
|
const CHILD_ELEMENT_WITH_ID = document.createElement('div');
|
|
@@ -13,13 +14,25 @@ describe('getElementByQuery', () => {
|
|
|
13
14
|
expect(getElementByQuery({ container: PARENT_ELEMENT, query: `#${ID}` })).toEqual(CHILD_ELEMENT_WITH_ID);
|
|
14
15
|
});
|
|
15
16
|
});
|
|
16
|
-
describe('
|
|
17
|
-
it('should remove the specified class from
|
|
18
|
-
|
|
17
|
+
describe('updateClassFromElementByQuery', () => {
|
|
18
|
+
it('should remove the specified class from the queried element', () => {
|
|
19
|
+
updateClassFromElementByQuery({
|
|
19
20
|
container: PARENT_ELEMENT,
|
|
20
21
|
query: `.${CLASS}`,
|
|
21
|
-
className: CLASS
|
|
22
|
+
className: CLASS,
|
|
23
|
+
condition: false
|
|
22
24
|
});
|
|
23
25
|
expect(PARENT_ELEMENT.querySelector(`.${CLASS}`)).toBeNull();
|
|
24
26
|
});
|
|
27
|
+
it('should add the specified class to the queried element', () => {
|
|
28
|
+
const ELEMENT_WITHOUT_CLASS = document.createElement('div');
|
|
29
|
+
PARENT_ELEMENT.appendChild(ELEMENT_WITHOUT_CLASS);
|
|
30
|
+
updateClassFromElementByQuery({
|
|
31
|
+
container: PARENT_ELEMENT,
|
|
32
|
+
query: 'div:not([class])',
|
|
33
|
+
className: NEW_CLASS,
|
|
34
|
+
condition: true
|
|
35
|
+
});
|
|
36
|
+
expect(PARENT_ELEMENT.querySelector(`.${NEW_CLASS}`)).not.toBeNull();
|
|
37
|
+
});
|
|
25
38
|
});
|
package/lib/npoplayer.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NpoPlayerServices } from './services/services';
|
|
2
|
-
import { type StreamTracker, type NPOTag } from '@npotag/tag';
|
|
2
|
+
import { type StreamTracker, type NPOTag, type PageTracker } from '@npotag/tag';
|
|
3
3
|
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';
|
|
@@ -7,12 +7,15 @@ import { LogEmitter } from './types/classes';
|
|
|
7
7
|
import { type DRMProfile, type ApiPayload, type NPOTagObject, type StreamObject, type StreamOptions, type UIComponents, type TimeLineMarker, type LocalStorageData, 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
|
-
playerConfig: PlayerConfig;
|
|
10
|
+
playerConfig: PlayerConfig | undefined;
|
|
11
11
|
sourceConfig: SourceConfig;
|
|
12
12
|
streamObject: StreamObject;
|
|
13
13
|
player: PlayerAPI | undefined;
|
|
14
14
|
uiManager: UIManager | undefined;
|
|
15
15
|
npoTag: NPOTagObject | undefined;
|
|
16
|
+
npoTagInitialisation: InitialisationProps | undefined;
|
|
17
|
+
npoTagInstance: NPOTag | undefined;
|
|
18
|
+
npoTagPageTracker: PageTracker | undefined;
|
|
16
19
|
streamTracker: StreamTracker | undefined;
|
|
17
20
|
logEmitter: LogEmitter;
|
|
18
21
|
uiComponents: UIComponents;
|
|
@@ -31,7 +34,14 @@ export default class NpoPlayer {
|
|
|
31
34
|
eventListeners: EventListeners | undefined;
|
|
32
35
|
mockNpoPlayer: any;
|
|
33
36
|
userPreferences: LocalStorageData;
|
|
34
|
-
constructor(
|
|
37
|
+
constructor(container: HTMLElement | {
|
|
38
|
+
container: HTMLElement;
|
|
39
|
+
playerConfig: PlayerConfig;
|
|
40
|
+
npoTag?: InitialisationProps | undefined;
|
|
41
|
+
npoTagInstance?: NPOTag | undefined;
|
|
42
|
+
variant?: NpoPlayerUIVariants;
|
|
43
|
+
npoTagPageTracker?: PageTracker | undefined;
|
|
44
|
+
}, playerConfig?: PlayerConfig | undefined, npoTag?: InitialisationProps | undefined, npoTagInstance?: NPOTag | undefined, variant?: NpoPlayerUIVariants, npoTagPageTracker?: PageTracker | undefined);
|
|
35
45
|
initPlayer(_container: HTMLElement, playerConfig: PlayerConfig): void;
|
|
36
46
|
loadStream(source: string, options?: StreamOptions): Promise<void>;
|
|
37
47
|
doError(input: any, status?: number): void;
|