- Add "Reset to defaults" button to column picker in AlbumTrackList, PlaylistDetail, Favorites (all 8 locales)
- Fix device sync cross-OS status detection: store filenameTemplate in manifest, use it for path computation on import
- Redesign filename template UI: preset buttons (Standard/Multi-Disc/Alt. Folder), clickable token chips ({artist}, {album}, etc.), clear button
- Fix suggestions section in PlaylistDetail missing album column rendering
- Add PRIVACY.md documenting all third-party integrations (Last.fm, LRCLIB, Apple Music, Discord); link from README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Write psysonic-sync.json to device after sync/deletions; auto-import
on folder select when localStorage is empty (cross-platform handoff)
- Add cancel button during active sync: AtomicBool flag per job,
tasks bail after acquiring semaphore, cancelled state in UI
- Fix sync status staying "pending": normalize template path separators
to OS separator (Windows: '/' → '\') so compute_sync_paths and
list_device_dir_files produce matching strings for Set comparison
- Add Geist and JetBrains Mono as variable fonts; font picker collapsible
- Fix device mount detection on Windows: removable drive letters (E:\)
were incorrectly skipped alongside system roots; strip \?\ prefix
from canonicalized paths before mount-point comparison
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract ALL_NAV_ITEMS to src/config/navItems.ts and add randomMix/randomAlbums
nav items. A new toggle in Settings switches between a single "Build a Mix" hub
and separate "Random Mix" / "Random Albums" sidebar entries (randomNavMode in
authStore). Fixes reorder crash caused by hidden items being overwritten with
undefined during the merge step.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The AlbumHeader and PlaylistDetail play buttons use t('common.play') which
was missing — 'Reproducir' would have appeared as fallback in all languages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Embed bash and zsh completion scripts and add a `completions` subcommand.
Extend the player CLI (library, audio device, instant mix) and surface
`music_library` in snapshots. Add a shared active-server switcher in the
header and locales; instant mix can reseed the queue from CLI and UI.
- 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>
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.
- 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.
- 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>
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>
- 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>
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>
- PlaylistDetail: Ctrl/Cmd+Click enters select mode; bulk drag emits
{ type: 'songs', tracks } when ≥2 selected; filtered-view rows now
also draggable as single songs
- Favorites songs: full multi-select system — Ctrl+Click, Shift+Click,
header toggle-all checkbox, bulk-selected highlight, bulk drag to
queue, bulk-bar with Add to Playlist + Clear
- ContextMenu: ArtistToPlaylistSubmenu resolves all artist album songs
and forwards to AddToPlaylistSubmenu
- Locale: common.clearSelection + playlists.addSelected in all 7 locales
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove the 10-page cap in fetchStatisticsLibraryAggregates — the loop now runs until
the server returns a partial page, so albums/songs/playtime reflect the full library
regardless of size (previously capped at 5,000 albums). Switched sort type from
'newest' to 'alphabeticalByName' for a stable pagination order.
Add a tooltip on the Artists stat card explaining it shows album artists only (Subsonic
API limitation — track-level featured/guest artists without their own album are not
included). Tooltip added in all 8 locales. Labels with a tooltip get a dotted underline
and cursor:help as visual hint.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>