The playerbar seek/progress bar could disappear entirely after switching
tracks, recoverable only by restarting the app. The waveform component
rendered the fallback `PlayerbarSeekSlider` only while `isLoading` was
true and cleared that flag on any wavesurfer `ready` event, with no
handling for a failed or superseded load: `wavesurfer.load()` had no
`.catch()` and there was no `error` listener, so a load failure left an
empty waveform canvas and no seek control.
Track an explicit `hasError` state and render the fallback slider whenever
the waveform `isLoading || hasError`, hiding the empty canvas in that case,
so a seek control is always present. Add an `error` listener and a
`.catch()` on `load()` that ignore `AbortError` (the expected result of a
rapid track switch) and surface only real failures. A per-load
`loadStarted` guard, together with the existing cleanup, ignores `ready`/
`error` events from a superseded load so they cannot clear the loading
state for the wrong track.
Closes#2193
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
- add setting to allow duplicates
- add setting to only prefer similar sogs
- fix autodj algorithm to match by the priority order instead of incorrectly grouping when limit not reached
- During queue edits, stream URL reloads briefly reported a bogus duration (~0.07s). The gapless handler treated that as near end-of-track and called .play() while the player was still paused
* feat: added playlist from queue creation
- added functionality to create a playlist from queue
- prefilling is done as an extra function to be api agnostic since navidrome native api for example does not offer a parameter for filling a playlist with songs on creation
#2204
* fix: fixed wrong declaration
An unset audio device id means "follow the system default" (setSinkId is
skipped and mpv uses audio-device=auto), but the Audio device select in
the player settings popover and the playback settings page rendered
blank in that state. Make both selects controlled and fall back to the
enumerated default entry (browser 'default' / mpv 'auto') so the device
actually in use is always displayed. The stored setting stays unset, so
playback keeps following the OS default until a device is explicitly
chosen; clearing the select returns to the default entry instead of
going blank.
* feat(player): add right-click audio output device menu to volume icon
Right-clicking the volume/speaker icon in the player bar now opens a
context menu listing available audio output devices, with the active
device checkmarked and a System default reset option.
Selecting a device writes to the existing audioDeviceId (web) or
mpvAudioDeviceId (mpv) playback settings, so the choice is applied live
and persisted across restarts via the settings store. Unlike the
settings-page selector, the menu is not disabled during playback.
* refactor(player): drop redundant audio menu label, document wrapper div
Address review feedback: remove the self-explanatory ContextMenu.Label
from the audio output menu, and add a comment explaining why the volume
icon is wrapped in a div (Mantine Tooltip does not forward Radix's
asChild onContextMenu/ref to the button).
applyStartupSeek() compared the armed target song against
getQueue().items[player.index], but player.index is a position in the
shuffled order while getQueue().items is always the default order. With
shuffle enabled the lookup resolves to the wrong song, the uniqueId
check fails, and the startup resume-seek is silently cancelled — the
track then plays from 0:00 and the progress poller overwrites the
persisted timestamp.
Use getCurrentSong() instead, which maps the index through
queue.shuffled, matching how the seek target is armed.
Fixes#2202
Co-authored-by: Maurits <WhoCarrot@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
mpv/ffmpeg had no network-level timeout or reconnect options, so a
network stream left open across a system sleep would block forever on
the now-dead TCP connection instead of failing or reconnecting. Since
Node-MPV's IPC commands only resolve when mpv replies, a wedged mpv
process also made quit()/restart hang indefinitely, so the only way
out was to kill the whole app.
- Add --network-timeout and ffmpeg reconnect options to mpv's default
parameters so a stalled stream fails fast instead of hanging.
- Make the quit() helper resilient to an unresponsive mpv process by
racing it against a timeout and force-killing as a fallback.
- Listen for Electron's powerMonitor 'resume' event and tell the
renderer to reload mpv, so playback recovers automatically instead
of requiring a manual app restart.
* Fixed bad smart playlist field s
* first try to add playlist highlight
* Simplified calls
* Now works for grids too.
* Derive the playlist highlight from the currently-playing track's origin instead of a stale global field.
* addressed comments
- path replacement during runtime instead of during API normalization
- fix Navidrome API path not appending libraryPath which caused inconsistency between ND and Subsonic paths
- switch to single web player instance for loop instead of dual-player
- this fixes the issue, but does have a breaking change if using the crossfade player