| 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<string, any> = {} |
| 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) |
| |
| 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) |
| } |
|
|