feat(downloads): M1 — schema, config, worker container, deps

- models: MediaAsset (shared file cache, unique on source+format_sig), DownloadJob
  (per-user request), DownloadProfile (presets), DownloadShare (ACL), DownloadQuota
- migrations 0036 (5 tables) + 0037 (6 builtin presets)
- sysconfig 'downloads' group (per-user defaults, retention/GC, layout, worker concurrency)
- config: DOWNLOAD_ROOT / WORKER_ENABLED env + download defaults
- deps: yt-dlp in requirements, ffmpeg in Dockerfile runtime stage
- worker: dedicated container (python -m app.worker), thin idle entry (loop lands in M2)
- localdev compose: worker service + downloads bind-mount; gitignore downloads/
This commit is contained in:
npeter83 2026-07-02 23:57:40 +02:00
parent 9ca90f515c
commit 317750e491
10 changed files with 496 additions and 0 deletions

View file

@ -66,6 +66,15 @@ SPECS: tuple[ConfigSpec, ...] = (
ConfigSpec("google_client_secret", "str", "google", "google_client_secret", secret=True),
# --- Access / registration ---
ConfigSpec("allow_registration", "bool", "access", "allow_registration"),
# --- Download center (yt-dlp) — per-user defaults + retention/GC + layout ---
ConfigSpec("download_default_max_bytes", "int", "downloads", "download_default_max_bytes", min=0),
ConfigSpec("download_default_max_concurrent", "int", "downloads", "download_default_max_concurrent", min=1, max=20),
ConfigSpec("download_default_max_jobs", "int", "downloads", "download_default_max_jobs", min=1, max=100_000),
ConfigSpec("download_retention_days", "int", "downloads", "download_retention_days", min=0, max=3_650),
ConfigSpec("download_gc_grace_days", "int", "downloads", "download_gc_grace_days", min=0, max=3_650),
ConfigSpec("download_layout", "str", "downloads", "download_layout"),
ConfigSpec("download_worker_concurrency", "int", "downloads", "download_worker_concurrency", min=1, max=16),
ConfigSpec("sponsorblock_default", "bool", "downloads", "sponsorblock_default"),
)
_BY_KEY: dict[str, ConfigSpec] = {s.key: s for s in SPECS}