const path = require('path'); const fs = require('fs'); const spawn = require('cross-spawn'); const logger = require('./logger'); const sendError = (res, code) => { res.writeHeader(code); res.write(code === 400 ? 'Bad Request' : 'Internal Server Error'); res.end(); }; module.exports = async function server(req, res) { let sent = false; let filename; const { url, format } = req.queryParams; logger.info(`Request: ${req.url}`); if (!url) { sendError(res, 400); return; } const dataPath = path.resolve(__dirname, '../data'); const params = [url]; if (format) { params.unshift(format); params.unshift('--format'); } logger.info(`Downloading ${url}`); const proc = spawn('youtube-dl', params, { stdio: 'pipe', cwd: dataPath, }); proc.stdout.on('data', data => { const match = data.toString().match(/\[download\] Destination: (.+)/i); const existsMatch = data.toString().match(/\[download\] (.+) has already been downloaded/i); if (match !== null) { // eslint-disable-next-line prefer-destructuring filename = match[1]; } else if (existsMatch !== null) { // eslint-disable-next-line prefer-destructuring filename = existsMatch[1]; } }); proc.on('error', err => { logger.error(err); logger.info(`child process exited with code ${err.code}`); if (!sent) { sendError(res, 500); sent = true; } }); proc.on('close', code => { logger.info(`child process exited with code ${code}`); if (!filename) { logger.error('Failed to capture download filename'); sendError(res, 500); sent = true; return; } const dlFilepath = path.join(__dirname, '../data', filename); logger.info(`Downloaded file is ${dlFilepath}`); if (!sent) { fs.readFile(dlFilepath, (err, fileBuffer) => { if (err) { sendError(res, 500); sent = true; return; } res.writeHead(200, { 'Content-Type': 'application/octet-stream', 'Content-Length': fileBuffer.length, 'Content-disposition': `attachment; filename=${filename}`, }); res.write(fileBuffer); res.end(); sent = true; }); } sent = true; // clean up the download if told to res.on('finish', () => { const { REMOVE_DOWNLOAD } = process.env; if (!REMOVE_DOWNLOAD) return; const shouldRemove = REMOVE_DOWNLOAD === '1' || REMOVE_DOWNLOAD.toLowerCase() === 'true'; if (shouldRemove) { logger.info('Removing local file:', dlFilepath); fs.unlinkSync(dlFilepath); } }); }); };