Skip to content

Commit

Permalink
feat: expose custom M3U8 mapper API (#325)
Browse files Browse the repository at this point in the history
  • Loading branch information
forbesjo authored Jan 10, 2019
1 parent bab70fd commit 609beb3
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 12 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Video.js Compatibility: 6.0, 7.0
- [smoothQualityChange](#smoothqualitychange)
- [allowSeeksWithinUnsafeLiveWindow](#allowseekswithinunsafelivewindow)
- [customTagParsers](#customtagparsers)
- [customTagMappers](#customtagmappers)
- [Runtime Properties](#runtime-properties)
- [hls.playlists.master](#hlsplaylistsmaster)
- [hls.playlists.media](#hlsplaylistsmedia)
Expand Down Expand Up @@ -401,6 +402,12 @@ The property defaults to `false`.

With `customTagParsers` you can pass an array of custom m3u8 tag parser objects. See https://github.com/videojs/m3u8-parser#custom-parsers

##### customTagMappers
* Type: `Array`
* can be used as a source option

Similar to `customTagParsers`, with `customTagMappers` you can pass an array of custom m3u8 tag mapper 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:
Expand Down
14 changes: 11 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"dependencies": {
"aes-decrypter": "3.0.0",
"global": "^4.3.0",
"m3u8-parser": "4.2.0",
"m3u8-parser": "4.3.0",
"mpd-parser": "0.7.0",
"mux.js": "5.0.1",
"url-toolkit": "^2.1.3",
Expand Down
7 changes: 7 additions & 0 deletions src/playlist-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export default class PlaylistLoader extends EventTarget {
const options = hls.options_;

this.customTagParsers = (options && options.customTagParsers) || [];
this.customTagMappers = (options && options.customTagMappers) || [];

if (!this.srcUrl) {
throw new Error('A non-empty playlist URL is required');
Expand Down Expand Up @@ -273,6 +274,9 @@ export default class PlaylistLoader extends EventTarget {
// adding custom tag parsers
this.customTagParsers.forEach(customParser => parser.addParser(customParser));

// adding custom tag mappers
this.customTagMappers.forEach(mapper => parser.addTagMapper(mapper));

parser.push(xhr.responseText);
parser.end();
parser.manifest.uri = url;
Expand Down Expand Up @@ -515,6 +519,9 @@ export default class PlaylistLoader extends EventTarget {
// adding custom tag parsers
this.customTagParsers.forEach(customParser => parser.addParser(customParser));

// adding custom tag mappers
this.customTagMappers.forEach(mapper => parser.addTagMapper(mapper));

parser.push(req.responseText);
parser.end();

Expand Down
4 changes: 3 additions & 1 deletion src/videojs-http-streaming.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ class HlsHandler extends Component {
this.source_.useBandwidthFromLocalStorage :
this.options_.useBandwidthFromLocalStorage || false;
this.options_.customTagParsers = this.options_.customTagParsers || [];
this.options_.customTagMappers = this.options_.customTagMappers || [];

if (typeof this.options_.blacklistDuration !== 'number') {
this.options_.blacklistDuration = 5 * 60;
Expand Down Expand Up @@ -439,7 +440,8 @@ class HlsHandler extends Component {
'limitRenditionByPlayerDimensions',
'bandwidth',
'smoothQualityChange',
'customTagParsers'
'customTagParsers',
'customTagMappers'
].forEach((option) => {
if (typeof this.source_[option] !== 'undefined') {
this.options_[option] = this.source_[option];
Expand Down
31 changes: 26 additions & 5 deletions test/configuration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,27 @@ const options = [{
default: false,
test: true,
alt: false
}, {
name: 'useBandwidthFromLocalStorage',
default: false,
test: true
}, {
name: 'customTagParsers',
default: [],
test: [{
expression: /#PARSER/,
customType: 'test',
segment: true
}]
}, {
name: 'customTagMappers',
default: [],
test: [{
expression: /#MAPPER/,
map(line) {
return `#FOO`;
}
}]
}];

const CONFIG_KEYS = Object.keys(Config);
Expand Down Expand Up @@ -270,7 +291,7 @@ options.forEach((opt) => {

let hls = this.player.tech_.hls;

assert.equal(hls.options_[opt.name],
assert.deepEqual(hls.options_[opt.name],
opt.default,
`${opt.name} should be default`);
});
Expand Down Expand Up @@ -306,7 +327,7 @@ options.forEach((opt) => {

let hls = this.player.tech_.hls;

assert.equal(hls.options_[opt.name],
assert.deepEqual(hls.options_[opt.name],
opt.test,
`${opt.name} should be equal to sourceHandler Option`);
});
Expand All @@ -325,7 +346,7 @@ options.forEach((opt) => {

let hls = this.player.tech_.hls;

assert.equal(hls.options_[opt.name],
assert.deepEqual(hls.options_[opt.name],
opt.test,
`${opt.name} should be equal to src option`);
});
Expand All @@ -345,7 +366,7 @@ options.forEach((opt) => {

let hls = this.player.tech_.hls;

assert.equal(hls.options_[opt.name],
assert.deepEqual(hls.options_[opt.name],
opt.test,
`${opt.name} should be equal to sourchHandler option`);
});
Expand All @@ -366,7 +387,7 @@ options.forEach((opt) => {

let hls = this.player.tech_.hls;

assert.equal(hls.options_[opt.name],
assert.deepEqual(hls.options_[opt.name],
opt.test,
`${opt.name} should be equal to sourchHandler option`);
});
Expand Down
16 changes: 14 additions & 2 deletions test/playlist-loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -862,28 +862,40 @@ QUnit.test('logs warning for master playlist with invalid STREAM-INF', function(
'logged a warning');
});

QUnit.test('executes custom tag parsers', function(assert) {
QUnit.test('executes custom parsers and mappers', function(assert) {
const customTagParsers = [{
expression: /#PARSER/,
customType: 'test',
segment: true
}];
const customTagMappers = [{
expression: /#MAPPER/,
map(line) {
const regex = /#MAPPER:(\d+)/g;
const match = regex.exec(line);
const ISOdate = new Date(Number(match[1])).toISOString();

return `#EXT-X-PROGRAM-DATE-TIME:${ISOdate}`;
}
}];

this.fakeHls.options_ = { customTagParsers };
this.fakeHls.options_ = { customTagParsers, customTagMappers };

let loader = new PlaylistLoader('master.m3u8', this.fakeHls);

loader.load();
this.requests.pop().respond(200, null,
'#EXTM3U\n' +
'#PARSER:parsed\n' +
'#MAPPER:1511816599485\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');
assert.ok(segment.dateTimeObject, 'converted and parsed custom time');

delete this.fakeHls.options_;
});
Expand Down

0 comments on commit 609beb3

Please sign in to comment.