diff --git a/web_server.py b/web_server.py index 8c9c18aa..f18175fb 100644 --- a/web_server.py +++ b/web_server.py @@ -12547,6 +12547,12 @@ def stream_library_audio(): return jsonify({"error": "path is required"}), 400 resolved = _resolve_library_file_path(raw_path) if not resolved or not os.path.exists(resolved): + # Not on disk — same Navidrome stream fallback as /api/library/play + # (#809), so crossfade preload of the NEXT track works for streamed + # libraries too. Resolves the song id by path (DB lookup). + stream_url = _build_library_stream_url(request.args.get('track_id'), raw_path) + if stream_url: + return _proxy_stream_url_with_range(stream_url) return jsonify({"error": _get_file_not_found_error(raw_path)}), 404 return _serve_audio_file_with_range(resolved) except Exception as e: diff --git a/webui/static/media-player.js b/webui/static/media-player.js index 4dff3642..4f155e92 100644 --- a/webui/static/media-player.js +++ b/webui/static/media-player.js @@ -1871,7 +1871,10 @@ function npStartCrossfade(nextIdx, next) { const targetVol = audioPlayer.volume; // fade the new track up to current level npXfadeMainVol = targetVol; // remember to restore on abort - xa.src = `/stream/library-audio?path=${encodeURIComponent(next.file_path)}&t=${Date.now()}`; + // Pass the server song id so a streamed (un-mounted) Navidrome track can + // crossfade-preload via the server stream API too (#809). + const _xfTid = next.id ? `&track_id=${encodeURIComponent(next.id)}` : ''; + xa.src = `/stream/library-audio?path=${encodeURIComponent(next.file_path)}${_xfTid}&t=${Date.now()}`; xa.volume = 0; xa.play().then(() => { const fadeMs = NP_CROSSFADE_SECONDS * 1000;