import { NextApiRequest, NextApiResponse } from "next" import { isUrl, shellSanitizeUrl } from "../../lib/utils" import { exec, ExecException } from "child_process" import * as util from "util" const asyncExec = util.promisify(exec) const memoizeExtractFromUrl = () => { let cache: Record = {} return async (url: string) => { if (url in cache) { const cached = cache[url] if (cached.pending) { return true } return cache[url] } if (!isUrl(url)) { console.error("Invalid url provided to source video from:", url) cache[url] = { error: true, stdout: "", stderr: "Invalid url", } return cache[url] } try { cache[url] = await asyncExec("yt-dlp -g " + url) } catch (error) { const e = error as ExecException console.error("Extraction failed", e) cache[url] = { error: true, stdout: "", stderr: e.message, } } return cache[url] } } const extractFromUrl = memoizeExtractFromUrl() const handleResult = async (url: string, res: NextApiResponse) => { const result = await extractFromUrl(url) // already pending? if (result === true) { setTimeout(async () => { await handleResult(url, res) }, 100) return } if (result.error) { console.error(`exec error: ${result.error}`) return res.status(500).send(result.stderr.replace("\n", "")) } res.json({ stdout: result.stdout, stderr: result.stderr.replace("\n", ""), }) } export default async function source( req: NextApiRequest, res: NextApiResponse ) { const url = shellSanitizeUrl(req.body) if (!isUrl(url)) { return res.status(400).send("Invalid url") } console.log("Requested video source of", req.body, "sanitized", url) await handleResult(url, res) }