const expressManager = require("./express.js"), path = require("path"), fs = require("fs"), ytdl = require("@distube/ytdl-core"), ffmpeg = require("ffmpeg-static"), cp = require("child_process") var qualityLabels = [ "144", "240", "360", "480", "720", "1080", "1440", "2160" ] var audioFormats = [ "mp3" ] expressManager.app.get("/download", async (req, res) => { var url = req.query.url, quality = req.query.quality, format = req.query.format, trimAudio = req.query.trimAudio && audioFormats.includes(format) || false if (ytdl.validateURL(url) && qualityLabels.includes(quality)) { var needsVideo = !audioFormats.includes(format) var info = await ytdl.getInfo(url) res.setHeader("Content-Disposition", `attachment; filename*="${info.videoDetails.title.replace(/[^a-z0-9 ]/gi, '')}.${format}"`) var audioFormat = ytdl.chooseFormat(info.formats, { filter: (format) => { return format.hasAudio && !format.hasVideo } }) var videoFormat = undefined var qualityLabel = quality while (videoFormat == undefined) { for (let i = 0; i < info.formats.length; i++) { const format = info.formats[i]; if (format.hasVideo && !format.hasAudio && format.height.toString() == qualityLabel.toString()) { videoFormat = format continue } } if (qualityLabels.indexOf(qualityLabel) - 1 < 0) { break } qualityLabel = qualityLabels[qualityLabels.indexOf(qualityLabel) - 1] } if (!videoFormat) { videoFormat = ytdl.chooseFormat(info.formats, { filter: "videoonly" }) } var baseArgs = [ // Remove ffmpeg's console spamming '-loglevel', 'error', // // Set inputs // '-i', 'pipe:4', // '-i', 'pipe:5', // Map audio & video from streams // '-map', '0:a', // '-map', '1:v', // Keep encoding '-c:v', 'copy', '-movflags','frag_keyframe+empty_moov', '-f', format, // Define output file '-', ] var inputArgs = [ '-i', 'pipe:4' ] var mapArgs = [ '-map', '0:a' ] var bonusArgs = [] if (needsVideo) { inputArgs = inputArgs.concat(['-i', 'pipe:5']) mapArgs = mapArgs.concat(['-map', '1:v']) } if (trimAudio) { bonusArgs = bonusArgs.concat(['-af', 'silenceremove=1:0:-50dB']) } var args = inputArgs.concat(mapArgs).concat(bonusArgs).concat(baseArgs) const ffmpegProcess = cp.spawn(ffmpeg, args, { windowsHide: true, stdio: [ /* Standard: stdin, stdout, stderr */ 'pipe', 'pipe', 'pipe', /* Custom: pipe:3, pipe:4, pipe:5 */ 'pipe', 'pipe', 'pipe', ], }); ffmpegProcess.stdio[1].pipe(res) var audio = ytdl(url, { format: audioFormat || "audioonly" }) audio.pipe(ffmpegProcess.stdio[4]) if (needsVideo) { var video = ytdl(url, { format: videoFormat || "videoonly" }) video.pipe(ffmpegProcess.stdio[5]) } } else { res.send("Invalid URL!") } })