Files
weircon-front/config.py
T

142 lines
8.3 KiB
Python

"""Konfiguration (env) + konstanter for portalen."""
import os
from pathlib import Path
BASE = Path(__file__).resolve().parent
DATA = Path(os.environ.get("PORTAL_DATA", "/opt/portal/data"))
DATA.mkdir(parents=True, exist_ok=True)
AUTHENTIK = os.environ["AUTHENTIK_BASE"].rstrip("/")
CLIENT_ID = os.environ["OIDC_CLIENT_ID"]
CLIENT_SECRET = os.environ["OIDC_CLIENT_SECRET"]
API_TOKEN = os.environ["AUTHENTIK_API_TOKEN"]
SECRET_KEY = os.environ["SESSION_SECRET"]
REDIRECT_URI = os.environ.get("OIDC_REDIRECT_URI", "https://weircon.dk/auth/callback")
ADMIN_GROUP = os.environ.get("ADMIN_GROUP", "authentik Admins")
# Hvem der må høre familiens podcasts (/podcast); admins kan altid. Kommasepareret:
# Familie er den nære familie, Gramps er slægten der kun har Gramps + podcast + portal.
PODCAST_GROUPS = {g.strip() for g in os.environ.get("PODCAST_GROUP", "Familie,Gramps").split(",") if g.strip()}
MATOMO_BASE = os.environ.get("MATOMO_BASE", "https://matomo.weircon.dk").rstrip("/")
MATOMO_TOKEN = os.environ.get("MATOMO_TOKEN", "")
MATOMO_SITE = os.environ.get("MATOMO_SITE", "2")
RP_BASE_URL = os.environ.get("RP_BASE_URL", "https://rp.weircon.dk").rstrip("/")
RP_API_KEY = os.environ.get("RP_API_KEY", "")
ASSETS_VERSION_URL = os.environ.get("ASSETS_VERSION_URL", "https://assets.weircon.dk/VERSION")
GEOIP_DB = os.environ.get("GEOIP_DB", str(DATA / "dbip-country.mmdb"))
GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", "") # valgfri: hæver GitHub-rate-limit 60→5000/t
NTFY_URL = os.environ.get("NTFY_URL", "") # fx https://ntfy.weircon.dk
NTFY_TOPIC = os.environ.get("NTFY_TOPIC", "ops")
NTFY_TOKEN = os.environ.get("NTFY_TOKEN", "") # tk_… publish-token
DISCO_BASE_URL = os.environ.get("DISCO_BASE_URL", "") # DiscoPanel Connect-RPC
DISCO_API_TOKEN = os.environ.get("DISCO_API_TOKEN", "")
DISCO_PANEL_URL = os.environ.get("DISCO_PANEL_URL", "") # bruger-vendt panel-URL til forsiden
USERPREFS = DATA / "userprefs.json"
IP_LABELS_LOCAL = DATA / "ip_labels.json"
IP_LABELS_REMOTE = os.environ.get("IP_LABELS_REMOTE", "")
SETTINGS_PATH = DATA / "settings.json"
MCP_REGISTRY = DATA / "mcp_registry.json"
MCP_SELF_URL = os.environ.get("MCP_SELF_URL", "https://weircon.dk/mcp")
# ---- Medie-oprydning (Emby + Sonarr/Radarr) ----
EMBY_URL = os.environ.get("EMBY_URL", "").rstrip("/")
EMBY_API_KEY = os.environ.get("EMBY_API_KEY", "")
RADARR_URL = os.environ.get("RADARR_URL", "").rstrip("/")
RADARR_API_KEY = os.environ.get("RADARR_API_KEY", "")
SONARR_URL = os.environ.get("SONARR_URL", "").rstrip("/")
SONARR_API_KEY = os.environ.get("SONARR_API_KEY", "")
NTFY_MEDIA_TOPIC = os.environ.get("NTFY_MEDIA_TOPIC", "media")
MEDIA_STATE_PATH = DATA / "media_state.json"
MEDIA_SETTINGS_PATH = DATA / "media_settings.json"
# Standardindstillinger — kan redigeres i /admin/media:
MEDIA_DEFAULTS = {
"enabled": False, # dry-run indtil du selv slår sletning til
"age_days": 90, # tilføjet for mindst så længe siden
"grace_days": 14, # "på vej ud"-vindue før sletning
"disk_throttle": True, # slet kun når lageret er over disk_high %
"disk_high": 85, # start sletning over denne fyldningsgrad
"disk_low": 80, # stop igen når under denne
"do_movies": True,
"do_series": True,
}
# ---- YouTube offline (yt-dlp + Emby) ----
YT_DOWNLOAD_DIR = os.environ.get("YT_DOWNLOAD_DIR", "/media/yt-offline")
YT_DLP_BIN = os.environ.get("YT_DLP_BIN", "/usr/local/bin/yt-dlp")
YT_STATE_PATH = DATA / "yt_state.json"
YT_SETTINGS_PATH = DATA / "yt_settings.json"
# Standardindstillinger - kan redigeres i /admin/yt:
YT_DEFAULTS = {
"enabled": True, # slet sete videoer automatisk
"grace_days": 7, # dage fra markeret-som-set til sletning
# H.264 foretrukket: medieserverens Pascal-GPU kan ikke afkode AV1, og AV1 kan
# mange afspillere slet ikke offline. Falder tilbage til alt-andet hvis
# YouTube ikke har H.264 i den oenskede oploesning.
"quality": "bestvideo[vcodec^=avc1][height<=1080]+bestaudio[acodec^=mp4a]/bestvideo[vcodec^=avc1][height<=1080]+bestaudio/best[vcodec^=avc1][height<=1080]/bestvideo[height<=1080]+bestaudio/best",
"sponsorblock": True, # klip sponsorater ud, behold resten som kapitler
"subtitles": True, # rigtige undertekster, ellers YouTubes automatiske
"sub_langs": "da,en,-live_chat",
"metadata": True, # titel/kanal/dato + miniature + kapitler i filen
"library_name": "YouTube",
}
# ---- e-pub (ebog/lydbog fra en biblioteks-reference) ----
EPUB_SETTINGS_PATH = DATA / "epub_settings.json"
# Per-job-mapper (output + TMP) oprettes her og slettes efter hentning/udløb.
EPUB_SCRATCH = Path(os.environ.get("EPUB_SCRATCH", str(DATA / "e-pub-scratch")))
# Standardindstillinger - kan redigeres i /admin/epub (RP_API_KEY/RP_BASE_URL kommer fra env ovenfor):
EPUB_DEFAULTS = {
"max_concurrent_jobs": 2, # samtidige jobs; resten venter i kø
"job_timeout_seconds": 1200, # et job dræbes efter så lang tid
# Fil + job slettes så længe efter jobbet sluttede (også hen over genstarter). Et døgn: nok til
# at hente filen på en anden enhed senere, og bogen ligger i forvejen i CWA/Audiobookshelf.
"output_ttl_seconds": 86400,
"tools_dir": "/opt/portal/tools/e-pub", # mappen med fetch.sh m.fl.
"rp_required": True, # job fejler (exit 4) frem for at gå direkte ud uden proxy-nøgle
"allowed_group": "", # tom = kun admins må bruge /e-pub
"cwa_ingest_dir": "/media/cwa-ingest", # Calibre-Web Automateds indbakke (tom = ingen knap)
"abs_dir": "/media/audiobooks", # Audiobookshelf-bibliotekets mappe (tom = ingen knap)
"auto_send": True, # færdige filer sendes selv til CWA/Audiobookshelf
}
GROUP_ORDER = {n: i for i, n in enumerate(
["Home", "Familie", "Medie", "Social", "AI", "Office", "Finans", "dev", "game", "Admin"])}
ADMIN_MODULES = [
{"key": "ip-labels", "title": "IP → label & land", "icon": "🌍",
"desc": "Mærk kendte IP-adresser (netværk/land) i statistikken."},
{"key": "cookies", "title": "Cookie-tekster", "icon": "🍪",
"desc": "Teksten på cookie-banneret og /cookies-siden."},
{"key": "stats", "title": "Statistik", "icon": "📊",
"desc": "Hurtigt overblik fra Matomo."},
{"key": "apps", "title": "App-beskrivelser & grupper", "icon": "🧩",
"desc": "Rediger beskrivelse og gruppe på dine Authentik-apps."},
{"key": "ops", "title": "Drift / egress", "icon": "🛰️",
"desc": "Static-assets-version + random-proxy egress, rollover & inflight."},
{"key": "users", "title": "Brugere", "icon": "👤",
"desc": "Opret og administrér brugere + adgang (via grupper)."},
{"key": "invitations", "title": "Invitationer", "icon": "✉️",
"desc": "Lav et invitationslink med gruppe og udløbstid. Modtageren opretter selv sit login."},
{"key": "groups", "title": "Grupper", "icon": "👥",
"desc": "Grupper og medlemmer — styrer hvilke services brugere har adgang til."},
{"key": "access", "title": "Adgang til services", "icon": "🔐",
"desc": "Hvilke brugere og grupper kan tilgå hver enkelt service."},
{"key": "media", "title": "Medie-oprydning", "icon": "🎬",
"desc": "Slet aldrig-set film & serier automatisk — med karens, behold-liste og ntfy."},
{"key": "yt", "title": "YouTube offline", "icon": "📺",
"desc": "Hent YouTube-videoer til Emby - og slet dem igen naar de er set."},
{"key": "epub", "title": "E-bøger & lydbøger", "icon": "📚",
"desc": "/e-pub: hvem der må bruge den, samtidige jobs, timeout og hvor længe filer ligger."},
{"key": "secrets", "title": "Hemmeligheder til Claude", "icon": "🔏",
"desc": "Giv et token eller kodeord til serveren krypteret, uden at skrive det i chatten."},
{"key": "podcast", "title": "Podcast", "icon": "🎙️",
"desc": "Slægtens Stemmer: udgiv kladder og se/træk lytternes personlige feed-adresser tilbage."},
{"key": "erindringer", "title": "Erindringer", "icon": "🎤",
"desc": "Familien fortæller minder og dagbog til en AI-interviewer: projekter, gæstelinks, klip og eksport."},
{"key": "claude-login", "title": "Claude-login", "icon": "🤖",
"desc": "Log Claude på serveren ind igen fra telefonen, uden terminal."},
{"key": "mcp-keys", "title": "MCP-nøgler", "icon": "🔑",
"desc": "Opret og se API-nøgler til alle MCP-servere (crawlkit, Gitea, HA, Paperless, portal)."},
]