function onResponse(stream) { // Clean up request. ee.removeListener('requestError', onRequestError); ee.removeListener('responseError', onResponseError); delete self._req; // Parse JSON with JStream. var jstream = new JStream(); // Listen for other errorneous events. function onError(err) { self.reconnect('exponential'); if (self.id) { err.streamid = self.id; err.streamtype = self.type; } self.emit('error', err); } function onResponseEnd() { self.reconnect('exponential'); self.emit('end'); } function onResponseClose() { self.reconnect('exponential'); self.emit('end'); } // Keep track of the last time a `data` event occurred to make sure // the stream does not time out. function onStreamTimeout() { self.reconnect('linear'); self.emit('timeout'); } function onData(data) { self._ondata(data); clearTimeout(timeout); timeout = setTimeout(onStreamTimeout, constants.STREAM_TIMEOUT); } var timeout = setTimeout(onStreamTimeout, constants.STREAM_TIMEOUT); jstream.on('data', onData); // Clean up everything after this stream is not used anymore. self._cleanup = function cleanup() { self.connected = false; stream.removeListener('error', onError); stream.removeListener('end', onResponseEnd); stream.removeListener('close', onResponseClose); stream.removeListener('data', onData); stream.destroy(); jstream.removeListener('error', onError); clearTimeout(timeout); delete self._stream; delete self._cleanup; }; stream.on('end', onResponseEnd); stream.on('close', onResponseClose); stream.pipe(jstream); stream.on('error', onError); jstream.on('error', onError); // Label as connected. self._stream = stream; self.connected = true; self.emit('connect'); }
crequest(link, function(err, body) { if (err) return callback(err); var jsonStr = util.between(body, 'ytplayer.config = ', '</script>'); if (!jsonStr) { return callback(new Error('could not find `ytplayer.config`')); } var jstream = new JStream(); var ended = false; jstream.on('data', function(config) { ended = true; jstream.pause(); var newFormats = util.parseFormats(config.args); var html5playerfile = 'http:' + config.assets.js; crequest(html5playerfile, function(err, body) { if (err) return callback(err); var tokens = exports.extractActions(body); if (!tokens || !tokens.length) { if (debug) { var splits = html5playerfile.split('/'); var name = splits[splits.length - 2].slice(12); var filename = name + '.js'; var filepath = path.resolve( __dirname, '../test/files/html5player/' + filename); fs.writeFile(filepath, body); var html5player = require('../test/html5player.json'); if (!html5player[name]) { html5player[name] = []; fs.writeFile( path.resolve(__dirname, '../test/html5player.json'), JSON.stringify(html5player, null, 2)); } } callback( new Error('could not extract signature deciphering actions')); return; } info.formats = info.formats.map(function(format) { var newFormat = newFormats .filter(function(f) { return f.itag === format.itag; })[0]; if (newFormat && newFormat.s) { format = newFormat; } var sig = exports.decipher(tokens, format.s); format.url = exports.getDownloadURL(format, sig, debug); return format; }); callback(null, info); }); }); jstream.on('error', function(err) { if (ended) { return; } callback( new Error('could not parse `ytplayer.config`: ' + err.message)); }); jstream.end(jsonStr); });
crequest(requestOptions, function(err, body) { if (err) return callback(err); var jsonStr = util.between(body, 'ytplayer.config = ', '</script>'); if (!jsonStr) { return callback(new Error('could not find `ytplayer.config`')); } var jstream = new JStream(); var ended = false; jstream.on('data', function(config) { ended = true; jstream.pause(); var info = config.args; if (info.status === 'fail') { callback(new Error('Error ' + info.errorcode + ': ' + info.reason)); return; } // Split some keys by commas. KEYS_TO_SPLIT.forEach(function(key) { if (!info[key]) return; info[key] = info[key] .split(',') .filter(function(v) { return v !== ''; }); }); info.fmt_list = info.fmt_list ? info.fmt_list.map(function(format) { return format.split('/'); }) : []; if (info.video_verticals) { info.video_verticals = info.video_verticals .slice(1, -1) .split(', ') .filter(function(val) { return val !== ''; }) .map(function(val) { return parseInt(val, 10); }) ; } info.formats = util.parseFormats(info); var $ = cheerio.load(body); info.description = $('#eow-description').text(); if (downloadURL) { sig.get(info, config.assets.js, debug, callback); } else { callback(null, info); } }); jstream.on('error', function(err) { if (ended) { return; } callback( new Error('could not parse `ytplayer.config`: ' + err.message)); }); jstream.end(jsonStr); });