diff --git a/compose.yaml b/compose.yaml
index ea9f61ead4255d47011ad00319d191ef58b9e9cb..f7e5e8758fbfbc9f0e11890d8b498d0dbc1e008f 100755
--- a/compose.yaml
+++ b/compose.yaml
@@ -336,7 +336,7 @@ services:
ND_PORT: "80"
labels:
net.paperclover.list.name: Navidrome Music
- net.paperclover.list.domain: nd
+ net.paperclover.list.domain: music
net.paperclover.list.priority: 109
net.paperclover.list.access: media
depends_on:
@@ -419,7 +419,7 @@ services:
restart: unless-stopped
labels:
net.paperclover.list.name: Sonarr TV PVR
- net.paperclover.list.domain: jkt
+ net.paperclover.list.domain: snr
net.paperclover.list.priority: 51
net.paperclover.list.access: media-manage
radarr: # port 7878
diff --git a/config/Caddyfile b/config/Caddyfile
index 662ac5110146defbdd1ec4d1da5c5a337bfc1f37..1604bdc69ea3bd61f7566de83fd0ea66cb2e6d9e 100644
--- a/config/Caddyfile
+++ b/config/Caddyfile
@@ -44,6 +44,12 @@
auth.{$HOME_DOMAIN} {
handle / {
redir / /realms/master/account
+ }
+ handle /apps {
+ rewrite * /static/apps.html
+ file_server {
+ root /etc/caddy
+ }
}
reverse_proxy "http://keycloak"
}
diff --git a/config/static/apps.html b/config/static/apps.html
new file mode 100644
index 0000000000000000000000000000000000000000..8990e80d3b86b22c3065e1bab900b1420871976c
--- /dev/null
+++ b/config/static/apps.html
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+apps (snow sign on)
+
+
+
+ ❄︎ apps on paperclover.net
+
+
+ for everyone
+ any snow sign on account
+
+
+
+ media
+ members of the media group
+
+
+
+ media management
+ members of the media-manage group
+
+
+
+ personal
+ just clover
+
+
+
+
+
+
diff --git a/generate-app-list.py b/generate-app-list.py
new file mode 100644
index 0000000000000000000000000000000000000000..2275c51c5e9694d5833e6db98435f61ae96a634a
--- /dev/null
+++ b/generate-app-list.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+# generates config/static/apps.html from the net.paperclover.list.* labels
+# in compose.yaml. usage:
+# sh docker.sh compose config --format json | python3 generate-app-list.py > config/static/apps.html
+# (or local: docker compose config --format json | ...)
+import json
+import os
+import sys
+
+PFX = "net.paperclover.list."
+DOMAIN = os.environ.get("HOME_DOMAIN", "paperclover.net")
+
+ACCESS_GROUPS = [
+ (None, "for everyone", "any snow sign on account"),
+ ("media", "media", "members of the media group"),
+ ("media-manage", "media management", "members of the media-manage group"),
+ ("personal", "personal", "just clover"),
+]
+
+cfg = json.load(sys.stdin)
+apps = []
+for name, svc in cfg["services"].items():
+ labels = svc.get("labels") or {}
+ if isinstance(labels, list):
+ labels = dict(l.split("=", 1) for l in labels)
+ if PFX + "name" not in labels:
+ continue
+ apps.append({
+ "name": labels[PFX + "name"],
+ "domain": labels.get(PFX + "domain"),
+ "priority": int(labels.get(PFX + "priority", 0)),
+ "access": labels.get(PFX + "access"),
+ })
+
+apps.sort(key=lambda a: -a["priority"])
+
+def entries(access):
+ out = []
+ for a in apps:
+ if a["access"] != access:
+ continue
+ if a["domain"]:
+ out.append(
+ f' '
+ f'{a["name"].lower()}'
+ f' {a["domain"]}.{DOMAIN}'
+ )
+ else:
+ out.append(f' {a["name"].lower()} (no web ui)')
+ return out
+
+sections = []
+for access, title, who in ACCESS_GROUPS:
+ items = entries(access)
+ if not items:
+ continue
+ sections.append(
+ f' \n {title}
\n'
+ f' {who}
\n \n'
+ + "\n".join(" " + i for i in items)
+ + "\n
\n "
+ )
+
+body = "\n".join(sections)
+
+print(f"""
+
+
+
+
+
+apps (snow sign on)
+
+
+
+ ❄︎ apps on {DOMAIN}
+
+{body}
+
+
+
+""")