Commit Graph

420 Commits

Author SHA1 Message Date
Psychotoxical 28b23a9de1 docs(changelog): add v1.34.8 release notes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 17:13:40 +02:00
Psychotoxical 649f5223b4 chore: bump version to 1.34.8
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 17:06:19 +02:00
Psychotoxical 1cc674e4ee fix(ui): icon updates, remove mic button, theme fixes
- LiveSearch: replace SlidersVertical with TextSearch for advanced search
- AlbumHeader: add Highlighter icon for artist bio button
- PlayerBar: remove unused lyrics/mic button
- components.css: album-detail-badge always opaque (accent bg, white text)
- theme: Middle Earth — remove sidebar stripes, fix queue/artist/bio contrast
- theme: Toy Tale — fix muted text, queue tabs, sidebar labels, divider
- theme: Tetrastack — brighten purple/blue palette, raise text-muted contrast
- theme: Horde & Alliance — remove repeating sidebar line pattern

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 17:05:20 +02:00
Psychotoxical 41e98d5783 fix(lyrics): strip Netease metadata lines from LRC output
Filter lines matching 作词/作曲/编曲/制作人/etc. that Netease
embeds as timestamped LRC entries at the start of the song.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 15:13:35 +02:00
Psychotoxical 6ffcd6f6fa feat(lyrics): add Netease Cloud Music as opt-in fallback source
Netease is queried only when server and LRCLIB both return nothing,
preserving the existing lyrics chain completely. Off by default.

- Rust command `fetch_netease_lyrics` proxies Netease API (CORS bypass)
- `src/api/netease.ts` TypeScript wrapper via invoke
- `authStore.enableNeteaselyrics` toggle (default: false)
- `useLyrics`: Netease fires last in fallback chain when enabled
- Settings toggle in the Lyrics section
- `lyricsSourceNetease` label in LyricsPane
- i18n: all 7 languages (en, de, fr, nl, nb, ru, zh)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 15:11:06 +02:00
Psychotoxical 33a15fd17a chore(settings): add AudioMuse-AI PR #147 to cucadmuh's contributions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 14:51:14 +02:00
Psychotoxical 084543e59b fix(tracklist): split multi-artist tracks and fix reset button style
- Use OpenSubsonic `artists[]` array to render each artist separately
  with · separator; artists with an ID are clickable, others plain text
- Fall back to single artist (artistId/artist) on non-OpenSubsonic servers
- Settings reset-to-defaults buttons changed from btn-ghost to btn-danger

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 14:37:29 +02:00
Psychotoxical b0081e3d7a Merge pull request #147 from cucadmuh/feat/audiomuse-navidrome
feat(discovery): Navidrome AudioMuse-AI (Instant Mix, similar artists, probe)
2026-04-10 14:09:21 +02:00
Psychotoxical ccc9f2cae5 Merge pull request #147: feat(discovery): Navidrome AudioMuse-AI integration
Resolves conflict in ContextMenu.tsx: keep useShallow import from main
alongside getSimilarSongs added by this PR.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 14:09:13 +02:00
Psychotoxical f34bd7c0f1 fix(audio): separate gapless chain from preload gate and reduce black flash
- Gapless now always chains at 30s regardless of preloadMode ('off' no
  longer breaks gapless playback)
- Byte pre-download (audio_preload) skips when Hot Cache is active to
  avoid duplicate downloads
- When both Gapless and Preload are active, bytes are pre-fetched early
  and the chain reuses the cached data (separate bytePreloadingId guard)
- player-album-art-wrap gets background: var(--bg-card) so the brief
  opacity-0 loading state shows a themed colour instead of black

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 14:04:30 +02:00
Psychotoxical 8cb5eb9384 chore(settings): remove alpha badges from Hot Cache and Hi-Res sections
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 13:45:56 +02:00
Psychotoxical 02a4c43f61 docs: add psysonic-bin AUR badge and early-development warning
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 13:41:51 +02:00
Psychotoxical c49f6af38b perf: reduce CPU usage and unify next-track buffering settings
- Throttle audio:progress from 100ms to 500ms; WaveformSeek and
  FsSeekbar use imperative DOM updates instead of React re-renders
- Fix all usePlayerStore() calls without selectors across pages and
  components (useShallow / individual selectors throughout)
- Remove filter:blur and transform:scale from Hero, AlbumDetail and
  FullscreenPlayer backgrounds — eliminated expensive software
  compositing layers on WebKitGTK
- Replace translate3d with 2D translate in FS mesh and portrait
  animations; remove will-change:transform from mesh blobs
- Move Hot Cache section from Storage tab to Audio tab; group Preload
  and Hot Cache under a shared 'Next Track Buffering' section with a
  mutual-exclusivity note and auto-disable logic
- Add 'off' toggle to Preload (replaces Off button with toggle switch);
  enabling either method now automatically disables the other

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 13:38:33 +02:00
Maxim Isaev 69c0c5a907 merge: integrate origin/main into feat/audiomuse-navidrome 2026-04-10 13:04:34 +03:00
Maxim Isaev 4de577eede feat(navidrome): Instant Mix probe, ping identity, and AudioMuse UX
Parse type and serverVersion from Subsonic ping; persist per-server identity and
run a background Instant Mix probe (random songs + getSimilarSongs) for
Navidrome 0.60+. Hide the AudioMuse server toggle when the probe returns no
similar tracks; clear prefs when the server is no longer eligible.

Artist pages fall back to Last.fm similar artists when AudioMuse is enabled but
the server returns none. Instant Mix failures set a per-server issue flag with a
settings warning and toast. Settings description links the official plugin repo
via i18n Trans.
2026-04-10 13:02:46 +03:00
Psychotoxical c9dfbcc19f chore(settings): reset uiScale to 1.0 on startup while scaling is disabled
Users who had previously set a custom scale are silently reset to 100%
on next launch so they are not stuck at a broken zoom level. The stored
value is cleared in fontStore so the slider starts at 100% once the
feature is re-enabled.

Also credits nisrael for the ICY / AzuraCast PR #146.

TODO: remove the reset effect and re-enable the slider in Settings.tsx
when UI scaling is properly reworked.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:17:43 +02:00
Maxim Isaev 36f3d42dbe feat(discovery): Navidrome AudioMuse-AI client integration and library scoping
Add per-server toggle for AudioMuse-style discovery: Instant Mix via
getSimilarSongs, server similar artists instead of Last.fm on artist pages,
and higher similar-artist count in Now Playing when enabled.

When browsing a single music folder, filter similar/top song results by
album ids from that scope (Navidrome does not apply musicFolderId to those
endpoints). Request larger similar batches under a narrow scope.

Keep radio-from-track as two blocks (shuffled top songs, then shuffled
similar-by-artist) so it differs from Instant Mix. Show Alpha badge beside
the setting. Add research/ to .gitignore.
2026-04-10 12:07:32 +03:00
Psychotoxical 49f7fe5f6e feat: add ICY metadata and AzuraCast radio streaming support (#146)
feat: add ICY metadata and AzuraCast radio streaming support
2026-04-10 11:05:59 +02:00
Psychotoxical 28943f1ecb chore(settings): disable UI scale slider pending rework
Interface scaling is temporarily disabled in the Settings UI
(opacity + pointer-events: none) with a note that it will return
in a future update.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:04:21 +02:00
Nils Israel 46cefb5712 feat: add ICY metadata and AzuraCast radio streaming support
Agent-Logs-Url: https://github.com/nisrael/psysonic/sessions/88faada5-28bb-446f-b53b-46a0efef387e

Co-authored-by: GitHub Copilot <198982749+copilot@users.noreply.github.com>
Signed-off-by: Nils Israel <nils@sxda.io>
2026-04-10 10:38:59 +02:00
Psychotoxical 74985fe331 fix(audio): fall back to track gain when album gain is missing
In album gain mode, tracks without albumGain tags received no
ReplayGain adjustment at all. Now falls back to trackGain before
defaulting to 0 dB — fixes inconsistent loudness across albums
where only some tracks have albumGain metadata.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 01:12:06 +02:00
Psychotoxical 4861d99cb1 fix(statistics): library-scoped genre stats, cached fetches, duration i18n
fix(statistics): library-scoped genre stats, cached fetches, duration i18n
2026-04-10 01:11:29 +02:00
Maxim Isaev d2592839b0 i18n(ru): use «Популярное» for most-played nav, home, and page title
«Чаще всего» read awkwardly; «Популярное» matches the play-count sense
without sounding like a grammar exercise.
2026-04-10 02:06:24 +03:00
Maxim Isaev bbeb2f661e merge: integrate origin/main into fix/statistics-i18n-small-fixes 2026-04-10 01:42:14 +03:00
Psychotoxical 5f0fb5dcbd feat(audio): auto-switch to new audio output device at runtime
Adds a background device-watcher that polls the OS default output device
every 3 s via CPAL. When the device changes (Bluetooth headphones connecting,
USB DAC plugging in, etc.) the stream is reopened on the new device, the old
Sink is dropped (it was bound to the now-closed OutputStream), and
audio:device-changed is emitted to the frontend.

Frontend handler (TauriEventBridge): if playing, restarts the current track
from the saved position; if paused, clears the warm-pause flag so the next
resume uses the cold path (audio_play + seek) which creates a new Sink on
the new device.

Fixes #143 (audio through speakers after connecting Bluetooth headphones).
Also covers the intermittently reported single-channel output after long idle,
which can be caused by the OS reconfiguring the audio device in the background.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 00:40:12 +02:00
Maxim Isaev 6f6cb0fd6b fix(statistics): cache Subsonic stat fetches and localize duration units
Add 7-minute TTL caches (same idea as rating prefetch) for overview
album strips, random-song format sample, and paginated library
aggregates; key by server and music folder.

Introduce formatHumanHoursMinutes with common.duration* strings in all
locales for Statistics and playlist duration labels.

Refresh RU/ZH statistics and nav wording; fix zh playtime label.
2026-04-10 01:39:08 +03:00
Psychotoxical 15dc970f53 fix(audio): restore msg binding in DecodeError arm, use SlidersVertical for EQ icon
- Revert _msg → msg in DecodeError match arm; the variable is used in the
  debug_assertions eprintln! block so the underscore prefix caused a compile error
- Replace SlidersHorizontal with SlidersVertical (lucide-react) in PlayerBar,
  LiveSearch, and AdvancedSearch so the EQ/filter icon shows vertical bars

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 00:28:12 +02:00
Maxim Isaev fc40d235d0 fix(statistics): scope genre insights to selected music library
getGenres() ignores musicFolderId. Derive genre counts from the same
paginated getAlbumList('newest') scan used for playtime and totals,
using each album's genre and songCount.
2026-04-10 01:18:44 +03:00
Psychotoxical f304589ea1 fix(audio): suppress unused variable warning in DecodeError match arm
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 00:15:55 +02:00
Psychotoxical 22f7de45e8 fix(audio): set User-Agent header, add debug fetch logging
Set psysonic/<version> as User-Agent on the audio reqwest::Client to
prevent reverse proxies (nginx, Caddy, Traefik) from blocking requests
with a 403. Add #[cfg(debug_assertions)] logging in fetch_data to show
the exact URL, status, content-type and server header — useful for
diagnosing proxy-related 403s reported by users.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 23:52:02 +02:00
Psychotoxical 05da369aad chore(aur): bump pkgver to 1.34.7
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 23:29:11 +02:00
Psychotoxical 9671f89a48 chore: bump version to 1.34.7, add changelog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 23:28:54 +02:00
Psychotoxical 9567a94dea feat(windows): replace GDI taskbar icons with embedded .ico assets
Strips the legacy monochrome GDI drawing code and loads high-quality
icons from embedded .ico files via CreateIconFromResourceEx. Fixes
windows 0.58 import paths (Controls→Shell subclassing, TaskbarList CLSID)
and adds proper cleanup for all four HICONs on WM_NCDESTROY.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 23:14:21 +02:00
Psychotoxical 1ba8619a37 chore: remove preview-update debug button, add GDI features, add contributor
- Remove debug "Preview Update Modal" button from Settings/About
- Add Win32_Graphics/Win32_Graphics_Gdi features for taskbar GDI icons
- Add sorensiimSalling contributor credit for Russian translation (PR #140)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:30:23 +02:00
kilyabin 973b472c1f fix: not translated lyricsServer* string to RU locale (#140) 2026-04-09 22:24:03 +02:00
Psychotoxical 20bf93c344 feat(windows): taskbar thumbnail toolbar with GDI media icons
Implements ITaskbarList3::ThumbBarAddButtons for Prev/Play-Pause/Next
buttons in the Windows taskbar thumbnail preview. Icons are drawn at
runtime via GDI (no binary assets). WndProc subclass intercepts
THBN_CLICKED and emits the same media:* events as souvlaki/tray.
update_taskbar_icon command swaps Play↔Pause icon on state change.
Frontend syncs via playerStore subscribe alongside mpris_set_playback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:12:35 +02:00
Psychotoxical fd834314ba fix(audio): VLC-style frame dropping for corrupt MP3s, silence logs in release
Replace the fixed DECODE_MAX_RETRIES (3) loop with a consecutive-error counter
that tolerates up to 100 bad frames before giving up — matching how VLC handles
files with a handful of invalid main_data offset frames. Frame-drop logs are
wrapped in #[cfg(debug_assertions)] so production builds stay silent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 21:42:38 +02:00
Psychotoxical a78c0fe9ac fix: font switching, layout scaling, embedded lyrics, folder opening
- fix(fonts): update CSS var declarations to @fontsource-variable naming
  ('Inter Variable', 'Outfit Variable', etc.) so dynamic font switching works
- fix(layout): 100vh → 100% on .app-shell to fix Windows WebView2 playerbar drift;
  1fr → minmax(0,1fr) in all grid-template-rows + remove min-height: 720px to fix
  Linux playerbar disappearing at high zoom or small window sizes
- fix(updater): replace shell open() with Rust open_folder command to bypass
  shell:allow-open capability scope blocking local paths on Windows
- fix(lyrics): add get_embedded_lyrics Tauri command (id3 crate for MP3 SYLT/USLT,
  lofty for FLAC SYNCEDLYRICS/LYRICS); fix parseLrc regex for LRC without fractional
  seconds; fix SubsonicStructuredLyrics to accept both synced and issynced fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 16:52:27 +02:00
Psychotoxical 9c57d4f887 feat(updater): professional update modal with skip, changelog, and OS-aware downloader
Replaces the small corner toast with a centered modal that appears on
startup when a newer GitHub release is detected (4 s delay).

Features:
- Skip this Version: stores skipped tag in localStorage, reappears only
  for newer releases
- Collapsible changelog: renders GitHub release body as markdown accordion
- OS-aware download: Windows → .exe installer, macOS → .dmg (aarch64
  preferred), Linux Arch → AUR hint (yay/pacman), Linux other → .AppImage/.deb
- In-app downloader: Rust download_update command streams to ~/Downloads/,
  emits update:download:progress every 250 ms for a real-time progress bar
- Post-download: Show in Folder button opens Downloads dir via shell.open
- Buttons: Download Now / Skip this Version / Remind me Later

Rust: check_arch_linux() reads /etc/arch-release + /etc/os-release
platform.ts: adds IS_MACOS, IS_WINDOWS alongside existing IS_LINUX
Settings About: Preview Update Modal button for testing
Fixes: renderInline regex had nested capture group causing undefined entries
in split() result → TypeError → React crash → WebKit white-screen freeze

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:23:48 +02:00
Psychotoxical 5d067b1f8b fix(app): hide resize grips in native fullscreen on all platforms
Previously onResized only tracked fullscreen on Linux. Now all platforms
set isWindowFullscreen, and an initial check on mount catches windows
that start maximized/fullscreened. CSS: .app-shell[data-fullscreen] .resizer
{ display: none } added in layout.css (shipped with updater commit).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:23:48 +02:00
Psychotoxical 48d0145dc8 fix(albums): align year filter inputs to button height and font size
Input padding and font-size now match adjacent .btn elements so the
year filter row no longer has mixed heights.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:23:48 +02:00
Psychotoxical 0da92c2fa1 fix(radio): prevent macOS WKWebView crash + shuffle Artist Radio queue
- Remove currentTime from Zustand persist partialize: it caused 100ms
  localStorage writes that grew with the queue, crashing WKWebView SQLite
  after ~10 min of Artist Radio on macOS
- Trim old played radio tracks from queue (keep last 5) to cap localStorage
  payload size during proactive radio top-up in next()
- Add reconnect logic for internet radio stall events (max 5 retries)
- Shuffle initial Artist Radio queue via Fisher-Yates so positions 2+
  are drawn from similar-artist tracks, not predictable top-5 tracks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:23:48 +02:00
Psychotoxical 4e3efa3814 feat: self-host fonts via @fontsource-variable, remove Google Fonts CDN
Replaces all Google Fonts CDN references (index.html preconnect/stylesheet
and theme.css @import) with local @fontsource-variable npm packages.
All 10 UI fonts now bundle as WOFF2 into dist/assets/ — app renders
correctly without any internet connection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:23:48 +02:00
Psychotoxical 77085a544e chore(credits): add missing contributor PRs to Settings page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:23:48 +02:00
Psychotoxical 8ffecb4b7c Merge pull request #138 from cucadmuh/fix/statistics-music-folder-totals
fix(statistics): scope album and song totals to selected music library
2026-04-09 12:48:02 +02:00
Maxim Isaev c569ff5f34 fix(statistics): scope album and song totals to selected music library
getGenres() is not musicFolder-scoped, so summing genre counts showed
global totals while other statistics respected the library filter.
Derive album and track counts from the same paginated getAlbumList
pass used for playtime, with the same 5000-album cap and ≥ prefix when
capped.
2026-04-09 00:59:16 +03:00
Psychotoxical d16a99a6f9 docs(help): add 11 new FAQ entries for undocumented features
Ratings (q37-q39): how to rate songs/albums/artists, click active star to
remove rating, Skip-to-1★ and rating filter for mixes. Folder Browser (q40).
Settings: Theme Scheduler (q41), UI Scale (q42), Seekbar styles (q43),
AutoEQ (q44), Replay Gain (q45), Hot Cache (q46). Offline: playlist
caching and toggle (q47). All 7 locales updated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 22:52:36 +02:00
Psychotoxical 9b239892ef chore: bump version to 1.34.6, add changelog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 22:36:59 +02:00
Psychotoxical ba670bd1e8 feat: fix UI freezes in ZIP and offline cache downloads
ZIP downloads (PlaylistDetail, Albums, NewReleases, RandomAlbums) now use
invoke('download_zip') via Rust streaming instead of fetch+blob+arrayBuffer,
eliminating JS heap saturation on large files. Progress shown in ZipDownloadOverlay.

Offline cache downloads (600+ songs) no longer freeze the UI: transient job
state moved to a separate non-persisted offlineJobStore, reducing localStorage
writes from ~1200 down to 2 for an entire download. Also adds playlist offline
toggle — clicking the cache button when already cached removes it from cache.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 22:33:23 +02:00
Psychotoxical c1e57b4c06 fix(home): recently added albums title links to /new-releases instead of /albums 2026-04-08 18:56:39 +02:00