fix(downloads): address code-review findings on the R2.5 mini-epic

- redownload: never clobber a co-held (deduped) asset. Drop the force-reset-to-pending;
  _release_asset already deletes+recreates a solo asset (genuine re-fetch), while a shared
  ready asset is left intact and the re-queued job re-points to it via _finish_from_cache —
  so one user's re-download can't delete another's file mid-serve (finding #1).
- redownload: reset queue_pos to the tail so a re-download doesn't front-run newer queued
  jobs on the worker's `ORDER BY queue_pos` claim (finding #3). Made service.next_queue_pos public.
- formats: video-only mp4 selector prefers every video-only option before any progressive
  `best`, so a "Video only" download stays audio-free whenever a video-only stream exists (#2).
- titles: a title that is only the engagement prefix no longer resurrects the stripped stats
  (return the stripped text / empty, not the raw) (#4).
- worker: probe the file's duration when yt-dlp gave none, so a long re-encode shows real
  progress instead of a frozen 0% (#5); tighten the ensure_browser_playable docstring to its
  actual mp4-profile scope (#6).
This commit is contained in:
2026-07-22 02:21:05 +02:00
parent e46f215ada
commit cae5702fbb
8 changed files with 55 additions and 21 deletions
+6 -7
View File
@@ -465,17 +465,15 @@ def redownload_download(
if job.status in ("queued", "running", "paused"):
raise HTTPException(status_code=409, detail="This download is still in progress.")
# Drop this job's hold on its current asset (deletes the file if it was the last holder), then
# resolve the asset for the current spec and force a genuinely fresh fetch even on a cache hit.
# Drop this job's hold on its current asset. `_release_asset` deletes the file + row when THIS
# job was the last holder (ref→0, ready) — so a solo re-download genuinely re-fetches. When the
# asset is still shared by another job/user we must NOT delete it out from under them: leaving it
# `ready` means the re-queued job just re-points to the shared file (the worker short-circuits a
# ready asset via `_finish_from_cache`), which is why there's no force-reset-to-pending here.
_release_asset(db, job)
spec = formats.normalize(job.profile_snapshot)
sig = formats.format_sig(spec)
asset = service.get_or_create_asset(db, job.source_kind, job.source_ref, sig)
if asset.status == "ready":
if asset.rel_path:
storage.delete_asset_files(settings.download_root, asset.rel_path)
asset.rel_path = None
asset.status = "pending"
service.populate_from_catalog(db, asset)
asset.ref_count = (asset.ref_count or 0) + 1
@@ -486,6 +484,7 @@ def redownload_download(
job.error = None
job.speed_bps = None
job.eta_s = None
job.queue_pos = service.next_queue_pos(db) # tail of the queue, not its stale original slot
db.commit()
return _serialize_job(db, job)