Audiofy – Musikwünsche für Partys

Server (Website, Admin-Bereich, Player-API) und Player (raspotify +
Controller) mit Install-Skripten für Debian-Systeme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 19:16:39 +01:00
co-authored by Claude Opus 5.5
commit 3610de7bae
45 changed files with 5666 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
"""Audiofy-Web – Konfiguration aus der .env.
Pfad über die Umgebungsvariable AUDIOFY_ENV, Standard /opt/audiofy/.env.
Geheimnisse stehen nur dort (Rechte 600), nie im Code oder in Logs.
"""
import os
from dataclasses import dataclass
from functools import lru_cache
from pathlib import Path
def env_lesen(pfad: Path) -> dict:
"""Einfacher KEY=VALUE-Parser (Kommentare und Anführungszeichen erlaubt)."""
werte = {}
for zeile in pfad.read_text().splitlines():
zeile = zeile.strip()
if not zeile or zeile.startswith("#") or "=" not in zeile:
continue
key, _, wert = zeile.partition("=")
werte[key.strip()] = wert.strip().strip('"').strip("'")
return werte
@dataclass(frozen=True)
class Konfig:
env_pfad: Path
db_pfad: Path
player_api_token: str
spotify_client_id: str
spotify_client_secret: str
spotify_refresh_token: str
admin_passwort_hash: str
session_secret: str
playlist_id: str # nur Startwert – danach gilt die Einstellung in der Datenbank
cookie_secure: bool = True # nur für lokale Tests über http auf 0 setzen
public_url: str = "" # z. B. https://musik.example.org (für Einladungslink/QR-Code)
turnstile_site_key: str = "" # Cloudflare Turnstile (öffentlich)
turnstile_secret: str = "" # Cloudflare Turnstile (geheim)
def env_wert_setzen(pfad: Path, key: str, wert: str) -> None:
"""Setzt KEY=wert in der .env – direkt in der Datei (der Ordner ist für den Dienst nicht beschreibbar)."""
zeilen = pfad.read_text().splitlines() if pfad.is_file() else []
neu = [z for z in zeilen if not z.strip().startswith(f"{key}=")]
neu.append(f"{key}={wert}")
fd = os.open(pfad, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
with os.fdopen(fd, "w") as f:
f.write("\n".join(neu) + "\n")
@lru_cache
def konfig() -> Konfig:
pfad = Path(os.environ.get("AUDIOFY_ENV", "/opt/audiofy/.env"))
werte = env_lesen(pfad) if pfad.is_file() else {}
return Konfig(
env_pfad=pfad,
db_pfad=Path(werte.get("DB_PATH") or "/opt/audiofy/data/audiofy.db"),
player_api_token=werte.get("PLAYER_API_TOKEN") or werte.get("PI_API_TOKEN", ""), # alter Name
spotify_client_id=werte.get("SPOTIFY_CLIENT_ID", ""),
spotify_client_secret=werte.get("SPOTIFY_CLIENT_SECRET", ""),
spotify_refresh_token=werte.get("SPOTIFY_REFRESH_TOKEN", ""),
admin_passwort_hash=werte.get("ADMIN_PASSWORD_HASH", ""),
session_secret=werte.get("SESSION_SECRET", ""),
playlist_id=werte.get("SPOTIFY_PLAYLIST_ID", ""),
cookie_secure=werte.get("COOKIE_SECURE", "1") != "0",
public_url=werte.get("PUBLIC_URL", "").rstrip("/"),
turnstile_site_key=werte.get("TURNSTILE_SITE_KEY", ""),
turnstile_secret=werte.get("TURNSTILE_SECRET_KEY", ""),
)