Merge branch 'dev' into chore/code-hygiene

This commit is contained in:
npeter83 2026-07-11 16:22:39 +02:00
commit aee1bdc85d
4 changed files with 38 additions and 11 deletions

View file

@ -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

View file

@ -62,7 +62,12 @@ def normalize(spec: dict) -> dict:
if s["mode"] not in ("av", "v", "a"):
s["mode"] = "av"
if s["max_height"] is not None:
s["max_height"] = int(s["max_height"])
# A malformed max_height (non-numeric inline spec / stored profile) falls back to "best"
# rather than raising an unhandled 500 at enqueue.
try:
s["max_height"] = int(s["max_height"])
except (TypeError, ValueError):
s["max_height"] = None
for b in ("embed_subs", "embed_chapters", "embed_thumbnail", "sponsorblock"):
s[b] = bool(s[b])
# Audio-only files can't embed subtitles/thumbnails as video; keep the flags meaningful.

View file

@ -60,6 +60,14 @@ def get_or_create_asset(
)
asset = db.execute(stmt).scalar_one_or_none()
if asset is not None:
# A previously-FAILED shared asset must be re-attempted for the new job about to hold it —
# reset it to pending (+clear the error) so the worker actually re-downloads instead of
# short-circuiting the new job with the asset's stale error. (Mirrors resume_download; without
# this a fresh enqueue of a once-failed (source,format) pair is permanently poisoned, since
# errored assets carry no expires_at and GC never clears them.)
if asset.status == "error":
asset.status = "pending"
asset.error = None
return asset
asset = MediaAsset(
source_kind=source_kind,