@artrix909/hls-dl
Version:
Downloads HTTP live/archived stream (m3u, m3u8, mpd)
80 lines (69 loc) • 3.27 kB
JavaScript
const stream = require('stream');
const url = require('url');
const http = require('http');
const https = require('https');
const fs = require('fs');
const m3u = require('./parsers/m3u');
const mpd = require('./parsers/mpd');
/**
* @param {String} path Path to stream playlist
* @param {Object} options Objects for configuring playlist capture
* @returns {ReadableStream} Readable stream of the playlist
*/
const hlsdl = (path, options) => {
if(path instanceof Object || path == '') throw Error('A path to an M3U or MPD stream was not provided. Please be sure to include a path to continue');
const hlsstream = new stream.PassThrough();
options = options || {};
options.path = path;
options.timeout = (options.timeout) ? options.timeout : 2500;
options.livebuffer = (options.livebuffer) ? options.livebuffer : 20000;
options.headers = (options.headers) ? options.headers : {};
const host = url.parse(path);
/**
* @type {https}
*/
let httpLib = null;
let parser = (options.parser) ? getParser(`.${options.parser}`) : getParser(path);
(host.protocol === 'http:') ? httpLib = http : httpLib = https;
if(host.protocol != 'http:' && host.protocol != 'https:' && host.protocol != 'file:') {
throw new Error('No protocol was included in the path provided. Please ensure an http, https, or file protocol is selected.')
}
if(host.protocol === 'file:') {
fs.readFile(host.path, (err, data) => {
if(err) throw Error('The path to the file provided does not exist. Please check again.');
let internalStream = new parser(httpLib, hlsstream, options);
internalStream.write(data);
});
} else {
/**
*
* @param {url.UrlWithStringQuery} host
*/
const downloadPlaylist = (host) => {
httpLib.get({ path: host.href, headers: options.headers }, (res) => {
let internalStream = new parser(httpLib, hlsstream, options);
let responseBody = '';
if (res.statusCode >= 500 || res.statusCode < 200) throw Error(`The path provided returned a ${res.statusCode} status code. Please ensure the request resource is available for access before continuing.`);
res.on('error', (err) => { console.log(err); downloadPlaylist(host) });
if (res.statusCode === 200) {
res.on('data', chunk => {
responseBody += chunk;
});
res.on('end', () => {
internalStream.write(responseBody);
});
} else {
res.on('data', chunk => console.log(chunk.toString()));
}
}).on('error', (err) => downloadPlaylist(host));
}
downloadPlaylist(host);
}
return hlsstream;
};
const getParser = (path) => {
if(RegExp('.m3u').test(path)) return m3u;
if(RegExp('.mpd').test(path)) return mpd;
throw Error('No compatible HLS stream type detected. Please ensure you\'ve provided a direct link to an M3U or MPD stream.');
};
module.exports = hlsdl;