Files
youtube-dl-web/src/server.js

108 lines
2.6 KiB
JavaScript

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);
}
});
});
};