@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/CHANGELOG.md +55 -7
- package/dist/core.mjs +11 -99
- package/dist/index.js +8567 -8627
- package/dist/index.mjs +429 -483
- package/dist/modules.mjs +148 -130
- package/dist/react.mjs +269 -306
- package/package.json +1 -1
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$
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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);
|
|
272
|
-
|
|
273
|
-
|
|
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
|
|
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.
|
|
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;
|