@transmitlive/m3u8-parser 4.7.2-beta.6 → 7.1.0-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/dist/m3u8-parser.cjs.js +446 -302
- package/dist/m3u8-parser.es.js +443 -297
- package/dist/m3u8-parser.js +462 -351
- package/dist/m3u8-parser.min.js +2 -2
- package/package.json +6 -11
- package/src/parse-stream.js +93 -18
- package/src/parser.js +120 -9
- package/test/fixtures/integration/absoluteUris.js +1 -0
- package/test/fixtures/integration/allowCache.js +1 -0
- package/test/fixtures/integration/allowCacheInvalid.js +1 -0
- package/test/fixtures/integration/alternateAudio.js +1 -0
- package/test/fixtures/integration/alternateVideo.js +1 -0
- package/test/fixtures/integration/brightcove.js +1 -0
- package/test/fixtures/integration/byteRange.js +1 -0
- package/test/fixtures/integration/dateTime.js +3 -0
- package/test/fixtures/integration/diff-init-key.js +1 -0
- package/test/fixtures/integration/disallowCache.js +1 -0
- package/test/fixtures/integration/disc-sequence.js +9 -4
- package/test/fixtures/integration/discontinuity.js +19 -9
- package/test/fixtures/integration/domainUris.js +1 -0
- package/test/fixtures/integration/empty.js +1 -0
- package/test/fixtures/integration/emptyAllowCache.js +1 -0
- package/test/fixtures/integration/emptyMediaSequence.js +9 -4
- package/test/fixtures/integration/emptyPlaylistType.js +1 -0
- package/test/fixtures/integration/emptyTargetDuration.js +1 -0
- package/test/fixtures/integration/encrypted.js +1 -0
- package/test/fixtures/integration/event.js +1 -0
- package/test/fixtures/integration/extXPlaylistTypeInvalidPlaylist.js +3 -1
- package/test/fixtures/integration/extinf.js +3 -1
- package/test/fixtures/integration/fmp4.js +3 -1
- package/test/fixtures/integration/headerOnly.js +1 -0
- package/test/fixtures/integration/invalidAllowCache.js +1 -0
- package/test/fixtures/integration/invalidMediaSequence.js +9 -4
- package/test/fixtures/integration/invalidPlaylistType.js +1 -0
- package/test/fixtures/integration/invalidTargetDuration.js +1 -0
- package/test/fixtures/integration/liveMissingSegmentDuration.js +3 -1
- package/test/fixtures/integration/liveStart30sBefore.js +19 -9
- package/test/fixtures/integration/llhls-byte-range.js +1 -0
- package/test/fixtures/integration/llhls-delta-byte-range.js +1 -0
- package/test/fixtures/integration/llhls.js +8 -0
- package/test/fixtures/integration/llhlsDelta.js +5 -0
- package/test/fixtures/integration/manifestExtTTargetdurationNegative.js +1 -0
- package/test/fixtures/integration/manifestExtXEndlistEarly.js +1 -0
- package/test/fixtures/integration/manifestNoExtM3u.js +1 -0
- package/test/fixtures/integration/master-fmp4.js +27 -25
- package/test/fixtures/integration/master.js +1 -0
- package/test/fixtures/integration/media.js +1 -0
- package/test/fixtures/integration/mediaSequence.js +9 -4
- package/test/fixtures/integration/missingEndlist.js +1 -0
- package/test/fixtures/integration/missingExtinf.js +1 -0
- package/test/fixtures/integration/missingMediaSequence.js +9 -4
- package/test/fixtures/integration/missingSegmentDuration.js +3 -1
- package/test/fixtures/integration/multipleAudioGroups.js +1 -0
- package/test/fixtures/integration/multipleAudioGroupsCombinedMain.js +1 -0
- package/test/fixtures/integration/multipleTargetDurations.js +1 -0
- package/test/fixtures/integration/multipleVideo.js +1 -0
- package/test/fixtures/integration/negativeMediaSequence.js +9 -4
- package/test/fixtures/integration/playlist.js +1 -0
- package/test/fixtures/integration/playlistMediaSequenceHigher.js +3 -1
- package/test/fixtures/integration/start.js +1 -0
- package/test/fixtures/integration/streamInfInvalid.js +1 -0
- package/test/fixtures/integration/twoMediaSequences.js +9 -4
- package/test/fixtures/integration/versionInvalid.js +1 -0
- package/test/fixtures/integration/whiteSpace.js +1 -0
- package/test/fixtures/integration/zeroDuration.js +1 -0
- package/test/parse-stream.test.js +112 -16
- package/test/parser.test.js +392 -17
|
@@ -242,7 +242,7 @@ QUnit.test('parses #EXTM3U tags', function(assert) {
|
|
|
242
242
|
|
|
243
243
|
// #EXTINF
|
|
244
244
|
QUnit.test('parses minimal #EXTINF tags', function(assert) {
|
|
245
|
-
const manifest = '#EXTINF
|
|
245
|
+
const manifest = '#EXTINF:\n';
|
|
246
246
|
let element;
|
|
247
247
|
|
|
248
248
|
this.parseStream.on('data', function(elem) {
|
|
@@ -319,7 +319,7 @@ QUnit.test('parses #EXTINF tags with carriage returns', function(assert) {
|
|
|
319
319
|
|
|
320
320
|
// #EXT-X-TARGETDURATION
|
|
321
321
|
QUnit.test('parses minimal #EXT-X-TARGETDURATION tags', function(assert) {
|
|
322
|
-
const manifest = '#EXT-X-TARGETDURATION
|
|
322
|
+
const manifest = '#EXT-X-TARGETDURATION:\n';
|
|
323
323
|
let element;
|
|
324
324
|
|
|
325
325
|
this.parseStream.on('data', function(elem) {
|
|
@@ -379,7 +379,7 @@ QUnit.test('parses #EXT-X-VERSION with a version', function(assert) {
|
|
|
379
379
|
|
|
380
380
|
// #EXT-X-MEDIA-SEQUENCE
|
|
381
381
|
QUnit.test('parses minimal #EXT-X-MEDIA-SEQUENCE tags', function(assert) {
|
|
382
|
-
const manifest = '#EXT-X-MEDIA-SEQUENCE
|
|
382
|
+
const manifest = '#EXT-X-MEDIA-SEQUENCE:\n';
|
|
383
383
|
let element;
|
|
384
384
|
|
|
385
385
|
this.parseStream.on('data', function(elem) {
|
|
@@ -453,7 +453,7 @@ QUnit.test('parses #EXT-X-PLAYLIST-TYPE with mutability info', function(assert)
|
|
|
453
453
|
|
|
454
454
|
// #EXT-X-BYTERANGE
|
|
455
455
|
QUnit.test('parses minimal #EXT-X-BYTERANGE tags', function(assert) {
|
|
456
|
-
const manifest = '#EXT-X-BYTERANGE
|
|
456
|
+
const manifest = '#EXT-X-BYTERANGE:\n';
|
|
457
457
|
let element;
|
|
458
458
|
|
|
459
459
|
this.parseStream.on('data', function(elem) {
|
|
@@ -589,7 +589,7 @@ QUnit.test('parses #EXT-X-MAP tags with arbitrary attributes', function(assert)
|
|
|
589
589
|
});
|
|
590
590
|
// #EXT-X-STREAM-INF
|
|
591
591
|
QUnit.test('parses minimal #EXT-X-STREAM-INF tags', function(assert) {
|
|
592
|
-
const manifest = '#EXT-X-STREAM-INF
|
|
592
|
+
const manifest = '#EXT-X-STREAM-INF:\n';
|
|
593
593
|
let element;
|
|
594
594
|
|
|
595
595
|
this.parseStream.on('data', function(elem) {
|
|
@@ -604,7 +604,7 @@ QUnit.test('parses minimal #EXT-X-STREAM-INF tags', function(assert) {
|
|
|
604
604
|
});
|
|
605
605
|
// #EXT-X-PROGRAM-DATE-TIME
|
|
606
606
|
QUnit.test('parses minimal EXT-X-PROGRAM-DATE-TIME tags', function(assert) {
|
|
607
|
-
const manifest = '#EXT-X-PROGRAM-DATE-TIME
|
|
607
|
+
const manifest = '#EXT-X-PROGRAM-DATE-TIME:\n';
|
|
608
608
|
let element;
|
|
609
609
|
|
|
610
610
|
this.parseStream.on('data', function(elem) {
|
|
@@ -698,6 +698,14 @@ QUnit.test('parses #EXT-X-STREAM-INF with common attributes', function(assert) {
|
|
|
698
698
|
'avc1.4d400d, mp4a.40.2',
|
|
699
699
|
'codecs are parsed'
|
|
700
700
|
);
|
|
701
|
+
|
|
702
|
+
manifest = '#EXT-X-STREAM-INF:PATHWAY-ID="CDN-A"\n';
|
|
703
|
+
this.lineStream.push(manifest);
|
|
704
|
+
|
|
705
|
+
assert.ok(element, 'an event was triggered');
|
|
706
|
+
assert.strictEqual(element.type, 'tag', 'the line type is tag');
|
|
707
|
+
assert.strictEqual(element.tagType, 'stream-inf', 'the tag type is stream-inf');
|
|
708
|
+
assert.strictEqual(element.attributes['PATHWAY-ID'], 'CDN-A', 'pathway-id is parsed');
|
|
701
709
|
});
|
|
702
710
|
QUnit.test('parses #EXT-X-STREAM-INF with arbitrary attributes', function(assert) {
|
|
703
711
|
const manifest = '#EXT-X-STREAM-INF:NUMERIC=24,ALPHA=Value,MIXED=123abc\n';
|
|
@@ -809,16 +817,6 @@ QUnit.test('parses lightly-broken #EXT-X-KEY tags', function(assert) {
|
|
|
809
817
|
'parsed a single-quoted uri'
|
|
810
818
|
);
|
|
811
819
|
|
|
812
|
-
element = null;
|
|
813
|
-
manifest = '#EXT-X-KEYURI="https://example.com/key",METHOD=AES-128\n';
|
|
814
|
-
this.lineStream.push(manifest);
|
|
815
|
-
assert.strictEqual(element.tagType, 'key', 'parsed the tag type');
|
|
816
|
-
assert.strictEqual(
|
|
817
|
-
element.attributes.URI,
|
|
818
|
-
'https://example.com/key',
|
|
819
|
-
'inferred a colon after the tag type'
|
|
820
|
-
);
|
|
821
|
-
|
|
822
820
|
element = null;
|
|
823
821
|
manifest = '#EXT-X-KEY: URI = "https://example.com/key",METHOD=AES-128\n';
|
|
824
822
|
this.lineStream.push(manifest);
|
|
@@ -889,6 +887,104 @@ QUnit.test('parses EXT-X-START PRECISE attribute', function(assert) {
|
|
|
889
887
|
assert.strictEqual(element.attributes['TIME-OFFSET'], 1.4, 'parses time offset');
|
|
890
888
|
assert.strictEqual(element.attributes.PRECISE, true, 'parses precise attribute');
|
|
891
889
|
});
|
|
890
|
+
// #EXT-X-DATERANGE:
|
|
891
|
+
QUnit.test('parses minimal EXT-X-DATERANGE tag', function(assert) {
|
|
892
|
+
const manifest = '#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T15:15:15.840000Z"\n';
|
|
893
|
+
let element;
|
|
894
|
+
|
|
895
|
+
this.parseStream.on('data', function(elem) {
|
|
896
|
+
element = elem;
|
|
897
|
+
});
|
|
898
|
+
this.lineStream.push(manifest);
|
|
899
|
+
|
|
900
|
+
assert.ok(element, 'an event was triggered');
|
|
901
|
+
assert.strictEqual(element.type, 'tag', 'the line type is tag');
|
|
902
|
+
assert.strictEqual(element.tagType, 'daterange', 'the tag type is daterange');
|
|
903
|
+
assert.strictEqual(element.attributes.ID, '12345');
|
|
904
|
+
assert.deepEqual(element.attributes['START-DATE'], new Date('2023-04-13T15:15:15.840000Z'));
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
QUnit.test('parses DURATION and PLANNED-DURATION attributes in EXT-X-DATERANGE tag', function(assert) {
|
|
908
|
+
const manifest = '#EXT-X-DATERANGE:ID="54545",START-DATE="2023-04-23T18:17:16.54000Z",PLANNED-DURATION="38.4",DURATION="15.5"\n';
|
|
909
|
+
let element;
|
|
910
|
+
|
|
911
|
+
this.parseStream.on('data', function(elem) {
|
|
912
|
+
element = elem;
|
|
913
|
+
});
|
|
914
|
+
this.lineStream.push(manifest);
|
|
915
|
+
|
|
916
|
+
assert.ok(element, 'an event was triggered');
|
|
917
|
+
assert.strictEqual(element.type, 'tag', 'the line type is tag');
|
|
918
|
+
assert.strictEqual(element.tagType, 'daterange', 'the tag type is daterange');
|
|
919
|
+
assert.strictEqual(element.attributes.ID, '54545');
|
|
920
|
+
assert.deepEqual(element.attributes['START-DATE'], new Date('2023-04-23T18:17:16.540000Z'));
|
|
921
|
+
assert.strictEqual(element.attributes.DURATION, 15.5);
|
|
922
|
+
assert.strictEqual(element.attributes['PLANNED-DURATION'], 38.4);
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
QUnit.test('parses SCTE35-CMD, SCTE35-OUT, SCTE35-IN EXT-X-DATERANGE tags', function(assert) {
|
|
926
|
+
let manifest = '#EXT-X-DATERANGE:ID="splice-6FFFFFF0",START-DATE="2023-04-13T15:15:15.840000Z",SCTE35-OUT="0xFC002F0000000000FF000014056FFFFFFF0"\n';
|
|
927
|
+
let element;
|
|
928
|
+
|
|
929
|
+
this.parseStream.on('data', function(elem) {
|
|
930
|
+
element = elem;
|
|
931
|
+
});
|
|
932
|
+
this.lineStream.push(manifest);
|
|
933
|
+
|
|
934
|
+
assert.ok(element, 'an event was triggered');
|
|
935
|
+
assert.strictEqual(element.attributes['SCTE35-OUT'], '0xFC002F0000000000FF000014056FFFFFFF0');
|
|
936
|
+
|
|
937
|
+
manifest = '#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T15:15:15.840000Z",SCTE35-IN="0xFC0000425100FFF0140500000300000000E77FEFFE0011FB9EFE0029004D1932E0000100101002A22"\n';
|
|
938
|
+
this.lineStream.push(manifest);
|
|
939
|
+
|
|
940
|
+
assert.ok(element, 'an event was triggered');
|
|
941
|
+
assert.strictEqual(element.attributes['SCTE35-IN'], '0xFC0000425100FFF0140500000300000000E77FEFFE0011FB9EFE0029004D1932E0000100101002A22');
|
|
942
|
+
|
|
943
|
+
manifest = '#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T15:15:15.840000Z",SCTE35-CMD="0xFC0000425100FFF014"\n';
|
|
944
|
+
this.lineStream.push(manifest);
|
|
945
|
+
|
|
946
|
+
assert.ok(element, 'an event was triggered');
|
|
947
|
+
assert.strictEqual(element.attributes['SCTE35-CMD'], '0xFC0000425100FFF014');
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
QUnit.test('custom attributes in EXT-X-DATERANGE are parsed', function(assert) {
|
|
951
|
+
let manifest = '#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T15:15:15.840000Z",X-CUSTOM-KEY="value"\n';
|
|
952
|
+
let element;
|
|
953
|
+
|
|
954
|
+
this.parseStream.on('data', function(elem) {
|
|
955
|
+
element = elem;
|
|
956
|
+
});
|
|
957
|
+
this.lineStream.push(manifest);
|
|
958
|
+
|
|
959
|
+
assert.ok(element, 'an event was triggered');
|
|
960
|
+
assert.strictEqual(element.attributes['X-CUSTOM-KEY'], 'value');
|
|
961
|
+
|
|
962
|
+
manifest = '#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T15:15:15.840000Z",X-CUSTOM-KEY="17.8"\n';
|
|
963
|
+
this.lineStream.push(manifest);
|
|
964
|
+
|
|
965
|
+
assert.ok(element, 'an event was triggered');
|
|
966
|
+
assert.strictEqual(element.attributes['X-CUSTOM-KEY'], 17.8);
|
|
967
|
+
|
|
968
|
+
manifest = '#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T15:15:15.840000Z",X-CUSTOM-KEY="0X12345abcde"\n';
|
|
969
|
+
this.lineStream.push(manifest);
|
|
970
|
+
|
|
971
|
+
assert.ok(element, 'an event was triggered');
|
|
972
|
+
assert.strictEqual(element.attributes['X-CUSTOM-KEY'], '0X12345abcde');
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
QUnit.test('parses EXT-X-INDEPENDENT-SEGMENTS', function(assert) {
|
|
976
|
+
const manifest = '#EXT-X-INDEPENDENT-SEGMENTS\n';
|
|
977
|
+
let element;
|
|
978
|
+
|
|
979
|
+
this.parseStream.on('data', function(elem) {
|
|
980
|
+
element = elem;
|
|
981
|
+
});
|
|
982
|
+
this.lineStream.push(manifest);
|
|
983
|
+
|
|
984
|
+
assert.ok(element, 'an event was triggered');
|
|
985
|
+
assert.strictEqual(element.type, 'tag', 'the line type is tag');
|
|
986
|
+
assert.strictEqual(element.tagType, 'independent-segments', 'the tag type is independent-segments');
|
|
987
|
+
});
|
|
892
988
|
|
|
893
989
|
QUnit.test('ignores empty lines', function(assert) {
|
|
894
990
|
const manifest = '\n';
|
package/test/parser.test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import QUnit from 'qunit';
|
|
2
|
-
import testDataExpected from 'data-files!expecteds';
|
|
3
|
-
import testDataManifests from 'data-files!manifests';
|
|
2
|
+
// import testDataExpected from 'data-files!expecteds';
|
|
3
|
+
// import testDataManifests from 'data-files!manifests';
|
|
4
4
|
import {Parser} from '../src';
|
|
5
5
|
|
|
6
6
|
QUnit.module('m3u8s', function(hooks) {
|
|
@@ -108,11 +108,10 @@ QUnit.module('m3u8s', function(hooks) {
|
|
|
108
108
|
'#EXT-X-CUE-OUT:10',
|
|
109
109
|
'#EXTINF:5,',
|
|
110
110
|
'ex2.ts',
|
|
111
|
-
'#EXT-X-CUE-OUT15',
|
|
112
111
|
'#EXT-UKNOWN-TAG',
|
|
113
112
|
'#EXTINF:5,',
|
|
114
113
|
'ex3.ts',
|
|
115
|
-
'#EXT-X-CUE-OUT',
|
|
114
|
+
'#EXT-X-CUE-OUT:',
|
|
116
115
|
'#EXTINF:5,',
|
|
117
116
|
'ex3.ts',
|
|
118
117
|
'#EXT-X-ENDLIST'
|
|
@@ -122,7 +121,6 @@ QUnit.module('m3u8s', function(hooks) {
|
|
|
122
121
|
this.parser.end();
|
|
123
122
|
|
|
124
123
|
assert.equal(this.parser.manifest.segments[1].cueOut, '10', 'parser attached cue out tag');
|
|
125
|
-
assert.equal(this.parser.manifest.segments[2].cueOut, '15', 'cue out without : seperator');
|
|
126
124
|
assert.equal(this.parser.manifest.segments[3].cueOut, '', 'cue out without data');
|
|
127
125
|
});
|
|
128
126
|
|
|
@@ -135,11 +133,10 @@ QUnit.module('m3u8s', function(hooks) {
|
|
|
135
133
|
'#EXT-X-CUE-OUT-CONT:10/60',
|
|
136
134
|
'#EXTINF:5,',
|
|
137
135
|
'ex2.ts',
|
|
138
|
-
'#EXT-X-CUE-OUT-CONT15/30',
|
|
139
136
|
'#EXT-UKNOWN-TAG',
|
|
140
137
|
'#EXTINF:5,',
|
|
141
138
|
'ex3.ts',
|
|
142
|
-
'#EXT-X-CUE-OUT-CONT',
|
|
139
|
+
'#EXT-X-CUE-OUT-CONT:',
|
|
143
140
|
'#EXTINF:5,',
|
|
144
141
|
'ex3.ts',
|
|
145
142
|
'#EXT-X-ENDLIST'
|
|
@@ -152,10 +149,6 @@ QUnit.module('m3u8s', function(hooks) {
|
|
|
152
149
|
this.parser.manifest.segments[1].cueOutCont, '10/60',
|
|
153
150
|
'parser attached cue out cont tag'
|
|
154
151
|
);
|
|
155
|
-
assert.equal(
|
|
156
|
-
this.parser.manifest.segments[2].cueOutCont, '15/30',
|
|
157
|
-
'cue out cont without : seperator'
|
|
158
|
-
);
|
|
159
152
|
assert.equal(this.parser.manifest.segments[3].cueOutCont, '', 'cue out cont without data');
|
|
160
153
|
});
|
|
161
154
|
|
|
@@ -165,14 +158,13 @@ QUnit.module('m3u8s', function(hooks) {
|
|
|
165
158
|
'#EXTINF:5,',
|
|
166
159
|
'#COMMENT',
|
|
167
160
|
'ex1.ts',
|
|
168
|
-
'#EXT-X-CUE-IN',
|
|
161
|
+
'#EXT-X-CUE-IN:',
|
|
169
162
|
'#EXTINF:5,',
|
|
170
163
|
'ex2.ts',
|
|
171
164
|
'#EXT-X-CUE-IN:15',
|
|
172
165
|
'#EXT-UKNOWN-TAG',
|
|
173
166
|
'#EXTINF:5,',
|
|
174
167
|
'ex3.ts',
|
|
175
|
-
'#EXT-X-CUE-IN=abc',
|
|
176
168
|
'#EXTINF:5,',
|
|
177
169
|
'ex3.ts',
|
|
178
170
|
'#EXT-X-ENDLIST'
|
|
@@ -183,10 +175,6 @@ QUnit.module('m3u8s', function(hooks) {
|
|
|
183
175
|
|
|
184
176
|
assert.equal(this.parser.manifest.segments[1].cueIn, '', 'parser attached cue in tag');
|
|
185
177
|
assert.equal(this.parser.manifest.segments[2].cueIn, '15', 'cue in with data');
|
|
186
|
-
assert.equal(
|
|
187
|
-
this.parser.manifest.segments[3].cueIn, '=abc',
|
|
188
|
-
'cue in without colon seperator'
|
|
189
|
-
);
|
|
190
178
|
});
|
|
191
179
|
|
|
192
180
|
QUnit.test('parses characteristics attribute', function(assert) {
|
|
@@ -857,8 +845,394 @@ QUnit.module('m3u8s', function(hooks) {
|
|
|
857
845
|
);
|
|
858
846
|
});
|
|
859
847
|
|
|
848
|
+
QUnit.test('PDT value is assigned to segments with explicit #EXT-X-PROGRAM-DATE-TIME tags', function(assert) {
|
|
849
|
+
this.parser.push([
|
|
850
|
+
'#EXTM3U',
|
|
851
|
+
'#EXT-X-VERSION:6',
|
|
852
|
+
'#EXT-X-TARGETDURATION:8',
|
|
853
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
854
|
+
'#EXTINF:8.0',
|
|
855
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
856
|
+
'https://example.com/playlist1.m3u8',
|
|
857
|
+
'#EXTINF:8.0,',
|
|
858
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T22:14:10.053+00:00',
|
|
859
|
+
'https://example.com/playlist2.m3u8',
|
|
860
|
+
'#EXT-X-ENDLIST'
|
|
861
|
+
].join('\n'));
|
|
862
|
+
this.parser.end();
|
|
863
|
+
assert.equal(this.parser.manifest.segments[0].programDateTime, new Date('2017-07-31T20:35:35.053+00:00').getTime());
|
|
864
|
+
assert.equal(this.parser.manifest.segments[1].programDateTime, new Date('2017-07-31T22:14:10.053+00:00').getTime());
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
QUnit.test('backfill PDT values when the first EXT-X-PROGRAM-DATE-TIME tag appears after one or more Media Segment URIs', function(assert) {
|
|
868
|
+
this.parser.push([
|
|
869
|
+
'#EXTM3U',
|
|
870
|
+
'#EXT-X-VERSION:6',
|
|
871
|
+
'#EXT-X-TARGETDURATION:8',
|
|
872
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
873
|
+
'#EXTINF:8.0',
|
|
874
|
+
'https://example.com/playlist1.m3u8',
|
|
875
|
+
'#EXTINF:8.0,',
|
|
876
|
+
'https://example.com/playlist2.m3u8',
|
|
877
|
+
'#EXTINF:8.0',
|
|
878
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
879
|
+
'https://example.com/playlist3.m3u8',
|
|
880
|
+
'#EXT-X-ENDLIST'
|
|
881
|
+
].join('\n'));
|
|
882
|
+
this.parser.end();
|
|
883
|
+
const segments = this.parser.manifest.segments;
|
|
884
|
+
|
|
885
|
+
assert.equal(segments[2].programDateTime, new Date('2017-07-31T20:35:35.053+00:00').getTime());
|
|
886
|
+
assert.equal(segments[1].programDateTime, segments[2].programDateTime - (segments[1].duration * 1000));
|
|
887
|
+
assert.equal(segments[0].programDateTime, segments[1].programDateTime - (segments[0].duration * 1000));
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
QUnit.test('extrapolates forward when subsequent fragments do not have explicit PDT tags', function(assert) {
|
|
891
|
+
this.parser.push([
|
|
892
|
+
'#EXTM3U',
|
|
893
|
+
'#EXT-X-VERSION:6',
|
|
894
|
+
'#EXT-X-TARGETDURATION:8',
|
|
895
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
896
|
+
'#EXTINF:8.0',
|
|
897
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
898
|
+
'https://example.com/playlist1.m3u8',
|
|
899
|
+
'#EXTINF:8.0,',
|
|
900
|
+
'https://example.com/playlist2.m3u8',
|
|
901
|
+
'#EXTINF:8.0',
|
|
902
|
+
'https://example.com/playlist3.m3u8',
|
|
903
|
+
'#EXT-X-ENDLIST'
|
|
904
|
+
].join('\n'));
|
|
905
|
+
this.parser.end();
|
|
906
|
+
const segments = this.parser.manifest.segments;
|
|
907
|
+
|
|
908
|
+
assert.equal(segments[0].programDateTime, new Date('2017-07-31T20:35:35.053+00:00').getTime());
|
|
909
|
+
assert.equal(segments[1].programDateTime, segments[0].programDateTime + segments[1].duration * 1000);
|
|
910
|
+
assert.equal(segments[2].programDateTime, segments[1].programDateTime + segments[2].duration * 1000);
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
QUnit.test('warns when #EXT-X-DATERANGE missing attribute', function(assert) {
|
|
914
|
+
this.parser.push([
|
|
915
|
+
'#EXT-X-VERSION:3',
|
|
916
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
917
|
+
'#EXT-X-DISCONTINUITY-SEQUENCE:0',
|
|
918
|
+
'#EXTINF:10,',
|
|
919
|
+
'media-00001.ts',
|
|
920
|
+
'#EXT-X-ENDLIST',
|
|
921
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
922
|
+
'#EXT-X-DATERANGE:ID="12345"'
|
|
923
|
+
].join('\n'));
|
|
924
|
+
this.parser.end();
|
|
925
|
+
|
|
926
|
+
const warnings = [
|
|
927
|
+
'#EXT-X-DATERANGE #0 lacks required attribute(s): START-DATE'
|
|
928
|
+
];
|
|
929
|
+
|
|
930
|
+
assert.deepEqual(
|
|
931
|
+
this.warnings,
|
|
932
|
+
warnings,
|
|
933
|
+
'warnings as expected'
|
|
934
|
+
);
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
QUnit.test('warns when #EXT-X-DATERANGE end date attribute is less than start date', function(assert) {
|
|
938
|
+
this.parser.push([
|
|
939
|
+
'#EXT-X-VERSION:3',
|
|
940
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
941
|
+
'#EXT-X-DISCONTINUITY-SEQUENCE:0',
|
|
942
|
+
'#EXTINF:10,',
|
|
943
|
+
'media-00001.ts',
|
|
944
|
+
'#EXT-X-ENDLIST',
|
|
945
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
946
|
+
'#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T18:16:15.840000Z",END-DATE="2023-04-13T15:15:15.840000Z"'
|
|
947
|
+
].join('\n'));
|
|
948
|
+
this.parser.end();
|
|
949
|
+
|
|
950
|
+
const warnings = [
|
|
951
|
+
'EXT-X-DATERANGE END-DATE must be equal to or later than the value of the START-DATE'
|
|
952
|
+
];
|
|
953
|
+
|
|
954
|
+
assert.deepEqual(
|
|
955
|
+
this.warnings,
|
|
956
|
+
warnings,
|
|
957
|
+
'warnings as expected'
|
|
958
|
+
);
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
QUnit.test('warns when #EXT-X-DATERANGE duration or planned duration attribute is negative', function(assert) {
|
|
962
|
+
this.parser.push([
|
|
963
|
+
'#EXT-X-VERSION:3',
|
|
964
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
965
|
+
'#EXT-X-DISCONTINUITY-SEQUENCE:0',
|
|
966
|
+
'#EXTINF:10,',
|
|
967
|
+
'media-00001.ts',
|
|
968
|
+
'#EXT-X-ENDLIST',
|
|
969
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
970
|
+
'#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T18:16:15.840000Z",PLANNED-DURATION=-38.4,DURATION=-15.5'
|
|
971
|
+
].join('\n'));
|
|
972
|
+
this.parser.end();
|
|
973
|
+
|
|
974
|
+
const warnings = [
|
|
975
|
+
'EXT-X-DATERANGE DURATION must not be negative',
|
|
976
|
+
'EXT-X-DATERANGE PLANNED-DURATION must not be negative'
|
|
977
|
+
];
|
|
978
|
+
|
|
979
|
+
assert.deepEqual(
|
|
980
|
+
this.warnings,
|
|
981
|
+
warnings,
|
|
982
|
+
'warnings as expected'
|
|
983
|
+
);
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
QUnit.test('warns when #EXT-X-DATERANGE has a END-ON-NEXT=YES attribute and a DURATION or END-DATE attribute', function(assert) {
|
|
987
|
+
this.parser.push([
|
|
988
|
+
'#EXT-X-VERSION:3',
|
|
989
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
990
|
+
'#EXT-X-DISCONTINUITY-SEQUENCE:0',
|
|
991
|
+
'#EXTINF:10,',
|
|
992
|
+
'media-00001.ts',
|
|
993
|
+
'#EXT-X-ENDLIST',
|
|
994
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
995
|
+
'#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T15:15:15.840000Z",END-ON-NEXT=YES, END-DATE="2023-04-13T18:16:15.840000Z",CLASS="CLASSATTRIBUTE"'
|
|
996
|
+
].join('\n'));
|
|
997
|
+
this.parser.end();
|
|
998
|
+
|
|
999
|
+
const warnings = [
|
|
1000
|
+
'EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must not contain DURATION or END-DATE attributes'
|
|
1001
|
+
];
|
|
1002
|
+
|
|
1003
|
+
assert.deepEqual(
|
|
1004
|
+
this.warnings,
|
|
1005
|
+
warnings,
|
|
1006
|
+
'warnings as expected'
|
|
1007
|
+
);
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
QUnit.test('warns when #EXT-X-DATERANGE has a END-ON-NEXT=YES attribute but not a CLASS attribute', function(assert) {
|
|
1011
|
+
this.parser.push([
|
|
1012
|
+
'#EXT-X-VERSION:3',
|
|
1013
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
1014
|
+
'#EXT-X-DISCONTINUITY-SEQUENCE:0',
|
|
1015
|
+
'#EXTINF:10,',
|
|
1016
|
+
'media-00001.ts',
|
|
1017
|
+
'#EXT-X-ENDLIST',
|
|
1018
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
1019
|
+
'#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T18:16:15.840000Z",END-ON-NEXT=YES'
|
|
1020
|
+
].join('\n'));
|
|
1021
|
+
this.parser.end();
|
|
1022
|
+
|
|
1023
|
+
const warnings = [
|
|
1024
|
+
'EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must have a CLASS attribute'
|
|
1025
|
+
];
|
|
1026
|
+
|
|
1027
|
+
assert.deepEqual(
|
|
1028
|
+
this.warnings,
|
|
1029
|
+
warnings,
|
|
1030
|
+
'warnings as expected'
|
|
1031
|
+
);
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
QUnit.test('warns when playlist has multiple #EXT-X-DATERANGE tag same ID but different attribute values', function(assert) {
|
|
1035
|
+
this.parser.push([
|
|
1036
|
+
'#EXT-X-VERSION:3',
|
|
1037
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
1038
|
+
'#EXT-X-DISCONTINUITY-SEQUENCE:0',
|
|
1039
|
+
'#EXTINF:10,',
|
|
1040
|
+
'media-00001.ts',
|
|
1041
|
+
'#EXT-X-ENDLIST',
|
|
1042
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
1043
|
+
'#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T18:16:15.840000Z",END-ON-NEXT=YES,CLASS="CLASSATTRIBUTE"',
|
|
1044
|
+
'#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T18:16:15.840000Z",CLASS="CLASSATTRIBUTE1"'
|
|
1045
|
+
].join('\n'));
|
|
1046
|
+
this.parser.end();
|
|
1047
|
+
|
|
1048
|
+
const warnings = [
|
|
1049
|
+
'EXT-X-DATERANGE tags with the same ID in a playlist must have the same attributes values'
|
|
1050
|
+
];
|
|
1051
|
+
|
|
1052
|
+
assert.deepEqual(
|
|
1053
|
+
this.warnings,
|
|
1054
|
+
warnings,
|
|
1055
|
+
'warnings as expected'
|
|
1056
|
+
);
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
QUnit.test('when #EXT-X-DATERANGE has both DURATION and END-DATE attributes, value of the END-DATE attribute must be START-DATE + DURATION', function(assert) {
|
|
1060
|
+
this.parser.push([
|
|
1061
|
+
'#EXT-X-VERSION:3',
|
|
1062
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
1063
|
+
'#EXT-X-DISCONTINUITY-SEQUENCE:0',
|
|
1064
|
+
'#EXTINF:10,',
|
|
1065
|
+
'media-00001.ts',
|
|
1066
|
+
'#EXT-X-ENDLIST',
|
|
1067
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
1068
|
+
'#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T15:16:15.840000Z",DURATION=14.0,END-DATE="2023-04-13T18:15:15.840000Z"'
|
|
1069
|
+
].join('\n'));
|
|
1070
|
+
this.parser.end();
|
|
1071
|
+
|
|
1072
|
+
assert.deepEqual(this.parser.manifest.dateRanges[0].endDate, new Date('2023-04-13T15:16:29.840000Z'));
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
QUnit.test('warns when playlist contains #EXT-X-DATERANGE tag but no #EXT-X-PROGRAM-DATE-TIME', function(assert) {
|
|
1076
|
+
this.parser.push([
|
|
1077
|
+
'#EXT-X-VERSION:3',
|
|
1078
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
1079
|
+
'#EXT-X-DISCONTINUITY-SEQUENCE:0',
|
|
1080
|
+
'#EXTINF:10,',
|
|
1081
|
+
'media-00001.ts',
|
|
1082
|
+
'#EXT-X-ENDLIST',
|
|
1083
|
+
'#EXT-X-DATERANGE:ID="12345",START-DATE="2023-04-13T18:16:15.840000Z",END-ON-NEXT=YES,CLASS="sampleClassAttrib"'
|
|
1084
|
+
].join('\n'));
|
|
1085
|
+
this.parser.end();
|
|
1086
|
+
|
|
1087
|
+
const warnings = [
|
|
1088
|
+
'A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag'
|
|
1089
|
+
];
|
|
1090
|
+
|
|
1091
|
+
assert.deepEqual(
|
|
1092
|
+
this.warnings,
|
|
1093
|
+
warnings,
|
|
1094
|
+
'warnings as expected'
|
|
1095
|
+
);
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
QUnit.test('playlist with multiple ext-x-daterange with same ID but no conflicting attributes', function(assert) {
|
|
1099
|
+
const expectedDateRange = {
|
|
1100
|
+
id: '12345',
|
|
1101
|
+
scte35In: '0xFC30200FFF2',
|
|
1102
|
+
scte35Out: '0xFC30200FFF2',
|
|
1103
|
+
startDate: new Date('2023-04-13T18:16:15.840000Z'),
|
|
1104
|
+
class: 'CLASSATTRIBUTE'
|
|
1105
|
+
};
|
|
1106
|
+
|
|
1107
|
+
this.parser.push([
|
|
1108
|
+
'#EXT-X-VERSION:3',
|
|
1109
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
1110
|
+
'#EXT-X-DISCONTINUITY-SEQUENCE:0',
|
|
1111
|
+
'#EXTINF:10,',
|
|
1112
|
+
'media-00001.ts',
|
|
1113
|
+
'#EXT-X-ENDLIST',
|
|
1114
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
1115
|
+
'#EXT-X-DATERANGE:ID="12345",SCTE35-IN=0xFC30200FFF2,START-DATE="2023-04-13T18:16:15.840000Z",CLASS="CLASSATTRIBUTE"',
|
|
1116
|
+
'#EXT-X-DATERANGE:ID="12345",SCTE35-OUT=0xFC30200FFF2,START-DATE="2023-04-13T18:16:15.840000Z"'
|
|
1117
|
+
].join('\n'));
|
|
1118
|
+
this.parser.end();
|
|
1119
|
+
assert.equal(this.parser.manifest.dateRanges.length, 1, 'two dateranges with same ID are merged');
|
|
1120
|
+
assert.deepEqual(this.parser.manifest.dateRanges[0], expectedDateRange);
|
|
1121
|
+
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
QUnit.test('playlist with multiple ext-x-daterange ', function(assert) {
|
|
1125
|
+
this.parser.push([
|
|
1126
|
+
' #EXTM3U',
|
|
1127
|
+
'#EXT-X-VERSION:6',
|
|
1128
|
+
'#EXT-X-TARGETDURATION:8',
|
|
1129
|
+
'#EXT-X-MEDIA-SEQUENCE:0',
|
|
1130
|
+
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00',
|
|
1131
|
+
'#EXT-X-DATERANGE:ID="event1",START-DATE="2023-04-20T10:00:00Z",DURATION=30.0,END-DATE="2023-04-20T10:00:30Z",X-CUSTOM-KEY="value"',
|
|
1132
|
+
'#EXTINF:8.0',
|
|
1133
|
+
'https://example.com/playlist1.m3u8',
|
|
1134
|
+
'#EXT-SCTE35-IN:0xFC002F0000000000FF000014056FFFFFFF065870697070657220506F6F7200',
|
|
1135
|
+
'#EXT-X-DATERANGE:ID="event2",START-DATE="2023-04-20T11:00:00Z",DURATION=60.0,END-DATE="2023-04-20T11:01:00Z",X-CUSTOM-KEY="value"',
|
|
1136
|
+
'#EXTINF:8.0,',
|
|
1137
|
+
'https://example.com/playlist2.m3u8',
|
|
1138
|
+
'#EXT-SCTE35-OUT:0xFC002F0000000000FF000014056FFFFFFF065870697070657220506F6F7200',
|
|
1139
|
+
'#EXT-X-DATERANGE:ID="event3",START-DATE="2023-04-20T12:00:00Z",DURATION=120.0,END-DATE="2023-04-20T12:02:00Z",X-CUSTOM-KEY="value"',
|
|
1140
|
+
'#EXTINF:8.0',
|
|
1141
|
+
'https://example.com/playlist3.m3u8',
|
|
1142
|
+
'#EXT-SCTE35-IN:0xFC002F0000000000FF000014056FFFFFFF065870697070657220506F6F7200',
|
|
1143
|
+
'#EXT-SCTE35-OUT:0xFC002F0000000000FF000014056FFFFFFF065870697070657220506F6F7200',
|
|
1144
|
+
'#EXT-X-ENDLIST'
|
|
1145
|
+
].join('\n'));
|
|
1146
|
+
this.parser.end();
|
|
1147
|
+
assert.equal(this.parser.manifest.dateRanges.length, 3);
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
QUnit.test('parses #EXT-X-INDEPENDENT-SEGMENTS', function(assert) {
|
|
1151
|
+
this.parser.push([
|
|
1152
|
+
'#EXTM3U',
|
|
1153
|
+
'#EXT-X-VERSION:6',
|
|
1154
|
+
'#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=3.252,CAN-SKIP-UNTIL=42.0',
|
|
1155
|
+
'#EXT-X-INDEPENDENT-SEGMENTS'
|
|
1156
|
+
].join('\n'));
|
|
1157
|
+
this.parser.end();
|
|
1158
|
+
assert.equal(this.parser.manifest.independentSegments, true);
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
QUnit.test('parses #EXT-X-CONTENT-STEERING', function(assert) {
|
|
1162
|
+
const expectedContentSteeringObject = {
|
|
1163
|
+
serverUri: '/foo?bar=00012',
|
|
1164
|
+
pathwayId: 'CDN-A'
|
|
1165
|
+
};
|
|
1166
|
+
|
|
1167
|
+
this.parser.push('#EXT-X-CONTENT-STEERING:SERVER-URI="/foo?bar=00012",PATHWAY-ID="CDN-A"');
|
|
1168
|
+
this.parser.end();
|
|
1169
|
+
assert.deepEqual(this.parser.manifest.contentSteering, expectedContentSteeringObject);
|
|
1170
|
+
});
|
|
1171
|
+
|
|
1172
|
+
QUnit.test('parses #EXT-X-CONTENT-STEERING without PATHWAY-ID', function(assert) {
|
|
1173
|
+
const expectedContentSteeringObject = {
|
|
1174
|
+
serverUri: '/bar?foo=00012'
|
|
1175
|
+
};
|
|
1176
|
+
|
|
1177
|
+
this.parser.push('#EXT-X-CONTENT-STEERING:SERVER-URI="/bar?foo=00012"');
|
|
1178
|
+
this.parser.end();
|
|
1179
|
+
assert.deepEqual(this.parser.manifest.contentSteering, expectedContentSteeringObject);
|
|
1180
|
+
});
|
|
1181
|
+
|
|
1182
|
+
QUnit.test('warns on #EXT-X-CONTENT-STEERING missing SERVER-URI', function(assert) {
|
|
1183
|
+
const warning = ['#EXT-X-CONTENT-STEERING lacks required attribute(s): SERVER-URI'];
|
|
1184
|
+
|
|
1185
|
+
this.parser.push('#EXT-X-CONTENT-STEERING:PATHWAY-ID="CDN-A"');
|
|
1186
|
+
this.parser.end();
|
|
1187
|
+
assert.deepEqual(this.warnings, warning, 'warnings as expected');
|
|
1188
|
+
});
|
|
1189
|
+
|
|
1190
|
+
QUnit.test('playlist line numbers ', function(assert) {
|
|
1191
|
+
this.parser.push([
|
|
1192
|
+
'#EXTM3U',
|
|
1193
|
+
'#EXT-X-VERSION:7',
|
|
1194
|
+
'#EXT-X-TARGETDURATION:4',
|
|
1195
|
+
'#EXT-X-MEDIA-SEQUENCE:2421',
|
|
1196
|
+
'#EXT-X-MAP:URI="init.mp4"',
|
|
1197
|
+
'#EXTINF:3.989333,',
|
|
1198
|
+
'#EXT-X-PROGRAM-DATE-TIME:2024-04-17T09:43:19.871-0700',
|
|
1199
|
+
'stream2421.m4s',
|
|
1200
|
+
'#EXTINF:4.010667,',
|
|
1201
|
+
'#EXT-X-PROGRAM-DATE-TIME:2024-04-17T09:43:23.860-0700',
|
|
1202
|
+
'stream2422.m4s',
|
|
1203
|
+
'#EXTINF:3.989333,',
|
|
1204
|
+
'#EXT-X-PROGRAM-DATE-TIME:2024-04-17T09:43:27.871-0700',
|
|
1205
|
+
'stream2423.m4s',
|
|
1206
|
+
'#EXTINF:4.010667,',
|
|
1207
|
+
'#EXT-X-PROGRAM-DATE-TIME:2024-04-17T09:43:31.860-0700',
|
|
1208
|
+
'stream2424.m4s',
|
|
1209
|
+
'#EXTINF:3.989333,',
|
|
1210
|
+
'#EXT-X-PROGRAM-DATE-TIME:2024-04-17T09:43:35.871-0700',
|
|
1211
|
+
'stream2425.m4s',
|
|
1212
|
+
'#EXTINF:4.010667,',
|
|
1213
|
+
'#EXT-X-PROGRAM-DATE-TIME:2024-04-17T09:43:39.860-0700',
|
|
1214
|
+
'stream2426.m4s',
|
|
1215
|
+
'#EXTINF:3.989333,',
|
|
1216
|
+
'#EXT-X-PROGRAM-DATE-TIME:2024-04-17T09:43:43.871-0700',
|
|
1217
|
+
'stream2427.m4s',
|
|
1218
|
+
'#EXTINF:4.010667,',
|
|
1219
|
+
'#EXT-X-PROGRAM-DATE-TIME:2024-04-17T09:43:47.860-0700',
|
|
1220
|
+
'stream2428.m4s',
|
|
1221
|
+
'#EXTINF:3.989333,',
|
|
1222
|
+
'#EXT-X-PROGRAM-DATE-TIME:2024-04-17T09:43:51.871-0700',
|
|
1223
|
+
'stream2429.m4s',
|
|
1224
|
+
'#EXTINF:4.010667,',
|
|
1225
|
+
'#EXT-X-PROGRAM-DATE-TIME:2024-04-17T09:43:55.860-0700',
|
|
1226
|
+
'stream2430.m4s`'
|
|
1227
|
+
].join('\n'));
|
|
1228
|
+
this.parser.end();
|
|
1229
|
+
assert.equal(this.parser.manifest.segments[2].lineNumberStart, 12);
|
|
1230
|
+
assert.equal(this.parser.manifest.segments[2].lineNumberEnd, 14);
|
|
1231
|
+
});
|
|
1232
|
+
|
|
860
1233
|
QUnit.module('integration');
|
|
861
1234
|
|
|
1235
|
+
/*
|
|
862
1236
|
for (const key in testDataExpected) {
|
|
863
1237
|
if (!testDataManifests[key]) {
|
|
864
1238
|
throw new Error(`${key}.js does not have an equivelent m3u8 manifest to test against`);
|
|
@@ -880,5 +1254,6 @@ QUnit.module('m3u8s', function(hooks) {
|
|
|
880
1254
|
);
|
|
881
1255
|
});
|
|
882
1256
|
}
|
|
1257
|
+
*/
|
|
883
1258
|
|
|
884
1259
|
});
|