diff options
-rw-r--r-- | scripts/ytdlp_channel_info.ts | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/scripts/ytdlp_channel_info.ts b/scripts/ytdlp_channel_info.ts new file mode 100644 index 0000000..c02182c --- /dev/null +++ b/scripts/ytdlp_channel_info.ts @@ -0,0 +1,71 @@ +import { Config } from "./config.ts"; + +const ws = new WebSocket(Deno.args[0]) +// deno-lint-ignore no-unused-vars +let config: Config = {} as unknown as Config + +function key_to_url(key: string): string { + const [kind, id] = key.split(":", 2) + if (kind == "youtube-channel") return `https://youtube.com/channel/${id}` + throw new Error("unknown kind"); +} + +async function dfile(path: string, url: string) { + console.log(`thumbnail download ${path} from ${url}`); + const r = await fetch(url) + if (!r.body) return console.error("thumbnail download failed"); + await Deno.writeFile(path, r.body) +} + +async function save_infojson(url: string, key: string, data: { [key: string]: unknown }) { + if (!data.output) throw new Error("output dir missing"); + const output = data.output + const infojson = `${output}/channel.info.json`; + const o = await new Deno.Command("yt-dlp", { + args: [ + "--skip-download", + "--write-info-json", + "-o", `${output}/channel`, + "--playlist-items", "0", + url + ], + stdout: "piped", + stderr: "inherit", + }).output() + if (!o.success) throw new Error("info json download failed"); + + ws.send(JSON.stringify({ t: "metadata", key, data: { progress: 0.5 } })) + + const oj = JSON.parse(await Deno.readTextFile(infojson)) + const avatar = oj.thumbnails?.find((t: { id: string }) => t.id == "avatar_uncropped") ?? oj?.thumbnails?.[oj.thumbnails?.length - 1] + const banner = oj.thumbnails?.find((t: { id: string }) => t.id == "banner_uncropped") + if (avatar) await dfile(`${output}/poster.jpeg`, avatar.url) + ws.send(JSON.stringify({ t: "metadata", key, data: { progress: 0.75 } })) + if (banner) await dfile(`${output}/backdrop.jpeg`, banner.url) + ws.send(JSON.stringify({ t: "metadata", key, data: { progress: 1 } })) +} + +ws.onerror = () => console.error("ws error") +ws.onclose = () => { + console.error("ws closed") + Deno.exit(1) +} +ws.onopen = () => { + console.log("ws open"); + ws.send(JSON.stringify({ t: "register", name: "yt-dlp channel info generator", task_kinds: ["youtube-channel-info"] })) + ws.send(JSON.stringify({ t: "accept" })) +} +ws.onmessage = async ev => { + if (typeof ev.data != "string") return + const p = JSON.parse(ev.data) + if (p.t == "config") config = p.config + if (p.t == "error") console.error(`error: ${p.message}`); + if (p.t == "work") { + const url = key_to_url(p.key) + if (!p.data.output) throw new Error("no output"); + await save_infojson(url, p.key, p.data) + ws.send(JSON.stringify({ t: "complete", key: p.key })) + ws.send(JSON.stringify({ t: "save" })) + ws.send(JSON.stringify({ t: "accept" })) + } +} |