siftlode/backend/app/routes
npeter83 cac5526399 chore(downloads): C3-C6 — DRY the source-URL, filename, and serialize helpers
- C3: `_reference_url` (downloads.py) and public.py's inline source-URL block were
  the same rule → extract `service.reference_url(job, asset)`; both surfaces now
  share it so the "downloaded from" link can't drift between them.
- C4: Content-Disposition filename derivation (ext pick + doubled-ext strip + join)
  was duplicated in download_file and watch_file → extract
  `storage.download_filename(display_name, container, path)`.
- C5: inline the one-line `_clean_basename` passthrough (folded into C4).
- C6: the `db.get(MediaAsset, job.asset_id) if job.asset_id else None; _serialize(...)`
  resolve-then-serialize dance was repeated across 6 single-job handlers → fold into
  `_serialize_job(db, job)`. (File-serving handlers that use the asset for their own
  checks keep their explicit resolve.)

Behavior-neutral; ruff/parse clean, localdev boots, downloads routes load.
2026-07-11 05:47:51 +02:00
..
__init__.py feat: M1 foundation — compose stack, FastAPI, Google OAuth, encrypted tokens 2026-06-11 01:01:37 +02:00
admin.py feat(search): ephemeral results, count selector, blocklist, new-first ordering (backend) 2026-07-01 00:42:32 +02:00
channels.py chore: Phase 1 hygiene — drop unused imports/exports/types (behavior-neutral) 2026-07-11 04:47:08 +02:00
config.py feat(config): DB-backed system_config infrastructure + SMTP group 2026-06-19 12:22:36 +02:00
downloads.py chore(downloads): C3-C6 — DRY the source-URL, filename, and serialize helpers 2026-07-11 05:47:51 +02:00
feed.py feat(search): ephemeral results, count selector, blocklist, new-first ordering (backend) 2026-07-01 00:42:32 +02:00
health.py feat: M1 foundation — compose stack, FastAPI, Google OAuth, encrypted tokens 2026-06-11 01:01:37 +02:00
me.py feat(plex): P1 frontend — Plex feed source, browse/search, show drill-down 2026-07-05 02:32:00 +02:00
messages.py feat(auth): per-tab account — different account per browser tab 2026-07-01 23:43:35 +02:00
notifications.py feat(notifications): durable per-user inbox (P1) + maintenance schema 2026-06-18 03:20:17 +02:00
playlists.py refactor(playlists,feed): share feed-row projection & playlist helpers 2026-06-26 03:15:53 +02:00
plex.py fix(plex): genre facet offers only co-occurring genres in AND mode 2026-07-11 03:41:17 +02:00
public.py chore(downloads): C3-C6 — DRY the source-URL, filename, and serialize helpers 2026-07-11 05:47:51 +02:00
quota.py feat(stats): per-user API quota attribution + admin usage page 2026-06-12 02:47:55 +02:00
saved_views.py feat(views): saved-views backend — table, model, CRUD + reorder API 2026-07-01 03:17:36 +02:00
scheduler.py feat(config): move operational params to DB (quota/backfill/shorts/batch) 2026-06-19 13:07:45 +02:00
search.py feat(search): ephemeral results, count selector, blocklist, new-first ordering (backend) 2026-07-01 00:42:32 +02:00
setup.py feat(setup): install-wizard step endpoints (epic 6c, API) 2026-06-21 00:40:54 +02:00
sync.py refactor(backend): quota.measured helper, consistent admin gating, messageable predicate 2026-06-26 03:15:53 +02:00
tags.py refactor(auth): centralize token hashing, email validation & admin gating 2026-06-26 03:15:36 +02:00
version.py feat(version): /api/version + build-time version/commit stamping 2026-06-15 00:06:57 +02:00