@kkcompany/player 2.25.0-canary.0 → 2.25.0-canary.10

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/dist/modules.mjs CHANGED
@@ -21,7 +21,7 @@ const ignoreMinorError = async (event, {
21
21
  retry,
22
22
  retryTimes
23
23
  } = {}) => {
24
- var _event$response, _event$response2, _event$config, _event$config2;
24
+ var _event$response, _event$response2, _event$response3;
25
25
 
26
26
  console.warn(event);
27
27
 
@@ -30,17 +30,34 @@ const ignoreMinorError = async (event, {
30
30
  return retry();
31
31
  }
32
32
 
33
- if (/start$|info$|heartbeat$/.test((_event$config = event.config) === null || _event$config === void 0 ? void 0 : _event$config.url)) {
33
+ const url = new URL(((_event$response3 = event.response) === null || _event$response3 === void 0 ? void 0 : _event$response3.url) || 'http://unknown/');
34
+
35
+ if (/start$|info$|heartbeat$/.test(url.pathname)) {
34
36
  return Promise.reject(event);
35
37
  }
36
38
 
37
- if (/end$/.test((_event$config2 = event.config) === null || _event$config2 === void 0 ? void 0 : _event$config2.url)) {
39
+ if (/end$/.test(url.pathname)) {
38
40
  return Promise.resolve();
39
41
  }
40
42
 
41
43
  console.log('Ignore non-critical playback API fail', event);
42
44
  return new Promise(() => {});
43
45
  };
46
+ /** @param {Response} response */
47
+
48
+
49
+ const handleFetchResponse = response => {
50
+ if (response.ok) {
51
+ return response.status === 200 ? response.json() : '';
52
+ }
53
+
54
+ return response.json().then(errorData => {
55
+ const error = new Error(`HTTP error status: ${response.status} ${errorData.message}`);
56
+ error.data = errorData;
57
+ error.response = response;
58
+ return Promise.reject(error);
59
+ });
60
+ };
44
61
 
45
62
  const createApi = (config, {
46
63
  onError = ignoreMinorError
@@ -68,7 +85,7 @@ const createApi = (config, {
68
85
  } = {}) => handleRequestError(() => fetch(`${url}?${new URLSearchParams(params).toString()}`, {
69
86
  method,
70
87
  headers: getHeaders()
71
- }).then(response => response.json()), {
88
+ }).then(handleFetchResponse), {
72
89
  onError
73
90
  });
74
91
 
@@ -82,7 +99,7 @@ const createApi = (config, {
82
99
  }).toString()}`, {
83
100
  method,
84
101
  headers: getHeaders()
85
- }).then(response => response.json()), {
102
+ }).then(handleFetchResponse), {
86
103
  onError
87
104
  });
88
105
 
@@ -265,15 +282,15 @@ function getDevice() {
265
282
  function getBrowser() {
266
283
  return parser.getBrowser();
267
284
  }
285
+
286
+ const isSafari = () => /^((?!chrome|android|X11|Linux).)*(safari|iPad|iPhone|Version)/i.test(navigator.userAgent);
287
+
268
288
  function needNativeHls() {
269
289
  // Don't let Android phones play HLS, even if some of them report supported
270
290
  // This covers Samsung & OPPO special cases
271
- const isAndroid = /android|X11|Linux/i.test(navigator.userAgent); // canPlayType isn't reliable across all iOS verion / device combinations, so also check user agent
272
-
273
- const isSafari = /^((?!chrome|android|X11|Linux).)*(safari|iPad|iPhone|Version)/i.test(navigator.userAgent); // ref: https://stackoverflow.com/a/12905122/4578017
274
- // none of our supported browsers other than Safari response to this
275
-
276
- return isAndroid || /firefox/i.test(navigator.userAgent) ? '' : isSafari ? 'maybe' : document.createElement('video').canPlayType('application/vnd.apple.mpegURL');
291
+ const isAndroid = /android|X11|Linux/i.test(navigator.userAgent);
292
+ return isAndroid || /firefox/i.test(navigator.userAgent) ? '' : // canPlayType isn't reliable across all iOS verion / device combinations, so also check user agent
293
+ isSafari() ? 'maybe' : document.createElement('video').canPlayType('application/vnd.apple.mpegURL');
277
294
  }
278
295
 
279
296
  const isDesktop = () => !getDevice().type; // TODO solve lint error:
@@ -373,38 +390,6 @@ const validateEnvironment = (supportEnvironmentList = []) => {
373
390
  }
374
391
  }; // Some touch devices with a mouse can't be distinguished, assume no mouse
375
392
 
376
- const timeoutError = () => new Error('request timeout');
377
- /**
378
- * @param {URL|RequestInfo} url
379
- * @param {RequestInit} options
380
- * @param {{responseType: 'json'|'text'}}
381
- */
382
-
383
-
384
- const retryRequest = (url, options = {}, {
385
- responseType = 'json',
386
- timeout = 6,
387
- retryTimes = 6
388
- } = {}) => new Promise((resolve, reject) => {
389
- setTimeout(() => reject(timeoutError()), timeout * 1000);
390
- fetch(url, options).then(response => {
391
- var _response$responseTyp;
392
-
393
- return resolve(((_response$responseTyp = response[responseType]) === null || _response$responseTyp === void 0 ? void 0 : _response$responseTyp.call(response)) || response);
394
- }).catch(reject);
395
- }).catch(error => {
396
- console.log(error);
397
-
398
- if (retryTimes > 0) {
399
- return retryRequest(url, options, {
400
- timeout,
401
- retryTimes: retryTimes - 1
402
- });
403
- }
404
-
405
- return error;
406
- });
407
-
408
393
  const protocolExtensions = {
409
394
  hls: 'm3u8',
410
395
  dash: 'mpd'
@@ -443,7 +428,7 @@ const getDrmOptions = fallbackDrm => {
443
428
  * @typedef {{hls: string, dash: string}} SourceObjectAlt backward compatiable form
444
429
  *
445
430
  * @param {SourceObject[]|SourceObject|SourceObjectAlt|string} sourceOptions
446
- * @param {{preferManifestType?: ('dash'|'hls')}} options
431
+ * @param {{preferManifestType?: ('dash'|'hls'|'platform')}} options
447
432
  * @return {{src: string, type: string, drm: Object}}
448
433
  */
449
434
 
@@ -486,7 +471,8 @@ const getSource = (sourceOptions, {
486
471
  });
487
472
  }
488
473
 
489
- const matched = sourceOptions.find(source => !preferManifestType || matchType(source, preferManifestType));
474
+ const targetType = preferManifestType !== 'platform' ? preferManifestType : isSafari() ? 'hls' : 'dash';
475
+ const matched = sourceOptions.find(source => matchType(source, targetType));
490
476
  const selected = matched || sourceOptions[0];
491
477
 
492
478
  if (!selected) {
@@ -501,90 +487,6 @@ const getSource = (sourceOptions, {
501
487
  };
502
488
  };
503
489
 
504
- function getVersion() {
505
- try {
506
- // eslint-disable-next-line no-undef
507
- return "2.25.0-canary.0";
508
- } catch (e) {
509
- return undefined;
510
- }
511
- }
512
-
513
- /* eslint-disable no-param-reassign */
514
-
515
- const matchAll = (input, pattern) => {
516
- const flags = [pattern.global && 'g', pattern.ignoreCase && 'i', pattern.multiline && 'm'].filter(Boolean).join('');
517
- const clone = new RegExp(pattern, flags);
518
- return Array.from(function* () {
519
- let matched = true;
520
-
521
- while (1) {
522
- matched = clone.exec(input);
523
-
524
- if (!matched) {
525
- return;
526
- }
527
-
528
- yield matched;
529
- }
530
- }());
531
- };
532
-
533
- const rewriteUrls = (manifest, sourceUrl) => manifest.replace(/((#EXT-X-MEDIA:.*URI=")([^"]*))|((#EXT-X-STREAM-INF.*\n)(.*)(?=\n))/g, (...matches) => [matches[2], matches[5], new URL(matches[3] || matches[6], sourceUrl)].filter(Boolean).join(''));
534
-
535
- const filterHlsManifestQualities = (originalManifest, filter) => {
536
- if (!filter) {
537
- return;
538
- }
539
-
540
- const manifest = `${originalManifest}\n`;
541
- const profiles = matchAll(manifest, /RESOLUTION=(\d+)x(\d+)/g).map(([, width, height]) => ({
542
- width: +width,
543
- height: +height
544
- }));
545
- const allowed = filter(profiles) || profiles;
546
- const newManifest = manifest.replace(/#EXT-X-STREAM-INF.*RESOLUTION=(\d+)x(\d+).*\n.*\n/g, (item, width, height) => allowed.some(p => p.width === +width && p.height === +height) ? item : '');
547
- return newManifest !== manifest && newManifest;
548
- };
549
-
550
- const meetRestriction = (quality, {
551
- minHeight,
552
- maxHeight
553
- } = {}) => !(quality.height < minHeight || quality.height > maxHeight);
554
-
555
- const selectHlsQualities = async (source, restrictions = {}) => {
556
- if (!needNativeHls() || !(restrictions.minHeight || restrictions.maxHeight)) {
557
- return source;
558
- }
559
-
560
- const selected = getSource(source, {
561
- preferManifestType: 'hls'
562
- });
563
-
564
- if (!((selected === null || selected === void 0 ? void 0 : selected.type.toLowerCase()) === mimeTypes.hls)) {
565
- return source;
566
- }
567
-
568
- const filtered = filterHlsManifestQualities(await retryRequest(selected.src, {}, {
569
- responseType: 'text'
570
- }), items => items.filter(item => meetRestriction(item, restrictions)));
571
-
572
- if (filtered) {
573
- return { ...selected,
574
-
575
- /*
576
- Native Safari couldn't support blob .m3u8. and will throw MediaError: 4
577
- We find the hacky method: dataURI.
578
- By the way, bitmovin also use this form even user gives the blob URI.
579
- */
580
- src: `data:application/x-mpegURL,${encodeURI(rewriteUrls(filtered, selected.src))}`
581
- };
582
- }
583
-
584
- return source;
585
- };
586
- // for unit test
587
-
588
490
  /* eslint-disable no-param-reassign */
589
491
 
590
492
  const SHAKA_LIVE_DURATION = 4294967296;
@@ -1086,6 +988,15 @@ const mapLogEvents$1 = ({
1086
988
  };
1087
989
  };
1088
990
 
991
+ function getVersion() {
992
+ try {
993
+ // eslint-disable-next-line no-undef
994
+ return "2.25.0-canary.10";
995
+ } catch (e) {
996
+ return undefined;
997
+ }
998
+ }
999
+
1089
1000
  const logEventNames = {
1090
1001
  playbackBeganLoading: 'playback_began_player_loading',
1091
1002
  playbackBeganPlayerStartupTime: 'playback_began_player_startup_time',
@@ -1502,7 +1413,7 @@ const createAnalytics = ({
1502
1413
  const logTarget = mapLogEvents({
1503
1414
  video,
1504
1415
  playerName: 'shaka',
1505
- version: "2.25.0-canary.0"
1416
+ version: "2.25.0-canary.10"
1506
1417
  });
1507
1418
  logTarget.all((type, data) => {
1508
1419
  const payload = {
@@ -1559,6 +1470,113 @@ const createAnalytics = ({
1559
1470
  };
1560
1471
  };
1561
1472
 
1473
+ const timeoutError = () => new Error('request timeout');
1474
+ /**
1475
+ * @param {URL|RequestInfo} url
1476
+ * @param {RequestInit} options
1477
+ * @param {{responseType: 'json'|'text'}}
1478
+ */
1479
+
1480
+
1481
+ const retryRequest = (url, options = {}, {
1482
+ responseType = 'json',
1483
+ timeout = 6,
1484
+ retryTimes = 6
1485
+ } = {}) => new Promise((resolve, reject) => {
1486
+ setTimeout(() => reject(timeoutError()), timeout * 1000);
1487
+ fetch(url, options).then(response => {
1488
+ var _response$responseTyp;
1489
+
1490
+ return resolve(((_response$responseTyp = response[responseType]) === null || _response$responseTyp === void 0 ? void 0 : _response$responseTyp.call(response)) || response);
1491
+ }).catch(reject);
1492
+ }).catch(error => {
1493
+ console.log(error);
1494
+
1495
+ if (retryTimes > 0) {
1496
+ return retryRequest(url, options, {
1497
+ timeout,
1498
+ retryTimes: retryTimes - 1
1499
+ });
1500
+ }
1501
+
1502
+ return error;
1503
+ });
1504
+
1505
+ /* eslint-disable no-param-reassign */
1506
+
1507
+ const matchAll = (input, pattern) => {
1508
+ const flags = [pattern.global && 'g', pattern.ignoreCase && 'i', pattern.multiline && 'm'].filter(Boolean).join('');
1509
+ const clone = new RegExp(pattern, flags);
1510
+ return Array.from(function* () {
1511
+ let matched = true;
1512
+
1513
+ while (1) {
1514
+ matched = clone.exec(input);
1515
+
1516
+ if (!matched) {
1517
+ return;
1518
+ }
1519
+
1520
+ yield matched;
1521
+ }
1522
+ }());
1523
+ };
1524
+
1525
+ const rewriteUrls = (manifest, sourceUrl) => manifest.replace(/((#EXT-X-MEDIA:.*URI=")([^"]*))|((#EXT-X-STREAM-INF.*\n)(.*)(?=\n))/g, (...matches) => [matches[2], matches[5], new URL(matches[3] || matches[6], sourceUrl)].filter(Boolean).join(''));
1526
+
1527
+ const filterHlsManifestQualities = (originalManifest, filter) => {
1528
+ if (!filter) {
1529
+ return;
1530
+ }
1531
+
1532
+ const manifest = `${originalManifest}\n`;
1533
+ const profiles = matchAll(manifest, /RESOLUTION=(\d+)x(\d+)/g).map(([, width, height]) => ({
1534
+ width: +width,
1535
+ height: +height
1536
+ }));
1537
+ const allowed = filter(profiles) || profiles;
1538
+ const newManifest = manifest.replace(/#EXT-X-STREAM-INF.*RESOLUTION=(\d+)x(\d+).*\n.*\n/g, (item, width, height) => allowed.some(p => p.width === +width && p.height === +height) ? item : '');
1539
+ return newManifest !== manifest && newManifest;
1540
+ };
1541
+
1542
+ const meetRestriction = (quality, {
1543
+ minHeight,
1544
+ maxHeight
1545
+ } = {}) => !(quality.height < minHeight || quality.height > maxHeight);
1546
+
1547
+ const selectHlsQualities = async (source, restrictions = {}) => {
1548
+ if (!isSafari() || !(restrictions.minHeight || restrictions.maxHeight)) {
1549
+ return source;
1550
+ }
1551
+
1552
+ const selected = getSource(source, {
1553
+ preferManifestType: 'hls'
1554
+ });
1555
+
1556
+ if (!((selected === null || selected === void 0 ? void 0 : selected.type.toLowerCase()) === mimeTypes.hls)) {
1557
+ return source;
1558
+ }
1559
+
1560
+ const filtered = filterHlsManifestQualities(await retryRequest(selected.src, {}, {
1561
+ responseType: 'text'
1562
+ }), items => items.filter(item => meetRestriction(item, restrictions)));
1563
+
1564
+ if (filtered) {
1565
+ return { ...selected,
1566
+
1567
+ /*
1568
+ Native Safari couldn't support blob .m3u8. and will throw MediaError: 4
1569
+ We find the hacky method: dataURI.
1570
+ By the way, bitmovin also use this form even user gives the blob URI.
1571
+ */
1572
+ src: `data:application/x-mpegURL,${encodeURI(rewriteUrls(filtered, selected.src))}`
1573
+ };
1574
+ }
1575
+
1576
+ return source;
1577
+ };
1578
+ // for unit test
1579
+
1562
1580
  /* eslint-disable no-empty */
1563
1581
  const storageKey = 'playcraft-tab-lock';
1564
1582
  const lockRenewTime = 3000;