@24i/bigscreen-sdk 1.0.11-alpha.2225 → 1.0.11-alpha.2229

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@24i/bigscreen-sdk",
3
- "version": "1.0.11-alpha.2225",
3
+ "version": "1.0.11-alpha.2229",
4
4
  "description": "SmartApps BIGscreen SDK monorepo",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,4 +1,5 @@
1
1
  import { DeviceBase } from '@24i/bigscreen-sdk/driver-base';
2
+ import { DeviceAndroidTV } from '@24i/bigscreen-sdk/driver-androidtv';
2
3
  import { IStorage } from '@24i/bigscreen-sdk/storage/interface';
3
4
  import { getUsedJSHeapSize, getTotalJSHeapSize } from '@24i/bigscreen-sdk/utils/memoryInfo';
4
5
  import { ipify } from '@24i/bigscreen-sdk/ipify';
@@ -270,14 +271,23 @@ class TechnicalInfoProvider implements ITechnicalInfoProvider {
270
271
  return this.props.appCoreVersions || unknown;
271
272
  }
272
273
 
273
- getSourceDataLayout() {
274
+ async getWrapperVersion() {
275
+ let value;
276
+ const { unknown } = this.translations;
277
+ try {
278
+ value = await (this.props.device as DeviceAndroidTV).getWrapperVersion();
279
+ } catch (e) {}
280
+ return value || unknown;
281
+ }
282
+
283
+ async getSourceDataLayout() {
274
284
  const {
275
285
  username, profile, appVersion, firmwareVersion, deviceModel,
276
286
  deviceManufacturer, platform, player, serialNumber, localIpAddress,
277
287
  publicIpAddress, connectionType, macAddress, memoryHeapSize,
278
288
  usedLocalStorage, timeZone, dateAndTime, flavour, userAgent,
279
289
  emeSupport, emeDrmSystems, mseSupport, fourKSupport, resolution, baseUrl,
280
- appCoreVersions,
290
+ appCoreVersions, androidWrapperVersion,
281
291
  } = this.translations;
282
292
  const dataLayout: SourceDataLayout = [
283
293
  { label: username, getter: this.getUserName },
@@ -307,9 +317,21 @@ class TechnicalInfoProvider implements ITechnicalInfoProvider {
307
317
  { label: resolution, getter: this.getAppResolution },
308
318
  { label: baseUrl, getter: this.getBackendBaseUrl },
309
319
  ];
320
+
321
+ if (await this.isAndroidTV()) {
322
+ dataLayout.push(
323
+ { label: androidWrapperVersion, getter: this.getWrapperVersion },
324
+ );
325
+ }
326
+
310
327
  return dataLayout;
311
328
  }
312
329
 
330
+ async isAndroidTV() {
331
+ const platformName = await this.props.device.getPlatformName();
332
+ return platformName === 'AndroidTV';
333
+ }
334
+
313
335
  async loadDataLayout(dataLayout: SourceDataLayout) {
314
336
  const promises = map(dataLayout, async (item) => item.getter.call(this));
315
337
  const values = await Promise.all(promises);
@@ -319,7 +341,7 @@ class TechnicalInfoProvider implements ITechnicalInfoProvider {
319
341
  }
320
342
 
321
343
  async getInfoData() {
322
- const sourceDataLayout = this.getSourceDataLayout();
344
+ const sourceDataLayout = await this.getSourceDataLayout();
323
345
  return this.loadDataLayout(sourceDataLayout);
324
346
  }
325
347
  }
@@ -46,6 +46,10 @@ class Device {
46
46
  async getMacAddress() {
47
47
  return 'mac address';
48
48
  }
49
+
50
+ async getWrapperVersion() {
51
+ return 'android wrapper version';
52
+ }
49
53
  }
50
54
 
51
55
  export { Device };
@@ -3,6 +3,7 @@ export type Translations = TranslationKeys | { [K in keyof TranslationKeys]?: ne
3
3
  export type TranslationKeys = {
4
4
  unknown: string
5
5
  anonymous: string,
6
+ androidWrapperVersion: string,
6
7
  yes: string,
7
8
  no: string,
8
9
  prefixed: string,
@@ -41,6 +42,7 @@ export type TranslationKeys = {
41
42
  export const defaultTranslations = {
42
43
  unknown: 'UNKNOWN',
43
44
  anonymous: 'ANONYMOUS',
45
+ androidWrapperVersion: 'Android wrapper version',
44
46
  yes: 'Yes',
45
47
  no: 'No',
46
48
  prefixed: 'prefixed',
@@ -154,6 +154,10 @@ export class DeviceAndroidTV extends DeviceBase {
154
154
  return VolumeRange.UNSUPPORTED;
155
155
  }
156
156
 
157
+ async getWrapperVersion(): Promise<string> {
158
+ return this.platformInfo.appVersion;
159
+ }
160
+
157
161
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
158
162
  async setVolume(volumePercentage: number): Promise<void> {
159
163
  // not supported on AndroidTV platform
@@ -195,7 +199,9 @@ export class DeviceAndroidTV extends DeviceBase {
195
199
  }
196
200
 
197
201
  async getLocalIP(): Promise<string> {
198
- // not supported on AndroidTV platform
202
+ const ipv4RegExp = /\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/;
203
+ const ip = this.platformInfo.ipLocal.toString().match(ipv4RegExp);
204
+ if (ip) return ip.toString();
199
205
  return '';
200
206
  }
201
207
 
@@ -7,6 +7,10 @@ export const mockJavaScriptBridge: IJavaScriptBridge = {
7
7
  deviceBrand: 'Sony',
8
8
  deviceModel: 'BRAVIA 4K 2015',
9
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',
10
14
  })
11
15
  ),
12
16
  bridgeJavaScriptToAndroid_Back: () => {},
@@ -2,7 +2,9 @@ interface JavaScriptBridge {
2
2
  /**
3
3
  * It returns a JSON string with device info.
4
4
  * @return JSON string with the information about the device brand, model and Android version.
5
- * Ex. '{"deviceBrand": "Sony", "deviceModel": "BRAVIA 4K 2015", "osVersion": "7.0" }'
5
+ * Ex. '{"deviceBrand": "Sony", "deviceModel": "BRAVIA 4K 2015", "osVersion": "7.0",
6
+ * "appFlavor": "appstage-bigscreen", "drmKeySystems": ["Widewine", "W3C ClearKey"],
7
+ * "ipLocal": "fe80::475:3045:2928:3a32%wlan0127.0.0.1", "appVersion": '0.0.1' }'
6
8
  */
7
9
  bridgeJavaScriptToAndroid_GetDeviceInfo: () => string,
8
10
  /**
@@ -24,6 +26,22 @@ export type DeviceInfo = {
24
26
  * Android version. Ex. "7.0"
25
27
  */
26
28
  osVersion: string,
29
+ /**
30
+ * Android wrapper version. Ex. "0.0.1"
31
+ */
32
+ appVersion: string,
33
+ /**
34
+ * Android flavor. Ex. "appstage-bigscreen"
35
+ */
36
+ appFlavor: string,
37
+ /**
38
+ * Android DRM key systems. Ex. ["Widewine", "W3C ClearKey"]
39
+ */
40
+ drmKeySystems: Array<string>,
41
+ /**
42
+ * Android local IP adress in array Ex. "fe80::475:3045:2928:3a32%wlan0127.0.0.1"
43
+ */
44
+ ipLocal: string,
27
45
  };
28
46
 
29
47
  export interface IJavaScriptBridge {
@@ -84,67 +84,115 @@ export class DataManager implements IDataManager {
84
84
  return [data[0].program!.startTime, data[data.length - 1].program!.endTime] as DataRange;
85
85
  }
86
86
 
87
- // TODO: Wait for fixes from @thepretiso before looking at this.
87
+ private isInterceptingDataRanges = (firstDataRange: DataRange, secondDataRange: DataRange) => (
88
+ (firstDataRange[START] < secondDataRange[END]
89
+ && firstDataRange[START] > secondDataRange[START])
90
+ || (secondDataRange[START] < firstDataRange[END]
91
+ && secondDataRange[START] > firstDataRange[START])
92
+ );
93
+
94
+ private findRangeBeforeAndAfter = (currentRange: DataRange) => {
95
+ const rangeAfterIndex = findIndex(
96
+ this.dataRanges,
97
+ (dataRange) => dataRange[END] >= currentRange[END],
98
+ );
99
+ if (rangeAfterIndex === -1) {
100
+ return {
101
+ rangeAfter: undefined,
102
+ rangeBefore: this.dataRanges[this.dataRanges.length - 1],
103
+ };
104
+ }
105
+ const rangeAfter = this.dataRanges[rangeAfterIndex];
106
+ const rangeBefore = this.dataRanges[rangeAfterIndex - 1];
107
+ return { rangeAfter, rangeBefore };
108
+ };
109
+
110
+ private generateDataRangesForward = (start: number, end: number, cellSize: number) => {
111
+ const dataRanges: DataRange[] = [[start, start + cellSize]];
112
+ let currentStart = start + cellSize;
113
+ let currentEnd = currentStart + cellSize;
114
+ while (currentStart < end) {
115
+ if (currentEnd >= end) {
116
+ dataRanges.push([currentStart, end]);
117
+ break;
118
+ }
119
+ dataRanges.push([currentStart, currentEnd]);
120
+ currentStart += cellSize;
121
+ currentEnd += cellSize;
122
+ }
123
+ return dataRanges;
124
+ };
125
+
126
+ private generateDataRangesBackward = (start: number, end: number, cellSize: number) => {
127
+ const dataRanges: DataRange[] = [[start - cellSize, start]];
128
+ let currentEnd = start - cellSize;
129
+ let currentStart = currentEnd - cellSize;
130
+ while (currentEnd > start) {
131
+ if (currentStart <= start) {
132
+ dataRanges.push([start, currentEnd]);
133
+ break;
134
+ }
135
+ dataRanges.push([currentStart, currentEnd]);
136
+ currentStart -= cellSize;
137
+ currentEnd -= cellSize;
138
+ }
139
+ return dataRanges;
140
+ };
141
+
88
142
  /* eslint-disable complexity */
89
143
  // eslint-disable-next-line sonarjs/cognitive-complexity
90
144
  private getRangesMissingFromDataInRange([start, end]: DataRange) {
91
- const rangesLength = this.dataRanges.length;
145
+ const currentRange = [start, end] as DataRange;
92
146
  const cellSize = TIMELINE_WIDTHS_TO_FETCH * this.timelineWidthMs;
93
- if (this.dataRanges.length === 0) return [[start, end]] as DataRange[];
94
- const firstRangeFrom = this.dataRanges[0][START];
95
- const firstRangeTo = this.dataRanges[0][END];
96
- if (end <= firstRangeFrom) return [[start, end]] as DataRange[];
97
- if (start < firstRangeFrom && end <= firstRangeTo) {
98
- return [
99
- [firstRangeFrom - cellSize, firstRangeFrom],
100
- ] as DataRange[];
101
- }
102
- const lastRangeFrom = this.dataRanges[rangesLength - 1][START];
103
- const lastRangeTo = this.dataRanges[rangesLength - 1][END];
104
- if (end > lastRangeTo && start <= lastRangeTo) {
105
- return [
106
- [lastRangeTo, lastRangeTo + cellSize],
107
- ] as DataRange[];
108
- }
109
- if (start >= lastRangeTo && end >= lastRangeTo && start - lastRangeTo >= cellSize) {
110
- return [
111
- [start, end],
112
- ] as DataRange[];
113
- }
114
- const ranges: DataRange[] = [];
115
- let newRange: DataRange = [start, end];
116
- for (let i = 0; i < rangesLength; i++) {
117
- const [rangeFrom, rangeTo] = this.dataRanges[i];
118
- if (start >= rangeTo) {
119
- if (start - rangeTo <= cellSize) {
120
- newRange[START] = rangeTo;
121
- } else {
122
- const newStart = lastRangeFrom - cellSize;
123
- newRange[START] = newStart;
147
+ if (this.dataRanges.length === 0) return [currentRange] as DataRange[];
148
+ const { rangeBefore, rangeAfter } = this.findRangeBeforeAndAfter(currentRange);
149
+ if (rangeAfter == null) {
150
+ const lastDataRange = this.dataRanges[this.dataRanges.length - 1];
151
+ if (this.isInterceptingDataRanges(lastDataRange, currentRange)) {
152
+ if (end > lastDataRange[END]) {
153
+ return this.generateDataRangesForward(lastDataRange[END], end, cellSize);
124
154
  }
125
- // eslint-disable-next-line no-continue
126
- continue;
127
- }
128
- if (start < rangeFrom) {
129
- if (end <= rangeFrom) {
130
- if (newRange[START] !== newRange[END]) ranges.push(newRange);
131
- return ranges;
155
+ if (start < lastDataRange[START]) {
156
+ return this.generateDataRangesBackward(start, lastDataRange[START], cellSize);
132
157
  }
133
- newRange[END] = rangeFrom;
134
- if (newRange[START] !== newRange[END]) ranges.push(newRange);
135
- if (end <= rangeTo) {
136
- return ranges;
158
+ }
159
+ return [currentRange] as DataRange[];
160
+ }
161
+ if (rangeBefore == null) {
162
+ const firstDataRange = this.dataRanges[0];
163
+ if (this.isInterceptingDataRanges(firstDataRange, currentRange)) {
164
+ if (end > firstDataRange[END]) {
165
+ return this.generateDataRangesForward(firstDataRange[END], end, cellSize);
137
166
  }
138
- newRange = [rangeTo, end];
139
- } else if (start < rangeTo) {
140
- if (end <= rangeTo) {
141
- return ranges;
167
+ if (start < firstDataRange[START]) {
168
+ return this.generateDataRangesBackward(firstDataRange[START], start, cellSize);
142
169
  }
143
- newRange = [rangeTo, end];
144
170
  }
171
+ return [currentRange] as DataRange[];
172
+ }
173
+ const rangeAfterFrom = rangeAfter[START];
174
+ const rangeBeforeTo = rangeBefore[END];
175
+ // Ranges are collapsed
176
+ if (rangeBeforeTo === rangeAfterFrom) return [];
177
+ // Both are not null and don't intercept
178
+ if (
179
+ !this.isInterceptingDataRanges(rangeAfter, currentRange)
180
+ && !this.isInterceptingDataRanges(rangeBefore, currentRange)
181
+ ) {
182
+ return [currentRange];
183
+ }
184
+ // Left intercepts
185
+ if (this.isInterceptingDataRanges(rangeBefore, currentRange)) {
186
+ return [rangeBefore, ...this.generateDataRangesForward(rangeBeforeTo, end, cellSize)];
187
+ }
188
+ // Right intercepts
189
+ if (this.isInterceptingDataRanges(rangeAfter, currentRange)) {
190
+ return [
191
+ ...this.generateDataRangesBackward(rangeAfterFrom, start, cellSize),
192
+ rangeAfter,
193
+ ];
145
194
  }
146
- if (newRange[START] !== newRange[END]) ranges.push(newRange);
147
- return ranges;
195
+ return [currentRange] as DataRange[];
148
196
  }
149
197
 
150
198
  private getMissingRanges(range: DataRange) {
@@ -4,6 +4,7 @@ import { stopEvent } from '@24i/bigscreen-sdk/utils/stopEvent';
4
4
  import { ITimeUpdateEvent, IDurationChangeEvent } from '@24i/player-base';
5
5
  import { createTimeout } from '@24i/bigscreen-sdk/utils/timers';
6
6
  import { switchByKey } from '@24i/bigscreen-sdk/device/keymap';
7
+ import { getDisplayToggler } from '@24i/bigscreen-sdk/utils/displayToggler';
7
8
  import { PlayerTime } from './PlayerTime';
8
9
  import { getLiveProgressBasedOnCurrentTime } from './timeUtils';
9
10
  import { PlayerUICommonProps } from './types';
@@ -26,6 +27,8 @@ export class Seekbar extends Component<Props> implements IFocusable {
26
27
 
27
28
  seekTime = createRef<PlayerTime>();
28
29
 
30
+ displaySeekPoint = getDisplayToggler(this.seekPoint);
31
+
29
32
  leftConsecutiveness = 0;
30
33
 
31
34
  rightConsecutiveness = 0;
@@ -40,6 +43,8 @@ export class Seekbar extends Component<Props> implements IFocusable {
40
43
 
41
44
  isMouseDownPressed = false;
42
45
 
46
+ seekingDisabled = false;
47
+
43
48
  static defaultProps = {
44
49
  className: '',
45
50
  };
@@ -67,7 +72,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
67
72
  }
68
73
 
69
74
  onMouseMove = (event: MouseEvent) => {
70
- if (!this.isMouseDownPressed) return;
75
+ if (!this.isMouseDownPressed || this.seekingDisabled) return;
71
76
  const { ui: { seeking } } = this.props;
72
77
  const wrapRect = this.wrap.current!.getBoundingClientRect();
73
78
  const clientX = event.clientX - wrapRect.left;
@@ -79,6 +84,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
79
84
  };
80
85
 
81
86
  onMouseClick = (event: MouseEvent) => {
87
+ if (this.seekingDisabled) return;
82
88
  const { ui: { seeking } } = this.props;
83
89
  const wrapWidth = this.wrap.current!.offsetWidth;
84
90
  const percentage = (TO_PERCENT * event.offsetX) / wrapWidth;
@@ -115,6 +121,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
115
121
  };
116
122
 
117
123
  onLeft = () => {
124
+ if (this.seekingDisabled) return true;
118
125
  const { ui } = this.props;
119
126
  this.leftConsecutiveness += 1;
120
127
  if (ui.seeking.isAutomaticallySeeking()) {
@@ -128,6 +135,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
128
135
  };
129
136
 
130
137
  onRight = () => {
138
+ if (this.seekingDisabled) return true;
131
139
  const { ui } = this.props;
132
140
  const { seekTime } = ui.seeking;
133
141
  if (seekTime == null && this.currentTime + SLOW_TIME >= this.duration) return true;
@@ -222,6 +230,20 @@ export class Seekbar extends Component<Props> implements IFocusable {
222
230
  this.seekPoint.current!.style.left = `${percentTime}%`;
223
231
  }
224
232
 
233
+ disableSeeking() {
234
+ this.seekingDisabled = true;
235
+ this.displaySeekPoint.hide();
236
+ }
237
+
238
+ enableSeeking() {
239
+ this.seekingDisabled = false;
240
+ this.displaySeekPoint.show();
241
+ }
242
+
243
+ isSeekingDisabled() {
244
+ return this.seekingDisabled;
245
+ }
246
+
225
247
  render() {
226
248
  const { className } = this.props;
227
249
  return (
@@ -84,7 +84,9 @@ function xhrSend(url: string, options: Partial<XhrOptions> = {}): Promise<XhrRes
84
84
  const xhr = new XMLHttpRequest();
85
85
 
86
86
  function onLoad() {
87
- const dataText = 'response' in xhr ? xhr.response : xhr.responseText;
87
+ const dataText = 'response' in (xhr as XMLHttpRequest)
88
+ ? xhr.response
89
+ : xhr.responseText;
88
90
  const dataJson = parseJson(dataText);
89
91
  const status = xhr.status === undefined ? HttpStatusCode.OK : xhr.status;
90
92
  const statusText = xhr.statusText === undefined ? 'OK' : xhr.statusText;