@24i/bigscreen-sdk 1.0.21-alpha.2358 → 1.0.22-alpha.2373

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/package.json +5 -3
  2. package/packages/adobe-heartbeat/src/AdobeHeartbeat.ts +9 -9
  3. package/packages/developer-tools/PlayerDebugWindow/README.md +1 -1
  4. package/packages/developer-tools/src/PlayerDebugWindow/PlayerDebugWindow.tsx +5 -5
  5. package/packages/developer-tools/src/TechnicalInfo/TechnicalInfoProvider.ts +1 -1
  6. package/packages/device/src/driver/index.firetv.ts +1 -0
  7. package/packages/device/src/resolver/resolver.ts +8 -0
  8. package/packages/digital-clock/src/DigitalClock.tsx +5 -1
  9. package/packages/driver-androidtv/src/DeviceAndroidTV.ts +3 -4
  10. package/packages/driver-androidtv/src/__mocks__/javaScriptBridge.ts +12 -0
  11. package/packages/driver-androidtv/src/types.ts +48 -0
  12. package/packages/driver-firetv/src/DeviceFireTV.ts +18 -0
  13. package/packages/driver-firetv/src/__mocks__/javaScriptBridge.ts +30 -0
  14. package/packages/driver-firetv/src/index.ts +1 -0
  15. package/packages/epg/src/v2/DatePicker.tsx +3 -1
  16. package/packages/epg/src/v2/DateToast/DateToast.tsx +2 -1
  17. package/packages/epg/src/v2/Day.tsx +3 -1
  18. package/packages/epg/src/v2/ProgramInfo/utils.ts +1 -1
  19. package/packages/epg/src/v2/TimelineSection.tsx +1 -1
  20. package/packages/gallup/src/Gallup.ts +3 -3
  21. package/packages/l10n/README.md +18 -0
  22. package/packages/l10n/src/date/types.ts +3 -0
  23. package/packages/l10n/src/l10n.ts +51 -3
  24. package/packages/player-ui/src/CurrentTime.tsx +2 -2
  25. package/packages/player-ui/src/Duration.tsx +2 -2
  26. package/packages/player-ui/src/PlayerUI.tsx +4 -4
  27. package/packages/player-ui/src/RemainingTime.tsx +2 -2
  28. package/packages/player-ui/src/Seekbar.tsx +3 -3
  29. package/packages/player-ui/src/Seeking.ts +4 -4
  30. package/packages/player-ui/src/Subtitles.tsx +2 -2
  31. package/packages/player-ui/src/mocks.ts +12 -4
  32. 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-alpha.2358",
3
+ "version": "1.0.22-alpha.2373",
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/player-base": "6.10.0",
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",
@@ -48,6 +48,7 @@
48
48
  "@types/prop-types": "^15.7.5",
49
49
  "@types/scheduler": "^0.16.3",
50
50
  "csstype": "^3.1.1",
51
+ "date-fns": "2.29.3",
51
52
  "lottie-web": "5.10.2",
52
53
  "prop-types": "^15.8.1"
53
54
  },
@@ -62,7 +63,7 @@
62
63
  "@types/jest": "^29.5.2",
63
64
  "@types/minimist": "^1.2.2",
64
65
  "@types/node": "^18.7.18",
65
- "@types/react": "^18.0.33",
66
+ "@types/react": "18.0.33",
66
67
  "babel-jest": "^29.4.3",
67
68
  "chalk": "^5.2.0",
68
69
  "coveralls": "^3.1.1",
@@ -118,6 +119,7 @@
118
119
  "./driver-base": "./packages/driver-base/src/index.ts",
119
120
  "./driver-browser": "./packages/driver-browser/src/index.ts",
120
121
  "./driver-entone": "./packages/driver-entone/src/index.ts",
122
+ "./driver-firetv": "./packages/driver-firetv/src/index.ts",
121
123
  "./driver-hbbtv": "./packages/driver-hbbtv/src/index.ts",
122
124
  "./driver-kreatv": "./packages/driver-kreatv/src/index.ts",
123
125
  "./driver-saphi": "./packages/driver-saphi/src/index.ts",
@@ -1,5 +1,5 @@
1
1
  /// <reference path='./__external__/Adobe/Adobe.d.ts' />
2
- import { IErrorEvent, PlayerBase } from '@24i/player-base';
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<any>;
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<any>) {
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.getMediaInfo() || {};
70
+ const { currentTime } = this.player.mediaInfo || {};
71
71
  if (this.player.live) {
72
72
  try {
73
- const { programEnd = NaN } = this.player.getMetadata();
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.getMediaInfo() || {};
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<any>) {
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<any>) {
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<any>) {
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);
@@ -45,7 +45,7 @@ playerDebugWindowRef.current?.setPlayerInstance(playerInstance);
45
45
 
46
46
  ```ts
47
47
  type Props = {
48
- playerInstance?: PlayerBase<any>;
48
+ playerInstance?: PlayerBase;
49
49
  updateInterval?: number;
50
50
  onClose?: () => void;
51
51
  };
@@ -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/player-base';
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<any>;
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<any> | null = null;
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<any>) {
37
+ setPlayerInstance(playerInstance: PlayerBase) {
38
38
  this.playerInstance = playerInstance;
39
39
  }
40
40
 
41
41
  getMediaInfo() {
42
- return this.playerInstance?.getMediaInfo() || {};
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/player-base';
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';
@@ -2,6 +2,7 @@ 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';
@@ -22,6 +23,13 @@ const getDevice = () => {
22
23
  return new DeviceHbbTV();
23
24
  }
24
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
25
33
  if (typeof (window as any).JavaScriptBridge !== 'undefined') {
26
34
  info('AndroidTV');
27
35
  return new DeviceAndroidTV();
@@ -10,7 +10,11 @@ export type Props = {
10
10
  className?: string,
11
11
  };
12
12
 
13
- const WITHOUT_SECONDS_OPTIONS = { hour: 'numeric', minute: '2-digit' } as const;
13
+ const WITHOUT_SECONDS_OPTIONS = {
14
+ hour: 'numeric',
15
+ minute: '2-digit',
16
+ formatType: 'timeFormat',
17
+ } as const;
14
18
  const WITH_SECONDS_OPTIONS = { ...WITHOUT_SECONDS_OPTIONS, second: '2-digit' } as const;
15
19
 
16
20
  export class DigitalClock extends Component<Props> {
@@ -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
- * key which are dispatched on the document
51
- * from the Android TV Bridge. We must catch them and re-emit them properly
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 = {
@@ -34,6 +74,14 @@ export type DeviceInfo = {
34
74
  * Android flavor. Ex. "appstage-bigscreen"
35
75
  */
36
76
  appFlavor: string,
77
+ /**
78
+ * Underlying player engine name. Ex. "exoplayer"
79
+ */
80
+ engineName: string,
81
+ /**
82
+ * Version of player engine. Ex. "2.18.1"
83
+ */
84
+ engineVersion: string,
37
85
  /**
38
86
  * Android DRM key systems. Ex. ["Widewine", "W3C ClearKey"]
39
87
  */
@@ -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';
@@ -49,7 +49,9 @@ const defaultFormat = (date: Date) => {
49
49
  const locale = i18n.getLanguage();
50
50
  return l10n
51
51
  .date(date.getTime() + time.getTimezoneOffsetMs(), locale)
52
- .toLocaleDateString({ weekday: 'short', day: 'numeric', month: 'short' });
52
+ .toLocaleDateString({
53
+ weekday: 'short', day: 'numeric', month: 'short', formatType: 'dateFormatShort',
54
+ });
53
55
  };
54
56
 
55
57
  export class DatePicker extends Component<Props> implements IDatePicker {
@@ -7,7 +7,7 @@ import { HOUR_IN_MS } from '@24i/bigscreen-sdk/utils/timeConstants';
7
7
  import { InternalEpg, Plugin } from '../interface';
8
8
 
9
9
  const formatTime = (localTimestamp: number) => l10n.date(localTimestamp).toLocaleTimeString(
10
- { hour: 'numeric', minute: '2-digit' },
10
+ { hour: 'numeric', minute: '2-digit', formatType: 'timeFormat' },
11
11
  );
12
12
 
13
13
  const formatDate = (localTimestamp: number) => {
@@ -24,6 +24,7 @@ const formatDate = (localTimestamp: number) => {
24
24
  weekday: 'short',
25
25
  day: 'numeric',
26
26
  month: 'short',
27
+ formatType: 'dateFormatShort',
27
28
  });
28
29
  };
29
30
 
@@ -18,7 +18,9 @@ export class Day extends Component<Props> implements IDay {
18
18
  private formatCurrentTimestamp() {
19
19
  return l10n
20
20
  .date(this.timestamp + time.getTimezoneOffsetMs())
21
- .toLocaleDateString({ weekday: 'long', day: 'numeric', month: 'short' });
21
+ .toLocaleDateString({
22
+ weekday: 'long', day: 'numeric', month: 'short', formatType: 'dateFormatShort',
23
+ });
22
24
  }
23
25
 
24
26
  render() {
@@ -19,7 +19,7 @@ export const getSubtitle = (asset: Asset) => (
19
19
 
20
20
  const toLocaleTimeString = (timestamp: number) => l10n
21
21
  .date(timestamp + time.getTimezoneOffsetMs())
22
- .toLocaleTimeString({ hour: 'numeric', minute: '2-digit' });
22
+ .toLocaleTimeString({ hour: 'numeric', minute: '2-digit', formatType: 'timeFormat' });
23
23
 
24
24
  export const getBroadcastTime = (asset: Asset) => {
25
25
  const start = toLocaleTimeString(asset.program!.startTime);
@@ -26,7 +26,7 @@ export class TimelineSection extends Component<Props> implements ITimelineSectio
26
26
  private formatCurrentTimestamp() {
27
27
  return l10n
28
28
  .date(this.timestamp + time.getTimezoneOffsetMs())
29
- .toLocaleTimeString({ hour: 'numeric', minute: '2-digit' });
29
+ .toLocaleTimeString({ hour: 'numeric', minute: '2-digit', formatType: 'timeFormat' });
30
30
  }
31
31
 
32
32
  render() {
@@ -1,4 +1,4 @@
1
- import { PlayerBase } from '@24i/player-base';
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<any>,
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.getMediaInfo();
70
+ const { playerVersion } = player.mediaInfo;
71
71
  return {
72
72
  pl: playerName,
73
73
  plv: playerVersion || '',
@@ -76,6 +76,24 @@ type DateTimeFormatOptions = {
76
76
  }
77
77
  ```
78
78
 
79
+ #### date-fns DateTime format
80
+ It is also possible to use formatting provided by [date-fns](https://date-fns.org/v2.30.0/docs/format) library. First you need to globally configure the formats used (usually from backstage):
81
+ ```ts
82
+ l10n.init({
83
+ dateFormatLong?: string | null, // e.g. 'eee, dd MMM' for "Wed, 09 Jul"
84
+ dateFormatNumeric?: string | null, // e.g. 'EEEE, MMMM d' for "Wednesday, July 9"
85
+ dateFormatShort?: string | null, // e.g. 'MM/dd/yyyy' for "07/09/2023"
86
+ timeFormat?: string | null, // e.g. 'h:mm a' for "9:05 PM"
87
+ });
88
+ ```
89
+ After that, `timeFormat` and `dateFormatShort` are used automatically where appropriate, in case the format string is _falsy_ the [default formatting implementation](#datetime-format) will be used. You can also specify which format you want to use in `DateTimeFormatOptions`:
90
+ ```ts
91
+ type DateTimeFormatOptions = {
92
+ ...
93
+ formatType: 'dateFormatLong' | 'dateFormatNumeric' | 'dateFormatShort' | 'timeFormat',
94
+ }
95
+ ```
96
+
79
97
  You can use both `timestamp` in `ms` or `Date` object directly for formatting.
80
98
 
81
99
  #### Examples
@@ -20,6 +20,8 @@ type TimeKeys = 'hour' | 'minute' | 'second';
20
20
 
21
21
  type DateKeys = 'weekday' | 'year' | 'month' | 'day';
22
22
 
23
+ type FormatType = 'dateFormatLong' | 'dateFormatNumeric' | 'dateFormatShort' | 'timeFormat';
24
+
23
25
  export type DateTimeFormatOptions = {
24
26
  weekday?: Weekday,
25
27
  year?: Year,
@@ -28,6 +30,7 @@ export type DateTimeFormatOptions = {
28
30
  hour?: Hour,
29
31
  minute?: Minute,
30
32
  second?: Second,
33
+ formatType?: FormatType,
31
34
  };
32
35
 
33
36
  export type DateFormatOptions = Pick<DateTimeFormatOptions, DateKeys>;
@@ -1,3 +1,5 @@
1
+ import { format } from 'date-fns';
2
+ import * as fnsLocales from 'date-fns/locale';
1
3
  import { EventsManager, IEvents } from '@24i/bigscreen-sdk/events-manager';
2
4
  import { csDateFormatter } from './date/cs';
3
5
  import { deDateFormatter } from './date/de';
@@ -6,11 +8,19 @@ import { frDateFormatter } from './date/fr';
6
8
  import { heDateFormatter } from './date/he';
7
9
  import { isoDateFormatter } from './date/iso';
8
10
  import { Formatters } from './types';
11
+ import { DateTimeFormatOptions } from './date/types';
9
12
 
10
13
  type Events = {
11
14
  'localechange': () => void,
12
15
  };
16
+
17
+ type DateFnsConfig = Partial<
18
+ Record<NonNullable<DateTimeFormatOptions['formatType']>, string | null>
19
+ >;
20
+
13
21
  class L10n implements IEvents<Events> {
22
+ private dateFnsConfig: DateFnsConfig = {};
23
+
14
24
  private readonly events = new EventsManager<Events>();
15
25
 
16
26
  addEventListener = this.events.addEventListener;
@@ -43,15 +53,53 @@ class L10n implements IEvents<Events> {
43
53
  return this.formatters[formatter].iso;
44
54
  }
45
55
 
56
+ init(config: DateFnsConfig) {
57
+ this.dateFnsConfig = config;
58
+ }
59
+
46
60
  setLocale(locale: string) {
47
61
  if (locale === this.locale) return;
48
62
  this.locale = locale;
49
63
  this.triggerEvent('localechange');
50
64
  }
51
65
 
52
- date(timestamp: number | Date, locale?: string) {
53
- const formatter = this.getFormatterByLocale('date', locale);
54
- return formatter(timestamp);
66
+ getDateFnsFormatter = (
67
+ timestamp: number | Date,
68
+ locale: string,
69
+ fallbackCb: (options?: DateTimeFormatOptions) => string,
70
+ fallbackFormatType?: DateTimeFormatOptions['formatType'],
71
+ ) => (
72
+ (options?: DateTimeFormatOptions): string => {
73
+ const { formatType, ...baseOptions } = options || {};
74
+ const dateFnsBsFormat = this.dateFnsConfig?.[formatType || fallbackFormatType!];
75
+ if (!dateFnsBsFormat) {
76
+ if (!options || Object.keys(baseOptions).length === 0) {
77
+ return fallbackCb();
78
+ }
79
+ return fallbackCb(baseOptions);
80
+ }
81
+ return format(
82
+ timestamp,
83
+ dateFnsBsFormat,
84
+ { locale: fnsLocales[locale as keyof typeof fnsLocales] },
85
+ );
86
+ }
87
+ );
88
+
89
+ date(timestamp: number | Date, locale: string = this.locale) {
90
+ const formatter = this.getFormatterByLocale('date', locale)(timestamp);
91
+
92
+ return {
93
+ toLocaleString: this.getDateFnsFormatter(
94
+ timestamp, locale, formatter.toLocaleString,
95
+ ),
96
+ toLocaleTimeString: this.getDateFnsFormatter(
97
+ timestamp, locale, formatter.toLocaleTimeString, 'timeFormat',
98
+ ),
99
+ toLocaleDateString: this.getDateFnsFormatter(
100
+ timestamp, locale, formatter.toLocaleDateString, 'dateFormatShort',
101
+ ),
102
+ };
55
103
  }
56
104
 
57
105
  addFormatter<T extends keyof Formatters, U extends keyof Formatters[T]>(
@@ -1,5 +1,5 @@
1
1
  import { Component, createRef, DeclareProps } from '@24i/bigscreen-sdk/jsx';
2
- import { ITimeUpdateEvent } from '@24i/player-base';
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.getMetadata() || {};
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/player-base';
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.getMetadata() || {};
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/player-base';
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<any>,
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<any> | null = null;
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<any>) {
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/player-base';
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.getMetadata() || {};
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/player-base';
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.getMetadata();
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.getMetadata();
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/player-base';
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<any> | null;
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<any> | null = null) {
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<any>) {
55
+ setPlayer(player: PlayerBase) {
56
56
  this.player = player;
57
57
  }
58
58
 
@@ -1,11 +1,11 @@
1
- import { PlayerBase, ITimeUpdateEvent } from '@24i/player-base';
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<any>,
8
+ player: PlayerBase,
9
9
  className?: string,
10
10
  };
11
11
 
@@ -1,4 +1,4 @@
1
- import { PlayerBase, PlayerBaseMock } from '@24i/player-base';
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<any> => {
39
- const playerMock = new PlayerBaseMock();
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<any> => getPlayerMock()),
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/player-base';
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<any>,
24
+ getPlayer: () => PlayerBase,
25
25
  disableHiding: () => void,
26
26
  enableHiding: () => void,
27
27
  disableSeeking: () => void,