Fix 8 code-review findings across transcode queue, requests, cleanup, music

- Episode transcode (single + bulk) now accepts storage_type=scan, matching
  stream_episode and the movie-transcode endpoint — Library-Scan-imported
  TV episodes can finally be transcoded, not just streamed.
- retry_job now forwards content_type, fixing retry for failed/cancelled
  episode jobs (was silently treating them as movies and failing again).
- cancel_job now updates the correct collection (movies vs episodes) based
  on content_type instead of always writing to db.movies.
- approve_request atomically claims the request (pending -> approving)
  before contacting Radarr/Sonarr, so a double-click or two concurrent
  admins can't both add the same content; releases the claim back to
  pending on any failure so a fixable error can be retried.
- Music enrichment's update_many now re-checks album_art_url is still
  empty, so it no longer clobbers art an admin manually set via PATCH.
- Library Cleanup's dangling-refs scan now also checks episode_progress
  for rows referencing a deleted episode (previously only watchlist/
  progress against movie_id were checked).
- Settings now surfaces a failed bulk-TMDB-enrich run as an error instead
  of a false "Enrichment done" success summary.
- Music player's isPlaying now syncs from the audio element's native
  play/pause events instead of only being set inside togglePlay/track-
  change, so it can't drift from actual playback state (buffering stalls,
  OS media-key pauses, etc).
This commit is contained in:
Myron Blair
2026-07-26 22:24:09 -05:00
parent 5ac78654d4
commit 5fc37e46e4
4 changed files with 89 additions and 49 deletions
+11 -2
View File
@@ -102,6 +102,12 @@ async def scan(db, videos_dir: Path, hls_dir: Path) -> Dict[str, List[Dict]]:
if r.get("movie_id") and r["movie_id"] not in movie_ids:
findings["dangling_refs"].append({"id": r["id"] if "id" in r else f"{r['profile_id']}:{r['movie_id']}", "content_type": coll_name, "label": r["movie_id"], "detail": f"references deleted movie {r['movie_id']}", "profile_id": r.get("profile_id"), "movie_id": r.get("movie_id")})
# --- Dangling episode_progress rows (reference a deleted episode) ---
ep_rows = await db.episode_progress.find({}, {"_id": 0}).to_list(20000)
for r in ep_rows:
if r.get("episode_id") and r["episode_id"] not in episode_ids:
findings["dangling_refs"].append({"id": f"{r['profile_id']}:{r['episode_id']}", "content_type": "episode_progress", "label": r["episode_id"], "detail": f"references deleted episode {r['episode_id']}", "profile_id": r.get("profile_id"), "episode_id": r.get("episode_id")})
return findings
@@ -155,8 +161,11 @@ async def fix_one(db, videos_dir: Path, hls_dir: Path, category: str, item: Dict
await db.subtitles.delete_one({"id": item_id})
elif category == "dangling_refs":
coll = {"watchlist": db.watchlist, "progress": db.progress}[content_type]
await coll.delete_one({"profile_id": item.get("profile_id"), "movie_id": item.get("movie_id")})
if content_type == "episode_progress":
await db.episode_progress.delete_one({"profile_id": item.get("profile_id"), "episode_id": item.get("episode_id")})
else:
coll = {"watchlist": db.watchlist, "progress": db.progress}[content_type]
await coll.delete_one({"profile_id": item.get("profile_id"), "movie_id": item.get("movie_id")})
else:
raise ValueError(f"Unknown cleanup category: {category}")