mirror of
https://github.com/xpltdco/media-rip.git
synced 2026-04-03 10:54:00 -06:00
Privacy Mode feature: - Toggle in Admin > Settings enables automatic purge of download history, session logs, and files after configurable retention period - Default retention: 24 hours when privacy mode is on - Configurable 1-8760 hours via number input - When enabled, starts purge scheduler (every 30 min) if not running - When disabled, data persists indefinitely Admin panel consolidation: - Removed separate 'Purge' tab — manual purge moved to Settings - Settings tab order: Privacy Mode > Manual Purge > Welcome Message > Output Formats > Change Password - Toggle switch UI with accent color and smooth animation - Retention input with left accent border and unit label Backend: - PurgeConfig: added privacy_mode (bool) and privacy_retention_hours - Purge service: uses privacy_retention_hours when privacy mode active - PUT /admin/settings: accepts privacy_mode + privacy_retention_hours - GET /config/public: exposes privacy settings to frontend - Runtime overrides passed to purge service via config._runtime_overrides
146 lines
4.1 KiB
Python
146 lines
4.1 KiB
Python
"""Application configuration via pydantic-settings.
|
|
|
|
Loads settings from (highest → lowest priority):
|
|
1. Environment variables (prefix ``MEDIARIP``, nested delimiter ``__``)
|
|
2. YAML config file (optional — zero-config if missing)
|
|
3. Init kwargs
|
|
4. .env file
|
|
|
|
Zero-config mode: if no YAML file is provided or the file doesn't exist,
|
|
all settings fall back to sensible defaults.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel
|
|
from pydantic_settings import (
|
|
BaseSettings,
|
|
PydanticBaseSettingsSource,
|
|
SettingsConfigDict,
|
|
YamlConfigSettingsSource,
|
|
)
|
|
|
|
logger = logging.getLogger("mediarip.config")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Nested config sections
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class ServerConfig(BaseModel):
|
|
"""Core server settings."""
|
|
|
|
host: str = "0.0.0.0"
|
|
port: int = 8000
|
|
log_level: str = "info"
|
|
db_path: str = "mediarip.db"
|
|
|
|
|
|
class DownloadsConfig(BaseModel):
|
|
"""Download behaviour defaults."""
|
|
|
|
output_dir: str = "/downloads"
|
|
max_concurrent: int = 3
|
|
source_templates: dict[str, str] = {
|
|
"youtube.com": "%(uploader)s/%(title)s.%(ext)s",
|
|
"soundcloud.com": "%(uploader)s/%(title)s.%(ext)s",
|
|
"*": "%(title)s.%(ext)s",
|
|
}
|
|
default_template: str = "%(title)s.%(ext)s"
|
|
|
|
|
|
class SessionConfig(BaseModel):
|
|
"""Session management settings."""
|
|
|
|
mode: str = "isolated"
|
|
timeout_hours: int = 72
|
|
|
|
|
|
class PurgeConfig(BaseModel):
|
|
"""Automatic purge / cleanup settings."""
|
|
|
|
enabled: bool = False
|
|
max_age_hours: int = 168 # 7 days
|
|
cron: str = "0 3 * * *" # 3 AM daily
|
|
privacy_mode: bool = False
|
|
privacy_retention_hours: int = 24 # default when privacy mode enabled
|
|
|
|
|
|
class UIConfig(BaseModel):
|
|
"""UI preferences."""
|
|
|
|
default_theme: str = "dark"
|
|
welcome_message: str = "Paste any video or audio URL. We rip it, you download it. No accounts, no tracking."
|
|
|
|
|
|
class AdminConfig(BaseModel):
|
|
"""Admin panel settings."""
|
|
|
|
enabled: bool = False
|
|
username: str = "admin"
|
|
password_hash: str = ""
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Safe YAML source — tolerates missing files
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class _SafeYamlSource(YamlConfigSettingsSource):
|
|
"""YAML source that returns an empty dict when the file is missing."""
|
|
|
|
def __call__(self) -> dict[str, Any]:
|
|
yaml_file = self.yaml_file_path
|
|
if yaml_file is None:
|
|
return {}
|
|
if not Path(yaml_file).is_file():
|
|
logger.debug("YAML config file not found at %s — using defaults", yaml_file)
|
|
return {}
|
|
return super().__call__()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Root config
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class AppConfig(BaseSettings):
|
|
"""Top-level application configuration.
|
|
|
|
Priority (highest wins): env vars → YAML file → init kwargs → .env file.
|
|
"""
|
|
|
|
model_config = SettingsConfigDict(
|
|
env_prefix="MEDIARIP__",
|
|
env_nested_delimiter="__",
|
|
yaml_file=None,
|
|
)
|
|
|
|
server: ServerConfig = ServerConfig()
|
|
downloads: DownloadsConfig = DownloadsConfig()
|
|
session: SessionConfig = SessionConfig()
|
|
purge: PurgeConfig = PurgeConfig()
|
|
ui: UIConfig = UIConfig()
|
|
admin: AdminConfig = AdminConfig()
|
|
themes_dir: str = "./themes"
|
|
|
|
@classmethod
|
|
def settings_customise_sources(
|
|
cls,
|
|
settings_cls: type[BaseSettings],
|
|
init_settings: PydanticBaseSettingsSource,
|
|
env_settings: PydanticBaseSettingsSource,
|
|
dotenv_settings: PydanticBaseSettingsSource,
|
|
file_secret_settings: PydanticBaseSettingsSource,
|
|
) -> tuple[PydanticBaseSettingsSource, ...]:
|
|
return (
|
|
env_settings,
|
|
_SafeYamlSource(settings_cls),
|
|
init_settings,
|
|
dotenv_settings,
|
|
)
|