Last active
September 14, 2023 01:29
-
-
Save adammw/6257550 to your computer and use it in GitHub Desktop.
HLS / M3U8 Downloader for AES-128 Encrypted Streams
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
// M3U8 Downloader (not working) | |
var fs = require('fs'); | |
var http = require('http'); | |
var https = require('https'); | |
var crypto = require('crypto'); | |
var program = require('commander'); | |
var ee = require('streamee'); | |
var urlparse = require('url').parse; | |
var PassThrough = require('stream').PassThrough; | |
var WritableBufferStream = require('buffertools').WritableBufferStream; | |
program | |
.version('0.0.1') | |
.usage('[options] <file ...>') | |
.parse(process.argv); | |
var file = program.args[0]; | |
var rendition = fs.readFileSync(file, {encoding: 'utf8'}); | |
var keyid = 0; | |
var keycbs = {}; | |
var id = 0; | |
var request = function(url, cb) { | |
var url = urlparse(url); | |
var module = ('https:' == url.protocol) ? https : http; | |
url.agent = module.globalAgent; | |
return module.get(url, function(res) { | |
if (res.statusCode != 200) throw new Error(res.statusCode + ': ' + http.STATUS_CODES[res.statusCode]); | |
cb(res); | |
}); | |
} | |
var bufferedRequest = function(url, cb) { | |
return request(url, function(res) { | |
var ostream = new WritableBufferStream(); | |
res.pipe(ostream); | |
res.on('end', function() { | |
cb(ostream.getBuffer()); | |
}); | |
}); | |
}; | |
var dataStreams = []; | |
rendition.split('\n').forEach(function (line) { | |
if (line.substr(0,1) == '#') { | |
if (/^#EXT-X-KEY/.test(line)) { | |
keyid++; | |
var mykeyid = keyid; | |
keycbs[mykeyid] = []; | |
var url = /URI="(.+?)"/.exec(line)[1]; | |
bufferedRequest(url, function(key) { | |
keycbs[mykeyid].forEach(function(cb) { | |
cb(key); | |
}) | |
}); | |
} else { | |
//console.log('Unhandled: %s', line); | |
} | |
} else if (/^http/.test(line)) { | |
var url = line; | |
var segid = id; | |
var dataStream = new PassThrough(); | |
dataStream.on('end', function() { | |
console.log('Segement #%d finsihed', segid); | |
}) | |
dataStreams.push(dataStream); | |
console.log('Queuing download of segment #%d', segid); | |
keycbs[keyid].push(function(key) { | |
var iv = new Buffer(16); | |
iv.fill(0); | |
var decipher = crypto.createDecipheriv('aes128', key, iv); | |
request(url, function(res) { | |
res.pipe(decipher).pipe(dataStream); | |
}).on('socket', function() { | |
console.log('Starting download of segment #%d', segid); | |
}); | |
}); | |
id++; | |
} | |
}); | |
console.log('%d segments',dataStreams.length); | |
var finalStream = ee.concatenate(dataStreams); | |
var outfile = fs.createWriteStream('output.ts'); | |
finalStream.pipe(outfile); | |
finalStream.on('end', function() { | |
console.log('Download completed.'); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment