Required by symphonia-adapter-libopus which bundles and compiles
libopus from source via CMake.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Changelog for v1.34.11 (Opus, Device Sync, community themes, SSL fix)
- Contributors updated in Settings About (PR #181, #182, #183)
- Version bumped to 1.34.11 in package.json, tauri.conf.json, Cargo.toml
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
symphonia-adapter-libopus bundles libopus and compiles it via cmake.
Without cmake installed, cargo build fails with a C compiler error.
Added install instructions for Linux, macOS, and Windows.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New two-panel layout with live album search (search3, 300ms debounce)
and 10 random albums when search is empty — replaces full paginated load
- Pre-sync summary modal: shows files to add/delete, net change, available
space; Proceed button disabled when space is insufficient
- calculate_sync_payload now filters already-synced tracks (path exists on
device) so add_bytes/add_count reflect the true delta
- Space check accounts for pending deletions: addBytes > availableBytes + delBytes
- Separate deviceSyncJobStore for ephemeral job progress state
- Removable drive detection + auto-poll every 5 s via sysinfo
- Desired-state diff: de-selecting a synced source stages it for deletion
instead of silently removing it
- Status badges (Synced / Pending / Deletion) with matching row highlights
- Live-Search badge (⚡) and Zufallsalben section label (⇌) in album browser
- Status summary row height aligned with search field (52 px)
- i18n: all new keys added to all 8 locales (en/de/fr/nl/nb/zh/ru/es)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire a lazy CodecRegistry built with symphonia::default::register_enabled_codecs
plus symphonia_adapter_libopus::OpusDecoder for SizedDecoder and radio decoders.
Raise package rust-version to 1.89 to match the MSRV required by
symphonia-adapter-libopus.
Fixes two bugs reported in #178:
- getBaseUrl() now strips trailing slashes from server URLs, consistent
with restBaseFromUrl(). A trailing slash caused double-slash stream URLs
(//rest/stream.view) which Caddy rejects. Trailing slash also caused
browsing to return 0 results. Fix manually ported from PR #179 by kveld9.
- reqwest now loads the OS native certificate store in addition to
Mozilla's webpki roots (rustls-tls-native-roots feature). Fixes HTTPS
streaming failures where the server certificate is signed by a local CA
(e.g. Caddy internal CA) that is trusted in the system keychain but not
in Mozilla's root store.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a new Device Sync page for transferring music from Navidrome to
USB drives or SD cards. Sidebar entry is hidden by default.
- Four new Tauri commands: sync_track_to_device, compute_sync_paths,
list_device_dir_files, delete_device_file
- Filename template engine with cross-platform path sanitization
- 4-concurrent-worker download, live progress via device:sync:progress event
- Persistent source list (albums/playlists/artists) with checkbox deletion
- Expandable artist tree in browser panel (per-album selection)
- i18n: DE + EN complete; other locales have stub keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(audio): stabilize Linux output device picker and watcher
Keep pinned ALSA/cpal device ids stable when enumeration omits the active
sink or returns an equivalent name. Stop Linux device-watcher from clearing
the pin based on missing list entries; macOS and Windows still treat repeated
absence as unplugged. Settings refresh flow calls canonicalize and refetches
the list; add i18n for the out-of-list device label.
* fix(settings): sort audio output devices by label
cpal enumeration order is arbitrary; order the dropdown by readable label
and place the current OS default device first among concrete outputs.
In software compositing (WEBKIT_DISABLE_COMPOSITING_MODE=1), WebKit renders
entirely on the CPU. The mesh blob animations were not covered by the
no-compositing overrides: blob-a occupies 130×130% of the viewport, so each
frame the CPU had to composite a surface larger than the screen. On high-DPI
displays (e.g. 8K) this drops the fullscreen player to ~10 FPS.
- Stop mesh blob pan animations (static gradients are preserved)
- Stop portrait drift animation (filter was already removed)
- Remove box-shadow from the seekbar played bar (its width changes on every
playback tick; in software mode each change triggers a box-shadow repaint)
- CI: add squashfs-tools dep, APPIMAGE_EXTRACT_AND_RUN=1, appimage to
--bundles, and *.AppImage to upload glob
- main.rs: set GDK_BACKEND=x11 and WEBKIT_DISABLE_COMPOSITING_MODE=1
on Linux before Tauri init — WebKitGTK on Wayland is unstable;
both vars are overridable by setting them before launch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add missing contributions: cucadmuh (PR #144, #167, #173, #174),
kveld9 (PR #168), nisarg-78 (PR #115)
- Remove aboutFeatures tag line from all 8 locales (too dynamic to maintain)
- Changelog section now shows only the 3 most recent versions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(settings): clearer audio device labels for duplicate ALSA names
Show HDMI outputs as "Card (HDMI n)" from hdmi:DEV indices; include PCM and
optional subdevice for hw/plughw/sysdefault; label other ALSA plugins with
iface and PCM. When labels still collide, append a structured hint
(iface · card · PCM) instead of only truncating the raw device string.
* feat(settings): improve audio output device picker
Parse ALSA-style ids into clearer labels (HDMI with DEV index, PCM/subdevice
for hw/plughw/sysdefault). Disambiguate colliding labels; share stderr
suppression for Linux device enumeration.
Add audio_default_output_device_name and tag the matching list entry as the
current system output (i18n). While the Audio tab is open, refresh list and
mark on audio:device-changed and audio:device-reset without toggling the
refresh spinner. Show an error toast if listing devices fails.
Skip column/list arrow handling when any modifier is down. Detect modifiers
via nativeEvent and getModifierState (WebKit/WebView), and match arrow keys
by both key and code. On row buttons, preventDefault for plain arrows only
to avoid native focus/scroll stealing navigation. Filter field ArrowDown uses
the same modifier check.
- Device watcher requires 3 consecutive misses (~9 s) before triggering
audio:device-reset, preventing false positives when ALSA temporarily
hides a busy device from output_devices() enumeration
- Add stderr suppression to open_stream_for_device_and_rate (last source
of ALSA terminal noise on Linux)
- Fix tooltip showing raw key 'common.refresh' — replaced with
settings.audioOutputDeviceRefresh (added to all 8 locales)
- Device switch restarts track from beginning (no seek-back)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Raw ALSA names like "sysdefault:CARD=U192k" are replaced with
readable labels ("U192k") in the device dropdown. The underlying
value stays unchanged so rodio can still open the correct device.
Covers: sysdefault, hw, plughw, iec958, front, surround prefixes.
Names without ALSA structure (pipewire, pulse, default) are kept as-is.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The module-level cache prevented newly connected USB audio devices
from appearing in the dropdown. Replace with a manual refresh button
(RotateCcw icon, spins while loading) next to the dropdown.
Device enumeration now runs on every Audio tab open and on explicit
refresh. ALSA stderr noise is already suppressed by the dup2 guard,
so re-enumeration is silent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Device watcher (3 s loop) and audio_list_devices both called
cpal output_devices(), triggering ALSA to probe unavailable backends
(JACK, OSS, dmix) and spam stderr with error messages.
Fix: redirect fd 2 to /dev/null for the duration of each enumeration
on Unix via libc dup/dup2 + RAII guard. Also add a module-level
cache in Settings.tsx so audio_list_devices is only invoked once
per app session instead of on every Audio tab activation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the ability to choose which audio output device Psysonic plays
through — useful for USB DACs, dedicated soundcards, and multi-device setups.
Rust (audio.rs):
- open_stream_for_device_and_rate(device_name, rate): opens a named
device by cpal name, falls back to system default if not found
- AudioEngine.selected_device: persists the chosen device across
stream reopens so hi-res rate switches stay on the right device
- audio_list_devices: Tauri command — returns all output device names
- audio_set_device: Tauri command — switches device immediately,
drops old sinks, emits audio:device-changed
- start_device_watcher: now handles two cases:
1. No pinned device + system default changed → reopen on new default
2. Pinned device disappeared (DAC unplugged) → clear selected_device,
fall back to system default, emit audio:device-reset
Frontend:
- authStore: audioOutputDevice (string | null), persisted
- playerStore: applies stored device on cold start
- App.tsx: listens to audio:device-reset, clears authStore device
and restarts playback on the fallback device
- Settings → Audio tab: device dropdown at top (above Hi-Res and EQ),
uses CustomSelect (portal-based, styled), all 8 locales
- CustomSelect: added disabled prop
Note: exclusive mode (WASAPI exclusive, CoreAudio exclusive) is out
of scope for now.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
https:// was already supported by the code (startsWith('http') check) but
the placeholder text only showed bare host:port examples, giving no hint
that a full URL with protocol is valid.
- Updated serverUrlPlaceholder in login namespace (all 8 locales) to show
https://music.example.com as the domain example
- Added settings.serverUrlPlaceholder i18n key (all 8 locales) and wired it
into AddServerForm — previously the placeholder was a hardcoded English string
Closes#171
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When offline with no cached content, the full-screen OfflineOverlay blocked
all navigation including Settings, making it impossible to fix a broken
server config. Replace it with the same slim banner used in offline-cache mode.
- OfflineBanner now handles both cases: cache (existing) and no-cache (new)
- No-cache banner shows server name and a direct link to Settings → Server tab
- OfflineOverlay component is no longer used (import removed from App.tsx)
- All 8 locales: added offlineNoCacheBanner and serverSettings keys
Fixes#170
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Multi-selection for Albums, Artists, Playlists with context menu bulk-add
- Collapsible playlist section in sidebar
- Infinite scroll on Artists page (IntersectionObserver)
- Submenu flip-up on viewport overflow
- Remove from Playlist in context menu
- All 8 locales synced
Fixes applied:
- title= → data-tooltip on playlist toggle button (CLAUDE.md)
- Hardcoded Spanish aria-label → i18n (sidebar.expandPlaylists/collapsePlaylists)
- AddToPlaylistSubmenu fetches playlists on first open if store empty
Co-Authored-By: kveld9 <kveld9@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace title= with data-tooltip on sidebar playlist expand button (CLAUDE.md)
- Replace hardcoded Spanish aria-label strings with i18n keys (sidebar.expandPlaylists / collapsePlaylists) across all 8 locales
- AddToPlaylistSubmenu now fetches playlists on first open if store is empty (regression fix)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Persist chords as ctrl/alt/shift/super plus key code; legacy single-key
bindings still match without modifiers. Settings capture uses buildInAppBinding;
App uses matchInAppBinding and skips chords also registered as global shortcuts.
Share MODIFIER_KEY_CODES and formatBinding with global shortcut formatting.
Fix seek-forward/backward hotkeys: seek() expects 0-1 progress, not seconds.
--bg-base is undefined — sticky filter bar would have rendered transparent.
Also added PR #165 to cucadmuh's contributions in Settings About.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Purple & Gold palette (Deuteranopia / Protanopia / Tritanopia safe).
Vision Dark: near-black #0D0B12 + Gold #FFD700 (~14.7:1 WCAG AAA).
Vision Navy: deep navy #0A1628 + Gold #FFD700 (~14.5:1 WCAG AAA).
New 'Accessibility' group in ThemePicker.
Removed stale theme count from aboutFeatures across all locales.
This is an initial step toward colorblind accessibility — color variables
alone cannot cover all CVD use cases. Structural improvements (secondary
indicators, pattern/shape cues) are still needed in future iterations.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add Ctrl+F filtering for the active Folder Browser column with keyboard handoff between filter and rows, and clear right-side filters when parent selection changes.
When pressing Shift+Enter on a filtered track list, append visible tracks to the queue instead of replacing the current queue.