/** * Downloads a video after retrieving video info. * * @param {Object} options * @param {ReadableStream} stream * @param {Object} info * @return {ReadableStream} */ function download(options, stream, info) { var formats = info.formats; if (options.filter) { formats = formats.filter(options.filter); if (formats.length === 0) { stream.emit('error', new Error('No formats found with custom filter')); return; } } var format; switch (options.quality) { case 'highest': format = formats[0]; break; case 'lowest': format = formats[formats.length - 1]; break; default: format = formats.filter(function(format) { return format.itag === '' + options.quality; })[0]; } if (!format) { stream.emit('error', new Error('No such format found')); return; } format = Hash.copy(format); var parsedUrl = url.parse(format.url, true); delete parsedUrl.search; var requestOptions = Hash.copy(options); delete requestOptions.quality; delete requestOptions.start; delete requestOptions.filter; if (options.start) { parsedUrl.query.begin = util.parseTime(options.start); } format.url = requestOptions.url = url.format(parsedUrl); // Start downloading the video. var res = request(requestOptions); res.on('response', function(res) { if (res.statusCode !== 200) { return stream.emit('error', new Error('status code ' + res.statusCode)); } format.size = res.headers['content-length']; stream.emit('info', info, format); }); stream.resolve(res); }
/** * Downloads a video after retrieving video info. * * @param {Object} options * @param {ReadableStream} stream * @param {Object} info * @return {ReadableStream} */ function download(options, stream, info) { var formats = info.formats; if (options.filter) { formats = formats.filter(options.filter); } var format; switch (options.quality) { case 'highest': format = formats[0]; break; case 'lowest': format = formats[formats.length - 1]; break; default: format = formats.filter(function(_format) { return _format.itag === options.quality; })[0]; } if (!format) { stream.emit('error', new Error('No such format found')); return; } format = Hash.copy(format); var url = format.url; var requestOptions = Hash.copy(options); if (options.start) { url = url + '&begin=' + parseTime(options.start); } format.url = requestOptions.url = url; // Start downloading the video. var res = request(requestOptions); res.on('response', function(res) { if (res.statusCode !== 200) { return stream.emit('error', new Error('status code ' + res.statusCode)); } format.size = res.headers['content-length']; stream.emit('info', info, format); }); stream.resolve(res); }
function checkUsage(f) { var _process = process; process = Hash.copy(process); var exit = false; process.exit = function () { exit = true }; process.env = Hash.merge(process.env, { _: 'node' }); process.argv = [ './usage' ]; var errors = []; var logs = []; console._error = console.error; console.error = function (msg) { errors.push(msg) }; console._log = console.log; console.log = function (msg) { logs.push(msg) }; var result = f(); process = _process; console.error = console._error; console.log = console._log; return { errors: errors, logs: logs, exit: exit, result: result, }; };
ytdl.getInfo = function getInfo(link, requestOptions, callback) { if (typeof requestOptions === 'function') { callback = requestOptions; requestOptions = {}; } else { requestOptions = Hash.copy(requestOptions); } var linkParsed = url.parse(link, true); var id = linkParsed.hostname === 'youtu.be' ? linkParsed.pathname.slice(1) : linkParsed.query.v; if (!id) { process.nextTick(function() { callback(new Error('Video ID not found')); }); return; } requestOptions.url = INFO_URL + id; request(requestOptions, function(err, res, body) { if (err) return callback(err); if (res.statusCode !== 200) { return callback(new Error('Video not found: ' + link)); } var info = qs.parse(body); 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 !== ''; }); }); // Convert some strings to javascript numbers and booleans. info = Hash.map(info, function(val) { var intVal = parseInt(val, 10); var floatVal = parseFloat(val, 10); if (intVal.toString() === val) { return intVal; } else if (floatVal.toString() === val) { return floatVal; } else if (val === 'True') { return true; } else if (val === 'False') { return false; } else { return val; } }); if (info.fmt_list) { info.fmt_list = info.fmt_list.map(function(format) { return format.split('/'); }); } else { info.fmt_list = []; } info.formats = []; if (info.url_encoded_fmt_stream_map) { info.formats = info.formats .concat(info.url_encoded_fmt_stream_map.split(',')); } if (info.adaptive_fmts) { info.formats = info.formats.concat(info.adaptive_fmts.split(',')); } info.formats = info.formats .map(function(format) { var data = qs.parse(format); if (data.conn && data.conn.indexOf('rtmp') === 0) { data.rtmp = true; } else { var parsedUrl = url.parse(data.url, true); delete parsedUrl.search; var query = parsedUrl.query; var sig = data.sig || data.s; if (sig) { query.signature = info.use_cipher_signature ? util.signatureDecipher(sig) : sig; } data.url = url.format(parsedUrl); } format = FORMATS[data.itag]; if (!format) { console.warn('No such format for itag ' + data.itag + ' found'); } Hash(format).forEach(function(val, key) { data[key] = val; }); return data; }); delete info.url_encoded_fmt_stream_map; delete info.adaptive_fmts; info.formats.sort(util.sortFormats); info.video_verticals = info.video_verticals .slice(1, -1) .split(', ') .filter(function(val) { return val !== ''; }) .map(function(val) { return parseInt(val, 10); }) ; cache.set(id, info); callback(null, info); }); };
exports.bundle = function (opts) { if (typeof opts === 'string') { opts = { base : opts }; var opts_ = arguments[1]; if (typeof opts_ === 'object') { Object.keys(opts_).forEach(function (key) { opts[key] = opts_[key]; }); } } if (opts.main && opts.main.match(/^\//) && !opts.filename) { opts.filename = opts.main; } var shim = 'shim' in opts ? opts.shim : true; var req = opts.require || []; if (!Array.isArray(req)) req = [req]; var src = fs.readFileSync(__dirname + '/wrappers/prelude.js', 'utf8') + fs.readFileSync(__dirname + '/wrappers/node_compat.js', 'utf8') + (shim ? source.modules('es5-shim')['es5-shim'] : '') + builtins + (req.length ? exports.wrap( req, Hash.merge(opts, { base : undefined }) ).source : '' ) ; if (Array.isArray(opts.base)) { opts.base.forEach(function (base) { src += exports.wrapDir(base, Hash.merge(opts, { base : base })); }); } else if (typeof opts.base === 'object') { Hash(opts.base).forEach(function (base, name) { src += exports.wrapDir(base, Hash.merge(opts, { base : base, name : name, })); }); } else if (typeof opts.base === 'string') { src += exports.wrapDir(opts.base, opts); } else if (!opts.base && opts.main) { var opts_ = Hash.copy(opts); opts_.base = path.dirname(opts.main); src += exports.wrap('./' + path.basename(opts.main), opts).source; } if (opts.entry) { if (!Array.isArray(opts.entry)) { opts.entry = [ opts.entry ]; } var entryBody = fs.readFileSync( __dirname + '/wrappers/entry.js', 'utf8' ); opts.entry.forEach(function (entry) { fileWatch(entry, opts); src += entryBody .replace(/\$aliases/g, function () { return JSON.stringify([]); }) .replace(/\$__filename/g, function () { return JSON.stringify('./' + path.basename(entry)) }) .replace(/\$__dirname/g, function () { return JSON.stringify('.') }) .replace('$body', function () { return fs.readFileSync(entry, 'utf8') }) ; }); } return opts.filter ? opts.filter(src) : src; };