const ytdl = require('ytdl-core'),
fs = require('fs'),
path = require('path'),
express = require('express'),
bodyParser = require('body-parser'),
cp = require("child_process"),
ffmpeg = require('ffmpeg-static'),
multer = require('multer')
const PORT = process.env.PORT || 8080
const app = express()
var formats = {
"matroska": "mkv"
}
if (fs.existsSync(path.join(__dirname, 'uploads'))) {
fs.rmSync(path.join(__dirname, 'uploads'), { recursive: true })
}
var uploads = multer({ dest: 'uploads/' })
const characters = "abcdefghijklmnopqrstuvwxyz!@$%^*()[]_-=+ "
process.on('uncaughtException', (err, origin) => {
fs.writeSync(
process.stderr.fd,
`Caught exception: ${err}\n` +
`Exception origin: ${origin}`,
);
});
app.use(bodyParser.urlencoded({ extended: false }))
app.post("/convert", uploads.single("files"), (req, res) => {
var file = req.file
var format = req.body.format || 'mp4'
const ffmpegProcess = cp.spawn(ffmpeg, [
'-i', file.path,
'-f', format,
'-loglevel', 'error',
'-movflags', 'frag_keyframe+empty_moov',
'-vcodec', 'copy' ,
'-acodec', 'copy',
'-'
], {
stdio: [
'pipe', 'pipe', 'pipe', 'pipe', 'pipe',
],
})
res.setHeader('Content-Disposition', `attachment; filename="${file.originalname.substring(0, file.originalname.lastIndexOf('.'))}.${formats[format] || format}"`);
ffmpegProcess.stdio[1].pipe(res)
.on("close", () => {
fs.rmSync(file.path)
})
})
app.get("/download", async (req, res) => {
const url = req.query.url
const format = req.query.format || 'mp4'
const quality = req.query.quality || 'highest'
const defin = req.query.definition || 'hd'
const preset = 'medium'
res.setHeader("X-Accel-Buffering", "no")
if (!ytdl.validateURL(url)) {
res.header("Content-Type", "text/html")
res.write(``)
res.write(`
Invalid URL! Check the url for any errors!
URL: ${url}
`)
return
}
var vidinfo = await ytdl.getBasicInfo(url)
const ogname = vidinfo.videoDetails.title
var filename = ""
for (let index = 0; index < ogname.length; index++) {
const letter = ogname[index];
if ((characters + characters.toUpperCase()).includes(letter)) {
filename += letter
}
}
if ("mp3 ogg wav".includes(format)) {
var audio = ytdl(url, { filter: 'audioonly', quality: quality })
const ffmpegProcess = cp.spawn(ffmpeg, [
'-i', `pipe:3`,
'-preset', preset,
'-f', format,
'-loglevel', 'error',
'-'
], {
stdio: [
'pipe', 'pipe', 'pipe', 'pipe', 'pipe',
],
})
audio.pipe(ffmpegProcess.stdio[3])
res.setHeader('Content-Disposition', `attachment; filename="${filename}.${formats[format] || format}"`);
ffmpegProcess.stdio[1].pipe(res)
} else if (defin == "hd") {
var video = ytdl(url, { filter: 'videoonly', quality: quality })
var audio = ytdl(url, { filter: 'audioonly', highWaterMark: 1 << 25 })
const ffmpegProcess = cp.spawn(ffmpeg, [
'-i', `pipe:3`,
'-i', `pipe:4`,
'-map', '0:v',
'-map', '1:a',
'-c:v', 'copy',
'-c:a', 'libmp3lame',
'-crf', '27',
'-preset', preset,
'-movflags', 'frag_keyframe+empty_moov',
'-f', format,
'-loglevel', 'error',
'-'
], {
stdio: [
'pipe', 'pipe', 'pipe', 'pipe', 'pipe',
],
})
video.pipe(ffmpegProcess.stdio[3])
audio.pipe(ffmpegProcess.stdio[4])
res.setHeader('Content-Disposition', `attachment; filename="${filename}.${formats[format] || format}"`);
ffmpegProcess.stdio[1].pipe(res)
} else {
var video = ytdl(url, { filter: 'videoandaudio', quality: quality })
const ffmpegProcess = cp.spawn(ffmpeg, [
'-i', `pipe:3`,
'-preset', preset,
'-f', format,
'-loglevel', 'error',
'-'
], {
stdio: [
'pipe', 'pipe', 'pipe', 'pipe', 'pipe',
],
})
video.pipe(ffmpegProcess.stdio[3])
res.setHeader('Content-Disposition', `attachment; filename="${filename}.${formats[format] || format}"`);
// res.setHeader('Content-Length', fs.readFileSync(dest).length)
ffmpegProcess.stdio[1].pipe(res)
}
})
app.use(express.static(path.join(__dirname, 'static')))
app.listen(PORT, function () {
console.log("Hosted on port " + PORT)
})