Socket
Socket
Sign inDemoInstall

m3u8stream

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

m3u8stream - npm Package Compare versions

Comparing version 0.4.2 to 0.5.0

62

lib/dash-mpd-parser.js

@@ -18,4 +18,5 @@ const Writable = require('stream').Writable;

let lastTag;
let starttime = 0;
let currtime = 0;
let seq = 0;
let segmentTemplate;
let timescale, offset, duration, baseURL;

@@ -27,6 +28,15 @@ let timeline = [];

const tmpl = (str) => {
const context = {
RepresentationID: targetID,
Number: seq,
Time: currtime,
};
return str.replace(/\$(\w+)\$/g, (m, p1) => context[p1]);
};
this._parser.on('opentag', (node) => {
switch (node.name) {
case 'mpd':
starttime =
currtime =
new Date(node.attributes.availabilitystarttime).getTime();

@@ -45,14 +55,19 @@ isStatic = node.attributes.type !== 'dynamic';

case 'segmentlist':
seq = parseInt(node.attributes.startnumber, 10) || seq;
timescale = parseInt(node.attributes.timescale, 10) || timescale;
duration = parseInt(node.attributes.duration, 10) || duration;
offset = parseInt(node.attributes.presentationtimeoffset, 10) || offset;
seq = parseInt(node.attributes.startnumber) || seq;
timescale = parseInt(node.attributes.timescale) || timescale;
duration = parseInt(node.attributes.duration) || duration;
offset = parseInt(node.attributes.presentationtimeoffset) || offset;
if (!startEmitted) {
startEmitted = true;
if (offset) {
starttime += offset;
currtime += offset;
}
this.emit('starttime', starttime);
this.emit('starttime', currtime);
}
break;
case 'segmenttemplate':
segmentTemplate = node.attributes;
seq = parseInt(node.attributes.startnumber) || seq;
timescale = parseInt(node.attributes.timescale) || timescale;
break;
case 'segmenttimeline':

@@ -63,3 +78,6 @@ case 'baseurl':

case 's':
timeline.push(parseInt(node.attributes.d, 10));
timeline.push([
parseInt(node.attributes.d),
parseInt(node.attributes.r)
]);
break;

@@ -73,2 +91,25 @@ case 'adaptationset':

getSegments = node.attributes.id === targetID + '';
if (getSegments && segmentTemplate && timeline.length) {
if (segmentTemplate.initialization) {
this.emit('item', {
url: baseURL.filter(s => !!s).join('') +
tmpl(segmentTemplate.initialization),
seq: seq - 1,
duration: 0,
});
}
for (let [duration, repeat] of timeline) {
duration = duration / timescale * 1000;
repeat = repeat || 1;
for (let i = 0; i < repeat; i++) {
this.emit('item', {
url: baseURL.filter(s => !!s).join('') +
tmpl(segmentTemplate.media),
seq: seq++,
duration,
});
currtime += duration;
}
}
}
break;

@@ -87,3 +128,3 @@ case 'initialization':

let tl = timeline.shift();
let segmentDuration = (tl || duration) / timescale * 1000;
let segmentDuration = (tl && tl[0] || duration) / timescale * 1000;
this.emit('item', {

@@ -94,2 +135,3 @@ url: baseURL.filter(s => !!s).join('') + node.attributes.media,

});
currtime += segmentDuration;
}

@@ -96,0 +138,0 @@ break;

22

lib/index.js

@@ -24,3 +24,3 @@ const PassThrough = require('stream').PassThrough;

'dash-mpd': DashMPDParser,
}[options.parser || 'm3u8'];
}[options.parser || (/\.mpd$/.test(playlistURL) ? 'dash-mpd' : 'm3u8')];
if (!Parser) {

@@ -36,12 +36,20 @@ throw TypeError(`parser '${options.parser}' not supported`);

let currSegment;
let bytesDownloaded = 0;
const streamQueue = new Queue((segment, callback) => {
currSegment = segment;
segment.pipe(stream, { end: false });
segment.on('data', (chunk) => { bytesDownloaded += chunk.length; });
segment.on('end', callback);
}, { concurrency: 1 });
let segmentNumber = 0;
const requestQueue = new Queue((segmentURL, callback) => {
let segment = miniget(urlResolve(playlistURL, segmentURL), requestOptions);
segmentURL = urlResolve(playlistURL, segmentURL);
let segment = miniget(segmentURL, requestOptions);
segment.on('error', callback);
streamQueue.push(segment, callback);
streamQueue.push(segment, () => {
stream.emit('progress',
++segmentNumber, requestQueue.total, bytesDownloaded, segmentURL);
callback();
});
}, { concurrency: chunkReadahead });

@@ -62,2 +70,3 @@

let ended = false;
let static = false;
let lastRefresh;

@@ -69,7 +78,8 @@

onError(err);
} else if (!fetchingPlaylist && !ended &&
} else if (!fetchingPlaylist && !ended && !static &&
requestQueue.tasks.length + requestQueue.active === refreshThreshold) {
let ms = Math.max(0, minRefreshTime - (Date.now() - lastRefresh));
refreshTimeout = setTimeout(refreshPlaylist, ms);
} else if (ended && !requestQueue.tasks.length && !requestQueue.active) {
} else if ((ended || static) &&
!requestQueue.tasks.length && !requestQueue.active) {
stream.end();

@@ -94,3 +104,3 @@ }

});
parser.on('endlist', () => { ended = true; });
parser.on('endlist', () => { static = true; });
parser.on('endearly', () => { currPlaylist.unpipe(parser); });

@@ -97,0 +107,0 @@

@@ -33,7 +33,7 @@ const Writable = require('stream').Writable;

case 'EXT-X-MEDIA-SEQUENCE':
this._seq = parseInt(value, 10);
this._seq = parseInt(value);
break;
case 'EXTINF':
this._nextItemDuration =
Math.round(parseFloat(value.split(',')[0], 10) * 1000);
Math.round(parseFloat(value.split(',')[0]) * 1000);
break;

@@ -40,0 +40,0 @@ case 'EXT-X-ENDLIST':

@@ -13,2 +13,3 @@ module.exports = class Queue {

this.tasks = [];
this.total = 0;
this.active = 0;

@@ -26,2 +27,3 @@ }

this.tasks.push({ item, callback });
this.total++;
this._next();

@@ -28,0 +30,0 @@ }

@@ -13,3 +13,3 @@ {

],
"version": "0.4.2",
"version": "0.5.0",
"repository": {

@@ -33,3 +33,3 @@ "type": "git",

"istanbul": "^0.4.5",
"lolex": "^2.7.1",
"lolex": "^3.0.0",
"mocha": "^5.0.0",

@@ -36,0 +36,0 @@ "nock": "^10.0.0"

@@ -35,7 +35,17 @@ # node-m3u8stream

* `requestOptions` - Any options you want to pass to [miniget](https://github.com/fent/node-miniget), such as `headers`.
* `parser` - Either "m3u8" or "dash-mpd". Defaults to "m3u8".
* `id` - If playlist contains multiple media options. Otherwise, the first representation will be picked.
* `parser` - Either "m3u8" or "dash-mpd". Defaults to guessing based on the playlist url ending in `.m3u8` or `.mpd`.
* `id` - For playlist containing multiple media options. If not given, the first representation will be picked.
Stream has an `.end()` method, that if called, stops requesting segments, and refreshing the playlist.
### Stream#end()
If called, stops requesting segments, and refreshing the playlist.
#### Event: progress
* `number` - Current segment number.
* `number` - Total number of segments.
* `number` - Bytes downloaded up to this point.
* `string` - URL of current segment.
For static non-live playlists, emitted each time a segment has finished downloading. Since total download size is unknown until all segment endpoints are hit, progress is calculated based on how many segments are available.
### Limitations

@@ -42,0 +52,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc