UNPKG

@eyevinn/m3u8

Version:

streaming m3u8 parser for Apple's HTTP Live Streaming protocol

185 lines (171 loc) 5.79 kB
var AttributeList = module.exports = function AttributeList(attributes) { this.attributes = {}; this.mergeAttributes(attributes); }; var dataTypes = AttributeList.dataTypes = { 'audio' : 'quoted-string', 'autoselect' : 'boolean', 'average-bandwidth' : 'decimal-integer', 'bandwidth' : 'decimal-integer', 'byterange' : 'enumerated-string', 'codecs' : 'quoted-string', 'default' : 'boolean', 'duration' : 'decimal-floating-point', 'forced' : 'boolean', 'frame-rate' : 'decimal-floating-point', 'group-id' : 'quoted-string', 'language' : 'quoted-string', 'name' : 'quoted-string', 'program-id' : 'decimal-integer', 'resolution' : 'decimal-resolution', 'sctedata' : 'enumerated-string', 'subtitles' : 'quoted-string', 'title' : 'enumerated-string', 'type' : 'enumerated-string', 'uri' : 'quoted-string', 'video' : 'quoted-string', 'cueout' : 'decimal-floating-point', 'cuein' : 'boolean', 'cont-offset' : 'decimal-floating-point', 'cont-dur' : 'decimal-floating-point', 'assetdata' : 'quoted-string', 'daterange' : 'quoted-string-array', 'channels' : 'quoted-string', 'closed-captions' : 'closed-captions', 'key-method' : 'enumerated-string', 'key-uri' : 'quoted-string', 'key-iv' : 'hexadecimal-sequence', 'key-id' : 'hexadecimal-sequence', 'key-keyformat' : 'quoted-string', 'key-keyformatversions': 'quoted-string', 'map-uri' : 'quoted-string', 'map-byterange' : 'quoted-string', 'start-timeoffset' : 'decimal-floating-point', 'start-precise' : 'boolean', 'video-range' : 'quoted-string' }; AttributeList.prototype.mergeAttributes = function mergeAttributes(attributes) { var self = this; if (Array.isArray(attributes)) { attributes.forEach(function(attribute) { self.set(attribute.key, attribute.value); }); } }; AttributeList.prototype.get = function getValue(key) { return this.attributes[key]; }; AttributeList.prototype.set = function setValue(key, value) { key = key.toLowerCase(); this.attributes[key] = parse[dataTypes[key] || 'unknown'](value, key); return this; }; AttributeList.prototype.getCoerced = function getCoerced(key) { return coerce[dataTypes[key] || 'unknown'](this.get(key)); }; AttributeList.prototype.toString = function toString() { var self = this; return Object.keys(this.attributes).map(function(key) { return [key.toUpperCase(), self.getCoerced(key)].join('='); }).join(','); }; AttributeList.prototype.serialize = function serialize() { return this.attributes; }; AttributeList.unserialize = function unserialize(object) { var list = new AttributeList; list.attributes = object; return list; }; function coerceQuotedString(value) { return '"' + value.replace(/"/g, '\\"') + '"'; } var coerce = { 'boolean': function coerceBoolean(value) { return value ? 'YES' : 'NO'; }, 'decimal-floating-point': parseFloat, 'decimal-integer': function coerceDecimalInteger(value) { return parseInt(value, 10); }, 'decimal-resolution': function coerceDecimalResolution(value) { if (Array.isArray(value)) { return value.join('x'); } else { return value; } }, 'enumerated-string': function coerceEnumeratedString(value) { return value; }, 'quoted-string': coerceQuotedString, 'closed-captions': function closedCaptions(value) { if (value === 'NONE') { return value; } return coerceQuotedString(value); }, 'quoted-string-array': function coerceQuotedStringArray(value) { var s = value.map(function(v) { var key = Object.keys(v)[0]; return key + "=" + `"${v[key]}"`; }).join(','); return s; }, 'hexadecimal-sequence': function coerceHexadecimalSequence(value) { return value.toString('hex'); }, 'unknown': function coerceUnknown(value) { return value; } }; function parseQuotedString(value) { if (Array.isArray(value)) { return value.join(','); } else if (value.indexOf('"') === 0 && value.lastIndexOf('"') == value.length - 1) { return value.slice(1,-1); } else { return value; } } function parseAttributeStringToDict(inputString) { const data = {}; const regex = /([\w-]+)=(".*?"|[^,]+)/g; let match; while ((match = regex.exec(inputString)) !== null) { const key = match[1]; const value = match[2].replace(/^"|"$/g, ''); data[key] = value; } return data; } var parse = { 'boolean': function parseBoolean(value) { return typeof value == 'boolean' ? value : (value == 'YES' ? true : false); }, 'decimal-floating-point': parseFloat, 'decimal-integer': function parseDecimalInteger(value) { return parseInt(value, 10); }, 'decimal-resolution': function coerceDecimalResolution(value) { return value.split('x').map(parse['decimal-integer']); }, 'enumerated-string': function parseEnumeratedString(value) { return value; }, 'quoted-string': parseQuotedString, 'closed-captions': parseQuotedString, 'quoted-string-array': function parseQuotedStringArray(value) { return parseAttributeStringToDict(value); }, 'hexadecimal-sequence': function parseHexadecimalSequence(value) { return value; }, 'unknown': function parseUnknown(value, key) { console.error('Handling value:', value, ' for unknown key:', key); return value; } };