2c86d7973f
- Navidrome password is now passed to curl via stdin (--data-urlencode "p@-") in navidrome-scan.sh and pipeline-status.sh, so it no longer appears in ps/proc. Verified the query sent is identical and a live scan still triggers. - MIN_ARTIST_DIRS (the share-health gate) is now a setting, threaded through to the pipeline env, so a user with a small library can lower it instead of the scan/sync being permanently blocked by the hardcoded 500. - /auth/logout is now POST-only (with a nav form + aria-label), so a drive-by GET can't log the user out; enforced allowed_email already landed separately. - view_log now confirms the run's log_path resolves under the logs dir before serving it (defense in depth). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
82 lines
3.2 KiB
Python
82 lines
3.2 KiB
Python
from pathlib import Path
|
|
|
|
from pydantic import AliasChoices, Field
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
model_config = SettingsConfigDict(env_prefix="", extra="ignore")
|
|
|
|
# Mount points — see docker-compose.snippet.yml. Two volumes total:
|
|
# everything audio-related under MUSIC_DATA_DIR, everything else
|
|
# (app DB, beets config+DB, rendered pipeline credentials, job logs)
|
|
# under ALEMBIC_CONFIG_DIR.
|
|
music_data_dir: Path = Path("/data/music")
|
|
alembic_config_dir: Path = Path("/config")
|
|
pipeline_dir: Path = Path("/app/pipeline")
|
|
|
|
alembic_port: int = 8420
|
|
|
|
# Fernet key for the `secrets` table, read from a Docker secret file
|
|
# (not a plain env var) — see docker-compose.snippet.yml's `secrets:` block.
|
|
encryption_key_file: Path = Path("/run/secrets/alembic_master_key")
|
|
|
|
# Session cookie signing secret for Starlette's SessionMiddleware.
|
|
# Left empty by default on purpose: an empty/placeholder value would let
|
|
# anyone forge a signed session cookie and skip login entirely. When this
|
|
# is unset, resolve_session_secret() generates and persists a random one
|
|
# to the config volume instead of falling back to a known constant.
|
|
session_secret: str = ""
|
|
|
|
# Pocket ID OIDC client, registered once in the Pocket ID admin UI
|
|
# (redirect URI: https://<alembic-host>/auth/callback).
|
|
pocketid_issuer: str = ""
|
|
pocketid_client_id: str = ""
|
|
pocketid_client_secret: str = ""
|
|
|
|
# Defense-in-depth: this is a single-user app. If set, only this email
|
|
# may complete login even if Pocket ID ever grows a second account.
|
|
allowed_email: str = ""
|
|
|
|
# IANA timezone (e.g. "America/Edmonton") used for all scheduling and for
|
|
# times shown in the UI and the status report. Defaults to UTC so a fresh
|
|
# install behaves predictably anywhere. Reads the standard Docker `TZ`
|
|
# variable, or `ALEMBIC_TIMEZONE` if you'd rather be explicit. An
|
|
# unrecognized value falls back to UTC (see scheduler_service).
|
|
timezone: str = Field(
|
|
default="UTC",
|
|
validation_alias=AliasChoices("TZ", "ALEMBIC_TIMEZONE", "TIMEZONE"),
|
|
)
|
|
|
|
# Share-health gate: the Navidrome scan and Bandcamp sync abort if the
|
|
# library has fewer than this many artist folders, to catch a half-mounted
|
|
# or empty share before it does damage. The default suits a large library;
|
|
# set it lower (via env MIN_ARTIST_DIRS) if yours is small.
|
|
min_artist_dirs: int = 500
|
|
|
|
@property
|
|
def beets_dir(self) -> Path:
|
|
return self.alembic_config_dir / "beets"
|
|
|
|
@property
|
|
def beets_db_path(self) -> Path:
|
|
return self.beets_dir / "data" / "beets_library.db"
|
|
|
|
@property
|
|
def pipeline_config_dir(self) -> Path:
|
|
"""Rendered/instance pipeline config: per-playlist .conf files,
|
|
credential env files, editable lists — NOT the static code in
|
|
pipeline_dir, which is baked into the image."""
|
|
return self.alembic_config_dir / "pipeline"
|
|
|
|
@property
|
|
def app_db_path(self) -> Path:
|
|
return self.alembic_config_dir / "alembic.db"
|
|
|
|
@property
|
|
def logs_dir(self) -> Path:
|
|
return self.alembic_config_dir / "logs"
|
|
|
|
|
|
settings = Settings()
|