Commit Graph
1573 Commits
Author SHA1 Message Date
vicrodh 65b42295e9 feat(favorites): add genre filter to Albums tab
- Add GenreFilterButton to Favorites > Albums toolbar
- Filter albums by genre name (multi-select supported)
- Use genreFilterVersion for reactivity tracking

Note: Artists tab doesn't have genre filter since artist
objects don't contain genre info directly.
2026-02-02 09:49:06 -06:00
vicrodh 6e4f48ff2e style(ui): clear button always visible, popup 530px wide 2026-02-02 09:43:00 -06:00
vicrodh 8dc1efec5d feat(genre): support multi-select genre filter
- Allow multiple genre selection (checkbox behavior)
- Add getSelectedGenreNames() for multiple name retrieval
- Merge results from multiple API calls for featured albums
- Clear button now closes the popup
- Button shows "N genres" when multiple selected
2026-02-02 09:37:43 -06:00
vicrodh 22ba76a8d1 feat(home): filter user sections by genre
- Add getSelectedGenreName() to genre filter store
- Add filterAlbumsByGenre() helper in HomeView
- Apply genre filter to Recently Played and Favorite Albums
- Fetch 3x more items when filtering to ensure enough results
2026-02-02 09:29:55 -06:00
vicrodh eee364e29c style(ui): genre popup extends left, 480px wide, 3 columns 2026-02-02 09:26:17 -06:00
vicrodh e61891bfc2 style(ui): widen genre filter popup to 420px with 4 columns 2026-02-02 09:25:04 -06:00
vicrodh 1b68b85402 style(ui): make genre filter cards smaller and more neutral
- Reduce card height from aspect-ratio to fixed 36px
- Use neutral bg-tertiary background instead of colored gradients
- Horizontal layout with name and check circle
- Selected state uses accent-primary
- Better spacing to prevent overlap
2026-02-02 09:24:37 -06:00
vicrodh d37b4ef7ff fix(ui): prevent infinite loop in GenreFilterButton
Use onMount instead of $effect to load genres once.
Add initialized flag to prevent onFilterChange from firing
during initial subscription setup, which was causing
loadHome -> re-render -> loadGenres -> notify -> loadHome loop.
2026-02-02 09:11:18 -06:00
vicrodh 733a12d702 fix(reco): fix migration for existing users without genre_id column
Remove genre_id from base schema and let migration add it.
This ensures existing databases don't fail when trying to create
index on non-existent column during initial schema execution.
2026-02-02 09:07:47 -06:00
vicrodh 8428fafaa5 feat(home): integrate genre filter into HomeView
- Add GenreFilterButton to home header
- Pass genre_id to fetchFeaturedAlbums API calls
- Reload home content when genre filter changes
- Featured sections now filter by selected genre
2026-02-02 08:53:13 -06:00
vicrodh 0d0da7c5fc feat(ui): add genre filter store and components
- Add genreFilterStore.ts with localStorage persistence
- Add GenreFilterButton.svelte for filter trigger
- Add GenreFilterPopup.svelte with colored genre cards
- Support "Remember my selection" toggle
- Single-genre selection (API limitation)
2026-02-02 08:51:37 -06:00
vicrodh d0dd42db65 feat(reco): add genre backfill commands
- Add reco_backfill_genres command to populate genre_id for existing events
- Add reco_needs_genre_backfill command to check if backfill is needed
- Fetches album details from Qobuz API and updates events in batches
- Includes rate limiting to avoid API throttling
2026-02-02 08:49:02 -06:00
vicrodh b4d7f7f4c3 feat(reco): add genre_id to reco_store schema
- Add genre_id column to reco_events table
- Add migration to add column to existing databases
- Update RecoEventInput and RecoEventRecord structs
- Update insert_event and get_events_since to handle genre_id
- Add get_album_ids_without_genre() for backfill
- Add update_genre_for_album() for backfill
2026-02-02 08:47:43 -06:00
vicrodh c2d61b46dc feat(api): add genre_id filter to get_featured_albums
- Add optional genre_id parameter to client method
- Add optional genre_id parameter to Tauri command
- Qobuz API filters featured albums by genre when provided
2026-02-02 08:45:44 -06:00
vicrodh 8e31717908 feat(api): add genre list endpoint
- Add GENRE_LIST endpoint constant
- Add GenreInfo model with id, name, color, slug, path
- Add get_genres() method to client
- Add get_genres Tauri command
2026-02-02 08:44:42 -06:00
vicrodh b6c723d3df fix(search): use 4-quadrant collage for playlist cards 2026-02-02 08:11:48 -06:00
vicrodh de0b820230 fix(search): use standard menu styles for playlist card dropdown 2026-02-02 08:09:17 -06:00
vicrodh d27ae32aee feat(search): wire up playlist handlers in main page
- Add playPlaylistById to set queue and play first track
- Add queuePlaylistNextById to add playlist tracks next
- Add queuePlaylistLaterById to add playlist tracks later
- Add copyPlaylistToLibraryById using subscribe_playlist
- Add sharePlaylistQobuzLinkById to copy link to clipboard
- Connect all handlers to SearchView component
2026-02-02 08:06:27 -06:00
vicrodh 61dd071326 feat(search): integrate playlists into search page
- Add playlists to unified search results (SearchAllResults)
- Add dedicated Playlists tab in jump-nav
- Create SearchPlaylistCard with album-like overlay (heart/play/menu)
- Add playlist menu: Play next, Add to queue, Copy to library, Share
- Add offset parameter to search_playlists command
- Add PlaylistGenre and extra fields to Playlist model
- Update searchState with Playlist type and playlistResults

UI changes:
- Remove glyphs from search tabs
- Reduce tab spacing (gap 8px→4px, padding 16px→12px)
- Reduce filter font size (13px→12px)
2026-02-02 07:57:16 -06:00
vicrodh f6d2a6bddd feat(immersive): default to coverflow view when opening immersive mode 2026-02-01 19:43:55 -06:00
vicrodh 2431a66545 refactor(settings): move limit quality toggle below streaming quality
- Repositioned toggle to appear right after Streaming Quality dropdown
- Updated description to clarify it overrides quality setting when device
  doesn't support the selected sample rate
2026-02-01 19:40:19 -06:00
vicrodh 39e8814848 feat(settings): add limit quality to device toggle and max sample rate tracking
Frontend changes for quality limiting feature:
- Add limitQualityToDevice state and handler
- Add AudioSettings interface fields for limit_quality_to_device and device_max_sample_rate
- Update handleBackendDeviceChange to send max_sample_rate when device changes
- Update handleOutputDeviceChange to find max_sample_rate from backend devices
- Add Settings UI toggle for "Limit Quality to Device"

This completes the quality limiting feature that prevents requesting tracks
that exceed the device's sample rate capabilities, ensuring bit-perfect playback.
2026-02-01 19:29:15 -06:00
vicrodh 6d53907233 feat(audio): add quality limiting based on device capabilities
- Add limit_quality_to_device setting (enabled by default)
- Add device_max_sample_rate field to store selected device's max rate
- Implement limit_quality_for_device() to restrict quality based on device
- Apply quality limiting in play_track and prefetch_track commands
- Add set_audio_device_max_sample_rate Tauri command

This ensures bit-perfect playback by not requesting tracks that
exceed the device's sample rate capabilities. When enabled:
- Devices <= 48kHz: limited to Lossless (44.1kHz)
- Devices <= 96kHz: limited to HiRes (up to 96kHz)
- Devices > 96kHz: allow UltraHiRes (up to 192kHz)
2026-02-01 19:21:02 -06:00
vicrodh be4786e6d3 feat(settings): add limit_quality_to_device setting
Add new audio setting to limit streaming quality based on device
capabilities. When enabled (default: true), QBZ will avoid requesting
tracks that exceed the device's max supported sample rate.

This ensures bit-perfect playback by preventing the need to resample
high-res tracks on devices that don't support them.

- Add limit_quality_to_device field to AudioSettings
- Add database migration for new column
- Add Tauri command for frontend integration

cc
2026-02-01 19:15:11 -06:00
vicrodh da5ec2abcb feat(audio): implement controlled hw→plughw fallback for ALSA Direct
- Add AlsaDirectError enum for structured error classification
- Add BitPerfectMode enum to track runtime bit-perfect status
- Implement automatic fallback: hw fails with format error → try plughw
- Abort on non-recoverable errors (busy, permissions, invalid params)
- Respect ALSA plugin selection from UI settings
- Log runtime mode for debugging

This allows SMSL-class DACs that fail on hw: to work via plughw:
while maintaining bit-perfect guarantees (format conversion only,
no resampling).

cc
2026-02-01 19:13:11 -06:00
vicrodh 4670b1548a feat(audio): add S24_3LE format support for SMSL-class USB DACs
- Add S24_3LE (S243LE) to format priority list as first choice
- Implement S24_3LE write handler with 3-byte packed conversion
- Add S24LE write handler (was missing explicit implementation)
- Reorder format priority: S24_3LE > S32LE > S24LE > S16LE > FloatLE

This fixes bit-perfect playback on USB DACs that only support
the S24_3LE format (SMSL, Topping, Fosi with TAS1020B chip).

Closes #30

cc
2026-02-01 19:07:17 -06:00
vicrodh bb4fcfd6b8 Optimize visualizer: 16 bins mirrored, Material You colors
- Reduce FFT to 30fps with 16 bins (mirrored to 32 visual bars)
- Use 1024 FFT size for faster processing
- Extract dominant colors from album artwork
- Center artwork with track info and quality badge
- Bars render from edges inward with color gradient
2026-02-01 18:44:52 -06:00
vicrodh 4b74e1c490 Update visualizer track info: larger art, artist/album/track order
- Increase artwork to 108px (20% larger)
- Reorder info: Artist (bold) > Album (italic) > Track
- Add album prop to VisualizerPanel
- Adjust text styling hierarchy
2026-02-01 15:42:43 -06:00
vicrodh a46936da53 Move track info to bottom-right, text aligned left of artwork
- Position track info at bottom-right with margin
- Reduce artwork to 90x90px
- Text aligned right, to the left of artwork
- Compact layout that doesn't obstruct visualization
2026-02-01 15:40:48 -06:00
vicrodh 55c3e80bbc Switch to Canvas 2D wave visualizer for lower CPU usage
- Replace WebGL2 instanced bars with simple Canvas 2D waves
- Mirror wave from center (top + bottom)
- Quadratic bezier curves for smooth lines
- Gradient coloring: cyan -> blue -> purple
- Black #000000 background
- Much lighter than 128 WebGL instances
2026-02-01 15:38:44 -06:00
vicrodh 283d17b5b8 Use black background for visualizer view (skip ImmersiveBackground entirely) 2026-02-01 15:36:35 -06:00
vicrodh 587e204c7b Disable ambient background animation in visualizer view
Reduces CPU usage by disabling the WebGL ambient motion when
the visualizer tab is active - both are GPU intensive.
2026-02-01 15:35:31 -06:00
vicrodh 337d4866d6 Add Visualizer tab to Focus mode with mirror visualization
- Add 'visualizer' to FocusTab type
- Add Visualizer tab with Activity icon in ImmersiveHeader
- Update VisualizerPanel with mirror mode (bars up and down from center)
- Integrate VisualizerPanel in ImmersivePlayer focus view
- Three-color gradient: teal -> purple -> pink
- Track info overlay with artwork, title, artist
2026-02-01 15:33:47 -06:00
vicrodh 06d3de0d73 Add WebGL2 VisualizerPanel frontend component
- Instanced bar rendering with vertex/fragment shaders
- Receives binary frequency data via Tauri events
- R32F texture for efficient frequency data upload
- Cyan-to-magenta gradient coloring
- Auto-enables/disables backend when mounted/unmounted
- 64 frequency bars with logarithmic mapping from backend
2026-02-01 15:11:40 -06:00
vicrodh 7bc429744b Integrate visualizer with audio thread
- Add VisualizerTap to Player for sample capture
- Create wrap_source helper in audio thread
- Wrap all audio sources with TappedSource at 4 append points
- Player now captures samples for visualization when enabled
- Zero overhead when disabled (fast atomic check)

Audio samples flow: Source -> TappedSource -> RingBuffer -> FFT Thread -> Frontend
2026-02-01 15:10:51 -06:00
vicrodh b8cfcfb34a Add audio visualizer backend infrastructure
- Add spectrum-analyzer crate for FFT processing
- Create visualizer module with:
  - RingBuffer: lockless SPSC buffer for audio samples
  - FFT processor: dedicated thread for spectrum analysis
  - TappedSource: rodio Source wrapper for sample capture
  - VisualizerTap: shared state for audio thread integration
- Add Tauri commands: set_visualizer_enabled, is_visualizer_enabled
- Register visualizer in AppState and lib.rs

Backend compiles. Next: integrate with audio thread to capture samples.
2026-02-01 15:07:21 -06:00
vicrodh 5a93ac509d Fix volume spam: deduplicate set_volume calls in backend
- Skip setting volume if already at same value (0.001 tolerance)
- Skip logging when volume unchanged
- Prevents MPRIS/PipeWire feedback loop spam
2026-02-01 14:33:56 -06:00
vicrodh 43444951ba Hypersensitive sleeve parallax: ±120px H, ±35px V with power curve
- Doubled horizontal range to ±120px
- Doubled vertical range to ±35px
- Added power curve (0.7) for hypersensitivity near center
- Small mouse movements now produce dramatic response
2026-02-01 14:27:57 -06:00
vicrodh 33dc0ccafb Increase sleeve parallax range: 120px horizontal, 35px vertical 2026-02-01 14:26:16 -06:00
vicrodh 1a4fa3cc78 Remove all parallax from vinyl - only sleeve moves
- Vinyl stays perfectly centered, only rotates
- Removed X and Y parallax from vinyl position
- Removed parallax uniform from shader
- Only the cover art (sleeve) responds to mouse movement
2026-02-01 14:24:36 -06:00
vicrodh 2fe0efc3d4 Fix vinyl rotation: 33⅓ RPM, concentric, no Y-axis movement
- Set rotation speed to 33.333 RPM (0.0582 rad/frame at 60fps)
- Remove Y-axis parallax from vinyl position (stays centered)
- Remove Y parallax from shader for perfectly concentric rotation
- Add mipmaps and trilinear filtering for anti-aliasing
- Enable anisotropic filtering when available
2026-02-01 14:22:56 -06:00
vicrodh 81232457d1 Fix parallax values to prevent artifacts 2026-02-01 14:15:37 -06:00
vicrodh 68b863ea64 Extreme horizontal parallax and use PNG texture
- Use PNG instead of SVG for better WebGL compatibility
- Extreme horizontal parallax: cover 200px, vinyl 120px
- Reduced vertical parallax for subtle depth
- Shader parallax: 0.15 horizontal, 0.05 vertical
- Disc appears to slide out of sleeve with minimal mouse movement
2026-02-01 14:14:02 -06:00
vicrodh fc85d66f5c Fix VinylPanel: add padding and aggressive parallax
- Add padding around vinyl (scale UV by 1.15x)
- Discard pixels outside bounds to avoid edge artifacts
- Much more aggressive parallax: cover 80/50px, vinyl 50/35px
- Shader parallax offset increased to 0.08
- Vinyl size reduced to 85% for more breathing room
2026-02-01 14:10:55 -06:00
vicrodh 6265e685ea Update logo and regenerate all app icons
- Updated qbz-logo.svg and qbz-logo.png
- Added qbz-vinyl-v3.svg for VinylPanel
- Regenerated all Tauri icons from new logo
- Updated Android icons and favicon
2026-02-01 14:09:57 -06:00
vicrodh b068426e9f Rewrite VinylPanel with WebGL2 for performance
- Use WebGL2 canvas for vinyl rendering instead of CSS
- Load qbz-vinyl-v3.svg as texture
- Shader-based rotation when playing
- Parallax effect via uniforms (no DOM updates)
- Album cover slides left to reveal vinyl
- Much lower CPU usage than CSS animation
2026-02-01 14:08:57 -06:00
vicrodh 20b9aa2c86 Improve VinylPanel parallax sensitivity and alignment
- Double parallax sensitivity (30/20px cover, 18/12px disc)
- Cover and disc now vertically centered together
- Cover slides 15% left when playing to reveal disc
- Simplified transform calculations
2026-02-01 13:55:05 -06:00
vicrodh fcb81dad2b Fix VinylPanel layout and styling to match Figma design
- Correct z-ordering: cover in front (z-10), disc behind
- Cover slides left when playing to reveal disc
- Add mouse parallax effect for depth
- More visible grooves with alternating brightness
- Neutral gray colors instead of amber vintage
- Use system typography instead of Oswald
- Radial gradient on disc for realistic shading
2026-02-01 13:52:26 -06:00
vicrodh d79fdf58b6 Add Vinyl panel to Focus mode and fix MPRIS volume feedback loop
- Add VinylPanel.svelte with spinning vinyl disc animation
- Album cover slides left when playing to reveal disc
- CSS-based grooves (40 rings) and amber center label
- Vintage typography with "33 1/3 RPM" badge
- Add 'vinyl' as new Focus tab option in ImmersiveHeader
- Fix MPRIS/PipeWire volume feedback loop by checking if volume
  actually changed before calling setVolume
2026-02-01 13:51:19 -06:00
vicrodh 319150920b Enhance immersive ambient animation vibrancy and speed
- Increase animation speed to 1.8x for more dynamic movement
- Add per-channel histogram normalization to expand color range
- Boost saturation to 2.5x and brightness to 0.85
- Add 12% red channel boost for warmer tones
- Target color range 30-240 to lift shadows and preserve highlights
2026-02-01 13:42:41 -06:00