hls-parser
Version:
A simple library to read/write HLS playlists
1,313 lines (1,304 loc) • 118 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["HLS"] = factory();
else
root["HLS"] = factory();
})(self, () => {
return /******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./index.ts":
/*!******************!*\
!*** ./index.ts ***!
\******************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.setOptions = exports.getOptions = exports.types = exports.stringify = exports.parse = void 0;
/*! Copyright Kuu Miyazaki. SPDX-License-Identifier: MIT */
const utils_1 = __webpack_require__(/*! ./utils */ "./utils.js");
Object.defineProperty(exports, "getOptions", ({ enumerable: true, get: function () { return utils_1.getOptions; } }));
Object.defineProperty(exports, "setOptions", ({ enumerable: true, get: function () { return utils_1.setOptions; } }));
const parse_1 = __importDefault(__webpack_require__(/*! ./parse */ "./parse.js"));
exports.parse = parse_1.default;
const stringify_1 = __importDefault(__webpack_require__(/*! ./stringify */ "./stringify.js"));
exports.stringify = stringify_1.default;
const types = __importStar(__webpack_require__(/*! ./types */ "./types.js"));
exports.types = types;
/***/ }),
/***/ "./parse.js":
/*!******************!*\
!*** ./parse.js ***!
\******************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
var __createBinding = this && this.__createBinding || (Object.create ? function (o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = {
enumerable: true,
get: function get() {
return m[k];
}
};
}
Object.defineProperty(o, k2, desc);
} : function (o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
});
var __setModuleDefault = this && this.__setModuleDefault || (Object.create ? function (o, v) {
Object.defineProperty(o, "default", {
enumerable: true,
value: v
});
} : function (o, v) {
o["default"] = v;
});
var __importStar = this && this.__importStar || function () {
var _ownKeys = function ownKeys(o) {
_ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return _ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = _ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
}();
Object.defineProperty(exports, "__esModule", ({
value: true
}));
var utils = __importStar(__webpack_require__(/*! ./utils */ "./utils.js"));
var types_1 = __webpack_require__(/*! ./types */ "./types.js");
function unquote(str) {
return utils.trim(str, '"');
}
function getTagCategory(tagName) {
switch (tagName) {
case 'EXTM3U':
case 'EXT-X-VERSION':
case 'EXT-X-CONTENT-STEERING':
return 'Basic';
case 'EXTINF':
case 'EXT-X-BYTERANGE':
case 'EXT-X-DISCONTINUITY':
case 'EXT-X-PREFETCH-DISCONTINUITY':
case 'EXT-X-KEY':
case 'EXT-X-MAP':
case 'EXT-X-PROGRAM-DATE-TIME':
case 'EXT-X-DATERANGE':
case 'EXT-X-CUE-OUT':
case 'EXT-X-CUE-IN':
case 'EXT-X-CUE-OUT-CONT':
case 'EXT-X-CUE':
case 'EXT-OATCLS-SCTE35':
case 'EXT-X-ASSET':
case 'EXT-X-SCTE35':
case 'EXT-X-PART':
case 'EXT-X-PRELOAD-HINT':
case 'EXT-X-GAP':
return 'Segment';
case 'EXT-X-TARGETDURATION':
case 'EXT-X-MEDIA-SEQUENCE':
case 'EXT-X-DISCONTINUITY-SEQUENCE':
case 'EXT-X-ENDLIST':
case 'EXT-X-PLAYLIST-TYPE':
case 'EXT-X-I-FRAMES-ONLY':
case 'EXT-X-SERVER-CONTROL':
case 'EXT-X-PART-INF':
case 'EXT-X-PREFETCH':
case 'EXT-X-RENDITION-REPORT':
case 'EXT-X-SKIP':
return 'MediaPlaylist';
case 'EXT-X-MEDIA':
case 'EXT-X-STREAM-INF':
case 'EXT-X-I-FRAME-STREAM-INF':
case 'EXT-X-SESSION-DATA':
case 'EXT-X-SESSION-KEY':
return 'MasterPlaylist';
case 'EXT-X-INDEPENDENT-SEGMENTS':
case 'EXT-X-START':
return 'MediaorMasterPlaylist';
default:
return 'Unknown';
}
}
function parseEXTINF(param) {
var pair = utils.splitAt(param, ',');
return {
duration: utils.toNumber(pair[0]),
title: decodeURIComponent(escape(pair[1]))
};
}
function parseBYTERANGE(param) {
var pair = utils.splitAt(param, '@');
return {
length: utils.toNumber(pair[0]),
offset: pair[1] ? utils.toNumber(pair[1]) : -1
};
}
function parseResolution(str) {
var pair = utils.splitAt(str, 'x');
return {
width: utils.toNumber(pair[0]),
height: utils.toNumber(pair[1])
};
}
function parseAllowedCpc(str) {
var message = 'ALLOWED-CPC: Each entry must consit of KEYFORMAT and Content Protection Configuration';
var list = str.split(',');
if (list.length === 0) {
utils.INVALIDPLAYLIST(message);
}
var allowedCpcList = [];
var _iterator = _createForOfIteratorHelper(list),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var item = _step.value;
var _utils$splitAt = utils.splitAt(item, ':'),
_utils$splitAt2 = _slicedToArray(_utils$splitAt, 2),
format = _utils$splitAt2[0],
cpcText = _utils$splitAt2[1];
if (!format || !cpcText) {
utils.INVALIDPLAYLIST(message);
continue;
}
allowedCpcList.push({
format: format,
cpcList: cpcText.split('/')
});
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return allowedCpcList;
}
function parseIV(str) {
var iv = utils.hexToByteSequence(str);
if (iv.length !== 16) {
utils.INVALIDPLAYLIST('IV must be a 128-bit unsigned integer');
}
return iv;
}
function parseUserAttribute(str) {
if (str.startsWith('"')) {
return unquote(str);
}
if (str.startsWith('0x') || str.startsWith('0X')) {
return utils.hexToByteSequence(str);
}
return utils.toNumber(str);
}
function setCompatibleVersionOfKey(params, attributes) {
if (attributes['IV'] && params.compatibleVersion < 2) {
params.compatibleVersion = 2;
}
if ((attributes['KEYFORMAT'] || attributes['KEYFORMATVERSIONS']) && params.compatibleVersion < 5) {
params.compatibleVersion = 5;
}
}
function parseAttributeList(param) {
var attributes = {};
var _iterator2 = _createForOfIteratorHelper(utils.splitByCommaWithPreservingQuotes(param)),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var item = _step2.value;
var _utils$splitAt3 = utils.splitAt(item, '='),
_utils$splitAt4 = _slicedToArray(_utils$splitAt3, 2),
key = _utils$splitAt4[0],
value = _utils$splitAt4[1];
var val = unquote(value);
switch (key) {
case 'URI':
attributes[key] = val;
break;
case 'START-DATE':
case 'END-DATE':
attributes[key] = new Date(val);
break;
case 'IV':
attributes[key] = parseIV(val);
break;
case 'BYTERANGE':
attributes[key] = parseBYTERANGE(val);
break;
case 'RESOLUTION':
attributes[key] = parseResolution(val);
break;
case 'ALLOWED-CPC':
attributes[key] = parseAllowedCpc(val);
break;
case 'END-ON-NEXT':
case 'DEFAULT':
case 'AUTOSELECT':
case 'FORCED':
case 'PRECISE':
case 'CAN-BLOCK-RELOAD':
case 'INDEPENDENT':
case 'GAP':
attributes[key] = val === 'YES';
break;
case 'DURATION':
case 'PLANNED-DURATION':
case 'BANDWIDTH':
case 'AVERAGE-BANDWIDTH':
case 'FRAME-RATE':
case 'TIME-OFFSET':
case 'CAN-SKIP-UNTIL':
case 'HOLD-BACK':
case 'PART-HOLD-BACK':
case 'PART-TARGET':
case 'BYTERANGE-START':
case 'BYTERANGE-LENGTH':
case 'LAST-MSN':
case 'LAST-PART':
case 'SKIPPED-SEGMENTS':
case 'SCORE':
case 'PROGRAM-ID':
attributes[key] = utils.toNumber(val);
break;
default:
if (key.startsWith('SCTE35-')) {
attributes[key] = utils.hexToByteSequence(val);
} else if (key.startsWith('X-')) {
attributes[key] = parseUserAttribute(value);
} else {
if (key === 'VIDEO-RANGE' && val !== 'SDR' && val !== 'HLG' && val !== 'PQ') {
utils.INVALIDPLAYLIST("VIDEO-RANGE: unknown value \"".concat(val, "\""));
}
attributes[key] = val;
}
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return attributes;
}
function parseTagParam(name, param) {
switch (name) {
case 'EXTM3U':
case 'EXT-X-DISCONTINUITY':
case 'EXT-X-ENDLIST':
case 'EXT-X-I-FRAMES-ONLY':
case 'EXT-X-INDEPENDENT-SEGMENTS':
case 'EXT-X-CUE-IN':
case 'EXT-X-GAP':
return [null, null];
case 'EXT-X-VERSION':
case 'EXT-X-TARGETDURATION':
case 'EXT-X-MEDIA-SEQUENCE':
case 'EXT-X-DISCONTINUITY-SEQUENCE':
return [utils.toNumber(param), null];
case 'EXT-X-CUE-OUT':
// For backwards compatibility: attributes list is optional,
// if only a number is found, use it as the duration
if (!Number.isNaN(Number(param))) {
return [utils.toNumber(param), null];
}
// If attributes are found, parse them out (i.e. DURATION)
return [null, parseAttributeList(param)];
case 'EXT-X-KEY':
case 'EXT-X-MAP':
case 'EXT-X-DATERANGE':
case 'EXT-X-MEDIA':
case 'EXT-X-STREAM-INF':
case 'EXT-X-I-FRAME-STREAM-INF':
case 'EXT-X-SESSION-DATA':
case 'EXT-X-SESSION-KEY':
case 'EXT-X-START':
case 'EXT-X-SERVER-CONTROL':
case 'EXT-X-PART-INF':
case 'EXT-X-PART':
case 'EXT-X-PRELOAD-HINT':
case 'EXT-X-RENDITION-REPORT':
case 'EXT-X-SKIP':
return [null, parseAttributeList(param)];
case 'EXTINF':
return [parseEXTINF(param), null];
case 'EXT-X-BYTERANGE':
return [parseBYTERANGE(param), null];
case 'EXT-X-PROGRAM-DATE-TIME':
return [new Date(param), null];
case 'EXT-X-PLAYLIST-TYPE':
return [param, null];
// <EVENT|VOD>
default:
return [param, null];
// Unknown tag
}
}
function MIXEDTAGS() {
utils.INVALIDPLAYLIST("The file contains both media and master playlist tags.");
}
function splitTag(line) {
var index = line.indexOf(':');
if (index === -1) {
return [line.slice(1).trim(), null];
}
return [line.slice(1, index).trim(), line.slice(index + 1).trim()];
}
function parseRendition(_ref) {
var attributes = _ref.attributes;
var rendition = new types_1.Rendition({
type: attributes['TYPE'],
uri: attributes['URI'],
groupId: attributes['GROUP-ID'],
language: attributes['LANGUAGE'],
assocLanguage: attributes['ASSOC-LANGUAGE'],
name: attributes['NAME'],
isDefault: attributes['DEFAULT'],
autoselect: attributes['AUTOSELECT'],
forced: attributes['FORCED'],
instreamId: attributes['INSTREAM-ID'],
characteristics: attributes['CHARACTERISTICS'],
channels: attributes['CHANNELS'],
pathwayId: attributes['PATHWAY-ID']
});
return rendition;
}
function checkRedundantRendition(renditions, rendition) {
var defaultFound = false;
var _iterator3 = _createForOfIteratorHelper(renditions),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var item = _step3.value;
if (item.name === rendition.name) {
return 'All EXT-X-MEDIA tags in the same Group MUST have different NAME attributes.';
}
if (item.isDefault) {
defaultFound = true;
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
if (defaultFound && rendition.isDefault) {
return 'EXT-X-MEDIA A Group MUST NOT have more than one member with a DEFAULT attribute of YES.';
}
return '';
}
function addRendition(variant, line, type) {
var rendition = parseRendition(line);
var renditions = variant[utils.camelify(type)];
var errorMessage = checkRedundantRendition(renditions, rendition);
if (errorMessage) {
utils.INVALIDPLAYLIST(errorMessage);
}
renditions.push(rendition);
if (rendition.isDefault) {
variant.currentRenditions[utils.camelify(type)] = renditions.length - 1;
}
}
function matchTypes(attrs, variant, params) {
var _loop = function _loop() {
var type = _arr[_i];
if (type === 'CLOSED-CAPTIONS' && attrs[type] === 'NONE') {
params.isClosedCaptionsNone = true;
variant.closedCaptions = [];
} else if (attrs[type] && !variant[utils.camelify(type)].some(function (item) {
return item.groupId === attrs[type];
})) {
utils.INVALIDPLAYLIST("".concat(type, " attribute MUST match the value of the GROUP-ID attribute of an EXT-X-MEDIA tag whose TYPE attribute is ").concat(type, "."));
}
};
for (var _i = 0, _arr = ['AUDIO', 'VIDEO', 'SUBTITLES', 'CLOSED-CAPTIONS']; _i < _arr.length; _i++) {
_loop();
}
}
function parseVariant(lines, variantAttrs, uri, iFrameOnly, params) {
var variant = new types_1.Variant({
uri: uri,
bandwidth: variantAttrs['BANDWIDTH'],
averageBandwidth: variantAttrs['AVERAGE-BANDWIDTH'],
score: variantAttrs['SCORE'],
codecs: variantAttrs['CODECS'],
resolution: variantAttrs['RESOLUTION'],
frameRate: variantAttrs['FRAME-RATE'],
hdcpLevel: variantAttrs['HDCP-LEVEL'],
allowedCpc: variantAttrs['ALLOWED-CPC'],
videoRange: variantAttrs['VIDEO-RANGE'],
stableVariantId: variantAttrs['STABLE-VARIANT-ID'],
pathwayId: variantAttrs['STABLE-PATHWAY-ID'],
programId: variantAttrs['PROGRAM-ID']
});
var _iterator4 = _createForOfIteratorHelper(lines),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var line = _step4.value;
if (line.name === 'EXT-X-MEDIA') {
var renditionAttrs = line.attributes;
var renditionType = renditionAttrs['TYPE'];
if (!renditionType || !renditionAttrs['GROUP-ID']) {
utils.INVALIDPLAYLIST('EXT-X-MEDIA TYPE attribute is REQUIRED.');
}
if (variantAttrs[renditionType] === renditionAttrs['GROUP-ID']) {
addRendition(variant, line, renditionType);
if (renditionType === 'CLOSED-CAPTIONS') {
var _iterator5 = _createForOfIteratorHelper(variant.closedCaptions),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var instreamId = _step5.value.instreamId;
if (instreamId && instreamId.startsWith('SERVICE') && params.compatibleVersion < 7) {
params.compatibleVersion = 7;
break;
}
}
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
}
}
}
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
matchTypes(variantAttrs, variant, params);
variant.isIFrameOnly = iFrameOnly;
return variant;
}
function sameKey(key1, key2) {
if (key1.method !== key2.method) {
return false;
}
if (key1.uri !== key2.uri) {
return false;
}
if (key1.iv) {
if (!key2.iv) {
return false;
}
if (key1.iv.byteLength !== key2.iv.byteLength) {
return false;
}
for (var i = 0; i < key1.iv.byteLength; i++) {
if (key1.iv[i] !== key2.iv[i]) {
return false;
}
}
} else if (key2.iv) {
return false;
}
if (key1.format !== key2.format) {
return false;
}
if (key1.formatVersion !== key2.formatVersion) {
return false;
}
return true;
}
function parseMasterPlaylist(lines, params) {
var playlist = new types_1.MasterPlaylist();
var variantIsScored = false;
var _iterator6 = _createForOfIteratorHelper(lines.entries()),
_step6;
try {
var _loop2 = function _loop2() {
var _step6$value = _slicedToArray(_step6.value, 2),
index = _step6$value[0],
line = _step6$value[1];
var _mapTo = mapTo(line),
name = _mapTo.name,
value = _mapTo.value,
attributes = _mapTo.attributes;
if (name === 'EXT-X-VERSION') {
playlist.version = value;
} else if (name === 'EXT-X-CONTENT-STEERING-SERVER') {
var contentSteering = new types_1.ContentSteering({
serverUri: attributes['SERVER-URI'],
pathwayId: attributes['PATHWAY-ID']
});
playlist.contentSteering = contentSteering;
} else if (name === 'EXT-X-STREAM-INF') {
var uri = lines[index + 1];
if (typeof uri !== 'string' || uri.startsWith('#EXT')) {
utils.INVALIDPLAYLIST('EXT-X-STREAM-INF must be followed by a URI line');
}
var _variant2 = parseVariant(lines, attributes, uri, false, params);
if (_variant2) {
if (typeof _variant2.score === 'number') {
variantIsScored = true;
if (_variant2.score < 0) {
utils.INVALIDPLAYLIST('SCORE attribute on EXT-X-STREAM-INF must be positive decimal-floating-point number.');
}
}
playlist.variants.push(_variant2);
}
} else if (name === 'EXT-X-I-FRAME-STREAM-INF') {
var _variant3 = parseVariant(lines, attributes, attributes.URI, true, params);
if (_variant3) {
playlist.variants.push(_variant3);
}
} else if (name === 'EXT-X-SESSION-DATA') {
var sessionData = new types_1.SessionData({
id: attributes['DATA-ID'],
value: attributes['VALUE'],
uri: attributes['URI'],
language: attributes['LANGUAGE']
});
if (playlist.sessionDataList.some(function (item) {
return item.id === sessionData.id && item.language === sessionData.language;
})) {
utils.INVALIDPLAYLIST('A Playlist MUST NOT contain more than one EXT-X-SESSION-DATA tag with the same DATA-ID attribute and the same LANGUAGE attribute.');
}
playlist.sessionDataList.push(sessionData);
} else if (name === 'EXT-X-SESSION-KEY') {
if (attributes['METHOD'] === 'NONE') {
utils.INVALIDPLAYLIST('EXT-X-SESSION-KEY: The value of the METHOD attribute MUST NOT be NONE');
}
var sessionKey = new types_1.Key({
method: attributes['METHOD'],
uri: attributes['URI'],
iv: attributes['IV'],
format: attributes['KEYFORMAT'],
formatVersion: attributes['KEYFORMATVERSIONS']
});
if (playlist.sessionKeyList.some(function (item) {
return sameKey(item, sessionKey);
})) {
utils.INVALIDPLAYLIST('A Master Playlist MUST NOT contain more than one EXT-X-SESSION-KEY tag with the same METHOD, URI, IV, KEYFORMAT, and KEYFORMATVERSIONS attribute values.');
}
setCompatibleVersionOfKey(params, attributes);
playlist.sessionKeyList.push(sessionKey);
} else if (name === 'EXT-X-INDEPENDENT-SEGMENTS') {
if (playlist.independentSegments) {
utils.INVALIDPLAYLIST('EXT-X-INDEPENDENT-SEGMENTS tag MUST NOT appear more than once in a Playlist');
}
playlist.independentSegments = true;
} else if (name === 'EXT-X-START') {
if (playlist.start) {
utils.INVALIDPLAYLIST('EXT-X-START tag MUST NOT appear more than once in a Playlist');
}
if (typeof attributes['TIME-OFFSET'] !== 'number') {
utils.INVALIDPLAYLIST('EXT-X-START: TIME-OFFSET attribute is REQUIRED');
}
playlist.start = {
offset: attributes['TIME-OFFSET'],
precise: attributes['PRECISE'] || false
};
}
};
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
_loop2();
}
} catch (err) {
_iterator6.e(err);
} finally {
_iterator6.f();
}
if (variantIsScored) {
var _iterator7 = _createForOfIteratorHelper(playlist.variants),
_step7;
try {
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
var variant = _step7.value;
if (typeof variant.score !== 'number') {
utils.INVALIDPLAYLIST('If any Variant Stream contains the SCORE attribute, then all Variant Streams in the Master Playlist SHOULD have a SCORE attribute');
}
}
} catch (err) {
_iterator7.e(err);
} finally {
_iterator7.f();
}
}
if (params.isClosedCaptionsNone) {
var _iterator8 = _createForOfIteratorHelper(playlist.variants),
_step8;
try {
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
var _variant = _step8.value;
if (_variant.closedCaptions.length > 0) {
utils.INVALIDPLAYLIST('If there is a variant with CLOSED-CAPTIONS attribute of NONE, all EXT-X-STREAM-INF tags MUST have this attribute with a value of NONE');
}
}
} catch (err) {
_iterator8.e(err);
} finally {
_iterator8.f();
}
}
return playlist;
}
function parseSegment(lines, uri, start, end, mediaSequenceNumber, discontinuitySequence, params) {
var segment = new types_1.Segment({
uri: uri,
mediaSequenceNumber: mediaSequenceNumber,
discontinuitySequence: discontinuitySequence
});
var mapHint = false;
var partHint = false;
for (var i = start; i <= end; i++) {
var _mapTo2 = mapTo(lines[i]),
name = _mapTo2.name,
value = _mapTo2.value,
attributes = _mapTo2.attributes;
if (name === 'EXTINF') {
if (!Number.isInteger(value.duration) && params.compatibleVersion < 3) {
params.compatibleVersion = 3;
}
if (Math.round(value.duration) > params.targetDuration) {
utils.INVALIDPLAYLIST('EXTINF duration, when rounded to the nearest integer, MUST be less than or equal to the target duration');
}
segment.duration = value.duration;
segment.title = value.title;
} else if (name === 'EXT-X-BYTERANGE') {
if (params.compatibleVersion < 4) {
params.compatibleVersion = 4;
}
segment.byterange = value;
} else if (name === 'EXT-X-DISCONTINUITY') {
if (segment.parts.length > 0) {
utils.INVALIDPLAYLIST('EXT-X-DISCONTINUITY must appear before the first EXT-X-PART tag of the Parent Segment.');
}
segment.discontinuity = true;
} else if (name === 'EXT-X-GAP') {
if (params.compatibleVersion < 8) {
params.compatibleVersion = 8;
}
segment.gap = true;
} else if (name === 'EXT-X-KEY') {
if (segment.parts.length > 0) {
utils.INVALIDPLAYLIST('EXT-X-KEY must appear before the first EXT-X-PART tag of the Parent Segment.');
}
setCompatibleVersionOfKey(params, attributes);
segment.key = new types_1.Key({
method: attributes['METHOD'],
uri: attributes['URI'],
iv: attributes['IV'],
format: attributes['KEYFORMAT'],
formatVersion: attributes['KEYFORMATVERSIONS']
});
} else if (name === 'EXT-X-MAP') {
if (segment.parts.length > 0) {
utils.INVALIDPLAYLIST('EXT-X-MAP must appear before the first EXT-X-PART tag of the Parent Segment.');
}
if (params.compatibleVersion < 5) {
params.compatibleVersion = 5;
}
params.hasMap = true;
segment.map = new types_1.MediaInitializationSection({
uri: attributes['URI'],
byterange: attributes['BYTERANGE']
});
} else if (name === 'EXT-X-PROGRAM-DATE-TIME') {
segment.programDateTime = value;
} else if (name === 'EXT-X-DATERANGE') {
var attrs = {};
for (var _i2 = 0, _Object$keys = Object.keys(attributes); _i2 < _Object$keys.length; _i2++) {
var key = _Object$keys[_i2];
if (key.startsWith('SCTE35-') || key.startsWith('X-')) {
attrs[key] = attributes[key];
}
}
segment.dateRange = new types_1.DateRange({
id: attributes['ID'],
classId: attributes['CLASS'],
start: attributes['START-DATE'],
end: attributes['END-DATE'],
duration: attributes['DURATION'],
plannedDuration: attributes['PLANNED-DURATION'],
endOnNext: attributes['END-ON-NEXT'],
attributes: attrs
});
} else if (name === 'EXT-X-CUE-OUT') {
segment.markers.push(new types_1.SpliceInfo({
type: 'OUT',
duration: attributes && attributes.DURATION || value
}));
} else if (name === 'EXT-X-CUE-IN') {
segment.markers.push(new types_1.SpliceInfo({
type: 'IN'
}));
} else if (name === 'EXT-X-CUE-OUT-CONT' || name === 'EXT-X-CUE' || name === 'EXT-OATCLS-SCTE35' || name === 'EXT-X-ASSET' || name === 'EXT-X-SCTE35') {
segment.markers.push(new types_1.SpliceInfo({
type: 'RAW',
tagName: name,
value: value
}));
} else if (name === 'EXT-X-PRELOAD-HINT' && !attributes['TYPE']) {
utils.INVALIDPLAYLIST('EXT-X-PRELOAD-HINT: TYPE attribute is mandatory');
} else if (name === 'EXT-X-PRELOAD-HINT' && attributes['TYPE'] === 'PART' && partHint) {
utils.INVALIDPLAYLIST('Servers should not add more than one EXT-X-PRELOAD-HINT tag with the same TYPE attribute to a Playlist.');
} else if ((name === 'EXT-X-PART' || name === 'EXT-X-PRELOAD-HINT') && !attributes['URI']) {
utils.INVALIDPLAYLIST('EXT-X-PART / EXT-X-PRELOAD-HINT: URI attribute is mandatory');
} else if (name === 'EXT-X-PRELOAD-HINT' && attributes['TYPE'] === 'MAP') {
if (mapHint) {
utils.INVALIDPLAYLIST('Servers should not add more than one EXT-X-PRELOAD-HINT tag with the same TYPE attribute to a Playlist.');
}
mapHint = true;
params.hasMap = true;
segment.map = new types_1.MediaInitializationSection({
hint: true,
uri: attributes['URI'],
byterange: {
length: attributes['BYTERANGE-LENGTH'],
offset: attributes['BYTERANGE-START'] || 0
}
});
} else if (name === 'EXT-X-PART' || name === 'EXT-X-PRELOAD-HINT' && attributes['TYPE'] === 'PART') {
if (name === 'EXT-X-PART' && !attributes['DURATION']) {
utils.INVALIDPLAYLIST('EXT-X-PART: DURATION attribute is mandatory');
}
if (name === 'EXT-X-PRELOAD-HINT') {
partHint = true;
}
var partialSegment = new types_1.PartialSegment({
hint: name === 'EXT-X-PRELOAD-HINT',
uri: attributes['URI'],
byterange: name === 'EXT-X-PART' ? attributes['BYTERANGE'] : {
length: attributes['BYTERANGE-LENGTH'],
offset: attributes['BYTERANGE-START'] || 0
},
duration: attributes['DURATION'],
independent: attributes['INDEPENDENT'],
gap: attributes['GAP']
});
if (segment.gap && !partialSegment.gap) {
// https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-6.2.1
utils.INVALIDPLAYLIST('Partial segments must have GAP=YES if they are in a gap (EXT-X-GAP)');
}
segment.parts.push(partialSegment);
}
}
return segment;
}
function parsePrefetchSegment(lines, uri, start, end, mediaSequenceNumber, discontinuitySequence, params) {
var segment = new types_1.PrefetchSegment({
uri: uri,
mediaSequenceNumber: mediaSequenceNumber,
discontinuitySequence: discontinuitySequence
});
for (var i = start; i <= end; i++) {
var _lines$i = lines[i],
name = _lines$i.name,
attributes = _lines$i.attributes;
if (name === 'EXTINF') {
utils.INVALIDPLAYLIST('A prefetch segment must not be advertised with an EXTINF tag.');
} else if (name === 'EXT-X-DISCONTINUITY') {
utils.INVALIDPLAYLIST('A prefetch segment must not be advertised with an EXT-X-DISCONTINUITY tag.');
} else if (name === 'EXT-X-PREFETCH-DISCONTINUITY') {
segment.discontinuity = true;
} else if (name === 'EXT-X-KEY') {
setCompatibleVersionOfKey(params, attributes);
segment.key = new types_1.Key({
method: attributes['METHOD'],
uri: attributes['URI'],
iv: attributes['IV'],
format: attributes['KEYFORMAT'],
formatVersion: attributes['KEYFORMATVERSIONS']
});
} else if (name === 'EXT-X-MAP') {
utils.INVALIDPLAYLIST('Prefetch segments must not be advertised with an EXT-X-MAP tag.');
}
}
return segment;
}
function parseMediaPlaylist(lines, params) {
var playlist = new types_1.MediaPlaylist();
var segmentStart = -1;
var mediaSequence = 0;
var discontinuityFound = false;
var prefetchFound = false;
var discontinuitySequence = 0;
var currentKey = null;
var currentMap = null;
var containsParts = false;
var _iterator9 = _createForOfIteratorHelper(lines.entries()),
_step9;
try {
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
var _step9$value = _slicedToArray(_step9.value, 2),
index = _step9$value[0],
line = _step9$value[1];
var _mapTo3 = mapTo(line),
name = _mapTo3.name,
value = _mapTo3.value,
attributes = _mapTo3.attributes,
category = _mapTo3.category;
if (category === 'Segment') {
if (segmentStart === -1) {
segmentStart = index;
}
if (name === 'EXT-X-DISCONTINUITY') {
discontinuityFound = true;
}
continue;
}
if (name === 'EXT-X-VERSION') {
if (playlist.version === undefined) {
playlist.version = value;
} else {
utils.INVALIDPLAYLIST('A Playlist file MUST NOT contain more than one EXT-X-VERSION tag.');
}
} else if (name === 'EXT-X-TARGETDURATION') {
playlist.targetDuration = params.targetDuration = value;
} else if (name === 'EXT-X-MEDIA-SEQUENCE') {
if (playlist.segments.length > 0) {
utils.INVALIDPLAYLIST('The EXT-X-MEDIA-SEQUENCE tag MUST appear before the first Media Segment in the Playlist.');
}
playlist.mediaSequenceBase = mediaSequence = value;
} else if (name === 'EXT-X-DISCONTINUITY-SEQUENCE') {
if (playlist.segments.length > 0) {
utils.INVALIDPLAYLIST('The EXT-X-DISCONTINUITY-SEQUENCE tag MUST appear before the first Media Segment in the Playlist.');
}
if (discontinuityFound) {
utils.INVALIDPLAYLIST('The EXT-X-DISCONTINUITY-SEQUENCE tag MUST appear before any EXT-X-DISCONTINUITY tag.');
}
playlist.discontinuitySequenceBase = discontinuitySequence = value;
} else if (name === 'EXT-X-ENDLIST') {
playlist.endlist = true;
} else if (name === 'EXT-X-PLAYLIST-TYPE') {
playlist.playlistType = value;
} else if (name === 'EXT-X-I-FRAMES-ONLY') {
if (params.compatibleVersion < 4) {
params.compatibleVersion = 4;
}
playlist.isIFrame = true;
} else if (name === 'EXT-X-INDEPENDENT-SEGMENTS') {
if (playlist.independentSegments) {
utils.INVALIDPLAYLIST('EXT-X-INDEPENDENT-SEGMENTS tag MUST NOT appear more than once in a Playlist');
}
playlist.independentSegments = true;
} else if (name === 'EXT-X-START') {
if (playlist.start) {
utils.INVALIDPLAYLIST('EXT-X-START tag MUST NOT appear more than once in a Playlist');
}
if (typeof attributes['TIME-OFFSET'] !== 'number') {
utils.INVALIDPLAYLIST('EXT-X-START: TIME-OFFSET attribute is REQUIRED');
}
playlist.start = {
offset: attributes['TIME-OFFSET'],
precise: attributes['PRECISE'] || false
};
} else if (name === 'EXT-X-SERVER-CONTROL') {
if (!attributes['CAN-BLOCK-RELOAD']) {
utils.INVALIDPLAYLIST('EXT-X-SERVER-CONTROL: CAN-BLOCK-RELOAD=YES is mandatory for Low-Latency HLS');
}
playlist.lowLatencyCompatibility = {
canBlockReload: attributes['CAN-BLOCK-RELOAD'],
canSkipUntil: attributes['CAN-SKIP-UNTIL'],
holdBack: attributes['HOLD-BACK'],
partHoldBack: attributes['PART-HOLD-BACK']
};
} else if (name === 'EXT-X-PART-INF') {
if (!attributes['PART-TARGET']) {
utils.INVALIDPLAYLIST('EXT-X-PART-INF: PART-TARGET attribute is mandatory');
}
playlist.partTargetDuration = attributes['PART-TARGET'];
} else if (name === 'EXT-X-RENDITION-REPORT') {
if (!attributes['URI']) {
utils.INVALIDPLAYLIST('EXT-X-RENDITION-REPORT: URI attribute is mandatory');
}
if (attributes['URI'].search(/^[a-z]+:/) === 0) {
utils.INVALIDPLAYLIST('EXT-X-RENDITION-REPORT: URI must be relative to the playlist uri');
}
playlist.renditionReports.push(new types_1.RenditionReport({
uri: attributes['URI'],
lastMSN: attributes['LAST-MSN'],
lastPart: attributes['LAST-PART']
}));
} else if (name === 'EXT-X-SKIP') {
if (!attributes['SKIPPED-SEGMENTS']) {
utils.INVALIDPLAYLIST('EXT-X-SKIP: SKIPPED-SEGMENTS attribute is mandatory');
}
if (params.compatibleVersion < 9) {
params.compatibleVersion = 9;
}
playlist.skip = attributes['SKIPPED-SEGMENTS'];
mediaSequence += playlist.skip;
} else if (name === 'EXT-X-PREFETCH') {
var _segment = parsePrefetchSegment(lines, value, segmentStart === -1 ? index : segmentStart, index - 1, mediaSequence++, discontinuitySequence, params);
if (_segment) {
if (_segment.discontinuity) {
_segment.discontinuitySequence++;
discontinuitySequence = _segment.discontinuitySequence;
}
if (_segment.key) {
currentKey = _segment.key;
} else {
_segment.key = currentKey;
}
playlist.prefetchSegments.push(_segment);
}
prefetchFound = true;
segmentStart = -1;
} else if (typeof line === 'string') {
// uri
if (segmentStart === -1) {
utils.INVALIDPLAYLIST('A URI line is not preceded by any segment tags');
}
if (!playlist.targetDuration) {
utils.INVALIDPLAYLIST('The EXT-X-TARGETDURATION tag is REQUIRED');
}
if (prefetchFound) {
utils.INVALIDPLAYLIST('These segments must appear after all complete segments.');
}
var _segment2 = parseSegment(lines, line, segmentStart, index - 1, mediaSequence++, discontinuitySequence, params);
if (_segment2) {
var _addSegment = addSegment(playlist, _segment2, discontinuitySequence, currentKey, currentMap);
var _addSegment2 = _slicedToArray(_addSegment, 3);
discontinuitySequence = _addSegment2[0];
currentKey = _addSegment2[1];
currentMap = _addSegment2[2];
if (!containsParts && _segment2.parts.length > 0) {
containsParts = true;
}
}
segmentStart = -1;
}
}
} catch (err) {
_iterator9.e(err);
} finally {
_iterator9.f();
}
if (segmentStart !== -1) {
var segment = parseSegment(lines, '', segmentStart, lines.length - 1, mediaSequence++, discontinuitySequence, params);
if (segment) {
var _parts$at;
var parts = segment.parts;
if (parts.length > 0 && !playlist.endlist && !((_parts$at = parts.at(-1)) !== null && _parts$at !== void 0 && _parts$at.hint)) {
utils.INVALIDPLAYLIST('If the Playlist contains EXT-X-PART tags and does not contain an EXT-X-ENDLIST tag, the Playlist must contain an EXT-X-PRELOAD-HINT tag with a TYPE=PART attribute');
}
// @ts-expect-error TODO check if this is not a bug the third argument should be a discontinuitySequence
addSegment(playlist, segment, currentKey, currentMap);
if (!containsParts && segment.parts.length > 0) {
containsParts = true;
}
}
}
checkDateRange(playlist.segments);
if (playlist.lowLatencyCompatibility) {
checkLowLatencyCompatibility(playlist, containsParts);
}
return playlist;
}
function addSegment(playlist, segment, discontinuitySequence, currentKey, currentMap) {
var discontinuity = segment.discontinuity,
key = segment.key,
map = segment.map,
byterange = segment.byterange,
uri = segment.uri;
if (discontinuity) {
segment.discontinuitySequence = discontinuitySequence + 1;
}
if (!key) {
segment.key = currentKey;
}
if (!map) {
segment.map = currentMap;
}
if (byterange && byterange.offset === -1) {
var segments = playlist.segments;
if (segments.length > 0) {
var prevSegment = segments.at(-1);
if (prevSegment.byterange && prevSegment.uri === uri) {
byterange.offset = prevSegment.byterange.offset + prevSegment.byterange.length;
} else {
utils.INVALIDPLAYLIST('If offset of EXT-X-BYTERANGE is not present, a previous Media Segment MUST be a sub-range of the same media resource');
}
} else {
utils.INVALIDPLAYLIST('If offset of EXT-X-BYTERANGE is not present, a previous Media Segment MUST appear in the Playlist file');
}
}
playlist.segments.push(segment);
return [segment.discontinuitySequence, segment.key, segment.map];
}
function checkDateRange(segments) {
var earliestDates = new Map();
var rangeList = new Map();
var hasDateRange = false;
var hasProgramDateTime = false;
for (var i = segments.length - 1; i >= 0; i--) {
var _segments$i = segments[i],
programDateTime = _segments$i.programDateTime,
dateRange = _segments$i.dateRange;
if (programDateTime) {
hasProgramDateTime = true;
}
if (dateRange && dateRange.start) {
hasDateRange = true;
if (dateRange.endOnNext && (dateRange.end || dateRange.duration)) {
utils.INVALIDPLAYLIST('An EXT-X-DATERANGE tag with an END-ON-NEXT=YES attribute MUST NOT contain DURATION or END-DATE attributes.');
}
var start = dateRange.start.getTime();
var duration = dateRange.duration || 0;
if (dateRange.end && dateRange.duration) {
if (start + duration * 1000 !== dateRange.end.getTime()) {
utils.INVALIDPLAYLIST('END-DATE MUST be equal to the value of the START-DATE attribute plus the value of the DURATION');
}
}
if (dateRange.endOnNext) {
dateRange.end = earliestDates.get(dateRange.classId);
}
earliestDates.set(dateRange.classId, dateRange.start);
var end = dateRange.end ? dateRange.end.getTime() : dateRange.start.getTime() + (dateRange.duration || 0) * 1000;
var range = rangeList.get(dateRange.classId);
if (range) {
var _iterator0 = _createForOfIteratorHelper(range),
_step0;
try {
for (_iterator0.s(); !(_step0 = _iterator0.n()).done;) {
var entry = _step0.value;
if (entry.start <= start && entry.end > start || entry.start >= start && entry.start < end) {
utils.INVALIDPLAYLIST('DATERANGE tags with the same CLASS should not overlap');
}
}
} catch (err) {
_iterator0.e(err);
} finally {
_iterator0.f();
}
range.push({
start: start,
end: end
});
} else if (dateRange.classId) {
rangeList.set(dateRange.classId, [{
start: start,
end: end
}]);
}
}
}
if (hasDateRange && !hasProgramDateTime) {
utils.INVALIDPLAYLIST('If a Playlist contains an EXT-X-DATERANGE tag, it MUST also contain at least one EXT-X-PROGRAM-DATE-TIME tag.');
}
}
function checkLowLatencyCompatibility(_ref2, containsParts) {
var lowLatencyCompatibility = _ref2.lowLatencyCompatibility,
targetDuration = _ref2.targetDuration,
partTargetDuration = _ref2.partTargetDuration,
segments = _ref2.segments,
renditionReports = _ref2.renditionReports;
var canSkipUntil = lowLatencyCompatibility.canSkipUntil,
holdBack = lowLatencyCompatibility.holdBack,
partHoldBack = lowLatencyCompatibility.partHoldBack;
if (canSkipUntil < targetDuration * 6) {
utils.INVALIDPLAYLIST('The Skip Boundary must be at least six times the EXT-X-TARGETDURATION.');
}
// Its value is a floating-point number of seconds and .
if (holdBack < targetDuration * 3) {
utils.INVALIDPLAYLIST('HOLD-BACK must be at least three times the EXT-X-TARGETDURATION.');
}
if (containsParts) {
if (partTargetDuration === undefined) {
utils.INVALIDPLAYLIST('EXT-X-PART-INF is required if a Playlist contains one or more EXT-X-PART tags');
}
if (partHoldBack === undefined) {
utils.INVALIDPLAYLIST('EXT-X-PART: PART-HOLD-BACK attribute is mandatory');
}
if (partHoldBack < partTargetDuration) {
utils.INVALIDPLAYLIST('PART-HOLD-BACK must be at least PART-TARGET');
}
var _iterator1 = _createForOfIteratorHelper(segments.entries()),
_step1;
try {
for (_iterator1.s(); !(_step1 = _iterator1.n()).done;) {
var _step1$value = _slicedToArray(_step1.value, 2),
segmentIndex = _step1$value[0],
parts = _step1$value[1].parts;
if (parts.length > 0 && segmentIndex < segments.length - 3) {
utils.INVALIDPLAYLIST('Remove EXT-X-PART tags from the Playlist after they are greater than three target durations from the end of the Playlist.');
}
var _iterator10 = _createForOfIteratorHelper(parts.entries()),
_step10;
try {
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
var _step10$value = _slicedToArray(_step10.value, 2),
partIndex = _step10$value[0],
duration = _step10$value[1].duration;
if (duration === undefined) {
continue;
}
if (duration > partTargetDuration) {
utils.INVALIDPLAYLIST('PART-TARGET is the maximum duration of any Partial Segment');
}
if (partIndex < parts.length - 1 && duration < partTargetDuration * 0.85) {
utils.INVALIDPLAYLIST('All Partial Segments except the last part of a segment must have a duration of at least 85% of PART-TARGET');
}
}
} catch (err) {
_iterator10.e(err);
} finally {
_iterator10.f();
}
}
} catch (err) {
_iterator1.e(err);
} finally {
_iterator1.f();
}
}
var _iterator11 = _createForOfIteratorHelper(renditionReports),
_step11;
try {
for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
var _report$lastMSN;
var report = _step11.value;
var lastSegment = segments.at(-1);
(_report$lastMSN = report.lastMSN) !== null && _report$lastMSN !== void 0 ? _report$lastMSN : report.lastMSN = lastSegment.mediaSequenceNumber;
if ((report.lastPart === null || report.lastPart === undefined) && lastSegment.parts.length > 0) {
report.lastPart = lastSegment.parts.length - 1;
}
}
} catch (err) {
_iterator11.e(err);
} finally {
_iterator11.f();
}
}
function CHECKTAGCATEGORY(category, params) {
if (category === 'Segment' || category === 'MediaPlaylist') {
if (params.isMasterPlaylist === undefined) {
params.isMasterPlaylist = false;
return;
}
if (params.isMasterPlaylist) {
MIXEDTAGS();
}
return;
}
if (category === 'MasterPlaylist') {
if (params.isMasterPlaylist === undefined) {
params.isMasterPlaylist = true;
return;
}
if (params.isMasterPlaylist === false) {
MIXEDTAGS();
}
}
// category === 'Basic' or 'MediaorMasterPlaylist' or 'Unknown'
}
function parseTag(line, params) {
var _splitTag = splitTag(line),
_splitTag2 = _slicedToArray(_splitTag, 2),
name = _splitTag2[0],
param = _splitTag2[1];
var category = getTagCategory(name);
CHECKTAGCATEGORY(category, params);
if (category === 'Unknown') {
return null;
}
if (category === 'MediaPlaylist' && name !== 'EXT-X-RENDITION-REPORT' && name !== 'EXT-X-PREFETCH') {
if (params.hash[name]) {
utils.INVALIDPLAYLIST('There MUST NOT be more than one Media Playlist tag of each type in any Media Playlist');
}
params.hash[name] = true;
}
var _parseTagParam = parseTagParam(name, param),
_parseTagParam2 = _slicedToArray(_parseTagParam, 2),
value = _parseTagParam2[0],
attributes = _parseTagParam2[1];
return {
name: name,
category: category,
value: value,
attributes: attributes
};
}
function lexicalParse(text, params) {
var lines = [];
var _iterator12 = _createForOfIteratorHelper(text.split('\n')),
_step12;
try {
for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
var l = _step12.value;
// V8 has garbage collection issues when cleaning up substrings split from strings greater
// than 13 characters so before we continue we need to safely copy over each line so that it
// doesn't hold any reference to the containing string.
var line = l.trim();
if (!line) {
// empty line
continue;
}
if (line.startsWith('#')) {
if (line.startsWith('#EXT')) {
// tag
var tag = parseTag(line, params);
if (tag) {
lines.push(tag);
}
}
// comment
continue;
}
// uri
lines.push(line);
}
} catch (err) {
_iterator12.e(err);
} finally {
_iterator12.f();
}
if (lines.length === 0 || lines[0].name !== 'EXTM3U')