Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
brainfood
/
videojs-contrib-hls
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
52308f18
authored
2016-02-01 14:56:28 -0500
by
brandonocasey
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
fixing code review issues
1 parent
a2a34318
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
77 additions
and
72 deletions
.gitignore
scripts/manifest-data.js
src/m3u8/index.js
test/m3u8.test.js
test/stub.test.js
.gitignore
View file @
52308f1
...
...
@@ -34,5 +34,5 @@ dist-test/
docs/api/
es5/
tmp
test/
data/
manifests.js
test/
data/
expected.js
test/
test-
manifests.js
test/
test-
expected.js
...
...
scripts/manifest-data.js
View file @
52308f1
var
fs
=
require
(
'fs'
);
var
path
=
require
(
'path'
);
var
shelljs
=
require
(
'shelljs'
);
var
basePath
=
path
.
resolve
(
__dirname
,
'..'
);
var
testDataDir
=
path
.
join
(
basePath
,
'test'
,
'data'
);
var
testDataDir
=
path
.
join
(
basePath
,
'test'
);
var
manifestDir
=
path
.
join
(
basePath
,
'utils'
,
'manifest'
);
var
manifestFilepath
=
path
.
join
(
testDataDir
,
'manifests.js'
);
var
expectedFilepath
=
path
.
join
(
testDataDir
,
'expected.js'
);
var
manifestFilepath
=
path
.
join
(
testDataDir
,
'test-manifests.js'
);
var
expectedFilepath
=
path
.
join
(
testDataDir
,
'test-expected.js'
);
var
build
=
function
()
{
var
manifests
=
'export default {\n'
;
var
expected
=
'export default {\n'
;
shelljs
.
mkdir
(
'-p'
,
testDataDir
);
var
files
=
fs
.
readdirSync
(
manifestDir
);
while
(
files
.
length
>
0
)
{
var
file
=
path
.
resolve
(
manifestDir
,
files
.
shift
());
...
...
src/m3u8/index.js
View file @
52308f1
...
...
@@ -35,29 +35,6 @@ export class LineStream extends Stream {
}
}
/**
* A line-level M3U8 parser event stream. It expects to receive input one
* line at a time and performs a context-free parse of its contents. A stream
* interpretation of a manifest can be useful if the manifest is expected to
* be too large to fit comfortably into memory or the entirety of the input
* is not immediately available. Otherwise, it's probably much easier to work
* with a regular `Parser` object.
*
* Produces `data` events with an object that captures the parser's
* interpretation of the input. That object has a property `tag` that is one
* of `uri`, `comment`, or `tag`. URIs only have a single additional
* property, `line`, which captures the entirety of the input without
* interpretation. Comments similarly have a single additional property
* `text` which is the input without the leading `#`.
*
* Tags always have a property `tagType` which is the lower-cased version of
* the M3U8 directive without the `#EXT` or `#EXT-X-` prefix. For instance,
* `#EXT-X-MEDIA-SEQUENCE` becomes `media-sequence` when parsed. Unrecognized
* tags are given the tag type `unknown` and a single additional property
* `data` with the remainder of the input.
*/
// "forgiving" attribute list psuedo-grammar:
// attributes -> keyvalue (',' keyvalue)*
// keyvalue -> key '=' value
...
...
@@ -95,6 +72,27 @@ const parseAttributes = function(attributes) {
return
result
;
};
/**
* A line-level M3U8 parser event stream. It expects to receive input one
* line at a time and performs a context-free parse of its contents. A stream
* interpretation of a manifest can be useful if the manifest is expected to
* be too large to fit comfortably into memory or the entirety of the input
* is not immediately available. Otherwise, it's probably much easier to work
* with a regular `Parser` object.
*
* Produces `data` events with an object that captures the parser's
* interpretation of the input. That object has a property `tag` that is one
* of `uri`, `comment`, or `tag`. URIs only have a single additional
* property, `line`, which captures the entirety of the input without
* interpretation. Comments similarly have a single additional property
* `text` which is the input without the leading `#`.
*
* Tags always have a property `tagType` which is the lower-cased version of
* the M3U8 directive without the `#EXT` or `#EXT-X-` prefix. For instance,
* `#EXT-X-MEDIA-SEQUENCE` becomes `media-sequence` when parsed. Unrecognized
* tags are given the tag type `unknown` and a single additional property
* `data` with the remainder of the input.
*/
export
class
ParseStream
extends
Stream
{
constructor
()
{
super
();
...
...
@@ -341,7 +339,24 @@ export class ParseStream extends Stream {
}
}
/**
* A parser for M3U8 files. The current interpretation of the input is
* exposed as a property `manifest` on parser objects. It's just two lines to
* create and parse a manifest once you have the contents available as a string:
*
* ```js
* var parser = new videojs.m3u8.Parser();
* parser.push(xhr.responseText);
* ```
*
* New input can later be applied to update the manifest object by calling
* `push` again.
*
* The parser attempts to create a usable manifest object even if the
* underlying input is somewhat nonsensical. It emits `info` and `warning`
* events during the parse if it encounters input that seems invalid or
* requires some property of the manifest object to be defaulted.
*/
export
class
Parser
extends
Stream
{
constructor
()
{
super
();
...
...
@@ -493,10 +508,8 @@ export class Parser extends Stream {
if
(
!
currentUri
.
attributes
)
{
currentUri
.
attributes
=
{};
}
currentUri
.
attributes
=
mergeOptions
(
currentUri
.
attributes
,
entry
.
attributes
);
currentUri
.
attributes
=
mergeOptions
(
currentUri
.
attributes
,
entry
.
attributes
);
},
discontinuity
()
{
currentUri
.
discontinuity
=
true
;
...
...
test/m3u8.test.js
View file @
52308f1
import
{
ParseStream
,
LineStream
,
Parser
}
from
'../src/m3u8'
;
import
QUnit
from
'qunit'
;
import
testDataExpected
from
'./
data/
expected.js'
;
import
testDataManifests
from
'./
data/
manifests.js'
;
import
testDataExpected
from
'./
test-
expected.js'
;
import
testDataManifests
from
'./
test-
manifests.js'
;
QUnit
.
module
(
'LineStream'
,
{
beforeEach
()
{
...
...
@@ -68,11 +68,9 @@ QUnit.test('stops sending events after deregistering', function() {
this
.
lineStream
.
on
(
'data'
,
temporary
);
this
.
lineStream
.
on
(
'data'
,
permanent
);
this
.
lineStream
.
push
(
'line one\n'
);
QUnit
.
strictEqual
(
temporaryLines
.
length
,
permanentLines
.
length
,
'both callbacks receive the event'
);
QUnit
.
strictEqual
(
temporaryLines
.
length
,
permanentLines
.
length
,
'both callbacks receive the event'
);
QUnit
.
ok
(
this
.
lineStream
.
off
(
'data'
,
temporary
),
'a listener was removed'
);
this
.
lineStream
.
push
(
'line two\n'
);
...
...
@@ -99,8 +97,8 @@ QUnit.test('parses comment lines', function() {
QUnit
.
ok
(
element
,
'an event was triggered'
);
QUnit
.
strictEqual
(
element
.
type
,
'comment'
,
'the type is comment'
);
QUnit
.
strictEqual
(
element
.
text
,
manifest
.
slice
(
1
,
manifest
.
length
-
1
),
'the comment text is parsed'
);
manifest
.
slice
(
1
,
manifest
.
length
-
1
),
'the comment text is parsed'
);
});
QUnit
.
test
(
'parses uri lines'
,
function
()
{
let
manifest
=
'any non-blank line that does not start with a hash-mark is a URI\n'
;
...
...
@@ -114,8 +112,8 @@ QUnit.test('parses uri lines', function() {
QUnit
.
ok
(
element
,
'an event was triggered'
);
QUnit
.
strictEqual
(
element
.
type
,
'uri'
,
'the type is uri'
);
QUnit
.
strictEqual
(
element
.
uri
,
manifest
.
substring
(
0
,
manifest
.
length
-
1
),
'the uri text is parsed'
);
manifest
.
substring
(
0
,
manifest
.
length
-
1
),
'the uri text is parsed'
);
});
QUnit
.
test
(
'parses unknown tag types'
,
function
()
{
let
manifest
=
'#EXT-X-EXAMPLE-TAG:some,additional,stuff\n'
;
...
...
@@ -129,8 +127,8 @@ QUnit.test('parses unknown tag types', function() {
QUnit
.
ok
(
element
,
'an event was triggered'
);
QUnit
.
strictEqual
(
element
.
type
,
'tag'
,
'the type is tag'
);
QUnit
.
strictEqual
(
element
.
data
,
manifest
.
slice
(
4
,
manifest
.
length
-
1
),
'unknown tag data is preserved'
);
manifest
.
slice
(
4
,
manifest
.
length
-
1
),
'unknown tag data is preserved'
);
});
// #EXTM3U
...
...
@@ -200,8 +198,8 @@ QUnit.test('parses #EXTINF tags with a duration and title', function() {
QUnit
.
strictEqual
(
element
.
tagType
,
'inf'
,
'the tag type is inf'
);
QUnit
.
strictEqual
(
element
.
duration
,
13
,
'the duration is parsed'
);
QUnit
.
strictEqual
(
element
.
title
,
manifest
.
substring
(
manifest
.
indexOf
(
','
)
+
1
,
manifest
.
length
-
1
),
'the title is parsed'
);
manifest
.
substring
(
manifest
.
indexOf
(
','
)
+
1
,
manifest
.
length
-
1
),
'the title is parsed'
);
});
QUnit
.
test
(
'parses #EXTINF tags with carriage returns'
,
function
()
{
let
manifest
=
'#EXTINF:13,Does anyone really use the title attribute?\r\n'
;
...
...
@@ -217,8 +215,8 @@ QUnit.test('parses #EXTINF tags with carriage returns', function() {
QUnit
.
strictEqual
(
element
.
tagType
,
'inf'
,
'the tag type is inf'
);
QUnit
.
strictEqual
(
element
.
duration
,
13
,
'the duration is parsed'
);
QUnit
.
strictEqual
(
element
.
title
,
manifest
.
substring
(
manifest
.
indexOf
(
','
)
+
1
,
manifest
.
length
-
2
),
'the title is parsed'
);
manifest
.
substring
(
manifest
.
indexOf
(
','
)
+
1
,
manifest
.
length
-
2
),
'the title is parsed'
);
});
// #EXT-X-TARGETDURATION
...
...
@@ -485,8 +483,8 @@ QUnit.test('parses #EXT-X-STREAM-INF with common attributes', function() {
QUnit
.
strictEqual
(
element
.
type
,
'tag'
,
'the line type is tag'
);
QUnit
.
strictEqual
(
element
.
tagType
,
'stream-inf'
,
'the tag type is stream-inf'
);
QUnit
.
strictEqual
(
element
.
attributes
.
CODECS
,
'avc1.4d400d, mp4a.40.2'
,
'codecs are parsed'
);
'avc1.4d400d, mp4a.40.2'
,
'codecs are parsed'
);
});
QUnit
.
test
(
'parses #EXT-X-STREAM-INF with arbitrary attributes'
,
function
()
{
let
manifest
=
'#EXT-X-STREAM-INF:NUMERIC=24,ALPHA=Value,MIXED=123abc\n'
;
...
...
@@ -501,11 +499,9 @@ QUnit.test('parses #EXT-X-STREAM-INF with arbitrary attributes', function() {
QUnit
.
strictEqual
(
element
.
type
,
'tag'
,
'the line type is tag'
);
QUnit
.
strictEqual
(
element
.
tagType
,
'stream-inf'
,
'the tag type is stream-inf'
);
QUnit
.
strictEqual
(
element
.
attributes
.
NUMERIC
,
'24'
,
'numeric attributes are parsed'
);
QUnit
.
strictEqual
(
element
.
attributes
.
ALPHA
,
'Value'
,
'alphabetic attributes are parsed'
);
QUnit
.
strictEqual
(
element
.
attributes
.
ALPHA
,
'Value'
,
'alphabetic attributes are parsed'
);
QUnit
.
strictEqual
(
element
.
attributes
.
MIXED
,
'123abc'
,
'mixed attributes are parsed'
);
});
// #EXT-X-ENDLIST
...
...
@@ -593,23 +589,23 @@ QUnit.test('parses lightly-broken #EXT-X-KEY tags', function() {
this
.
lineStream
.
push
(
manifest
);
QUnit
.
strictEqual
(
element
.
attributes
.
URI
,
'https://example.com/single-quote'
,
'parsed a single-quoted uri'
);
'https://example.com/single-quote'
,
'parsed a single-quoted uri'
);
element
=
null
;
manifest
=
'#EXT-X-KEYURI="https://example.com/key",METHOD=AES-128\n'
;
this
.
lineStream
.
push
(
manifest
);
QUnit
.
strictEqual
(
element
.
tagType
,
'key'
,
'parsed the tag type'
);
QUnit
.
strictEqual
(
element
.
attributes
.
URI
,
'https://example.com/key'
,
'inferred a colon after the tag type'
);
'https://example.com/key'
,
'inferred a colon after the tag type'
);
element
=
null
;
manifest
=
'#EXT-X-KEY: URI = "https://example.com/key",METHOD=AES-128\n'
;
this
.
lineStream
.
push
(
manifest
);
QUnit
.
strictEqual
(
element
.
attributes
.
URI
,
'https://example.com/key'
,
'trims and removes quotes around the URI'
);
'https://example.com/key'
,
'trims and removes quotes around the URI'
);
});
QUnit
.
test
(
'ignores empty lines'
,
function
()
{
...
...
@@ -640,10 +636,9 @@ QUnit.test('parses static manifests as expected', function() {
let
parser
=
new
Parser
();
parser
.
push
(
testDataManifests
[
key
]);
QUnit
.
deepEqual
(
parser
.
manifest
,
testDataExpected
[
key
],
key
+
'.m3u8 was parsed correctly'
QUnit
.
deepEqual
(
parser
.
manifest
,
testDataExpected
[
key
],
key
+
'.m3u8 was parsed correctly'
);
}
}
...
...
test/stub.test.js
View file @
52308f1
import
manifests
from
'./
data/
manifests'
;
import
expected
from
'./
data/
expected'
;
import
manifests
from
'./
test-
manifests'
;
import
expected
from
'./
test-
expected'
;
window
.
manifests
=
manifests
;
window
.
expected
=
expected
;
...
...
Please
register
or
sign in
to post a comment