Added
Sidebar — pin Now Playing to the top
By @Psychotoxical, PR #1000, suggested by @PHLAK
- New Settings → Sidebar toggle moves the "Now Playing" entry to the top of the sidebar instead of the bottom (off by default).
Fullscreen player — rebuilt for much lower CPU/RAM
By @Psychotoxical, PR #1001
- The previous fullscreen player was a heavy CPU and memory consumer — constant repaints from animated/blurred backgrounds and effects kept the GPU and a CPU core busy the whole time it was open. It has been completely replaced by a static, low-overhead screen: only the seekbar, elapsed time, and clock update live; everything else stays still.
- Features: sharp high-res background, large album cover, true waveform seekbar, up-next queue popover, scrolling synced lyrics, clickable rating stars, and an on-screen clock.
- The artist photo now always shows as the background (album cover as fallback); the old Appearance → "Fullscreen player" settings were removed.
Queue — Timeline display mode
By @Psychotoxical, PR #1004, suggested by @Legislate3030
- New third queue display mode (cycle the header button, or pick it in Settings → Personalisation → Queue display). Timeline keeps the current track centered with played history above and upcoming tracks below — both visible at once — so it's easy to follow playback and jump back to earlier songs.
- The up-next order respects shuffle, and a "History" / "Up next" divider marks the boundary.
Offline — unified local playback, library index join, and favorites sync
- All local audio bytes live under one
media/tree:cache/(ephemeral hot-cache),library/(user-pinned offline), andfavorites/(auto-synced stars). Paths use library-index metadata and the URL-derived server index key so two profiles on the same server share one bucket. localPlaybackStorereplaces the split hot-cache / offline metadata stores — one index drives prefetch, promotion, eviction, andpsysonic-local://playback resolution.- Offline Library lists pinned and favorites-tier tracks by joining that index with the SQLite library catalog (no duplicate offline album cards). Pin album, playlist, or artist from browse; disk usage shown in the Offline Library header.
- Favorites auto-sync keeps starred tracks on disk in
media/favorites/with a compact toggle, cross-server reconcile, and cancel-on-unstar so orphaned files are not left behind. - Cached offline pins stay in sync — manually pinned albums and artist discographies reconcile after a library index sync (delta/full); regular playlists reconcile hourly and when edited in-app. Added tracks download and removed ones are pruned. Smart playlists (
psy-smart-…) are excluded — their contents refresh from server rules automatically. - Mixed-server queues play offline with correct per-track server scope; network guards skip Subsonic when local bytes exist.
- Startup migration from legacy
psysonic-offline/layout; Settings → Storage uses a single media directory picker and a live hot-cache track count.
Themes — community Theme Store
By @Psychotoxical, PR #1009, #1011, #1012, #1013, #1014, #1015, #1016, #1018, #1020, #1036, #1038, #1041
- New Settings → Themes tab: pick a theme, set the day/night scheduler, and browse a built-in Theme Store to install, update and uninstall community themes — with search, a dark/light filter, and full-size thumbnail previews.
- The app now bundles six core themes (Catppuccin Mocha & Latte, Kanagawa Wave, Stark HUD, and the colour-blind-safe Vision Dark / Vision Navy); every other palette installs on demand from the psysonic-themes repo. Installed themes are saved locally and apply instantly at startup, even offline.
- Import a theme from a local
.zip(manifest.json + theme.css): the package is validated, you confirm its name and author, then it installs like any other community theme. - Themes are free-form — beyond recolouring, they can add their own styling and animations and react to playback / fullscreen / sidebar / lyrics state. A safety floor (no network, no scripts) is always enforced; store themes are reviewed, and imported themes install at your own risk.
- The store paginates large catalogues, and refreshing the list no longer jumps back to the top.
- Each store theme shows its total downloads and a last-changed date, and can be sorted by most popular, newest or name; the catalogue now has numbered page navigation. These stats refresh once a day.
- The Now Playing page now follows the active theme end to end — light themes render it legibly instead of washed-out, with no per-theme tweaks needed.
- The sidebar now shows a small notice when one of your installed themes has an update available — click it to jump straight to the Theme Store, or dismiss it until the next update. Themes with an update also show an update control right on their card under Settings → Themes to update them in place with one click, and the store refreshes once on startup so new themes and updates show up without hitting refresh.
- Upgrading from an older build: an active or scheduled theme that has moved to the store and isn't installed falls back to Mocha (dark) / Latte (light).
Offline — local-bytes browse when the server is down
- When the active server is unreachable, browse and detail pages read from local playback bytes and the library index instead of Subsonic — albums, artists, tracks, cached playlists, and cross-server favorites.
- Single integration contract:
offlineBrowseContext,offlineActionPolicy, andresolveAlbum/resolveArtist/resolvePlaylistresolvers; context menus and detail toolbars block server mutations offline. - Disconnect navigation forks by offline capability (stay on page, stay-reload, or redirect); Home reuses the last cached feed snapshot; DEV offline toggle simulates full disconnect for testing.
- PlayerBar hides star rating and favorite controls while offline browse is active.
Startup — themed loading splash before the app bundle loads
- Inline splash in
index.html(progress bar + P logo) shows while the Vite bundle loads in dev and production — no empty or black window on launch. - Splash colours follow the persisted theme (built-in palettes, day/night scheduler, and installed community themes); the logo uses each theme's accent gradient instead of a hardcoded white asset.
- The native window stays hidden until the splash has painted (
visible: false+ deferredshowfrom Rust/JS); window-state restore no longer overrides startup visibility.
Servers — software and version on each server card
By @Psychotoxical, PR #1045
- Each server card under Settings → Servers now shows the server software and version (e.g.
Navidrome 0.62.0) under the server name. The value comes from the existing connection ping, so no extra request is made; it is hidden for servers that don't report it (plain Subsonic without OpenSubsonic).
What's New — remote release notes
- The What's New page shows user-friendly highlights from
WHATS_NEW.mdinstead of embedding the full technical changelog in the app bundle. - RC and stable builds prefetch
whats-new.mdfrom the GitHub release on startup and cache it locally; offline users see a thin embedded fallback. tauri:devreads markdown straight from the repo for easy editing; shipped bundles embed only the current release-line slice. A Full changelog tab on the page shows the technical list for the same version.- CI uploads
whats-new.mdon eachnext/releasetag alongside platform artifacts. - Remote download uses the existing Rust
fetch_url_bytesproxy so GitHub release assets work without browser CORS.
Changed
Settings → Servers — compact server cards
- Two-line header: custom entry name plus
user@host, HTTPS lock, and a clickable version info tooltip (hover or tap). - Navidrome 0.62+: green AudioMuse-AI inline badge when the plugin is detected; older Navidrome keeps the manual toggle row below the card.
- Use and Active share one rightmost slot (green badge vs primary button); card actions are edit → test → use/active. Delete lives in the edit form footer.
- TooltipPortal:
data-tooltip-clickfor click-pinned tooltips (touch and explicit open without the 1s hover delay).
Dependencies — npm and Rust refresh
- Frontend and Tauri npm dependencies bumped (React, Vite, Vitest, i18next, axios, Tauri plugins); test stack upgraded to jsdom 29.
- Rust workspace:
id31.17,reqwest0.13.4,sysinfo0.39, zip 8 for library backups. Symphonia 0.6 andmach20.6 remain deferred (upstream constraints).
Audio — Symphonia 0.6 upgrade
- Audio decode + analysis pipeline ported to Symphonia 0.6 (new
AudioDecoderAPI,GenericAudioBufferRef,Time/Timestampunits);symphonia-adapter-libopusbumped to 0.3 and the vendoredsymphonia-format-isomp40.5 patch dropped in favour of upstream ISO-BMFF fixes. rodio'ssymphonia-allfeature dropped so the workspace no longer pulls a duplicatesymphonia-core.
Playback — Preload Next Track setting removed
- The Preload Next Track toggle and timing modes under Settings → Storage → Buffering are gone — ranged streaming now starts playback without that extra RAM prefetch.
- Gapless and crossfade still prefetch the next track internally when Hot Cache is off; Hot Cache is unchanged.
PsyLab — Performance Probe rename, Tuning tab, and log tools
- Ctrl+Shift+D opens PsyLab (formerly Performance Probe). Cover backfill thread tuning moved to a new Tuning tab.
- Logs tab: selectable text, toolbar copy/export, and a context-menu Copy for the current selection.
- Runtime log lines are sanitized before they enter the buffer — Subsonic/auth tokens and remote hostnames are redacted or partially masked; LAN and localhost addresses stay readable.
PsyLab — Connections tab and Navidrome admin role
- New Connections tab: session/endpoint status, active-server capability readout (OpenSubsonic, AudioMuse detection, provider/strategy, detection trust, resolved call route, and AudioMuse mode), and queue-playback server when it differs from the active profile.
- Navidrome admin vs standard user badge via native login probe — useful when diagnosing plugin/settings visibility.
Servers — capability framework with AudioMuse sonic routing (Navidrome ≥ 0.62)
- New declarative server-capability framework (
src/serverCapabilities/): a catalog picks a feature strategy per server generation, runs only the needed probes, and routes API calls — replacing scattered version checks in the UI and call sites. - Navidrome 0.62+: detect the AudioMuse-AI plugin from
getOpenSubsonicExtensionswhensonicSimilarityis advertised — the first reliable signal. Settings shows an auto-managed status indicator (no manual toggle); older Navidrome keeps the manual toggle and the legacygetSimilarSongsInstant Mix probe. - Path routing: Instant Mix and Lucky Mix prefer the OpenSubsonic
getSonicSimilarTracksendpoint when the plugin is present, falling back to legacygetSimilarSongs.
Fixed
Local index — multi-genre browse, filters, and counts
By @cucadmuh, reported by HiveMind on the Psysonic Discord, PR #1059
- Tracks tagged with several genres in one metadata field (e.g.
Noise Metal/Dark Ambient/Experimental Black Metal) again match each atomic genre in Genres browse, All Albums filters, genre detail, and Advanced Search — not only the first segment. - New
track_genreindex (OpenSubsonicgenres[]when present, Navidrome-default split fallback), maintained on sync; one-time blocking startup backfill for existing libraries with progress. - Migration v12 repairs databases that recorded legacy schema versions 2–11; TS network fallback uses robust
genreTagsForparsing.
Navidrome Now Playing and scrobble with local playback
- Show in Now Playing and Navidrome play-count scrobbles no longer silently skip when audio plays from hot cache, offline library pins, or favorites-auto bytes.
- Presence and queue sync target the playback server reachability gate, so a queue on server A still reports to Navidrome while browsing server B.
Now Playing — cards no longer blank out on track change
By @Psychotoxical, PR #1042
- The "from this album", "discography" and "most played" sections on the Now Playing page disappeared after a track change once the next track started playing from the local cache, and didn't come back. The page now keeps loading that info whenever the server is reachable, regardless of whether the audio plays from cached or offline bytes.
Now Playing — metadata reads from the local library index first
By @Psychotoxical, PR #1049
- The "from this album", "discography", "most played" and song details on the Now Playing page now come from the local library index when it has them, only falling back to the server when the index can't serve a row. Cards and fields (genre, play count, contributors) stay populated during cached and offline playback, with fewer server requests.
Library DB — named slow-write ops for stall diagnosis
- Production
library-dbwrite paths now log stablemodule.actionop names instead of the genericmisc, so the next[library-db] SLOW writeline on macOS (or elsewhere) identifies the call site — diagnostic step for playback stalls under long write-lock holds (#1040).
Servers — complete border on the active server card
By @Psychotoxical, PR #998
- The active server card under Settings → Servers now draws its border on all four sides; previously only the left and right edges showed.
Audio streaming — start latency and stall recovery
- Ranged-HTTP FLAC/MP3/OGG streams start playing as soon as enough data is buffered again, instead of waiting for the whole file to download (Symphonia 0.6's trailing-metadata probe scan is skipped for progressive non-MP4 streams).
- The streaming format probe now runs under a 20s timeout on a worker thread, so a stalled stream (e.g. right after a server switch) no longer blocks playback start until a manual player restart.
Playback — macOS stutter from background device checks
By @Psychotoxical, PR #1039
- On some macOS setups playback stuttered at a steady ~3-second cadence: a background check that scans every audio output device ran on each poll and briefly contended with playback. It now runs only when a specific output device is pinned; with the system default (the common case) a single lightweight check runs instead.
Track preview — Symphonia 0.6 format hints and fast stream start
- Preview resolves container format from HTTP headers, Subsonic
suffix, and magic-byte sniff so Symphonia 0.6 no longer fails with.unknowndemuxer errors. - Preview opens via ranged HTTP when the server supports byte ranges — audio starts after ~384 KiB buffered instead of waiting for a full-file download; buffered fallback uses the same probe seek-gate as main playback.
- Player bar cover guard while preview metadata loads; progress ring leaves the loading spinner once the engine emits
audio:preview-start.
Mainstage — hero backdrop stays in sync when skipping albums quickly
By @cucadmuh, reported by Asra on the Psysonic Discord, PR #1021
- Rapid prev/next clicks on the Mainstage hero no longer leave the blurred cover-art background on the previous album while the foreground cover and metadata already show the next one.
Song rails — multi-artist credits link to each artist
By @cucadmuh, reported by zunoz on Discord, PR #1023
- Random Picks, Discover Songs, and other song cards now split OpenSubsonic
artists[]into individually clickable names — the same behaviour as album track rows and the player bar, instead of one link for the whole joined credit string. - Album cards and the rest of the app share the same artist-ref helper, including when Subsonic returns a single ref object instead of a one-element array.
Fullscreen player — corner clock follows Clock format setting
By @cucadmuh, reported by zunoz on Discord, PR #1025
- The wall clock in the fullscreen player now honours Settings → System → Clock format (24-hour vs 12-hour), matching the queue ETA and sleep-timer preview instead of always showing AM/PM.
All Albums — Only compilations filter returns results
By @cucadmuh, reported by zunoz on Discord, PR #1026
- The Only compilations toggle on All Albums no longer returns an empty list when compilations are tagged via Various Artists as album artist or when genre is combined with other browse filters — local index SQL, track-grouped browse, and client-side detection now agree on the same compilation signals.
Artist page — Top Tracks play button
- Play on Top Tracks rows no longer silently does nothing when the artist page has top songs but no albums loaded (e.g. lossless artist view); playback starts from the clicked track and continues into the catalog when albums are available.
PsyLab — tab bar no longer collapses on the Logs tab
- The PsyLab tab row keeps its height when the Logs flex layout fills the modal — tabs were previously squashed to a thin strip.
Themes — consistent focus borders on inputs and dropdowns
By @Psychotoxical, PR #1052
- Text fields no longer draw a double border when focused — they now show a single clean ring across every theme. The colour-blind-safe themes keep their stronger high-contrast focus ring on every field, including the header search.
- Dropdown and popover borders now follow the active theme in all themes (a couple of themes previously rendered them with an unthemed colour).
Home — Most Played no longer jumps the page when loading more
By @Psychotoxical, reported by zunoz on Discord, PR #1053
- Clicking the arrow to load more albums in the Most Played rail sometimes snapped the page up to an earlier section. Loading more now keeps the viewport in place.
Album grids — album artist on compilation cards
By @cucadmuh, PR #1057, reported in #1056
- Random Albums, New Releases, All Albums, and other album grids no longer show a track artist on compilation albums when the tags set a single album artist (e.g. Underworld on a various-artists mix); the card matches the album page.
- Local index browse, live search, and FTS album dedupe prefer
album_artistover per-trackartist; Hero, Most Played, and offline pin labels use the same display helper.
Dev startup — missing generated release-notes bundle
- Fresh clones no longer crash Vite on
tauri:devwhensrc/generated/releaseNotesBundle.tsis missing —devandtauri:devnow runprebuild:release-notesbefore launch (file stays gitignored).
What's New — release-notes cache file on disk (RC/stable)
- RC and stable builds now persist the downloaded
whats-new.mdslice under AppData —plugin-fshad mkdir but lacked recursive write scope, so therelease-notes/folder appeared empty and every launch re-fetched from GitHub.