about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRobert Günzler <r@gnzler.io>2025-09-07 17:32:13 +0200
committerRobert Günzler <r@gnzler.io>2025-09-25 12:56:47 +0200
commit8db9d0cc31582750026c66fa02236c494c2a8e2c (patch)
treec8c89acfed7ad9a0016936e700b69f67db6b269f
parent0bb17cd2f34918add1ddaedeb0a66531dea561a3 (diff)
add bitfroest bundle
Signed-off-by: Robert Günzler <r@gnzler.io>
-rwxr-xr-xbundles/bitfroest/files/bitfroest63
-rw-r--r--bundles/bitfroest/files/cron_job4
-rwxr-xr-xbundles/bitfroest/files/qbapi45
-rw-r--r--bundles/bitfroest/items.py26
-rw-r--r--bundles/bitfroest/metadata.py6
-rw-r--r--nodes.py1
6 files changed, 145 insertions, 0 deletions
diff --git a/bundles/bitfroest/files/bitfroest b/bundles/bitfroest/files/bitfroest
new file mode 100755
index 0000000..ac3c010
--- /dev/null
+++ b/bundles/bitfroest/files/bitfroest
@@ -0,0 +1,63 @@
+#!/bin/sh
+set -eu
+
+remote_host=kum4@porphyrion.feralhosting.com
+ssh_args='-i /home/robert/.ssh/kum4'
+inbox_dir=/media/hayasui/media/.inbox
+textfiles_dir=/run/prom
+
+do_transfer() {
+	local remote_path=$1
+
+	rsync --archive --protect-args \
+		--verbose \
+		-hhh --info=flist2,name,progress \
+		--partial \
+		--rsh="ssh $ssh_args -o Compression=no" \
+		"$remote_host:$remote_path" \
+		"$inbox_dir"/
+
+	chown -R nobody:wheel "$inbox_dir/$name"
+	chmod g+w "$inbox_dir/$name"
+}
+
+do_fetch() {
+	local name remote_path
+	qbapi getnew | while read -r name remote_path; do
+		do_transfer "$remote_path"
+		qbapi markx "$name"
+		do_notify "$name"
+	done
+}
+
+do_notify() {
+	local name=$1
+
+	tgnotify "📼**shimakaze/bitfröst**\nDownloaded $name"
+}
+
+do_metrics() {
+	mkdir -p "$textfiles_dir"
+
+	tmp=$(mktemp --tmpdir bitfroest-XXXXX.prom)
+	chmod +r "$tmp"
+	chown nobody:nobody "$tmp"
+
+	(
+		printf '# HELP bitfroest_transferred_bytes_total Total size of transfers in bytes.\n'
+		printf '# TYPE bitfroest_transferred_bytes_total counter\n'
+		printf 'bitfroest_transferred_bytes_total %d\n' "$(du -s "$inbox_dir" | cut -f1)"
+		printf '# HELP bitfroest_transferred_files_total Total number of files transferred.\n'
+		printf '# TYPE bitfroest_transferred_files_total counter\n'
+		printf 'bitfroest_transferred_files_total %d\n' "$(find "$inbox_dir" -type f -print | wc -l)"
+	) | tee "$tmp"
+
+	mv -vf "$tmp" "$textfiles_dir"/bitfroest.prom
+}
+
+main() {
+	do_fetch
+	do_metrics
+}
+
+main "$@"
diff --git a/bundles/bitfroest/files/cron_job b/bundles/bitfroest/files/cron_job
new file mode 100644
index 0000000..2f5c94e
--- /dev/null
+++ b/bundles/bitfroest/files/cron_job
@@ -0,0 +1,4 @@
+#!/bin/sh
+set -eu
+/usr/bin/bitfroest >/dev/null 2>&1
+exit 0
diff --git a/bundles/bitfroest/files/qbapi b/bundles/bitfroest/files/qbapi
new file mode 100755
index 0000000..89d328e
--- /dev/null
+++ b/bundles/bitfroest/files/qbapi
@@ -0,0 +1,45 @@
+#!/bin/sh
+set -eu
+
+qb_host=https://porphyrion.feralhosting.com/kum4/qbittorrent
+qb_user=kum4
+qb_pass=${repo.vault.cmd("rbw get 6e66abae-094c-4c98-83ad-9b7bae3eb1b2")}
+qb_cookiejar=/dev/shm/qb.cookies
+
+do_login() {
+	curl -sS -o /dev/null \
+		-H "Referer: $qb_host" \
+		-d "username=$qb_user&password=$qb_pass" \
+		-c "$qb_cookiejar" \
+		"$qb_host/api/v2/auth/login"
+}
+
+do_getnew() {
+	curl -sS -b "$qb_cookiejar" \
+		"$qb_host/api/v2/torrents/info?filter=completed&sort=added_on&tag=" |
+		jq -rc '.[]|[.name,.content_path]|@tsv'
+}
+
+do_markx() {
+	local name=$1
+	local hash
+
+	hash=$(curl -sS -b "$qb_cookiejar" \
+		"$qb_host/api/v2/torrents/info?filter=completed&sort=added_on&tag=" |
+		jq -rc --arg filter "$name" '.[]|select(.name==$filter)|.hash')
+
+	curl -sS -b "$qb_cookiejar" \
+		-d "hashes=$hash&tags=x" \
+		"$qb_host/api/v2/torrents/addTags"
+}
+
+main() {
+	test -f "$qb_cookiejar" || do_login
+
+	case "$1" in
+	getnew) do_getnew ;;
+	markx) do_markx "$2" ;;
+	esac
+}
+
+main "$@"
diff --git a/bundles/bitfroest/items.py b/bundles/bitfroest/items.py
new file mode 100644
index 0000000..db880a9
--- /dev/null
+++ b/bundles/bitfroest/items.py
@@ -0,0 +1,26 @@
+if node.os != "alpine":
+    raise BundleError(f"{node.name}: OS {node.os} is not supported.")
+
+
+files = {
+    "/usr/bin/qbapi": {
+        "source": "qbapi",
+        "content_type": "mako",
+        "mode": "0755",
+    },
+    "/usr/bin/bitfroest": {
+        "source": "bitfroest",
+        "mode": "0755",
+        "needs": {
+            "file:/usr/bin/qbapi",
+            "bundle:tgnotify",
+        },
+    },
+    "/etc/periodic/daily/bitfroest": {
+        "source": "cron_job",
+        "mode": "0755",
+        "needs": {
+            "file:/usr/bin/bitfroest",
+        },
+    },
+}
diff --git a/bundles/bitfroest/metadata.py b/bundles/bitfroest/metadata.py
new file mode 100644
index 0000000..9b16788
--- /dev/null
+++ b/bundles/bitfroest/metadata.py
@@ -0,0 +1,6 @@
+defaults = {
+    "apk": {
+        "packages": {
+        },
+    },
+}
diff --git a/nodes.py b/nodes.py
index f85e3c2..2e71ac4 100644
--- a/nodes.py
+++ b/nodes.py
@@ -79,6 +79,7 @@ nodes = {
             "jellyfin",
             "immich",
             "nfs",
+            "bitfroest",
         },
     },