Skip to content

Instantly share code, notes, and snippets.

@devsnek
Last active April 7, 2017 15:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devsnek/8490da94e86679581cf37ec97359b780 to your computer and use it in GitHub Desktop.
Save devsnek/8490da94e86679581cf37ec97359b780 to your computer and use it in GitHub Desktop.
const Stream = require('stream');
const https = require('https');
const http = require('http');
const URL = require('url');
/**
* Resumable stream via a Stream PassThrough
* @param {string|URL} url Input url
* @param {stream.Transform} [output=stream.PassThrough] Output stream
* @param {Object} [meta] Meta information to pass between stuff
* @returns {stream.Transform}
* @example
* const Speaker = require('speaker');
*
* const speaker = new Speaker({
* channels: 2,
* bitDepth: 16,
* sampleRate: 44100,
* });
*
* require('./')('http://www.music.helsinki.fi/tmt/opetus/uusmedia/esim/a2002011001-e02.wav').pipe(speaker);
*/
function streamIt(url, output = new Stream.PassThrough(), meta = { downloaded: 0, total: 0 }) {
if (output._destroyed) return output;
let input;
output.destroy = function destroy() {
this._destroyed = true;
if (input) {
input.unpipe();
input.destroy();
}
};
const options = typeof url === 'string' ? URL.parse(url) : url;
options.headers = {};
(url.startsWith('https') ? https : http).get(options, (res) => {
output.resume();
input = res;
if (meta.downloaded === 0) meta.total = Number(input.headers['content-length']);
input.on('data', (chunk) => {
meta.downloaded += Buffer.byteLength(chunk);
});
input.on('end', () => {
if (meta.downloaded < meta.total) {
input.unpipe();
options.headers.Range = `bytes=${meta.downloaded}`;
streamIt(options, output, meta);
} else {
output.end();
}
});
input.on('error', (err) => {
if (!err) return;
if (err.message === 'read ECONNRESET') {
output.pause();
return;
}
output.emit('error', err);
});
input.pipe(output, { end: false });
});
return output;
}
module.exports = streamIt;
@itslukej
Copy link

itslukej commented Apr 7, 2017

url.startsWith('https') should be options.protocol === 'https:', If it starts again url is a parsed object
The range header should also be bytes=${meta.downloaded}- not bytes=${meta.downloaded}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment