soulsync/core/streaming
BoulderBadgeDad df929dc022 #809 Navidrome playback: stream via the server's API when the library isn't mounted on disk
mlody95pl: Navidrome sync works, playback fails ("Failed to resume playback").
Root cause: SoulSync plays library tracks by reading the file off its OWN
disk (/api/library/play → resolve path → serve bytes). "Report Real Path"
gives the correct path STRING, but that's Navidrome's container path — the
files still have to be mounted into the SoulSync container to open them, and
the user's compose has /music commented out. So disk resolution 404s.

Navidrome is a streaming server, so requiring a disk mirror to play from it is
the real limitation. Now, when a library file isn't on SoulSync's disk and the
active server is Navidrome, playback streams through the server's own Subsonic
/rest/stream API — no mount needed:

- NavidromeClient.build_stream_url(song_id, max_bitrate) — token-authed
  /rest/stream URL (mirrors build_cover_art_url; password never exposed).
- /api/library/play: on disk-miss, _build_library_stream_url (Navidrome-only;
  uses the song id sent by the player, or a DB lookup by file_path) sets a
  session stream_url instead of failing.
- /stream/audio: proxies that stream_url with Range passthrough so HTML5
  seeking works, streaming upstream bytes through in 64KB chunks (no full-file
  buffering).
- session state gains stream_url; the two library-play callers now send the
  track's server id.

Disk playback is unchanged (file_path path still wins when the file resolves),
so Plex/Jellyfin and mounted-Navidrome setups behave exactly as before.

Tests: 7 on the URL builder (auth shape, no-transcode default, maxBitRate,
guards) + 4 on the play-fallback routing (navidrome-only, passed-id vs
DB-lookup, none). 200 navidrome/stream/media-server tests pass.
2026-06-07 13:52:14 -07:00
..
__init__.py Lift _prepare_stream_task + playlist_explorer_build_tree to core/ 2026-04-29 11:26:07 -07:00
prepare.py Stream button: the player never learns its stream is ready (2.6.5 regression) 2026-06-06 12:43:20 -07:00
state.py #809 Navidrome playback: stream via the server's API when the library isn't mounted on disk 2026-06-07 13:52:14 -07:00