const ws = new WebSocket(Deno.args[0]) function key_to_url(key: string): [string, string] { const [kind, id] = key.split(":", 2) if (kind == "youtube-channel") return ["youtube", `https://youtube.com/channel/${id}`] throw new Error("unknown kind"); } async function flat_playlist(url: string, kind: string, output: string) { console.log(output, url); const o = await new Deno.Command("yt-dlp", { args: [ "--flat-playlist", "--print-json", "--match-filter", "availability=public & live_status=not_live", url ], stdout: "piped", stderr: "inherit", }).output() const otext = new TextDecoder().decode(o.stdout) for (const line of otext.split("\n")) { if (!line.length) continue const ob = JSON.parse(line) const key = `${kind}:${ob.id}`; ws.send(JSON.stringify({ t: "metadata", key, data: { title: ob.title, subtitle: `by ${ob.playlist_uploader}; duration ${ob.duration_string}`, description: ob.description, thumbnail: ob.thumbnails[0]?.url, output, } })) ws.send(JSON.stringify({ t: "enqueue", key })) } console.log("done"); } ws.onerror = () => console.error("ws error") ws.onclose = () => console.error("ws closed") ws.onopen = () => { console.log("ws open"); ws.send(JSON.stringify({ t: "register", name: "yt-dlp playlist flattener", task_kinds: ["youtube-channel"] })) 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 == "error") console.error(`error: ${p.message}`); if (p.t == "work") { const [outkind, url] = key_to_url(p.key) if (!p.data.output) throw new Error("no output"); await flat_playlist(url, outkind, p.data.output) ws.send(JSON.stringify({ t: "complete", key: p.key })) ws.send(JSON.stringify({ t: "save" })) ws.send(JSON.stringify({ t: "accept" })) } }