147 lines
No EOL
4.2 KiB
JavaScript
147 lines
No EOL
4.2 KiB
JavaScript
const expressManager = require("./express.js"),
|
|
path = require("path"),
|
|
fs = require("fs"),
|
|
ffmpeg = require("ffmpeg-static"),
|
|
cp = require("child_process"),
|
|
axios = require("axios"),
|
|
{ Readable } = require("stream")
|
|
|
|
const qualityLabels = [
|
|
"144",
|
|
"240",
|
|
"360",
|
|
"480",
|
|
"720",
|
|
"1080",
|
|
"1440",
|
|
"2160",
|
|
"4320"
|
|
]
|
|
|
|
var audioFormats = [
|
|
"mp3"
|
|
]
|
|
|
|
expressManager.app.get("/watch", async (req, res) => {
|
|
var html = fs.readFileSync(path.join(__dirname, "resources/playInBrowser.html")).toString()
|
|
var finalMetadata = "?"
|
|
for (var i in req.query) {
|
|
if (i != "playInBrowser") {
|
|
finalMetadata += i + "=" + req.query[i] + "&"
|
|
}
|
|
}
|
|
html = html.replaceAll("{DOWNLOAD_URL}", finalMetadata)
|
|
res.send(html)
|
|
})
|
|
|
|
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
|
|
|
|
// url = url.substring(url.indexOf("v=") + 2)
|
|
// if (url.includes("&")) url = url.substring(0, url.indexOf("&"))
|
|
|
|
if (req.query.playInBrowser && !audioFormats.includes(format)) {
|
|
var metadata = req.url.substring(req.url.indexOf("?"))
|
|
res.redirect("/watch" + metadata)
|
|
} else if (url && qualityLabels.includes(quality)) {
|
|
var needsVideo = !audioFormats.includes(format)
|
|
|
|
// var info = await fetch("https://cobalt.univerter.dev/", {
|
|
// method: 'POST',
|
|
// headers: {
|
|
// Accept: "application/json",
|
|
// "Content-Type": "application/json"
|
|
// },
|
|
// body: JSON.stringify({
|
|
// url
|
|
// }),
|
|
// })
|
|
|
|
var downloadMode = "audio"
|
|
if (needsVideo) downloadMode = "auto"
|
|
|
|
var info = await axios.post("https://cobalt.univerter.dev/", {
|
|
url,
|
|
downloadMode,
|
|
videoQuality: quality,
|
|
localProcessing: true,
|
|
}, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json'
|
|
}
|
|
})
|
|
|
|
console.log(info)
|
|
|
|
var downloadType = "attachment"
|
|
if (req.query.playInBrowser) downloadType = "inline";
|
|
|
|
res.setHeader("Content-Disposition", `${downloadType}; filename="${info.data.output.filename.replace(/[^a-z0-9 ]/gi, '')}.${format}"`)
|
|
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 = await fetch(info.data.tunnel[1] || info.data.tunnel[0])
|
|
|
|
Readable.fromWeb(audio.body).pipe(ffmpegProcess.stdio[4])
|
|
|
|
if (needsVideo) {
|
|
var video = await fetch(info.data.tunnel[0])
|
|
|
|
Readable.fromWeb(video.body).pipe(ffmpegProcess.stdio[5])
|
|
}
|
|
|
|
} else {
|
|
res.send("Invalid URL!")
|
|
}
|
|
}) |