aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/config.ts20
-rw-r--r--scripts/enqueue.ts57
-rw-r--r--scripts/ytdlp_download.ts33
-rw-r--r--scripts/ytdlp_flatten.ts24
4 files changed, 93 insertions, 41 deletions
diff --git a/scripts/config.ts b/scripts/config.ts
new file mode 100644
index 0000000..1068c92
--- /dev/null
+++ b/scripts/config.ts
@@ -0,0 +1,20 @@
+
+export interface Config {
+ enqueue: EnqueueTask[]
+ ytdlp_flatten: {
+ filters: { [key: string]: string }
+ }
+ ytdlp_download: {
+ output: string,
+ profiles: { [key: string]: string[] }
+ }
+}
+
+export interface EnqueueTask {
+ list_file: string
+ kind: string,
+ interval: number,
+ filter?: string,
+ oneshot?: boolean,
+ data: { [key: string]: unknown }
+}
diff --git a/scripts/enqueue.ts b/scripts/enqueue.ts
index 8d19e53..5dfb6b7 100644
--- a/scripts/enqueue.ts
+++ b/scripts/enqueue.ts
@@ -1,38 +1,59 @@
+import { Config, EnqueueTask } from "./config.ts";
const ws = new WebSocket(Deno.args[0])
-const file = await Deno.readTextFile(Deno.args[1])
-const outdir = Deno.args.length >= 3 ? Deno.args[2] : "."
-const note_filter = Deno.args.length >= 4 ? Deno.args[3] : ""
-const requeue = Deno.env.has("REQUEUE")
+let config: Config = {} as unknown as Config
-function run_enqueue() {
- let kind = "http"
+async function run_enqueue(eqt: EnqueueTask) {
+ const file = await Deno.readTextFile(eqt.list_file)
for (const line of file.split("\n")) {
if (!line.trim().length) continue
- else if (line.startsWith("[") && line.endsWith("]"))
- kind = line.substring(1, line.length - 1)
- else {
- const [name, rest] = line.split("=", 2)
- const [id, note] = rest.split(";", 2)
- if (note_filter.length && note != note_filter) continue
- const key = `${kind}:${id}`;
- ws.send(JSON.stringify({ t: "metadata", key, data: { output: outdir + "/" + name, title: name } }))
- ws.send(JSON.stringify({ t: "enqueue", key, ignore_complete: requeue }))
- }
+ let [name, rest] = line.split("=", 2)
+ let [id, flags_raw] = rest.split(";", 2)
+ let flags = flags_raw.split(" ")
+
+ if (eqt.filter && !flags.includes(eqt.filter)) continue
+ name = name.trim()
+ id = id.trim()
+ flags = flags.filter(e => e.length && e != eqt.filter)
+
+ const key = `${eqt.kind}:${id}`;
+ ws.send(JSON.stringify({
+ t: "metadata", key, data: {
+ ...eqt.data,
+ output: (eqt.data.output ?? ".") + "/" + name,
+ title: name,
+ flags,
+ }
+ }))
+ ws.send(JSON.stringify({ t: "enqueue", key, ignore_complete: !(eqt.oneshot ?? false) }))
}
ws.send(JSON.stringify({ t: "save" }))
console.log("done");
+ setTimeout(() => run_enqueue(eqt), eqt.interval * 1000)
+}
+
+let started = false;
+function start() {
+ started = true
+ for (const t of config.enqueue)
+ run_enqueue(t)
}
ws.onerror = () => console.error("ws error")
-ws.onclose = () => console.error("ws closed")
+ws.onclose = () => {
+ console.error("ws closed")
+ Deno.exit(1)
+}
ws.onopen = () => {
console.log("ws open");
ws.send(JSON.stringify({ t: "register", name: "enqueuer", task_kinds: [] }))
- run_enqueue()
}
ws.onmessage = ev => {
if (typeof ev.data != "string") return
const p = JSON.parse(ev.data)
+ if (p.t == "config") {
+ config = p.config
+ if (!started) start()
+ }
if (p.t == "error") console.error(`error: ${p.message}`);
}
diff --git a/scripts/ytdlp_download.ts b/scripts/ytdlp_download.ts
index f82e3b8..760ac26 100644
--- a/scripts/ytdlp_download.ts
+++ b/scripts/ytdlp_download.ts
@@ -1,5 +1,7 @@
+import { Config } from "./config.ts";
const ws = new WebSocket(Deno.args[0])
+let config: Config = {} as unknown as Config
export class TextLineStream extends TransformStream<string, string> {
line = "";
@@ -28,8 +30,15 @@ function key_to_url(key: string): string {
throw new Error("unknown kind");
}
-async function do_download(key: string, output: string) {
+async function do_download(key: string, data: { [key: string]: string }) {
const url = key_to_url(key)
+
+ if (!data.output) throw new Error("no output");
+ const output = data.output as string;
+ if (!data.profile) throw new Error("no profile");
+ const args = config.ytdlp_download.profiles[data.profile as string]
+ if (!args) throw new Error(`unknown profile ${data.profile}`);
+
await Deno.mkdir(output, { recursive: true })
const child = new Deno.Command("yt-dlp", {
args: [
@@ -37,16 +46,7 @@ async function do_download(key: string, output: string) {
"--progress",
"--progress-template", "%(progress)j",
"--newline",
- "--download-archive", "archive",
- "-f", "bestvideo+bestaudio",
- "--embed-metadata",
- "--embed-thumbnail",
- "--embed-info-json",
- "--embed-subs",
- "--embed-chapters",
- "--ignore-no-formats",
- "--remux", "mkv",
- "-o", "%(id)s",
+ ...args,
url
],
stdout: "piped",
@@ -68,12 +68,15 @@ async function do_download(key: string, output: string) {
}
const status = await child.status
if (!status.success) throw new Error("download failed");
-
+ ws.send(JSON.stringify({ t: "metadata", key, data: { progress: null, status: null } }))
ws.send(JSON.stringify({ t: "complete", key }))
}
ws.onerror = () => console.error("ws error")
-ws.onclose = () => console.error("ws closed")
+ws.onclose = () => {
+ console.error("ws closed")
+ Deno.exit(1)
+}
ws.onopen = () => {
console.log("ws open");
ws.send(JSON.stringify({ t: "register", name: "yt-dlp video downloader", task_kinds: ["youtube"] }))
@@ -82,10 +85,10 @@ ws.onopen = () => {
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") {
- if (!p.data.output) throw new Error("no output");
- await do_download(p.key, p.data.output)
+ await do_download(p.key, p.data)
ws.send(JSON.stringify({ t: "accept" }))
}
}
diff --git a/scripts/ytdlp_flatten.ts b/scripts/ytdlp_flatten.ts
index 84bbc8f..6d246da 100644
--- a/scripts/ytdlp_flatten.ts
+++ b/scripts/ytdlp_flatten.ts
@@ -1,6 +1,7 @@
+import { Config } from "./config.ts";
const ws = new WebSocket(Deno.args[0])
-
+let config: Config = {} as unknown as Config
function key_to_url(key: string): [string, string] {
const [kind, id] = key.split(":", 2)
@@ -8,13 +9,16 @@ function key_to_url(key: string): [string, string] {
throw new Error("unknown kind");
}
-async function flat_playlist(url: string, kind: string, output: string) {
- console.log(output, url);
+async function flat_playlist(url: string, kind: string, data: { [key: string]: unknown }) {
+ const flags = (data.flags as string[]) ?? []
+ if (!(flags instanceof Array)) throw new Error("flags is not an array");
+ const filter_parts = flags.map(e => config.ytdlp_flatten.filters[e]).join(" & ")
+ const filter_args = flags.length ? ["--match-filter", filter_parts] : []
const o = await new Deno.Command("yt-dlp", {
args: [
"--flat-playlist",
"--print-json",
- "--match-filter", "availability=public & live_status=not_live",
+ ...filter_args,
url
],
stdout: "piped",
@@ -29,11 +33,11 @@ async function flat_playlist(url: string, kind: string, output: string) {
t: "metadata",
key,
data: {
+ ...data,
title: ob.title,
subtitle: `by ${ob.playlist_uploader}; duration ${ob.duration_string}`,
- description: ob.description,
thumbnail: ob.thumbnails[0]?.url,
- output,
+ // description: ob.description,
}
}))
ws.send(JSON.stringify({ t: "enqueue", key }))
@@ -42,7 +46,10 @@ async function flat_playlist(url: string, kind: string, output: string) {
}
ws.onerror = () => console.error("ws error")
-ws.onclose = () => console.error("ws closed")
+ws.onclose = () => {
+ console.error("ws closed")
+ Deno.exit(1)
+}
ws.onopen = () => {
console.log("ws open");
ws.send(JSON.stringify({ t: "register", name: "yt-dlp playlist flattener", task_kinds: ["youtube-channel"] }))
@@ -51,11 +58,12 @@ ws.onopen = () => {
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 [outkind, url] = key_to_url(p.key)
if (!p.data.output) throw new Error("no output");
- await flat_playlist(url, outkind, p.data.output)
+ await flat_playlist(url, outkind, p.data)
ws.send(JSON.stringify({ t: "complete", key: p.key }))
ws.send(JSON.stringify({ t: "save" }))
ws.send(JSON.stringify({ t: "accept" }))