@24i/bigscreen-sdk 1.0.21-alpha.2355 → 1.0.21
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/package.json +5 -3
- package/packages/adobe-heartbeat/src/AdobeHeartbeat.ts +9 -9
- package/packages/developer-tools/PlayerDebugWindow/README.md +1 -1
- package/packages/developer-tools/src/PlayerDebugWindow/PlayerDebugWindow.tsx +5 -5
- package/packages/developer-tools/src/TechnicalInfo/TechnicalInfoProvider.ts +1 -1
- package/packages/device/src/driver/index.firetv.ts +1 -0
- package/packages/device/src/driver/index.smartcast.tv.ts +1 -0
- package/packages/device/src/resolver/resolver.ts +13 -0
- package/packages/driver-androidtv/src/DeviceAndroidTV.ts +3 -4
- package/packages/driver-androidtv/src/__mocks__/javaScriptBridge.ts +12 -0
- package/packages/driver-androidtv/src/types.ts +40 -0
- package/packages/driver-base/src/DeviceBase.ts +4 -0
- package/packages/driver-base/src/types/DeviceEvent.ts +2 -0
- package/packages/driver-firetv/src/DeviceFireTV.ts +18 -0
- package/packages/driver-firetv/src/__mocks__/javaScriptBridge.ts +30 -0
- package/packages/driver-firetv/src/index.ts +1 -0
- package/packages/driver-smartcast/src/DeviceSmartCast.ts +310 -0
- package/packages/driver-smartcast/src/__mocks__/api.ts +49 -0
- package/packages/driver-smartcast/src/index.ts +1 -0
- package/packages/driver-smartcast/src/keymap.ts +9 -0
- package/packages/driver-smartcast/src/types.ts +65 -0
- package/packages/gallup/src/Gallup.ts +3 -3
- package/packages/keyboard/src/KeyboardBase.tsx +9 -2
- package/packages/list/src/CenteredList/controller.ts +0 -1
- package/packages/player-ui/src/CurrentTime.tsx +2 -2
- package/packages/player-ui/src/Duration.tsx +2 -2
- package/packages/player-ui/src/PlayerUI.tsx +4 -4
- package/packages/player-ui/src/RemainingTime.tsx +2 -2
- package/packages/player-ui/src/Seekbar.tsx +3 -3
- package/packages/player-ui/src/Seeking.ts +4 -4
- package/packages/player-ui/src/Subtitles.tsx +2 -2
- package/packages/player-ui/src/mocks.ts +12 -4
- package/packages/player-ui/src/types.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@24i/bigscreen-sdk",
|
|
3
|
-
"version": "1.0.21
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"description": "SmartApps BIGscreen SDK monorepo",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@24i/appstage-shared-analytics": "1.0.16-alpha.58",
|
|
41
41
|
"@24i/appstage-shared-events-manager": "1.0.7",
|
|
42
42
|
"@24i/appstage-shared-perf-utils": "1.0.5",
|
|
43
|
-
"@24i/
|
|
43
|
+
"@24i/bigscreen-players-engine-base": "1.0.0",
|
|
44
44
|
"@24i/smartapps-datalayer": "3.0.9-alpha.1010",
|
|
45
45
|
"@sentry/browser": "7.35.0",
|
|
46
46
|
"@sentry/types": "7.35.0",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"@types/jest": "^29.5.2",
|
|
63
63
|
"@types/minimist": "^1.2.2",
|
|
64
64
|
"@types/node": "^18.7.18",
|
|
65
|
-
"@types/react": "
|
|
65
|
+
"@types/react": "18.0.33",
|
|
66
66
|
"babel-jest": "^29.4.3",
|
|
67
67
|
"chalk": "^5.2.0",
|
|
68
68
|
"coveralls": "^3.1.1",
|
|
@@ -118,9 +118,11 @@
|
|
|
118
118
|
"./driver-base": "./packages/driver-base/src/index.ts",
|
|
119
119
|
"./driver-browser": "./packages/driver-browser/src/index.ts",
|
|
120
120
|
"./driver-entone": "./packages/driver-entone/src/index.ts",
|
|
121
|
+
"./driver-firetv": "./packages/driver-firetv/src/index.ts",
|
|
121
122
|
"./driver-hbbtv": "./packages/driver-hbbtv/src/index.ts",
|
|
122
123
|
"./driver-kreatv": "./packages/driver-kreatv/src/index.ts",
|
|
123
124
|
"./driver-saphi": "./packages/driver-saphi/src/index.ts",
|
|
125
|
+
"./driver-smartcast": "./packages/driver-smartcast/src/index.ts",
|
|
124
126
|
"./driver-tizen": "./packages/driver-tizen/src/index.ts",
|
|
125
127
|
"./driver-vidaa": "./packages/driver-vidaa/src/index.ts",
|
|
126
128
|
"./driver-webos/scripts/template": "./packages/driver-webos/scripts/template.ts",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference path='./__external__/Adobe/Adobe.d.ts' />
|
|
2
|
-
import { IErrorEvent, PlayerBase } from '@24i/
|
|
2
|
+
import { IErrorEvent, PlayerBase } from '@24i/bigscreen-players-engine-base';
|
|
3
3
|
import { time } from '@24i/bigscreen-sdk/time';
|
|
4
4
|
import { SECOND_IN_MS } from '@24i/bigscreen-sdk/utils';
|
|
5
5
|
import { va as Adobe } from './__external__/Adobe/MediaSDK.min';
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
export class AdobeHeartbeat<CustomMetadata extends CustomerMetadata | void = void> {
|
|
16
16
|
static StreamType = Adobe.MediaHeartbeat.StreamType;
|
|
17
17
|
|
|
18
|
-
private player?: PlayerBase
|
|
18
|
+
private player?: PlayerBase;
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Heartbeat configuration object
|
|
@@ -32,7 +32,7 @@ export class AdobeHeartbeat<CustomMetadata extends CustomerMetadata | void = voi
|
|
|
32
32
|
* @param config - Heartbeat configuration object
|
|
33
33
|
* @param player - 24i universal player instance
|
|
34
34
|
*/
|
|
35
|
-
constructor(config: HeartbeatConfig, player?: PlayerBase
|
|
35
|
+
constructor(config: HeartbeatConfig, player?: PlayerBase) {
|
|
36
36
|
if (!window.s || !AppMeasurement) throw new Error('Missing Adobe Launch library!');
|
|
37
37
|
this.config = config;
|
|
38
38
|
this.player = player;
|
|
@@ -67,10 +67,10 @@ export class AdobeHeartbeat<CustomMetadata extends CustomerMetadata | void = voi
|
|
|
67
67
|
return {
|
|
68
68
|
getCurrentPlaybackTime: () => {
|
|
69
69
|
if (!this.player) return 0;
|
|
70
|
-
const { currentTime } = this.player.
|
|
70
|
+
const { currentTime } = this.player.mediaInfo || {};
|
|
71
71
|
if (this.player.live) {
|
|
72
72
|
try {
|
|
73
|
-
const { programEnd = NaN } = this.player.
|
|
73
|
+
const { programEnd = NaN } = this.player.metadata;
|
|
74
74
|
return Math.floor((programEnd - currentTime) / SECOND_IN_MS)
|
|
75
75
|
|| time.getCurrentUnixTime();
|
|
76
76
|
} catch (e) {
|
|
@@ -81,7 +81,7 @@ export class AdobeHeartbeat<CustomMetadata extends CustomerMetadata | void = voi
|
|
|
81
81
|
},
|
|
82
82
|
getQoSObject: () => {
|
|
83
83
|
if (!this.player) return Adobe.MediaHeartbeat.createQoSObject();
|
|
84
|
-
const { bitrate, droppedVideoFrames } = this.player.
|
|
84
|
+
const { bitrate, droppedVideoFrames } = this.player.mediaInfo || {};
|
|
85
85
|
return Adobe.MediaHeartbeat.createQoSObject(
|
|
86
86
|
bitrate, undefined, undefined, droppedVideoFrames,
|
|
87
87
|
);
|
|
@@ -89,7 +89,7 @@ export class AdobeHeartbeat<CustomMetadata extends CustomerMetadata | void = voi
|
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
private attachPlayerListeners(player: PlayerBase
|
|
92
|
+
private attachPlayerListeners(player: PlayerBase) {
|
|
93
93
|
player.addEventListener('play', this.onPlay);
|
|
94
94
|
player.addEventListener('pause', this.onPause);
|
|
95
95
|
player.addEventListener('ended', this.onEnded);
|
|
@@ -98,7 +98,7 @@ export class AdobeHeartbeat<CustomMetadata extends CustomerMetadata | void = voi
|
|
|
98
98
|
player.addEventListener('error', this.onError);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
private dettachPlayerListeners(player: PlayerBase
|
|
101
|
+
private dettachPlayerListeners(player: PlayerBase) {
|
|
102
102
|
player.removeEventListener('play', this.onPlay);
|
|
103
103
|
player.removeEventListener('pause', this.onPause);
|
|
104
104
|
player.removeEventListener('ended', this.onEnded);
|
|
@@ -143,7 +143,7 @@ export class AdobeHeartbeat<CustomMetadata extends CustomerMetadata | void = voi
|
|
|
143
143
|
* this will replace the old one.
|
|
144
144
|
* @param player - 24i universal player instance
|
|
145
145
|
*/
|
|
146
|
-
attachPlayer(player: PlayerBase
|
|
146
|
+
attachPlayer(player: PlayerBase) {
|
|
147
147
|
if (this.player) this.dettachPlayerListeners(this.player);
|
|
148
148
|
this.player = player;
|
|
149
149
|
if (this.player) this.attachPlayerListeners(this.player);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Component, createRef, DeclareProps } from '@24i/bigscreen-sdk/jsx';
|
|
2
2
|
import { DISPLAY_NONE, getDisplayToggler } from '@24i/bigscreen-sdk/utils';
|
|
3
3
|
import { createInterval } from '@24i/bigscreen-sdk/utils/timers';
|
|
4
|
-
import { IMediaInfo, PlayerBase } from '@24i/
|
|
4
|
+
import { IMediaInfo, PlayerBase } from '@24i/bigscreen-players-engine-base';
|
|
5
5
|
import { IDeveloperTool } from '../IDeveloperTool';
|
|
6
6
|
import { MEDIA_INFO_DESCRIPTION, MediaInfo } from './constants';
|
|
7
7
|
|
|
8
8
|
export type Props = {
|
|
9
|
-
playerInstance?: PlayerBase
|
|
9
|
+
playerInstance?: PlayerBase;
|
|
10
10
|
updateInterval?: number;
|
|
11
11
|
onClose?: () => void;
|
|
12
12
|
};
|
|
@@ -16,7 +16,7 @@ export class PlayerDebugWindow extends Component<Props> implements IDeveloperToo
|
|
|
16
16
|
|
|
17
17
|
div = createRef<HTMLDivElement>();
|
|
18
18
|
|
|
19
|
-
playerInstance: PlayerBase
|
|
19
|
+
playerInstance: PlayerBase | null = null;
|
|
20
20
|
|
|
21
21
|
interval = createInterval();
|
|
22
22
|
|
|
@@ -34,12 +34,12 @@ export class PlayerDebugWindow extends Component<Props> implements IDeveloperToo
|
|
|
34
34
|
if (playerInstance) this.setPlayerInstance(playerInstance);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
setPlayerInstance(playerInstance: PlayerBase
|
|
37
|
+
setPlayerInstance(playerInstance: PlayerBase) {
|
|
38
38
|
this.playerInstance = playerInstance;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
getMediaInfo() {
|
|
42
|
-
return this.playerInstance?.
|
|
42
|
+
return this.playerInstance?.mediaInfo || {};
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
getFormattedValue(item: MediaInfo, value: any) {
|
|
@@ -4,7 +4,7 @@ import { IStorage } from '@24i/bigscreen-sdk/storage/interface';
|
|
|
4
4
|
import { getUsedJSHeapSize, getTotalJSHeapSize } from '@24i/bigscreen-sdk/utils/memoryInfo';
|
|
5
5
|
import { ipify } from '@24i/bigscreen-sdk/ipify';
|
|
6
6
|
import { map } from '@24i/bigscreen-sdk/perf-utils/array';
|
|
7
|
-
import { PlayerBase } from '@24i/
|
|
7
|
+
import { PlayerBase } from '@24i/bigscreen-players-engine-base';
|
|
8
8
|
import { hasEMESupport, getListOfSupportedDRM } from './utils/emeSupport';
|
|
9
9
|
import {
|
|
10
10
|
hasEMESupport as hasEMESupport01b,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DeviceFireTV as Device } from '@24i/bigscreen-sdk/driver-firetv';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DeviceSmartCast as Device } from '@24i/bigscreen-sdk/driver-smartcast';
|
|
@@ -2,11 +2,13 @@ import { KeycodeKeyMap, DeviceEventMap } from '@24i/bigscreen-sdk/driver-base';
|
|
|
2
2
|
import { DeviceAndroidTV } from '@24i/bigscreen-sdk/driver-androidtv';
|
|
3
3
|
import { DeviceBrowser } from '@24i/bigscreen-sdk/driver-browser';
|
|
4
4
|
import { DeviceEntone } from '@24i/bigscreen-sdk/driver-entone';
|
|
5
|
+
import { DeviceFireTV } from '@24i/bigscreen-sdk/driver-firetv';
|
|
5
6
|
import { DeviceHbbTV } from '@24i/bigscreen-sdk/driver-hbbtv';
|
|
6
7
|
import { DeviceKreaTV } from '@24i/bigscreen-sdk/driver-kreatv';
|
|
7
8
|
import { DeviceSaphi } from '@24i/bigscreen-sdk/driver-saphi';
|
|
8
9
|
import { DeviceTizen } from '@24i/bigscreen-sdk/driver-tizen';
|
|
9
10
|
import { DeviceVidaa } from '@24i/bigscreen-sdk/driver-vidaa';
|
|
11
|
+
import { DeviceSmartCast } from '@24i/bigscreen-sdk/driver-smartcast';
|
|
10
12
|
import { DeviceWebos } from '@24i/bigscreen-sdk/driver-webos';
|
|
11
13
|
import { DeviceXbox } from '@24i/bigscreen-sdk/driver-xbox';
|
|
12
14
|
|
|
@@ -21,6 +23,13 @@ const getDevice = () => {
|
|
|
21
23
|
return new DeviceHbbTV();
|
|
22
24
|
}
|
|
23
25
|
// any because JavaScriptBridge property is defined on Android TV Bridge platform
|
|
26
|
+
if (typeof (window as any).JavaScriptBridge !== 'undefined'
|
|
27
|
+
&& (userAgent.match(/AFT/) || userAgent.match('AmazonWebAppPlatform'))
|
|
28
|
+
) {
|
|
29
|
+
info('FireTV');
|
|
30
|
+
return new DeviceFireTV();
|
|
31
|
+
}
|
|
32
|
+
// any because JavaScriptBridge property is defined on Android TV Bridge platform
|
|
24
33
|
if (typeof (window as any).JavaScriptBridge !== 'undefined') {
|
|
25
34
|
info('AndroidTV');
|
|
26
35
|
return new DeviceAndroidTV();
|
|
@@ -29,6 +38,10 @@ const getDevice = () => {
|
|
|
29
38
|
info('Tizen');
|
|
30
39
|
return new DeviceTizen();
|
|
31
40
|
}
|
|
41
|
+
if (userAgent.match(/Vizio/i)) {
|
|
42
|
+
info('SmartCast');
|
|
43
|
+
return new DeviceSmartCast();
|
|
44
|
+
}
|
|
32
45
|
if (userAgent.match(/Web0S/)) { // Yes, it is Web ZERO S
|
|
33
46
|
info('WebOS');
|
|
34
47
|
return new DeviceWebos();
|
|
@@ -46,10 +46,9 @@ export class DeviceAndroidTV extends DeviceBase {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Handles keydown/up events for the BACK, FF, REW, STOP, PLAY
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* on the active (focused) element in the DOM tree.
|
|
49
|
+
* Handles keydown/up events for the BACK, FF, REW, STOP, PLAY key which are
|
|
50
|
+
* dispatched on the document from the Android TV Bridge. We must catch them
|
|
51
|
+
* and re-emit them properly on the active (focused) element in the DOM tree.
|
|
53
52
|
* @param event keyboard event
|
|
54
53
|
*/
|
|
55
54
|
// eslint-disable-next-line complexity
|
|
@@ -14,5 +14,17 @@ export const mockJavaScriptBridge: IJavaScriptBridge = {
|
|
|
14
14
|
})
|
|
15
15
|
),
|
|
16
16
|
bridgeJavaScriptToAndroid_Back: () => {},
|
|
17
|
+
bridgeJavaScriptToAndroid_StopVideo: () => {},
|
|
18
|
+
bridgeJavaScriptToAndroid_FullScreenVideo: () => {},
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
20
|
+
bridgeJavaScriptToAndroid_SetVideoPath: (url: string) => {},
|
|
21
|
+
bridgeJavaScriptToAndroid_IsPlaying: () => true,
|
|
22
|
+
bridgeJavaScriptToAndroid_PauseVideo: () => {},
|
|
23
|
+
bridgeJavaScriptToAndroid_PlayVideo: () => {},
|
|
24
|
+
bridgeJavaScriptToAndroid_IsLive: () => false,
|
|
25
|
+
bridgeJavaScriptToAndroid_GetCurrentTime: () => Date.now(),
|
|
26
|
+
bridgeJavaScriptToAndroid_GetTotalTime: () => Date.now(),
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
+
bridgeJavaScriptToAndroid_SeekTo: (milliseconds: number) => {},
|
|
17
29
|
},
|
|
18
30
|
};
|
|
@@ -11,6 +11,46 @@ interface JavaScriptBridge {
|
|
|
11
11
|
* It simulates a native Android back press.
|
|
12
12
|
*/
|
|
13
13
|
bridgeJavaScriptToAndroid_Back: () => void,
|
|
14
|
+
/**
|
|
15
|
+
* It simulates a native Android stop button press.
|
|
16
|
+
*/
|
|
17
|
+
bridgeJavaScriptToAndroid_StopVideo: () => void;
|
|
18
|
+
/**
|
|
19
|
+
* It sets the video to fullscreen mode
|
|
20
|
+
*/
|
|
21
|
+
bridgeJavaScriptToAndroid_FullScreenVideo: () => void;
|
|
22
|
+
/**
|
|
23
|
+
* It sets the video url
|
|
24
|
+
*/
|
|
25
|
+
bridgeJavaScriptToAndroid_SetVideoPath: (url: string) => void;
|
|
26
|
+
/**
|
|
27
|
+
* It returns whether the video is playing
|
|
28
|
+
*/
|
|
29
|
+
bridgeJavaScriptToAndroid_IsPlaying: () => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* It pauses the video
|
|
32
|
+
*/
|
|
33
|
+
bridgeJavaScriptToAndroid_PauseVideo: () => void;
|
|
34
|
+
/**
|
|
35
|
+
* It plays the video
|
|
36
|
+
*/
|
|
37
|
+
bridgeJavaScriptToAndroid_PlayVideo: () => void;
|
|
38
|
+
/**
|
|
39
|
+
* It returns whether the video is live
|
|
40
|
+
*/
|
|
41
|
+
bridgeJavaScriptToAndroid_IsLive: () => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* It returns current time of currently played video
|
|
44
|
+
*/
|
|
45
|
+
bridgeJavaScriptToAndroid_GetCurrentTime: () => number;
|
|
46
|
+
/**
|
|
47
|
+
* It returns total duration of the video
|
|
48
|
+
*/
|
|
49
|
+
bridgeJavaScriptToAndroid_GetTotalTime: () => number;
|
|
50
|
+
/**
|
|
51
|
+
* It seeks the video to specified milliseconds
|
|
52
|
+
*/
|
|
53
|
+
bridgeJavaScriptToAndroid_SeekTo: (milliseconds: number) => void;
|
|
14
54
|
}
|
|
15
55
|
|
|
16
56
|
export type DeviceInfo = {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
type NetworkChangeListener = (payload: { isConnected: boolean }) => void;
|
|
2
2
|
type VisibilityChangeListener = (payload: { isVisible: boolean }) => void;
|
|
3
3
|
type MouseActiveListener = (payload: { isMouseActive: boolean }) => void;
|
|
4
|
+
type CCToggleListener = (payload: { isEnabled: boolean }) => void;
|
|
4
5
|
|
|
5
6
|
export interface DeviceEventMap {
|
|
6
7
|
'networkchange': NetworkChangeListener,
|
|
7
8
|
'visibilitychange': VisibilityChangeListener,
|
|
8
9
|
'mouseactive': MouseActiveListener,
|
|
10
|
+
'cctoggle': CCToggleListener,
|
|
9
11
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DeviceAndroidTV } from '@24i/bigscreen-sdk/driver-androidtv';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fire TV driver implementing API of Android TV Bridge.
|
|
5
|
+
*
|
|
6
|
+
* See https://github.com/24i/prd-smart-ott-androidtv
|
|
7
|
+
*/
|
|
8
|
+
export class DeviceFireTV extends DeviceAndroidTV {
|
|
9
|
+
async getPlatformName(): Promise<string> {
|
|
10
|
+
return 'FireTV';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async getDeviceName(): Promise<string> {
|
|
14
|
+
const modelName = await this.getModelName();
|
|
15
|
+
const manufacturerName = await this.getManufacturerName();
|
|
16
|
+
return `FireTV ${manufacturerName} ${modelName}`.trim();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { IJavaScriptBridge } from '../../../driver-androidtv/src/types';
|
|
2
|
+
|
|
3
|
+
export const mockJavaScriptBridge: IJavaScriptBridge = {
|
|
4
|
+
JavaScriptBridge: {
|
|
5
|
+
bridgeJavaScriptToAndroid_GetDeviceInfo: () => (
|
|
6
|
+
JSON.stringify({
|
|
7
|
+
deviceBrand: 'Amazon',
|
|
8
|
+
deviceModel: 'AFTR',
|
|
9
|
+
osVersion: '8.0.0',
|
|
10
|
+
appVersion: '0.0.1',
|
|
11
|
+
appFlavor: 'appstage-bigscreen',
|
|
12
|
+
drmKeySystems: '["W3C Clear Key", "Google Widevine"]',
|
|
13
|
+
ipLocal: '127.0.0.1',
|
|
14
|
+
})
|
|
15
|
+
),
|
|
16
|
+
bridgeJavaScriptToAndroid_Back: () => {},
|
|
17
|
+
bridgeJavaScriptToAndroid_StopVideo: () => {},
|
|
18
|
+
bridgeJavaScriptToAndroid_FullScreenVideo: () => {},
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
20
|
+
bridgeJavaScriptToAndroid_SetVideoPath: (url: string) => {},
|
|
21
|
+
bridgeJavaScriptToAndroid_IsPlaying: () => true,
|
|
22
|
+
bridgeJavaScriptToAndroid_PauseVideo: () => {},
|
|
23
|
+
bridgeJavaScriptToAndroid_PlayVideo: () => {},
|
|
24
|
+
bridgeJavaScriptToAndroid_IsLive: () => false,
|
|
25
|
+
bridgeJavaScriptToAndroid_GetCurrentTime: () => Date.now(),
|
|
26
|
+
bridgeJavaScriptToAndroid_GetTotalTime: () => Date.now(),
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
+
bridgeJavaScriptToAndroid_SeekTo: (milliseconds: number) => {},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DeviceFireTV } from './DeviceFireTV';
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DeviceBase, ConnectionType, ScreenSaverStatus, VolumeRange,
|
|
3
|
+
} from '@24i/bigscreen-sdk/driver-base';
|
|
4
|
+
import { runAsync } from '@24i/bigscreen-sdk/utils/timers';
|
|
5
|
+
import { getKeyMap } from './keymap';
|
|
6
|
+
import { ISmartCastApi, IFA, DEFAULT_TTS_TIMEOUT, DevicePlaybackQuality } from './types';
|
|
7
|
+
|
|
8
|
+
declare const window: Window & { VIZIO: ISmartCastApi };
|
|
9
|
+
|
|
10
|
+
export class DeviceSmartCast extends DeviceBase {
|
|
11
|
+
keyMap = getKeyMap();
|
|
12
|
+
|
|
13
|
+
deviceId = '';
|
|
14
|
+
|
|
15
|
+
deviceModel = '';
|
|
16
|
+
|
|
17
|
+
deviceFirmware = '';
|
|
18
|
+
|
|
19
|
+
readonly backAsBackspaceInSearch = true;
|
|
20
|
+
|
|
21
|
+
devicePlaybackQualities: DevicePlaybackQuality[] = [];
|
|
22
|
+
|
|
23
|
+
closedCaptionsStatus = false;
|
|
24
|
+
|
|
25
|
+
textToSpeechStatus = false;
|
|
26
|
+
|
|
27
|
+
textToSpeechTimeout?: null | number;
|
|
28
|
+
|
|
29
|
+
lastTextToSpeechItem?: { delay: number, text: string } | null;
|
|
30
|
+
|
|
31
|
+
API?: ISmartCastApi;
|
|
32
|
+
|
|
33
|
+
IFA?: IFA;
|
|
34
|
+
|
|
35
|
+
async initDevice() {
|
|
36
|
+
this.initNetworkChangeListener();
|
|
37
|
+
this.initVisibilityChangeListener();
|
|
38
|
+
this.initMouseActiveListener();
|
|
39
|
+
await this.initPlatformApiListeners();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async initPlatformApiListeners(): Promise<void> {
|
|
43
|
+
return new Promise((resolve) => {
|
|
44
|
+
document.addEventListener('VIZIO_LIBRARY_DID_LOAD', async () => {
|
|
45
|
+
const API = window.VIZIO;
|
|
46
|
+
this.API = window.VIZIO;
|
|
47
|
+
const promises = [];
|
|
48
|
+
|
|
49
|
+
API.setClosedCaptionHandler((isEnabled: boolean) => {
|
|
50
|
+
this.closedCaptionsStatus = isEnabled;
|
|
51
|
+
this.triggerEvent('cctoggle', { isEnabled });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
promises.push(new Promise<void>((r) => {
|
|
55
|
+
API.setAdvertiserIDListener((advertiserID: IFA) => {
|
|
56
|
+
this.IFA = advertiserID;
|
|
57
|
+
r();
|
|
58
|
+
});
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
promises.push(new Promise<void>((r) => {
|
|
62
|
+
API.getDeviceId((id: string) => {
|
|
63
|
+
this.deviceId = id;
|
|
64
|
+
r();
|
|
65
|
+
});
|
|
66
|
+
}));
|
|
67
|
+
|
|
68
|
+
this.deviceModel = API.deviceModel;
|
|
69
|
+
|
|
70
|
+
promises.push(new Promise<void>((r) => {
|
|
71
|
+
API.getFirmwareVersion((version: string) => {
|
|
72
|
+
this.deviceFirmware = version;
|
|
73
|
+
r();
|
|
74
|
+
});
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
promises.push(new Promise<void>((r) => {
|
|
78
|
+
API.getDevicePlaybackQualities((qualities: DevicePlaybackQuality[]) => {
|
|
79
|
+
this.devicePlaybackQualities = qualities;
|
|
80
|
+
r();
|
|
81
|
+
});
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
85
|
+
API.setContentChangeHandler(this.handleDeeplink);
|
|
86
|
+
|
|
87
|
+
await Promise.all(promises);
|
|
88
|
+
|
|
89
|
+
resolve();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
document.addEventListener('VIZIO_TTS_ENABLED', () => {
|
|
93
|
+
this.textToSpeechStatus = true;
|
|
94
|
+
}, false);
|
|
95
|
+
|
|
96
|
+
document.addEventListener('VIZIO_TTS_DISABLED', () => {
|
|
97
|
+
this.lastTextToSpeechItem = null;
|
|
98
|
+
this.textToSpeechStatus = false;
|
|
99
|
+
window.clearTimeout(this.textToSpeechTimeout as any);
|
|
100
|
+
this.API?.Chromevox.cancel();
|
|
101
|
+
}, false);
|
|
102
|
+
|
|
103
|
+
const object = document.createElement('script');
|
|
104
|
+
object.src = 'http://127.0.0.1:12345/scfs/cl/js/vizio-companion-lib.js';
|
|
105
|
+
document.body.appendChild(object);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
initNetworkChangeListener() {
|
|
110
|
+
window.addEventListener('online', () => {
|
|
111
|
+
this.triggerEvent('networkchange', { isConnected: true });
|
|
112
|
+
});
|
|
113
|
+
window.addEventListener('offline', () => {
|
|
114
|
+
this.triggerEvent('networkchange', { isConnected: false });
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
initVisibilityChangeListener() {
|
|
119
|
+
document.addEventListener('visibilitychange', () => {
|
|
120
|
+
this.triggerEvent('visibilitychange', {
|
|
121
|
+
isVisible: document.visibilityState === 'visible',
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
initMouseActiveListener() {
|
|
127
|
+
document.addEventListener('mousemove', this.onMouseActive);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
onMouseActive = () => {
|
|
131
|
+
document.removeEventListener('mousemove', this.onMouseActive);
|
|
132
|
+
document.addEventListener('keydown', this.onMouseInactive, true);
|
|
133
|
+
this.isMouseActive = true;
|
|
134
|
+
this.triggerEvent('mouseactive', { isMouseActive: true });
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
onMouseInactive = (event: KeyboardEvent) => {
|
|
138
|
+
if (!this.isDirectionalArrow(event)) return;
|
|
139
|
+
document.removeEventListener('keydown', this.onMouseInactive);
|
|
140
|
+
this.initMouseActiveListener();
|
|
141
|
+
|
|
142
|
+
// to let other handlers to use this property before change
|
|
143
|
+
runAsync(() => {
|
|
144
|
+
this.isMouseActive = false;
|
|
145
|
+
});
|
|
146
|
+
this.triggerEvent('mouseactive', { isMouseActive: false });
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
handleDeeplink = (deeplinkUrl: string) => {
|
|
150
|
+
if (typeof deeplinkUrl !== 'string') return;
|
|
151
|
+
const newRoute = deeplinkUrl.split('#')[1];
|
|
152
|
+
if (newRoute) {
|
|
153
|
+
const currentUrl = window.location.href.split('#')[0];
|
|
154
|
+
window.location.href = `${currentUrl}#${newRoute}`;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Reads provided text by the device internal reader.
|
|
160
|
+
*/
|
|
161
|
+
readText({ text, delay = DEFAULT_TTS_TIMEOUT }: {
|
|
162
|
+
text: string, delay?: number
|
|
163
|
+
}) {
|
|
164
|
+
if (this.textToSpeechStatus && text) {
|
|
165
|
+
if (this.textToSpeechTimeout) {
|
|
166
|
+
this.lastTextToSpeechItem = { text, delay };
|
|
167
|
+
} else {
|
|
168
|
+
this.API?.Chromevox.play(text);
|
|
169
|
+
|
|
170
|
+
this.textToSpeechTimeout = window.setTimeout(() => {
|
|
171
|
+
this.textToSpeechTimeout = null;
|
|
172
|
+
|
|
173
|
+
if (this.lastTextToSpeechItem) {
|
|
174
|
+
const last = this.lastTextToSpeechItem;
|
|
175
|
+
|
|
176
|
+
this.API?.Chromevox.play(last.text);
|
|
177
|
+
this.lastTextToSpeechItem = null;
|
|
178
|
+
}
|
|
179
|
+
}, delay);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
exit() {
|
|
185
|
+
this.API?.exitApplication();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
reboot() {
|
|
189
|
+
window.location.reload();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Returs the status of Closed Captions feature.
|
|
194
|
+
*/
|
|
195
|
+
async getClosedCaptionsStatus() {
|
|
196
|
+
return this.closedCaptionsStatus;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Returs the status of Text to Speech Engine if it is available by the device.
|
|
201
|
+
*/
|
|
202
|
+
async getTextToSpeechStatus() {
|
|
203
|
+
return this.textToSpeechStatus;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Returns filled in Vast Tag URL.
|
|
208
|
+
*/
|
|
209
|
+
getVastTagUrl(template: string): null | string {
|
|
210
|
+
const IFAObject = this.IFA;
|
|
211
|
+
const resolution = this.getResolution();
|
|
212
|
+
|
|
213
|
+
if (!IFAObject) return null;
|
|
214
|
+
|
|
215
|
+
return template
|
|
216
|
+
.replace('{{width}}', String(resolution.width))
|
|
217
|
+
.replace('{{height}}', String(resolution.height))
|
|
218
|
+
.replace('{{cb}}', String(Date.now()))
|
|
219
|
+
.replace('{{user_agent}}', encodeURIComponent(window.navigator.userAgent))
|
|
220
|
+
.replace('{{ifa}}', IFAObject.IFA)
|
|
221
|
+
.replace('{{ifa_type}}', IFAObject.IFA_TYPE)
|
|
222
|
+
.replace('{{lmt}}', String(IFAObject.LMT));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async getManufacturerName() {
|
|
226
|
+
return 'VIZIO';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async getPlatformName() {
|
|
230
|
+
return 'SmartCast';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async getPlatformVersion() {
|
|
234
|
+
return '';
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async getDeviceName() {
|
|
238
|
+
return 'VIZIO SmartCast';
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async getModelName() {
|
|
242
|
+
return this.deviceModel;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async getFirmware() {
|
|
246
|
+
return this.deviceFirmware;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async is4KSupported() {
|
|
250
|
+
return this.devicePlaybackQualities.includes('UHD');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async is8KSupported() {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async getUuid() {
|
|
258
|
+
return this.deviceId;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async getVolume() {
|
|
262
|
+
return VolumeRange.UNSUPPORTED;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
266
|
+
async setVolume(volumePercentage: number) {
|
|
267
|
+
// not supported on SmartCast platform
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
271
|
+
async mute(mute: boolean) {
|
|
272
|
+
// not supported on SmartCast platform
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async isMute() {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async getScreenSaver() {
|
|
280
|
+
return { enabled: false };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
284
|
+
async setScreenSaver(status: ScreenSaverStatus) {
|
|
285
|
+
// not supported on SmartCast platform
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
289
|
+
async setUserAgent(userAgent: string) {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async getConnectionType() {
|
|
294
|
+
return 'unknown' as ConnectionType;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async isNetworkConnected() {
|
|
298
|
+
return window.navigator.onLine;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async getLocalIP() {
|
|
302
|
+
// not supported on SmartCast platform
|
|
303
|
+
return '';
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async getMacAddress() {
|
|
307
|
+
// not supported on SmartCast platform
|
|
308
|
+
return '';
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { IFA, ISmartCastApi, DevicePlaybackQuality } from '../types';
|
|
2
|
+
|
|
3
|
+
export const deviceId = '2bd671ef-02cd-445f-9295-b3565dbaf1e8';
|
|
4
|
+
export const deviceModel = 'D24f4-J01';
|
|
5
|
+
export const firmware = '3.520.28.1-2';
|
|
6
|
+
export const playbackQualities = ['UHD', 'HD'] as DevicePlaybackQuality[];
|
|
7
|
+
// eslint-disable-next-line max-len
|
|
8
|
+
export const deeplinkUrl = 'https://smartapps-bigscreen.24i.com/#/detail/SERIES/FO03OogBXRsigNB1VRz_/undefined/undefined/';
|
|
9
|
+
// eslint-disable-next-line max-len
|
|
10
|
+
export const deeplinkUrl2 = 'https://smartapps-bigscreen.24i.com/#/detail/SERIES/Ge1sO4gBXRsigNB1TBwy/undefined/undefined/';
|
|
11
|
+
// eslint-disable-next-line max-len
|
|
12
|
+
export const vastTagTemplate = 'w={{width}}&h={{height}}&did={{ifa}}&ifa_type={{ifa_type}}&lmt={{lmt}}';
|
|
13
|
+
|
|
14
|
+
export const SmartCastMockApi: ISmartCastApi = {
|
|
15
|
+
deviceModel,
|
|
16
|
+
|
|
17
|
+
getDeviceId: (callback: (id: string) => void): void => callback(deviceId),
|
|
18
|
+
|
|
19
|
+
getFirmwareVersion: (callback: (id: string) => void): void => callback(firmware),
|
|
20
|
+
|
|
21
|
+
getDevicePlaybackQualities: (
|
|
22
|
+
callback: (
|
|
23
|
+
qualities: DevicePlaybackQuality[]
|
|
24
|
+
) => void,
|
|
25
|
+
): void => callback(playbackQualities),
|
|
26
|
+
|
|
27
|
+
exitApplication: (): void => {},
|
|
28
|
+
|
|
29
|
+
setClosedCaptionHandler: (callback: (isEnabled: boolean) => void): void => callback(false),
|
|
30
|
+
|
|
31
|
+
setAdvertiserIDListener: (callback: (advertiserID: IFA) => void): void => callback({
|
|
32
|
+
IFA: deviceId,
|
|
33
|
+
IFA_TYPE: 'vida',
|
|
34
|
+
LMT: 0,
|
|
35
|
+
}),
|
|
36
|
+
|
|
37
|
+
setContentChangeHandler:
|
|
38
|
+
(callback: (contentUrl: string) => void): void => callback(deeplinkUrl),
|
|
39
|
+
|
|
40
|
+
Chromevox: {
|
|
41
|
+
cancel: (): void => {
|
|
42
|
+
throw new Error('Function not implemented.');
|
|
43
|
+
},
|
|
44
|
+
play: (text: string): void => {
|
|
45
|
+
// eslint-disable-next-line no-console
|
|
46
|
+
console.log(text);
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DeviceSmartCast } from './DeviceSmartCast';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { generateKeyCodeKeyMap, overrideValues } from '@24i/bigscreen-sdk/driver-base/keymap';
|
|
2
|
+
|
|
3
|
+
export const getKeyMap = () => {
|
|
4
|
+
overrideValues({
|
|
5
|
+
CHANNEL_PREVIOUS: { code: 'PrevCh', keyCode: 500 },
|
|
6
|
+
SUBTITLES: { keyCode: 204 },
|
|
7
|
+
});
|
|
8
|
+
return generateKeyCodeKeyMap();
|
|
9
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export type ISmartCastApi = {
|
|
2
|
+
/**
|
|
3
|
+
* Sets the callback to receive the device UID in standard 32 digits.
|
|
4
|
+
*/
|
|
5
|
+
getDeviceId: (callback: (id: string) => void) => void;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Sets the callback to receive the device firmware version.
|
|
9
|
+
*/
|
|
10
|
+
getFirmwareVersion: (callback: (firmwareVersion: string) => void) => void;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Sets the callback to receive the device playback qualities.
|
|
14
|
+
*/
|
|
15
|
+
getDevicePlaybackQualities: (callback: (qualities: DevicePlaybackQuality[]) => void) => void;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Exits the application.
|
|
19
|
+
*/
|
|
20
|
+
exitApplication: () => void;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Sets the callback to receive the device CC toggle event.
|
|
24
|
+
*/
|
|
25
|
+
setClosedCaptionHandler: (callback: (isEnabled: boolean) => void) => void;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Sets the callback to receive IFA object with the device ads related parameters.
|
|
29
|
+
*/
|
|
30
|
+
setAdvertiserIDListener: (callback: (advertiserID: IFA) => void) => void;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Sets the callback to receive the device content change event.
|
|
34
|
+
*/
|
|
35
|
+
setContentChangeHandler: (callback: (contentUrl: string) => void) => void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Device model.
|
|
39
|
+
*/
|
|
40
|
+
deviceModel: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Chromevox Text-to-Speech accessibility playback engine.
|
|
44
|
+
*/
|
|
45
|
+
Chromevox: {
|
|
46
|
+
cancel: () => void,
|
|
47
|
+
play: (text: string) => void,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Identifier For Advertising (IFA) and Limited Tracking parameter object
|
|
53
|
+
*/
|
|
54
|
+
export type IFA = {
|
|
55
|
+
/** Unique identifier string for advertising */
|
|
56
|
+
IFA: string,
|
|
57
|
+
/** String value for IFA type ("vida") */
|
|
58
|
+
IFA_TYPE: string,
|
|
59
|
+
/** O or 1 (1=Limited tracking enabled, 0=Limited tracking disabled) */
|
|
60
|
+
LMT: 0 | 1
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export type DevicePlaybackQuality = 'UHD' | 'HD' | 'SD';
|
|
64
|
+
|
|
65
|
+
export const DEFAULT_TTS_TIMEOUT = 3000;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PlayerBase } from '@24i/
|
|
1
|
+
import { PlayerBase } from '@24i/bigscreen-players-engine-base';
|
|
2
2
|
import './__external__/SpringStreams';
|
|
3
3
|
|
|
4
4
|
const SECOND_IN_MS = 1000;
|
|
@@ -16,7 +16,7 @@ export class Gallup {
|
|
|
16
16
|
*/
|
|
17
17
|
constructor(
|
|
18
18
|
siteCode: string,
|
|
19
|
-
private readonly player: PlayerBase
|
|
19
|
+
private readonly player: PlayerBase,
|
|
20
20
|
private readonly playerName: string,
|
|
21
21
|
) {
|
|
22
22
|
this.sensors = new SpringStreams(siteCode);
|
|
@@ -67,7 +67,7 @@ export class Gallup {
|
|
|
67
67
|
getPosition: () => Math.floor(player.currentTime / SECOND_IN_MS),
|
|
68
68
|
getMeta: () => {
|
|
69
69
|
const { width, height } = window.screen;
|
|
70
|
-
const { playerVersion } = player.
|
|
70
|
+
const { playerVersion } = player.mediaInfo;
|
|
71
71
|
return {
|
|
72
72
|
pl: playerName,
|
|
73
73
|
plv: playerVersion || '',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component, createRef, Reference } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
-
import { getKeyDigit } from '@24i/bigscreen-sdk/device';
|
|
2
|
+
import { getKeyDigit, device } from '@24i/bigscreen-sdk/device';
|
|
3
3
|
import { isRtl } from '@24i/bigscreen-sdk/i18n';
|
|
4
4
|
import { EventsManager } from '@24i/bigscreen-sdk/events-manager';
|
|
5
5
|
import {
|
|
@@ -121,8 +121,15 @@ export abstract class KeyboardBase<
|
|
|
121
121
|
*/
|
|
122
122
|
onKeyDown(event: KeyboardEvent) {
|
|
123
123
|
const { handleRemoteDigits, handleHWKeyboard } = this.props;
|
|
124
|
+
const preventBack = 'backAsBackspaceInSearch' in device && !!device.backAsBackspaceInSearch;
|
|
125
|
+
const inputLength = this.inputElement?.value?.length;
|
|
126
|
+
|
|
124
127
|
if (BACK.is(event)) {
|
|
125
|
-
|
|
128
|
+
if (preventBack && inputLength) {
|
|
129
|
+
this.onBackspace();
|
|
130
|
+
} else {
|
|
131
|
+
this.onCancel();
|
|
132
|
+
}
|
|
126
133
|
} else {
|
|
127
134
|
let char: string | null = null;
|
|
128
135
|
if (handleHWKeyboard) {
|
|
@@ -30,7 +30,6 @@ export class CenteredListController<T> extends UnifiedListController<T, Props<an
|
|
|
30
30
|
this.scrollListScroller(-this.topOffset);
|
|
31
31
|
if (initialFocusIndex !== 0) {
|
|
32
32
|
base.index = initialFocusIndex!;
|
|
33
|
-
this.focusCurrentItem();
|
|
34
33
|
this.scroll(base.index, false);
|
|
35
34
|
}
|
|
36
35
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component, createRef, DeclareProps } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
-
import { ITimeUpdateEvent } from '@24i/
|
|
2
|
+
import { ITimeUpdateEvent } from '@24i/bigscreen-players-engine-base';
|
|
3
3
|
import { PlayerTime } from './PlayerTime';
|
|
4
4
|
import { PlayerUICommonProps, PlayerUITimeProps } from './types';
|
|
5
5
|
|
|
@@ -26,7 +26,7 @@ export class CurrentTime extends Component<Props> {
|
|
|
26
26
|
const playerInstance = ui.getPlayer();
|
|
27
27
|
this.isLive = playerInstance.live;
|
|
28
28
|
playerInstance.addEventListener('timeupdate', this.onTimeUpdate);
|
|
29
|
-
const { programStart = 0 } = playerInstance.
|
|
29
|
+
const { programStart = 0 } = playerInstance.metadata || {};
|
|
30
30
|
this.liveStartTime = programStart || Date.now();
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component, createRef, DeclareProps } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
-
import { IDurationChangeEvent } from '@24i/
|
|
2
|
+
import { IDurationChangeEvent } from '@24i/bigscreen-players-engine-base';
|
|
3
3
|
import { PlayerTime } from './PlayerTime';
|
|
4
4
|
import { PlayerUICommonProps, PlayerUITimeProps } from './types';
|
|
5
5
|
|
|
@@ -20,7 +20,7 @@ export class Duration extends Component<Props> {
|
|
|
20
20
|
componentDidMount() {
|
|
21
21
|
const { ui } = this.props;
|
|
22
22
|
const playerInstance = ui.getPlayer();
|
|
23
|
-
const { programStart = 0, programEnd = 0 } = playerInstance.
|
|
23
|
+
const { programStart = 0, programEnd = 0 } = playerInstance.metadata || {};
|
|
24
24
|
const isLive = playerInstance.live;
|
|
25
25
|
if (isLive && programStart < programEnd) {
|
|
26
26
|
this.time.current!.updateTime(programEnd - programStart);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component, createRef, DeclareProps } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
-
import { PlayerBase } from '@24i/
|
|
2
|
+
import { PlayerBase } from '@24i/bigscreen-players-engine-base';
|
|
3
3
|
import { FF, REW, switchByKey } from '@24i/bigscreen-sdk/device/keymap';
|
|
4
4
|
import { stopEvent } from '@24i/bigscreen-sdk/utils/stopEvent';
|
|
5
5
|
import {
|
|
@@ -16,7 +16,7 @@ export type PlayerUIState = {
|
|
|
16
16
|
|
|
17
17
|
type Props = {
|
|
18
18
|
children: (state: PlayerUIState) => JSX.Element | JSX.Element[] | string | null | null[],
|
|
19
|
-
player: PlayerBase
|
|
19
|
+
player: PlayerBase,
|
|
20
20
|
timeout?: number,
|
|
21
21
|
className?: string,
|
|
22
22
|
hidden?: boolean,
|
|
@@ -44,7 +44,7 @@ export class PlayerUI extends Component<Props>
|
|
|
44
44
|
// eslint-disable-next-line react/destructuring-assignment
|
|
45
45
|
divDisplay: IDisplayToggler = getDisplayToggler(this.div, this.props.hidden);
|
|
46
46
|
|
|
47
|
-
player: PlayerBase
|
|
47
|
+
player: PlayerBase | null = null;
|
|
48
48
|
|
|
49
49
|
static defaultProps = {
|
|
50
50
|
timeout: 5000,
|
|
@@ -175,7 +175,7 @@ export class PlayerUI extends Component<Props>
|
|
|
175
175
|
|
|
176
176
|
getPlayer = () => this.player!;
|
|
177
177
|
|
|
178
|
-
setPlayer(player: PlayerBase
|
|
178
|
+
setPlayer(player: PlayerBase) {
|
|
179
179
|
this.player = player;
|
|
180
180
|
if (this.seeking) this.seeking.setPlayer(player);
|
|
181
181
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component, createRef, DeclareProps } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
-
import { IDurationChangeEvent, ITimeUpdateEvent } from '@24i/
|
|
2
|
+
import { IDurationChangeEvent, ITimeUpdateEvent } from '@24i/bigscreen-players-engine-base';
|
|
3
3
|
import { PlayerTime } from './PlayerTime';
|
|
4
4
|
import { PlayerUICommonProps, PlayerUITimeProps } from './types';
|
|
5
5
|
|
|
@@ -32,7 +32,7 @@ export class RemainingTime extends Component<Props> {
|
|
|
32
32
|
this.duration = playerInstance.duration;
|
|
33
33
|
playerInstance.addEventListener('timeupdate', this.onTimeUpdate);
|
|
34
34
|
playerInstance.addEventListener('durationchange', this.onDurationChange);
|
|
35
|
-
const { programEnd = 0 } = playerInstance.
|
|
35
|
+
const { programEnd = 0 } = playerInstance.metadata || {};
|
|
36
36
|
this.liveEndTime = programEnd || Date.now();
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Component, createRef } from '@24i/bigscreen-sdk/jsx';
|
|
2
2
|
import { IFocusable } from '@24i/bigscreen-sdk/focus';
|
|
3
3
|
import { stopEvent } from '@24i/bigscreen-sdk/utils/stopEvent';
|
|
4
|
-
import { ITimeUpdateEvent, IDurationChangeEvent } from '@24i/
|
|
4
|
+
import { ITimeUpdateEvent, IDurationChangeEvent } from '@24i/bigscreen-players-engine-base';
|
|
5
5
|
import { createTimeout } from '@24i/bigscreen-sdk/utils/timers';
|
|
6
6
|
import { switchByKey } from '@24i/bigscreen-sdk/device/keymap';
|
|
7
7
|
import { getDisplayToggler } from '@24i/bigscreen-sdk/utils/displayToggler';
|
|
@@ -195,7 +195,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
|
|
|
195
195
|
const { ui } = this.props;
|
|
196
196
|
const player = ui.getPlayer();
|
|
197
197
|
if (player.live) {
|
|
198
|
-
const { programStart = 0, programEnd = 0 } = player.
|
|
198
|
+
const { programStart = 0, programEnd = 0 } = player.metadata;
|
|
199
199
|
this.duration = programEnd - programStart || Date.now();
|
|
200
200
|
} else {
|
|
201
201
|
this.duration = duration;
|
|
@@ -207,7 +207,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
|
|
|
207
207
|
const { ui } = this.props;
|
|
208
208
|
const player = ui.getPlayer();
|
|
209
209
|
if (player.live) {
|
|
210
|
-
const { programStart = 0, programEnd = 0 } = player.
|
|
210
|
+
const { programStart = 0, programEnd = 0 } = player.metadata;
|
|
211
211
|
const { start, end } = player.seekableRange;
|
|
212
212
|
return getLiveProgressBasedOnCurrentTime(
|
|
213
213
|
programStart,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IEvents, EventMapType, EventsManager } from '@24i/bigscreen-sdk/events-manager';
|
|
2
2
|
import { createInterval, createTimeout } from '@24i/bigscreen-sdk/utils/timers';
|
|
3
|
-
import { PlayerBase } from '@24i/
|
|
3
|
+
import { PlayerBase } from '@24i/bigscreen-players-engine-base';
|
|
4
4
|
|
|
5
5
|
const DEFAULT_SEEK_TIME = 10000;
|
|
6
6
|
const FAST_SEEK_TIME = 30000;
|
|
@@ -26,7 +26,7 @@ export class Seeking implements IEvents<SeekingEventsMap> {
|
|
|
26
26
|
|
|
27
27
|
automaticSeekInterval = createInterval();
|
|
28
28
|
|
|
29
|
-
player: PlayerBase
|
|
29
|
+
player: PlayerBase | null;
|
|
30
30
|
|
|
31
31
|
isAutomaticallySeekingForward = false;
|
|
32
32
|
|
|
@@ -40,7 +40,7 @@ export class Seeking implements IEvents<SeekingEventsMap> {
|
|
|
40
40
|
|
|
41
41
|
rewConsecutiveTimeout = createTimeout();
|
|
42
42
|
|
|
43
|
-
constructor(player: PlayerBase
|
|
43
|
+
constructor(player: PlayerBase | null = null) {
|
|
44
44
|
this.player = player;
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -52,7 +52,7 @@ export class Seeking implements IEvents<SeekingEventsMap> {
|
|
|
52
52
|
this.player!.removeEventListener('seeked', this.nullSeekTime);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
setPlayer(player: PlayerBase
|
|
55
|
+
setPlayer(player: PlayerBase) {
|
|
56
56
|
this.player = player;
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { PlayerBase, ITimeUpdateEvent } from '@24i/
|
|
1
|
+
import { PlayerBase, ITimeUpdateEvent } from '@24i/bigscreen-players-engine-base';
|
|
2
2
|
import { Component, createRef, DeclareProps, setText } from '@24i/bigscreen-sdk/jsx';
|
|
3
3
|
import { getDisplayToggler } from '@24i/bigscreen-sdk/utils';
|
|
4
4
|
import { SubtitlesType } from '@24i/smartapps-datalayer/src/models';
|
|
5
5
|
import { timeToMs } from './timeUtils';
|
|
6
6
|
|
|
7
7
|
type Props = {
|
|
8
|
-
player: PlayerBase
|
|
8
|
+
player: PlayerBase,
|
|
9
9
|
className?: string,
|
|
10
10
|
};
|
|
11
11
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PlayerBase, PlayerBaseMock } from '@24i/
|
|
1
|
+
import { IPlayerProperties, PlayerBase, PlayerBaseMock } from '@24i/bigscreen-players-engine-base';
|
|
2
2
|
import { EventsManager } from '@24i/bigscreen-sdk/events-manager';
|
|
3
3
|
import { IPlayerUIWithSeeking } from './types';
|
|
4
4
|
|
|
@@ -35,8 +35,16 @@ const getSeekingMock = (): jest.Mocked<IPlayerUIWithSeeking['seeking']> => ({
|
|
|
35
35
|
|
|
36
36
|
const PLAYER_MOCK_DURATION = 60000;
|
|
37
37
|
|
|
38
|
-
export const getPlayerMock = (): PlayerBase
|
|
39
|
-
const
|
|
38
|
+
export const getPlayerMock = (): PlayerBase => {
|
|
39
|
+
const initialConfig: IPlayerProperties = {
|
|
40
|
+
source: {
|
|
41
|
+
url: '',
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
const parentElement = document.createElement('div');
|
|
45
|
+
|
|
46
|
+
const playerMock = new PlayerBaseMock(initialConfig, parentElement);
|
|
47
|
+
playerMock.source = initialConfig.source;
|
|
40
48
|
jest.spyOn(playerMock, 'duration', 'get').mockReturnValue(PLAYER_MOCK_DURATION);
|
|
41
49
|
|
|
42
50
|
return playerMock;
|
|
@@ -44,7 +52,7 @@ export const getPlayerMock = (): PlayerBase<any> => {
|
|
|
44
52
|
|
|
45
53
|
export const getUiMock = (): { ui: jest.Mocked<IPlayerUIWithSeeking> } => ({
|
|
46
54
|
ui: {
|
|
47
|
-
getPlayer: jest.fn((): PlayerBase
|
|
55
|
+
getPlayer: jest.fn((): PlayerBase => getPlayerMock()),
|
|
48
56
|
heartbeat: jest.fn(),
|
|
49
57
|
trigger: jest.fn(),
|
|
50
58
|
isPlaying: jest.fn(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PlayerBase } from '@24i/
|
|
1
|
+
import { PlayerBase } from '@24i/bigscreen-players-engine-base';
|
|
2
2
|
import { Seeking } from './Seeking';
|
|
3
3
|
|
|
4
4
|
export enum PlayerAction {
|
|
@@ -21,7 +21,7 @@ export interface ActionsWithPayloadMap {
|
|
|
21
21
|
|
|
22
22
|
export interface IPlayerUI {
|
|
23
23
|
seeking?: Seeking;
|
|
24
|
-
getPlayer: () => PlayerBase
|
|
24
|
+
getPlayer: () => PlayerBase,
|
|
25
25
|
disableHiding: () => void,
|
|
26
26
|
enableHiding: () => void,
|
|
27
27
|
disableSeeking: () => void,
|