108 lines
2.8 KiB
JavaScript
108 lines
2.8 KiB
JavaScript
import {join} from "jsr:@std/path";
|
|
var decoder = new TextDecoder("utf8");
|
|
|
|
var infojsoncache = new Map();
|
|
async function getInfoJson(ytid) {
|
|
if (infojsoncache.has(ytid)) return infojsoncache.get(ytid);
|
|
try {
|
|
var text = await Deno.readTextFile(join(process.env.MEDIA_DIR, ytid, "info.json"));
|
|
var json = JSON.parse(text);
|
|
infojsoncache.set(ytid, json);
|
|
setTimeout(() => {
|
|
infojsoncache.delete(ytid);
|
|
}, 600000);
|
|
return json;
|
|
} catch (e) {
|
|
infojsoncache.set(ytid, null);
|
|
setTimeout(() => {
|
|
infojsoncache.delete(ytid);
|
|
}, 5000);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function ytdl_if_not_already(ytid) {
|
|
var info = await getInfoJson(ytid);
|
|
if (info) return info;
|
|
return await run_ytdlp_deduplicated(ytid);
|
|
}
|
|
|
|
var running_ytdl = new Map();
|
|
export async function run_ytdlp_deduplicated(ytid) {
|
|
var run = running_ytdl.get(ytid);
|
|
if (!run) {
|
|
run = run_ytdlp(ytid);
|
|
run.finally(() => {
|
|
running_ytdl.delete(ytid);
|
|
}).catch(()=>{});
|
|
running_ytdl.set(ytid, run);
|
|
}
|
|
return await run;
|
|
}
|
|
|
|
export async function run_ytdlp(ytid) {
|
|
var cwd = await Deno.makeTempDir();
|
|
console.debug("tmpdir", cwd);
|
|
|
|
var command = new Deno.Command("yt-dlp", {
|
|
args: [
|
|
"-f", "bestvideo*[vcodec!^=av01]+bestaudio/best",
|
|
"--no-mtime", "--no-playlist", "-J", "--no-simulate", ytid,
|
|
],
|
|
cwd,
|
|
stdout: "piped",
|
|
stderr: "piped",
|
|
stdin: "null"
|
|
});
|
|
|
|
var result = {ts: new Date()};
|
|
var output = await command.output();
|
|
if (!output.success) {
|
|
result.error = decoder.decode(output.stderr).trim();
|
|
}
|
|
|
|
else {
|
|
var stdout_text = decoder.decode(output.stdout).trim();
|
|
var jsons = stdout_text.split("\n");
|
|
if (jsons.length > 1) console.warn("more than one jsons outputted");
|
|
var json = JSON.parse(jsons[0]);
|
|
await Deno.writeTextFile(join(cwd, "more.json"), JSON.stringify(json));
|
|
|
|
result.title = json.title;
|
|
result.description = json.description;
|
|
result.thumbnail = json.thumbnail;
|
|
result.channel = json.channel;
|
|
result.duration = json.duration;
|
|
result.duration_string = json.duration_string;
|
|
result.view_count = json.view_count;
|
|
result.upload_date = json.upload_date;
|
|
result.filename = json.requested_downloads[0].filename;
|
|
|
|
if (!result.filename) {
|
|
var files = await Array.fromAsync(Deno.readDir(cwd));
|
|
files = files.map(file => file.name);
|
|
result.filename = files.find(name => /\.(?:webm|mp4|mkv)$/i.test(name));
|
|
}
|
|
|
|
let stat = await Deno.stat(join(cwd, result.filename));
|
|
result.size = stat.size;
|
|
}
|
|
|
|
await Deno.writeTextFile(join(cwd, "info.json"), JSON.stringify(result));
|
|
|
|
var newpath = join(process.env.MEDIA_DIR, ytid);
|
|
try {
|
|
await Deno.rename(cwd, newpath);
|
|
} catch (error) {
|
|
if (error.code === "ENOTEMPTY") {
|
|
await Deno.remove(newpath, {recursive: true});
|
|
await Deno.rename(cwd, newpath);
|
|
}
|
|
else {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|