m3u8 parser
Installation
npm install --save m3u8-parser
The npm installation is preferred, but Bower works, too.
bower install --save m3u8-parser
Usage
var manifest = [ '#EXTM3U', '#EXT-X-VERSION:3', '#EXT-X-TARGETDURATION:6', '#EXT-X-MEDIA-SEQUENCE:0', '#EXT-X-DISCONTINUITY-SEQUENCE:0', '#EXTINF:6,', '0.ts', '#EXTINF:6,', '1.ts', '#EXT-X-PROGRAM-DATE-TIME:2019-02-14T02:14:00.106Z' '#EXTINF:6,', '2.ts', '#EXT-X-ENDLIST' ].join('\n'); var parser = new m3u8Parser.Parser(); parser.push(manifest); parser.end(); var parsedManifest = parser.manifest;
Constructor Options
The constructor optinally takes an options object with two properties. These are needed when using #EXT-X-DEFINE for variable replacement.
var parser = new m3u8Parser.Parser({ url: 'https://exmaple.com/video.m3u8?param_a=34¶m_b=abc', mainDefinitions: { param_c: 'def' } });
options.urlstring The URL from which the playlist was fetched. If the request was redirected this should be the final URL. This is required if usingQUERYSTRINGrules with#EXT-X-DEFINE.options.mainDefinitionsobject An object of definitions from the main playlist. This is required if usingIMPORTrules with#EXT-X-DEFINE.
Parsed Output
The parser ouputs a plain javascript object with the following structure:
Manifest { allowCache: boolean, endList: boolean, mediaSequence: number, dateRanges: [], discontinuitySequence: number, playlistType: string, custom: {}, playlists: [ { attributes: {}, Manifest } ], mediaGroups: { AUDIO: { 'GROUP-ID': { NAME: { default: boolean, autoselect: boolean, language: string, uri: string, instreamId: string, characteristics: string, forced: boolean } } }, VIDEO: {}, 'CLOSED-CAPTIONS': {}, SUBTITLES: {} }, dateTimeString: string, dateTimeObject: Date, targetDuration: number, totalDuration: number, discontinuityStarts: [number], segments: [ { title: string, byterange: { length: number, offset: number }, duration: number, programDateTime: number, attributes: {}, discontinuity: number, uri: string, timeline: number, key: { method: string, uri: string, iv: string }, map: { uri: string, byterange: { length: number, offset: number } }, 'cue-out': string, 'cue-out-cont': string, 'cue-in': string, custom: {} } ] }
Supported Tags
Basic Playlist Tags
Media Segment Tags
- EXTINF
- EXT-X-BYTERANGE
- EXT-X-DISCONTINUITY
- EXT-X-KEY
- EXT-X-MAP
- EXT-X-PROGRAM-DATE-TIME
- EXT-X-DATERANGE
- EXT-X-I-FRAMES-ONLY
Media Playlist Tags
- EXT-X-TARGETDURATION
- EXT-X-MEDIA-SEQUENCE
- EXT-X-DISCONTINUITY-SEQUENCE
- EXT-X-ENDLIST
- EXT-X-PLAYLIST-TYPE
- EXT-X-START
- EXT-X-INDEPENDENT-SEGMENTS
- EXT-X-DEFINE
Main Playlist Tags
Experimental Tags
m3u8-parser supports 3 additional Media Segment Tags not present in the HLS specification.
EXT-X-CUE-OUT
The EXT-X-CUE-OUT indicates that the following media segment is a break in main content and the start of interstitial content. Its format is:
#EXT-X-CUE-OUT:<duration>
where duration is a decimal-floating-point or decimal-integer number that specifies the total duration of the interstitial in seconds.
EXT-X-CUE-OUT-CONT
The EXT-X-CUE-OUT-CONT indicates that the following media segment is a part of interstitial content and not the main content. Every media segment following a media segment with an EXT-X-CUE-OUT tag SHOULD have an EXT-X-CUE-OUT-CONT applied to it until there is an EXT-X-CUE-IN tag. A media segment between a EXT-X-CUE-OUT and EXT-X-CUE-IN segment without a EXT-X-CUE-OUT-CONT is assumed to be part of the interstitial. Its format is:
#EXT-X-CUE-OUT-CONT:<n>/<duration>
where n is a decimal-floating-point or decimal-integer number that specifies the time in seconds the first sample of the media segment lies within the interstitial content and duration is a decimal-floating-point or decimal-integer number that specifies the total duration of the interstitial in seconds. n SHOULD be the sum of EXTINF durations for all preceding media segments up to the EXT-X-CUE-OUT tag for the current interstitial. duration SHOULD match the duration specified in the EXT-X-CUE-OUT tag for the current interstitial.'
EXT-X-CUE-IN
The EXT-X-CUE-IN indicates the end of the interstitial and the return of the main content. Its format is:
There SHOULD be a closing EXT-X-CUE-IN tag for every EXT-X-CUE-OUT tag. If a second EXT-X-CUE-OUT tag is encountered before an EXT-X-CUE-IN tag, the client MAY choose to ignore the EXT-X-CUE-OUT and treat it as part of the interstitial, or reject the playlist.
Example media playlist using EXT-X-CUE- tags.
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXTINF:10,
0.ts
#EXTINF:10,
1.ts
#EXT-X-CUE-OUT:30
#EXTINF:10,
2.ts
#EXT-X-CUE-OUT-CONT:10/30
#EXTINF:10,
3.ts
#EXT-X-CUE-OUT-CONT:20/30
#EXTINF:10,
4.ts
#EXT-X-CUE-IN
#EXTINF:10,
5.ts
#EXTINF:10,
6.ts
#EXT-X-ENDLIST
Not Yet Supported
Custom Parsers
To add a parser for a non-standard tag the parser object allows for the specification of custom tags using regular expressions. If a custom parser is specified, a custom object is appended to the manifest object.
const manifest = [ '#EXTM3U', '#EXT-X-VERSION:3', '#VOD-FRAMERATE:29.97', '' ].join('\n'); const parser = new m3u8Parser.Parser(); parser.addParser({ expression: /^#VOD-FRAMERATE/, customType: 'framerate' }); parser.push(manifest); parser.end(); parser.manifest.custom.framerate // "#VOD-FRAMERATE:29.97"
Custom parsers may additionally be provided a data parsing function that take a line and return a value.
const manifest = [ '#EXTM3U', '#EXT-X-VERSION:3', '#VOD-FRAMERATE:29.97', '' ].join('\n'); const parser = new m3u8Parser.Parser(); parser.addParser({ expression: /^#VOD-FRAMERATE/, customType: 'framerate', dataParser: function(line) { return parseFloat(line.split(':')[1]); } }); parser.push(manifest); parser.end(); parser.manifest.custom.framerate // 29.97
Custom parsers may also extract data at a segment level by passing segment: true to the options object. Having a segment level custom parser will add a custom object to the segment data.
const manifest = [ '#EXTM3U', '#VOD-TIMING:1511816599485', '#EXTINF:8.0,', 'ex1.ts', '' ].join('\n'); const parser = new m3u8Parser.Parser(); parser.addParser({ expression: /#VOD-TIMING/, customType: 'vodTiming', segment: true }); parser.push(manifest); parser.end(); parser.manifest.segments[0].custom.vodTiming // #VOD-TIMING:1511816599485
Custom parsers may also map a tag to another tag. The old tag will not be replaced and all matching registered mappers and parsers will be executed.
const manifest = [ '#EXTM3U', '#EXAMPLE', '#EXTINF:8.0,', 'ex1.ts', '' ].join('\n'); const parser = new m3u8Parser.Parser(); parser.addTagMapper({ expression: /#EXAMPLE/, map(line) { return `#NEW-TAG:123`; } }); parser.addParser({ expression: /#NEW-TAG/, customType: 'mappingExample', segment: true }); parser.push(manifest); parser.end(); parser.manifest.segments[0].custom.mappingExample // #NEW-TAG:123
Including the Parser
To include m3u8-parser on your website or web application, use any of the following methods.
<script> Tag
This is the simplest case. Get the script in whatever way you prefer and include it on your page.
<script src="//path/to/m3u8-parser.min.js"></script> <script> var parser = new m3u8Parser.Parser(); </script>
Browserify
When using with Browserify, install m3u8-parser via npm and require the parser as you would any other module.
var m3u8Parser = require('m3u8-parser'); var parser = new m3u8Parser.Parser();
With ES6:
import { Parser } from 'm3u8-parser'; const parser = new Parser();
RequireJS/AMD
When using with RequireJS (or another AMD library), get the script in whatever way you prefer and require the parser as you normally would:
require(['m3u8-parser'], function(m3u8Parser) { var parser = new m3u8Parser.Parser(); });
License
Apache-2.0. Copyright (c) Brightcove, Inc
