Univerter/downloader.js

127 lines
3.7 KiB
JavaScript
Raw Normal View History

2024-07-29 00:45:58 -05:00
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,
2024-07-31 02:54:26 -05:00
format = req.query.format,
trimAudio = req.query.trimAudio && audioFormats.includes(format) || false
2024-07-29 00:45:58 -05:00
if (ytdl.validateURL(url) && qualityLabels.includes(quality)) {
var needsVideo = !audioFormats.includes(format)
var info = await ytdl.getInfo(url)
2024-11-06 18:51:46 -06:00
var downloadType = "attachment"
if (req.query.playInBrowser) downloadType = "inline";
res.setHeader("Content-Disposition", `${downloadType}; filename="${info.videoDetails.title.replace(/[^a-z0-9 ]/gi, '')}.${format}"`)
2024-07-29 00:45:58 -05:00
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];
2024-09-15 14:49:35 -05:00
if (format.hasVideo && !format.hasAudio && format.height && format.height.toString() == qualityLabel.toString() && (format.videoCodec.includes("avc1") || format.codecs.includes("avc1"))) {
// console.log(format.videoCodec)
2024-07-29 00:45:58 -05:00
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'
]
2024-07-31 02:54:26 -05:00
var bonusArgs = []
2024-07-29 00:45:58 -05:00
if (needsVideo) {
inputArgs = inputArgs.concat(['-i', 'pipe:5'])
mapArgs = mapArgs.concat(['-map', '1:v'])
}
2024-07-31 02:54:26 -05:00
if (trimAudio) {
bonusArgs = bonusArgs.concat(['-af', 'silenceremove=1:0:-50dB'])
}
var args = inputArgs.concat(mapArgs).concat(bonusArgs).concat(baseArgs)
2024-07-29 00:45:58 -05:00
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!")
}
})