Compare commits

..

No commits in common. "e32e4f586f6cddcbe8759924c445e65e35d69a6a" and "b54e137b2ead0e9ab9ba3b05df2bf6c78fe013d2" have entirely different histories.

16 changed files with 227 additions and 658 deletions

View File

@ -1,13 +1,11 @@
{ {
email neale@woozle.org email neale@woozle.org
#debug
} }
(restricted-access) { (restricted-access) {
forward_auth simpleauth:8080 { forward_auth simpleauth:8080 {
uri / uri /
copy_headers X-Simpleauth-Username copy_headers X-Simpleauth-Token
header_down X-Simpleauth-Domain "woozle.org"
} }
} }
@ -17,11 +15,19 @@ git.woozle.org {
drive.woozle.org { drive.woozle.org {
import restricted-access import restricted-access
reverse_proxy webfs:5000
}
media.woozle.org { # XXX: browsing says method not allowed
reverse_proxy jellyfin:8096 @nondav {
method HEAD GET
}
# route overrides built-in ordering
route {
file_server @nondav {
root /srv/
browse /browser.html
}
reverse_proxy webdav:8000
}
} }
# XXX: have this use caddy auth # XXX: have this use caddy auth
@ -29,69 +35,89 @@ ancestry.woozle.org {
reverse_proxy geneweb:2317 reverse_proxy geneweb:2317
} }
photos.woozle.org {
import restricted-access
reverse_proxy pigallery2:80
}
## ##
## handle sends original path ## handle sends original path
## handle_path truncates path ## handle_path truncates path
## ##
deergrove.woozle.org { (deergrove) {
import restricted-access
handle_path /ddns/* { handle_path /ddns/* {
import restricted-access
reverse_proxy ddns:8000 reverse_proxy ddns:8000
} }
handle /transmission/* { handle /transmission/* {
reverse_proxy transmission:9091 import restricted-access
reverse_proxy host.docker.internal:9091
} }
handle /nzbget/* { handle /nzbget/* {
import restricted-access
reverse_proxy nzbget:6789 reverse_proxy nzbget:6789
} }
handle /sonarr/* { handle /sonarr/* {
import restricted-access
reverse_proxy sonarr:8989 reverse_proxy sonarr:8989
} }
handle /radarr/* { handle /radarr/* {
import restricted-access
reverse_proxy radarr:7878 reverse_proxy radarr:7878
} }
handle /readarr/* { handle /readarr/* {
import restricted-access
reverse_proxy readarr:8787 reverse_proxy readarr:8787
} }
handle /lidarr/* { handle /lidarr/* {
import restricted-access
reverse_proxy lidarr:8686 reverse_proxy lidarr:8686
} }
handle /prowlarr/* { handle /prowlarr/* {
import restricted-access
reverse_proxy prowlarr:9696 reverse_proxy prowlarr:9696
} }
handle /unmanic/* {
reverse_proxy unmanic:8888
}
handle_path /sucker/* { handle_path /sucker/* {
reverse_proxy host.lan:5801 import restricted-access
reverse_proxy host.docker.internal:5880
} }
handle_path /netdata/* {
reverse_proxy netdata:19999
}
# Octoprint serves up broken webcam URLs
uri replace /webcam/ /octoprint/webcam/
handle_path /octoprint/* { handle_path /octoprint/* {
import restricted-access
reverse_proxy { reverse_proxy {
to 192.168.86.20:80 to 192.168.86.20:80
header_up X-Script-Name "/octoprint" header_up X-Script-Name "/octoprint"
} }
} }
handle /webcam/* {
# Octoprint doesn't properly prefix webcam URLs
import restricted-access
reverse_proxy {
to 192.168.86.20:80
}
}
handle_path /public/* {
file_server {
root /srv/storage/public
}
}
handle { handle {
reverse_proxy portal:8080 import restricted-access
file_server {
root /www
}
} }
} }
deergrove.woozle.org {
import deergrove
}
sweetums.lan {
tls internal
import deergrove
}

View File

@ -1,7 +1,7 @@
. { . {
bind 192.168.86.2 bind lan
hosts { hosts {
192.168.86.2 sweetums.woozle.org deergrove.woozle.org drive.woozle.org git.woozle.org ancestry.woozle.org media.woozle.org photos.woozle.org auth.woozle.org 192.168.86.2 sweetums.woozle.org deergrove.woozle.org drive.woozle.org git.woozle.org ancestry.woozle.org
fallthrough fallthrough
} }
forward . 8.8.8.8 forward . 8.8.8.8

View File

@ -4,16 +4,14 @@ This is the stuff I run on my little Raspberry Pi.
I guess I fiddle around with it pretty frequently. I guess I fiddle around with it pretty frequently.
## Portal ## Routing
In the [www](www) directory is a static HTML/JavaScript portal thing I wrote. My ISP uses Carrier-Grade NAT,
It doesn't need any server configuration, which I would have called IP Masquerading.
you just edit the HTML to manage what apps it serves.
Other things like this exist, This means I can't bind ports on a routeable IP.
but they all require ridiculous things like relational databases or weird config files. So instead what I do is run this SSH connection off to my cloud server,
listens for incoming connections on port 5800,
and then have my cloud server proxy stuff to port 5800.
I should probably package this up or something, It's a gross kludge but it works well :)
but then I'd have to put effort into publicizing it,
and run a ticketing system or something,
so meh.

View File

@ -1,9 +0,0 @@
* Single Sign-On
* [x] Replace simpleauth with somebody else's project
* [x] Set up Forgejo OIDC to Authelia (there's a guide on Authelia's site)
* [x] Persist "remember me" across reboots
* LDAP restrictions
* [x] People can only r/w their own storage
* [x] Public storage
* [x] Per-Group storage
* [x] Media-Sucker secure setup (bind to 0.0.0.0 opens to internet)

View File

@ -1,12 +1,10 @@
#! /bin/sh #! /bin/sh
caddy_hash () {
echo -n "$1 "
echo "$2" | docker run --rm -i caddy caddy hash-password
}
stack=$(basename $(pwd)) stack=$(basename $(pwd))
extra="--resolve-image changed" docker --context deergrove stack deploy -c docker-compose.yaml --prune $stack
if [ "$1" = "--slow" ]; then
extra=
shift
fi
docker --context deergrove stack deploy -c docker-compose.yaml --prune $extra "$@" $stack
#docker --context deergrove compose up --detach

View File

@ -28,44 +28,28 @@ services:
configs: configs:
- source: Caddyfile - source: Caddyfile
target: /etc/caddy/Caddyfile target: /etc/caddy/Caddyfile
- source: index.html
target: /www/index.html
- source: index.mjs
target: /www/index.mjs
- source: index.css
target: /www/index.css
- source: browser.html
target: /browser.html
extra_hosts: extra_hosts:
- host.docker.internal:host-gateway - host.docker.internal:host-gateway
- host.lan:192.168.86.2
simpleauth: simpleauth:
image: git.woozle.org/neale/simpleauth image: git.woozle.org/neale/simpleauth
command:
- -secret
- /run/secrets/simpleauth.key
secrets: secrets:
- passwd - passwd
- simpleauth.key - simpleauth.key
portal:
image: git.woozle.org/neale/portal
configs:
- source: portal.json
target: /web/portal.json
- source: deergrove.png
target: /web/portal.png
jellyfin:
image: jellyfin/jellyfin
deploy:
replicas: 0
environment:
TZ: US/Mountain
volumes:
- type: bind
source: /srv/sys/jellyfin/config
target: /config
- type: bind
source: /srv/sys/jellyfin/cache
target: /cache
- type: bind
source: /srv/media/
target: /srv/media/
read_only: true
plex: plex:
image: lscr.io/linuxserver/plex:latest image: ghcr.io/linuxserver/plex:1.29.2
networks: networks:
- hostnet - hostnet
environment: environment:
@ -76,29 +60,14 @@ services:
source: /srv/sys/plex source: /srv/sys/plex
target: /config target: /config
- type: bind - type: bind
source: /srv/media/ source: /srv
target: /srv/media/ target: /srv
read_only: true
pigallery2:
image: bpatrik/pigallery2:latest
volumes:
- type: bind
source: /srv/sys/pigallery2/config
target: /app/data/config
- type: bind
source: /srv/sys/pigallery2/db
target: /app/data/db
- type: bind
source: /srv/sys/pigallery2/cache
target: /app/data/cache
- type: bind
source: /srv/media/photos
target: /srv/media/photos
read_only: true read_only: true
bind:
propagation: rslave
transmission: transmission:
image: lscr.io/linuxserver/transmission:latest image: lscr.io/linuxserver/transmission
volumes: volumes:
- type: bind - type: bind
source: /srv/sys/transmission source: /srv/sys/transmission
@ -106,11 +75,8 @@ services:
- type: bind - type: bind
source: /srv/incoming source: /srv/incoming
target: /srv/incoming target: /srv/incoming
environment: networks:
PEERPORT: "51413" - hostnet
ports:
- 51413:51413
- 51413:51413/udp
sonarr: sonarr:
image: lscr.io/linuxserver/sonarr image: lscr.io/linuxserver/sonarr
@ -172,7 +138,7 @@ services:
source: /srv/incoming source: /srv/incoming
target: /srv/incoming target: /srv/incoming
prowlarr: prowlarr:
image: lscr.io/linuxserver/prowlarr:latest image: lscr.io/linuxserver/prowlarr:develop
extra_hosts: extra_hosts:
- host.docker.internal:host-gateway - host.docker.internal:host-gateway
volumes: volumes:
@ -191,16 +157,10 @@ services:
target: /srv/incoming target: /srv/incoming
gitea: gitea:
image: codeberg.org/forgejo/forgejo:1.18-rootless image: gitea/gitea:1
secrets: environment:
- source: gitea.ini USER_UID: 1000
target: /etc/gitea/app.ini USER_GID: 1000
uid: "1000"
gid: "1000"
mode: 0400
configs:
- source: gitea-robots.txt
target: /var/lib/gitea/custom/robots.txt
volumes: volumes:
- type: bind - type: bind
source: /srv/sys/gitea source: /srv/sys/gitea
@ -224,37 +184,18 @@ services:
source: /srv/sys/atlas/status source: /srv/sys/atlas/status
target: /var/atlas-probe/status target: /var/atlas-probe/status
netdata:
image: netdata/netdata
hostname: "{{.Node.Hostname}}"
deploy:
replicas: 0
environment:
NETDATA_DISABLE_CLOUD: "1"
cap_add:
- SYS_PTRACE
volumes:
- type: bind
source: /
target: /host
read_only: true
- type: bind
source: /srv/sys/netdata/lib
target: /var/lib/netdata
- type: bind
source: /srv/sys/netdata/cache
target: /var/cache/netdata
configs:
- source: netdata.conf
target: /etc/netdata/netdata.conf
geneweb: geneweb:
image: ravermeister/geneweb image: ravermeister/geneweb
volumes: volumes:
- type: bind - type: bind
source: /srv/sys/geneweb/ source: /srv/sys/geneweb/etc
target: /usr/local/share/geneweb/etc
- type: bind
source: /srv/sys/geneweb/share/data
target: /usr/local/share/geneweb/share/data target: /usr/local/share/geneweb/share/data
- type: bind
source: /srv/sys/geneweb/log
target: /usr/local/share/geneweb/log
samba: samba:
image: dperson/samba image: dperson/samba
@ -280,21 +221,15 @@ services:
- published: 445 - published: 445
target: 445 target: 445
webfs: webdav:
image: sigoden/dufs image: micromata/dave
volumes: volumes:
- type: bind - type: bind
source: /srv/storage source: /srv
target: /srv/storage target: /data
- type: bind configs:
source: /srv/incoming - source: dave.yaml
target: /srv/incoming target: /config/config.yaml
- type: bind
source: /srv/media
target: /srv/media
command:
- -A
- /srv
user: "911:911" user: "911:911"
ddns: ddns:
@ -307,8 +242,6 @@ services:
target: /updater/data target: /updater/data
tunnel: tunnel:
deploy:
replicas: 0
image: lscr.io/linuxserver/openssh-server image: lscr.io/linuxserver/openssh-server
user: abc user: abc
entrypoint: entrypoint:
@ -339,22 +272,22 @@ configs:
name: dave.yaml-v3 name: dave.yaml-v3
Corefile: Corefile:
file: Corefile file: Corefile
name: Corefile-v7 name: Corefile-v2
Caddyfile: Caddyfile:
file: Caddyfile file: Caddyfile
name: Caddyfile-v145 name: Caddyfile-v80
portal.json: index.html:
file: portal.json file: www/index.html
name: portal.json-v6 name: index.html-v32
deergrove.png: index.mjs:
file: www/deergrove.png file: www/index.mjs
name: deergrove.png-v1 name: index.mjs-v1
netdata.conf: index.css:
file: netdata.conf file: www/index.css
name: netdata.conf-v1 name: index.css-v1
gitea-robots.txt: browser.html:
file: gitea-robots.txt file: www/browser.html
name: gitea-robots.txt-v1 name: browser.html-v3
secrets: secrets:
passwd: passwd:
@ -369,24 +302,6 @@ secrets:
known_hosts: known_hosts:
file: secrets/known_hosts file: secrets/known_hosts
name: known_hosts-v1 name: known_hosts-v1
gitea.ini:
file: secrets/gitea.ini
name: gitea.ini-v4
jwt.secret:
file: secrets/jwt.secret
name: jwt.secret-v1
storage.secret:
file: secrets/storage.secret
name: storage.secret-v1
session.secret:
file: secrets/session.secret
name: session.secret-v1
users.yaml:
file: secrets/users.yaml
name: users.yaml-v9
authelia.oidc.yaml:
file: secrets/authelia.oidc.yaml
name: authelia.oidc.yaml-v2
networks: networks:
hostnet: hostnet:

View File

@ -1,76 +0,0 @@
[
{
"title": "Storage",
"href": "https://drive.woozle.org/",
"icon": "https://drive.woozle.org/storage/public/icons/cloud-folder.png",
"target": "_blank"
},
{
"title": "Photos",
"href": "https://photos.woozle.org/",
"icon": "https://photos.woozle.org/assets/icon_inv.png",
"target": "_blank"
},
{
"title": "Git",
"href": "https://git.woozle.org/",
"icon": "https://git.woozle.org/assets/img/logo.svg",
"target": "_blank"
},
{
"title": "Genealogy",
"href": "https://ancestry.woozle.org/",
"icon": "https://ancestry.woozle.org/images/arbre_start.png",
"target": "_blank"
},
{
"title": "Movies",
"href": "https://deergrove.woozle.org/radarr/",
"icon": "/radarr/Content/Images/logo.svg"
},
{
"title": "Episodes",
"href": "https://deergrove.woozle.org/sonarr/",
"icon": "/sonarr/Content/Images/logo.svg"
},
{
"title": "Music",
"href": "https://deergrove.woozle.org/lidarr/",
"icon": "/lidarr/Content/Images/logo.svg"
},
{
"title": "Books",
"href": "https://deergrove.woozle.org/readarr/",
"icon": "/readarr/Content/Images/logo.svg"
},
{
"title": "Media Sucker",
"href": "https://deergrove.woozle.org/sucker/",
"icon": "/sucker/cd-dvd.svg"
},
{
"title": "Searcher",
"href": "https://deergrove.woozle.org/prowlarr/",
"icon": "/prowlarr/Content/Images/logo.png"
},
{
"title": "Usenet",
"href": "https://deergrove.woozle.org/nzbget/",
"icon": "/nzbget/img/favicon-256x256.png"
},
{
"title": "BitTorrent",
"href": "https://deergrove.woozle.org/transmission/web/",
"icon": "/transmission/web/images/webclip-icon.png"
},
{
"title": "3D Printer",
"href": "https://deergrove.woozle.org/octoprint/",
"icon": "/octoprint/static/img/logo.png"
},
{
"title": "Host Stats",
"href": "/stat.html",
"app": "stat"
}
}

View File

@ -1,363 +1,47 @@
version: "3.8" version: "3.8"
services: services:
coredns:
image: coredns/coredns
networks:
- hostnet
configs:
- source: Corefile
target: /Corefile
caddy:
image: caddy:2-alpine
ports:
- target: 443
published: 443
mode: host
- target: 80
published: 80
mode: host
volumes:
- type: bind
source: /srv
target: /srv
read_only: true
- type: bind
source: /srv/sys/caddy
target: /data/caddy
configs:
- source: Caddyfile
target: /etc/caddy/Caddyfile
- source: index.html
target: /www/index.html
- source: index.mjs
target: /www/index.mjs
- source: deergrove.png
target: /www/deergrove.png
- source: index.css
target: /www/index.css
- source: browser.html
target: /browser.html
extra_hosts:
- host.docker.internal:host-gateway
authelia:
image: authelia/authelia
environment:
AUTHELIA_JWT_SECRET_FILE: /run/secrets/jwt.secret
AUTHELIA_SESSION_SECRET_FILE: /run/secrets/session.secret
AUTHELIA_STORAGE_ENCRYPTION_FILE: /run/secrets/storage.secret
secrets:
- jwt.secret
- session.secret
- storage.secret
- users.yaml
configs:
- source: authelia.yaml
target: /config/configuration.yml
volumes:
- type: bind
source: /srv/sys/authelia
target: /srv/sys/authelia
jellyfin: jellyfin:
image: jellyfin/jellyfin image: ghcr.io/linuxserver/jellyfin:10.7.7
ports:
- target: 8096
published: 8096
- target: 7359
published: 7359
protocol: udp
- target: 1900
published: 1900
protocol: udp
environment: environment:
TZ: US/Mountain TZ: US/Mountain
volumes: volumes:
- type: bind - type: bind
source: /srv/sys/jellyfin/config source: /mnt/ext/srv/jellyfin
target: /config target: /config
- type: bind - type: bind
source: /srv/sys/jellyfin/cache source: /media
target: /cache target: /media
- type: bind
source: /srv/media
target: /srv/media
read_only: true read_only: true
plex:
image: ghcr.io/linuxserver/plex:1.29.2
networks:
- hostnet
environment:
TZ: US/Mountain
VERSION: public
volumes:
- type: bind
source: /srv/sys/plex
target: /config
- type: bind
source: /srv
target: /srv
read_only: true
transmission:
image: lscr.io/linuxserver/transmission
volumes:
- type: bind
source: /srv/sys/transmission
target: /config
- type: bind
source: /srv/incoming
target: /srv/incoming
networks:
- hostnet
sonarr:
image: lscr.io/linuxserver/sonarr
extra_hosts:
- host.docker.internal:host-gateway
volumes:
- type: bind
source: /srv/sys/sonarr
target: /config
- type: bind
source: /srv/media/tv
target: /srv/media/tv
- type: bind
source: /srv/incoming
target: /srv/incoming
radarr:
image: lscr.io/linuxserver/radarr
extra_hosts:
- host.docker.internal:host-gateway
volumes:
- type: bind
source: /srv/sys/radarr
target: /config
- type: bind
source: /srv/media/movies
target: /srv/media/movies
- type: bind
source: /srv/incoming
target: /srv/incoming
lidarr:
image: lscr.io/linuxserver/lidarr
extra_hosts:
- host.docker.internal:host-gateway
volumes:
- type: bind
source: /srv/sys/lidarr
target: /config
- type: bind
source: /srv/media/music
target: /srv/media/music
- type: bind
source: /srv/incoming
target: /srv/incoming
readarr:
image: lscr.io/linuxserver/readarr:develop
extra_hosts:
- host.docker.internal:host-gateway
volumes:
- type: bind
source: /srv/sys/readarr
target: /config
- type: bind
source: /srv/media/books
target: /srv/media/books
- type: bind
source: /srv/media/audiobooks
target: /srv/media/audiobooks
- type: bind
source: /srv/incoming
target: /srv/incoming
prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
extra_hosts:
- host.docker.internal:host-gateway
volumes:
- type: bind
source: /srv/sys/prowlarr
target: /config
nzbget:
image: lscr.io/linuxserver/nzbget
volumes:
- type: bind
source: /srv/sys/nzbget
target: /config
- type: bind
source: /srv/incoming
target: /srv/incoming
forgejo:
image: codeberg.org/forgejo/forgejo:1.18-rootless
secrets:
- source: forgejo.ini
target: /etc/gitea/app.ini
uid: "1000"
gid: "1000"
mode: 0400
volumes:
- type: bind
source: /srv/sys/forgejo
target: /data
- type: bind
source: /etc/timezone
target: /etc/timezone
read_only: true
- type: bind
source: /etc/localtime
target: /etc/localtime
read_only: true
atlas:
image: ctassisf/ripe-atlas-alpine:arm64v8
volumes:
- type: bind
source: /srv/sys/atlas/etc
target: /var/atlas-probe/etc
- type: bind
source: /srv/sys/atlas/status
target: /var/atlas-probe/status
geneweb:
image: ravermeister/geneweb
volumes:
- type: bind
source: /srv/sys/geneweb/etc
target: /usr/local/share/geneweb/etc
- type: bind
source: /srv/sys/geneweb/share/data
target: /usr/local/share/geneweb/share/data
- type: bind
source: /srv/sys/geneweb/log
target: /usr/local/share/geneweb/log
samba:
image: dperson/samba
volumes:
- type: bind
source: /srv
target: /srv
bind: bind:
propagation: rslave propagation: rslave
environment:
NMBD: enable
RECYCLE: disable
USERID: 911
GROUPID: 911
# name;path;browse;readonly;guest
SHARE1: drive;/srv;yes;no;no
SHARE2: retropie;/srv/media/games/retropie;yes;yes;yes
env_file:
- secrets/samba-users.env
ports:
- published: 139
target: 139
- published: 445
target: 445
webdav:
image: micromata/dave
volumes:
- type: bind - type: bind
source: /srv source: /dev/video10
target: /data target: /dev/video10
configs:
- source: dave.yaml
target: /config/config.yaml
user: "911:911"
ddns:
image: qmcgaw/ddns-updater
dns:
- 1.1.1.1
volumes:
- type: bind - type: bind
source: /srv/sys/ddns-updater source: /dev/video11
target: /updater/data target: /dev/video11
- type: bind
tunnel: source: /dev/video12
deploy: target: /dev/video12
replicas: 0 - type: bind
image: lscr.io/linuxserver/openssh-server source: /dev/video13
user: abc target: /dev/video13
entrypoint: - type: bind
- /usr/bin/ssh source: /dev/video14
- -N target: /dev/video14
- -R 172.17.0.1:5880:caddy:80 # 172.17.0.1 = docker host IP - type: bind
- -R :5822:host.docker.internal:22 source: /dev/video15
- -o ServerAliveInterval=30 target: /dev/video15
- core@melville.woozle.org - type: bind
extra_hosts: source: /dev/video16
- host.docker.internal:host-gateway target: /dev/video16
secrets:
- source: tunnel
target: /config/.ssh/id_rsa
uid: "911"
gid: "911"
mode: 0600
- source: known_hosts
target: /config/.ssh/known_hosts
uid: "911"
gid: "911"
mode: 0600
configs:
dave.yaml:
file: dave.yaml
name: dave.yaml-v3
Corefile:
file: Corefile
name: Corefile-v3
Caddyfile:
file: Caddyfile
name: Caddyfile-v89
index.html:
file: www/index.html
name: index.html-v36
index.mjs:
file: www/index.mjs
name: index.mjs-v1
index.css:
file: www/index.css
name: index.css-v1
browser.html:
file: www/browser.html
name: browser.html-v3
deergrove.png:
file: www/deergrove.png
name: deergrove.png-v1
authelia.yaml:
file: authelia.yaml
name: authelia.yaml-v1
secrets:
passwd:
file: secrets/passwd
name: passwd-v2
simpleauth.key:
file: secrets/simpleauth.key
name: simpleauth.key-v1
tunnel:
file: secrets/tunnel
name: tunnel-v1
known_hosts:
file: secrets/known_hosts
name: known_hosts-v1
forgejo.ini:
file: secrets/forgejo.ini
name: forgejo.ini-v1
jwt.secret:
file: secrets/jwt.secret
name: jwt.secret-v1
storage.secret:
file: secrets/storage.secret
name: storage.secret-v1
session.secret:
file: secrets/session.secret
name: session.secret-v1
users.yaml:
file: secrets/users.yaml
name: users.yaml-v1
networks:
hostnet:
external: true
name: host

36
homelab/www/browser.html Normal file
View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>Woozle Drive</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/dom111/webdav-js/assets/css/style-min.css">
<script>
function init() {
// This is dumb, but webdav-min.js doesn't have any checks to make sure the document is loaded.
let scr = document.head.appendChild(document.createElement("script"))
scr.src = "https://cdn.jsdelivr.net/gh/dom111/webdav-js/src/webdav-min.js"
for (let e of document.querySelectorAll(".listing")) {
console.log("Let's pray the WebDAV stuff works!", e)
e.remove()
}
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init)
} else {
init()
}
</script>
</head>
<body>
<ul class="listing">
{{range .Items}}
<li>
<a href="{{html .URL}}">{{html .Name}}</a>
<span class="size" data-value="{{.Size}}">{{.HumanSize}}</span>
<time>{{.HumanModTime "2006-01-02T15:04:05Z"}}</time>
</li>
{{end}}
</ul>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@ -27,7 +27,7 @@ nav a {
text-decoration: none; text-decoration: none;
white-space: nowrap; white-space: nowrap;
} }
nav a[data-no-menu] { nav a[target] {
display: none; display: none;
} }
nav a:hover { nav a:hover {

View File

@ -4,12 +4,29 @@
<title>Deer Grove</title> <title>Deer Grove</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="deergrove.png"> <link rel="icon" href="icons/deergrove.png">
<link rel="stylesheet" href="index.css"> <link rel="stylesheet" href="index.css">
<script src="index.mjs" type="module"></script> <script src="index.mjs" type="module"></script>
</head> </head>
<body> <body>
<nav> <nav>
<a href="/sonarr/" data-icon="/sonarr/Content/Images/logo.svg" title="Episode manager">Shows</a>
<a href="/radarr/" data-icon="/radarr/Content/Images/logo.svg" title="Movie manager">Movies</a>
<a href="/lidarr/" data-icon="/lidarr/Content/Images/logo.svg" title="Music manager">Music</a>
<a href="/readarr/" data-icon="/readarr/Content/Images/logo.svg" title="Book manager">Books</a>
<a href="/sucker/" data-icon="/sucker/cd-dvd.svg" title="Media Sucker">Sucker</a>
<hr>
<a href="/prowlarr/" data-icon="/prowlarr/Content/Images/logo.png" title="Indexer/Searcher">Search</a>
<a href="/nzbget/" data-icon="/nzbget/img/favicon-256x256.png" title="Usenet downloader">Usenet</a>
<a href="/transmission/web/" data-icon="/transmission/web/style/transmission/images/logo.png" title="BitTorrent downloader">BitTorrent</a>
<hr>
<a href="/octoprint/" data-icon="/octoprint/static/img/logo.png" title="3D Printer Front-End">Octoprint</a>
<a href="/wallart/" data-icon="/wallart/wallart.png" title="Wall Art uploader">Wall Art</a>
<!-- Items that launch a new tab don't appear in the top menu -->
<a href="https://git.woozle.org" target="_blank" data-icon="https://git.woozle.org/assets/img/logo.svg" title="Git repositories">Git</a>
<a href="https://drive.woozle.org/" target="_blank" data-icon="/public/icons/cloud-folder.png" titled="Shared storage">Drive</a>
<a href="https://ancestry.woozle.org/" target="_blank" data-icon="https://ancestry.woozle.org/images/favicon_gwd.png" title="Genealogy">Ancestry</a>
</nav> </nav>
<section id="app"> <section id="app">
<iframe></iframe> <iframe></iframe>

View File

@ -1,5 +1,8 @@
let frames = {} let frames = {}
function activate(event, element) { function activate(event, element) {
if (element.target) {
return
}
event.preventDefault() event.preventDefault()
let parent = element.parentElement let parent = element.parentElement
@ -46,7 +49,7 @@ function frameLoaded(frame) {
} }
let defaultIcon = null let defaultIcon = null
async function init() { function init() {
let doc = document.querySelector("iframe").contentDocument let doc = document.querySelector("iframe").contentDocument
defaultIcon = document.querySelector("link[rel~='icon']").href defaultIcon = document.querySelector("link[rel~='icon']").href
@ -65,40 +68,22 @@ async function init() {
let icons = doc.body.appendChild(doc.createElement("section")) let icons = doc.body.appendChild(doc.createElement("section"))
icons.classList.add("icons") icons.classList.add("icons")
let portalURL = new URL("portal.json", window.location) for (let link of document.querySelectorAll("nav a")) {
let resp = await fetch(portalURL) let dlink = icons.appendChild(link.cloneNode(true))
let obj = await resp.json() dlink.textContent = ""
let nav = document.querySelector("nav")
for (let app of obj) {
let hlink = null
if (app.target != "_blank") {
hlink = nav.appendChild(document.createElement("a"))
hlink.href = app.href
hlink.textContent = app.title
if (app.target) {
hlink.target = app.target
} else {
hlink.addEventListener("click", event => activate(event, hlink))
}
}
let dlink = icons.appendChild(doc.createElement("a")) if (link.dataset.icon) {
dlink.href = app.href
if (app.target) {
dlink.target = app.target
} else {
dlink.addEventListener("click", event => activate(event, hlink))
}
if (app.icon) {
let icon = dlink.appendChild(doc.createElement("img")) let icon = dlink.appendChild(doc.createElement("img"))
icon.src = app.icon icon.src = link.dataset.icon
icon.alt = app.title
icon.title = app.title
icon.style.objectFit = "cover" icon.style.objectFit = "cover"
} else { } else {
let text = dlink.appendChild(doc.createElement("div")) let text = dlink.appendChild(doc.createElement("div"))
text.textContent = app.title text.textContent = link.textContent
} }
// Make both of them update the selected tab
link.addEventListener("click", event => activate(event, link))
dlink.addEventListener("click", event => activate(event, link))
} }
} }

View File

@ -17,11 +17,6 @@ deergrove.woozle.org, git.woozle.org, ancestry.woozle.org, drive.woozle.org {
reverse_proxy host.docker.internal:5880 reverse_proxy host.docker.internal:5880
} }
passwords.woozle.org {
reverse_proxy /notifications/hub vaultwarden:3012
reverse_proxy vaultwarden:80
}
www.woozle.org, woozle.org { www.woozle.org, woozle.org {
root * /srv/www/woozle.org root * /srv/www/woozle.org
file_server file_server

View File

@ -36,5 +36,5 @@ services:
configs: configs:
Caddyfile: Caddyfile:
file: Caddyfile file: Caddyfile
name: Caddyfile-v11 name: Caddyfile-v9