diff --git a/README.md b/README.md index e29ec60d4..4e6434e51 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,8 @@ Video.js Compatibility: 6.0, 7.0 - [enableLowInitialPlaylist](#enablelowinitialplaylist) - [limitRenditionByPlayerDimensions](#limitrenditionbyplayerdimensions) - [smoothQualityChange](#smoothqualitychange) - - [allowSeeksWithinUnsafeLiveWindow](#allowSeeksWithinUnsafeLiveWindow) + - [allowSeeksWithinUnsafeLiveWindow](#allowseekswithinunsafelivewindow) + - [customTagParsers](#customtagparsers) - [Runtime Properties](#runtime-properties) - [hls.playlists.master](#hlsplaylistsmaster) - [hls.playlists.media](#hlsplaylistsmedia) @@ -394,6 +395,12 @@ content. The property defaults to `false`. +##### customTagParsers +* Type: `Array` +* can be used as a source option + +With `customTagParsers` you can pass an array of custom m3u8 tag parser objects. See https://github.com/videojs/m3u8-parser#custom-parsers + ### Runtime Properties Runtime properties are attached to the tech object when HLS is in use. You can get a reference to the HLS source handler like this: diff --git a/src/playlist-loader.js b/src/playlist-loader.js index a1c8c7bc0..bf60034f7 100644 --- a/src/playlist-loader.js +++ b/src/playlist-loader.js @@ -203,6 +203,10 @@ export default class PlaylistLoader extends EventTarget { this.hls_ = hls; this.withCredentials = withCredentials; + const options = hls.options_; + + this.customTagParsers = (options && options.customTagParsers) || []; + if (!this.srcUrl) { throw new Error('A non-empty playlist URL is required'); } @@ -266,6 +270,9 @@ export default class PlaylistLoader extends EventTarget { const parser = new M3u8Parser(); + // adding custom tag parsers + this.customTagParsers.forEach(customParser => parser.addParser(customParser)); + parser.push(xhr.responseText); parser.end(); parser.manifest.uri = url; @@ -505,6 +512,9 @@ export default class PlaylistLoader extends EventTarget { const parser = new M3u8Parser(); + // adding custom tag parsers + this.customTagParsers.forEach(customParser => parser.addParser(customParser)); + parser.push(req.responseText); parser.end(); diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index d81e18a6e..6d0707b48 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -401,6 +401,7 @@ class HlsHandler extends Component { typeof this.source_.useBandwidthFromLocalStorage !== 'undefined' ? this.source_.useBandwidthFromLocalStorage : this.options_.useBandwidthFromLocalStorage || false; + this.options_.customTagParsers = this.options_.customTagParsers || []; if (typeof this.options_.blacklistDuration !== 'number') { this.options_.blacklistDuration = 5 * 60; @@ -433,7 +434,13 @@ class HlsHandler extends Component { this.options_.bandwidth === Config.INITIAL_BANDWIDTH; // grab options passed to player.src - ['withCredentials', 'limitRenditionByPlayerDimensions', 'bandwidth', 'smoothQualityChange'].forEach((option) => { + [ + 'withCredentials', + 'limitRenditionByPlayerDimensions', + 'bandwidth', + 'smoothQualityChange', + 'customTagParsers' + ].forEach((option) => { if (typeof this.source_[option] !== 'undefined') { this.options_[option] = this.source_[option]; } diff --git a/test/playlist-loader.test.js b/test/playlist-loader.test.js index 477a94fc5..e11d16ac8 100644 --- a/test/playlist-loader.test.js +++ b/test/playlist-loader.test.js @@ -862,6 +862,32 @@ QUnit.test('logs warning for master playlist with invalid STREAM-INF', function( 'logged a warning'); }); +QUnit.test('executes custom tag parsers', function(assert) { + const customTagParsers = [{ + expression: /#PARSER/, + customType: 'test', + segment: true + }]; + + this.fakeHls.options_ = { customTagParsers }; + + let loader = new PlaylistLoader('master.m3u8', this.fakeHls); + + loader.load(); + this.requests.pop().respond(200, null, + '#EXTM3U\n' + + '#PARSER:parsed\n' + + '#EXTINF:10,\n' + + '0.ts\n' + + '#EXT-X-ENDLIST\n'); + + const segment = loader.master.playlists[0].segments[0]; + + assert.strictEqual(segment.custom.test, '#PARSER:parsed', 'parsed custom tag'); + + delete this.fakeHls.options_; +}); + QUnit.test('jumps to HAVE_METADATA when initialized with a media playlist', function(assert) { let loadedmetadatas = 0;