fix(downloads): repair 5 confirmed backend bugs (B1-B5)
- B1 (sticky errored asset): get_or_create_asset now resets a reused status=='error' asset back to 'pending' (+clears the error), so a fresh enqueue/edit of a once-failed (source,format) pair actually re-downloads instead of the worker short-circuiting the new job with the stale error. Errored assets carry no expires_at, so without this the pair was permanently poisoned for all users until someone hit resume. - B2 (ref_count leak): _release_asset counts 'error' as a holding state, so deleting an errored job decrements the ref_count that enqueue always incremented (the worker never decrements on failure). Errored rows are deliberately NOT deleted here — a concurrent B1 reuse could otherwise be lost-updated + FK-nulled; the row is fileless and harmless. - B3: admin storage dashboard reads sysconfig.get_int(db,'download_total_max_bytes') (the admin-editable DB value GC enforces) instead of the raw env default. - B4: the single-trim branch of normalize_edit_spec guards its float() coercion like the crop/segments branches — a malformed trim now yields a 400, not an unhandled 500. - B5: formats.normalize guards int(max_height) → falls back to "best" instead of 500. Reviewed (race in an earlier B2 draft caught + fixed); localdev boots, B4/B5 unit-verified.
This commit is contained in:
parent
bf8d4b94a0
commit
7a6f351e64
4 changed files with 38 additions and 11 deletions
|
|
@ -79,13 +79,17 @@ def normalize_edit_spec(spec: dict | None) -> dict:
|
|||
# Single TRIM (one output file; the frontend fans a "separate" split out into N of these).
|
||||
trim = spec.get("trim") or {}
|
||||
if trim:
|
||||
start = max(0.0, float(trim.get("start_s") or 0.0))
|
||||
end_raw = trim.get("end_s")
|
||||
# Guard the numeric coercion like the crop/segments branches do — a malformed value must
|
||||
# drop the trim (→ empty spec → 400 EditError), not raise an unhandled 500.
|
||||
try:
|
||||
start = max(0.0, float(trim.get("start_s") or 0.0))
|
||||
end_raw = trim.get("end_s")
|
||||
end = float(end_raw) if end_raw is not None else None
|
||||
except (TypeError, ValueError):
|
||||
start, end = 0.0, None
|
||||
t: dict = {"start_s": round(start, 3)}
|
||||
if end_raw is not None:
|
||||
end = float(end_raw)
|
||||
if end > start:
|
||||
t["end_s"] = round(end, 3)
|
||||
if end is not None and end > start:
|
||||
t["end_s"] = round(end, 3)
|
||||
# A trim with only a start (open-ended) is valid (cut to the end).
|
||||
if t.get("start_s") or "end_s" in t:
|
||||
out["trim"] = t
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue