v0.6.10-beta - ARR-stack met een schakelaar per onderdeel
All checks were successful
Deploy server-up (dev) / deploy (push) Successful in 1m32s
All checks were successful
Deploy server-up (dev) / deploy (push) Successful in 1m32s
De ARR-stack installeerde altijd dezelfde zeven containers. Nu kies je per onderdeel uit twintig: - Media: sonarr, radarr, lidarr, readarr, whisparr - Indexers: prowlarr, jackett, flaresolverr, bazarr - Downloaden: qbittorrent, sabnzbd, nzbget, gluetun (VPN) - Aanvullend: jellyseerr, recyclarr, unpackerr, tdarr, autobrr, maintainerr, huntarr Standaard aan: sonarr, radarr, prowlarr, bazarr, qbittorrent, jellyseerr. Gluetun: - Staat die aan, dan draaien de downloadclients in diens netwerknamespace zonder eigen poortmapping; anders lekt hun verkeer om de VPN heen. Hun webinterfaces komen op de poorten van de Gluetun-container. - qBittorrent en SABnzbd luisteren allebei standaard op 8080 en botsten daardoor achter een gedeelde namespace. qBittorrent draait nu intern op 8090. Groepsschakelaars werkten niet: - Een `toggle` op een groep in template.json was zelf geen variabele en kreeg dus nooit een startwaarde, waardoor elk schakelbaar onderdeel standaard uit stond en een stack met schakelaars leeg binnenkwam. fields() geeft de schakelaar nu mee als synthetisch bool-veld met een instelbare standaardstand (toggle_default), en de UI toont hem alleen in de kop van de groep in plaats van er ook nog eens onder. Tests: elk onderdeel levert precies een service op als het aan staat en geen spoor als het uit staat, de downloadclients zitten achter de VPN zonder eigen poorten, en de interne poorten achter Gluetun botsen niet. Poortbotsingen met bestaande apps rechtgezet (8090 -> 8097, 8095 -> 8098); 6881 en 5055 blijven gedeeld met de losse variant van dezelfde app. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
This commit is contained in:
parent
b8c8e89fa0
commit
7ae62fe78c
7 changed files with 754 additions and 61 deletions
40
CHANGELOG.md
40
CHANGELOG.md
|
|
@ -1,3 +1,43 @@
|
||||||
|
# v0.6.10-beta — ARR-stack met een schakelaar per onderdeel
|
||||||
|
|
||||||
|
De ARR-stack installeerde altijd dezelfde zeven containers. Nu kies je per
|
||||||
|
onderdeel wat je wilt, uit twintig:
|
||||||
|
|
||||||
|
**Media beheren** — Sonarr (series), Radarr (films), Lidarr (muziek), Readarr
|
||||||
|
(boeken), Whisparr
|
||||||
|
|
||||||
|
**Indexers en ondersteuning** — Prowlarr, Jackett, FlareSolverr, Bazarr
|
||||||
|
(ondertitels)
|
||||||
|
|
||||||
|
**Downloaden** — qBittorrent, SABnzbd, NZBGet, en Gluetun om al het
|
||||||
|
downloadverkeer door een VPN te leiden
|
||||||
|
|
||||||
|
**Verzoeken en aanvullingen** — Jellyseerr, Recyclarr (TRaSH-profielen),
|
||||||
|
Unpackerr, Tdarr (hercoderen), Autobrr, Maintainerr, Huntarr
|
||||||
|
|
||||||
|
Standaard staan Sonarr, Radarr, Prowlarr, Bazarr, qBittorrent en Jellyseerr aan;
|
||||||
|
de rest zet je zelf bij.
|
||||||
|
|
||||||
|
## Gluetun schakelt de downloadclients om
|
||||||
|
|
||||||
|
Zet je Gluetun aan, dan verhuizen qBittorrent, SABnzbd en NZBGet naar diens
|
||||||
|
netwerknamespace en verliezen ze hun eigen poortmapping — precies zoals het
|
||||||
|
hoort, want anders lekt hun verkeer om de VPN heen. Hun webinterfaces bereik je
|
||||||
|
dan via de poorten van de Gluetun-container.
|
||||||
|
|
||||||
|
Daarbij zat een val: qBittorrent en SABnzbd luisteren allebei standaard op 8080,
|
||||||
|
en achter één VPN-container botsen ze. qBittorrent draait nu intern op 8090.
|
||||||
|
|
||||||
|
## Groepsschakelaars werkten niet
|
||||||
|
|
||||||
|
Een groepsschakelaar in template.json was zelf geen variabele en kreeg dus nooit
|
||||||
|
een startwaarde. Elk schakelbaar onderdeel stond daardoor standaard uit — een
|
||||||
|
stack met schakelaars zou leeg binnenkomen. Ze worden nu als veld meegegeven met
|
||||||
|
een instelbare standaardstand, en de interface toont ze alleen als schakelaar in
|
||||||
|
de kop van de groep.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# v0.6.00-beta — 29 apps erbij, en een bug die zes bestaande apps onstartbaar maakte
|
# v0.6.00-beta — 29 apps erbij, en een bug die zes bestaande apps onstartbaar maakte
|
||||||
|
|
||||||
## 🐛 Named volumes verdwenen uit het compose-bestand
|
## 🐛 Named volumes verdwenen uit het compose-bestand
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
0.6.00-beta
|
0.6.10-beta
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,13 @@
|
||||||
|
# ARR-stack — kies per onderdeel of je het wilt.
|
||||||
|
#
|
||||||
|
# Aandachtspunten:
|
||||||
|
# * Zet de download- en mediamap op hetzelfde bestandssysteem, anders kopieert
|
||||||
|
# elke voltooide download in plaats van te verplaatsen (traag, dubbele opslag).
|
||||||
|
# * Draai je met Gluetun, dan zitten de downloadclients in het netwerk van die
|
||||||
|
# container en bereik je hun webinterface via de Gluetun-poorten.
|
||||||
services:
|
services:
|
||||||
<< service_name >>-radarr:
|
|
||||||
image: lscr.io/linuxserver/radarr:latest
|
|
||||||
container_name: << service_name >>-radarr
|
|
||||||
environment:
|
|
||||||
- PUID=<< puid >>
|
|
||||||
- PGID=<< pgid >>
|
|
||||||
- TZ=<< timezone >>
|
|
||||||
volumes:
|
|
||||||
- << data_dir >>/<< service_name >>/radarr:/config
|
|
||||||
- << media_dir >>/films:/movies
|
|
||||||
- << downloads_dir >>:/downloads
|
|
||||||
ports:
|
|
||||||
- "<< port_radarr >>:7878"
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
|
<%- if enable_sonarr %>
|
||||||
<< service_name >>-sonarr:
|
<< service_name >>-sonarr:
|
||||||
image: lscr.io/linuxserver/sonarr:latest
|
image: lscr.io/linuxserver/sonarr:latest
|
||||||
container_name: << service_name >>-sonarr
|
container_name: << service_name >>-sonarr
|
||||||
|
|
@ -28,7 +22,26 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "<< port_sonarr >>:8989"
|
- "<< port_sonarr >>:8989"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_radarr %>
|
||||||
|
<< service_name >>-radarr:
|
||||||
|
image: lscr.io/linuxserver/radarr:latest
|
||||||
|
container_name: << service_name >>-radarr
|
||||||
|
environment:
|
||||||
|
- PUID=<< puid >>
|
||||||
|
- PGID=<< pgid >>
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/radarr:/config
|
||||||
|
- << media_dir >>/films:/movies
|
||||||
|
- << downloads_dir >>:/downloads
|
||||||
|
ports:
|
||||||
|
- "<< port_radarr >>:7878"
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_lidarr %>
|
||||||
<< service_name >>-lidarr:
|
<< service_name >>-lidarr:
|
||||||
image: lscr.io/linuxserver/lidarr:latest
|
image: lscr.io/linuxserver/lidarr:latest
|
||||||
container_name: << service_name >>-lidarr
|
container_name: << service_name >>-lidarr
|
||||||
|
|
@ -43,7 +56,9 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "<< port_lidarr >>:8686"
|
- "<< port_lidarr >>:8686"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_readarr %>
|
||||||
<< service_name >>-readarr:
|
<< service_name >>-readarr:
|
||||||
image: lscr.io/linuxserver/readarr:develop
|
image: lscr.io/linuxserver/readarr:develop
|
||||||
container_name: << service_name >>-readarr
|
container_name: << service_name >>-readarr
|
||||||
|
|
@ -58,7 +73,26 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "<< port_readarr >>:8787"
|
- "<< port_readarr >>:8787"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_whisparr %>
|
||||||
|
<< service_name >>-whisparr:
|
||||||
|
image: ghcr.io/hotio/whisparr:latest
|
||||||
|
container_name: << service_name >>-whisparr
|
||||||
|
environment:
|
||||||
|
- PUID=<< puid >>
|
||||||
|
- PGID=<< pgid >>
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/whisparr:/config
|
||||||
|
- << media_dir >>/volwassen:/adult
|
||||||
|
- << downloads_dir >>:/downloads
|
||||||
|
ports:
|
||||||
|
- "<< port_whisparr >>:6969"
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_prowlarr %>
|
||||||
<< service_name >>-prowlarr:
|
<< service_name >>-prowlarr:
|
||||||
image: lscr.io/linuxserver/prowlarr:latest
|
image: lscr.io/linuxserver/prowlarr:latest
|
||||||
container_name: << service_name >>-prowlarr
|
container_name: << service_name >>-prowlarr
|
||||||
|
|
@ -71,7 +105,24 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "<< port_prowlarr >>:9696"
|
- "<< port_prowlarr >>:9696"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_jackett %>
|
||||||
|
<< service_name >>-jackett:
|
||||||
|
image: lscr.io/linuxserver/jackett:latest
|
||||||
|
container_name: << service_name >>-jackett
|
||||||
|
environment:
|
||||||
|
- PUID=<< puid >>
|
||||||
|
- PGID=<< pgid >>
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/jackett:/config
|
||||||
|
ports:
|
||||||
|
- "<< port_jackett >>:9117"
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_bazarr %>
|
||||||
<< service_name >>-bazarr:
|
<< service_name >>-bazarr:
|
||||||
image: lscr.io/linuxserver/bazarr:latest
|
image: lscr.io/linuxserver/bazarr:latest
|
||||||
container_name: << service_name >>-bazarr
|
container_name: << service_name >>-bazarr
|
||||||
|
|
@ -86,14 +137,226 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "<< port_bazarr >>:6767"
|
- "<< port_bazarr >>:6767"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_flaresolverr %>
|
||||||
|
<< service_name >>-flaresolverr:
|
||||||
|
image: ghcr.io/flaresolverr/flaresolverr:latest
|
||||||
|
container_name: << service_name >>-flaresolverr
|
||||||
|
environment:
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
- LOG_LEVEL=info
|
||||||
|
ports:
|
||||||
|
- "<< port_flaresolverr >>:8191"
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_gluetun %>
|
||||||
|
<< service_name >>-gluetun:
|
||||||
|
image: qmcgaw/gluetun:latest
|
||||||
|
container_name: << service_name >>-gluetun
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
devices:
|
||||||
|
- /dev/net/tun:/dev/net/tun
|
||||||
|
environment:
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
- VPN_SERVICE_PROVIDER=<< vpn_provider >>
|
||||||
|
- VPN_TYPE=<< vpn_type >>
|
||||||
|
- WIREGUARD_PRIVATE_KEY=<< wireguard_private_key >>
|
||||||
|
- WIREGUARD_ADDRESSES=<< wireguard_addresses >>
|
||||||
|
- OPENVPN_USER=<< openvpn_user >>
|
||||||
|
- OPENVPN_PASSWORD=<< openvpn_password >>
|
||||||
|
ports:
|
||||||
|
# De downloadclients delen dit netwerk, dus hun poorten staan hier.
|
||||||
|
<%- if enable_qbittorrent %>
|
||||||
|
- "<< port_qbittorrent >>:8090"
|
||||||
|
- "<< port_qbittorrent_tcp >>:6881"
|
||||||
|
- "<< port_qbittorrent_tcp >>:6881/udp"
|
||||||
|
<%- endif %>
|
||||||
|
<%- if enable_sabnzbd %>
|
||||||
|
- "<< port_sabnzbd >>:8080"
|
||||||
|
<%- endif %>
|
||||||
|
<%- if enable_nzbget %>
|
||||||
|
- "<< port_nzbget >>:6789"
|
||||||
|
<%- endif %>
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/gluetun:/gluetun
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_qbittorrent %>
|
||||||
|
<< service_name >>-qbittorrent:
|
||||||
|
image: lscr.io/linuxserver/qbittorrent:latest
|
||||||
|
container_name: << service_name >>-qbittorrent
|
||||||
|
environment:
|
||||||
|
- PUID=<< puid >>
|
||||||
|
- PGID=<< pgid >>
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
- WEBUI_PORT=8090
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/qbittorrent:/config
|
||||||
|
- << downloads_dir >>:/downloads
|
||||||
|
<%- if enable_gluetun %>
|
||||||
|
network_mode: "service:<< service_name >>-gluetun"
|
||||||
|
depends_on:
|
||||||
|
- << service_name >>-gluetun
|
||||||
|
<%- endif %>
|
||||||
|
<%- if not enable_gluetun %>
|
||||||
|
ports:
|
||||||
|
- "<< port_qbittorrent >>:8090"
|
||||||
|
- "<< port_qbittorrent_tcp >>:6881"
|
||||||
|
- "<< port_qbittorrent_tcp >>:6881/udp"
|
||||||
|
<%- endif %>
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_sabnzbd %>
|
||||||
|
<< service_name >>-sabnzbd:
|
||||||
|
image: lscr.io/linuxserver/sabnzbd:latest
|
||||||
|
container_name: << service_name >>-sabnzbd
|
||||||
|
environment:
|
||||||
|
- PUID=<< puid >>
|
||||||
|
- PGID=<< pgid >>
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/sabnzbd:/config
|
||||||
|
- << downloads_dir >>:/downloads
|
||||||
|
<%- if enable_gluetun %>
|
||||||
|
network_mode: "service:<< service_name >>-gluetun"
|
||||||
|
depends_on:
|
||||||
|
- << service_name >>-gluetun
|
||||||
|
<%- endif %>
|
||||||
|
<%- if not enable_gluetun %>
|
||||||
|
ports:
|
||||||
|
- "<< port_sabnzbd >>:8080"
|
||||||
|
<%- endif %>
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_nzbget %>
|
||||||
|
<< service_name >>-nzbget:
|
||||||
|
image: lscr.io/linuxserver/nzbget:latest
|
||||||
|
container_name: << service_name >>-nzbget
|
||||||
|
environment:
|
||||||
|
- PUID=<< puid >>
|
||||||
|
- PGID=<< pgid >>
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/nzbget:/config
|
||||||
|
- << downloads_dir >>:/downloads
|
||||||
|
<%- if enable_gluetun %>
|
||||||
|
network_mode: "service:<< service_name >>-gluetun"
|
||||||
|
depends_on:
|
||||||
|
- << service_name >>-gluetun
|
||||||
|
<%- endif %>
|
||||||
|
<%- if not enable_gluetun %>
|
||||||
|
ports:
|
||||||
|
- "<< port_nzbget >>:6789"
|
||||||
|
<%- endif %>
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_jellyseerr %>
|
||||||
<< service_name >>-jellyseerr:
|
<< service_name >>-jellyseerr:
|
||||||
image: fallenbagel/jellyseerr:latest
|
image: fallenbagel/jellyseerr:latest
|
||||||
container_name: << service_name >>-jellyseerr
|
container_name: << service_name >>-jellyseerr
|
||||||
environment:
|
environment:
|
||||||
- TZ=<< timezone >>
|
- TZ=<< timezone >>
|
||||||
|
- LOG_LEVEL=info
|
||||||
volumes:
|
volumes:
|
||||||
- << data_dir >>/<< service_name >>/jellyseerr:/app/config
|
- << data_dir >>/<< service_name >>/jellyseerr:/app/config
|
||||||
ports:
|
ports:
|
||||||
- "<< port_jellyseerr >>:5055"
|
- "<< port_jellyseerr >>:5055"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_recyclarr %>
|
||||||
|
<< service_name >>-recyclarr:
|
||||||
|
image: ghcr.io/recyclarr/recyclarr:latest
|
||||||
|
container_name: << service_name >>-recyclarr
|
||||||
|
user: << puid >>:<< pgid >>
|
||||||
|
environment:
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/recyclarr:/config
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_unpackerr %>
|
||||||
|
<< service_name >>-unpackerr:
|
||||||
|
image: ghcr.io/unpackerr/unpackerr:latest
|
||||||
|
container_name: << service_name >>-unpackerr
|
||||||
|
user: << puid >>:<< pgid >>
|
||||||
|
environment:
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
- UN_SONARR_0_URL=http://<< service_name >>-sonarr:8989
|
||||||
|
- UN_RADARR_0_URL=http://<< service_name >>-radarr:7878
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/unpackerr:/config
|
||||||
|
- << downloads_dir >>:/downloads
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_tdarr %>
|
||||||
|
<< service_name >>-tdarr:
|
||||||
|
image: ghcr.io/haveagitgat/tdarr:latest
|
||||||
|
container_name: << service_name >>-tdarr
|
||||||
|
environment:
|
||||||
|
- PUID=<< puid >>
|
||||||
|
- PGID=<< pgid >>
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
- serverIP=0.0.0.0
|
||||||
|
- serverPort=8266
|
||||||
|
- webUIPort=8265
|
||||||
|
- internalNode=true
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/tdarr/server:/app/server
|
||||||
|
- << data_dir >>/<< service_name >>/tdarr/configs:/app/configs
|
||||||
|
- << media_dir >>:/media
|
||||||
|
- << downloads_dir >>/tdarr-cache:/temp
|
||||||
|
ports:
|
||||||
|
- "<< port_tdarr >>:8265"
|
||||||
|
- "<< port_tdarr_server >>:8266"
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_autobrr %>
|
||||||
|
<< service_name >>-autobrr:
|
||||||
|
image: ghcr.io/autobrr/autobrr:latest
|
||||||
|
container_name: << service_name >>-autobrr
|
||||||
|
environment:
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/autobrr:/config
|
||||||
|
ports:
|
||||||
|
- "<< port_autobrr >>:7474"
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_maintainerr %>
|
||||||
|
<< service_name >>-maintainerr:
|
||||||
|
image: ghcr.io/jorenn92/maintainerr:latest
|
||||||
|
container_name: << service_name >>-maintainerr
|
||||||
|
user: << puid >>:<< pgid >>
|
||||||
|
environment:
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/maintainerr:/opt/data
|
||||||
|
ports:
|
||||||
|
- "<< port_maintainerr >>:6246"
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
||||||
|
<%- if enable_huntarr %>
|
||||||
|
<< service_name >>-huntarr:
|
||||||
|
image: ghcr.io/plexguide/huntarr:latest
|
||||||
|
container_name: << service_name >>-huntarr
|
||||||
|
environment:
|
||||||
|
- TZ=<< timezone >>
|
||||||
|
volumes:
|
||||||
|
- << data_dir >>/<< service_name >>/huntarr:/config
|
||||||
|
ports:
|
||||||
|
- "<< port_huntarr >>:9705"
|
||||||
|
restart: unless-stopped
|
||||||
|
<%- endif %>
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,21 @@
|
||||||
"kind": "compose",
|
"kind": "compose",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "ARR-stack",
|
"name": "ARR-stack",
|
||||||
"description": "Complete media-automatiseringsstack: Radarr (films), Sonarr (series), Lidarr (muziek), Readarr (boeken), Prowlarr (indexers), Bazarr (ondertitels) en Jellyseerr (verzoeken).",
|
"description": "Media-automatisering met een schakelaar per onderdeel: Sonarr, Radarr, Lidarr, Readarr, Whisparr, Prowlarr, Jackett, Bazarr, FlareSolverr, qBittorrent, SABnzbd, NZBGet, Gluetun (VPN), Jellyseerr, Recyclarr, Unpackerr, Tdarr, Autobrr, Maintainerr en Huntarr.",
|
||||||
"tags": ["media", "automatisering", "radarr", "sonarr", "prowlarr", "bazarr", "jellyseerr"],
|
"tags": [
|
||||||
"icon": {"provider": "selfhst", "id": "radarr"},
|
"media",
|
||||||
"version": {"name": "latest"}
|
"automatisering",
|
||||||
|
"films",
|
||||||
|
"series",
|
||||||
|
"downloaden"
|
||||||
|
],
|
||||||
|
"icon": {
|
||||||
|
"provider": "selfhst",
|
||||||
|
"id": "sonarr"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "latest"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"variables": [
|
"variables": [
|
||||||
{
|
{
|
||||||
|
|
@ -14,34 +25,33 @@
|
||||||
{
|
{
|
||||||
"name": "service_name",
|
"name": "service_name",
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"title": "Servicenaam (prefix)",
|
"title": "Naam van de stack",
|
||||||
"default": "arr",
|
"default": "arr",
|
||||||
"required": true,
|
"required": true,
|
||||||
"description": "Prefix voor alle containers in de stack, bijv. 'arr' geeft arr-radarr, arr-sonarr, etc."
|
"description": "Wordt het voorvoegsel van elke container, bv. arr-sonarr"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "data_dir",
|
"name": "data_dir",
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"title": "Config directory",
|
"title": "Configuratiemap",
|
||||||
"default": "/opt/serverup/appdata",
|
"default": "/opt/serverup/appdata",
|
||||||
"required": true,
|
"required": true
|
||||||
"description": "Basismap voor configuratiebestanden van alle ARR-apps"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "media_dir",
|
"name": "media_dir",
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"title": "Media directory",
|
"title": "Mediamap",
|
||||||
"default": "/mnt/media",
|
"default": "/mnt/media",
|
||||||
"required": true,
|
"required": true,
|
||||||
"description": "Map voor films, series en muziek. Moet ook zichtbaar zijn voor de download-client."
|
"description": "Hier komen films/, series/, muziek/ en boeken/ onder te staan"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "downloads_dir",
|
"name": "downloads_dir",
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"title": "Downloads directory",
|
"title": "Downloadmap",
|
||||||
"default": "/mnt/downloads",
|
"default": "/mnt/downloads",
|
||||||
"required": true,
|
"required": true,
|
||||||
"description": "Map waar de download-client bestanden neerzet (qBittorrent of SABnzbd). Moet overeenkomen met het pad in de download-client."
|
"description": "Zet deze op hetzelfde bestandssysteem als de mediamap, anders kopieert elke download in plaats van te verplaatsen"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "timezone",
|
"name": "timezone",
|
||||||
|
|
@ -49,84 +59,365 @@
|
||||||
"title": "Tijdzone",
|
"title": "Tijdzone",
|
||||||
"default": "Europe/Amsterdam",
|
"default": "Europe/Amsterdam",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"title": "Gebruiker",
|
|
||||||
"items": [
|
|
||||||
{
|
{
|
||||||
"name": "puid",
|
"name": "puid",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"title": "PUID",
|
"title": "Gebruikers-ID (PUID)",
|
||||||
"default": 1000,
|
"default": 1000,
|
||||||
"required": true,
|
"required": true,
|
||||||
"description": "User ID van de systeemgebruiker (id -u)"
|
"description": "`id -u` op je host; bepaalt de eigenaar van bestanden"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pgid",
|
"name": "pgid",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"title": "PGID",
|
"title": "Groeps-ID (PGID)",
|
||||||
"default": 1000,
|
"default": 1000,
|
||||||
"required": true,
|
"required": true
|
||||||
"description": "Group ID van de systeemgebruiker (id -g)"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Poorten",
|
"title": "Sonarr — series",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_sonarr",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Poort",
|
||||||
|
"default": 8989,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_sonarr",
|
||||||
|
"toggle_default": true,
|
||||||
|
"description": "Zoekt, downloadt en hernoemt series"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Radarr — films",
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"name": "port_radarr",
|
"name": "port_radarr",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"title": "Radarr poort",
|
"title": "Poort",
|
||||||
"default": 7878,
|
"default": 7878,
|
||||||
"required": true
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_radarr",
|
||||||
|
"toggle_default": true,
|
||||||
|
"description": "Zoekt, downloadt en hernoemt films"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "port_sonarr",
|
"title": "Lidarr — muziek",
|
||||||
"type": "int",
|
"items": [
|
||||||
"title": "Sonarr poort",
|
|
||||||
"default": 8989,
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "port_lidarr",
|
"name": "port_lidarr",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"title": "Lidarr poort",
|
"title": "Poort",
|
||||||
"default": 8686,
|
"default": 8686,
|
||||||
"required": true
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_lidarr",
|
||||||
|
"toggle_default": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "Readarr — boeken",
|
||||||
|
"items": [
|
||||||
{
|
{
|
||||||
"name": "port_readarr",
|
"name": "port_readarr",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"title": "Readarr poort",
|
"title": "Poort",
|
||||||
"default": 8787,
|
"default": 8787,
|
||||||
"required": true
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_readarr",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Let op: de ontwikkeling van Readarr is stilgelegd; het draait nog wel"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "Whisparr — volwassenen",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_whisparr",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Poort",
|
||||||
|
"default": 6969,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_whisparr",
|
||||||
|
"toggle_default": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Prowlarr — indexerbeheer",
|
||||||
|
"items": [
|
||||||
{
|
{
|
||||||
"name": "port_prowlarr",
|
"name": "port_prowlarr",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"title": "Prowlarr poort",
|
"title": "Poort",
|
||||||
"default": 9696,
|
"default": 9696,
|
||||||
"required": true
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_prowlarr",
|
||||||
|
"toggle_default": true,
|
||||||
|
"description": "Beheert je indexers centraal en duwt ze naar de andere *arr-apps"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "Jackett — indexerproxy",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_jackett",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Poort",
|
||||||
|
"default": 9117,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_jackett",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Ouder alternatief voor Prowlarr; meestal heb je er maar één nodig"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "FlareSolverr — Cloudflare omzeilen",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_flaresolverr",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Poort",
|
||||||
|
"default": 8191,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_flaresolverr",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Nodig voor indexers die achter een Cloudflare-controle zitten"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Bazarr — ondertitels",
|
||||||
|
"items": [
|
||||||
{
|
{
|
||||||
"name": "port_bazarr",
|
"name": "port_bazarr",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"title": "Bazarr poort",
|
"title": "Poort",
|
||||||
"default": 6767,
|
"default": 6767,
|
||||||
"required": true
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_bazarr",
|
||||||
|
"toggle_default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "qBittorrent — torrents",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_qbittorrent",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Webinterface",
|
||||||
|
"default": 8097,
|
||||||
|
"required": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "port_qbittorrent_tcp",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Inkomende poort",
|
||||||
|
"default": 6881,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_qbittorrent",
|
||||||
|
"toggle_default": true,
|
||||||
|
"description": "Torrentclient met webinterface"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "SABnzbd — usenet",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_sabnzbd",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Poort",
|
||||||
|
"default": 8098,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_sabnzbd",
|
||||||
|
"toggle_default": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "NZBGet — usenet (lichter)",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_nzbget",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Poort",
|
||||||
|
"default": 6789,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_nzbget",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Zuiniger alternatief voor SABnzbd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Gluetun — VPN voor de downloadclient",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "vpn_provider",
|
||||||
|
"type": "str",
|
||||||
|
"title": "VPN-aanbieder",
|
||||||
|
"default": "mullvad",
|
||||||
|
"required": true,
|
||||||
|
"description": "Bijvoorbeeld mullvad, nordvpn, protonvpn of surfshark"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vpn_type",
|
||||||
|
"type": "enum",
|
||||||
|
"title": "Protocol",
|
||||||
|
"default": "wireguard",
|
||||||
|
"required": true,
|
||||||
|
"config": {
|
||||||
|
"options": [
|
||||||
|
"wireguard",
|
||||||
|
"openvpn"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wireguard_private_key",
|
||||||
|
"type": "str",
|
||||||
|
"title": "WireGuard privésleutel",
|
||||||
|
"default": "",
|
||||||
|
"required": false,
|
||||||
|
"config": {
|
||||||
|
"placeholder": "alleen bij wireguard"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wireguard_addresses",
|
||||||
|
"type": "str",
|
||||||
|
"title": "WireGuard adressen",
|
||||||
|
"default": "",
|
||||||
|
"required": false,
|
||||||
|
"config": {
|
||||||
|
"placeholder": "10.64.0.2/32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "openvpn_user",
|
||||||
|
"type": "str",
|
||||||
|
"title": "OpenVPN gebruiker",
|
||||||
|
"default": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "openvpn_password",
|
||||||
|
"type": "str",
|
||||||
|
"title": "OpenVPN wachtwoord",
|
||||||
|
"default": "",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_gluetun",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Leidt al je downloadverkeer door een VPN. De downloadclients delen dan het netwerk van deze container, dus hun poorten komen hier te liggen."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Jellyseerr — verzoeken",
|
||||||
|
"items": [
|
||||||
{
|
{
|
||||||
"name": "port_jellyseerr",
|
"name": "port_jellyseerr",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"title": "Jellyseerr poort",
|
"title": "Poort",
|
||||||
"default": 5055,
|
"default": 5055,
|
||||||
"required": true,
|
"required": true
|
||||||
"description": "Webinterface voor gebruikers om films en series aan te vragen"
|
}
|
||||||
}
|
],
|
||||||
]
|
"toggle": "enable_jellyseerr",
|
||||||
|
"toggle_default": true,
|
||||||
|
"description": "Laat huisgenoten films en series aanvragen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Recyclarr — TRaSH-instellingen",
|
||||||
|
"items": [],
|
||||||
|
"toggle": "enable_recyclarr",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Synchroniseert kwaliteitsprofielen uit de TRaSH-gidsen naar Sonarr en Radarr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Unpackerr — archieven uitpakken",
|
||||||
|
"items": [],
|
||||||
|
"toggle": "enable_unpackerr",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Pakt gedownloade rar-archieven automatisch uit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Tdarr — hercoderen",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_tdarr",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Webinterface",
|
||||||
|
"default": 8265,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "port_tdarr_server",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Serverpoort",
|
||||||
|
"default": 8266,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_tdarr",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Zet je bibliotheek om naar een zuiniger formaat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Autobrr — automatisch grijpen",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_autobrr",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Poort",
|
||||||
|
"default": 7474,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_autobrr",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Reageert direct op aankondigingen in plaats van periodiek te zoeken"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Maintainerr — opruimen",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_maintainerr",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Poort",
|
||||||
|
"default": 6246,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_maintainerr",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Ruimt media op volgens regels die je zelf instelt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Huntarr — gaten opvullen",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "port_huntarr",
|
||||||
|
"type": "int",
|
||||||
|
"title": "Poort",
|
||||||
|
"default": 9705,
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toggle": "enable_huntarr",
|
||||||
|
"toggle_default": false,
|
||||||
|
"description": "Zoekt gericht naar ontbrekende en te verbeteren afleveringen"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,19 @@ def fields(d: Path) -> list[dict]:
|
||||||
for grp in t.get("variables", []) or []:
|
for grp in t.get("variables", []) or []:
|
||||||
gname = grp.get("title") or grp.get("name", "")
|
gname = grp.get("title") or grp.get("name", "")
|
||||||
toggle = grp.get("toggle")
|
toggle = grp.get("toggle")
|
||||||
|
if toggle:
|
||||||
|
# De groepsschakelaar is zelf geen item in template.json, waardoor
|
||||||
|
# hij nergens een startwaarde kreeg en dus altijd uit stond. Als
|
||||||
|
# synthetisch veld krijgt hij die wel; de UI toont hem als schakelaar
|
||||||
|
# in de kop en slaat hem over in de lijst eronder.
|
||||||
|
out.append({
|
||||||
|
"name": toggle, "type": "bool",
|
||||||
|
"title": gname, "group": gname, "group_toggle": toggle,
|
||||||
|
"default": bool(grp.get("toggle_default", True)),
|
||||||
|
"required": False, "options": [], "needs": [],
|
||||||
|
"placeholder": "", "description": grp.get("description", ""),
|
||||||
|
"is_group_toggle": True,
|
||||||
|
})
|
||||||
for item in grp.get("items", []) or []:
|
for item in grp.get("items", []) or []:
|
||||||
cfg = item.get("config") or {}
|
cfg = item.get("config") or {}
|
||||||
out.append({
|
out.append({
|
||||||
|
|
|
||||||
|
|
@ -1156,7 +1156,9 @@ tailwind.config = {
|
||||||
</summary>
|
</summary>
|
||||||
<div class="px-3.5 py-3 grid sm:grid-cols-2 gap-3" x-show="!grp.toggle || install.values[grp.toggle]">
|
<div class="px-3.5 py-3 grid sm:grid-cols-2 gap-3" x-show="!grp.toggle || install.values[grp.toggle]">
|
||||||
<template x-for="f in grp.items" :key="f.name">
|
<template x-for="f in grp.items" :key="f.name">
|
||||||
<div x-show="bpFieldVisible(f)" :class="f.type==='bool' ? 'sm:col-span-2' : ''">
|
<!-- De groepsschakelaar staat al in de kop; niet nog eens tonen -->
|
||||||
|
<div x-show="!f.is_group_toggle && bpFieldVisible(f)"
|
||||||
|
:class="f.type==='bool' ? 'sm:col-span-2' : ''">
|
||||||
<label class="form-label flex items-center gap-1"><span x-text="f.title"></span><span x-show="f.required" class="text-er">*</span></label>
|
<label class="form-label flex items-center gap-1"><span x-text="f.title"></span><span x-show="f.required" class="text-er">*</span></label>
|
||||||
<template x-if="f.type === 'enum'">
|
<template x-if="f.type === 'enum'">
|
||||||
<select class="form-input" x-model="install.values[f.name]"><template x-for="opt in f.options" :key="opt"><option :value="opt" x-text="opt"></option></template></select>
|
<select class="form-input" x-model="install.values[f.name]"><template x-for="opt in f.options" :key="opt"><option :value="opt" x-text="opt"></option></template></select>
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ GEDEELDE_POORTEN = {
|
||||||
443: {"nginx-proxy-manager", "traefik"},
|
443: {"nginx-proxy-manager", "traefik"},
|
||||||
53: {"adguard-home", "pihole"}, # dns-blokkers
|
53: {"adguard-home", "pihole"}, # dns-blokkers
|
||||||
5055: {"arr-stack", "jellyseerr"}, # zelfde app
|
5055: {"arr-stack", "jellyseerr"}, # zelfde app
|
||||||
|
6881: {"arr-stack", "qbittorrent"}, # zelfde app
|
||||||
# Hieronder: botsingen die er al waren vóór deze testsuite. De
|
# Hieronder: botsingen die er al waren vóór deze testsuite. De
|
||||||
# vrije-poortsuggestie bij installeren vangt ze op, dus ze zijn hinderlijk
|
# vrije-poortsuggestie bij installeren vangt ze op, dus ze zijn hinderlijk
|
||||||
# maar niet kapot. Nieuwe apps horen hier niet bij te komen.
|
# maar niet kapot. Nieuwe apps horen hier niet bij te komen.
|
||||||
|
|
@ -120,3 +121,86 @@ def test_poorten_botsen_niet_tussen_apps():
|
||||||
if len(apps) > 1 and not apps <= GEDEELDE_POORTEN.get(poort, set()):
|
if len(apps) > 1 and not apps <= GEDEELDE_POORTEN.get(poort, set()):
|
||||||
botsingen[poort] = sorted(apps)
|
botsingen[poort] = sorted(apps)
|
||||||
assert not botsingen, f"onbedoeld dubbele standaardpoorten: {botsingen}"
|
assert not botsingen, f"onbedoeld dubbele standaardpoorten: {botsingen}"
|
||||||
|
|
||||||
|
|
||||||
|
# ── ARR-stack: schakelbare onderdelen ────────────────────────────────────────
|
||||||
|
|
||||||
|
ARR = WORTEL / "apps" / "arr-stack"
|
||||||
|
|
||||||
|
|
||||||
|
def _arr_render(overrides: dict) -> dict:
|
||||||
|
velden = bp.fields(ARR)
|
||||||
|
waarden = {f["name"]: f["default"] for f in velden if f.get("default") is not None}
|
||||||
|
waarden["service_name"] = "arr"
|
||||||
|
waarden.update(overrides)
|
||||||
|
with tempfile.TemporaryDirectory() as t:
|
||||||
|
tmp = Path(t)
|
||||||
|
bp.render_to_dir(ARR, tmp, waarden)
|
||||||
|
return yaml.safe_load((tmp / "docker-compose.yml").read_text())
|
||||||
|
|
||||||
|
|
||||||
|
def _arr_schakelaars() -> list[str]:
|
||||||
|
return [f["name"] for f in bp.fields(ARR) if f.get("is_group_toggle")]
|
||||||
|
|
||||||
|
|
||||||
|
def test_arr_heeft_veel_schakelbare_onderdelen():
|
||||||
|
assert len(_arr_schakelaars()) >= 20
|
||||||
|
|
||||||
|
|
||||||
|
def test_arr_standaard_levert_een_werkbare_basis():
|
||||||
|
doc = _arr_render({})
|
||||||
|
diensten = {s.split("-", 1)[1] for s in doc["services"]}
|
||||||
|
assert {"sonarr", "radarr", "prowlarr", "bazarr"} <= diensten
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("schakelaar", _arr_schakelaars())
|
||||||
|
def test_arr_elk_onderdeel_levert_precies_een_service(schakelaar):
|
||||||
|
"""Aan betekent één service erbij, uit betekent geen enkel spoor."""
|
||||||
|
uit = {s: False for s in _arr_schakelaars()}
|
||||||
|
naam = schakelaar.replace("enable_", "")
|
||||||
|
|
||||||
|
doc = _arr_render({**uit, schakelaar: True})
|
||||||
|
assert set(doc["services"]) == {f"arr-{naam}"}
|
||||||
|
|
||||||
|
doc_uit = _arr_render(uit)
|
||||||
|
assert not (doc_uit or {}).get("services")
|
||||||
|
|
||||||
|
|
||||||
|
def test_arr_downloadclients_zitten_achter_de_vpn():
|
||||||
|
"""Met Gluetun delen de clients diens netwerknamespace en mogen ze geen
|
||||||
|
eigen poortmapping hebben — anders lekt het verkeer om de VPN heen."""
|
||||||
|
uit = {s: False for s in _arr_schakelaars()}
|
||||||
|
doc = _arr_render({**uit, "enable_gluetun": True, "enable_qbittorrent": True,
|
||||||
|
"enable_sabnzbd": True, "enable_nzbget": True})
|
||||||
|
for client in ("qbittorrent", "sabnzbd", "nzbget"):
|
||||||
|
svc = doc["services"][f"arr-{client}"]
|
||||||
|
assert svc.get("network_mode") == "service:arr-gluetun", client
|
||||||
|
assert "ports" not in svc, f"{client} heeft een eigen poort naast de VPN"
|
||||||
|
|
||||||
|
|
||||||
|
def test_arr_interne_poorten_botsen_niet_achter_de_vpn():
|
||||||
|
"""Alle clients delen één netwerknamespace, dus hun interne poorten moeten
|
||||||
|
verschillen. qBittorrent en SABnzbd wilden allebei 8080."""
|
||||||
|
uit = {s: False for s in _arr_schakelaars()}
|
||||||
|
doc = _arr_render({**uit, "enable_gluetun": True, "enable_qbittorrent": True,
|
||||||
|
"enable_sabnzbd": True, "enable_nzbget": True})
|
||||||
|
intern = [str(p).split(":", 1)[1] for p in doc["services"]["arr-gluetun"]["ports"]]
|
||||||
|
assert len(intern) == len(set(intern)), f"botsende interne poorten: {intern}"
|
||||||
|
|
||||||
|
|
||||||
|
def test_arr_zonder_vpn_eigen_poorten():
|
||||||
|
uit = {s: False for s in _arr_schakelaars()}
|
||||||
|
doc = _arr_render({**uit, "enable_qbittorrent": True})
|
||||||
|
svc = doc["services"]["arr-qbittorrent"]
|
||||||
|
assert "network_mode" not in svc
|
||||||
|
assert svc.get("ports")
|
||||||
|
|
||||||
|
|
||||||
|
def test_groepsschakelaar_krijgt_een_startwaarde():
|
||||||
|
"""Een groepsschakelaar was geen veld en werd dus nooit ge??nitialiseerd,
|
||||||
|
waardoor elk onderdeel standaard uit stond in de installatiemodal."""
|
||||||
|
schakelaars = [f for f in bp.fields(ARR) if f.get("is_group_toggle")]
|
||||||
|
assert schakelaars
|
||||||
|
assert all(isinstance(f["default"], bool) for f in schakelaars)
|
||||||
|
aan = [f["name"] for f in schakelaars if f["default"]]
|
||||||
|
assert "enable_sonarr" in aan and "enable_radarr" in aan
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue