Merge pull request #534 from BrandonOCasey/browserify-p2
browserify-p2: m3u8, stream, and stub
Showing
19 changed files
with
670 additions
and
666 deletions
... | @@ -40,14 +40,17 @@ | ... | @@ -40,14 +40,17 @@ |
40 | </label> | 40 | </label> |
41 | <button type=submit>Load</button> | 41 | <button type=submit>Load</button> |
42 | </form> | 42 | </form> |
43 | <ul> | ||
44 | <li><a href="/test/">Run unit tests in browser.</a></li> | ||
45 | <li><a href="/docs/api/">Read generated docs.</a></li> | ||
46 | </ul> | ||
43 | 47 | ||
44 | <script src="/node_modules/video.js/dist/video.js"></script> | 48 | <script src="/node_modules/video.js/dist/video.js"></script> |
45 | <script src="/node_modules/videojs-contrib-media-sources/dist/videojs-media-sources.js"></script> | 49 | <script src="/node_modules/videojs-contrib-media-sources/dist/videojs-media-sources.js"></script> |
46 | <script src="/node_modules/pkcs7/dist/pkcs7.unpad.js"></script> | 50 | <script src="/node_modules/pkcs7/dist/pkcs7.unpad.js"></script> |
47 | <script src="/src/videojs-hls.js"></script> | 51 | <script src="/src/videojs-contrib-hls.js"></script> |
48 | <script src="/src/xhr.js"></script> | 52 | <script src="/src/xhr.js"></script> |
49 | <script src="/src/stream.js"></script> | 53 | <script src="/dist/videojs-contrib-hls.js"></script> |
50 | <script src="/src/m3u8/m3u8-parser.js"></script> | ||
51 | <script src="/src/playlist.js"></script> | 54 | <script src="/src/playlist.js"></script> |
52 | <script src="/src/playlist-loader.js"></script> | 55 | <script src="/src/playlist-loader.js"></script> |
53 | <script src="/src/decrypter.js"></script> | 56 | <script src="/src/decrypter.js"></script> | ... | ... |
... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
2 | "name": "videojs-contrib-hls", | 2 | "name": "videojs-contrib-hls", |
3 | "version": "1.3.5", | 3 | "version": "1.3.5", |
4 | "description": "Play back HLS with video.js, even where it's not natively supported", | 4 | "description": "Play back HLS with video.js, even where it's not natively supported", |
5 | "main": "es5/videojs-hls.js", | 5 | "main": "es5/stub.js", |
6 | "engines": { | 6 | "engines": { |
7 | "node": ">= 0.10.12" | 7 | "node": ">= 0.10.12" |
8 | }, | 8 | }, |
... | @@ -13,16 +13,17 @@ | ... | @@ -13,16 +13,17 @@ |
13 | "scripts": { | 13 | "scripts": { |
14 | "prebuild": "npm run clean", | 14 | "prebuild": "npm run clean", |
15 | "build": "npm-run-all -p build:*", | 15 | "build": "npm-run-all -p build:*", |
16 | "build:manifest": "node -e \"var b=require('./scripts/manifest-data.js'); b.build();\"", | ||
17 | "build:js": "npm-run-all build:js:babel build:js:browserify build:js:bannerize build:js:uglify", | 16 | "build:js": "npm-run-all build:js:babel build:js:browserify build:js:bannerize build:js:uglify", |
18 | "build:js:babel": "babel src -d es5", | 17 | "build:js:babel": "babel src -d es5", |
19 | "build:js:bannerize": "bannerize dist/videojs-contrib-hls.js --banner=scripts/banner.ejs", | 18 | "build:js:bannerize": "bannerize dist/videojs-contrib-hls.js --banner=scripts/banner.ejs", |
20 | "build:js:browserify": "browserify . -s src/videojs-hls.js -o dist/videojs-contrib-hls.js", | 19 | "build:js:browserify": "browserify . -s videojs-contrib-hls -o dist/videojs-contrib-hls.js", |
21 | "build:js:uglify": "uglifyjs dist/videojs-contrib-hls.js --comments --mangle --compress -o dist/videojs-contrib-hls.min.js", | 20 | "build:js:uglify": "uglifyjs dist/videojs-contrib-hls.js --comments --mangle --compress -o dist/videojs-contrib-hls.min.js", |
22 | "build:test": "node scripts/build-test.js", | 21 | "build:test": "npm-run-all build:test:manifest build:test:js", |
23 | "clean": "npm-run-all clean:*", | 22 | "build:test:js": "node scripts/build-test.js", |
23 | "build:test:manifest": "node -e \"var b=require('./scripts/manifest-data.js'); b.build();\"", | ||
24 | "clean": "npm-run-all -p clean:*", | ||
24 | "clean:build": "node -e \"var s=require('shelljs'),d=['dist','dist-test','es5'];s.rm('-rf',d);s.mkdir('-p',d);\"", | 25 | "clean:build": "node -e \"var s=require('shelljs'),d=['dist','dist-test','es5'];s.rm('-rf',d);s.mkdir('-p',d);\"", |
25 | "clean:manifest": "node -e \"var b=require('./scripts/manifest-data.js'); b.clean();\"", | 26 | "clean:test": "node -e \"var b=require('./scripts/manifest-data.js'); b.clean();\"", |
26 | "docs": "npm-run-all docs:*", | 27 | "docs": "npm-run-all docs:*", |
27 | "docs:api": "jsdoc src -r -d docs/api", | 28 | "docs:api": "jsdoc src -r -d docs/api", |
28 | "docs:toc": "doctoc README.md", | 29 | "docs:toc": "doctoc README.md", |
... | @@ -39,9 +40,10 @@ | ... | @@ -39,9 +40,10 @@ |
39 | "preversion": "npm test", | 40 | "preversion": "npm test", |
40 | "version": "npm run build", | 41 | "version": "npm run build", |
41 | "watch": "npm-run-all -p watch:*", | 42 | "watch": "npm-run-all -p watch:*", |
42 | "watch:manifest": "node -e \"var b=require('./scripts/manifest-data.js'); b.watch();\"", | 43 | "watch:js": "watchify src/stub.js -t babelify -v -o dist/videojs-contrib-hls.js", |
43 | "watch:js": "watchify src/videojs-hls.js -t babelify -v -o dist/videojs-contrib-hls.js", | 44 | "watch:test": "npm-run-all -p watch:test:*", |
44 | "watch:test": "node scripts/watch-test.js", | 45 | "watch:test:js": "node scripts/watch-test.js", |
46 | "watch:test:manifest": "node -e \"var b=require('./scripts/manifest-data.js'); b.watch();\"", | ||
45 | "prepublish": "npm run build" | 47 | "prepublish": "npm run build" |
46 | }, | 48 | }, |
47 | "keywords": [ | 49 | "keywords": [ |
... | @@ -69,7 +71,8 @@ | ... | @@ -69,7 +71,8 @@ |
69 | "test/karma", | 71 | "test/karma", |
70 | "scripts", | 72 | "scripts", |
71 | "utils", | 73 | "utils", |
72 | "test/data" | 74 | "test/test-manifests.js", |
75 | "test/test-expected.js" | ||
73 | ] | 76 | ] |
74 | }, | 77 | }, |
75 | "files": [ | 78 | "files": [ | ... | ... |
... | @@ -2,7 +2,7 @@ var browserify = require('browserify'); | ... | @@ -2,7 +2,7 @@ var browserify = require('browserify'); |
2 | var fs = require('fs'); | 2 | var fs = require('fs'); |
3 | var glob = require('glob'); | 3 | var glob = require('glob'); |
4 | 4 | ||
5 | glob('test/**/*.test.js', function(err, files) { | 5 | glob('test/{m3u8,stub}.test.js', function(err, files) { |
6 | browserify(files) | 6 | browserify(files) |
7 | .transform('babelify') | 7 | .transform('babelify') |
8 | .bundle() | 8 | .bundle() | ... | ... |
1 | var fs = require('fs'); | 1 | var fs = require('fs'); |
2 | var path = require('path'); | 2 | var path = require('path'); |
3 | 3 | ||
4 | var basePath = path.resolve(__dirname + '/..'); | 4 | var basePath = path.resolve(__dirname, '..'); |
5 | var testDataDir = basePath + '/test/data'; | 5 | var testDataDir = path.join(basePath,'test'); |
6 | var manifestDir = basePath + '/utils/manifest'; | 6 | var manifestDir = path.join(basePath, 'utils', 'manifest'); |
7 | var manifestFilepath = testDataDir + '/manifests.js'; | 7 | var manifestFilepath = path.join(testDataDir, 'test-manifests.js'); |
8 | var expectedFilepath = testDataDir + '/expected.js'; | 8 | var expectedFilepath = path.join(testDataDir, 'test-expected.js'); |
9 | |||
10 | 9 | ||
11 | var build = function() { | 10 | var build = function() { |
12 | var manifests = 'window.manifests = {\n'; | 11 | var manifests = 'export default {\n'; |
13 | var expected = 'window.expected = {\n'; | 12 | var expected = 'export default {\n'; |
14 | 13 | ||
15 | var files = fs.readdirSync(manifestDir); | 14 | var files = fs.readdirSync(manifestDir); |
16 | while (files.length > 0) { | 15 | while (files.length > 0) { | ... | ... |
... | @@ -3,7 +3,7 @@ var fs = require('fs'); | ... | @@ -3,7 +3,7 @@ var fs = require('fs'); |
3 | var glob = require('glob'); | 3 | var glob = require('glob'); |
4 | var watchify = require('watchify'); | 4 | var watchify = require('watchify'); |
5 | 5 | ||
6 | glob('test/**/*.test.js', function(err, files) { | 6 | glob('test/{m3u8,stub}.test.js', function(err, files) { |
7 | var b = browserify(files, { | 7 | var b = browserify(files, { |
8 | cache: {}, | 8 | cache: {}, |
9 | packageCache: {}, | 9 | packageCache: {}, | ... | ... |
src/.jshintrc
deleted
100644 → 0
... | @@ -5,30 +5,55 @@ | ... | @@ -5,30 +5,55 @@ |
5 | * that do not assume the entirety of the manifest is ready and expose a | 5 | * that do not assume the entirety of the manifest is ready and expose a |
6 | * ReadableStream-like interface. | 6 | * ReadableStream-like interface. |
7 | */ | 7 | */ |
8 | (function(videojs, parseInt, isFinite, mergeOptions, undefined) { | 8 | |
9 | var | 9 | import Stream from '../stream'; |
10 | noop = function() {}, | 10 | import {mergeOptions} from 'video.js'; |
11 | 11 | /** | |
12 | // "forgiving" attribute list psuedo-grammar: | 12 | * A stream that buffers string input and generates a `data` event for each |
13 | // attributes -> keyvalue (',' keyvalue)* | 13 | * line. |
14 | // keyvalue -> key '=' value | 14 | */ |
15 | // key -> [^=]* | 15 | export class LineStream extends Stream { |
16 | // value -> '"' [^"]* '"' | [^,]* | 16 | constructor() { |
17 | attributeSeparator = (function() { | 17 | super(); |
18 | var | 18 | this.buffer = ''; |
19 | key = '[^=]*', | 19 | } |
20 | value = '"[^"]*"|[^,]*', | 20 | |
21 | keyvalue = '(?:' + key + ')=(?:' + value + ')'; | 21 | /** |
22 | * Add new data to be parsed. | ||
23 | * @param data {string} the text to process | ||
24 | */ | ||
25 | push(data) { | ||
26 | let nextNewline; | ||
27 | |||
28 | this.buffer += data; | ||
29 | nextNewline = this.buffer.indexOf('\n'); | ||
30 | |||
31 | for (; nextNewline > -1; nextNewline = this.buffer.indexOf('\n')) { | ||
32 | this.trigger('data', this.buffer.substring(0, nextNewline)); | ||
33 | this.buffer = this.buffer.substring(nextNewline + 1); | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | |||
38 | // "forgiving" attribute list psuedo-grammar: | ||
39 | // attributes -> keyvalue (',' keyvalue)* | ||
40 | // keyvalue -> key '=' value | ||
41 | // key -> [^=]* | ||
42 | // value -> '"' [^"]* '"' | [^,]* | ||
43 | const attributeSeparator = function() { | ||
44 | let key = '[^=]*'; | ||
45 | let value = '"[^"]*"|[^,]*'; | ||
46 | let keyvalue = '(?:' + key + ')=(?:' + value + ')'; | ||
22 | 47 | ||
23 | return new RegExp('(?:^|,)(' + keyvalue + ')'); | 48 | return new RegExp('(?:^|,)(' + keyvalue + ')'); |
24 | })(), | 49 | }; |
25 | parseAttributes = function(attributes) { | 50 | |
26 | var | 51 | const parseAttributes = function(attributes) { |
27 | // split the string using attributes as the separator | 52 | // split the string using attributes as the separator |
28 | attrs = attributes.split(attributeSeparator), | 53 | let attrs = attributes.split(attributeSeparator()); |
29 | i = attrs.length, | 54 | let i = attrs.length; |
30 | result = {}, | 55 | let result = {}; |
31 | attr; | 56 | let attr; |
32 | 57 | ||
33 | while (i--) { | 58 | while (i--) { |
34 | // filter out unmatched portions of the string | 59 | // filter out unmatched portions of the string |
... | @@ -37,7 +62,7 @@ | ... | @@ -37,7 +62,7 @@ |
37 | } | 62 | } |
38 | 63 | ||
39 | // split the key and value | 64 | // split the key and value |
40 | attr = /([^=]*)=(.*)/.exec(attrs[i]).slice(1); | 65 | attr = (/([^=]*)=(.*)/).exec(attrs[i]).slice(1); |
41 | // trim whitespace and remove optional quotes around the value | 66 | // trim whitespace and remove optional quotes around the value |
42 | attr[0] = attr[0].replace(/^\s+|\s+$/g, ''); | 67 | attr[0] = attr[0].replace(/^\s+|\s+$/g, ''); |
43 | attr[1] = attr[1].replace(/^\s+|\s+$/g, ''); | 68 | attr[1] = attr[1].replace(/^\s+|\s+$/g, ''); |
... | @@ -45,39 +70,9 @@ | ... | @@ -45,39 +70,9 @@ |
45 | result[attr[0]] = attr[1]; | 70 | result[attr[0]] = attr[1]; |
46 | } | 71 | } |
47 | return result; | 72 | return result; |
48 | }, | 73 | }; |
49 | Stream = videojs.Hls.Stream, | ||
50 | LineStream, | ||
51 | ParseStream, | ||
52 | Parser; | ||
53 | |||
54 | /** | ||
55 | * A stream that buffers string input and generates a `data` event for each | ||
56 | * line. | ||
57 | */ | ||
58 | LineStream = function() { | ||
59 | var buffer = ''; | ||
60 | LineStream.prototype.init.call(this); | ||
61 | |||
62 | /** | ||
63 | * Add new data to be parsed. | ||
64 | * @param data {string} the text to process | ||
65 | */ | ||
66 | this.push = function(data) { | ||
67 | var nextNewline; | ||
68 | |||
69 | buffer += data; | ||
70 | nextNewline = buffer.indexOf('\n'); | ||
71 | |||
72 | for (; nextNewline > -1; nextNewline = buffer.indexOf('\n')) { | ||
73 | this.trigger('data', buffer.substring(0, nextNewline)); | ||
74 | buffer = buffer.substring(nextNewline + 1); | ||
75 | } | ||
76 | }; | ||
77 | }; | ||
78 | LineStream.prototype = new Stream(); | ||
79 | 74 | ||
80 | /** | 75 | /** |
81 | * A line-level M3U8 parser event stream. It expects to receive input one | 76 | * A line-level M3U8 parser event stream. It expects to receive input one |
82 | * line at a time and performs a context-free parse of its contents. A stream | 77 | * line at a time and performs a context-free parse of its contents. A stream |
83 | * interpretation of a manifest can be useful if the manifest is expected to | 78 | * interpretation of a manifest can be useful if the manifest is expected to |
... | @@ -98,18 +93,20 @@ | ... | @@ -98,18 +93,20 @@ |
98 | * tags are given the tag type `unknown` and a single additional property | 93 | * tags are given the tag type `unknown` and a single additional property |
99 | * `data` with the remainder of the input. | 94 | * `data` with the remainder of the input. |
100 | */ | 95 | */ |
101 | ParseStream = function() { | 96 | export class ParseStream extends Stream { |
102 | ParseStream.prototype.init.call(this); | 97 | constructor() { |
103 | }; | 98 | super(); |
104 | ParseStream.prototype = new Stream(); | 99 | } |
100 | |||
105 | /** | 101 | /** |
106 | * Parses an additional line of input. | 102 | * Parses an additional line of input. |
107 | * @param line {string} a single line of an M3U8 file to parse | 103 | * @param line {string} a single line of an M3U8 file to parse |
108 | */ | 104 | */ |
109 | ParseStream.prototype.push = function(line) { | 105 | push(line) { |
110 | var match, event; | 106 | let match; |
107 | let event; | ||
111 | 108 | ||
112 | //strip whitespace | 109 | // strip whitespace |
113 | line = line.replace(/^[\u0000\s]+|[\u0000\s]+$/g, ''); | 110 | line = line.replace(/^[\u0000\s]+|[\u0000\s]+$/g, ''); |
114 | if (line.length === 0) { | 111 | if (line.length === 0) { |
115 | // ignore empty lines | 112 | // ignore empty lines |
... | @@ -134,12 +131,12 @@ | ... | @@ -134,12 +131,12 @@ |
134 | return; | 131 | return; |
135 | } | 132 | } |
136 | 133 | ||
137 | //strip off any carriage returns here so the regex matching | 134 | // strip off any carriage returns here so the regex matching |
138 | //doesn't have to account for them. | 135 | // doesn't have to account for them. |
139 | line = line.replace('\r',''); | 136 | line = line.replace('\r', ''); |
140 | 137 | ||
141 | // Tags | 138 | // Tags |
142 | match = /^#EXTM3U/.exec(line); | 139 | match = (/^#EXTM3U/).exec(line); |
143 | if (match) { | 140 | if (match) { |
144 | this.trigger('data', { | 141 | this.trigger('data', { |
145 | type: 'tag', | 142 | type: 'tag', |
... | @@ -271,10 +268,9 @@ | ... | @@ -271,10 +268,9 @@ |
271 | event.attributes = parseAttributes(match[1]); | 268 | event.attributes = parseAttributes(match[1]); |
272 | 269 | ||
273 | if (event.attributes.RESOLUTION) { | 270 | if (event.attributes.RESOLUTION) { |
274 | (function() { | 271 | let split = event.attributes.RESOLUTION.split('x'); |
275 | var | 272 | let resolution = {}; |
276 | split = event.attributes.RESOLUTION.split('x'), | 273 | |
277 | resolution = {}; | ||
278 | if (split[0]) { | 274 | if (split[0]) { |
279 | resolution.width = parseInt(split[0], 10); | 275 | resolution.width = parseInt(split[0], 10); |
280 | } | 276 | } |
... | @@ -282,7 +278,6 @@ | ... | @@ -282,7 +278,6 @@ |
282 | resolution.height = parseInt(split[1], 10); | 278 | resolution.height = parseInt(split[1], 10); |
283 | } | 279 | } |
284 | event.attributes.RESOLUTION = resolution; | 280 | event.attributes.RESOLUTION = resolution; |
285 | })(); | ||
286 | } | 281 | } |
287 | if (event.attributes.BANDWIDTH) { | 282 | if (event.attributes.BANDWIDTH) { |
288 | event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10); | 283 | event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10); |
... | @@ -320,7 +315,7 @@ | ... | @@ -320,7 +315,7 @@ |
320 | event.attributes = parseAttributes(match[1]); | 315 | event.attributes = parseAttributes(match[1]); |
321 | // parse the IV string into a Uint32Array | 316 | // parse the IV string into a Uint32Array |
322 | if (event.attributes.IV) { | 317 | if (event.attributes.IV) { |
323 | if (event.attributes.IV.substring(0,2) === '0x') { | 318 | if (event.attributes.IV.substring(0, 2) === '0x') { |
324 | event.attributes.IV = event.attributes.IV.substring(2); | 319 | event.attributes.IV = event.attributes.IV.substring(2); |
325 | } | 320 | } |
326 | 321 | ||
... | @@ -341,7 +336,8 @@ | ... | @@ -341,7 +336,8 @@ |
341 | type: 'tag', | 336 | type: 'tag', |
342 | data: line.slice(4, line.length) | 337 | data: line.slice(4, line.length) |
343 | }); | 338 | }); |
344 | }; | 339 | } |
340 | } | ||
345 | 341 | ||
346 | /** | 342 | /** |
347 | * A parser for M3U8 files. The current interpretation of the input is | 343 | * A parser for M3U8 files. The current interpretation of the input is |
... | @@ -361,17 +357,19 @@ | ... | @@ -361,17 +357,19 @@ |
361 | * events during the parse if it encounters input that seems invalid or | 357 | * events during the parse if it encounters input that seems invalid or |
362 | * requires some property of the manifest object to be defaulted. | 358 | * requires some property of the manifest object to be defaulted. |
363 | */ | 359 | */ |
364 | Parser = function() { | 360 | export class Parser extends Stream { |
365 | var | 361 | constructor() { |
366 | self = this, | 362 | super(); |
367 | uris = [], | ||
368 | currentUri = {}, | ||
369 | key; | ||
370 | Parser.prototype.init.call(this); | ||
371 | |||
372 | this.lineStream = new LineStream(); | 363 | this.lineStream = new LineStream(); |
373 | this.parseStream = new ParseStream(); | 364 | this.parseStream = new ParseStream(); |
374 | this.lineStream.pipe(this.parseStream); | 365 | this.lineStream.pipe(this.parseStream); |
366 | /* eslint-disable consistent-this */ | ||
367 | let self = this; | ||
368 | /* eslint-enable consistent-this */ | ||
369 | let uris = []; | ||
370 | let currentUri = {}; | ||
371 | let key; | ||
372 | let noop = function() {}; | ||
375 | 373 | ||
376 | // the manifest is empty until the parse stream begins delivering data | 374 | // the manifest is empty until the parse stream begins delivering data |
377 | this.manifest = { | 375 | this.manifest = { |
... | @@ -382,10 +380,10 @@ | ... | @@ -382,10 +380,10 @@ |
382 | // update the manifest with the m3u8 entry from the parse stream | 380 | // update the manifest with the m3u8 entry from the parse stream |
383 | this.parseStream.on('data', function(entry) { | 381 | this.parseStream.on('data', function(entry) { |
384 | ({ | 382 | ({ |
385 | tag: function() { | 383 | tag() { |
386 | // switch based on the tag type | 384 | // switch based on the tag type |
387 | (({ | 385 | (({ |
388 | 'allow-cache': function() { | 386 | 'allow-cache'() { |
389 | this.manifest.allowCache = entry.allowed; | 387 | this.manifest.allowCache = entry.allowed; |
390 | if (!('allowed' in entry)) { | 388 | if (!('allowed' in entry)) { |
391 | this.trigger('info', { | 389 | this.trigger('info', { |
... | @@ -394,8 +392,9 @@ | ... | @@ -394,8 +392,9 @@ |
394 | this.manifest.allowCache = true; | 392 | this.manifest.allowCache = true; |
395 | } | 393 | } |
396 | }, | 394 | }, |
397 | 'byterange': function() { | 395 | byterange() { |
398 | var byterange = {}; | 396 | let byterange = {}; |
397 | |||
399 | if ('length' in entry) { | 398 | if ('length' in entry) { |
400 | currentUri.byterange = byterange; | 399 | currentUri.byterange = byterange; |
401 | byterange.length = entry.length; | 400 | byterange.length = entry.length; |
... | @@ -412,10 +411,10 @@ | ... | @@ -412,10 +411,10 @@ |
412 | byterange.offset = entry.offset; | 411 | byterange.offset = entry.offset; |
413 | } | 412 | } |
414 | }, | 413 | }, |
415 | 'endlist': function() { | 414 | endlist() { |
416 | this.manifest.endList = true; | 415 | this.manifest.endList = true; |
417 | }, | 416 | }, |
418 | 'inf': function() { | 417 | inf() { |
419 | if (!('mediaSequence' in this.manifest)) { | 418 | if (!('mediaSequence' in this.manifest)) { |
420 | this.manifest.mediaSequence = 0; | 419 | this.manifest.mediaSequence = 0; |
421 | this.trigger('info', { | 420 | this.trigger('info', { |
... | @@ -435,7 +434,7 @@ | ... | @@ -435,7 +434,7 @@ |
435 | this.manifest.segments = uris; | 434 | this.manifest.segments = uris; |
436 | 435 | ||
437 | }, | 436 | }, |
438 | 'key': function() { | 437 | key() { |
439 | if (!entry.attributes) { | 438 | if (!entry.attributes) { |
440 | this.trigger('warn', { | 439 | this.trigger('warn', { |
441 | message: 'ignoring key declaration without attribute list' | 440 | message: 'ignoring key declaration without attribute list' |
... | @@ -465,11 +464,11 @@ | ... | @@ -465,11 +464,11 @@ |
465 | uri: entry.attributes.URI | 464 | uri: entry.attributes.URI |
466 | }; | 465 | }; |
467 | 466 | ||
468 | if (entry.attributes.IV !== undefined) { | 467 | if (typeof entry.attributes.IV !== 'undefined') { |
469 | key.iv = entry.attributes.IV; | 468 | key.iv = entry.attributes.IV; |
470 | } | 469 | } |
471 | }, | 470 | }, |
472 | 'media-sequence': function() { | 471 | 'media-sequence'() { |
473 | if (!isFinite(entry.number)) { | 472 | if (!isFinite(entry.number)) { |
474 | this.trigger('warn', { | 473 | this.trigger('warn', { |
475 | message: 'ignoring invalid media sequence: ' + entry.number | 474 | message: 'ignoring invalid media sequence: ' + entry.number |
... | @@ -478,7 +477,7 @@ | ... | @@ -478,7 +477,7 @@ |
478 | } | 477 | } |
479 | this.manifest.mediaSequence = entry.number; | 478 | this.manifest.mediaSequence = entry.number; |
480 | }, | 479 | }, |
481 | 'discontinuity-sequence': function() { | 480 | 'discontinuity-sequence'() { |
482 | if (!isFinite(entry.number)) { | 481 | if (!isFinite(entry.number)) { |
483 | this.trigger('warn', { | 482 | this.trigger('warn', { |
484 | message: 'ignoring invalid discontinuity sequence: ' + entry.number | 483 | message: 'ignoring invalid discontinuity sequence: ' + entry.number |
... | @@ -487,7 +486,7 @@ | ... | @@ -487,7 +486,7 @@ |
487 | } | 486 | } |
488 | this.manifest.discontinuitySequence = entry.number; | 487 | this.manifest.discontinuitySequence = entry.number; |
489 | }, | 488 | }, |
490 | 'playlist-type': function() { | 489 | 'playlist-type'() { |
491 | if (!(/VOD|EVENT/).test(entry.playlistType)) { | 490 | if (!(/VOD|EVENT/).test(entry.playlistType)) { |
492 | this.trigger('warn', { | 491 | this.trigger('warn', { |
493 | message: 'ignoring unknown playlist type: ' + entry.playlist | 492 | message: 'ignoring unknown playlist type: ' + entry.playlist |
... | @@ -496,7 +495,7 @@ | ... | @@ -496,7 +495,7 @@ |
496 | } | 495 | } |
497 | this.manifest.playlistType = entry.playlistType; | 496 | this.manifest.playlistType = entry.playlistType; |
498 | }, | 497 | }, |
499 | 'stream-inf': function() { | 498 | 'stream-inf'() { |
500 | this.manifest.playlists = uris; | 499 | this.manifest.playlists = uris; |
501 | 500 | ||
502 | if (!entry.attributes) { | 501 | if (!entry.attributes) { |
... | @@ -512,11 +511,11 @@ | ... | @@ -512,11 +511,11 @@ |
512 | currentUri.attributes = mergeOptions(currentUri.attributes, | 511 | currentUri.attributes = mergeOptions(currentUri.attributes, |
513 | entry.attributes); | 512 | entry.attributes); |
514 | }, | 513 | }, |
515 | 'discontinuity': function() { | 514 | discontinuity() { |
516 | currentUri.discontinuity = true; | 515 | currentUri.discontinuity = true; |
517 | this.manifest.discontinuityStarts.push(uris.length); | 516 | this.manifest.discontinuityStarts.push(uris.length); |
518 | }, | 517 | }, |
519 | 'targetduration': function() { | 518 | targetduration() { |
520 | if (!isFinite(entry.duration) || entry.duration < 0) { | 519 | if (!isFinite(entry.duration) || entry.duration < 0) { |
521 | this.trigger('warn', { | 520 | this.trigger('warn', { |
522 | message: 'ignoring invalid target duration: ' + entry.duration | 521 | message: 'ignoring invalid target duration: ' + entry.duration |
... | @@ -525,7 +524,7 @@ | ... | @@ -525,7 +524,7 @@ |
525 | } | 524 | } |
526 | this.manifest.targetDuration = entry.duration; | 525 | this.manifest.targetDuration = entry.duration; |
527 | }, | 526 | }, |
528 | 'totalduration': function() { | 527 | totalduration() { |
529 | if (!isFinite(entry.duration) || entry.duration < 0) { | 528 | if (!isFinite(entry.duration) || entry.duration < 0) { |
530 | this.trigger('warn', { | 529 | this.trigger('warn', { |
531 | message: 'ignoring invalid total duration: ' + entry.duration | 530 | message: 'ignoring invalid total duration: ' + entry.duration |
... | @@ -536,7 +535,7 @@ | ... | @@ -536,7 +535,7 @@ |
536 | } | 535 | } |
537 | })[entry.tagType] || noop).call(self); | 536 | })[entry.tagType] || noop).call(self); |
538 | }, | 537 | }, |
539 | uri: function() { | 538 | uri() { |
540 | currentUri.uri = entry.uri; | 539 | currentUri.uri = entry.uri; |
541 | uris.push(currentUri); | 540 | uris.push(currentUri); |
542 | 541 | ||
... | @@ -556,33 +555,36 @@ | ... | @@ -556,33 +555,36 @@ |
556 | // prepare for the next URI | 555 | // prepare for the next URI |
557 | currentUri = {}; | 556 | currentUri = {}; |
558 | }, | 557 | }, |
559 | comment: function() { | 558 | comment() { |
560 | // comments are not important for playback | 559 | // comments are not important for playback |
561 | } | 560 | } |
562 | })[entry.type].call(self); | 561 | })[entry.type].call(self); |
563 | }); | 562 | }); |
564 | }; | 563 | |
565 | Parser.prototype = new Stream(); | 564 | } |
565 | |||
566 | /** | 566 | /** |
567 | * Parse the input string and update the manifest object. | 567 | * Parse the input string and update the manifest object. |
568 | * @param chunk {string} a potentially incomplete portion of the manifest | 568 | * @param chunk {string} a potentially incomplete portion of the manifest |
569 | */ | 569 | */ |
570 | Parser.prototype.push = function(chunk) { | 570 | push(chunk) { |
571 | this.lineStream.push(chunk); | 571 | this.lineStream.push(chunk); |
572 | }; | 572 | } |
573 | |||
573 | /** | 574 | /** |
574 | * Flush any remaining input. This can be handy if the last line of an M3U8 | 575 | * Flush any remaining input. This can be handy if the last line of an M3U8 |
575 | * manifest did not contain a trailing newline but the file has been | 576 | * manifest did not contain a trailing newline but the file has been |
576 | * completely received. | 577 | * completely received. |
577 | */ | 578 | */ |
578 | Parser.prototype.end = function() { | 579 | end() { |
579 | // flush any buffered input | 580 | // flush any buffered input |
580 | this.lineStream.push('\n'); | 581 | this.lineStream.push('\n'); |
581 | }; | 582 | } |
582 | 583 | ||
583 | window.videojs.m3u8 = { | 584 | } |
584 | LineStream: LineStream, | 585 | |
585 | ParseStream: ParseStream, | 586 | export default { |
586 | Parser: Parser | 587 | LineStream, |
587 | }; | 588 | ParseStream, |
588 | })(window.videojs, window.parseInt, window.isFinite, window.videojs.mergeOptions); | 589 | Parser |
590 | }; | ... | ... |
... | @@ -2,45 +2,57 @@ | ... | @@ -2,45 +2,57 @@ |
2 | * A lightweight readable stream implemention that handles event dispatching. | 2 | * A lightweight readable stream implemention that handles event dispatching. |
3 | * Objects that inherit from streams should call init in their constructors. | 3 | * Objects that inherit from streams should call init in their constructors. |
4 | */ | 4 | */ |
5 | (function(videojs, undefined) { | 5 | export default class Stream { |
6 | var Stream = function() { | 6 | constructor() { |
7 | this.init = function() { | 7 | this.init(); |
8 | var listeners = {}; | 8 | } |
9 | |||
10 | init() { | ||
11 | this.listeners = {}; | ||
12 | } | ||
13 | |||
9 | /** | 14 | /** |
10 | * Add a listener for a specified event type. | 15 | * Add a listener for a specified event type. |
11 | * @param type {string} the event name | 16 | * @param type {string} the event name |
12 | * @param listener {function} the callback to be invoked when an event of | 17 | * @param listener {function} the callback to be invoked when an event of |
13 | * the specified type occurs | 18 | * the specified type occurs |
14 | */ | 19 | */ |
15 | this.on = function(type, listener) { | 20 | on(type, listener) { |
16 | if (!listeners[type]) { | 21 | if (!this.listeners[type]) { |
17 | listeners[type] = []; | 22 | this.listeners[type] = []; |
18 | } | 23 | } |
19 | listeners[type].push(listener); | 24 | this.listeners[type].push(listener); |
20 | }; | 25 | } |
26 | |||
21 | /** | 27 | /** |
22 | * Remove a listener for a specified event type. | 28 | * Remove a listener for a specified event type. |
23 | * @param type {string} the event name | 29 | * @param type {string} the event name |
24 | * @param listener {function} a function previously registered for this | 30 | * @param listener {function} a function previously registered for this |
25 | * type of event through `on` | 31 | * type of event through `on` |
26 | */ | 32 | */ |
27 | this.off = function(type, listener) { | 33 | off(type, listener) { |
28 | var index; | 34 | let index; |
29 | if (!listeners[type]) { | 35 | |
36 | if (!this.listeners[type]) { | ||
30 | return false; | 37 | return false; |
31 | } | 38 | } |
32 | index = listeners[type].indexOf(listener); | 39 | index = this.listeners[type].indexOf(listener); |
33 | listeners[type].splice(index, 1); | 40 | this.listeners[type].splice(index, 1); |
34 | return index > -1; | 41 | return index > -1; |
35 | }; | 42 | } |
43 | |||
36 | /** | 44 | /** |
37 | * Trigger an event of the specified type on this stream. Any additional | 45 | * Trigger an event of the specified type on this stream. Any additional |
38 | * arguments to this function are passed as parameters to event listeners. | 46 | * arguments to this function are passed as parameters to event listeners. |
39 | * @param type {string} the event name | 47 | * @param type {string} the event name |
40 | */ | 48 | */ |
41 | this.trigger = function(type) { | 49 | trigger(type) { |
42 | var callbacks, i, length, args; | 50 | let callbacks; |
43 | callbacks = listeners[type]; | 51 | let i; |
52 | let length; | ||
53 | let args; | ||
54 | |||
55 | callbacks = this.listeners[type]; | ||
44 | if (!callbacks) { | 56 | if (!callbacks) { |
45 | return; | 57 | return; |
46 | } | 58 | } |
... | @@ -60,15 +72,14 @@ | ... | @@ -60,15 +72,14 @@ |
60 | callbacks[i].apply(this, args); | 72 | callbacks[i].apply(this, args); |
61 | } | 73 | } |
62 | } | 74 | } |
63 | }; | 75 | } |
76 | |||
64 | /** | 77 | /** |
65 | * Destroys the stream and cleans up. | 78 | * Destroys the stream and cleans up. |
66 | */ | 79 | */ |
67 | this.dispose = function() { | 80 | dispose() { |
68 | listeners = {}; | 81 | this.listeners = {}; |
69 | }; | 82 | } |
70 | }; | ||
71 | }; | ||
72 | /** | 83 | /** |
73 | * Forwards all `data` events on this stream to the destination stream. The | 84 | * Forwards all `data` events on this stream to the destination stream. The |
74 | * destination stream should provide a method `push` to receive the data | 85 | * destination stream should provide a method `push` to receive the data |
... | @@ -76,11 +87,9 @@ | ... | @@ -76,11 +87,9 @@ |
76 | * @param destination {stream} the stream that will receive all `data` events | 87 | * @param destination {stream} the stream that will receive all `data` events |
77 | * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options | 88 | * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options |
78 | */ | 89 | */ |
79 | Stream.prototype.pipe = function(destination) { | 90 | pipe(destination) { |
80 | this.on('data', function(data) { | 91 | this.on('data', function(data) { |
81 | destination.push(data); | 92 | destination.push(data); |
82 | }); | 93 | }); |
83 | }; | 94 | } |
84 | 95 | } | |
85 | videojs.Hls.Stream = Stream; | ||
86 | })(window.videojs); | ... | ... |
src/stub.js
0 → 100644
... | @@ -16,22 +16,16 @@ | ... | @@ -16,22 +16,16 @@ |
16 | <script src="/node_modules/video.js/dist/video.js"></script> | 16 | <script src="/node_modules/video.js/dist/video.js"></script> |
17 | <script src="/node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script> | 17 | <script src="/node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script> |
18 | 18 | ||
19 | <script src="/src/videojs-hls.js"></script> | 19 | <script src="/src/videojs-contrib-hls.js"></script> |
20 | <script src="/src/xhr.js"></script> | 20 | <script src="/src/xhr.js"></script> |
21 | <script src="/src/stream.js"></script> | 21 | <script src="/dist/videojs-contrib-hls.js"></script> |
22 | <script src="/src/m3u8/m3u8-parser.js"></script> | ||
23 | <script src="/src/playlist.js"></script> | 22 | <script src="/src/playlist.js"></script> |
24 | <script src="/src/playlist-loader.js"></script> | 23 | <script src="/src/playlist-loader.js"></script> |
25 | <script src="/src/decrypter.js"></script> | 24 | <script src="/src/decrypter.js"></script> |
26 | <script src="/src/bin-utils.js"></script> | 25 | <script src="/src/bin-utils.js"></script> |
27 | 26 | ||
28 | <script src="/test/data/manifests.js"></script> | 27 | <script src="/test/videojs-contrib-hls.test.js"></script> |
29 | <script src="/test/data/expected.js"></script> | 28 | <script src="/dist-test/videojs-contrib-hls.js"></script> |
30 | <script src="/test/data/ts-segment-bc.js"></script> | ||
31 | |||
32 | |||
33 | <script src="/test/videojs-hls.test.js"></script> | ||
34 | <script src="/test/m3u8.test.js"></script> | ||
35 | <script src="/test/playlist.test.js"></script> | 29 | <script src="/test/playlist.test.js"></script> |
36 | <script src="/test/playlist-loader.test.js"></script> | 30 | <script src="/test/playlist-loader.test.js"></script> |
37 | <script src="/test/decrypter.test.js"></script> | 31 | <script src="/test/decrypter.test.js"></script> | ... | ... |
... | @@ -2,8 +2,7 @@ var merge = require('lodash-compat/object/merge'); | ... | @@ -2,8 +2,7 @@ var merge = require('lodash-compat/object/merge'); |
2 | 2 | ||
3 | var DEFAULTS = { | 3 | var DEFAULTS = { |
4 | basePath: '../..', | 4 | basePath: '../..', |
5 | //frameworks: ['browserify', 'qunit'], | 5 | frameworks: ['browserify', 'qunit'], |
6 | frameworks: ['qunit'], | ||
7 | 6 | ||
8 | 7 | ||
9 | files: [ | 8 | files: [ |
... | @@ -16,20 +15,19 @@ var DEFAULTS = { | ... | @@ -16,20 +15,19 @@ var DEFAULTS = { |
16 | 'node_modules/pkcs7/dist/pkcs7.unpad.js', | 15 | 'node_modules/pkcs7/dist/pkcs7.unpad.js', |
17 | 'node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js', | 16 | 'node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js', |
18 | 17 | ||
19 | 'src/videojs-hls.js', | 18 | // these two stub old functionality |
19 | 'src/videojs-contrib-hls.js', | ||
20 | 'src/xhr.js', | 20 | 'src/xhr.js', |
21 | 'src/stream.js', | 21 | 'dist/videojs-contrib-hls.js', |
22 | 'src/m3u8/m3u8-parser.js', | 22 | |
23 | 'src/playlist.js', | 23 | 'src/playlist.js', |
24 | 'src/playlist-loader.js', | 24 | 'src/playlist-loader.js', |
25 | 'src/decrypter.js', | 25 | 'src/decrypter.js', |
26 | 'src/bin-utils.js', | 26 | 'src/bin-utils.js', |
27 | 27 | ||
28 | 'test/data/manifests.js', | 28 | 'test/stub.test.js', |
29 | 'test/data/expected.js', | ||
30 | 'test/data/ts-segment-bc.js', | ||
31 | 29 | ||
32 | 'test/videojs-hls.test.js', | 30 | 'test/videojs-contrib-hls.test.js', |
33 | 'test/m3u8.test.js', | 31 | 'test/m3u8.test.js', |
34 | 'test/playlist.test.js', | 32 | 'test/playlist.test.js', |
35 | 'test/playlist-loader.test.js', | 33 | 'test/playlist-loader.test.js', |
... | @@ -44,12 +42,12 @@ var DEFAULTS = { | ... | @@ -44,12 +42,12 @@ var DEFAULTS = { |
44 | ], | 42 | ], |
45 | 43 | ||
46 | plugins: [ | 44 | plugins: [ |
47 | // 'karma-browserify', | 45 | 'karma-browserify', |
48 | 'karma-qunit' | 46 | 'karma-qunit' |
49 | ], | 47 | ], |
50 | 48 | ||
51 | preprocessors: { | 49 | preprocessors: { |
52 | // 'test/**/*.js': ['browserify'] | 50 | 'test/{stub,m3u8}.test.js': ['browserify'] |
53 | }, | 51 | }, |
54 | 52 | ||
55 | reporters: ['dots'], | 53 | reporters: ['dots'], |
... | @@ -59,18 +57,16 @@ var DEFAULTS = { | ... | @@ -59,18 +57,16 @@ var DEFAULTS = { |
59 | singleRun: true, | 57 | singleRun: true, |
60 | concurrency: Infinity, | 58 | concurrency: Infinity, |
61 | 59 | ||
62 | /* | ||
63 | browserify: { | 60 | browserify: { |
64 | debug: true, | 61 | debug: true, |
65 | transform: [ | 62 | transform: [ |
66 | 'babelify', | 63 | 'babelify', |
67 | 'browserify-shim' | 64 | 'browserify-shim' |
68 | ], | 65 | ], |
69 | noparse: [ | 66 | noParse: [ |
70 | 'test/data/**', | 67 | 'test/data/**', |
71 | ] | 68 | ] |
72 | } | 69 | } |
73 | */ | ||
74 | }; | 70 | }; |
75 | 71 | ||
76 | /** | 72 | /** | ... | ... |
... | @@ -29,6 +29,7 @@ module.exports = function(config) { | ... | @@ -29,6 +29,7 @@ module.exports = function(config) { |
29 | postDetection: function(availableBrowsers) { | 29 | postDetection: function(availableBrowsers) { |
30 | var safariIndex = availableBrowsers.indexOf('Safari'); | 30 | var safariIndex = availableBrowsers.indexOf('Safari'); |
31 | if(safariIndex !== -1) { | 31 | if(safariIndex !== -1) { |
32 | console.log("Not running safari it is/was broken"); | ||
32 | availableBrowsers.splice(safariIndex, 1); | 33 | availableBrowsers.splice(safariIndex, 1); |
33 | } | 34 | } |
34 | return availableBrowsers; | 35 | return availableBrowsers; | ... | ... |
1 | (function(window, undefined) { | 1 | import {ParseStream, LineStream, Parser} from '../src/m3u8'; |
2 | var | 2 | import QUnit from 'qunit'; |
3 | //manifestController = this.manifestController, | 3 | import testDataExpected from './test-expected.js'; |
4 | m3u8 = window.videojs.m3u8, | 4 | import testDataManifests from './test-manifests.js'; |
5 | ParseStream = m3u8.ParseStream, | 5 | |
6 | parseStream, | 6 | QUnit.module('LineStream', { |
7 | LineStream = m3u8.LineStream, | 7 | beforeEach() { |
8 | lineStream, | 8 | this.lineStream = new LineStream(); |
9 | Parser = m3u8.Parser, | ||
10 | parser; | ||
11 | |||
12 | /* | ||
13 | M3U8 Test Suite | ||
14 | */ | ||
15 | |||
16 | QUnit.module('LineStream', { | ||
17 | setup: function() { | ||
18 | lineStream = new LineStream(); | ||
19 | } | 9 | } |
20 | }); | 10 | }); |
21 | test('empty inputs produce no tokens', function() { | 11 | QUnit.test('empty inputs produce no tokens', function() { |
22 | var data = false; | 12 | let data = false; |
23 | lineStream.on('data', function() { | 13 | |
14 | this.lineStream.on('data', function() { | ||
24 | data = true; | 15 | data = true; |
25 | }); | 16 | }); |
26 | lineStream.push(''); | 17 | this.lineStream.push(''); |
27 | ok(!data, 'no tokens were produced'); | 18 | QUnit.ok(!data, 'no tokens were produced'); |
28 | }); | 19 | }); |
29 | test('splits on newlines', function() { | 20 | QUnit.test('splits on newlines', function() { |
30 | var lines = []; | 21 | let lines = []; |
31 | lineStream.on('data', function(line) { | ||
32 | lines.push(line); | ||
33 | }); | ||
34 | lineStream.push('#EXTM3U\nmovie.ts\n'); | ||
35 | 22 | ||
36 | strictEqual(2, lines.length, 'two lines are ready'); | 23 | this.lineStream.on('data', function(line) { |
37 | strictEqual('#EXTM3U', lines.shift(), 'the first line is the first token'); | ||
38 | strictEqual('movie.ts', lines.shift(), 'the second line is the second token'); | ||
39 | }); | ||
40 | test('empty lines become empty strings', function() { | ||
41 | var lines = []; | ||
42 | lineStream.on('data', function(line) { | ||
43 | lines.push(line); | 24 | lines.push(line); |
44 | }); | 25 | }); |
45 | lineStream.push('\n\n'); | 26 | this.lineStream.push('#EXTM3U\nmovie.ts\n'); |
46 | 27 | ||
47 | strictEqual(2, lines.length, 'two lines are ready'); | 28 | QUnit.strictEqual(2, lines.length, 'two lines are ready'); |
48 | strictEqual('', lines.shift(), 'the first line is empty'); | 29 | QUnit.strictEqual('#EXTM3U', lines.shift(), 'the first line is the first token'); |
49 | strictEqual('', lines.shift(), 'the second line is empty'); | 30 | QUnit.strictEqual('movie.ts', lines.shift(), 'the second line is the second token'); |
50 | }); | 31 | }); |
51 | test('handles lines broken across appends', function() { | 32 | QUnit.test('empty lines become empty strings', function() { |
52 | var lines = []; | 33 | let lines = []; |
53 | lineStream.on('data', function(line) { | 34 | |
35 | this.lineStream.on('data', function(line) { | ||
54 | lines.push(line); | 36 | lines.push(line); |
55 | }); | 37 | }); |
56 | lineStream.push('#EXTM'); | 38 | this.lineStream.push('\n\n'); |
57 | strictEqual(0, lines.length, 'no lines are ready'); | 39 | |
40 | QUnit.strictEqual(2, lines.length, 'two lines are ready'); | ||
41 | QUnit.strictEqual('', lines.shift(), 'the first line is empty'); | ||
42 | QUnit.strictEqual('', lines.shift(), 'the second line is empty'); | ||
43 | }); | ||
44 | QUnit.test('handles lines broken across appends', function() { | ||
45 | let lines = []; | ||
58 | 46 | ||
59 | lineStream.push('3U\nmovie.ts\n'); | 47 | this.lineStream.on('data', function(line) { |
60 | strictEqual(2, lines.length, 'two lines are ready'); | 48 | lines.push(line); |
61 | strictEqual('#EXTM3U', lines.shift(), 'the first line is the first token'); | ||
62 | strictEqual('movie.ts', lines.shift(), 'the second line is the second token'); | ||
63 | }); | 49 | }); |
64 | test('stops sending events after deregistering', function() { | 50 | this.lineStream.push('#EXTM'); |
65 | var | 51 | QUnit.strictEqual(0, lines.length, 'no lines are ready'); |
66 | temporaryLines = [], | 52 | |
67 | temporary = function(line) { | 53 | this.lineStream.push('3U\nmovie.ts\n'); |
54 | QUnit.strictEqual(2, lines.length, 'two lines are ready'); | ||
55 | QUnit.strictEqual('#EXTM3U', lines.shift(), 'the first line is the first token'); | ||
56 | QUnit.strictEqual('movie.ts', lines.shift(), 'the second line is the second token'); | ||
57 | }); | ||
58 | QUnit.test('stops sending events after deregistering', function() { | ||
59 | let temporaryLines = []; | ||
60 | let temporary = function(line) { | ||
68 | temporaryLines.push(line); | 61 | temporaryLines.push(line); |
69 | }, | 62 | }; |
70 | permanentLines = [], | 63 | let permanentLines = []; |
71 | permanent = function(line) { | 64 | let permanent = function(line) { |
72 | permanentLines.push(line); | 65 | permanentLines.push(line); |
73 | }; | 66 | }; |
74 | 67 | ||
75 | lineStream.on('data', temporary); | 68 | this.lineStream.on('data', temporary); |
76 | lineStream.on('data', permanent); | 69 | this.lineStream.on('data', permanent); |
77 | lineStream.push('line one\n'); | 70 | this.lineStream.push('line one\n'); |
78 | strictEqual(temporaryLines.length, permanentLines.length, 'both callbacks receive the event'); | 71 | QUnit.strictEqual(temporaryLines.length, |
79 | 72 | permanentLines.length, | |
80 | ok(lineStream.off('data', temporary), 'a listener was removed'); | 73 | 'both callbacks receive the event'); |
81 | lineStream.push('line two\n'); | 74 | |
82 | strictEqual(1, temporaryLines.length, 'no new events are received'); | 75 | QUnit.ok(this.lineStream.off('data', temporary), 'a listener was removed'); |
83 | strictEqual(2, permanentLines.length, 'new events are still received'); | 76 | this.lineStream.push('line two\n'); |
84 | }); | 77 | QUnit.strictEqual(1, temporaryLines.length, 'no new events are received'); |
85 | 78 | QUnit.strictEqual(2, permanentLines.length, 'new events are still received'); | |
86 | QUnit.module('ParseStream', { | 79 | }); |
87 | setup: function() { | 80 | |
88 | lineStream = new LineStream(); | 81 | QUnit.module('ParseStream', { |
89 | parseStream = new ParseStream(); | 82 | beforeEach() { |
90 | lineStream.pipe(parseStream); | 83 | this.lineStream = new LineStream(); |
84 | this.parseStream = new ParseStream(); | ||
85 | this.lineStream.pipe(this.parseStream); | ||
91 | } | 86 | } |
92 | }); | 87 | }); |
93 | test('parses comment lines', function() { | 88 | QUnit.test('parses comment lines', function() { |
94 | var | 89 | let manifest = '# a line that starts with a hash mark without "EXT" is a comment\n'; |
95 | manifest = '# a line that starts with a hash mark without "EXT" is a comment\n', | 90 | let element; |
96 | element; | 91 | |
97 | parseStream.on('data', function(elem) { | 92 | this.parseStream.on('data', function(elem) { |
98 | element = elem; | 93 | element = elem; |
99 | }); | 94 | }); |
100 | lineStream.push(manifest); | 95 | this.lineStream.push(manifest); |
101 | 96 | ||
102 | ok(element, 'an event was triggered'); | 97 | QUnit.ok(element, 'an event was triggered'); |
103 | strictEqual(element.type, 'comment', 'the type is comment'); | 98 | QUnit.strictEqual(element.type, 'comment', 'the type is comment'); |
104 | strictEqual(element.text, | 99 | QUnit.strictEqual(element.text, |
105 | manifest.slice(1, manifest.length - 1), | 100 | manifest.slice(1, manifest.length - 1), |
106 | 'the comment text is parsed'); | 101 | 'the comment text is parsed'); |
107 | }); | 102 | }); |
108 | test('parses uri lines', function() { | 103 | QUnit.test('parses uri lines', function() { |
109 | var | 104 | let manifest = 'any non-blank line that does not start with a hash-mark is a URI\n'; |
110 | manifest = 'any non-blank line that does not start with a hash-mark is a URI\n', | 105 | let element; |
111 | element; | 106 | |
112 | parseStream.on('data', function(elem) { | 107 | this.parseStream.on('data', function(elem) { |
113 | element = elem; | 108 | element = elem; |
114 | }); | 109 | }); |
115 | lineStream.push(manifest); | 110 | this.lineStream.push(manifest); |
116 | 111 | ||
117 | ok(element, 'an event was triggered'); | 112 | QUnit.ok(element, 'an event was triggered'); |
118 | strictEqual(element.type, 'uri', 'the type is uri'); | 113 | QUnit.strictEqual(element.type, 'uri', 'the type is uri'); |
119 | strictEqual(element.uri, | 114 | QUnit.strictEqual(element.uri, |
120 | manifest.substring(0, manifest.length - 1), | 115 | manifest.substring(0, manifest.length - 1), |
121 | 'the uri text is parsed'); | 116 | 'the uri text is parsed'); |
122 | }); | 117 | }); |
123 | test('parses unknown tag types', function() { | 118 | QUnit.test('parses unknown tag types', function() { |
124 | var | 119 | let manifest = '#EXT-X-EXAMPLE-TAG:some,additional,stuff\n'; |
125 | manifest = '#EXT-X-EXAMPLE-TAG:some,additional,stuff\n', | 120 | let element; |
126 | element; | 121 | |
127 | parseStream.on('data', function(elem) { | 122 | this.parseStream.on('data', function(elem) { |
128 | element = elem; | 123 | element = elem; |
129 | }); | 124 | }); |
130 | lineStream.push(manifest); | 125 | this.lineStream.push(manifest); |
131 | 126 | ||
132 | ok(element, 'an event was triggered'); | 127 | QUnit.ok(element, 'an event was triggered'); |
133 | strictEqual(element.type, 'tag', 'the type is tag'); | 128 | QUnit.strictEqual(element.type, 'tag', 'the type is tag'); |
134 | strictEqual(element.data, | 129 | QUnit.strictEqual(element.data, |
135 | manifest.slice(4, manifest.length - 1), | 130 | manifest.slice(4, manifest.length - 1), |
136 | 'unknown tag data is preserved'); | 131 | 'unknown tag data is preserved'); |
137 | }); | 132 | }); |
138 | 133 | ||
139 | // #EXTM3U | 134 | // #EXTM3U |
140 | test('parses #EXTM3U tags', function() { | 135 | QUnit.test('parses #EXTM3U tags', function() { |
141 | var | 136 | let manifest = '#EXTM3U\n'; |
142 | manifest = '#EXTM3U\n', | 137 | let element; |
143 | element; | 138 | |
144 | parseStream.on('data', function(elem) { | 139 | this.parseStream.on('data', function(elem) { |
145 | element = elem; | 140 | element = elem; |
146 | }); | 141 | }); |
147 | lineStream.push(manifest); | 142 | this.lineStream.push(manifest); |
148 | 143 | ||
149 | ok(element, 'an event was triggered'); | 144 | QUnit.ok(element, 'an event was triggered'); |
150 | strictEqual(element.type, 'tag', 'the line type is tag'); | 145 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
151 | strictEqual(element.tagType, 'm3u', 'the tag type is m3u'); | 146 | QUnit.strictEqual(element.tagType, 'm3u', 'the tag type is m3u'); |
152 | }); | 147 | }); |
153 | 148 | ||
154 | // #EXTINF | 149 | // #EXTINF |
155 | test('parses minimal #EXTINF tags', function() { | 150 | QUnit.test('parses minimal #EXTINF tags', function() { |
156 | var | 151 | let manifest = '#EXTINF\n'; |
157 | manifest = '#EXTINF\n', | 152 | let element; |
158 | element; | 153 | |
159 | parseStream.on('data', function(elem) { | 154 | this.parseStream.on('data', function(elem) { |
160 | element = elem; | 155 | element = elem; |
161 | }); | 156 | }); |
162 | lineStream.push(manifest); | 157 | this.lineStream.push(manifest); |
163 | 158 | ||
164 | ok(element, 'an event was triggered'); | 159 | QUnit.ok(element, 'an event was triggered'); |
165 | strictEqual(element.type, 'tag', 'the line type is tag'); | 160 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
166 | strictEqual(element.tagType, 'inf', 'the tag type is inf'); | 161 | QUnit.strictEqual(element.tagType, 'inf', 'the tag type is inf'); |
167 | }); | 162 | }); |
168 | test('parses #EXTINF tags with durations', function() { | 163 | QUnit.test('parses #EXTINF tags with durations', function() { |
169 | var | 164 | let manifest = '#EXTINF:15\n'; |
170 | manifest = '#EXTINF:15\n', | 165 | let element; |
171 | element; | 166 | |
172 | parseStream.on('data', function(elem) { | 167 | this.parseStream.on('data', function(elem) { |
173 | element = elem; | 168 | element = elem; |
174 | }); | 169 | }); |
175 | lineStream.push(manifest); | 170 | this.lineStream.push(manifest); |
176 | 171 | ||
177 | ok(element, 'an event was triggered'); | 172 | QUnit.ok(element, 'an event was triggered'); |
178 | strictEqual(element.type, 'tag', 'the line type is tag'); | 173 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
179 | strictEqual(element.tagType, 'inf', 'the tag type is inf'); | 174 | QUnit.strictEqual(element.tagType, 'inf', 'the tag type is inf'); |
180 | strictEqual(element.duration, 15, 'the duration is parsed'); | 175 | QUnit.strictEqual(element.duration, 15, 'the duration is parsed'); |
181 | ok(!('title' in element), 'no title is parsed'); | 176 | QUnit.ok(!('title' in element), 'no title is parsed'); |
182 | 177 | ||
183 | manifest = '#EXTINF:21,\n'; | 178 | manifest = '#EXTINF:21,\n'; |
184 | lineStream.push(manifest); | 179 | this.lineStream.push(manifest); |
185 | 180 | ||
186 | ok(element, 'an event was triggered'); | 181 | QUnit.ok(element, 'an event was triggered'); |
187 | strictEqual(element.type, 'tag', 'the line type is tag'); | 182 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
188 | strictEqual(element.tagType, 'inf', 'the tag type is inf'); | 183 | QUnit.strictEqual(element.tagType, 'inf', 'the tag type is inf'); |
189 | strictEqual(element.duration, 21, 'the duration is parsed'); | 184 | QUnit.strictEqual(element.duration, 21, 'the duration is parsed'); |
190 | ok(!('title' in element), 'no title is parsed'); | 185 | QUnit.ok(!('title' in element), 'no title is parsed'); |
191 | }); | 186 | }); |
192 | test('parses #EXTINF tags with a duration and title', function() { | 187 | QUnit.test('parses #EXTINF tags with a duration and title', function() { |
193 | var | 188 | let manifest = '#EXTINF:13,Does anyone really use the title attribute?\n'; |
194 | manifest = '#EXTINF:13,Does anyone really use the title attribute?\n', | 189 | let element; |
195 | element; | 190 | |
196 | parseStream.on('data', function(elem) { | 191 | this.parseStream.on('data', function(elem) { |
197 | element = elem; | 192 | element = elem; |
198 | }); | 193 | }); |
199 | lineStream.push(manifest); | 194 | this.lineStream.push(manifest); |
200 | 195 | ||
201 | ok(element, 'an event was triggered'); | 196 | QUnit.ok(element, 'an event was triggered'); |
202 | strictEqual(element.type, 'tag', 'the line type is tag'); | 197 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
203 | strictEqual(element.tagType, 'inf', 'the tag type is inf'); | 198 | QUnit.strictEqual(element.tagType, 'inf', 'the tag type is inf'); |
204 | strictEqual(element.duration, 13, 'the duration is parsed'); | 199 | QUnit.strictEqual(element.duration, 13, 'the duration is parsed'); |
205 | strictEqual(element.title, | 200 | QUnit.strictEqual(element.title, |
206 | manifest.substring(manifest.indexOf(',') + 1, manifest.length - 1), | 201 | manifest.substring(manifest.indexOf(',') + 1, manifest.length - 1), |
207 | 'the title is parsed'); | 202 | 'the title is parsed'); |
208 | }); | 203 | }); |
209 | test('parses #EXTINF tags with carriage returns', function() { | 204 | QUnit.test('parses #EXTINF tags with carriage returns', function() { |
210 | var | 205 | let manifest = '#EXTINF:13,Does anyone really use the title attribute?\r\n'; |
211 | manifest = '#EXTINF:13,Does anyone really use the title attribute?\r\n', | 206 | let element; |
212 | element; | 207 | |
213 | parseStream.on('data', function(elem) { | 208 | this.parseStream.on('data', function(elem) { |
214 | element = elem; | 209 | element = elem; |
215 | }); | 210 | }); |
216 | lineStream.push(manifest); | 211 | this.lineStream.push(manifest); |
217 | 212 | ||
218 | ok(element, 'an event was triggered'); | 213 | QUnit.ok(element, 'an event was triggered'); |
219 | strictEqual(element.type, 'tag', 'the line type is tag'); | 214 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
220 | strictEqual(element.tagType, 'inf', 'the tag type is inf'); | 215 | QUnit.strictEqual(element.tagType, 'inf', 'the tag type is inf'); |
221 | strictEqual(element.duration, 13, 'the duration is parsed'); | 216 | QUnit.strictEqual(element.duration, 13, 'the duration is parsed'); |
222 | strictEqual(element.title, | 217 | QUnit.strictEqual(element.title, |
223 | manifest.substring(manifest.indexOf(',') + 1, manifest.length - 2), | 218 | manifest.substring(manifest.indexOf(',') + 1, manifest.length - 2), |
224 | 'the title is parsed'); | 219 | 'the title is parsed'); |
225 | }); | 220 | }); |
226 | 221 | ||
227 | // #EXT-X-TARGETDURATION | 222 | // #EXT-X-TARGETDURATION |
228 | test('parses minimal #EXT-X-TARGETDURATION tags', function() { | 223 | QUnit.test('parses minimal #EXT-X-TARGETDURATION tags', function() { |
229 | var | 224 | let manifest = '#EXT-X-TARGETDURATION\n'; |
230 | manifest = '#EXT-X-TARGETDURATION\n', | 225 | let element; |
231 | element; | 226 | |
232 | parseStream.on('data', function(elem) { | 227 | this.parseStream.on('data', function(elem) { |
233 | element = elem; | 228 | element = elem; |
234 | }); | 229 | }); |
235 | lineStream.push(manifest); | 230 | this.lineStream.push(manifest); |
236 | 231 | ||
237 | ok(element, 'an event was triggered'); | 232 | QUnit.ok(element, 'an event was triggered'); |
238 | strictEqual(element.type, 'tag', 'the line type is tag'); | 233 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
239 | strictEqual(element.tagType, 'targetduration', 'the tag type is targetduration'); | 234 | QUnit.strictEqual(element.tagType, 'targetduration', 'the tag type is targetduration'); |
240 | ok(!('duration' in element), 'no duration is parsed'); | 235 | QUnit.ok(!('duration' in element), 'no duration is parsed'); |
241 | }); | 236 | }); |
242 | test('parses #EXT-X-TARGETDURATION with duration', function() { | 237 | QUnit.test('parses #EXT-X-TARGETDURATION with duration', function() { |
243 | var | 238 | let manifest = '#EXT-X-TARGETDURATION:47\n'; |
244 | manifest = '#EXT-X-TARGETDURATION:47\n', | 239 | let element; |
245 | element; | 240 | |
246 | parseStream.on('data', function(elem) { | 241 | this.parseStream.on('data', function(elem) { |
247 | element = elem; | 242 | element = elem; |
248 | }); | 243 | }); |
249 | lineStream.push(manifest); | 244 | this.lineStream.push(manifest); |
250 | 245 | ||
251 | ok(element, 'an event was triggered'); | 246 | QUnit.ok(element, 'an event was triggered'); |
252 | strictEqual(element.type, 'tag', 'the line type is tag'); | 247 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
253 | strictEqual(element.tagType, 'targetduration', 'the tag type is targetduration'); | 248 | QUnit.strictEqual(element.tagType, 'targetduration', 'the tag type is targetduration'); |
254 | strictEqual(element.duration, 47, 'the duration is parsed'); | 249 | QUnit.strictEqual(element.duration, 47, 'the duration is parsed'); |
255 | }); | 250 | }); |
256 | 251 | ||
257 | // #EXT-X-VERSION | 252 | // #EXT-X-VERSION |
258 | test('parses minimal #EXT-X-VERSION tags', function() { | 253 | QUnit.test('parses minimal #EXT-X-VERSION tags', function() { |
259 | var | 254 | let manifest = '#EXT-X-VERSION:\n'; |
260 | manifest = '#EXT-X-VERSION:\n', | 255 | let element; |
261 | element; | 256 | |
262 | parseStream.on('data', function(elem) { | 257 | this.parseStream.on('data', function(elem) { |
263 | element = elem; | 258 | element = elem; |
264 | }); | 259 | }); |
265 | lineStream.push(manifest); | 260 | this.lineStream.push(manifest); |
266 | 261 | ||
267 | ok(element, 'an event was triggered'); | 262 | QUnit.ok(element, 'an event was triggered'); |
268 | strictEqual(element.type, 'tag', 'the line type is tag'); | 263 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
269 | strictEqual(element.tagType, 'version', 'the tag type is version'); | 264 | QUnit.strictEqual(element.tagType, 'version', 'the tag type is version'); |
270 | ok(!('version' in element), 'no version is present'); | 265 | QUnit.ok(!('version' in element), 'no version is present'); |
271 | }); | 266 | }); |
272 | test('parses #EXT-X-VERSION with a version', function() { | 267 | QUnit.test('parses #EXT-X-VERSION with a version', function() { |
273 | var | 268 | let manifest = '#EXT-X-VERSION:99\n'; |
274 | manifest = '#EXT-X-VERSION:99\n', | 269 | let element; |
275 | element; | 270 | |
276 | parseStream.on('data', function(elem) { | 271 | this.parseStream.on('data', function(elem) { |
277 | element = elem; | 272 | element = elem; |
278 | }); | 273 | }); |
279 | lineStream.push(manifest); | 274 | this.lineStream.push(manifest); |
280 | 275 | ||
281 | ok(element, 'an event was triggered'); | 276 | QUnit.ok(element, 'an event was triggered'); |
282 | strictEqual(element.type, 'tag', 'the line type is tag'); | 277 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
283 | strictEqual(element.tagType, 'version', 'the tag type is version'); | 278 | QUnit.strictEqual(element.tagType, 'version', 'the tag type is version'); |
284 | strictEqual(element.version, 99, 'the version is parsed'); | 279 | QUnit.strictEqual(element.version, 99, 'the version is parsed'); |
285 | }); | 280 | }); |
281 | |||
282 | // #EXT-X-MEDIA-SEQUENCE | ||
283 | QUnit.test('parses minimal #EXT-X-MEDIA-SEQUENCE tags', function() { | ||
284 | let manifest = '#EXT-X-MEDIA-SEQUENCE\n'; | ||
285 | let element; | ||
286 | 286 | ||
287 | // #EXT-X-MEDIA-SEQUENCE | 287 | this.parseStream.on('data', function(elem) { |
288 | test('parses minimal #EXT-X-MEDIA-SEQUENCE tags', function() { | ||
289 | var | ||
290 | manifest = '#EXT-X-MEDIA-SEQUENCE\n', | ||
291 | element; | ||
292 | parseStream.on('data', function(elem) { | ||
293 | element = elem; | 288 | element = elem; |
294 | }); | 289 | }); |
295 | lineStream.push(manifest); | 290 | this.lineStream.push(manifest); |
296 | 291 | ||
297 | ok(element, 'an event was triggered'); | 292 | QUnit.ok(element, 'an event was triggered'); |
298 | strictEqual(element.type, 'tag', 'the line type is tag'); | 293 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
299 | strictEqual(element.tagType, 'media-sequence', 'the tag type is media-sequence'); | 294 | QUnit.strictEqual(element.tagType, 'media-sequence', 'the tag type is media-sequence'); |
300 | ok(!('number' in element), 'no number is present'); | 295 | QUnit.ok(!('number' in element), 'no number is present'); |
301 | }); | 296 | }); |
302 | test('parses #EXT-X-MEDIA-SEQUENCE with sequence numbers', function() { | 297 | QUnit.test('parses #EXT-X-MEDIA-SEQUENCE with sequence numbers', function() { |
303 | var | 298 | let manifest = '#EXT-X-MEDIA-SEQUENCE:109\n'; |
304 | manifest = '#EXT-X-MEDIA-SEQUENCE:109\n', | 299 | let element; |
305 | element; | 300 | |
306 | parseStream.on('data', function(elem) { | 301 | this.parseStream.on('data', function(elem) { |
307 | element = elem; | 302 | element = elem; |
308 | }); | 303 | }); |
309 | lineStream.push(manifest); | 304 | this.lineStream.push(manifest); |
310 | 305 | ||
311 | ok(element, 'an event was triggered'); | 306 | QUnit.ok(element, 'an event was triggered'); |
312 | strictEqual(element.type, 'tag', 'the line type is tag'); | 307 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
313 | strictEqual(element.tagType, 'media-sequence', 'the tag type is media-sequence'); | 308 | QUnit.strictEqual(element.tagType, 'media-sequence', 'the tag type is media-sequence'); |
314 | ok(element.number, 109, 'the number is parsed'); | 309 | QUnit.ok(element.number, 109, 'the number is parsed'); |
315 | }); | 310 | }); |
311 | |||
312 | // #EXT-X-PLAYLIST-TYPE | ||
313 | QUnit.test('parses minimal #EXT-X-PLAYLIST-TYPE tags', function() { | ||
314 | let manifest = '#EXT-X-PLAYLIST-TYPE:\n'; | ||
315 | let element; | ||
316 | 316 | ||
317 | // #EXT-X-PLAYLIST-TYPE | 317 | this.parseStream.on('data', function(elem) { |
318 | test('parses minimal #EXT-X-PLAYLIST-TYPE tags', function() { | ||
319 | var | ||
320 | manifest = '#EXT-X-PLAYLIST-TYPE:\n', | ||
321 | element; | ||
322 | parseStream.on('data', function(elem) { | ||
323 | element = elem; | 318 | element = elem; |
324 | }); | 319 | }); |
325 | lineStream.push(manifest); | 320 | this.lineStream.push(manifest); |
326 | 321 | ||
327 | ok(element, 'an event was triggered'); | 322 | QUnit.ok(element, 'an event was triggered'); |
328 | strictEqual(element.type, 'tag', 'the line type is tag'); | 323 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
329 | strictEqual(element.tagType, 'playlist-type', 'the tag type is playlist-type'); | 324 | QUnit.strictEqual(element.tagType, 'playlist-type', 'the tag type is playlist-type'); |
330 | ok(!('playlistType' in element), 'no playlist type is present'); | 325 | QUnit.ok(!('playlistType' in element), 'no playlist type is present'); |
331 | }); | 326 | }); |
332 | test('parses #EXT-X-PLAYLIST-TYPE with mutability info', function() { | 327 | QUnit.test('parses #EXT-X-PLAYLIST-TYPE with mutability info', function() { |
333 | var | 328 | let manifest = '#EXT-X-PLAYLIST-TYPE:EVENT\n'; |
334 | manifest = '#EXT-X-PLAYLIST-TYPE:EVENT\n', | 329 | let element; |
335 | element; | 330 | |
336 | parseStream.on('data', function(elem) { | 331 | this.parseStream.on('data', function(elem) { |
337 | element = elem; | 332 | element = elem; |
338 | }); | 333 | }); |
339 | lineStream.push(manifest); | 334 | this.lineStream.push(manifest); |
340 | 335 | ||
341 | ok(element, 'an event was triggered'); | 336 | QUnit.ok(element, 'an event was triggered'); |
342 | strictEqual(element.type, 'tag', 'the line type is tag'); | 337 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
343 | strictEqual(element.tagType, 'playlist-type', 'the tag type is playlist-type'); | 338 | QUnit.strictEqual(element.tagType, 'playlist-type', 'the tag type is playlist-type'); |
344 | strictEqual(element.playlistType, 'EVENT', 'the playlist type is EVENT'); | 339 | QUnit.strictEqual(element.playlistType, 'EVENT', 'the playlist type is EVENT'); |
345 | 340 | ||
346 | manifest = '#EXT-X-PLAYLIST-TYPE:VOD\n'; | 341 | manifest = '#EXT-X-PLAYLIST-TYPE:VOD\n'; |
347 | lineStream.push(manifest); | 342 | this.lineStream.push(manifest); |
348 | ok(element, 'an event was triggered'); | 343 | QUnit.ok(element, 'an event was triggered'); |
349 | strictEqual(element.type, 'tag', 'the line type is tag'); | 344 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
350 | strictEqual(element.tagType, 'playlist-type', 'the tag type is playlist-type'); | 345 | QUnit.strictEqual(element.tagType, 'playlist-type', 'the tag type is playlist-type'); |
351 | strictEqual(element.playlistType, 'VOD', 'the playlist type is VOD'); | 346 | QUnit.strictEqual(element.playlistType, 'VOD', 'the playlist type is VOD'); |
352 | 347 | ||
353 | manifest = '#EXT-X-PLAYLIST-TYPE:nonsense\n'; | 348 | manifest = '#EXT-X-PLAYLIST-TYPE:nonsense\n'; |
354 | lineStream.push(manifest); | 349 | this.lineStream.push(manifest); |
355 | ok(element, 'an event was triggered'); | 350 | QUnit.ok(element, 'an event was triggered'); |
356 | strictEqual(element.type, 'tag', 'the line type is tag'); | 351 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
357 | strictEqual(element.tagType, 'playlist-type', 'the tag type is playlist-type'); | 352 | QUnit.strictEqual(element.tagType, 'playlist-type', 'the tag type is playlist-type'); |
358 | strictEqual(element.playlistType, 'nonsense', 'the playlist type is parsed'); | 353 | QUnit.strictEqual(element.playlistType, 'nonsense', 'the playlist type is parsed'); |
359 | }); | 354 | }); |
360 | 355 | ||
361 | // #EXT-X-BYTERANGE | 356 | // #EXT-X-BYTERANGE |
362 | test('parses minimal #EXT-X-BYTERANGE tags', function() { | 357 | QUnit.test('parses minimal #EXT-X-BYTERANGE tags', function() { |
363 | var | 358 | let manifest = '#EXT-X-BYTERANGE\n'; |
364 | manifest = '#EXT-X-BYTERANGE\n', | 359 | let element; |
365 | element; | 360 | |
366 | parseStream.on('data', function(elem) { | 361 | this.parseStream.on('data', function(elem) { |
367 | element = elem; | 362 | element = elem; |
368 | }); | 363 | }); |
369 | lineStream.push(manifest); | 364 | this.lineStream.push(manifest); |
370 | 365 | ||
371 | ok(element, 'an event was triggered'); | 366 | QUnit.ok(element, 'an event was triggered'); |
372 | strictEqual(element.type, 'tag', 'the line type is tag'); | 367 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
373 | strictEqual(element.tagType, 'byterange', 'the tag type is byterange'); | 368 | QUnit.strictEqual(element.tagType, 'byterange', 'the tag type is byterange'); |
374 | ok(!('length' in element), 'no length is present'); | 369 | QUnit.ok(!('length' in element), 'no length is present'); |
375 | ok(!('offset' in element), 'no offset is present'); | 370 | QUnit.ok(!('offset' in element), 'no offset is present'); |
376 | }); | 371 | }); |
377 | test('parses #EXT-X-BYTERANGE with length and offset', function() { | 372 | QUnit.test('parses #EXT-X-BYTERANGE with length and offset', function() { |
378 | var | 373 | let manifest = '#EXT-X-BYTERANGE:45\n'; |
379 | manifest = '#EXT-X-BYTERANGE:45\n', | 374 | let element; |
380 | element; | 375 | |
381 | parseStream.on('data', function(elem) { | 376 | this.parseStream.on('data', function(elem) { |
382 | element = elem; | 377 | element = elem; |
383 | }); | 378 | }); |
384 | lineStream.push(manifest); | 379 | this.lineStream.push(manifest); |
385 | 380 | ||
386 | ok(element, 'an event was triggered'); | 381 | QUnit.ok(element, 'an event was triggered'); |
387 | strictEqual(element.type, 'tag', 'the line type is tag'); | 382 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
388 | strictEqual(element.tagType, 'byterange', 'the tag type is byterange'); | 383 | QUnit.strictEqual(element.tagType, 'byterange', 'the tag type is byterange'); |
389 | strictEqual(element.length, 45, 'length is parsed'); | 384 | QUnit.strictEqual(element.length, 45, 'length is parsed'); |
390 | ok(!('offset' in element), 'no offset is present'); | 385 | QUnit.ok(!('offset' in element), 'no offset is present'); |
391 | 386 | ||
392 | manifest = '#EXT-X-BYTERANGE:108@16\n'; | 387 | manifest = '#EXT-X-BYTERANGE:108@16\n'; |
393 | lineStream.push(manifest); | 388 | this.lineStream.push(manifest); |
394 | ok(element, 'an event was triggered'); | 389 | QUnit.ok(element, 'an event was triggered'); |
395 | strictEqual(element.type, 'tag', 'the line type is tag'); | 390 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
396 | strictEqual(element.tagType, 'byterange', 'the tag type is byterange'); | 391 | QUnit.strictEqual(element.tagType, 'byterange', 'the tag type is byterange'); |
397 | strictEqual(element.length, 108, 'length is parsed'); | 392 | QUnit.strictEqual(element.length, 108, 'length is parsed'); |
398 | strictEqual(element.offset, 16, 'offset is parsed'); | 393 | QUnit.strictEqual(element.offset, 16, 'offset is parsed'); |
399 | }); | 394 | }); |
400 | 395 | ||
401 | // #EXT-X-ALLOW-CACHE | 396 | // #EXT-X-ALLOW-CACHE |
402 | test('parses minimal #EXT-X-ALLOW-CACHE tags', function() { | 397 | QUnit.test('parses minimal #EXT-X-ALLOW-CACHE tags', function() { |
403 | var | 398 | let manifest = '#EXT-X-ALLOW-CACHE:\n'; |
404 | manifest = '#EXT-X-ALLOW-CACHE:\n', | 399 | let element; |
405 | element; | 400 | |
406 | parseStream.on('data', function(elem) { | 401 | this.parseStream.on('data', function(elem) { |
407 | element = elem; | 402 | element = elem; |
408 | }); | 403 | }); |
409 | lineStream.push(manifest); | 404 | this.lineStream.push(manifest); |
410 | 405 | ||
411 | ok(element, 'an event was triggered'); | 406 | QUnit.ok(element, 'an event was triggered'); |
412 | strictEqual(element.type, 'tag', 'the line type is tag'); | 407 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
413 | strictEqual(element.tagType, 'allow-cache', 'the tag type is allow-cache'); | 408 | QUnit.strictEqual(element.tagType, 'allow-cache', 'the tag type is allow-cache'); |
414 | ok(!('allowed' in element), 'no allowed is present'); | 409 | QUnit.ok(!('allowed' in element), 'no allowed is present'); |
415 | }); | 410 | }); |
416 | test('parses valid #EXT-X-ALLOW-CACHE tags', function() { | 411 | QUnit.test('parses valid #EXT-X-ALLOW-CACHE tags', function() { |
417 | var | 412 | let manifest = '#EXT-X-ALLOW-CACHE:YES\n'; |
418 | manifest = '#EXT-X-ALLOW-CACHE:YES\n', | 413 | let element; |
419 | element; | 414 | |
420 | parseStream.on('data', function(elem) { | 415 | this.parseStream.on('data', function(elem) { |
421 | element = elem; | 416 | element = elem; |
422 | }); | 417 | }); |
423 | lineStream.push(manifest); | 418 | this.lineStream.push(manifest); |
424 | 419 | ||
425 | ok(element, 'an event was triggered'); | 420 | QUnit.ok(element, 'an event was triggered'); |
426 | strictEqual(element.type, 'tag', 'the line type is tag'); | 421 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
427 | strictEqual(element.tagType, 'allow-cache', 'the tag type is allow-cache'); | 422 | QUnit.strictEqual(element.tagType, 'allow-cache', 'the tag type is allow-cache'); |
428 | ok(element.allowed, 'allowed is parsed'); | 423 | QUnit.ok(element.allowed, 'allowed is parsed'); |
429 | 424 | ||
430 | manifest = '#EXT-X-ALLOW-CACHE:NO\n'; | 425 | manifest = '#EXT-X-ALLOW-CACHE:NO\n'; |
431 | lineStream.push(manifest); | 426 | this.lineStream.push(manifest); |
432 | 427 | ||
433 | ok(element, 'an event was triggered'); | 428 | QUnit.ok(element, 'an event was triggered'); |
434 | strictEqual(element.type, 'tag', 'the line type is tag'); | 429 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
435 | strictEqual(element.tagType, 'allow-cache', 'the tag type is allow-cache'); | 430 | QUnit.strictEqual(element.tagType, 'allow-cache', 'the tag type is allow-cache'); |
436 | ok(!element.allowed, 'allowed is parsed'); | 431 | QUnit.ok(!element.allowed, 'allowed is parsed'); |
437 | }); | 432 | }); |
438 | // #EXT-X-STREAM-INF | 433 | // #EXT-X-STREAM-INF |
439 | test('parses minimal #EXT-X-STREAM-INF tags', function() { | 434 | QUnit.test('parses minimal #EXT-X-STREAM-INF tags', function() { |
440 | var | 435 | let manifest = '#EXT-X-STREAM-INF\n'; |
441 | manifest = '#EXT-X-STREAM-INF\n', | 436 | let element; |
442 | element; | 437 | |
443 | parseStream.on('data', function(elem) { | 438 | this.parseStream.on('data', function(elem) { |
444 | element = elem; | 439 | element = elem; |
445 | }); | 440 | }); |
446 | lineStream.push(manifest); | 441 | this.lineStream.push(manifest); |
447 | 442 | ||
448 | ok(element, 'an event was triggered'); | 443 | QUnit.ok(element, 'an event was triggered'); |
449 | strictEqual(element.type, 'tag', 'the line type is tag'); | 444 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
450 | strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); | 445 | QUnit.strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); |
451 | ok(!('attributes' in element), 'no attributes are present'); | 446 | QUnit.ok(!('attributes' in element), 'no attributes are present'); |
452 | }); | 447 | }); |
453 | test('parses #EXT-X-STREAM-INF with common attributes', function() { | 448 | QUnit.test('parses #EXT-X-STREAM-INF with common attributes', function() { |
454 | var | 449 | let manifest = '#EXT-X-STREAM-INF:BANDWIDTH=14400\n'; |
455 | manifest = '#EXT-X-STREAM-INF:BANDWIDTH=14400\n', | 450 | let element; |
456 | element; | 451 | |
457 | parseStream.on('data', function(elem) { | 452 | this.parseStream.on('data', function(elem) { |
458 | element = elem; | 453 | element = elem; |
459 | }); | 454 | }); |
460 | lineStream.push(manifest); | 455 | this.lineStream.push(manifest); |
461 | 456 | ||
462 | ok(element, 'an event was triggered'); | 457 | QUnit.ok(element, 'an event was triggered'); |
463 | strictEqual(element.type, 'tag', 'the line type is tag'); | 458 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
464 | strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); | 459 | QUnit.strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); |
465 | strictEqual(element.attributes.BANDWIDTH, 14400, 'bandwidth is parsed'); | 460 | QUnit.strictEqual(element.attributes.BANDWIDTH, 14400, 'bandwidth is parsed'); |
466 | 461 | ||
467 | manifest = '#EXT-X-STREAM-INF:PROGRAM-ID=7\n'; | 462 | manifest = '#EXT-X-STREAM-INF:PROGRAM-ID=7\n'; |
468 | lineStream.push(manifest); | 463 | this.lineStream.push(manifest); |
469 | 464 | ||
470 | ok(element, 'an event was triggered'); | 465 | QUnit.ok(element, 'an event was triggered'); |
471 | strictEqual(element.type, 'tag', 'the line type is tag'); | 466 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
472 | strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); | 467 | QUnit.strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); |
473 | strictEqual(element.attributes['PROGRAM-ID'], 7, 'program-id is parsed'); | 468 | QUnit.strictEqual(element.attributes['PROGRAM-ID'], 7, 'program-id is parsed'); |
474 | 469 | ||
475 | manifest = '#EXT-X-STREAM-INF:RESOLUTION=396x224\n'; | 470 | manifest = '#EXT-X-STREAM-INF:RESOLUTION=396x224\n'; |
476 | lineStream.push(manifest); | 471 | this.lineStream.push(manifest); |
477 | 472 | ||
478 | ok(element, 'an event was triggered'); | 473 | QUnit.ok(element, 'an event was triggered'); |
479 | strictEqual(element.type, 'tag', 'the line type is tag'); | 474 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
480 | strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); | 475 | QUnit.strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); |
481 | strictEqual(element.attributes.RESOLUTION.width, 396, 'width is parsed'); | 476 | QUnit.strictEqual(element.attributes.RESOLUTION.width, 396, 'width is parsed'); |
482 | strictEqual(element.attributes.RESOLUTION.height, 224, 'heigth is parsed'); | 477 | QUnit.strictEqual(element.attributes.RESOLUTION.height, 224, 'heigth is parsed'); |
483 | 478 | ||
484 | manifest = '#EXT-X-STREAM-INF:CODECS="avc1.4d400d, mp4a.40.2"\n'; | 479 | manifest = '#EXT-X-STREAM-INF:CODECS="avc1.4d400d, mp4a.40.2"\n'; |
485 | lineStream.push(manifest); | 480 | this.lineStream.push(manifest); |
486 | 481 | ||
487 | ok(element, 'an event was triggered'); | 482 | QUnit.ok(element, 'an event was triggered'); |
488 | strictEqual(element.type, 'tag', 'the line type is tag'); | 483 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
489 | strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); | 484 | QUnit.strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); |
490 | strictEqual(element.attributes.CODECS, | 485 | QUnit.strictEqual(element.attributes.CODECS, |
491 | 'avc1.4d400d, mp4a.40.2', | 486 | 'avc1.4d400d, mp4a.40.2', |
492 | 'codecs are parsed'); | 487 | 'codecs are parsed'); |
493 | }); | 488 | }); |
494 | test('parses #EXT-X-STREAM-INF with arbitrary attributes', function() { | 489 | QUnit.test('parses #EXT-X-STREAM-INF with arbitrary attributes', function() { |
495 | var | 490 | let manifest = '#EXT-X-STREAM-INF:NUMERIC=24,ALPHA=Value,MIXED=123abc\n'; |
496 | manifest = '#EXT-X-STREAM-INF:NUMERIC=24,ALPHA=Value,MIXED=123abc\n', | 491 | let element; |
497 | element; | 492 | |
498 | parseStream.on('data', function(elem) { | 493 | this.parseStream.on('data', function(elem) { |
499 | element = elem; | 494 | element = elem; |
500 | }); | 495 | }); |
501 | lineStream.push(manifest); | 496 | this.lineStream.push(manifest); |
502 | 497 | ||
503 | ok(element, 'an event was triggered'); | 498 | QUnit.ok(element, 'an event was triggered'); |
504 | strictEqual(element.type, 'tag', 'the line type is tag'); | 499 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
505 | strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); | 500 | QUnit.strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf'); |
506 | strictEqual(element.attributes.NUMERIC, '24', 'numeric attributes are parsed'); | 501 | QUnit.strictEqual(element.attributes.NUMERIC, '24', 'numeric attributes are parsed'); |
507 | strictEqual(element.attributes.ALPHA, 'Value', 'alphabetic attributes are parsed'); | 502 | QUnit.strictEqual(element.attributes.ALPHA, |
508 | strictEqual(element.attributes.MIXED, '123abc', 'mixed attributes are parsed'); | 503 | 'Value', |
509 | }); | 504 | 'alphabetic attributes are parsed'); |
510 | // #EXT-X-ENDLIST | 505 | QUnit.strictEqual(element.attributes.MIXED, '123abc', 'mixed attributes are parsed'); |
511 | test('parses #EXT-X-ENDLIST tags', function() { | 506 | }); |
512 | var | 507 | // #EXT-X-ENDLIST |
513 | manifest = '#EXT-X-ENDLIST\n', | 508 | QUnit.test('parses #EXT-X-ENDLIST tags', function() { |
514 | element; | 509 | let manifest = '#EXT-X-ENDLIST\n'; |
515 | parseStream.on('data', function(elem) { | 510 | let element; |
511 | |||
512 | this.parseStream.on('data', function(elem) { | ||
516 | element = elem; | 513 | element = elem; |
517 | }); | 514 | }); |
518 | lineStream.push(manifest); | 515 | this.lineStream.push(manifest); |
519 | 516 | ||
520 | ok(element, 'an event was triggered'); | 517 | QUnit.ok(element, 'an event was triggered'); |
521 | strictEqual(element.type, 'tag', 'the line type is tag'); | 518 | QUnit.strictEqual(element.type, 'tag', 'the line type is tag'); |
522 | strictEqual(element.tagType, 'endlist', 'the tag type is stream-inf'); | 519 | QUnit.strictEqual(element.tagType, 'endlist', 'the tag type is stream-inf'); |
523 | }); | 520 | }); |
521 | |||
522 | // #EXT-X-KEY | ||
523 | QUnit.test('parses valid #EXT-X-KEY tags', function() { | ||
524 | let manifest = | ||
525 | '#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"\n'; | ||
526 | let element; | ||
524 | 527 | ||
525 | // #EXT-X-KEY | 528 | this.parseStream.on('data', function(elem) { |
526 | test('parses valid #EXT-X-KEY tags', function() { | ||
527 | var | ||
528 | manifest = '#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"\n', | ||
529 | element; | ||
530 | parseStream.on('data', function(elem) { | ||
531 | element = elem; | 529 | element = elem; |
532 | }); | 530 | }); |
533 | lineStream.push(manifest); | 531 | this.lineStream.push(manifest); |
534 | 532 | ||
535 | ok(element, 'an event was triggered'); | 533 | QUnit.ok(element, 'an event was triggered'); |
536 | deepEqual(element, { | 534 | QUnit.deepEqual(element, { |
537 | type: 'tag', | 535 | type: 'tag', |
538 | tagType: 'key', | 536 | tagType: 'key', |
539 | attributes: { | 537 | attributes: { |
... | @@ -543,9 +541,9 @@ | ... | @@ -543,9 +541,9 @@ |
543 | }, 'parsed a valid key'); | 541 | }, 'parsed a valid key'); |
544 | 542 | ||
545 | manifest = '#EXT-X-KEY:URI="https://example.com/key#1",METHOD=FutureType-1024\n'; | 543 | manifest = '#EXT-X-KEY:URI="https://example.com/key#1",METHOD=FutureType-1024\n'; |
546 | lineStream.push(manifest); | 544 | this.lineStream.push(manifest); |
547 | ok(element, 'an event was triggered'); | 545 | QUnit.ok(element, 'an event was triggered'); |
548 | deepEqual(element, { | 546 | QUnit.deepEqual(element, { |
549 | type: 'tag', | 547 | type: 'tag', |
550 | tagType: 'key', | 548 | tagType: 'key', |
551 | attributes: { | 549 | attributes: { |
... | @@ -555,92 +553,93 @@ | ... | @@ -555,92 +553,93 @@ |
555 | }, 'parsed the attribute list independent of order'); | 553 | }, 'parsed the attribute list independent of order'); |
556 | 554 | ||
557 | manifest = '#EXT-X-KEY:IV=1234567890abcdef1234567890abcdef\n'; | 555 | manifest = '#EXT-X-KEY:IV=1234567890abcdef1234567890abcdef\n'; |
558 | lineStream.push(manifest); | 556 | this.lineStream.push(manifest); |
559 | ok(element.attributes.IV, 'detected an IV attribute'); | 557 | QUnit.ok(element.attributes.IV, 'detected an IV attribute'); |
560 | deepEqual(element.attributes.IV, new Uint32Array([ | 558 | QUnit.deepEqual(element.attributes.IV, new Uint32Array([ |
561 | 0x12345678, | 559 | 0x12345678, |
562 | 0x90abcdef, | 560 | 0x90abcdef, |
563 | 0x12345678, | 561 | 0x12345678, |
564 | 0x90abcdef | 562 | 0x90abcdef |
565 | ]), 'parsed an IV value'); | 563 | ]), 'parsed an IV value'); |
566 | }); | 564 | }); |
565 | |||
566 | QUnit.test('parses minimal #EXT-X-KEY tags', function() { | ||
567 | let manifest = '#EXT-X-KEY:\n'; | ||
568 | let element; | ||
567 | 569 | ||
568 | test('parses minimal #EXT-X-KEY tags', function() { | 570 | this.parseStream.on('data', function(elem) { |
569 | var | ||
570 | manifest = '#EXT-X-KEY:\n', | ||
571 | element; | ||
572 | parseStream.on('data', function(elem) { | ||
573 | element = elem; | 571 | element = elem; |
574 | }); | 572 | }); |
575 | lineStream.push(manifest); | 573 | this.lineStream.push(manifest); |
576 | 574 | ||
577 | ok(element, 'an event was triggered'); | 575 | QUnit.ok(element, 'an event was triggered'); |
578 | deepEqual(element, { | 576 | QUnit.deepEqual(element, { |
579 | type: 'tag', | 577 | type: 'tag', |
580 | tagType: 'key' | 578 | tagType: 'key' |
581 | }, 'parsed a minimal key tag'); | 579 | }, 'parsed a minimal key tag'); |
582 | }); | 580 | }); |
581 | |||
582 | QUnit.test('parses lightly-broken #EXT-X-KEY tags', function() { | ||
583 | let manifest = '#EXT-X-KEY:URI=\'https://example.com/single-quote\',METHOD=AES-128\n'; | ||
584 | let element; | ||
583 | 585 | ||
584 | test('parses lightly-broken #EXT-X-KEY tags', function() { | 586 | this.parseStream.on('data', function(elem) { |
585 | var | ||
586 | manifest = '#EXT-X-KEY:URI=\'https://example.com/single-quote\',METHOD=AES-128\n', | ||
587 | element; | ||
588 | parseStream.on('data', function(elem) { | ||
589 | element = elem; | 587 | element = elem; |
590 | }); | 588 | }); |
591 | lineStream.push(manifest); | 589 | this.lineStream.push(manifest); |
592 | 590 | ||
593 | strictEqual(element.attributes.URI, | 591 | QUnit.strictEqual(element.attributes.URI, |
594 | 'https://example.com/single-quote', | 592 | 'https://example.com/single-quote', |
595 | 'parsed a single-quoted uri'); | 593 | 'parsed a single-quoted uri'); |
596 | 594 | ||
597 | element = null; | 595 | element = null; |
598 | manifest = '#EXT-X-KEYURI="https://example.com/key",METHOD=AES-128\n'; | 596 | manifest = '#EXT-X-KEYURI="https://example.com/key",METHOD=AES-128\n'; |
599 | lineStream.push(manifest); | 597 | this.lineStream.push(manifest); |
600 | strictEqual(element.tagType, 'key', 'parsed the tag type'); | 598 | QUnit.strictEqual(element.tagType, 'key', 'parsed the tag type'); |
601 | strictEqual(element.attributes.URI, | 599 | QUnit.strictEqual(element.attributes.URI, |
602 | 'https://example.com/key', | 600 | 'https://example.com/key', |
603 | 'inferred a colon after the tag type'); | 601 | 'inferred a colon after the tag type'); |
604 | 602 | ||
605 | element = null; | 603 | element = null; |
606 | manifest = '#EXT-X-KEY: URI = "https://example.com/key",METHOD=AES-128\n'; | 604 | manifest = '#EXT-X-KEY: URI = "https://example.com/key",METHOD=AES-128\n'; |
607 | lineStream.push(manifest); | 605 | this.lineStream.push(manifest); |
608 | strictEqual(element.attributes.URI, | 606 | QUnit.strictEqual(element.attributes.URI, |
609 | 'https://example.com/key', | 607 | 'https://example.com/key', |
610 | 'trims and removes quotes around the URI'); | 608 | 'trims and removes quotes around the URI'); |
611 | }); | 609 | }); |
610 | |||
611 | QUnit.test('ignores empty lines', function() { | ||
612 | let manifest = '\n'; | ||
613 | let event = false; | ||
612 | 614 | ||
613 | test('ignores empty lines', function() { | 615 | this.parseStream.on('data', function() { |
614 | var | ||
615 | manifest = '\n', | ||
616 | event = false; | ||
617 | parseStream.on('data', function() { | ||
618 | event = true; | 616 | event = true; |
619 | }); | 617 | }); |
620 | lineStream.push(manifest); | 618 | this.lineStream.push(manifest); |
621 | 619 | ||
622 | ok(!event, 'no event is triggered'); | 620 | QUnit.ok(!event, 'no event is triggered'); |
623 | }); | 621 | }); |
624 | 622 | ||
625 | QUnit.module('m3u8 parser'); | 623 | QUnit.module('m3u8 parser'); |
626 | 624 | ||
627 | test('can be constructed', function() { | 625 | QUnit.test('can be constructed', function() { |
628 | notStrictEqual(new Parser(), undefined, 'parser is defined'); | 626 | QUnit.notStrictEqual(typeof new Parser(), 'undefined', 'parser is defined'); |
629 | }); | 627 | }); |
630 | 628 | ||
631 | QUnit.module('m3u8s'); | 629 | QUnit.module('m3u8s'); |
632 | 630 | ||
633 | test('parses static manifests as expected', function() { | 631 | QUnit.test('parses static manifests as expected', function() { |
634 | var key; | 632 | let key; |
635 | for (key in window.manifests) { | 633 | |
636 | if (window.expected[key]) { | 634 | for (key in testDataManifests) { |
637 | parser = new Parser(); | 635 | if (testDataExpected[key]) { |
638 | parser.push(window.manifests[key]); | 636 | let parser = new Parser(); |
639 | deepEqual(parser.manifest, | 637 | |
640 | window.expected[key], | 638 | parser.push(testDataManifests[key]); |
641 | key + '.m3u8 was parsed correctly'); | 639 | QUnit.deepEqual(parser.manifest, |
640 | testDataExpected[key], | ||
641 | key + '.m3u8 was parsed correctly' | ||
642 | ); | ||
642 | } | 643 | } |
643 | } | 644 | } |
644 | }); | 645 | }); |
645 | |||
646 | })(window, window.console); | ... | ... |
test/stub.test.js
0 → 100644
-
Please register or sign in to post a comment