m3u8-parser
Advanced tools
Comparing version 6.2.0 to 7.0.0
@@ -0,1 +1,17 @@ | ||
<a name="7.0.0"></a> | ||
# [7.0.0](https://github.com/videojs/m3u8-parser/compare/v6.2.0...v7.0.0) (2023-07-10) | ||
### Features | ||
* Add PDT to each segment ([#168](https://github.com/videojs/m3u8-parser/issues/168)) ([e7c683f](https://github.com/videojs/m3u8-parser/commit/e7c683f)) | ||
* output segment title from EXTINF ([#158](https://github.com/videojs/m3u8-parser/issues/158)) ([4adaa2c](https://github.com/videojs/m3u8-parser/commit/4adaa2c)) | ||
### Bug Fixes | ||
* rename daterange to dateRanges ([#166](https://github.com/videojs/m3u8-parser/issues/166)) ([516ab67](https://github.com/videojs/m3u8-parser/commit/516ab67)) | ||
### Documentation | ||
* correct `customType` option name ([#147](https://github.com/videojs/m3u8-parser/issues/147)) ([4d3e6ce](https://github.com/videojs/m3u8-parser/commit/4d3e6ce)) | ||
<a name="6.2.0"></a> | ||
@@ -2,0 +18,0 @@ # [6.2.0](https://github.com/videojs/m3u8-parser/compare/v6.1.0...v6.2.0) (2023-05-25) |
@@ -1,2 +0,2 @@ | ||
/*! @name m3u8-parser @version 6.2.0 @license Apache-2.0 */ | ||
/*! @name m3u8-parser @version 7.0.0 @license Apache-2.0 */ | ||
'use strict'; | ||
@@ -460,3 +460,2 @@ | ||
event.dateTimeString = match[1]; | ||
event.dateTimeObject = new Date(match[1]); | ||
} | ||
@@ -912,2 +911,3 @@ | ||
this.lineStream.pipe(this.parseStream); | ||
this.lastProgramDateTime = null; | ||
/* eslint-disable consistent-this */ | ||
@@ -943,2 +943,3 @@ | ||
discontinuityStarts: [], | ||
dateRanges: [], | ||
segments: [] | ||
@@ -952,3 +953,3 @@ }; // keep track of the last seen segment's byte range end, as segments are not required | ||
let lastPartByterangeEnd = 0; | ||
const daterangeTags = {}; | ||
const dateRangeTags = {}; | ||
this.on('end', () => { | ||
@@ -1049,2 +1050,6 @@ // only add preloadSegment if we don't yet have a uri for it. | ||
if (entry.title) { | ||
currentUri.title = entry.title; | ||
} | ||
if (entry.duration > 0) { | ||
@@ -1291,13 +1296,17 @@ currentUri.duration = entry.duration; | ||
'program-date-time'() { | ||
if (typeof this.manifest.dateTimeString === 'undefined') { | ||
// PROGRAM-DATE-TIME is a media-segment tag, but for backwards | ||
// compatibility, we add the first occurence of the PROGRAM-DATE-TIME tag | ||
// to the manifest object | ||
// TODO: Consider removing this in future major version | ||
this.manifest.dateTimeString = entry.dateTimeString; | ||
this.manifest.dateTimeObject = entry.dateTimeObject; | ||
const { | ||
lastProgramDateTime | ||
} = this; | ||
this.lastProgramDateTime = new Date(entry.dateTimeString).getTime(); // We should extrapolate Program Date Time backward only during first program date time occurrence. | ||
// Once we have at least one program date time point, we can always extrapolate it forward using lastProgramDateTime reference. | ||
if (lastProgramDateTime === null) { | ||
// Extrapolate Program Date Time backward | ||
// Since it is first program date time occurrence we're assuming that | ||
// all this.manifest.segments have no program date time info | ||
this.manifest.segments.reduceRight((programDateTime, segment) => { | ||
segment.programDateTime = programDateTime - segment.duration * 1000; | ||
return segment.programDateTime; | ||
}, this.lastProgramDateTime); | ||
} | ||
currentUri.dateTimeString = entry.dateTimeString; | ||
currentUri.dateTimeObject = entry.dateTimeObject; | ||
}, | ||
@@ -1466,9 +1475,8 @@ | ||
'daterange'() { | ||
this.manifest.daterange = this.manifest.daterange || []; | ||
this.manifest.daterange.push(camelCaseKeys(entry.attributes)); | ||
const index = this.manifest.daterange.length - 1; | ||
this.manifest.dateRanges.push(camelCaseKeys(entry.attributes)); | ||
const index = this.manifest.dateRanges.length - 1; | ||
this.warnOnMissingAttributes_(`#EXT-X-DATERANGE #${index}`, entry.attributes, ['ID', 'START-DATE']); | ||
const daterange = this.manifest.daterange[index]; | ||
const dateRange = this.manifest.dateRanges[index]; | ||
if (daterange.endDate && daterange.startDate && new Date(daterange.endDate) < new Date(daterange.startDate)) { | ||
if (dateRange.endDate && dateRange.startDate && new Date(dateRange.endDate) < new Date(dateRange.startDate)) { | ||
this.trigger('warn', { | ||
@@ -1479,3 +1487,3 @@ message: 'EXT-X-DATERANGE END-DATE must be equal to or later than the value of the START-DATE' | ||
if (daterange.duration && daterange.duration < 0) { | ||
if (dateRange.duration && dateRange.duration < 0) { | ||
this.trigger('warn', { | ||
@@ -1486,3 +1494,3 @@ message: 'EXT-X-DATERANGE DURATION must not be negative' | ||
if (daterange.plannedDuration && daterange.plannedDuration < 0) { | ||
if (dateRange.plannedDuration && dateRange.plannedDuration < 0) { | ||
this.trigger('warn', { | ||
@@ -1493,5 +1501,5 @@ message: 'EXT-X-DATERANGE PLANNED-DURATION must not be negative' | ||
const endOnNextYes = !!daterange.endOnNext; | ||
const endOnNextYes = !!dateRange.endOnNext; | ||
if (endOnNextYes && !daterange.class) { | ||
if (endOnNextYes && !dateRange.class) { | ||
this.trigger('warn', { | ||
@@ -1502,3 +1510,3 @@ message: 'EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must have a CLASS attribute' | ||
if (endOnNextYes && (daterange.duration || daterange.endDate)) { | ||
if (endOnNextYes && (dateRange.duration || dateRange.endDate)) { | ||
this.trigger('warn', { | ||
@@ -1509,19 +1517,13 @@ message: 'EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must not contain DURATION or END-DATE attributes' | ||
if (daterange.duration && daterange.endDate) { | ||
const startDate = daterange.startDate; | ||
const newDateInSeconds = startDate.setSeconds(startDate.getSeconds() + daterange.duration); | ||
this.manifest.daterange[index].endDate = new Date(newDateInSeconds); | ||
if (dateRange.duration && dateRange.endDate) { | ||
const startDate = dateRange.startDate; | ||
const newDateInSeconds = startDate.setSeconds(startDate.getSeconds() + dateRange.duration); | ||
this.manifest.dateRanges[index].endDate = new Date(newDateInSeconds); | ||
} | ||
if (daterange && !this.manifest.dateTimeString) { | ||
this.trigger('warn', { | ||
message: 'A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag' | ||
}); | ||
} | ||
if (!daterangeTags[daterange.id]) { | ||
daterangeTags[daterange.id] = daterange; | ||
if (!dateRangeTags[dateRange.id]) { | ||
dateRangeTags[dateRange.id] = dateRange; | ||
} else { | ||
for (const attribute in daterangeTags[daterange.id]) { | ||
if (daterangeTags[daterange.id][attribute] !== daterange[attribute]) { | ||
for (const attribute in dateRangeTags[dateRange.id]) { | ||
if (dateRangeTags[dateRange.id][attribute] !== dateRange[attribute]) { | ||
this.trigger('warn', { | ||
@@ -1566,4 +1568,10 @@ message: 'EXT-X-DATERANGE tags with the same ID in a playlist must have the same attributes and same attribute values' | ||
lastPartByterangeEnd = 0; // prepare for the next URI | ||
lastPartByterangeEnd = 0; // Once we have at least one program date time we can always extrapolate it forward | ||
if (this.lastProgramDateTime !== null) { | ||
currentUri.programDateTime = this.lastProgramDateTime; | ||
this.lastProgramDateTime += currentUri.duration * 1000; | ||
} // prepare for the next URI | ||
currentUri = {}; | ||
@@ -1624,2 +1632,10 @@ }, | ||
this.lineStream.push('\n'); | ||
if (this.manifest.dateRanges.length && this.lastProgramDateTime === null) { | ||
this.trigger('warn', { | ||
message: 'A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag' | ||
}); | ||
} | ||
this.lastProgramDateTime = null; | ||
this.trigger('end'); | ||
@@ -1632,3 +1648,3 @@ } | ||
* @param {RegExp} options.expression a regular expression to match the custom header | ||
* @param {string} options.type the type to register to the output | ||
* @param {string} options.customType the custom type to register to the output | ||
* @param {Function} [options.dataParser] function to parse the line into an object | ||
@@ -1635,0 +1651,0 @@ * @param {boolean} [options.segment] should tag data be attached to the segment object |
@@ -1,2 +0,2 @@ | ||
/*! @name m3u8-parser @version 6.2.0 @license Apache-2.0 */ | ||
/*! @name m3u8-parser @version 7.0.0 @license Apache-2.0 */ | ||
import Stream from '@videojs/vhs-utils/es/stream.js'; | ||
@@ -450,3 +450,2 @@ import _extends from '@babel/runtime/helpers/extends'; | ||
event.dateTimeString = match[1]; | ||
event.dateTimeObject = new Date(match[1]); | ||
} | ||
@@ -902,2 +901,3 @@ | ||
this.lineStream.pipe(this.parseStream); | ||
this.lastProgramDateTime = null; | ||
/* eslint-disable consistent-this */ | ||
@@ -933,2 +933,3 @@ | ||
discontinuityStarts: [], | ||
dateRanges: [], | ||
segments: [] | ||
@@ -942,3 +943,3 @@ }; // keep track of the last seen segment's byte range end, as segments are not required | ||
let lastPartByterangeEnd = 0; | ||
const daterangeTags = {}; | ||
const dateRangeTags = {}; | ||
this.on('end', () => { | ||
@@ -1039,2 +1040,6 @@ // only add preloadSegment if we don't yet have a uri for it. | ||
if (entry.title) { | ||
currentUri.title = entry.title; | ||
} | ||
if (entry.duration > 0) { | ||
@@ -1281,13 +1286,17 @@ currentUri.duration = entry.duration; | ||
'program-date-time'() { | ||
if (typeof this.manifest.dateTimeString === 'undefined') { | ||
// PROGRAM-DATE-TIME is a media-segment tag, but for backwards | ||
// compatibility, we add the first occurence of the PROGRAM-DATE-TIME tag | ||
// to the manifest object | ||
// TODO: Consider removing this in future major version | ||
this.manifest.dateTimeString = entry.dateTimeString; | ||
this.manifest.dateTimeObject = entry.dateTimeObject; | ||
const { | ||
lastProgramDateTime | ||
} = this; | ||
this.lastProgramDateTime = new Date(entry.dateTimeString).getTime(); // We should extrapolate Program Date Time backward only during first program date time occurrence. | ||
// Once we have at least one program date time point, we can always extrapolate it forward using lastProgramDateTime reference. | ||
if (lastProgramDateTime === null) { | ||
// Extrapolate Program Date Time backward | ||
// Since it is first program date time occurrence we're assuming that | ||
// all this.manifest.segments have no program date time info | ||
this.manifest.segments.reduceRight((programDateTime, segment) => { | ||
segment.programDateTime = programDateTime - segment.duration * 1000; | ||
return segment.programDateTime; | ||
}, this.lastProgramDateTime); | ||
} | ||
currentUri.dateTimeString = entry.dateTimeString; | ||
currentUri.dateTimeObject = entry.dateTimeObject; | ||
}, | ||
@@ -1456,9 +1465,8 @@ | ||
'daterange'() { | ||
this.manifest.daterange = this.manifest.daterange || []; | ||
this.manifest.daterange.push(camelCaseKeys(entry.attributes)); | ||
const index = this.manifest.daterange.length - 1; | ||
this.manifest.dateRanges.push(camelCaseKeys(entry.attributes)); | ||
const index = this.manifest.dateRanges.length - 1; | ||
this.warnOnMissingAttributes_(`#EXT-X-DATERANGE #${index}`, entry.attributes, ['ID', 'START-DATE']); | ||
const daterange = this.manifest.daterange[index]; | ||
const dateRange = this.manifest.dateRanges[index]; | ||
if (daterange.endDate && daterange.startDate && new Date(daterange.endDate) < new Date(daterange.startDate)) { | ||
if (dateRange.endDate && dateRange.startDate && new Date(dateRange.endDate) < new Date(dateRange.startDate)) { | ||
this.trigger('warn', { | ||
@@ -1469,3 +1477,3 @@ message: 'EXT-X-DATERANGE END-DATE must be equal to or later than the value of the START-DATE' | ||
if (daterange.duration && daterange.duration < 0) { | ||
if (dateRange.duration && dateRange.duration < 0) { | ||
this.trigger('warn', { | ||
@@ -1476,3 +1484,3 @@ message: 'EXT-X-DATERANGE DURATION must not be negative' | ||
if (daterange.plannedDuration && daterange.plannedDuration < 0) { | ||
if (dateRange.plannedDuration && dateRange.plannedDuration < 0) { | ||
this.trigger('warn', { | ||
@@ -1483,5 +1491,5 @@ message: 'EXT-X-DATERANGE PLANNED-DURATION must not be negative' | ||
const endOnNextYes = !!daterange.endOnNext; | ||
const endOnNextYes = !!dateRange.endOnNext; | ||
if (endOnNextYes && !daterange.class) { | ||
if (endOnNextYes && !dateRange.class) { | ||
this.trigger('warn', { | ||
@@ -1492,3 +1500,3 @@ message: 'EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must have a CLASS attribute' | ||
if (endOnNextYes && (daterange.duration || daterange.endDate)) { | ||
if (endOnNextYes && (dateRange.duration || dateRange.endDate)) { | ||
this.trigger('warn', { | ||
@@ -1499,19 +1507,13 @@ message: 'EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must not contain DURATION or END-DATE attributes' | ||
if (daterange.duration && daterange.endDate) { | ||
const startDate = daterange.startDate; | ||
const newDateInSeconds = startDate.setSeconds(startDate.getSeconds() + daterange.duration); | ||
this.manifest.daterange[index].endDate = new Date(newDateInSeconds); | ||
if (dateRange.duration && dateRange.endDate) { | ||
const startDate = dateRange.startDate; | ||
const newDateInSeconds = startDate.setSeconds(startDate.getSeconds() + dateRange.duration); | ||
this.manifest.dateRanges[index].endDate = new Date(newDateInSeconds); | ||
} | ||
if (daterange && !this.manifest.dateTimeString) { | ||
this.trigger('warn', { | ||
message: 'A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag' | ||
}); | ||
} | ||
if (!daterangeTags[daterange.id]) { | ||
daterangeTags[daterange.id] = daterange; | ||
if (!dateRangeTags[dateRange.id]) { | ||
dateRangeTags[dateRange.id] = dateRange; | ||
} else { | ||
for (const attribute in daterangeTags[daterange.id]) { | ||
if (daterangeTags[daterange.id][attribute] !== daterange[attribute]) { | ||
for (const attribute in dateRangeTags[dateRange.id]) { | ||
if (dateRangeTags[dateRange.id][attribute] !== dateRange[attribute]) { | ||
this.trigger('warn', { | ||
@@ -1556,4 +1558,10 @@ message: 'EXT-X-DATERANGE tags with the same ID in a playlist must have the same attributes and same attribute values' | ||
lastPartByterangeEnd = 0; // prepare for the next URI | ||
lastPartByterangeEnd = 0; // Once we have at least one program date time we can always extrapolate it forward | ||
if (this.lastProgramDateTime !== null) { | ||
currentUri.programDateTime = this.lastProgramDateTime; | ||
this.lastProgramDateTime += currentUri.duration * 1000; | ||
} // prepare for the next URI | ||
currentUri = {}; | ||
@@ -1614,2 +1622,10 @@ }, | ||
this.lineStream.push('\n'); | ||
if (this.manifest.dateRanges.length && this.lastProgramDateTime === null) { | ||
this.trigger('warn', { | ||
message: 'A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag' | ||
}); | ||
} | ||
this.lastProgramDateTime = null; | ||
this.trigger('end'); | ||
@@ -1622,3 +1638,3 @@ } | ||
* @param {RegExp} options.expression a regular expression to match the custom header | ||
* @param {string} options.type the type to register to the output | ||
* @param {string} options.customType the custom type to register to the output | ||
* @param {Function} [options.dataParser] function to parse the line into an object | ||
@@ -1625,0 +1641,0 @@ * @param {boolean} [options.segment] should tag data be attached to the segment object |
@@ -1,2 +0,2 @@ | ||
/*! @name m3u8-parser @version 6.2.0 @license Apache-2.0 */ | ||
/*! @name m3u8-parser @version 7.0.0 @license Apache-2.0 */ | ||
(function (global, factory) { | ||
@@ -593,3 +593,2 @@ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
event.dateTimeString = match[1]; | ||
event.dateTimeObject = new Date(match[1]); | ||
} | ||
@@ -1060,2 +1059,3 @@ | ||
this.lineStream.pipe(this.parseStream); | ||
this.lastProgramDateTime = null; | ||
/* eslint-disable consistent-this */ | ||
@@ -1091,2 +1091,3 @@ | ||
discontinuityStarts: [], | ||
dateRanges: [], | ||
segments: [] | ||
@@ -1100,3 +1101,3 @@ }; // keep track of the last seen segment's byte range end, as segments are not required | ||
let lastPartByterangeEnd = 0; | ||
const daterangeTags = {}; | ||
const dateRangeTags = {}; | ||
this.on('end', () => { | ||
@@ -1197,2 +1198,6 @@ // only add preloadSegment if we don't yet have a uri for it. | ||
if (entry.title) { | ||
currentUri.title = entry.title; | ||
} | ||
if (entry.duration > 0) { | ||
@@ -1439,13 +1444,17 @@ currentUri.duration = entry.duration; | ||
'program-date-time'() { | ||
if (typeof this.manifest.dateTimeString === 'undefined') { | ||
// PROGRAM-DATE-TIME is a media-segment tag, but for backwards | ||
// compatibility, we add the first occurence of the PROGRAM-DATE-TIME tag | ||
// to the manifest object | ||
// TODO: Consider removing this in future major version | ||
this.manifest.dateTimeString = entry.dateTimeString; | ||
this.manifest.dateTimeObject = entry.dateTimeObject; | ||
const { | ||
lastProgramDateTime | ||
} = this; | ||
this.lastProgramDateTime = new Date(entry.dateTimeString).getTime(); // We should extrapolate Program Date Time backward only during first program date time occurrence. | ||
// Once we have at least one program date time point, we can always extrapolate it forward using lastProgramDateTime reference. | ||
if (lastProgramDateTime === null) { | ||
// Extrapolate Program Date Time backward | ||
// Since it is first program date time occurrence we're assuming that | ||
// all this.manifest.segments have no program date time info | ||
this.manifest.segments.reduceRight((programDateTime, segment) => { | ||
segment.programDateTime = programDateTime - segment.duration * 1000; | ||
return segment.programDateTime; | ||
}, this.lastProgramDateTime); | ||
} | ||
currentUri.dateTimeString = entry.dateTimeString; | ||
currentUri.dateTimeObject = entry.dateTimeObject; | ||
}, | ||
@@ -1614,9 +1623,8 @@ | ||
'daterange'() { | ||
this.manifest.daterange = this.manifest.daterange || []; | ||
this.manifest.daterange.push(camelCaseKeys(entry.attributes)); | ||
const index = this.manifest.daterange.length - 1; | ||
this.manifest.dateRanges.push(camelCaseKeys(entry.attributes)); | ||
const index = this.manifest.dateRanges.length - 1; | ||
this.warnOnMissingAttributes_(`#EXT-X-DATERANGE #${index}`, entry.attributes, ['ID', 'START-DATE']); | ||
const daterange = this.manifest.daterange[index]; | ||
const dateRange = this.manifest.dateRanges[index]; | ||
if (daterange.endDate && daterange.startDate && new Date(daterange.endDate) < new Date(daterange.startDate)) { | ||
if (dateRange.endDate && dateRange.startDate && new Date(dateRange.endDate) < new Date(dateRange.startDate)) { | ||
this.trigger('warn', { | ||
@@ -1627,3 +1635,3 @@ message: 'EXT-X-DATERANGE END-DATE must be equal to or later than the value of the START-DATE' | ||
if (daterange.duration && daterange.duration < 0) { | ||
if (dateRange.duration && dateRange.duration < 0) { | ||
this.trigger('warn', { | ||
@@ -1634,3 +1642,3 @@ message: 'EXT-X-DATERANGE DURATION must not be negative' | ||
if (daterange.plannedDuration && daterange.plannedDuration < 0) { | ||
if (dateRange.plannedDuration && dateRange.plannedDuration < 0) { | ||
this.trigger('warn', { | ||
@@ -1641,5 +1649,5 @@ message: 'EXT-X-DATERANGE PLANNED-DURATION must not be negative' | ||
const endOnNextYes = !!daterange.endOnNext; | ||
const endOnNextYes = !!dateRange.endOnNext; | ||
if (endOnNextYes && !daterange.class) { | ||
if (endOnNextYes && !dateRange.class) { | ||
this.trigger('warn', { | ||
@@ -1650,3 +1658,3 @@ message: 'EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must have a CLASS attribute' | ||
if (endOnNextYes && (daterange.duration || daterange.endDate)) { | ||
if (endOnNextYes && (dateRange.duration || dateRange.endDate)) { | ||
this.trigger('warn', { | ||
@@ -1657,19 +1665,13 @@ message: 'EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must not contain DURATION or END-DATE attributes' | ||
if (daterange.duration && daterange.endDate) { | ||
const startDate = daterange.startDate; | ||
const newDateInSeconds = startDate.setSeconds(startDate.getSeconds() + daterange.duration); | ||
this.manifest.daterange[index].endDate = new Date(newDateInSeconds); | ||
if (dateRange.duration && dateRange.endDate) { | ||
const startDate = dateRange.startDate; | ||
const newDateInSeconds = startDate.setSeconds(startDate.getSeconds() + dateRange.duration); | ||
this.manifest.dateRanges[index].endDate = new Date(newDateInSeconds); | ||
} | ||
if (daterange && !this.manifest.dateTimeString) { | ||
this.trigger('warn', { | ||
message: 'A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag' | ||
}); | ||
} | ||
if (!daterangeTags[daterange.id]) { | ||
daterangeTags[daterange.id] = daterange; | ||
if (!dateRangeTags[dateRange.id]) { | ||
dateRangeTags[dateRange.id] = dateRange; | ||
} else { | ||
for (const attribute in daterangeTags[daterange.id]) { | ||
if (daterangeTags[daterange.id][attribute] !== daterange[attribute]) { | ||
for (const attribute in dateRangeTags[dateRange.id]) { | ||
if (dateRangeTags[dateRange.id][attribute] !== dateRange[attribute]) { | ||
this.trigger('warn', { | ||
@@ -1714,4 +1716,10 @@ message: 'EXT-X-DATERANGE tags with the same ID in a playlist must have the same attributes and same attribute values' | ||
lastPartByterangeEnd = 0; // prepare for the next URI | ||
lastPartByterangeEnd = 0; // Once we have at least one program date time we can always extrapolate it forward | ||
if (this.lastProgramDateTime !== null) { | ||
currentUri.programDateTime = this.lastProgramDateTime; | ||
this.lastProgramDateTime += currentUri.duration * 1000; | ||
} // prepare for the next URI | ||
currentUri = {}; | ||
@@ -1772,2 +1780,10 @@ }, | ||
this.lineStream.push('\n'); | ||
if (this.manifest.dateRanges.length && this.lastProgramDateTime === null) { | ||
this.trigger('warn', { | ||
message: 'A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag' | ||
}); | ||
} | ||
this.lastProgramDateTime = null; | ||
this.trigger('end'); | ||
@@ -1780,3 +1796,3 @@ } | ||
* @param {RegExp} options.expression a regular expression to match the custom header | ||
* @param {string} options.type the type to register to the output | ||
* @param {string} options.customType the custom type to register to the output | ||
* @param {Function} [options.dataParser] function to parse the line into an object | ||
@@ -1783,0 +1799,0 @@ * @param {boolean} [options.segment] should tag data be attached to the segment object |
@@ -1,2 +0,2 @@ | ||
/*! @name m3u8-parser @version 6.2.0 @license Apache-2.0 */ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).m3u8Parser={})}(this,(function(t){"use strict";var e=function(){function t(){this.listeners={}}var e=t.prototype;return e.on=function(t,e){this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(e)},e.off=function(t,e){if(!this.listeners[t])return!1;var i=this.listeners[t].indexOf(e);return this.listeners[t]=this.listeners[t].slice(0),this.listeners[t].splice(i,1),i>-1},e.trigger=function(t){var e=this.listeners[t];if(e)if(2===arguments.length)for(var i=e.length,a=0;a<i;++a)e[a].call(this,arguments[1]);else for(var s=Array.prototype.slice.call(arguments,1),r=e.length,n=0;n<r;++n)e[n].apply(this,s)},e.dispose=function(){this.listeners={}},e.pipe=function(t){this.on("data",(function(e){t.push(e)}))},t}();class i extends e{constructor(){super(),this.buffer=""}push(t){let e;for(this.buffer+=t,e=this.buffer.indexOf("\n");e>-1;e=this.buffer.indexOf("\n"))this.trigger("data",this.buffer.substring(0,e)),this.buffer=this.buffer.substring(e+1)}}function a(){return s=a=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var a in i)Object.prototype.hasOwnProperty.call(i,a)&&(t[a]=i[a])}return t},a.apply(this,arguments)}var s=a,r=s;const n=String.fromCharCode(9),u=function(t){const e=/([0-9.]*)?@?([0-9.]*)?/.exec(t||""),i={};return e[1]&&(i.length=parseInt(e[1],10)),e[2]&&(i.offset=parseInt(e[2],10)),i},o=function(t){const e={};if(!t)return e;const i=t.split(new RegExp('(?:^|,)((?:[^=]*)=(?:"[^"]*"|[^,]*))'));let a,s=i.length;for(;s--;)""!==i[s]&&(a=/([^=]*)=(.*)/.exec(i[s]).slice(1),a[0]=a[0].replace(/^\s+|\s+$/g,""),a[1]=a[1].replace(/^\s+|\s+$/g,""),a[1]=a[1].replace(/^['"](.*)['"]$/g,"$1"),e[a[0]]=a[1]);return e};class g extends e{constructor(){super(),this.customParsers=[],this.tagMappers=[]}push(t){let e,i;if(0===(t=t.trim()).length)return;if("#"!==t[0])return void this.trigger("data",{type:"uri",uri:t});this.tagMappers.reduce(((e,i)=>{const a=i(t);return a===t?e:e.concat([a])}),[t]).forEach((t=>{for(let e=0;e<this.customParsers.length;e++)if(this.customParsers[e].call(this,t))return;if(0===t.indexOf("#EXT"))if(t=t.replace("\r",""),e=/^#EXTM3U/.exec(t),e)this.trigger("data",{type:"tag",tagType:"m3u"});else{if(e=/^#EXTINF:([0-9\.]*)?,?(.*)?$/.exec(t),e)return i={type:"tag",tagType:"inf"},e[1]&&(i.duration=parseFloat(e[1])),e[2]&&(i.title=e[2]),void this.trigger("data",i);if(e=/^#EXT-X-TARGETDURATION:([0-9.]*)?/.exec(t),e)return i={type:"tag",tagType:"targetduration"},e[1]&&(i.duration=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-VERSION:([0-9.]*)?/.exec(t),e)return i={type:"tag",tagType:"version"},e[1]&&(i.version=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-MEDIA-SEQUENCE:(\-?[0-9.]*)?/.exec(t),e)return i={type:"tag",tagType:"media-sequence"},e[1]&&(i.number=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-DISCONTINUITY-SEQUENCE:(\-?[0-9.]*)?/.exec(t),e)return i={type:"tag",tagType:"discontinuity-sequence"},e[1]&&(i.number=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-PLAYLIST-TYPE:(.*)?$/.exec(t),e)return i={type:"tag",tagType:"playlist-type"},e[1]&&(i.playlistType=e[1]),void this.trigger("data",i);if(e=/^#EXT-X-BYTERANGE:(.*)?$/.exec(t),e)return i=r(u(e[1]),{type:"tag",tagType:"byterange"}),void this.trigger("data",i);if(e=/^#EXT-X-ALLOW-CACHE:(YES|NO)?/.exec(t),e)return i={type:"tag",tagType:"allow-cache"},e[1]&&(i.allowed=!/NO/.test(e[1])),void this.trigger("data",i);if(e=/^#EXT-X-MAP:(.*)$/.exec(t),e){if(i={type:"tag",tagType:"map"},e[1]){const t=o(e[1]);t.URI&&(i.uri=t.URI),t.BYTERANGE&&(i.byterange=u(t.BYTERANGE))}this.trigger("data",i)}else if(e=/^#EXT-X-STREAM-INF:(.*)$/.exec(t),e){if(i={type:"tag",tagType:"stream-inf"},e[1]){if(i.attributes=o(e[1]),i.attributes.RESOLUTION){const t=i.attributes.RESOLUTION.split("x"),e={};t[0]&&(e.width=parseInt(t[0],10)),t[1]&&(e.height=parseInt(t[1],10)),i.attributes.RESOLUTION=e}i.attributes.BANDWIDTH&&(i.attributes.BANDWIDTH=parseInt(i.attributes.BANDWIDTH,10)),i.attributes["FRAME-RATE"]&&(i.attributes["FRAME-RATE"]=parseFloat(i.attributes["FRAME-RATE"])),i.attributes["PROGRAM-ID"]&&(i.attributes["PROGRAM-ID"]=parseInt(i.attributes["PROGRAM-ID"],10))}this.trigger("data",i)}else{if(e=/^#EXT-X-MEDIA:(.*)$/.exec(t),e)return i={type:"tag",tagType:"media"},e[1]&&(i.attributes=o(e[1])),void this.trigger("data",i);if(e=/^#EXT-X-ENDLIST/.exec(t),e)this.trigger("data",{type:"tag",tagType:"endlist"});else if(e=/^#EXT-X-DISCONTINUITY/.exec(t),e)this.trigger("data",{type:"tag",tagType:"discontinuity"});else{if(e=/^#EXT-X-PROGRAM-DATE-TIME:(.*)$/.exec(t),e)return i={type:"tag",tagType:"program-date-time"},e[1]&&(i.dateTimeString=e[1],i.dateTimeObject=new Date(e[1])),void this.trigger("data",i);if(e=/^#EXT-X-KEY:(.*)$/.exec(t),e)return i={type:"tag",tagType:"key"},e[1]&&(i.attributes=o(e[1]),i.attributes.IV&&("0x"===i.attributes.IV.substring(0,2).toLowerCase()&&(i.attributes.IV=i.attributes.IV.substring(2)),i.attributes.IV=i.attributes.IV.match(/.{8}/g),i.attributes.IV[0]=parseInt(i.attributes.IV[0],16),i.attributes.IV[1]=parseInt(i.attributes.IV[1],16),i.attributes.IV[2]=parseInt(i.attributes.IV[2],16),i.attributes.IV[3]=parseInt(i.attributes.IV[3],16),i.attributes.IV=new Uint32Array(i.attributes.IV))),void this.trigger("data",i);if(e=/^#EXT-X-START:(.*)$/.exec(t),e)return i={type:"tag",tagType:"start"},e[1]&&(i.attributes=o(e[1]),i.attributes["TIME-OFFSET"]=parseFloat(i.attributes["TIME-OFFSET"]),i.attributes.PRECISE=/YES/.test(i.attributes.PRECISE)),void this.trigger("data",i);if(e=/^#EXT-X-CUE-OUT-CONT:(.*)?$/.exec(t),e)return i={type:"tag",tagType:"cue-out-cont"},e[1]?i.data=e[1]:i.data="",void this.trigger("data",i);if(e=/^#EXT-X-CUE-OUT:(.*)?$/.exec(t),e)return i={type:"tag",tagType:"cue-out"},e[1]?i.data=e[1]:i.data="",void this.trigger("data",i);if(e=/^#EXT-X-CUE-IN:(.*)?$/.exec(t),e)return i={type:"tag",tagType:"cue-in"},e[1]?i.data=e[1]:i.data="",void this.trigger("data",i);if(e=/^#EXT-X-SKIP:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"skip"},i.attributes=o(e[1]),i.attributes.hasOwnProperty("SKIPPED-SEGMENTS")&&(i.attributes["SKIPPED-SEGMENTS"]=parseInt(i.attributes["SKIPPED-SEGMENTS"],10)),i.attributes.hasOwnProperty("RECENTLY-REMOVED-DATERANGES")&&(i.attributes["RECENTLY-REMOVED-DATERANGES"]=i.attributes["RECENTLY-REMOVED-DATERANGES"].split(n)),void this.trigger("data",i);if(e=/^#EXT-X-PART:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"part"},i.attributes=o(e[1]),["DURATION"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=parseFloat(i.attributes[t]))})),["INDEPENDENT","GAP"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=/YES/.test(i.attributes[t]))})),i.attributes.hasOwnProperty("BYTERANGE")&&(i.attributes.byterange=u(i.attributes.BYTERANGE)),void this.trigger("data",i);if(e=/^#EXT-X-SERVER-CONTROL:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"server-control"},i.attributes=o(e[1]),["CAN-SKIP-UNTIL","PART-HOLD-BACK","HOLD-BACK"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=parseFloat(i.attributes[t]))})),["CAN-SKIP-DATERANGES","CAN-BLOCK-RELOAD"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=/YES/.test(i.attributes[t]))})),void this.trigger("data",i);if(e=/^#EXT-X-PART-INF:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"part-inf"},i.attributes=o(e[1]),["PART-TARGET"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=parseFloat(i.attributes[t]))})),void this.trigger("data",i);if(e=/^#EXT-X-PRELOAD-HINT:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"preload-hint"},i.attributes=o(e[1]),["BYTERANGE-START","BYTERANGE-LENGTH"].forEach((function(t){if(i.attributes.hasOwnProperty(t)){i.attributes[t]=parseInt(i.attributes[t],10);const e="BYTERANGE-LENGTH"===t?"length":"offset";i.attributes.byterange=i.attributes.byterange||{},i.attributes.byterange[e]=i.attributes[t],delete i.attributes[t]}})),void this.trigger("data",i);if(e=/^#EXT-X-RENDITION-REPORT:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"rendition-report"},i.attributes=o(e[1]),["LAST-MSN","LAST-PART"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=parseInt(i.attributes[t],10))})),void this.trigger("data",i);if(e=/^#EXT-X-DATERANGE:(.*)$/.exec(t),e&&e[1]){i={type:"tag",tagType:"daterange"},i.attributes=o(e[1]),["ID","CLASS"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=String(i.attributes[t]))})),["START-DATE","END-DATE"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=new Date(i.attributes[t]))})),["DURATION","PLANNED-DURATION"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=parseFloat(i.attributes[t]))})),["END-ON-NEXT"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=/YES/i.test(i.attributes[t]))})),["SCTE35-CMD"," SCTE35-OUT","SCTE35-IN"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=i.attributes[t].toString(16))}));const t=/^X-([A-Z]+-)+[A-Z]+$/;for(const e in i.attributes){if(!t.test(e))continue;const a=/[0-9A-Fa-f]{6}/g.test(i.attributes[e]),s=/^\d+(\.\d+)?$/.test(i.attributes[e]);i.attributes[e]=a?i.attributes[e].toString(16):s?parseFloat(i.attributes[e]):String(i.attributes[e])}this.trigger("data",i)}else e=/^#EXT-X-INDEPENDENT-SEGMENTS/.exec(t),e?this.trigger("data",{type:"tag",tagType:"independent-segments"}):this.trigger("data",{type:"tag",data:t.slice(4)})}}}else this.trigger("data",{type:"comment",text:t.slice(1)})}))}addParser({expression:t,customType:e,dataParser:i,segment:a}){"function"!=typeof i&&(i=t=>t),this.customParsers.push((s=>{if(t.exec(s))return this.trigger("data",{type:"custom",data:i(s),customType:e,segment:a}),!0}))}addTagMapper({expression:t,map:e}){this.tagMappers.push((i=>t.test(i)?e(i):i))}}function h(t){for(var e,i=(e=t,window.atob?window.atob(e):Buffer.from(e,"base64").toString("binary")),a=new Uint8Array(i.length),s=0;s<i.length;s++)a[s]=i.charCodeAt(s);return a}const p=function(t){const e={};return Object.keys(t).forEach((function(i){var a;e[(a=i,a.toLowerCase().replace(/-(\w)/g,(t=>t[1].toUpperCase())))]=t[i]})),e},d=function(t){const{serverControl:e,targetDuration:i,partTargetDuration:a}=t;if(!e)return;const s="#EXT-X-SERVER-CONTROL",r="holdBack",n="partHoldBack",u=i&&3*i,o=a&&2*a;i&&!e.hasOwnProperty(r)&&(e[r]=u,this.trigger("info",{message:`${s} defaulting HOLD-BACK to targetDuration * 3 (${u}).`})),u&&e[r]<u&&(this.trigger("warn",{message:`${s} clamping HOLD-BACK (${e[r]}) to targetDuration * 3 (${u})`}),e[r]=u),a&&!e.hasOwnProperty(n)&&(e[n]=3*a,this.trigger("info",{message:`${s} defaulting PART-HOLD-BACK to partTargetDuration * 3 (${e[n]}).`})),a&&e[n]<o&&(this.trigger("warn",{message:`${s} clamping PART-HOLD-BACK (${e[n]}) to partTargetDuration * 2 (${o}).`}),e[n]=o)};t.LineStream=i,t.ParseStream=g,t.Parser=class extends e{constructor(){super(),this.lineStream=new i,this.parseStream=new g,this.lineStream.pipe(this.parseStream);const t=this,e=[];let a,s,n={},u=!1;const o=function(){},f={AUDIO:{},VIDEO:{},"CLOSED-CAPTIONS":{},SUBTITLES:{}};let E=0;this.manifest={allowCache:!0,discontinuityStarts:[],segments:[]};let c=0,T=0;const b={};this.on("end",(()=>{n.uri||!n.parts&&!n.preloadHints||(!n.map&&a&&(n.map=a),!n.key&&s&&(n.key=s),n.timeline||"number"!=typeof E||(n.timeline=E),this.manifest.preloadSegment=n)})),this.parseStream.on("data",(function(i){let g,m;({tag(){({version(){i.version&&(this.manifest.version=i.version)},"allow-cache"(){this.manifest.allowCache=i.allowed,"allowed"in i||(this.trigger("info",{message:"defaulting allowCache to YES"}),this.manifest.allowCache=!0)},byterange(){const t={};"length"in i&&(n.byterange=t,t.length=i.length,"offset"in i||(i.offset=c)),"offset"in i&&(n.byterange=t,t.offset=i.offset),c=t.offset+t.length},endlist(){this.manifest.endList=!0},inf(){"mediaSequence"in this.manifest||(this.manifest.mediaSequence=0,this.trigger("info",{message:"defaulting media sequence to zero"})),"discontinuitySequence"in this.manifest||(this.manifest.discontinuitySequence=0,this.trigger("info",{message:"defaulting discontinuity sequence to zero"})),i.duration>0&&(n.duration=i.duration),0===i.duration&&(n.duration=.01,this.trigger("info",{message:"updating zero segment duration to a small value"})),this.manifest.segments=e},key(){if(i.attributes)if("NONE"!==i.attributes.METHOD)if(i.attributes.URI){if("com.apple.streamingkeydelivery"===i.attributes.KEYFORMAT)return this.manifest.contentProtection=this.manifest.contentProtection||{},void(this.manifest.contentProtection["com.apple.fps.1_0"]={attributes:i.attributes});if("com.microsoft.playready"===i.attributes.KEYFORMAT)return this.manifest.contentProtection=this.manifest.contentProtection||{},void(this.manifest.contentProtection["com.microsoft.playready"]={uri:i.attributes.URI});if("urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"===i.attributes.KEYFORMAT){return-1===["SAMPLE-AES","SAMPLE-AES-CTR","SAMPLE-AES-CENC"].indexOf(i.attributes.METHOD)?void this.trigger("warn",{message:"invalid key method provided for Widevine"}):("SAMPLE-AES-CENC"===i.attributes.METHOD&&this.trigger("warn",{message:"SAMPLE-AES-CENC is deprecated, please use SAMPLE-AES-CTR instead"}),"data:text/plain;base64,"!==i.attributes.URI.substring(0,23)?void this.trigger("warn",{message:"invalid key URI provided for Widevine"}):i.attributes.KEYID&&"0x"===i.attributes.KEYID.substring(0,2)?(this.manifest.contentProtection=this.manifest.contentProtection||{},void(this.manifest.contentProtection["com.widevine.alpha"]={attributes:{schemeIdUri:i.attributes.KEYFORMAT,keyId:i.attributes.KEYID.substring(2)},pssh:h(i.attributes.URI.split(",")[1])})):void this.trigger("warn",{message:"invalid key ID provided for Widevine"}))}i.attributes.METHOD||this.trigger("warn",{message:"defaulting key method to AES-128"}),s={method:i.attributes.METHOD||"AES-128",uri:i.attributes.URI},void 0!==i.attributes.IV&&(s.iv=i.attributes.IV)}else this.trigger("warn",{message:"ignoring key declaration without URI"});else s=null;else this.trigger("warn",{message:"ignoring key declaration without attribute list"})},"media-sequence"(){isFinite(i.number)?this.manifest.mediaSequence=i.number:this.trigger("warn",{message:"ignoring invalid media sequence: "+i.number})},"discontinuity-sequence"(){isFinite(i.number)?(this.manifest.discontinuitySequence=i.number,E=i.number):this.trigger("warn",{message:"ignoring invalid discontinuity sequence: "+i.number})},"playlist-type"(){/VOD|EVENT/.test(i.playlistType)?this.manifest.playlistType=i.playlistType:this.trigger("warn",{message:"ignoring unknown playlist type: "+i.playlist})},map(){a={},i.uri&&(a.uri=i.uri),i.byterange&&(a.byterange=i.byterange),s&&(a.key=s)},"stream-inf"(){this.manifest.playlists=e,this.manifest.mediaGroups=this.manifest.mediaGroups||f,i.attributes?(n.attributes||(n.attributes={}),r(n.attributes,i.attributes)):this.trigger("warn",{message:"ignoring empty stream-inf attributes"})},media(){if(this.manifest.mediaGroups=this.manifest.mediaGroups||f,!(i.attributes&&i.attributes.TYPE&&i.attributes["GROUP-ID"]&&i.attributes.NAME))return void this.trigger("warn",{message:"ignoring incomplete or missing media group"});const t=this.manifest.mediaGroups[i.attributes.TYPE];t[i.attributes["GROUP-ID"]]=t[i.attributes["GROUP-ID"]]||{},g=t[i.attributes["GROUP-ID"]],m={default:/yes/i.test(i.attributes.DEFAULT)},m.default?m.autoselect=!0:m.autoselect=/yes/i.test(i.attributes.AUTOSELECT),i.attributes.LANGUAGE&&(m.language=i.attributes.LANGUAGE),i.attributes.URI&&(m.uri=i.attributes.URI),i.attributes["INSTREAM-ID"]&&(m.instreamId=i.attributes["INSTREAM-ID"]),i.attributes.CHARACTERISTICS&&(m.characteristics=i.attributes.CHARACTERISTICS),i.attributes.FORCED&&(m.forced=/yes/i.test(i.attributes.FORCED)),g[i.attributes.NAME]=m},discontinuity(){E+=1,n.discontinuity=!0,this.manifest.discontinuityStarts.push(e.length)},"program-date-time"(){void 0===this.manifest.dateTimeString&&(this.manifest.dateTimeString=i.dateTimeString,this.manifest.dateTimeObject=i.dateTimeObject),n.dateTimeString=i.dateTimeString,n.dateTimeObject=i.dateTimeObject},targetduration(){!isFinite(i.duration)||i.duration<0?this.trigger("warn",{message:"ignoring invalid target duration: "+i.duration}):(this.manifest.targetDuration=i.duration,d.call(this,this.manifest))},start(){i.attributes&&!isNaN(i.attributes["TIME-OFFSET"])?this.manifest.start={timeOffset:i.attributes["TIME-OFFSET"],precise:i.attributes.PRECISE}:this.trigger("warn",{message:"ignoring start declaration without appropriate attribute list"})},"cue-out"(){n.cueOut=i.data},"cue-out-cont"(){n.cueOutCont=i.data},"cue-in"(){n.cueIn=i.data},skip(){this.manifest.skip=p(i.attributes),this.warnOnMissingAttributes_("#EXT-X-SKIP",i.attributes,["SKIPPED-SEGMENTS"])},part(){u=!0;const t=this.manifest.segments.length,e=p(i.attributes);n.parts=n.parts||[],n.parts.push(e),e.byterange&&(e.byterange.hasOwnProperty("offset")||(e.byterange.offset=T),T=e.byterange.offset+e.byterange.length);const a=n.parts.length-1;this.warnOnMissingAttributes_(`#EXT-X-PART #${a} for segment #${t}`,i.attributes,["URI","DURATION"]),this.manifest.renditionReports&&this.manifest.renditionReports.forEach(((t,e)=>{t.hasOwnProperty("lastPart")||this.trigger("warn",{message:`#EXT-X-RENDITION-REPORT #${e} lacks required attribute(s): LAST-PART`})}))},"server-control"(){const t=this.manifest.serverControl=p(i.attributes);t.hasOwnProperty("canBlockReload")||(t.canBlockReload=!1,this.trigger("info",{message:"#EXT-X-SERVER-CONTROL defaulting CAN-BLOCK-RELOAD to false"})),d.call(this,this.manifest),t.canSkipDateranges&&!t.hasOwnProperty("canSkipUntil")&&this.trigger("warn",{message:"#EXT-X-SERVER-CONTROL lacks required attribute CAN-SKIP-UNTIL which is required when CAN-SKIP-DATERANGES is set"})},"preload-hint"(){const t=this.manifest.segments.length,e=p(i.attributes),a=e.type&&"PART"===e.type;n.preloadHints=n.preloadHints||[],n.preloadHints.push(e),e.byterange&&(e.byterange.hasOwnProperty("offset")||(e.byterange.offset=a?T:0,a&&(T=e.byterange.offset+e.byterange.length)));const s=n.preloadHints.length-1;if(this.warnOnMissingAttributes_(`#EXT-X-PRELOAD-HINT #${s} for segment #${t}`,i.attributes,["TYPE","URI"]),e.type)for(let i=0;i<n.preloadHints.length-1;i++){const a=n.preloadHints[i];a.type&&(a.type===e.type&&this.trigger("warn",{message:`#EXT-X-PRELOAD-HINT #${s} for segment #${t} has the same TYPE ${e.type} as preload hint #${i}`}))}},"rendition-report"(){const t=p(i.attributes);this.manifest.renditionReports=this.manifest.renditionReports||[],this.manifest.renditionReports.push(t);const e=this.manifest.renditionReports.length-1,a=["LAST-MSN","URI"];u&&a.push("LAST-PART"),this.warnOnMissingAttributes_(`#EXT-X-RENDITION-REPORT #${e}`,i.attributes,a)},"part-inf"(){this.manifest.partInf=p(i.attributes),this.warnOnMissingAttributes_("#EXT-X-PART-INF",i.attributes,["PART-TARGET"]),this.manifest.partInf.partTarget&&(this.manifest.partTargetDuration=this.manifest.partInf.partTarget),d.call(this,this.manifest)},daterange(){this.manifest.daterange=this.manifest.daterange||[],this.manifest.daterange.push(p(i.attributes));const t=this.manifest.daterange.length-1;this.warnOnMissingAttributes_(`#EXT-X-DATERANGE #${t}`,i.attributes,["ID","START-DATE"]);const e=this.manifest.daterange[t];e.endDate&&e.startDate&&new Date(e.endDate)<new Date(e.startDate)&&this.trigger("warn",{message:"EXT-X-DATERANGE END-DATE must be equal to or later than the value of the START-DATE"}),e.duration&&e.duration<0&&this.trigger("warn",{message:"EXT-X-DATERANGE DURATION must not be negative"}),e.plannedDuration&&e.plannedDuration<0&&this.trigger("warn",{message:"EXT-X-DATERANGE PLANNED-DURATION must not be negative"});const a=!!e.endOnNext;if(a&&!e.class&&this.trigger("warn",{message:"EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must have a CLASS attribute"}),a&&(e.duration||e.endDate)&&this.trigger("warn",{message:"EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must not contain DURATION or END-DATE attributes"}),e.duration&&e.endDate){const i=e.startDate,a=i.setSeconds(i.getSeconds()+e.duration);this.manifest.daterange[t].endDate=new Date(a)}if(e&&!this.manifest.dateTimeString&&this.trigger("warn",{message:"A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag"}),b[e.id]){for(const t in b[e.id])if(b[e.id][t]!==e[t]){this.trigger("warn",{message:"EXT-X-DATERANGE tags with the same ID in a playlist must have the same attributes and same attribute values"});break}}else b[e.id]=e},"independent-segments"(){this.manifest.independentSegments=!0}}[i.tagType]||o).call(t)},uri(){n.uri=i.uri,e.push(n),this.manifest.targetDuration&&!("duration"in n)&&(this.trigger("warn",{message:"defaulting segment duration to the target duration"}),n.duration=this.manifest.targetDuration),s&&(n.key=s),n.timeline=E,a&&(n.map=a),T=0,n={}},comment(){},custom(){i.segment?(n.custom=n.custom||{},n.custom[i.customType]=i.data):(this.manifest.custom=this.manifest.custom||{},this.manifest.custom[i.customType]=i.data)}})[i.type].call(t)}))}warnOnMissingAttributes_(t,e,i){const a=[];i.forEach((function(t){e.hasOwnProperty(t)||a.push(t)})),a.length&&this.trigger("warn",{message:`${t} lacks required attribute(s): ${a.join(", ")}`})}push(t){this.lineStream.push(t)}end(){this.lineStream.push("\n"),this.trigger("end")}addParser(t){this.parseStream.addParser(t)}addTagMapper(t){this.parseStream.addTagMapper(t)}},Object.defineProperty(t,"__esModule",{value:!0})})); | ||
/*! @name m3u8-parser @version 7.0.0 @license Apache-2.0 */ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).m3u8Parser={})}(this,(function(t){"use strict";var e=function(){function t(){this.listeners={}}var e=t.prototype;return e.on=function(t,e){this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(e)},e.off=function(t,e){if(!this.listeners[t])return!1;var i=this.listeners[t].indexOf(e);return this.listeners[t]=this.listeners[t].slice(0),this.listeners[t].splice(i,1),i>-1},e.trigger=function(t){var e=this.listeners[t];if(e)if(2===arguments.length)for(var i=e.length,a=0;a<i;++a)e[a].call(this,arguments[1]);else for(var s=Array.prototype.slice.call(arguments,1),r=e.length,n=0;n<r;++n)e[n].apply(this,s)},e.dispose=function(){this.listeners={}},e.pipe=function(t){this.on("data",(function(e){t.push(e)}))},t}();class i extends e{constructor(){super(),this.buffer=""}push(t){let e;for(this.buffer+=t,e=this.buffer.indexOf("\n");e>-1;e=this.buffer.indexOf("\n"))this.trigger("data",this.buffer.substring(0,e)),this.buffer=this.buffer.substring(e+1)}}function a(){return s=a=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var a in i)Object.prototype.hasOwnProperty.call(i,a)&&(t[a]=i[a])}return t},a.apply(this,arguments)}var s=a,r=s;const n=String.fromCharCode(9),o=function(t){const e=/([0-9.]*)?@?([0-9.]*)?/.exec(t||""),i={};return e[1]&&(i.length=parseInt(e[1],10)),e[2]&&(i.offset=parseInt(e[2],10)),i},u=function(t){const e={};if(!t)return e;const i=t.split(new RegExp('(?:^|,)((?:[^=]*)=(?:"[^"]*"|[^,]*))'));let a,s=i.length;for(;s--;)""!==i[s]&&(a=/([^=]*)=(.*)/.exec(i[s]).slice(1),a[0]=a[0].replace(/^\s+|\s+$/g,""),a[1]=a[1].replace(/^\s+|\s+$/g,""),a[1]=a[1].replace(/^['"](.*)['"]$/g,"$1"),e[a[0]]=a[1]);return e};class g extends e{constructor(){super(),this.customParsers=[],this.tagMappers=[]}push(t){let e,i;if(0===(t=t.trim()).length)return;if("#"!==t[0])return void this.trigger("data",{type:"uri",uri:t});this.tagMappers.reduce(((e,i)=>{const a=i(t);return a===t?e:e.concat([a])}),[t]).forEach((t=>{for(let e=0;e<this.customParsers.length;e++)if(this.customParsers[e].call(this,t))return;if(0===t.indexOf("#EXT"))if(t=t.replace("\r",""),e=/^#EXTM3U/.exec(t),e)this.trigger("data",{type:"tag",tagType:"m3u"});else{if(e=/^#EXTINF:([0-9\.]*)?,?(.*)?$/.exec(t),e)return i={type:"tag",tagType:"inf"},e[1]&&(i.duration=parseFloat(e[1])),e[2]&&(i.title=e[2]),void this.trigger("data",i);if(e=/^#EXT-X-TARGETDURATION:([0-9.]*)?/.exec(t),e)return i={type:"tag",tagType:"targetduration"},e[1]&&(i.duration=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-VERSION:([0-9.]*)?/.exec(t),e)return i={type:"tag",tagType:"version"},e[1]&&(i.version=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-MEDIA-SEQUENCE:(\-?[0-9.]*)?/.exec(t),e)return i={type:"tag",tagType:"media-sequence"},e[1]&&(i.number=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-DISCONTINUITY-SEQUENCE:(\-?[0-9.]*)?/.exec(t),e)return i={type:"tag",tagType:"discontinuity-sequence"},e[1]&&(i.number=parseInt(e[1],10)),void this.trigger("data",i);if(e=/^#EXT-X-PLAYLIST-TYPE:(.*)?$/.exec(t),e)return i={type:"tag",tagType:"playlist-type"},e[1]&&(i.playlistType=e[1]),void this.trigger("data",i);if(e=/^#EXT-X-BYTERANGE:(.*)?$/.exec(t),e)return i=r(o(e[1]),{type:"tag",tagType:"byterange"}),void this.trigger("data",i);if(e=/^#EXT-X-ALLOW-CACHE:(YES|NO)?/.exec(t),e)return i={type:"tag",tagType:"allow-cache"},e[1]&&(i.allowed=!/NO/.test(e[1])),void this.trigger("data",i);if(e=/^#EXT-X-MAP:(.*)$/.exec(t),e){if(i={type:"tag",tagType:"map"},e[1]){const t=u(e[1]);t.URI&&(i.uri=t.URI),t.BYTERANGE&&(i.byterange=o(t.BYTERANGE))}this.trigger("data",i)}else if(e=/^#EXT-X-STREAM-INF:(.*)$/.exec(t),e){if(i={type:"tag",tagType:"stream-inf"},e[1]){if(i.attributes=u(e[1]),i.attributes.RESOLUTION){const t=i.attributes.RESOLUTION.split("x"),e={};t[0]&&(e.width=parseInt(t[0],10)),t[1]&&(e.height=parseInt(t[1],10)),i.attributes.RESOLUTION=e}i.attributes.BANDWIDTH&&(i.attributes.BANDWIDTH=parseInt(i.attributes.BANDWIDTH,10)),i.attributes["FRAME-RATE"]&&(i.attributes["FRAME-RATE"]=parseFloat(i.attributes["FRAME-RATE"])),i.attributes["PROGRAM-ID"]&&(i.attributes["PROGRAM-ID"]=parseInt(i.attributes["PROGRAM-ID"],10))}this.trigger("data",i)}else{if(e=/^#EXT-X-MEDIA:(.*)$/.exec(t),e)return i={type:"tag",tagType:"media"},e[1]&&(i.attributes=u(e[1])),void this.trigger("data",i);if(e=/^#EXT-X-ENDLIST/.exec(t),e)this.trigger("data",{type:"tag",tagType:"endlist"});else if(e=/^#EXT-X-DISCONTINUITY/.exec(t),e)this.trigger("data",{type:"tag",tagType:"discontinuity"});else{if(e=/^#EXT-X-PROGRAM-DATE-TIME:(.*)$/.exec(t),e)return i={type:"tag",tagType:"program-date-time"},e[1]&&(i.dateTimeString=e[1]),void this.trigger("data",i);if(e=/^#EXT-X-KEY:(.*)$/.exec(t),e)return i={type:"tag",tagType:"key"},e[1]&&(i.attributes=u(e[1]),i.attributes.IV&&("0x"===i.attributes.IV.substring(0,2).toLowerCase()&&(i.attributes.IV=i.attributes.IV.substring(2)),i.attributes.IV=i.attributes.IV.match(/.{8}/g),i.attributes.IV[0]=parseInt(i.attributes.IV[0],16),i.attributes.IV[1]=parseInt(i.attributes.IV[1],16),i.attributes.IV[2]=parseInt(i.attributes.IV[2],16),i.attributes.IV[3]=parseInt(i.attributes.IV[3],16),i.attributes.IV=new Uint32Array(i.attributes.IV))),void this.trigger("data",i);if(e=/^#EXT-X-START:(.*)$/.exec(t),e)return i={type:"tag",tagType:"start"},e[1]&&(i.attributes=u(e[1]),i.attributes["TIME-OFFSET"]=parseFloat(i.attributes["TIME-OFFSET"]),i.attributes.PRECISE=/YES/.test(i.attributes.PRECISE)),void this.trigger("data",i);if(e=/^#EXT-X-CUE-OUT-CONT:(.*)?$/.exec(t),e)return i={type:"tag",tagType:"cue-out-cont"},e[1]?i.data=e[1]:i.data="",void this.trigger("data",i);if(e=/^#EXT-X-CUE-OUT:(.*)?$/.exec(t),e)return i={type:"tag",tagType:"cue-out"},e[1]?i.data=e[1]:i.data="",void this.trigger("data",i);if(e=/^#EXT-X-CUE-IN:(.*)?$/.exec(t),e)return i={type:"tag",tagType:"cue-in"},e[1]?i.data=e[1]:i.data="",void this.trigger("data",i);if(e=/^#EXT-X-SKIP:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"skip"},i.attributes=u(e[1]),i.attributes.hasOwnProperty("SKIPPED-SEGMENTS")&&(i.attributes["SKIPPED-SEGMENTS"]=parseInt(i.attributes["SKIPPED-SEGMENTS"],10)),i.attributes.hasOwnProperty("RECENTLY-REMOVED-DATERANGES")&&(i.attributes["RECENTLY-REMOVED-DATERANGES"]=i.attributes["RECENTLY-REMOVED-DATERANGES"].split(n)),void this.trigger("data",i);if(e=/^#EXT-X-PART:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"part"},i.attributes=u(e[1]),["DURATION"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=parseFloat(i.attributes[t]))})),["INDEPENDENT","GAP"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=/YES/.test(i.attributes[t]))})),i.attributes.hasOwnProperty("BYTERANGE")&&(i.attributes.byterange=o(i.attributes.BYTERANGE)),void this.trigger("data",i);if(e=/^#EXT-X-SERVER-CONTROL:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"server-control"},i.attributes=u(e[1]),["CAN-SKIP-UNTIL","PART-HOLD-BACK","HOLD-BACK"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=parseFloat(i.attributes[t]))})),["CAN-SKIP-DATERANGES","CAN-BLOCK-RELOAD"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=/YES/.test(i.attributes[t]))})),void this.trigger("data",i);if(e=/^#EXT-X-PART-INF:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"part-inf"},i.attributes=u(e[1]),["PART-TARGET"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=parseFloat(i.attributes[t]))})),void this.trigger("data",i);if(e=/^#EXT-X-PRELOAD-HINT:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"preload-hint"},i.attributes=u(e[1]),["BYTERANGE-START","BYTERANGE-LENGTH"].forEach((function(t){if(i.attributes.hasOwnProperty(t)){i.attributes[t]=parseInt(i.attributes[t],10);const e="BYTERANGE-LENGTH"===t?"length":"offset";i.attributes.byterange=i.attributes.byterange||{},i.attributes.byterange[e]=i.attributes[t],delete i.attributes[t]}})),void this.trigger("data",i);if(e=/^#EXT-X-RENDITION-REPORT:(.*)$/.exec(t),e&&e[1])return i={type:"tag",tagType:"rendition-report"},i.attributes=u(e[1]),["LAST-MSN","LAST-PART"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=parseInt(i.attributes[t],10))})),void this.trigger("data",i);if(e=/^#EXT-X-DATERANGE:(.*)$/.exec(t),e&&e[1]){i={type:"tag",tagType:"daterange"},i.attributes=u(e[1]),["ID","CLASS"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=String(i.attributes[t]))})),["START-DATE","END-DATE"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=new Date(i.attributes[t]))})),["DURATION","PLANNED-DURATION"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=parseFloat(i.attributes[t]))})),["END-ON-NEXT"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=/YES/i.test(i.attributes[t]))})),["SCTE35-CMD"," SCTE35-OUT","SCTE35-IN"].forEach((function(t){i.attributes.hasOwnProperty(t)&&(i.attributes[t]=i.attributes[t].toString(16))}));const t=/^X-([A-Z]+-)+[A-Z]+$/;for(const e in i.attributes){if(!t.test(e))continue;const a=/[0-9A-Fa-f]{6}/g.test(i.attributes[e]),s=/^\d+(\.\d+)?$/.test(i.attributes[e]);i.attributes[e]=a?i.attributes[e].toString(16):s?parseFloat(i.attributes[e]):String(i.attributes[e])}this.trigger("data",i)}else e=/^#EXT-X-INDEPENDENT-SEGMENTS/.exec(t),e?this.trigger("data",{type:"tag",tagType:"independent-segments"}):this.trigger("data",{type:"tag",data:t.slice(4)})}}}else this.trigger("data",{type:"comment",text:t.slice(1)})}))}addParser({expression:t,customType:e,dataParser:i,segment:a}){"function"!=typeof i&&(i=t=>t),this.customParsers.push((s=>{if(t.exec(s))return this.trigger("data",{type:"custom",data:i(s),customType:e,segment:a}),!0}))}addTagMapper({expression:t,map:e}){this.tagMappers.push((i=>t.test(i)?e(i):i))}}function h(t){for(var e,i=(e=t,window.atob?window.atob(e):Buffer.from(e,"base64").toString("binary")),a=new Uint8Array(i.length),s=0;s<i.length;s++)a[s]=i.charCodeAt(s);return a}const p=function(t){const e={};return Object.keys(t).forEach((function(i){var a;e[(a=i,a.toLowerCase().replace(/-(\w)/g,(t=>t[1].toUpperCase())))]=t[i]})),e},d=function(t){const{serverControl:e,targetDuration:i,partTargetDuration:a}=t;if(!e)return;const s="#EXT-X-SERVER-CONTROL",r="holdBack",n="partHoldBack",o=i&&3*i,u=a&&2*a;i&&!e.hasOwnProperty(r)&&(e[r]=o,this.trigger("info",{message:`${s} defaulting HOLD-BACK to targetDuration * 3 (${o}).`})),o&&e[r]<o&&(this.trigger("warn",{message:`${s} clamping HOLD-BACK (${e[r]}) to targetDuration * 3 (${o})`}),e[r]=o),a&&!e.hasOwnProperty(n)&&(e[n]=3*a,this.trigger("info",{message:`${s} defaulting PART-HOLD-BACK to partTargetDuration * 3 (${e[n]}).`})),a&&e[n]<u&&(this.trigger("warn",{message:`${s} clamping PART-HOLD-BACK (${e[n]}) to partTargetDuration * 2 (${u}).`}),e[n]=u)};t.LineStream=i,t.ParseStream=g,t.Parser=class extends e{constructor(){super(),this.lineStream=new i,this.parseStream=new g,this.lineStream.pipe(this.parseStream),this.lastProgramDateTime=null;const t=this,e=[];let a,s,n={},o=!1;const u=function(){},E={AUDIO:{},VIDEO:{},"CLOSED-CAPTIONS":{},SUBTITLES:{}};let f=0;this.manifest={allowCache:!0,discontinuityStarts:[],dateRanges:[],segments:[]};let c=0,T=0;const l={};this.on("end",(()=>{n.uri||!n.parts&&!n.preloadHints||(!n.map&&a&&(n.map=a),!n.key&&s&&(n.key=s),n.timeline||"number"!=typeof f||(n.timeline=f),this.manifest.preloadSegment=n)})),this.parseStream.on("data",(function(i){let g,m;({tag(){({version(){i.version&&(this.manifest.version=i.version)},"allow-cache"(){this.manifest.allowCache=i.allowed,"allowed"in i||(this.trigger("info",{message:"defaulting allowCache to YES"}),this.manifest.allowCache=!0)},byterange(){const t={};"length"in i&&(n.byterange=t,t.length=i.length,"offset"in i||(i.offset=c)),"offset"in i&&(n.byterange=t,t.offset=i.offset),c=t.offset+t.length},endlist(){this.manifest.endList=!0},inf(){"mediaSequence"in this.manifest||(this.manifest.mediaSequence=0,this.trigger("info",{message:"defaulting media sequence to zero"})),"discontinuitySequence"in this.manifest||(this.manifest.discontinuitySequence=0,this.trigger("info",{message:"defaulting discontinuity sequence to zero"})),i.title&&(n.title=i.title),i.duration>0&&(n.duration=i.duration),0===i.duration&&(n.duration=.01,this.trigger("info",{message:"updating zero segment duration to a small value"})),this.manifest.segments=e},key(){if(i.attributes)if("NONE"!==i.attributes.METHOD)if(i.attributes.URI){if("com.apple.streamingkeydelivery"===i.attributes.KEYFORMAT)return this.manifest.contentProtection=this.manifest.contentProtection||{},void(this.manifest.contentProtection["com.apple.fps.1_0"]={attributes:i.attributes});if("com.microsoft.playready"===i.attributes.KEYFORMAT)return this.manifest.contentProtection=this.manifest.contentProtection||{},void(this.manifest.contentProtection["com.microsoft.playready"]={uri:i.attributes.URI});if("urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"===i.attributes.KEYFORMAT){return-1===["SAMPLE-AES","SAMPLE-AES-CTR","SAMPLE-AES-CENC"].indexOf(i.attributes.METHOD)?void this.trigger("warn",{message:"invalid key method provided for Widevine"}):("SAMPLE-AES-CENC"===i.attributes.METHOD&&this.trigger("warn",{message:"SAMPLE-AES-CENC is deprecated, please use SAMPLE-AES-CTR instead"}),"data:text/plain;base64,"!==i.attributes.URI.substring(0,23)?void this.trigger("warn",{message:"invalid key URI provided for Widevine"}):i.attributes.KEYID&&"0x"===i.attributes.KEYID.substring(0,2)?(this.manifest.contentProtection=this.manifest.contentProtection||{},void(this.manifest.contentProtection["com.widevine.alpha"]={attributes:{schemeIdUri:i.attributes.KEYFORMAT,keyId:i.attributes.KEYID.substring(2)},pssh:h(i.attributes.URI.split(",")[1])})):void this.trigger("warn",{message:"invalid key ID provided for Widevine"}))}i.attributes.METHOD||this.trigger("warn",{message:"defaulting key method to AES-128"}),s={method:i.attributes.METHOD||"AES-128",uri:i.attributes.URI},void 0!==i.attributes.IV&&(s.iv=i.attributes.IV)}else this.trigger("warn",{message:"ignoring key declaration without URI"});else s=null;else this.trigger("warn",{message:"ignoring key declaration without attribute list"})},"media-sequence"(){isFinite(i.number)?this.manifest.mediaSequence=i.number:this.trigger("warn",{message:"ignoring invalid media sequence: "+i.number})},"discontinuity-sequence"(){isFinite(i.number)?(this.manifest.discontinuitySequence=i.number,f=i.number):this.trigger("warn",{message:"ignoring invalid discontinuity sequence: "+i.number})},"playlist-type"(){/VOD|EVENT/.test(i.playlistType)?this.manifest.playlistType=i.playlistType:this.trigger("warn",{message:"ignoring unknown playlist type: "+i.playlist})},map(){a={},i.uri&&(a.uri=i.uri),i.byterange&&(a.byterange=i.byterange),s&&(a.key=s)},"stream-inf"(){this.manifest.playlists=e,this.manifest.mediaGroups=this.manifest.mediaGroups||E,i.attributes?(n.attributes||(n.attributes={}),r(n.attributes,i.attributes)):this.trigger("warn",{message:"ignoring empty stream-inf attributes"})},media(){if(this.manifest.mediaGroups=this.manifest.mediaGroups||E,!(i.attributes&&i.attributes.TYPE&&i.attributes["GROUP-ID"]&&i.attributes.NAME))return void this.trigger("warn",{message:"ignoring incomplete or missing media group"});const t=this.manifest.mediaGroups[i.attributes.TYPE];t[i.attributes["GROUP-ID"]]=t[i.attributes["GROUP-ID"]]||{},g=t[i.attributes["GROUP-ID"]],m={default:/yes/i.test(i.attributes.DEFAULT)},m.default?m.autoselect=!0:m.autoselect=/yes/i.test(i.attributes.AUTOSELECT),i.attributes.LANGUAGE&&(m.language=i.attributes.LANGUAGE),i.attributes.URI&&(m.uri=i.attributes.URI),i.attributes["INSTREAM-ID"]&&(m.instreamId=i.attributes["INSTREAM-ID"]),i.attributes.CHARACTERISTICS&&(m.characteristics=i.attributes.CHARACTERISTICS),i.attributes.FORCED&&(m.forced=/yes/i.test(i.attributes.FORCED)),g[i.attributes.NAME]=m},discontinuity(){f+=1,n.discontinuity=!0,this.manifest.discontinuityStarts.push(e.length)},"program-date-time"(){const{lastProgramDateTime:t}=this;this.lastProgramDateTime=new Date(i.dateTimeString).getTime(),null===t&&this.manifest.segments.reduceRight(((t,e)=>(e.programDateTime=t-1e3*e.duration,e.programDateTime)),this.lastProgramDateTime)},targetduration(){!isFinite(i.duration)||i.duration<0?this.trigger("warn",{message:"ignoring invalid target duration: "+i.duration}):(this.manifest.targetDuration=i.duration,d.call(this,this.manifest))},start(){i.attributes&&!isNaN(i.attributes["TIME-OFFSET"])?this.manifest.start={timeOffset:i.attributes["TIME-OFFSET"],precise:i.attributes.PRECISE}:this.trigger("warn",{message:"ignoring start declaration without appropriate attribute list"})},"cue-out"(){n.cueOut=i.data},"cue-out-cont"(){n.cueOutCont=i.data},"cue-in"(){n.cueIn=i.data},skip(){this.manifest.skip=p(i.attributes),this.warnOnMissingAttributes_("#EXT-X-SKIP",i.attributes,["SKIPPED-SEGMENTS"])},part(){o=!0;const t=this.manifest.segments.length,e=p(i.attributes);n.parts=n.parts||[],n.parts.push(e),e.byterange&&(e.byterange.hasOwnProperty("offset")||(e.byterange.offset=T),T=e.byterange.offset+e.byterange.length);const a=n.parts.length-1;this.warnOnMissingAttributes_(`#EXT-X-PART #${a} for segment #${t}`,i.attributes,["URI","DURATION"]),this.manifest.renditionReports&&this.manifest.renditionReports.forEach(((t,e)=>{t.hasOwnProperty("lastPart")||this.trigger("warn",{message:`#EXT-X-RENDITION-REPORT #${e} lacks required attribute(s): LAST-PART`})}))},"server-control"(){const t=this.manifest.serverControl=p(i.attributes);t.hasOwnProperty("canBlockReload")||(t.canBlockReload=!1,this.trigger("info",{message:"#EXT-X-SERVER-CONTROL defaulting CAN-BLOCK-RELOAD to false"})),d.call(this,this.manifest),t.canSkipDateranges&&!t.hasOwnProperty("canSkipUntil")&&this.trigger("warn",{message:"#EXT-X-SERVER-CONTROL lacks required attribute CAN-SKIP-UNTIL which is required when CAN-SKIP-DATERANGES is set"})},"preload-hint"(){const t=this.manifest.segments.length,e=p(i.attributes),a=e.type&&"PART"===e.type;n.preloadHints=n.preloadHints||[],n.preloadHints.push(e),e.byterange&&(e.byterange.hasOwnProperty("offset")||(e.byterange.offset=a?T:0,a&&(T=e.byterange.offset+e.byterange.length)));const s=n.preloadHints.length-1;if(this.warnOnMissingAttributes_(`#EXT-X-PRELOAD-HINT #${s} for segment #${t}`,i.attributes,["TYPE","URI"]),e.type)for(let i=0;i<n.preloadHints.length-1;i++){const a=n.preloadHints[i];a.type&&(a.type===e.type&&this.trigger("warn",{message:`#EXT-X-PRELOAD-HINT #${s} for segment #${t} has the same TYPE ${e.type} as preload hint #${i}`}))}},"rendition-report"(){const t=p(i.attributes);this.manifest.renditionReports=this.manifest.renditionReports||[],this.manifest.renditionReports.push(t);const e=this.manifest.renditionReports.length-1,a=["LAST-MSN","URI"];o&&a.push("LAST-PART"),this.warnOnMissingAttributes_(`#EXT-X-RENDITION-REPORT #${e}`,i.attributes,a)},"part-inf"(){this.manifest.partInf=p(i.attributes),this.warnOnMissingAttributes_("#EXT-X-PART-INF",i.attributes,["PART-TARGET"]),this.manifest.partInf.partTarget&&(this.manifest.partTargetDuration=this.manifest.partInf.partTarget),d.call(this,this.manifest)},daterange(){this.manifest.dateRanges.push(p(i.attributes));const t=this.manifest.dateRanges.length-1;this.warnOnMissingAttributes_(`#EXT-X-DATERANGE #${t}`,i.attributes,["ID","START-DATE"]);const e=this.manifest.dateRanges[t];e.endDate&&e.startDate&&new Date(e.endDate)<new Date(e.startDate)&&this.trigger("warn",{message:"EXT-X-DATERANGE END-DATE must be equal to or later than the value of the START-DATE"}),e.duration&&e.duration<0&&this.trigger("warn",{message:"EXT-X-DATERANGE DURATION must not be negative"}),e.plannedDuration&&e.plannedDuration<0&&this.trigger("warn",{message:"EXT-X-DATERANGE PLANNED-DURATION must not be negative"});const a=!!e.endOnNext;if(a&&!e.class&&this.trigger("warn",{message:"EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must have a CLASS attribute"}),a&&(e.duration||e.endDate)&&this.trigger("warn",{message:"EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must not contain DURATION or END-DATE attributes"}),e.duration&&e.endDate){const i=e.startDate,a=i.setSeconds(i.getSeconds()+e.duration);this.manifest.dateRanges[t].endDate=new Date(a)}if(l[e.id]){for(const t in l[e.id])if(l[e.id][t]!==e[t]){this.trigger("warn",{message:"EXT-X-DATERANGE tags with the same ID in a playlist must have the same attributes and same attribute values"});break}}else l[e.id]=e},"independent-segments"(){this.manifest.independentSegments=!0}}[i.tagType]||u).call(t)},uri(){n.uri=i.uri,e.push(n),this.manifest.targetDuration&&!("duration"in n)&&(this.trigger("warn",{message:"defaulting segment duration to the target duration"}),n.duration=this.manifest.targetDuration),s&&(n.key=s),n.timeline=f,a&&(n.map=a),T=0,null!==this.lastProgramDateTime&&(n.programDateTime=this.lastProgramDateTime,this.lastProgramDateTime+=1e3*n.duration),n={}},comment(){},custom(){i.segment?(n.custom=n.custom||{},n.custom[i.customType]=i.data):(this.manifest.custom=this.manifest.custom||{},this.manifest.custom[i.customType]=i.data)}})[i.type].call(t)}))}warnOnMissingAttributes_(t,e,i){const a=[];i.forEach((function(t){e.hasOwnProperty(t)||a.push(t)})),a.length&&this.trigger("warn",{message:`${t} lacks required attribute(s): ${a.join(", ")}`})}push(t){this.lineStream.push(t)}end(){this.lineStream.push("\n"),this.manifest.dateRanges.length&&null===this.lastProgramDateTime&&this.trigger("warn",{message:"A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag"}),this.lastProgramDateTime=null,this.trigger("end")}addParser(t){this.parseStream.addParser(t)}addTagMapper(t){this.parseStream.addTagMapper(t)}},Object.defineProperty(t,"__esModule",{value:!0})})); |
{ | ||
"name": "m3u8-parser", | ||
"version": "6.2.0", | ||
"version": "7.0.0", | ||
"description": "m3u8 parser", | ||
@@ -5,0 +5,0 @@ "main": "dist/m3u8-parser.cjs.js", |
@@ -60,2 +60,3 @@ # m3u8-parser | ||
'1.ts', | ||
'#EXT-X-PROGRAM-DATE-TIME:2019-02-14T02:14:00.106Z' | ||
'#EXTINF:6,', | ||
@@ -83,2 +84,3 @@ '2.ts', | ||
mediaSequence: number, | ||
dateRanges: [], | ||
discontinuitySequence: number, | ||
@@ -111,4 +113,2 @@ playlistType: string, | ||
}, | ||
dateTimeString: string, | ||
dateTimeObject: Date, | ||
targetDuration: number, | ||
@@ -119,2 +119,3 @@ totalDuration: number, | ||
{ | ||
title: string, | ||
byterange: { | ||
@@ -125,2 +126,3 @@ length: number, | ||
duration: number, | ||
programDateTime: number, | ||
attributes: {}, | ||
@@ -127,0 +129,0 @@ discontinuity: number, |
@@ -359,3 +359,2 @@ /** | ||
event.dateTimeString = match[1]; | ||
event.dateTimeObject = new Date(match[1]); | ||
} | ||
@@ -362,0 +361,0 @@ this.trigger('data', event); |
@@ -100,2 +100,4 @@ /** | ||
this.lastProgramDateTime = null; | ||
/* eslint-disable consistent-this */ | ||
@@ -128,2 +130,3 @@ const self = this; | ||
discontinuityStarts: [], | ||
dateRanges: [], | ||
segments: [] | ||
@@ -137,3 +140,3 @@ }; | ||
let lastPartByterangeEnd = 0; | ||
const daterangeTags = {}; | ||
const dateRangeTags = {}; | ||
@@ -227,2 +230,7 @@ this.on('end', () => { | ||
} | ||
if (entry.title) { | ||
currentUri.title = entry.title; | ||
} | ||
if (entry.duration > 0) { | ||
@@ -458,13 +466,17 @@ currentUri.duration = entry.duration; | ||
'program-date-time'() { | ||
if (typeof this.manifest.dateTimeString === 'undefined') { | ||
// PROGRAM-DATE-TIME is a media-segment tag, but for backwards | ||
// compatibility, we add the first occurence of the PROGRAM-DATE-TIME tag | ||
// to the manifest object | ||
// TODO: Consider removing this in future major version | ||
this.manifest.dateTimeString = entry.dateTimeString; | ||
this.manifest.dateTimeObject = entry.dateTimeObject; | ||
const { lastProgramDateTime } = this; | ||
this.lastProgramDateTime = new Date(entry.dateTimeString).getTime(); | ||
// We should extrapolate Program Date Time backward only during first program date time occurrence. | ||
// Once we have at least one program date time point, we can always extrapolate it forward using lastProgramDateTime reference. | ||
if (lastProgramDateTime === null) { | ||
// Extrapolate Program Date Time backward | ||
// Since it is first program date time occurrence we're assuming that | ||
// all this.manifest.segments have no program date time info | ||
this.manifest.segments.reduceRight((programDateTime, segment) => { | ||
segment.programDateTime = programDateTime - (segment.duration * 1000); | ||
return segment.programDateTime; | ||
}, this.lastProgramDateTime); | ||
} | ||
currentUri.dateTimeString = entry.dateTimeString; | ||
currentUri.dateTimeObject = entry.dateTimeObject; | ||
}, | ||
@@ -642,5 +654,4 @@ targetduration() { | ||
'daterange'() { | ||
this.manifest.daterange = this.manifest.daterange || []; | ||
this.manifest.daterange.push(camelCaseKeys(entry.attributes)); | ||
const index = this.manifest.daterange.length - 1; | ||
this.manifest.dateRanges.push(camelCaseKeys(entry.attributes)); | ||
const index = this.manifest.dateRanges.length - 1; | ||
@@ -652,5 +663,5 @@ this.warnOnMissingAttributes_( | ||
); | ||
const daterange = this.manifest.daterange[index]; | ||
const dateRange = this.manifest.dateRanges[index]; | ||
if (daterange.endDate && daterange.startDate && new Date(daterange.endDate) < new Date(daterange.startDate)) { | ||
if (dateRange.endDate && dateRange.startDate && new Date(dateRange.endDate) < new Date(dateRange.startDate)) { | ||
this.trigger('warn', { | ||
@@ -660,3 +671,3 @@ message: 'EXT-X-DATERANGE END-DATE must be equal to or later than the value of the START-DATE' | ||
} | ||
if (daterange.duration && daterange.duration < 0) { | ||
if (dateRange.duration && dateRange.duration < 0) { | ||
this.trigger('warn', { | ||
@@ -666,3 +677,3 @@ message: 'EXT-X-DATERANGE DURATION must not be negative' | ||
} | ||
if (daterange.plannedDuration && daterange.plannedDuration < 0) { | ||
if (dateRange.plannedDuration && dateRange.plannedDuration < 0) { | ||
this.trigger('warn', { | ||
@@ -672,5 +683,5 @@ message: 'EXT-X-DATERANGE PLANNED-DURATION must not be negative' | ||
} | ||
const endOnNextYes = !!daterange.endOnNext; | ||
const endOnNextYes = !!dateRange.endOnNext; | ||
if (endOnNextYes && !daterange.class) { | ||
if (endOnNextYes && !dateRange.class) { | ||
this.trigger('warn', { | ||
@@ -680,3 +691,3 @@ message: 'EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must have a CLASS attribute' | ||
} | ||
if (endOnNextYes && (daterange.duration || daterange.endDate)) { | ||
if (endOnNextYes && (dateRange.duration || dateRange.endDate)) { | ||
this.trigger('warn', { | ||
@@ -686,18 +697,13 @@ message: 'EXT-X-DATERANGE with an END-ON-NEXT=YES attribute must not contain DURATION or END-DATE attributes' | ||
} | ||
if (daterange.duration && daterange.endDate) { | ||
const startDate = daterange.startDate; | ||
const newDateInSeconds = startDate.setSeconds(startDate.getSeconds() + daterange.duration); | ||
if (dateRange.duration && dateRange.endDate) { | ||
const startDate = dateRange.startDate; | ||
const newDateInSeconds = startDate.setSeconds(startDate.getSeconds() + dateRange.duration); | ||
this.manifest.daterange[index].endDate = new Date(newDateInSeconds); | ||
this.manifest.dateRanges[index].endDate = new Date(newDateInSeconds); | ||
} | ||
if (daterange && !this.manifest.dateTimeString) { | ||
this.trigger('warn', { | ||
message: 'A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag' | ||
}); | ||
} | ||
if (!daterangeTags[daterange.id]) { | ||
daterangeTags[daterange.id] = daterange; | ||
if (!dateRangeTags[dateRange.id]) { | ||
dateRangeTags[dateRange.id] = dateRange; | ||
} else { | ||
for (const attribute in daterangeTags[daterange.id]) { | ||
if (daterangeTags[daterange.id][attribute] !== daterange[attribute]) { | ||
for (const attribute in dateRangeTags[dateRange.id]) { | ||
if (dateRangeTags[dateRange.id][attribute] !== dateRange[attribute]) { | ||
this.trigger('warn', { | ||
@@ -740,2 +746,8 @@ message: 'EXT-X-DATERANGE tags with the same ID in a playlist must have the same attributes and same attribute values' | ||
// Once we have at least one program date time we can always extrapolate it forward | ||
if (this.lastProgramDateTime !== null) { | ||
currentUri.programDateTime = this.lastProgramDateTime; | ||
this.lastProgramDateTime += currentUri.duration * 1000; | ||
} | ||
// prepare for the next URI | ||
@@ -793,3 +805,9 @@ currentUri = {}; | ||
this.lineStream.push('\n'); | ||
if (this.manifest.dateRanges.length && this.lastProgramDateTime === null) { | ||
this.trigger('warn', { | ||
message: 'A playlist with EXT-X-DATERANGE tag must contain atleast one EXT-X-PROGRAM-DATE-TIME tag' | ||
}); | ||
} | ||
this.lastProgramDateTime = null; | ||
this.trigger('end'); | ||
@@ -802,3 +820,3 @@ } | ||
* @param {RegExp} options.expression a regular expression to match the custom header | ||
* @param {string} options.type the type to register to the output | ||
* @param {string} options.customType the custom type to register to the output | ||
* @param {Function} [options.dataParser] function to parse the line into an object | ||
@@ -805,0 +823,0 @@ * @param {boolean} [options.segment] should tag data be attached to the segment object |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
mediaSequence: 0, | ||
dateRanges: [], | ||
playlistType: 'VOD', | ||
@@ -5,0 +6,0 @@ segments: [ |
module.exports = { | ||
allowCache: true, | ||
mediaSequence: 0, | ||
dateRanges: [], | ||
playlistType: 'VOD', | ||
@@ -5,0 +6,0 @@ segments: [ |
module.exports = { | ||
allowCache: true, | ||
discontinuityStarts: [], | ||
dateRanges: [], | ||
mediaGroups: { | ||
@@ -5,0 +6,0 @@ // TYPE |
module.exports = { | ||
allowCache: true, | ||
discontinuityStarts: [], | ||
dateRanges: [], | ||
mediaGroups: { | ||
@@ -5,0 +6,0 @@ 'AUDIO': { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
playlists: [ | ||
@@ -4,0 +5,0 @@ { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: false, | ||
mediaSequence: 0, | ||
dateRanges: [], | ||
playlistType: 'VOD', | ||
segments: [ | ||
{ | ||
dateTimeString: '2016-06-22T09:20:16.166-04:00', | ||
dateTimeObject: new Date('2016-06-22T09:20:16.166-04:00'), | ||
programDateTime: 1466601616166, | ||
duration: 10, | ||
@@ -14,4 +14,3 @@ timeline: 0, | ||
{ | ||
dateTimeString: '2016-06-22T09:20:26.166-04:00', | ||
dateTimeObject: new Date('2016-06-22T09:20:26.166-04:00'), | ||
programDateTime: 1466601626166, | ||
duration: 10, | ||
@@ -24,6 +23,4 @@ timeline: 0, | ||
endList: true, | ||
dateTimeString: '2016-06-22T09:20:16.166-04:00', | ||
dateTimeObject: new Date('2016-06-22T09:20:16.166-04:00'), | ||
discontinuitySequence: 0, | ||
discontinuityStarts: [] | ||
}; |
@@ -5,2 +5,3 @@ module.exports = { | ||
discontinuityStarts: [], | ||
dateRanges: [], | ||
mediaSequence: 7794, | ||
@@ -7,0 +8,0 @@ segments: [ |
module.exports = { | ||
allowCache: false, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -9,3 +10,4 @@ discontinuitySequence: 3, | ||
timeline: 3, | ||
uri: '001.ts' | ||
uri: '001.ts', | ||
title: '0' | ||
}, | ||
@@ -15,3 +17,4 @@ { | ||
timeline: 3, | ||
uri: '002.ts' | ||
uri: '002.ts', | ||
title: '0' | ||
}, | ||
@@ -22,3 +25,4 @@ { | ||
timeline: 4, | ||
uri: '003.ts' | ||
uri: '003.ts', | ||
title: '0' | ||
}, | ||
@@ -28,3 +32,4 @@ { | ||
timeline: 4, | ||
uri: '004.ts' | ||
uri: '004.ts', | ||
title: '0' | ||
} | ||
@@ -31,0 +36,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -9,3 +10,4 @@ discontinuitySequence: 0, | ||
timeline: 0, | ||
uri: '001.ts' | ||
uri: '001.ts', | ||
title: '0' | ||
}, | ||
@@ -15,3 +17,4 @@ { | ||
timeline: 0, | ||
uri: '002.ts' | ||
uri: '002.ts', | ||
title: '0' | ||
}, | ||
@@ -22,3 +25,4 @@ { | ||
timeline: 1, | ||
uri: '003.ts' | ||
uri: '003.ts', | ||
title: '0' | ||
}, | ||
@@ -28,3 +32,4 @@ { | ||
timeline: 1, | ||
uri: '004.ts' | ||
uri: '004.ts', | ||
title: '0' | ||
}, | ||
@@ -35,3 +40,4 @@ { | ||
timeline: 2, | ||
uri: '005.ts' | ||
uri: '005.ts', | ||
title: '0' | ||
}, | ||
@@ -41,3 +47,4 @@ { | ||
timeline: 2, | ||
uri: '006.ts' | ||
uri: '006.ts', | ||
title: '0' | ||
}, | ||
@@ -47,3 +54,4 @@ { | ||
timeline: 2, | ||
uri: '007.ts' | ||
uri: '007.ts', | ||
title: '0' | ||
}, | ||
@@ -54,3 +62,4 @@ { | ||
timeline: 3, | ||
uri: '008.ts' | ||
uri: '008.ts', | ||
title: '0' | ||
}, | ||
@@ -60,3 +69,4 @@ { | ||
timeline: 3, | ||
uri: '009.ts' | ||
uri: '009.ts', | ||
title: '0' | ||
} | ||
@@ -63,0 +73,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
discontinuityStarts: [], | ||
segments: [] | ||
}; |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -9,3 +10,4 @@ playlistType: 'VOD', | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts' | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -15,3 +17,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts' | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -21,3 +24,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts' | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -27,3 +31,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts' | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts', | ||
title: '{}' | ||
} | ||
@@ -30,0 +35,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ segments: [ |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
playlists: [ | ||
@@ -4,0 +5,0 @@ { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 7794, | ||
@@ -4,0 +5,0 @@ discontinuitySequence: 0, |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'EVENT', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -22,3 +23,4 @@ playlistType: 'VOD', | ||
timeline: 0, | ||
uri: 'hls_450k_video.ts' | ||
uri: 'hls_450k_video.ts', | ||
title: ';asljasdfii11)))00,' | ||
}, | ||
@@ -25,0 +27,0 @@ { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 1, | ||
@@ -8,3 +9,4 @@ segments: [ | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts' | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts', | ||
title: '{}' | ||
} | ||
@@ -11,0 +13,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 1, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
discontinuityStarts: [], | ||
segments: [] | ||
}; |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -9,3 +10,4 @@ playlistType: 'VOD', | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts' | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -15,3 +17,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts' | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -21,3 +24,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts' | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -27,3 +31,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts' | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts', | ||
title: '{}' | ||
} | ||
@@ -30,0 +35,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ segments: [ |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -9,3 +10,4 @@ playlistType: 'VOD', | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts' | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -12,0 +14,0 @@ { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -8,3 +9,4 @@ segments: [ | ||
timeline: 0, | ||
uri: '001.ts' | ||
uri: '001.ts', | ||
title: '0' | ||
}, | ||
@@ -14,3 +16,4 @@ { | ||
timeline: 0, | ||
uri: '002.ts' | ||
uri: '002.ts', | ||
title: '0' | ||
}, | ||
@@ -20,3 +23,4 @@ { | ||
timeline: 0, | ||
uri: '003.ts' | ||
uri: '003.ts', | ||
title: '0' | ||
}, | ||
@@ -26,3 +30,4 @@ { | ||
timeline: 0, | ||
uri: '004.ts' | ||
uri: '004.ts', | ||
title: '0' | ||
}, | ||
@@ -32,3 +37,4 @@ { | ||
timeline: 0, | ||
uri: '005.ts' | ||
uri: '005.ts', | ||
title: '0' | ||
}, | ||
@@ -38,3 +44,4 @@ { | ||
timeline: 0, | ||
uri: '006.ts' | ||
uri: '006.ts', | ||
title: '0' | ||
}, | ||
@@ -44,3 +51,4 @@ { | ||
timeline: 0, | ||
uri: '007.ts' | ||
uri: '007.ts', | ||
title: '0' | ||
}, | ||
@@ -50,3 +58,4 @@ { | ||
timeline: 0, | ||
uri: '008.ts' | ||
uri: '008.ts', | ||
title: '0' | ||
}, | ||
@@ -56,3 +65,4 @@ { | ||
timeline: 0, | ||
uri: '009.ts' | ||
uri: '009.ts', | ||
title: '0' | ||
} | ||
@@ -59,0 +69,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
discontinuitySequence: 0, | ||
@@ -4,0 +5,0 @@ discontinuityStarts: [], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
discontinuitySequence: 0, | ||
@@ -4,0 +5,0 @@ discontinuityStarts: [], |
module.exports = { | ||
allowCache: true, | ||
dateTimeObject: new Date('2019-02-14T02:13:36.106Z'), | ||
dateTimeString: '2019-02-14T02:13:36.106Z', | ||
dateRanges: [], | ||
discontinuitySequence: 0, | ||
@@ -41,4 +40,3 @@ discontinuityStarts: [], | ||
{ | ||
dateTimeObject: new Date('2019-02-14T02:13:36.106Z'), | ||
dateTimeString: '2019-02-14T02:13:36.106Z', | ||
programDateTime: 1550110416106, | ||
duration: 4.00008, | ||
@@ -56,2 +54,3 @@ map: { | ||
}, | ||
programDateTime: 1550110420106.08, | ||
timeline: 0, | ||
@@ -65,2 +64,3 @@ uri: 'fileSequence267.mp4' | ||
}, | ||
programDateTime: 1550110424106.1602, | ||
timeline: 0, | ||
@@ -74,2 +74,3 @@ uri: 'fileSequence268.mp4' | ||
}, | ||
programDateTime: 1550110428106.2402, | ||
timeline: 0, | ||
@@ -83,2 +84,3 @@ uri: 'fileSequence269.mp4' | ||
}, | ||
programDateTime: 1550110432106.3203, | ||
timeline: 0, | ||
@@ -92,2 +94,3 @@ uri: 'fileSequence270.mp4' | ||
}, | ||
programDateTime: 1550110436106.4004, | ||
timeline: 0, | ||
@@ -149,4 +152,2 @@ uri: 'fileSequence271.mp4', | ||
{ | ||
dateTimeObject: new Date('2019-02-14T02:14:00.106Z'), | ||
dateTimeString: '2019-02-14T02:14:00.106Z', | ||
duration: 4.00008, | ||
@@ -156,2 +157,3 @@ map: { | ||
}, | ||
programDateTime: 1550110440106, | ||
timeline: 0, | ||
@@ -158,0 +160,0 @@ uri: 'fileSequence272.mp4', |
module.exports = { | ||
allowCache: true, | ||
dateTimeObject: new Date('2019-02-14T02:14:00.106Z'), | ||
dateTimeString: '2019-02-14T02:14:00.106Z', | ||
dateRanges: [], | ||
discontinuitySequence: 0, | ||
@@ -45,2 +44,3 @@ discontinuityStarts: [], | ||
duration: 4.00008, | ||
programDateTime: 1550110428105.7598, | ||
timeline: 0, | ||
@@ -51,2 +51,3 @@ uri: 'fileSequence269.mp4' | ||
duration: 4.00008, | ||
programDateTime: 1550110432105.8398, | ||
timeline: 0, | ||
@@ -57,2 +58,3 @@ uri: 'fileSequence270.mp4' | ||
duration: 4.00008, | ||
programDateTime: 1550110436105.92, | ||
timeline: 0, | ||
@@ -114,5 +116,4 @@ uri: 'fileSequence271.mp4', | ||
{ | ||
dateTimeObject: new Date('2019-02-14T02:14:00.106Z'), | ||
dateTimeString: '2019-02-14T02:14:00.106Z', | ||
duration: 4.00008, | ||
programDateTime: 1550110440106, | ||
timeline: 0, | ||
@@ -119,0 +120,0 @@ uri: 'fileSequence272.mp4', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ segments: [ |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ segments: [ |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ segments: [ |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
discontinuityStarts: [], | ||
@@ -4,0 +5,0 @@ mediaGroups: { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
playlists: [ | ||
@@ -4,0 +5,0 @@ { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -9,3 +10,4 @@ playlistType: 'VOD', | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts' | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -15,3 +17,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts' | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -21,3 +24,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts' | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -27,3 +31,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts' | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts', | ||
title: '{}' | ||
} | ||
@@ -30,0 +35,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ segments: [ |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -9,3 +10,4 @@ playlistType: 'VOD', | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts' | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -15,3 +17,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts' | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -21,3 +24,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts' | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -27,3 +31,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts' | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts', | ||
title: '{}' | ||
} | ||
@@ -30,0 +35,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -9,3 +10,4 @@ playlistType: 'VOD', | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts' | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -12,0 +14,0 @@ { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
discontinuityStarts: [], | ||
@@ -4,0 +5,0 @@ mediaGroups: { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
discontinuityStarts: [], | ||
@@ -4,0 +5,0 @@ mediaGroups: { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ targetDuration: 10, |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
discontinuityStarts: [], | ||
@@ -4,0 +5,0 @@ mediaGroups: { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: -11, | ||
@@ -9,3 +10,4 @@ playlistType: 'VOD', | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts' | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -15,3 +17,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts' | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -21,3 +24,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts' | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -27,3 +31,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts' | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts', | ||
title: '{}' | ||
} | ||
@@ -30,0 +35,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 17, | ||
@@ -9,3 +10,4 @@ playlistType: 'VOD', | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts' | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts', | ||
title: '{}' | ||
} | ||
@@ -12,0 +14,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
playlists: [ | ||
@@ -4,0 +5,0 @@ { |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 11, | ||
@@ -9,3 +10,4 @@ playlistType: 'VOD', | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts' | ||
uri: '/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -15,3 +17,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts' | ||
uri: '/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -21,3 +24,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts' | ||
uri: '/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts', | ||
title: '{}' | ||
}, | ||
@@ -27,3 +31,4 @@ { | ||
timeline: 0, | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts' | ||
uri: '/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts', | ||
title: '{}' | ||
} | ||
@@ -30,0 +35,0 @@ ], |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
dateRanges: [], | ||
mediaSequence: 0, | ||
@@ -4,0 +5,0 @@ playlistType: 'VOD', |
module.exports = { | ||
allowCache: true, | ||
mediaSequence: 0, | ||
dateRanges: [], | ||
playlistType: 'VOD', | ||
@@ -5,0 +6,0 @@ segments: [ |
@@ -638,6 +638,2 @@ import {LineStream, ParseStream} from '../src'; | ||
); | ||
assert.deepEqual( | ||
element.dateTimeObject, new Date('2016-06-22T09:20:16.166-04:00'), | ||
'dateTimeObject is parsed' | ||
); | ||
@@ -654,6 +650,2 @@ manifest = '#EXT-X-PROGRAM-DATE-TIME:2016-06-22T09:20:16.16389Z\n'; | ||
); | ||
assert.deepEqual( | ||
element.dateTimeObject, new Date('2016-06-22T09:20:16.16389Z'), | ||
'dateTimeObject is parsed' | ||
); | ||
} | ||
@@ -660,0 +652,0 @@ ); |
@@ -848,2 +848,67 @@ import QUnit from 'qunit'; | ||
QUnit.test('PDT value is assigned to segments with explicit #EXT-X-PROGRAM-DATE-TIME tags', function(assert) { | ||
this.parser.push([ | ||
'#EXTM3U', | ||
'#EXT-X-VERSION:6', | ||
'#EXT-X-TARGETDURATION:8', | ||
'#EXT-X-MEDIA-SEQUENCE:0', | ||
'#EXTINF:8.0', | ||
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00', | ||
'https://example.com/playlist1.m3u8', | ||
'#EXTINF:8.0,', | ||
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T22:14:10.053+00:00', | ||
'https://example.com/playlist2.m3u8', | ||
'#EXT-X-ENDLIST' | ||
].join('\n')); | ||
this.parser.end(); | ||
assert.equal(this.parser.manifest.segments[0].programDateTime, new Date('2017-07-31T20:35:35.053+00:00').getTime()); | ||
assert.equal(this.parser.manifest.segments[1].programDateTime, new Date('2017-07-31T22:14:10.053+00:00').getTime()); | ||
}); | ||
QUnit.test('backfill PDT values when the first EXT-X-PROGRAM-DATE-TIME tag appears after one or more Media Segment URIs', function(assert) { | ||
this.parser.push([ | ||
'#EXTM3U', | ||
'#EXT-X-VERSION:6', | ||
'#EXT-X-TARGETDURATION:8', | ||
'#EXT-X-MEDIA-SEQUENCE:0', | ||
'#EXTINF:8.0', | ||
'https://example.com/playlist1.m3u8', | ||
'#EXTINF:8.0,', | ||
'https://example.com/playlist2.m3u8', | ||
'#EXTINF:8.0', | ||
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00', | ||
'https://example.com/playlist3.m3u8', | ||
'#EXT-X-ENDLIST' | ||
].join('\n')); | ||
this.parser.end(); | ||
const segments = this.parser.manifest.segments; | ||
assert.equal(segments[2].programDateTime, new Date('2017-07-31T20:35:35.053+00:00').getTime()); | ||
assert.equal(segments[1].programDateTime, segments[2].programDateTime - (segments[1].duration * 1000)); | ||
assert.equal(segments[0].programDateTime, segments[1].programDateTime - (segments[0].duration * 1000)); | ||
}); | ||
QUnit.test('extrapolates forward when subsequent fragments do not have explicit PDT tags', function(assert) { | ||
this.parser.push([ | ||
'#EXTM3U', | ||
'#EXT-X-VERSION:6', | ||
'#EXT-X-TARGETDURATION:8', | ||
'#EXT-X-MEDIA-SEQUENCE:0', | ||
'#EXTINF:8.0', | ||
'#EXT-X-PROGRAM-DATE-TIME:2017-07-31T20:35:35.053+00:00', | ||
'https://example.com/playlist1.m3u8', | ||
'#EXTINF:8.0,', | ||
'https://example.com/playlist2.m3u8', | ||
'#EXTINF:8.0', | ||
'https://example.com/playlist3.m3u8', | ||
'#EXT-X-ENDLIST' | ||
].join('\n')); | ||
this.parser.end(); | ||
const segments = this.parser.manifest.segments; | ||
assert.equal(segments[0].programDateTime, new Date('2017-07-31T20:35:35.053+00:00').getTime()); | ||
assert.equal(segments[1].programDateTime, segments[0].programDateTime + segments[1].duration * 1000); | ||
assert.equal(segments[2].programDateTime, segments[1].programDateTime + segments[2].duration * 1000); | ||
}); | ||
QUnit.test('warns when #EXT-X-DATERANGE missing attribute', function(assert) { | ||
@@ -1008,3 +1073,3 @@ this.parser.push([ | ||
assert.deepEqual(this.parser.manifest.daterange[0].endDate, new Date('2023-04-13T15:16:29.840000Z')); | ||
assert.deepEqual(this.parser.manifest.dateRanges[0].endDate, new Date('2023-04-13T15:16:29.840000Z')); | ||
}); | ||
@@ -1058,3 +1123,3 @@ | ||
this.parser.end(); | ||
assert.equal(this.parser.manifest.daterange.length, 3); | ||
assert.equal(this.parser.manifest.dateRanges.length, 3); | ||
}); | ||
@@ -1061,0 +1126,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
454300
11571
391
0