@eyevinn/m3u8
Version:
streaming m3u8 parser for Apple's HTTP Live Streaming protocol
185 lines (171 loc) • 5.79 kB
JavaScript
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;
}
};