const ytdl = require('ytdl-core'), fs = require('fs'), path = require('path'), express = require('express'), ffmpeg = require('ffmpeg'), bodyParser = require('body-parser') const PORT = process.env.PORT || 8080 const app = express() if (fs.existsSync(path.join(__dirname, 'cached'))) { fs.rmSync(path.join(__dirname, 'cached'), { recursive: true, force: true }) } function formatBytes(bytes, decimals = 2) { if (!+bytes) return '0 Bytes' const k = 1024 const dm = decimals < 0 ? 0 : decimals const sizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'] const i = Math.floor(Math.log(bytes) / Math.log(k)) return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}` } fs.mkdirSync(path.join(__dirname, 'cached')) const cacheDuration = 30 || process.env.CACHEDUR process.on('uncaughtException', (err, origin) => { fs.writeSync( process.stderr.fd, `Caught exception: ${err}\n` + `Exception origin: ${origin}`, ); }); app.use(bodyParser.urlencoded({ extended: false })) app.get("/getLink", async (req, res) => { const url = req.query.url const format = req.query.format const quality = req.query.quality const redir = req.query.redirect 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 filename = vidinfo.videoDetails.title if (["mp4", "webm"].includes(format)) { var ytvid = ytdl(url, { 'quality': quality, 'format': format }) var debounce = false ytvid.on("progress", (chunk, cd, td) => { if (!debounce) { res.setHeader('Content-Disposition', `attachment; filename="${filename}.${format}";`); res.setHeader("Content-Length", td) ytvid.pipe(res) // console.log(td) debounce = true } }) } else { if (redir != "redirect") { res.setHeader("Content-Type", "text/html"); res.write(``) res.write(` `) } // String(Math.floor(Math.random() * 100000)) + var ytpath = path.join(__dirname, 'cached/' + ytdl.getVideoID(url) + '.mp4') if (redir != "redirect") { res.write(`

Starting download...

`) } var lastp = 0 var ytvid = ytdl(url, { 'quality': quality, 'format': 'mp4' }) if (redir != "redirect") { ytvid.on("progress", (data, ctotal, etotal) => { var integer = 1 var percent = (Math.ceil(ctotal / etotal * 100)) if (percent % integer == 0 && lastp != percent) { res.write(`

Downloading... ${percent}% (${formatBytes(ctotal)})

`) res.write(` `) lastp = percent } }) } ytvid.pipe(fs.createWriteStream(ytpath)) .on("close", () => { if (redir != "redirect") { res.write("

Downloaded!

") } var proc = new ffmpeg(ytpath) // res.write(`

Converting... (May take a while, doesn't support progress updates yet)

`) var endpath = ('cached/' + ytdl.getVideoID(url) + String(Math.floor(Math.random() * 10000000)) + "Converted." + format) if (redir != "redirect") { res.write(`

Starting Video Conversion... Conversion may be slow depending on instance.

`) } proc.then(function (video) { video .setVideoDuration(vidinfo.videoDetails.lengthSeconds) .setVideoFormat(format) .save(endpath, (error, file) => { if (redir != "redirect") { res.write(`

Converted! (Why doesn't conversion support %s?)

`) res.write(` `) res.write(`

Link to video download! (Link is deleted after ${cacheDuration} minutes!)

`) if (redir == "redirectjs") { res.write(` `) } } else { res.redirect(`/download?path=${path.basename(file)}&filename=${filename}.${format}`) } setTimeout(() => { if (fs.existsSync(ytpath)) { fs.unlinkSync(ytpath) } if (fs.existsSync(file)) { fs.unlinkSync(file) } }, 60 * 1000) }) }) var count = 0 async function update() { if (fs.existsSync(endpath)) { var ffile = await fs.readFileSync(endpath) var yt = await fs.readFileSync(ytpath) res.write(`

Converting... (${formatBytes(ffile.length)})

`) res.write(` `) count += 1 // } } if ( redir != "redirect") { setTimeout(() => { update() }, 2000); } } update() }) } }); app.get('/download', (req, res) => { var file = req.query.path var filename = req.query.filename var dest = path.join(__dirname, 'cached/', file) if (fs.existsSync(dest)) { res.setHeader('Content-Disposition', `attachment; filename="${filename}"`); res.setHeader('Content-Length', fs.readFileSync(dest).length) fs.createReadStream(dest).pipe(res) } else { res.header("Content-Type", "text/html") res.write(``) res.write(`

Uh oh! It seems that video couldn't be found... Maybe the URL expired? Or, the link was invalid.
If you believe this was a mistake, please put a issue on Github

`, () => { res.end() }) } }) app.use(express.static(path.join(__dirname, 'static'))) app.listen(PORT, function () { console.log("Hosted on port " + PORT) })