UNPKG

1.71 kBJavaScriptView Raw
1const Writable = require('stream').Writable;
2
3
4/**
5 * A very simple m3u8 playlist file parser that detects tags and segments.
6 *
7 * @extends WritableStream
8 * @constructor
9 */
10module.exports = class m3u8Parser extends Writable {
11 constructor() {
12 super();
13 this._lastLine = '';
14 this._seq = 0;
15 this._nextItemDuration = null;
16 this.on('finish', () => {
17 this._parseLine(this._lastLine);
18 this.emit('end');
19 });
20 }
21
22 _parseLine(line) {
23 let match = line.match(/^#(EXT[A-Z0-9-]+)(?::(.*))?/);
24 if (match) {
25 // This is a tag.
26 const tag = match[1];
27 const value = match[2] || null;
28 switch (tag) {
29 case 'EXT-X-PROGRAM-DATE-TIME':
30 this.emit('starttime', new Date(value).getTime());
31 break;
32 case 'EXT-X-MEDIA-SEQUENCE':
33 this._seq = parseInt(value);
34 break;
35 case 'EXTINF':
36 this._nextItemDuration =
37 Math.round(parseFloat(value.split(',')[0]) * 1000);
38 break;
39 case 'EXT-X-ENDLIST':
40 this.emit('endlist');
41 break;
42 }
43
44 } else if (!/^#/.test(line) && line.trim()) {
45 // This is a segment
46 this.emit('item', {
47 url: line.trim(),
48 seq: this._seq++,
49 duration: this._nextItemDuration,
50 });
51 }
52 }
53
54 _write(chunk, encoding, callback) {
55 let lines = chunk.toString('utf8').split('\n');
56 if (this._lastLine) { lines[0] = this._lastLine + lines[0]; }
57 lines.forEach((line, i) => {
58 if (i < lines.length - 1) {
59 this._parseLine(line);
60 } else {
61 // Save the last line in case it has been broken up.
62 this._lastLine = line;
63 }
64 });
65 callback();
66 }
67};