hls.js 1.6.0-rc.1.0.canary.11071 → 1.6.0-rc.1.0.canary.11074
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/hls.d.mts +1 -0
- package/dist/hls.d.ts +1 -0
- package/dist/hls.js +101 -21
- package/dist/hls.js.d.ts +1 -0
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +101 -21
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +108 -21
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +108 -21
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/package.json +2 -2
- package/src/config.ts +2 -0
- package/src/controller/base-playlist-controller.ts +24 -0
- package/src/loader/m3u8-parser.ts +62 -7
- package/src/loader/playlist-loader.ts +19 -15
- package/src/utils/level-helper.ts +37 -1
package/dist/hls.light.mjs
CHANGED
@@ -402,7 +402,7 @@ function enableLogs(debugConfig, context, id) {
|
|
402
402
|
// Some browsers don't allow to use bind on console object anyway
|
403
403
|
// fallback to default if needed
|
404
404
|
try {
|
405
|
-
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-rc.1.0.canary.
|
405
|
+
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-rc.1.0.canary.11074"}`);
|
406
406
|
} catch (e) {
|
407
407
|
/* log fn threw an exception. All logger methods are no-ops. */
|
408
408
|
return createLogger();
|
@@ -4642,7 +4642,7 @@ const LEVEL_PLAYLIST_REGEX_FAST = new RegExp([/#EXTINF:\s*(\d*(?:\.\d+)?)(?:,(.*
|
|
4642
4642
|
// segment URI, group 3 => the URI (note newline is not eaten)
|
4643
4643
|
/#.*/.source // All other non-segment oriented tags will match with all groups empty
|
4644
4644
|
].join('|'), 'g');
|
4645
|
-
const LEVEL_PLAYLIST_REGEX_SLOW = new RegExp([/#
|
4645
|
+
const LEVEL_PLAYLIST_REGEX_SLOW = new RegExp([/#EXT-X-(PROGRAM-DATE-TIME|BYTERANGE|DATERANGE|DEFINE|KEY|MAP|PART|PART-INF|PLAYLIST-TYPE|PRELOAD-HINT|RENDITION-REPORT|SERVER-CONTROL|SKIP|START):(.+)/.source, /#EXT-X-(BITRATE|DISCONTINUITY-SEQUENCE|MEDIA-SEQUENCE|TARGETDURATION|VERSION): *(\d+)/.source, /#EXT-X-(DISCONTINUITY|ENDLIST|GAP|INDEPENDENT-SEGMENTS)/.source, /(#)([^:]*):(.*)/.source, /(#)(.*)(?:.*)\r?\n?/.source].join('|'));
|
4646
4646
|
class M3U8Parser {
|
4647
4647
|
static findGroup(groups, mediaGroupId) {
|
4648
4648
|
for (let i = 0; i < groups.length; i++) {
|
@@ -4832,6 +4832,7 @@ class M3U8Parser {
|
|
4832
4832
|
return results;
|
4833
4833
|
}
|
4834
4834
|
static parseLevelPlaylist(string, baseurl, id, type, levelUrlId, multivariantVariableList) {
|
4835
|
+
var _LEVEL_PLAYLIST_REGEX;
|
4835
4836
|
const base = {
|
4836
4837
|
url: baseurl
|
4837
4838
|
};
|
@@ -4853,9 +4854,14 @@ class M3U8Parser {
|
|
4853
4854
|
let firstPdtIndex = -1;
|
4854
4855
|
let createNextFrag = false;
|
4855
4856
|
let nextByteRange = null;
|
4857
|
+
let serverControlAttrs;
|
4856
4858
|
LEVEL_PLAYLIST_REGEX_FAST.lastIndex = 0;
|
4857
4859
|
level.m3u8 = string;
|
4858
4860
|
level.hasVariableRefs = false;
|
4861
|
+
if (((_LEVEL_PLAYLIST_REGEX = LEVEL_PLAYLIST_REGEX_FAST.exec(string)) == null ? void 0 : _LEVEL_PLAYLIST_REGEX[0]) !== '#EXTM3U') {
|
4862
|
+
level.playlistParsingError = new Error('Missing format identifier #EXTM3U');
|
4863
|
+
return level;
|
4864
|
+
}
|
4859
4865
|
while ((result = LEVEL_PLAYLIST_REGEX_FAST.exec(string)) !== null) {
|
4860
4866
|
if (createNextFrag) {
|
4861
4867
|
createNextFrag = false;
|
@@ -4944,15 +4950,23 @@ class M3U8Parser {
|
|
4944
4950
|
}
|
4945
4951
|
break;
|
4946
4952
|
case 'PLAYLIST-TYPE':
|
4953
|
+
if (level.type) {
|
4954
|
+
assignMultipleMediaPlaylistTagOccuranceError(level, tag, result);
|
4955
|
+
}
|
4947
4956
|
level.type = value1.toUpperCase();
|
4948
4957
|
break;
|
4949
4958
|
case 'MEDIA-SEQUENCE':
|
4959
|
+
if (level.startSN !== 0) {
|
4960
|
+
assignMultipleMediaPlaylistTagOccuranceError(level, tag, result);
|
4961
|
+
} else if (fragments.length > 0) {
|
4962
|
+
assignMustAppearBeforeSegmentsError(level, tag, result);
|
4963
|
+
}
|
4950
4964
|
currentSN = level.startSN = parseInt(value1);
|
4951
4965
|
break;
|
4952
4966
|
case 'SKIP':
|
4953
4967
|
{
|
4954
4968
|
if (level.skippedSegments) {
|
4955
|
-
level
|
4969
|
+
assignMultipleMediaPlaylistTagOccuranceError(level, tag, result);
|
4956
4970
|
}
|
4957
4971
|
const skipAttrs = new AttrList(value1, level);
|
4958
4972
|
const skippedSegments = skipAttrs.decimalInteger('SKIPPED-SEGMENTS');
|
@@ -4971,15 +4985,23 @@ class M3U8Parser {
|
|
4971
4985
|
break;
|
4972
4986
|
}
|
4973
4987
|
case 'TARGETDURATION':
|
4988
|
+
if (level.targetduration !== 0) {
|
4989
|
+
assignMultipleMediaPlaylistTagOccuranceError(level, tag, result);
|
4990
|
+
}
|
4974
4991
|
level.targetduration = Math.max(parseInt(value1), 1);
|
4975
4992
|
break;
|
4976
4993
|
case 'VERSION':
|
4994
|
+
if (level.version !== null) {
|
4995
|
+
assignMultipleMediaPlaylistTagOccuranceError(level, tag, result);
|
4996
|
+
}
|
4977
4997
|
level.version = parseInt(value1);
|
4978
4998
|
break;
|
4979
4999
|
case 'INDEPENDENT-SEGMENTS':
|
4980
|
-
case 'EXTM3U':
|
4981
5000
|
break;
|
4982
5001
|
case 'ENDLIST':
|
5002
|
+
if (!level.live) {
|
5003
|
+
assignMultipleMediaPlaylistTagOccuranceError(level, tag, result);
|
5004
|
+
}
|
4983
5005
|
level.live = false;
|
4984
5006
|
break;
|
4985
5007
|
case '#':
|
@@ -5023,6 +5045,11 @@ class M3U8Parser {
|
|
5023
5045
|
break;
|
5024
5046
|
}
|
5025
5047
|
case 'DISCONTINUITY-SEQUENCE':
|
5048
|
+
if (level.startCC !== 0) {
|
5049
|
+
assignMultipleMediaPlaylistTagOccuranceError(level, tag, result);
|
5050
|
+
} else if (fragments.length > 0) {
|
5051
|
+
assignMustAppearBeforeSegmentsError(level, tag, result);
|
5052
|
+
}
|
5026
5053
|
level.startCC = discontinuityCounter = parseInt(value1);
|
5027
5054
|
break;
|
5028
5055
|
case 'KEY':
|
@@ -5081,7 +5108,10 @@ class M3U8Parser {
|
|
5081
5108
|
}
|
5082
5109
|
case 'SERVER-CONTROL':
|
5083
5110
|
{
|
5084
|
-
|
5111
|
+
if (serverControlAttrs) {
|
5112
|
+
assignMultipleMediaPlaylistTagOccuranceError(level, tag, result);
|
5113
|
+
}
|
5114
|
+
serverControlAttrs = new AttrList(value1);
|
5085
5115
|
level.canBlockReload = serverControlAttrs.bool('CAN-BLOCK-RELOAD');
|
5086
5116
|
level.canSkipUntil = serverControlAttrs.optionalFloat('CAN-SKIP-UNTIL', 0);
|
5087
5117
|
level.canSkipDateRanges = level.canSkipUntil > 0 && serverControlAttrs.bool('CAN-SKIP-DATERANGES');
|
@@ -5091,6 +5121,9 @@ class M3U8Parser {
|
|
5091
5121
|
}
|
5092
5122
|
case 'PART-INF':
|
5093
5123
|
{
|
5124
|
+
if (level.partTarget) {
|
5125
|
+
assignMultipleMediaPlaylistTagOccuranceError(level, tag, result);
|
5126
|
+
}
|
5094
5127
|
const partInfAttrs = new AttrList(value1);
|
5095
5128
|
level.partTarget = partInfAttrs.decimalFloatingPoint('PART-TARGET');
|
5096
5129
|
break;
|
@@ -5142,6 +5175,9 @@ class M3U8Parser {
|
|
5142
5175
|
setFragLevelKeys(frag, levelkeys, level);
|
5143
5176
|
}
|
5144
5177
|
}
|
5178
|
+
if (!level.targetduration) {
|
5179
|
+
level.playlistParsingError = new Error(`#EXT-X-TARGETDURATION is required`);
|
5180
|
+
}
|
5145
5181
|
const fragmentLength = fragments.length;
|
5146
5182
|
const firstFragment = fragments[0];
|
5147
5183
|
const lastFragment = fragments[fragmentLength - 1];
|
@@ -5319,6 +5355,12 @@ function setFragLevelKeys(frag, levelkeys, level) {
|
|
5319
5355
|
encryptedFragments.push(frag);
|
5320
5356
|
}
|
5321
5357
|
}
|
5358
|
+
function assignMultipleMediaPlaylistTagOccuranceError(level, tag, result) {
|
5359
|
+
level.playlistParsingError = new Error(`#EXT-X-${tag} must not appear more than once (${result[0]})`);
|
5360
|
+
}
|
5361
|
+
function assignMustAppearBeforeSegmentsError(level, tag, result) {
|
5362
|
+
level.playlistParsingError = new Error(`#EXT-X-${tag} must appear before the first Media Segment (${result[0]})`);
|
5363
|
+
}
|
5322
5364
|
|
5323
5365
|
function updateFromToPTS(fragFrom, fragTo) {
|
5324
5366
|
const fragToPTS = fragTo.startPTS;
|
@@ -5606,9 +5648,24 @@ function mapFragmentIntersection(oldDetails, newDetails, intersectionFn) {
|
|
5606
5648
|
}
|
5607
5649
|
if (oldFrag && newFrag) {
|
5608
5650
|
intersectionFn(oldFrag, newFrag, i, newFrags);
|
5651
|
+
if (oldFrag.url && oldFrag.url !== newFrag.url) {
|
5652
|
+
newDetails.playlistParsingError = getSequenceError(`media sequence mismatch ${newFrag.sn}:`, oldDetails, newDetails, oldFrag, newFrag);
|
5653
|
+
return;
|
5654
|
+
} else if (oldFrag.cc !== newFrag.cc) {
|
5655
|
+
newDetails.playlistParsingError = getSequenceError(`discontinuity sequence mismatch (${oldFrag.cc}!=${newFrag.cc})`, oldDetails, newDetails, oldFrag, newFrag);
|
5656
|
+
return;
|
5657
|
+
}
|
5609
5658
|
}
|
5610
5659
|
}
|
5611
5660
|
}
|
5661
|
+
function getSequenceError(message, oldDetails, newDetails, oldFrag, newFrag) {
|
5662
|
+
return new Error(`${message} ${newFrag.url}
|
5663
|
+
Playlist starting @${oldDetails.startSN}
|
5664
|
+
${oldDetails.m3u8}
|
5665
|
+
|
5666
|
+
Playlist starting @${newDetails.startSN}
|
5667
|
+
${newDetails.m3u8}`);
|
5668
|
+
}
|
5612
5669
|
function adjustSliding(oldDetails, newDetails, matchingStableVariantOrRendition = true) {
|
5613
5670
|
const delta = newDetails.startSN + newDetails.skippedSegments - oldDetails.startSN;
|
5614
5671
|
const oldFragments = oldDetails.fragments;
|
@@ -5821,6 +5878,31 @@ class BasePlaylistController extends Logger {
|
|
5821
5878
|
// Merge live playlists to adjust fragment starts and fill in delta playlist skipped segments
|
5822
5879
|
if (previousDetails && details.fragments.length > 0) {
|
5823
5880
|
mergeDetails(previousDetails, details);
|
5881
|
+
const error = details.playlistParsingError;
|
5882
|
+
if (error) {
|
5883
|
+
this.warn(error);
|
5884
|
+
const hls = this.hls;
|
5885
|
+
if (!hls.config.ignorePlaylistParsingErrors) {
|
5886
|
+
var _details$fragments$;
|
5887
|
+
const {
|
5888
|
+
networkDetails
|
5889
|
+
} = data;
|
5890
|
+
hls.trigger(Events.ERROR, {
|
5891
|
+
type: ErrorTypes.NETWORK_ERROR,
|
5892
|
+
details: ErrorDetails.LEVEL_PARSING_ERROR,
|
5893
|
+
fatal: false,
|
5894
|
+
url: details.url,
|
5895
|
+
error,
|
5896
|
+
reason: error.message,
|
5897
|
+
level: data.level || undefined,
|
5898
|
+
parent: (_details$fragments$ = details.fragments[0]) == null ? void 0 : _details$fragments$.type,
|
5899
|
+
networkDetails,
|
5900
|
+
stats
|
5901
|
+
});
|
5902
|
+
return;
|
5903
|
+
}
|
5904
|
+
details.playlistParsingError = null;
|
5905
|
+
}
|
5824
5906
|
}
|
5825
5907
|
if (details.requestScheduled === -1) {
|
5826
5908
|
details.requestScheduled = stats.loading.start;
|
@@ -17380,6 +17462,7 @@ const hlsDefaultConfig = _objectSpread2(_objectSpread2({
|
|
17380
17462
|
// used by fps-controller
|
17381
17463
|
appendErrorMaxRetry: 3,
|
17382
17464
|
// used by buffer-controller
|
17465
|
+
ignorePlaylistParsingErrors: false,
|
17383
17466
|
loader: XhrLoader,
|
17384
17467
|
// loader: FetchLoader,
|
17385
17468
|
fLoader: undefined,
|
@@ -19524,7 +19607,7 @@ function assignTrackIdsByGroup(tracks) {
|
|
19524
19607
|
});
|
19525
19608
|
}
|
19526
19609
|
|
19527
|
-
const version = "1.6.0-rc.1.0.canary.
|
19610
|
+
const version = "1.6.0-rc.1.0.canary.11074";
|
19528
19611
|
|
19529
19612
|
// ensure the worker ends up in the bundle
|
19530
19613
|
// If the worker should not be included this gets aliased to empty.js
|
@@ -21944,21 +22027,25 @@ class PlaylistLoader {
|
|
21944
22027
|
}
|
21945
22028
|
const error = levelDetails.playlistParsingError;
|
21946
22029
|
if (error) {
|
21947
|
-
hls.
|
21948
|
-
|
21949
|
-
|
21950
|
-
|
21951
|
-
|
21952
|
-
|
21953
|
-
|
21954
|
-
|
21955
|
-
|
21956
|
-
|
21957
|
-
|
21958
|
-
|
21959
|
-
|
21960
|
-
|
21961
|
-
|
22030
|
+
this.hls.logger.warn(error);
|
22031
|
+
if (!hls.config.ignorePlaylistParsingErrors) {
|
22032
|
+
hls.trigger(Events.ERROR, {
|
22033
|
+
type: ErrorTypes.NETWORK_ERROR,
|
22034
|
+
details: ErrorDetails.LEVEL_PARSING_ERROR,
|
22035
|
+
fatal: false,
|
22036
|
+
url,
|
22037
|
+
error,
|
22038
|
+
reason: error.message,
|
22039
|
+
response,
|
22040
|
+
context,
|
22041
|
+
level: levelIndex,
|
22042
|
+
parent,
|
22043
|
+
networkDetails,
|
22044
|
+
stats
|
22045
|
+
});
|
22046
|
+
return;
|
22047
|
+
}
|
22048
|
+
levelDetails.playlistParsingError = null;
|
21962
22049
|
}
|
21963
22050
|
if (levelDetails.live && loader) {
|
21964
22051
|
if (loader.getCacheAge) {
|