Commit Graph

27 Commits

Author SHA1 Message Date
Myron Blair 6438407f5b Fix retry-all-failed silently no-oping when content already has a queued job
Also lift the artificial 500-row cap on the retry-failed query.
2026-07-27 17:25:52 -05:00
Myron Blair e54803abb0 Add app version number, shown in Navbar next to the logo
New backend/VERSION file (starts at 1.0.0) served via GET /api/version,
displayed as a small "v1.0.0" next to the StreamHoard wordmark. Going
forward I'll bump this on meaningful changes -- patch for fixes, minor
for new features, major for big/breaking redesigns.
2026-07-27 00:01:04 -05:00
Myron Blair b74d8a2652 Add fast audio-only transcode mode; fixes no-sound from AC3/DTS/EAC3
Root cause of "movies have no volume control / can't hear anything":
0 of 200 movies had finished transcoding, so every movie streamed its
raw source file — and BDRip/AVI sources very commonly carry AC3/DTS/EAC3
audio, which no browser can decode natively. Browsers respond by hiding
the volume control entirely when they can't find a playable audio track,
which is exactly the symptom reported.

New "audio" transcode quality: video is stream-copied untouched, only
the audio track is re-encoded to AAC — dramatically faster than a full
ABR pass since no video re-encoding happens. Added:
- transcode_audio_fix() in transcode.py
- "audio" as a valid quality value everywhere quick/abr were validated
- POST /transcode/queue/fix-audio-all: cancels every still-pending job
  and replaces it with the fast audio fix for the same content (running
  jobs are left alone), so a library-wide backlog of slow ABR jobs can
  be swapped for something that actually restores sound soon
- Per-movie "Audio" button in Admin, "Fix Audio (Fast, All)" button on
  the Transcode Queue page

Note: this doesn't help HEVC/x265 sources, whose video (not just audio)
isn't natively browser-playable either — those still need a full ABR
re-encode to H.264.
2026-07-26 23:31:23 -05:00
Myron Blair cf8c7890be Add confirm+stop to Library Cleanup scan; branded album art placeholder
- Library Cleanup scan is now a real background job (POST .../start,
  GET .../status, POST .../stop) instead of one long synchronous request,
  so a Stop button can actually abandon it instead of just waiting.
  Frontend confirms before starting (explains it can take a minute+)
  and polls status while running.
- New shared AlbumArt component: shows real art when available, otherwise
  a branded "Streamhoard" placeholder instead of a bare icon in an empty
  box. Used in the Music grid, album detail header, and the player bar —
  swaps to real art automatically once enrichment/a manual edit sets it.
2026-07-26 23:15:07 -05:00
Myron Blair 5fc37e46e4 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).
2026-07-26 22:24:09 -05:00
Myron Blair 9af505b45c Add live progress status to bulk TMDB movie enrichment
Was a single synchronous request with no visibility into progress —
large libraries gave no indication whether it was working or just slow.
Now runs as a background job (matching the existing music-enrich pattern)
with GET /api/tmdb/enrich-all/status polled every 2s; Settings shows
"Enriching... N/total" while running and a summary once done.
2026-07-26 22:01:12 -05:00
Myron Blair 4e72f568f3 Speed up transcoding without overloading the VM, add bulk retry
- nice level 19 -> 10 (was the absolute lowest CPU priority) and cap
  ffmpeg to 6 threads on this 8-core host, leaving headroom for Mongo,
  the *arr stack, and the API itself instead of an unbounded encode.
- Add POST /transcode/queue/retry-failed to re-queue every failed/
  cancelled job at once; label the per-job Retry button with text
  (was icon-only) and clarify in the page copy that failed/cancelled
  jobs never delete the movie — retry just re-queues the same file.
2026-07-26 21:21:22 -05:00
Myron Blair c174ac60b1 Add Library Cleanup admin page — missing files, orphaned records, stuck jobs, duplicates
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.
2026-07-26 21:13:16 -05:00
Myron Blair 3d2b7a4122 Wire Requests approval into Radarr/Sonarr with live download status
Admin can now Approve a pending request as Movie or TV, which looks up
the title via Radarr/Sonarr's own lookup API, adds the best match with
search-on-add enabled, and tracks the resulting radarr_id/sonarr_id on
the request. A live status line (searching/queued/downloading/downloaded,
polled every 15s) shows next to each approved request.
2026-07-26 20:55:22 -05:00
Myron Blair 64d8945460 Fix wrong Content-Type for m4a/flac/ogg/wav/aac track streams
mimetypes on the backend image doesn't recognize these extensions, so
every non-mp3 track streamed as audio/mpeg — wrong codec hint, breaks
playback in strict browsers. Add an explicit fallback map.
2026-07-26 20:40:59 -05:00
Myron Blair cf31a14ae1 Speed up music scan by deferring tag reads to import time
Reading embedded ID3/MP4 tags for every file during the scan itself was
taking minutes even for a small (146-track) library, since each mutagen
open is a slow round trip over the CIFS-mounted NAS share. Scan now uses
fast filename/path parsing only; tag reads happen once, only for the
tracks actually selected for import.
2026-07-26 20:38:09 -05:00
Myron Blair 514cbad4ab Add filesystem Library Scan (movies/tv/music) and a full Music library
- New admin Library Scan page walks the NAS mounts directly for movies,
  TV, and music not already in Radarr/Sonarr/local storage, and imports
  them with storage_type=scan (fully integrated: streamable, transcodable,
  listed in Admin) — Radarr/Sonarr import flows are untouched.
- New Music section (nav tab, album-grid browse, per-album track list,
  persistent bottom player with queue/seek) backed by a Track model and
  range-request audio streaming endpoint.
- MusicBrainz + Cover Art Archive integration (free, no API key) to fill
  in album art for scanned tracks, paced to their 1 req/sec rate limit.
- Mounted the NAS music share into CT104 (new mp2 LXC mountpoint,
  CIFS read-only) alongside the existing video mount.
- Optional Bluetooth/output-device picker on the player bar via the Audio
  Output Devices API (setSinkId) for already-paired speakers — Chrome/Edge
  only, since browsers can't pair new BT devices directly.
2026-07-26 20:25:41 -05:00
Myron Blair f7626ced2e Merge watch profiles into user accounts — one profile per login, no picker
- Removed the "Who's Watching" sub-profile picker entirely: ProfileProvider now
  auto-resolves the single profile tied to the account immediately after login
- Backend: removed POST/DELETE /profiles (no more creating/deleting extra
  profiles — lifecycle is entirely driven by user create/delete, already wired
  in the admin Users CRUD); kept GET (internal) and PATCH (edit your own
  profile's avatar/kids-mode/rating cap)
- Deleted ProfileSelect page and the now-unused ProtectedRoute component
- Navbar: removed the "switch profile" action, account avatar is now just a
  static display
- api.js: dropped the now-dead X-Profile-Id header logic (backend already
  falls back to the account's single profile when the header is absent)
2026-07-26 19:40:12 -05:00
Myron Blair 5b191da471 Add user management (CRUD + admin toggle), make Settings available to all users
- New /admin/users page: create/delete users, toggle admin role, guarded against
  self-demotion/self-deletion
- Backend: GET/POST/PATCH/DELETE /api/admin/users, admin-only
- Settings moved from /admin/settings to /settings (all logged-in users); the
  password-change section shows for everyone, integration/API-key sections only
  render (and only fetch) for admins, since those endpoints stay admin-gated
- Navbar: Settings link now visible to all users; added Users nav link for admins
2026-07-26 19:21:50 -05:00
Myron Blair 4d77a36f99 Add admin-only service status panel with restart, wired to Docker directly 2026-07-26 17:53:19 -05:00
Myron Blair 19374b694e Add self-service admin password change (requires current password) 2026-07-23 22:48:32 -05:00
Myron Blair 5b881a902d Auto-enqueue ABR transcode on Sonarr import, matching Radarr import behavior 2026-07-23 22:45:40 -05:00
Myron Blair e27bb37f7b Rebrand StreamHoard, strip Emergent.sh platform artifacts
- Remove .emergent/ state dir, tracked .gitconfig, @emergentbase/visual-edits
  dep + craco wiring, emergent.sh script/meta tags, PostHog telemetry snippet
- Rename UI/docs branding Kino -> StreamHoard (README, DEPLOY.md, Navbar,
  Login, Register, AdminShowEpisodes, FastAPI title, health check response)
- Rename docker-compose container/network names to streamhoard-*
- Default admin email domain -> admin@streamhoard.local
2026-07-23 20:20:29 -05:00
emergent-agent-e1 211d4c23d5 auto-commit for 296e06eb-544f-4710-845e-c5a611b15f0e 2026-07-23 23:03:09 +00:00
emergent-agent-e1 bd8480bd14 auto-commit for 0175172f-4f7e-4804-ad7f-68312dcdad0d 2026-07-23 22:23:41 +00:00
emergent-agent-e1 22d8479b39 auto-commit for b082c1c8-f6e3-4cfd-82ee-0396c70d1a00 2026-07-23 22:18:08 +00:00
emergent-agent-e1 21cdd24116 auto-commit for b6946a78-11ff-4dc8-85b6-12e35b57d256 2026-04-29 16:34:49 +00:00
emergent-agent-e1 da8a2903b4 auto-commit for b5490b7b-d57f-4f53-9a99-bd8ed84027db 2026-04-29 16:33:26 +00:00
emergent-agent-e1 20aba50fa1 auto-commit for cf4f0369-14b7-4d06-b915-b8f7098fd48d 2026-04-29 16:21:32 +00:00
emergent-agent-e1 cdc8c8955f auto-commit for 14921357-f5e2-4aba-b4c1-a07a52c800cc 2026-04-29 16:01:20 +00:00
emergent-agent-e1 356aa13063 auto-commit for df4b0748-985b-4592-8c48-1e56102f3613 2026-04-29 14:49:07 +00:00
emergent-agent-e1 7673090279 auto-commit for a6c922a7-7216-4688-a9a9-38dcd5c45488 2026-04-29 14:33:29 +00:00