Files
99admandClaude Opus 5.5 fc15f2b933 Umbenennung: Audiofy heißt jetzt Playwish
Name, Seitentitel, Dienste (playwish-web, playwish-controller), Dienst-Benutzer
(playwish), Pfade (/opt/playwish, /usr/local/src/playwish), Vorlagen und
Repository-Adresse. „Audiofy“ war bereits von mehreren Produkten belegt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 20:27:59 +01:00

51 lines
1.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Playwish-Web – FastAPI-Anwendung.
Start (Server): uvicorn app.main:app --host 127.0.0.1 --port 8000 --workers 1 --no-access-log
Caddy terminiert HTTPS und leitet an 127.0.0.1:8000 weiter.
"""
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from . import admin, db, gaeste, player_api
from .config import konfig
# Streng: nur eigene Skripte/Styles, Cover-Bilder vom Spotify-CDN, Turnstile von Cloudflare
CSP = ("default-src 'self'; script-src 'self' https://challenges.cloudflare.com; style-src 'self'; "
"img-src 'self' https://i.scdn.co data:; frame-src https://challenges.cloudflare.com; "
"connect-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'")
@asynccontextmanager
async def lifespan(app: FastAPI):
k = konfig()
db.initialisieren(k.db_pfad, k.playlist_id)
yield
# Keine automatische API-Doku öffentlich ausliefern
app = FastAPI(title="Playwish – Musikwünsche", lifespan=lifespan, docs_url=None, redoc_url=None, openapi_url=None)
@app.middleware("http")
async def sicherheits_header(request: Request, call_next):
antwort = await call_next(request)
antwort.headers.setdefault("Content-Security-Policy", CSP)
if request.url.path.startswith("/api/"):
antwort.headers.setdefault("Cache-Control", "no-store")
return antwort
app.include_router(player_api.router, prefix="/api/player")
app.include_router(player_api.router, prefix="/api/pi", include_in_schema=False) # alter Pfad, für ältere Player
app.include_router(gaeste.router)
app.include_router(admin.router)
app.mount("/static", StaticFiles(directory=gaeste.STATIC), name="static")
@app.get("/healthz")
def healthz() -> dict:
return {"ok": True}