Commit Graph

945 Commits

Author SHA1 Message Date
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
Psychotoxical fbe68116cc chore(aur): bump pkgver to 1.34.5 2026-04-08 18:05:26 +02:00
Psychotoxical dba0c26480 docs(changelog): add v1.34.5 release notes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 18:04:03 +02:00
Psychotoxical 3643a78cd6 perf: drastically reduce background API requests to Navidrome (v1.34.5)
- NowPlaying polling: only active while dropdown is open + respects
  Page Visibility API — was firing every 10s unconditionally (~8.6k req/day)
- Connection check interval: 30s → 120s (4× reduction)
- Queue sync debounce: 1.5s → 5s (prevents burst on rapid skip)
- Rating prefetch: add 7-minute in-memory TTL cache for artist/album
  ratings — repeated random album loads no longer re-fetch known ratings

Fixes server log flooding reported by users behind reverse proxies (Traefik).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 18:04:03 +02:00
Psychotoxical 1e4b851e9e feat: disable native decorations on Linux, hide custom TitleBar for tiling WMs
feat: disable native decorations on Linux, hide custom TitleBar for t…
2026-04-08 17:49:38 +02:00
kilyabin 37799fb861 feat: disable native decorations on Linux, hide custom TitleBar for tiling WMs
On tiling window managers (Hyprland, Sway, i3, bspwm, AwesomeWM, Openbox, etc.)
     the window has no title bar at all — neither native nor custom. On stacking DEs
     (GNOME, KDE, XFCE) the custom TitleBar can be toggled in settings as before.

     Native decorations are disabled on all Linux at startup. The frontend checks
     is_tiling_wm() to decide whether to render the custom TitleBar:
     - DE (GNOME/KDE): custom TitleBar shown (user-toggleable in settings)
     - Tiling WM: no TitleBar at all, setting hidden from Settings page

     Detection is based on environment variables:
     - HYPRLAND_INSTANCE_SIGNATURE, SWAYSOCK, I3SOCK (direct compositor signatures)
     - XDG_CURRENT_DESKTOP check for known tiling WMs

     Changes:
     - Added is_tiling_wm_cmd() Tauri command for frontend detection
     - Native decorations disabled on all Linux at startup
     - TitleBar not rendered on tiling WMs
     - Custom TitleBar setting hidden in Settings for tiling WMs
2026-04-08 19:36:39 +04:00
Psychotoxical 099516121e perf(fullscreen): fix dynamic accent color delay via direct fetch + cache
- Bypass ImageCache 5-slot queue: fetch cover art directly, create blob URL
  for canvas extraction, revoke immediately after use
- Module-level cache (artKey → accent) avoids re-fetching within the same
  album — same-cover tracks get the color instantly
- Keep previous color visible on cache miss instead of flashing to theme color

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 16:13:48 +02:00
Psychotoxical 9047a44480 perf(fullscreen): extract dynamic accent from already-loaded cover blob
Previously a separate getCachedUrl call fetched the 300px cover art just
for color extraction, racing with the 500px fetch for display. Now reuses
resolvedCoverUrl directly — color appears as soon as the display image is
ready, with no redundant network request.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:56:18 +02:00
Psychotoxical 47fcade3b3 feat(settings): show hint in theme picker when scheduler is active
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:51:43 +02:00
Psychotoxical d832dfb253 fix(statistics): remove Top Rated Songs/Artists sections
The implementation was unreliable (depended on starred songs + session-only
overrides) so the sections are removed entirely. All PR#130 rating logic
(StarRating, setRating API calls, userRatingOverrides) is untouched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:37:12 +02:00
Psychotoxical 041d946b58 feat(settings): 12-hour AM/PM time format for English locale in theme scheduler
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:23:46 +02:00
Psychotoxical 64d8b1cbd3 fix(titlebar): window drag, resize grips and mobile-mode grid for custom titlebar
- Add core:window:allow-start-dragging capability so data-tauri-drag-region
  actually works (was silently blocked without this permission)
- Add CSS resize grips (bottom-left + bottom-right) that replace the native
  GTK grip lost when decorations: false
- Add [data-mobile][data-titlebar] grid override so the titlebar renders
  correctly in narrow-window mode instead of being hidden

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:13:58 +02:00
Psychotoxical 5848c621fd feat(folder-browser): Miller columns directory navigation
New page /folders with macOS Finder-style column layout:
- getMusicDirectory / getMusicIndexes / getMusicFolders Subsonic API methods
- Root level uses getIndexes.view (music folder IDs are not getMusicDirectory IDs)
- Columns fill available width with flex: 1, min-width: 200px
- Auto-scroll to rightmost column on expand
- Cancelled-flag prevents stale state on fast navigation
- Clicking a track plays it in the context of the current column's tracks
- FolderOpen/Folder/Music icons, accent-colored selection, ellipsis truncation
- Hidden in sidebar by default (user can enable in Settings)
- i18n: EN DE FR NL NB ZH RU

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 14:40:29 +02:00
Psychotoxical 0a0dde057d feat(seekbar): fade edges on waveform style
Apply a destination-in gradient mask after drawing the waveform bars so
both the left and right edges fade smoothly to transparent instead of
cutting off abruptly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 13:30:01 +02:00
Psychotoxical 0119e27f6d feat(covers): logo fallback for broken cover art images
CachedImage now shows /logo-psysonic.png when an image fails to load
instead of a broken icon. The fallback switches to object-fit: contain
with a card background so the logo stays proportional inside the container.

If the caller provides a custom onError (e.g. to hide the element), that
handler is used instead. A separate fallbackSrc state prevents React from
re-writing the broken URL on re-renders. The DOM-level onerror = null
guard prevents any infinite error loop.

extractCoverColors skips color extraction when the logo fallback is
active, falling back to the theme accent color instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 13:25:25 +02:00
Psychotoxical c7adb599ee fix(artist): decouple artist info fetch from main render path (fix #132)
getArtistInfo2.view can trigger Navidrome to do slow external lookups
(Last.fm / Apple Music) when no local artist image exists, blocking the
entire page for 10+ seconds.

Render the page immediately after getArtist() resolves (local data only),
then fire getArtistInfo and getTopSongs in the background. A cancelled
flag prevents stale state updates when the user navigates away before
either background fetch completes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 13:10:01 +02:00
Psychotoxical d6546e12ca docs(readme): bring features and roadmap up to date with v1.34.4
- Update language count to 7 (add Norwegian and Russian)
- Update theme count to 67, add Theme Scheduler mention
- Expand seekbar description to all 10 styles
- Add missing features: Ratings, Fullscreen Player, Playlist Management,
  AutoEQ, Internet Radio, Tray Icon, Backup & Restore, UI Scale,
  Album Multiselect, Custom Linux Titlebar
- Add ~15 missing completed items to roadmap

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 12:57:25 +02:00
Psychotoxical f0438cae5e fix(seekbar): pulsewave clean connection, retrotape rolling wheel at playhead
Pulsewave: draw flat played line only up to where the Gaussian envelope
starts (startX), eliminating overlap between the flat line and the wave.

Retrotape: replace dual fixed-position reels with a single spinning reel
that tracks the playhead position across the full seek bar width.

fix(i18n): remove literal 'N' from skip-star descriptions in all languages

Replace 'After N skips' with natural phrasing ('after several skips') in
EN, FR, NL, NB, ZH. Simplify ratingsSkipStarThresholdLabel to a single
word (Skips / Sauts / Overslagen / Hopp / 跳过次数). DE was already fixed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 12:46:58 +02:00
Psychotoxical e64d151079 feat(settings): theme scheduler, UI scale, CustomSelect scroll fix
- Time-based theme scheduler: auto-switches between day/night theme
  based on configurable times; setInterval re-checks every minute
- UI scale slider (80–150%) via CSS zoom on document root; preset
  buttons aligned to actual slider positions
- CustomSelect: scroll listener keeps dropdown anchored on scroll
- All features i18n in 7 languages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 12:23:24 +02:00
Psychotoxical f0b423ddc4 Update CHANGELOG.md 2026-04-08 12:04:37 +02:00
Psychotoxical 8f3b9ebe00 ci: use setup-node built-in npm cache instead of manual cache step 2026-04-08 11:30:05 +02:00
Psychotoxical d4b18fec5a fix(statistics): explicit Map<string, SubsonicSong> type to satisfy tsc 2026-04-08 11:17:05 +02:00
Psychotoxical dbb53bfa70 release: bump to v1.34.4
Song ratings in context menu + player bar, entity ratings (PR #130),
5 new seekbar styles, custom Linux title bar, album multi-select,
mix rating filter, top-rated stats, compilation filter, scroll reset.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 11:13:23 +02:00
Psychotoxical 737b057d4a feat(seekbar+ratings): 5 new seekbar styles and entity/mix rating system (PR #130)
Seekbar styles (5 new, by Psychotoxical):
- Neon Glow: transparent track, played section as multi-layer glowing neon tube
- Pulse Wave: flat line with animated gaussian sine pulse at playhead (rAF)
- Particle Trail: particles spawn at playhead and drift with glow (rAF)
- Liquid Fill: glass tube fills with liquid and animated wave surface (rAF)
- Retro Tape: two spinning reels connected by tape, shrink/grow with progress (rAF)

Ratings system (PR #130 by cucadmuh):
- Shared StarRating component with pulse/clear animations, disabled/locked states
- Entity ratings for albums and artists via OpenSubsonic probe (setEntityRatingSupport)
- Skip→1★: after N consecutive manual skips, set unrated track to 1★ (persisted per server)
- Mix rating filter: exclude low-rated songs/albums/artists from RandomMix, RandomAlbums, Hero, Home
- Batch refill in fetchRandomMixSongsUntilFull to fill list despite strict filters
- Prefetch artist/album ratings via getArtist/getAlbum for incomplete list payloads
- Settings: new Ratings section for skip threshold and per-axis mix filter stars
- i18n: all 7 languages (en, de, fr, nl, zh, nb, ru)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 10:29:21 +02:00
Maxim Isaev 0c2ac13fed merge: integrate origin/main into feat/improve-rating-ux
Resolve conflicts in RandomAlbums (keep mix rating filter with batch ZIP/offline
selection from upstream) and Settings (SeekbarPreview + mix filter constants).
2026-04-08 05:04:12 +03:00
Maxim Isaev 1624880c2a feat(ratings): mix cutoff filter for random flows and home, i18n
Apply the same per-axis star cutoff to random mix (multi-batch fetch until
full), random albums, Hero, and Home hero/discover rows. Prefetch artist and
album ratings via Subsonic when list payloads omit them. Exclude items when
0 < rating ≤ threshold; 0 or missing counts as unrated.

Settings: rating filter description interpolates sidebar menu labels; Russian
strings for custom title bar; short axis labels aligned across locales.
2026-04-08 04:57:26 +03:00