- 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).
Fixing a missing-file or duplicate-import episode only deleted the
episode itself, leaving its episode_progress/subtitle rows behind for
the next scan to catch as separate orphaned_subtitles/dangling findings.
Consolidated movie/episode/track deletion (with all their dependent rows)
into one _delete_content() helper, used consistently by missing_files,
orphaned_episodes, and duplicate_paths.
New read-only scan (GET /api/library/cleanup/scan) across movies, episodes,
tracks, subtitles, HLS output, transcode queue, and watchlist/progress rows:
- Missing files: DB record exists but the file is gone from disk
- Orphaned episodes: show_id no longer exists
- Orphaned HLS output: transcoded folders left behind by deleted content
- Stuck transcode jobs: "running" 2+ hours with no completion (backend-restart artifact)
- Duplicate imports: same file imported into the library more than once
- Orphaned subtitles / dangling watchlist+progress rows
Nothing is deleted until an admin clicks Fix (per-item or Fix All per
category) via POST /api/library/cleanup/fix.