# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [1.5.0] - 2026-03-18 ### Added #### 10-Band Graphic Equalizer - Full **10-band graphic EQ** implemented entirely in the Rust audio engine using biquad peak filters (31 Hz – 16 kHz). Gains adjustable ±12 dB per band. - EQ is processed in the audio pipeline via `EqSource` — a custom `rodio::Source` wrapper that applies cascaded biquad filters in real-time. - Filter coefficients update smoothly on every 1024-sample block without audio interruption. - **Seek support**: `EqSource::try_seek()` implemented — filter state is reset on seek to prevent clicks/artefacts. This also **fixes waveform seek**, which had silently broken when the EQ was introduced (rodio returned `SeekError::NotSupported` without the impl). - **10 built-in presets**: Flat, Bass Boost, Treble Boost, Rock, Pop, Jazz, Classical, Electronic, Vocal, Acoustic. - Custom presets: save, name, and delete your own presets. - EQ state persisted via `psysonic-eq` localStorage key (gains, enabled, active preset, custom presets). - New `audio_set_eq` Tauri command; settings synced to Rust on startup via `eqStore.syncToRust()`. #### Connection Indicator - **LED indicator** in the header bar (green = connected, red = disconnected, pulsing = checking). Sits between the search bar and the Now Playing dropdown. - Shows server name and LAN/WAN status next to the LED. - **Offline overlay**: when the server is unreachable, a full-content-area overlay appears with a retry button. - `useConnectionStatus` hook pings the active server periodically and exposes `status`, `isRetrying`, `retry`, `isLan`, and `serverName`. #### Now Playing Page - New `/now-playing` route and `NowPlayingPage` component — accessible from the sidebar. ### Fixed #### Waveform Seek (Player Bar) - **Drag out of canvas no longer breaks seeking**: `mousemove` and `mouseup` events are now registered on `window` (not the canvas element), so dragging fast across other elements still updates playback position correctly. - **Stale closure fix**: `trackId` and `seek` function are kept in refs so the window-level handlers always see the current values. ### Changed #### App Icon - New app icon (`public/logo-psysonic.png`) across all platforms — Login page, Sidebar, Settings About section, README header, and all generated Tauri platform icons (Windows ICO, macOS ICNS, Linux PNGs, Android, iOS). ## [1.4.5] - 2026-03-17 ### Changed #### Artist Pages — External Links - Last.fm and Wikipedia buttons now open in the **system browser** instead of an in-app window. The button label temporarily changes to "Opened in browser" / "Im Browser geöffnet" for 2.5 seconds as visual confirmation. #### Queue Panel - **Release year** added to the now-playing meta box, shown below the album name (when available). - **Cover art enlarged** from 72 × 72 px to 90 × 90 px, aligned to the top of the meta block so it lines up with the song title. - **Default width increased** from 300 px to 340 px. ## [1.4.4] - 2026-03-17 ### Added #### AUR Package - Psysonic is now available on the **Arch User Repository** — Arch and CachyOS users can install via `yay -S psysonic` or `paru -S psysonic`. Builds from source using the system's own WebKitGTK, avoiding the EGL/Mesa compatibility issues that affected the AppImage on modern distros. ### Changed #### App Icon - New app icon across all platforms (Windows, macOS, Linux, Android, iOS). #### Linux Distribution - **AppImage removed**: The AppImage was fundamentally incompatible with non-Ubuntu distros (Arch, Fedora) due to bundled WebKitGTK conflicting with the system's Mesa/EGL. Linux users should use the `.deb` (Ubuntu/Debian), `.rpm` (Fedora/RHEL), or the new AUR package (Arch/CachyOS). ## [1.4.3] - 2026-03-16 ### Fixed #### Random Mix — Genre Mix - **Second "Play All" button removed**: The genre mix section had a redundant play button below the super-genre selector. The top-right button is now context-aware — it plays the genre mix when one is active, otherwise the regular mix. - **"Play All" disabled during genre mix loading**: The button now stays grayed out with a live progress counter (`n / 50`) until all songs are fully loaded. Clicking while the list was still building sent only the songs loaded so far. - **Over-fetching fixed**: Genre mix previously fetched up to 100+ songs and sliced to 50 at the end. Now the matched genre list is capped at 50 (randomly sampled when more match) so the total fetch stays close to 50 with no wasted server I/O. - **Regular mix cache-busting**: `getRandomSongs` requests now include a timestamp parameter, preventing browser/axios from returning a cached response and showing the same list on every remix. - **Display/state mismatch on remix**: Clicking "Mischen" now clears the current list immediately, ensuring the spinner is shown and the displayed songs always match what "Play All" would send. #### Queue Panel - **Hover highlight lost on right-click**: Queue items now retain their hover highlight while a context menu is open for them (`.context-active` CSS class). - **Song count and total duration**: The queue header now shows the number of tracks and total runtime below the title (e.g. `12 tracks · 47:32`). #### Context Menu - **"Favorite" option added for queue items**: Right-clicking a queue item now includes a "Favorite" option, consistent with the song context menu. ## [1.4.2] - 2026-03-16 ### Fixed #### Linux AppImage — Modern Distro Compatibility - **Build upgraded to Ubuntu 24.04**: The AppImage was previously built on Ubuntu 22.04 with WebKitGTK 2.36. On modern distros (CachyOS, Arch, etc.) with Mesa 25.x, `eglGetDisplay(EGL_DEFAULT_DISPLAY)` returns `EGL_BAD_PARAMETER` and aborts immediately because newer Mesa no longer accepts implicit platform detection. Building on Ubuntu 24.04 bundles WebKitGTK 2.44 which uses the correct `eglGetPlatformDisplay` API. - **`EGL_PLATFORM=x11` added to AppRun**: Additional safeguard that explicitly tells Mesa's EGL loader to use the X11 platform when the app is running under XWayland. #### Shell — Update Link - `shell:allow-open` capability now includes a URL scope (`https://**`), fixing the update toast link that silently did nothing in Tauri v2 without an explicit allow-list. ## [1.4.1] - 2026-03-16 ### Fixed #### Random Albums — Performance & Memory - **Auto-refresh removed**: The 30-second auto-cycle timer caused 10 React state updates/second (progress bar interval) and a burst of 30 concurrent image fetches on every tick, eventually making the whole app unresponsive. The page now loads once on mount; use the manual refresh button to get a new selection. - **Concurrent fetch limit**: Image fetches are now capped at 5 simultaneous network requests (was unlimited — 30 at once on every refresh). - **Object URL memory leak**: The in-memory image cache now caps at 150 entries and revokes old object URLs via `URL.revokeObjectURL()` when evicting. Previously, object URLs accumulated without bound across the entire session. - **Dangling state updates**: `useCachedUrl` now uses a cancellation flag — if a component unmounts while a fetch is in flight (e.g. during a grid refresh), the resolved URL is discarded instead of calling `setState` on an unmounted component. #### i18n - Page title "Neueste" on the New Releases page was hardcoded German. Now uses `t('sidebar.newReleases')`. ## [1.4.0] - 2026-03-16 ### Added #### Statistics Page — Upgraded - **Library overview**: Four stat cards at the top showing total Artists, Albums, Songs, and Genres — counts derived from the library in parallel. - **Recently Played**: Horizontal scroll row showing the last played albums with cover art. - **Most Played**: Ranked list of the most frequently played tracks. - **Highest Rated**: List of top-rated tracks by user star rating. - **Genre Chart**: Visual bar chart of the top genres by song and album count. #### Playlists Page — Redesigned - Replaced the card grid with a clean list layout. - **Sort buttons**: Sort by Name, Tracks, or Duration — click again to toggle ascending/descending. - **Filter input**: Live search across playlist names. - Play and delete buttons appear on row hover. #### Favorites — Songs Section Upgraded - Tracks now display in a full tracklist layout matching Album Detail: separate `#`, Title, Artist, and Duration columns with a header row. - Artist name is clickable and navigates to the artist page. - Right-click context menu on any track (Go to Album, Add to Queue, etc.). - **"Add all to queue"** button (`btn btn-surface`) next to the section title. #### Context Menu — Go to Album - New **Go to Album** option (`Disc3` icon) added for `song` and `queue-item` context menu types. - Only shown when the song has a known `albumId`. #### Queue Panel — Meta Box - Now shows: **Title** (no link) → **Artist** (linked to artist page) → **Album** (linked to album page). - Removed year display and the old title→album link. #### Random Mix — Hover Persistence - Track row stays highlighted while its context menu is open via `.context-active` CSS class. - Highlight is cleared automatically when the context menu closes. #### Artist Cards — Redesigned - `ArtistCardLocal` now matches `AlbumCard` exactly: no padding, full-width square cover via `aspect-ratio: 1`, name and meta below. - Uses `CachedImage` with `coverArtCacheKey` for proper IndexedDB caching. - Same `flex: 0 0 clamp(140px, 15vw, 180px)` sizing as album cards — artist cards are no longer oversized. ### Fixed #### Random Albums — Cover Loading & Manual Refresh - **Removed `renderKey`**: The album grid was fully remounted on every refresh, restarting all 30 IndexedDB image lookups from scratch. Grid is now stable — only data changes, images stay cached. - **`loadingRef` guard**: Prevents concurrent fetch calls if the auto-cycle timer fires during a manual refresh. - **Timer race condition**: Manual refresh now calls `clearTimers()` before `load()`, eliminating the race where the auto-cycle timer fired mid-load. #### Favorites — Artist Navigation - Arrow nav buttons in the Artists section now use the same CSS classes as the Albums section (`album-row-section`, `album-row-header`, `album-row-nav`) — consistent styling across both rows. ### Changed - **AlbumDetail** refactored into a thin orchestrator. Logic extracted into `AlbumHeader` (`src/components/AlbumHeader.tsx`) and `AlbumTrackList` (`src/components/AlbumTrackList.tsx`). - **German i18n**: "Queue" consistently translated as "Warteschlange" throughout — `queue.shuffle`, `favorites.enqueueAll`. ## [1.3.0] - 2026-03-15 ### Added #### Player Bar — Complete Redesign - **Waveform seekbar**: Replaces the classic thin slider. A canvas-based waveform with 500 deterministic bars (seeded by `trackId`) fills the full available width. Played portion renders as a blue → mauve gradient with a soft glow; buffered range is slightly brighter; unplayed bars are dimmed to 28% opacity. Click or drag anywhere to seek. - **New layout**: Single flex row — `[Cover + Track Info] [Transport Controls] [Waveform + Times] [Volume]`. More breathing room for the waveform; controls feel lighter and better proportioned. - **Queue toggle relocated**: Moved from the bottom player bar to the top-right of the content header — consistent with the sidebar collapse button pattern. Uses `PanelRightClose` / `PanelRight` icons (same family as `PanelLeftClose` / `PanelLeft` in the sidebar). #### Ambient Stage — MilkDrop Visualizer - **Butterchurn integration**: Clicking the waveform icon (top-right of the fullscreen player) activates the MilkDrop visualizer powered by [butterchurn](https://github.com/jberg/butterchurn) + `butterchurn-presets`. - A hidden `