Commit Graph
100 Commits
Author SHA1 Message Date
vicrodh 0f6c24f4f9 fix(lyrics): disable karaoke gradient in immersive, increase font +2pt
- Font size: 28px inactive, 30px active
- Disabled background-clip karaoke effect in immersive mode
- Active line now pure white (#ffffff)
- Past lines dimmed to 35% opacity
2026-02-01 12:06:18 -06:00
vicrodh 9d3f05025a fix(immersive): preserve blue colors and improve lyrics readability
Shader:
- Fixed luminance formula that was killing blue (30% blend instead of 100%)

Lyrics:
- Added Oswald font for immersive lyrics
- Increased font size by 2pt (26px inactive, 28px active)
- Active lines now pure white with higher weight for clarity
2026-02-01 11:58:47 -06:00
vicrodh 01adbb7ab4 feat(immersive): enhance shader and widen lyrics panel
Shader improvements:
- Multi-sample blur (4 corners averaged)
- Luminance preservation over saturation
- Gradient tint (cool top, warm bottom) for anti-flat look

Layout:
- Lyrics panel width increased from 560px to 700px (+140px)
- Responsive breakpoint adjusted (480px → 620px)
2026-02-01 11:50:16 -06:00
vicrodh 7535fdb8cc fix(lyrics): add text shadow for contrast against any background
Immersive lyrics now have dark shadow behind text for readability
on light/warm backgrounds like Powerslave's golden tones.
2026-02-01 11:43:41 -06:00
vicrodh 240ca09c6a fix(immersive): sample 90-100% of image for complete color representation
Rely on extreme blur to destroy details, not cropping.
This ensures all dominant colors (like blue sky) are captured.
2026-02-01 11:39:32 -06:00
vicrodh 8917049b00 fix(immersive): increase crop sample size for more relevant colors
Zoom factor changed from 1.5-3x to 1.1-1.6x
Now samples 62-90% of image instead of 33-66%
2026-02-01 11:34:36 -06:00
vicrodh 0bdd83dc08 fix(immersive): destroy artwork structure, preserve only mood
Implement proper atmospheric background pipeline:
- Random NON-CENTERED crop (150-300% zoom) to break composition
- Extreme blur at small size (destroys all semantic detail)
- Scale up with smoothing for additional blur
- Color adjustments (saturation 1.4x, brightness 0.5x)
- Vignette overlay

The background is now an unrecognizable color field derived from
artwork colors. Acceptance test: "Can I identify the album from
the background alone?" must be NO.

Applies to both WebGL and CSS fallback renderers.
2026-02-01 11:32:29 -06:00
vicrodh e4a108dc16 refactor(immersive): separate blur and motion concerns
- texture-loader.ts: Multi-pass blur (4×15px) at 256x256 for CSS-equivalent quality
- ambient.frag: Simplified to UV drift, zoom breathing, and color breathing only
- Blur computed ONCE at load time, shader only does motion effects
- No per-frame blur, image processing, or texture uploads
2026-02-01 11:24:24 -06:00
vicrodh b110516965 feat(immersive): increase source quality to 256x256
- Source canvas now 256x256 (was 64x64)
- Light pre-blur (8px), GPU shader does main blur
- Increased shader blur radius and samples (16 samples)
- Should produce much smoother results
2026-02-01 10:53:13 -06:00
vicrodh add1cf3cc0 feat(immersive): add GPU blur + noise distortion in shader
- Multi-sample blur: 12 samples in circular pattern
- Noise-based UV distortion to break up pixelation
- Random sample offsets for organic blur effect
- All blur computation is GPU-side (no CPU cost)
2026-02-01 10:50:14 -06:00
vicrodh 6fc1156b93 fix(immersive): match original blur quality with triple-pass blur
- Canvas size back to 64x64 (like original)
- Blur radius 20px applied 3 times (20 + 20 + 10 = ~50px total)
- Expanded canvas for blur overflow, then crop to final
- Brightness 0.55, saturation 1.3 (matching original)
2026-02-01 10:46:43 -06:00
vicrodh 7795fa159e fix(immersive): increase animation visibility + more blur + debug logs
- Animation params increased: 8% UV drift, 5% zoom, 12% brightness
- Canvas reduced to 8x8 for maximum blur effect
- Added debug logs to verify animation is running
2026-02-01 10:31:18 -06:00
vicrodh 606fb43853 fix(immersive): proper two-canvas blur technique + reduce to 15fps
Blur fix:
- Use three separate canvases (source, blur, final)
- Apply blur filter when drawing BETWEEN canvases (not to self)
- Canvas size reduced to 16x16 for extreme blur when scaled
- Double blur pass for extra smoothness

CPU fix:
- Reduce animation from 30fps to 15fps
- Slow ambient motion doesn't need high frame rate
2026-02-01 10:27:12 -06:00
vicrodh 3a93651122 fix(immersive): increase blur intensity for proper background effect
- Reduce canvas to 32x32 (was 128) for more natural scaling blur
- Apply triple-pass blur technique:
  1. Scale down (interpolation blur)
  2. Apply blur filter and redraw
  3. Third pass for extra smoothness
- Adjust brightness to 0.45 (darker) and saturation to 1.3
- Lower JPEG quality to 0.7 (blur hides artifacts anyway)
2026-02-01 10:19:11 -06:00
vicrodh 34710e92e1 feat(immersive): integrate WebGL2 renderer into ImmersiveBackground
- ImmersiveBackground now checks WebGL2 availability on mount
- Dynamically imports ImmersiveAmbientCanvas when WebGL2 available
- Falls back to CSS blur when WebGL2 unavailable
- New props: enableAmbient (default true), ambientIntensity

Automatic renderer selection:
1. Check BUILD_IMMERSIVE_ENABLED (compile-time)
2. Check isRuntimeEnabled() (user preference)
3. Check isWebGL2Available() (browser capability)
4. If all pass: use WebGL2 with ambient motion
5. Otherwise: use CSS fallback (original behavior)
2026-02-01 10:13:50 -06:00
vicrodh c94857fc87 feat(immersive): add Phase 3 ambient motion shader
- Add shaders/ambient.frag with:
  - UV drift (slow wandering motion)
  - Zoom oscillation (breathing effect)
  - Color breathing (subtle brightness pulsing)
  - Configurable intensity via u_intensity uniform

- Update ImmersiveAmbientCanvas.svelte:
  - Use ambient shader instead of static
  - Add animation loop with requestAnimationFrame
  - Frame throttling at 30fps for power efficiency
  - Visibility-aware: pauses when tab hidden
  - Props: enableMotion, intensity
  - Responds to enableMotion changes dynamically

All motion computation is GPU-side. No CPU per-frame work
except uniform updates (3 floats).
2026-02-01 10:12:09 -06:00
vicrodh 350352afb9 feat(immersive): add Phase 2 texture loader with pre-blur
- Add utils/texture-loader.ts with:
  - Async pre-blur generation using canvas 2D
  - Blur cache (max 20 entries)
  - Request cancellation for rapid track changes
  - Abort signal support throughout

- Update ImmersiveAmbientCanvas.svelte:
  - Use texture-loader for blurred artwork
  - Handle cancellation gracefully
  - Report texture metrics
  - Clean up pending loads on destroy

Pre-blur is computed once per track change (CPU), then uploaded
to GPU texture. No per-frame blur computation.
2026-02-01 10:10:44 -06:00
vicrodh 979326eeba feat(immersive): add Phase 1 minimal WebGL2 renderer
- Add utils/webgl-utils.ts with context creation, shader compilation,
  texture loading, and cleanup utilities
- Add shaders/fullscreen.vert for fullscreen quad rendering
- Add shaders/static.frag for basic texture display
- Add shaders/index.ts for Vite ?raw shader imports
- Add ImmersiveAmbientCanvas.svelte component with:
  - WebGL2 context management
  - Context loss/restore handling
  - Automatic resize handling
  - Performance metrics reporting
- Update app.d.ts with shader file type declarations

This is a static renderer only - no animation yet.
Phase 2 will connect to real artwork with pre-blur.
2026-02-01 10:09:13 -06:00
vicrodh 19d0916a46 feat(immersive): add Phase 0 infrastructure for WebGL2 rendering
- Create src/lib/immersive/ module structure
- Add types.ts with ImmersiveState, ImmersiveConfig interfaces
- Add config.ts with build-time and runtime feature flags
- Add ImmersiveRenderer.ts with lifecycle management and stores
- Add index.ts as public API boundary
- Add VITE_IMMERSIVE_ENABLED to vite.config.js
- Add app.d.ts for TypeScript env declarations

Build without immersive: QBZ_IMMERSIVE=false pnpm build

No visual changes yet - this is capability detection and guards only.
2026-02-01 10:05:12 -06:00
vicrodh 600a33026a feat(immersive): add infinite play button to player controls 2026-02-01 08:44:20 -06:00
vicrodh 520aaf8185 feat(immersive): add History tab to split and focus modes
- Create HistoryPanel component for viewing playback history
- Add 'history' tab to split mode tabs
- Add 'history-focus' tab to focus mode tabs
- Sync history when immersive mode opens (fix coverflow prev tracks)
- Keyboard shortcuts: H for history, 5 for history-focus
2026-02-01 08:37:16 -06:00
vicrodh e72901ac79 fix(coverflow): include history tracks for previous covers 2026-02-01 08:22:58 -06:00
vicrodh 4e8c2f5a9b fix(coverflow): reduce shadow and reflection intensity 2026-02-01 08:18:54 -06:00
vicrodh 9099f94904 feat(immersive): add real coverflow with queue navigation
- Rename old CoverflowPanel to StaticPanel (single artwork view)
- Create new CoverflowPanel with actual coverflow effect:
  - Shows 5 album covers (2 prev, current, 2 next)
  - 3D perspective rotation on side covers
  - Click on side covers to navigate queue
  - Smooth animation on track change
- Add 'static' tab to focus mode (4 tabs total)
- Update keyboard shortcuts: 1-4 for focus tabs
2026-02-01 08:18:17 -06:00
vicrodh 1aa7e9eb3a fix(immersive): center mode toggle and fix icon direction
- Move mode toggle inside tabs nav (centered)
- Icon now shows target mode, not current mode
- Add divider between toggle and tabs
2026-02-01 08:10:42 -06:00
vicrodh 2004a59660 feat(immersive): unify tab navigation with view mode toggle
Consolidates navigation into single bar with mode toggle:
- Split mode tabs: Lyrics, Track Info, Suggestions, Queue
- Focus mode tabs: Coverflow, Lyrics, Queue
- Mode toggle button (lotus/split-view icons)
- V key toggles view mode, 1-3 for focus tabs
2026-02-01 08:08:51 -06:00
vicrodh aea99a66d6 Hide lyrics scrollbar by default, show on hover 2026-02-01 08:01:20 -06:00
vicrodh 6d2ff56bf0 Fix lyrics auto-scroll by restoring height: 100% to panel-section 2026-02-01 07:59:55 -06:00
vicrodh 15bfad00b8 Add unmaximize permission for restore button 2026-02-01 07:55:30 -06:00
vicrodh 8cdb63912c Fix radio card, suggestions height, and lyrics auto-scroll
- Radio card: Remove queue buttons (radio replaces entire queue)
- Suggestions panel: Add max-height 80vh like other panels
- Lyrics: Revert overflow change that broke auto-scroll
- Lyrics: Apply scrollbar-on-hover to internal LyricsLines component
2026-02-01 07:53:54 -06:00
vicrodh ed5e7d13cf Fix radio glyph z-index on collage overlay 2026-02-01 07:50:24 -06:00
vicrodh 2c389408d0 Add maximize/restore/minimize buttons and QualityBadge placement
Window controls:
- Maximize button shows restore icon when maximized
- Add minimize button
- Button order: Fullscreen | Maximize/Restore | Minimize | Exit | Close

QualityBadge placement:
- Coverflow: below album name
- Split views (Lyrics/TrackInfo/Suggestions/Queue): below album name
- Added album name display in split view

Layout improvements:
- Panel section max-height 80vh
- Lyrics scrollbar only visible on hover
- Content vertically centered with artwork
2026-02-01 07:44:18 -06:00
vicrodh 730ce323c4 Exit fullscreen when leaving immersive mode, add maximize button
- Exit fullscreen automatically when closing immersive view
- Add maximize (window) button separate from fullscreen
- Button order: Fullscreen | Maximize | Exit Immersive | Close App
2026-02-01 07:30:03 -06:00
vicrodh 9502ca9013 Add fullscreen permissions and lighten immersive UI
- Add core:window:allow-set-fullscreen permission
- Add core:window:allow-is-fullscreen permission
- Lighten all buttons and tabs by ~20%
- Reduce background darkness from 0.6 to 0.5
- Increase border visibility
2026-02-01 07:28:03 -06:00
vicrodh e1cd13bd19 Add expandable window controls and fullscreen support
- Add expandable window controls in header (hover to expand)
  - Fullscreen toggle (F11)
  - Exit immersive (Esc)
  - Close app
- Move Repeat button to left group: Fav | Shuffle | Repeat
- Remove QualityBadge from player controls
- Add F11 keyboard shortcut for fullscreen toggle
- Use Tauri window API for fullscreen functionality
2026-02-01 07:22:03 -06:00
vicrodh df0cd9e1dd Simplify immersive player to use single compact controls
- Remove PlayerControlsMedium variant (unused)
- Keep only PlayerControlsCompact as the single player style
- Add QualityBadge above player controls
- Center play/pause button with balanced left/right groups
- Remove expand/compact toggle (no longer needed)
- Pass quality, bitDepth, samplingRate props from parent
2026-02-01 07:09:55 -06:00
vicrodh 62f2e3dffc feat(ui): show ALSA device descriptions in audio badge tooltip
Load ALSA device descriptions from backend and display fancy names
in the tooltip, with fallback to heuristic names when unavailable
2026-02-01 06:03:44 -06:00
vicrodh 7a76973920 fix(audio): expand ALSA bit-perfect detection for front:CARD devices
- Add front:CARD=X,DEV=Y device enumeration from aplay -L output
- Recognize front: devices as bit-perfect in AlsaDirectStream
- Group front:CARD and "bit-perfect" named devices correctly in UI
- Add tooltip to device dropdown showing full device name
- Add current selection indicator in device dropdown
- Extend dropdown idle timeout to 10 seconds for long device names

Addresses issue #30 for USB DACs that expose front: but not hw: devices
2026-02-01 05:55:37 -06:00
vicrodh 9680bbb9cd fix(volume): sync persisted volume to backend on app startup 2026-02-01 05:06:31 -06:00
vicrodh 046e333f18 fix(theme): make DAC/EXC tooltip responsive to theme changes 2026-02-01 05:01:37 -06:00
vicrodh 19fa233f7e fix(volume): load persisted volume on startup and allow adjustment before playback
- Initialize volume from localStorage instead of hardcoded 75
- Pass volume and onVolumeChange to NowPlayingBar even when no track is playing
- Users can now adjust volume before playing anything (important to prevent
  loud surprises when volume was left at max)
2026-02-01 04:47:08 -06:00
vicrodh 4548845fbf fix(notification): fail silently when notification system unavailable
Systems without a notification daemon (e.g., minimal Linux setups) would
crash when the app tried to show notifications. Now we log a warning and
continue instead of propagating the error.

Fixes #32
2026-02-01 04:35:59 -06:00
vicrodh 90e4216826 Merge feature/immersive-player into pre-release 2026-02-01 04:31:59 -06:00
vicrodh 52bde38d9f fix(audio): return format_id from play_track and set device name for backend system
1. play_track now returns PlayTrackResult with format_id from Qobuz API
   - Returns actual format (5=MP3, 6=FLAC16, 7=FLAC24, 27=Hi-Res)
   - Returns None for cache hits (format unknown)

2. Frontend updates track.format based on format_id
   - QualityBadge can now correctly show "MP3" when format_id=5
   - Previously badge showed "CD" even for MP3 because format was empty

3. Device name now set after backend system init
   - PipeWire and ALSA backends now set current_device from settings
   - Fixes tooltip showing no device when using backend system
2026-02-01 04:27:23 -06:00
vicrodh e08593af41 feat(nowplaying): make track title clickable to open track info modal
Added onTrackClick handler to NowPlayingBar that opens TrackInfoModal when
the track title is clicked. Uses cursor: help for informative visual cue.
Only works for non-local tracks.
2026-02-01 04:04:02 -06:00
vicrodh ba4c969570 fix(playback): respect streaming_only setting in prefetch
When streaming_only is enabled, prefetch is now skipped entirely.
This ensures tracks are always streamed fresh from the network
without being pre-cached in the background.

When streaming_only is disabled, prefetch works normally.
2026-02-01 03:55:16 -06:00
vicrodh d33ea8b69e feat(playback): add detailed logging for cache vs streaming behavior
Logs now clearly show:
- [CACHE HIT] when playing from memory/disk/offline cache
- [STREAMING] when streaming from network with cache_after flag
- [DOWNLOAD] when using full download mode
- [CACHED] / [NOT CACHED] after download completes
- [Playback Settings] shows stream_first, streaming_only, buffer values
2026-02-01 03:49:37 -06:00
vicrodh 4a40f04b67 feat(search): make entire album card clickable to navigate to album view 2026-02-01 03:20:19 -06:00
vicrodh 859818b4b5 fix(search): add bottom margin to quality badge and fix ticker animation
- Added 1px bottom padding to quality badge
- Reset overflow measurement when most_popular content changes
- Ticker animation now properly triggers on new search results
2026-02-01 03:18:57 -06:00
vicrodh b0b1d3ea5e fix(search): reduce album art to 142px to fit quality badge inside card 2026-02-01 03:17:06 -06:00
vicrodh 4182d7645c feat(search): add border to quality badge and ticker animation for long titles
- Quality badge now has border (alpha-15) and background (alpha-10)
- Added 5px top margin for separation
- Title and subtitle now use ticker animation on hover for long text
- Animation matches AlbumCard behavior (scroll left then back)
2026-02-01 03:13:31 -06:00
vicrodh 01fe3cfdf5 refactor(search): redesign Most Popular album/track cards
- Card now has background like artist-card (bg-secondary, rounded)
- Artwork reduced to 148x148 with 6px padding around
- Quality badge moved to bottom of card (outside artwork)
- Genre only visible on hover overlay with slide-in animation
- Text centered and sized down for consistency
2026-02-01 03:07:49 -06:00
vicrodh 5b7a169e93 feat(search): move quality badge to bottom-right, add genre badge top-left
- Quality badge now at bottom-right with lighter background (0.55 opacity)
- Genre badge at top-left for albums (tracks don't have genre data)
- Both badges use consistent styling with blur backdrop
2026-02-01 03:01:55 -06:00
vicrodh 8c9a27afbb feat(search): add quality badge to Most Popular album/track cards
- Shows compact QualityBadge (e.g. "24bit/96kHz", "CD Quality")
- Positioned at top-right corner of artwork
- Semi-transparent background with blur for readability
2026-02-01 02:59:45 -06:00
vicrodh 5e83c1df47 fix(search): use portal pattern for Most Popular dropdown menu
- Dropdown now renders in document body (escapes stacking context)
- z-index: 99999 matches TrackMenu
- Styling matches TrackMenu (font-size 12px, padding 8px 12px)
- Fixed positioning calculates viewport bounds correctly
2026-02-01 02:54:54 -06:00
vicrodh d9af56192d feat(search): add overlay card UI for Most Popular tracks and albums
- New popular-card with square image, title, and subtitle
- Hover overlay with heart, play, and menu buttons
- Dropdown menu with play controls and navigation options
- Track cards show "Go to album", album cards show "Go to artist"
- Artists still use the existing circular card design
2026-02-01 02:46:29 -06:00
vicrodh f699cf0e63 fix(search): resolve notification loops causing multiple API requests
- Make auth_token() public for catalog/search endpoint authentication
- Fix setSearchQuery to skip notification when value unchanged
- Fix setSearchState to only notify listeners when query actually changed
- Add title case transformation for better most_popular API results
- Add stale result detection to ignore outdated search responses
- Preserve most_popular when API returns inconsistent results
- Clean up debug logging
2026-02-01 02:41:55 -06:00
vicrodh d8bd93374f feat(search): use Qobuz API most_popular field directly
Replace heuristic-based most popular detection with Qobuz's actual
most_popular field from the catalog/search endpoint.

- Add CATALOG_SEARCH endpoint path
- Make app_id() and get_http() public on QobuzClient
- Add MostPopularItem enum with tagged serialization (artists/albums/tracks)
- Update search_all to use catalog/search and parse most_popular field
- Update SearchView template to use allResults.most_popular with new types
- Add MostPopularItem type to searchState store
2026-02-01 01:33:17 -06:00
vicrodh aa16a9276b feat(search): Most Popular can now show artist, album, or track
The Most Popular result in search now intelligently determines
the best match based on query:
- Exact name match: artist > album > track
- Starts with match: artist > album > track
- Fallback: first artist, then album, then track

Added track card display for when a track is the most popular result.
2026-02-01 01:13:06 -06:00
vicrodh d5cbd32fce feat(library): add folder search filter in settings 2026-02-01 01:07:42 -06:00
vicrodh c025e7b8ae fix(library): make entire folder row clickable to toggle checkbox 2026-02-01 01:06:12 -06:00
vicrodh a55c85348d fix(settings): simplify subscription display to inline text with separator 2026-02-01 01:04:20 -06:00
vicrodh 46d91af88f fix(settings): center account card content with symmetric padding 2026-02-01 01:02:37 -06:00
vicrodh d650670ef3 fix(settings): improve streaming-only copy and account card alignment
- Update "Streaming Only" description to be less technical:
  "Disables temporary cache. Not recommended without a fast connection.
  Offline library tracks always play first."
- Fix account card vertical centering with explicit align-self on
  avatar, info container, and logout button
2026-02-01 00:53:33 -06:00
vicrodh c2fcdcec32 feat(settings): add Streaming Only toggle to audio settings
Adds UI toggle for streaming_only mode that skips L1/L2 cache writes.
When enabled, tracks are streamed fresh each time but offline cache
still works for downloaded tracks (local-first principle).
2026-02-01 00:39:12 -06:00
vicrodh b4944aa527 feat(audio): add streaming-only mode backend
Add streaming_only setting that skips L1+L2 cache writes while still
respecting offline cache (local-first). When enabled:
- download_and_stream() skips final cache.insert()
- Standard download path skips cache.insert()
- Offline cache continues to work normally

This reduces storage usage for users who prefer pure streaming.
2026-02-01 00:37:26 -06:00
vicrodh eb9d9dbb15 fix: revert to hi-res-gray.svg (hi-res.svg has poor text contrast) 2026-02-01 00:16:36 -06:00
vicrodh 03cee3f9fc fix: add fixed-width icon container (24px) and use hi-res.svg instead of hi-res-gray.svg 2026-02-01 00:14:08 -06:00
vicrodh 8c7af66d05 fix: increase quality badge min-width to 136px for consistent sizing 2026-02-01 00:07:49 -06:00
vicrodh f8825d98dd fix: set fixed heights for quality badge (36px) and audio badges row (20px) to prevent size changes 2026-02-01 00:02:59 -06:00
vicrodh adc0742fdb fix: maintain consistent badge width by always reserving space for downgrade indicator 2026-01-31 23:58:47 -06:00
vicrodh eaf250383a fix: move loadStatus call to mouseenter handler to prevent re-render loop 2026-01-31 23:51:12 -06:00
vicrodh ae81b1c3c4 Fix quality setting and device name display issues (#34)
- Clear both L1 memory and L2 disk caches when quality setting changes
  This ensures cached tracks at wrong quality are removed
- Fix device name not showing in popup on first hover
  Now refreshes status on each hover instead of only when null
- Add quality downgrade indicator when stream quality is lower than
  track's original quality (shows yellow arrow with tooltip)
- Store original track quality values for comparison with actual stream
2026-01-31 23:46:02 -06:00
vicrodh 8b7e4dab27 feat: show actual stream quality in player UI
Issue #34 - Display actual stream quality, not track metadata

Backend changes:
- Add sample_rate and bit_depth to PlaybackEvent
- Add stream quality tracking to SharedState
- Extract bit_depth from FLAC/M4A headers in streaming path
- Player sets stream quality when decoding audio

Frontend changes:
- Update PlaybackEvent interface with new fields
- Update currentTrack with actual stream quality from backend

This allows the UI to show the actual quality being played (e.g., 44.1kHz
when streaming a 192kHz track at CD Quality) instead of the track's
maximum advertised quality.
2026-01-31 23:32:29 -06:00
vicrodh 38b7ea7aef fix: enforce streaming quality setting by clearing cache on change
Issue #34 - Max quality setting not respected

Changes:
- Remove 'Prefer Highest Available' toggle (was dead code, conflicted with quality dropdown)
- Clear playback cache (L1+L2) when streaming quality changes
- Show toast notification when cache is cleared
- Add description to streaming quality setting
- Update i18n for new messages (en/es)

This ensures the quality setting takes effect immediately, important for:
- Users with metered internet connections
- Users with hardware sample rate limitations (e.g., DACs limited to 96kHz)

The Qobuz API respects format_id and downsamples server-side, so this
change guarantees the correct quality is fetched for new streams.
2026-01-31 23:15:09 -06:00
vicrodh f83eed1076 debug: add quality logging to diagnose issue #34
- Log requested vs returned format_id and sample_rate in get_stream_url_with_fallback
- Log quality_str, parsed quality, and format_id in play_track and prefetch_track commands
- Add console.log in getStreamingQuality for frontend debugging

This will help diagnose why 192kHz is played despite lower quality settings.
2026-01-31 20:54:05 -06:00
vicrodh e1771db099 docs: update CONTRIBUTING.md to require PRs target pre-release
- Add branch workflow section explaining pre-release integration
- Clarify that all PRs must target pre-release, not main
- Update maintainer procedure for new workflow
- Add release procedure section
2026-01-31 20:08:03 -06:00
vicrodh 583bf8f774 Merge PR #35: Make release sort options on artist detail view sticky and global 2026-01-31 20:07:13 -06:00
vicrodh 011ee02ec9 Merge pre-release into feature/immersive-player
Resolved conflicts:
- src-tauri/src/api/client.rs: Keep TrackUnavailable error handling
- i18n files: Combined immersive player keys with trackUnavailable key
2026-01-31 17:19:03 -06:00
vicrodh 38b92bb8d8 chore: update package-lock.json after reinstall 2026-01-31 17:17:23 -06:00
vicrodh 6e55e36652 fix: use proper i18n keys in TrackReplacementModal
Added playlist-specific keys for search button, cancel, loading,
and preview instead of generic common.* keys that didn't exist.
2026-01-31 17:05:46 -06:00
vicrodh 90f24ff122 fix: pass onFindReplacement to TrackMenu from TrackRow
Added missing onFindReplacement to TrackMenuActions interface and
pass it through to TrackMenu component.
2026-01-31 17:02:04 -06:00
vicrodh 2ffd9df133 feat: add "Find available version" option for unavailable tracks
- Add TrackReplacementModal to search for replacement tracks
- Add onFindReplacement action to TrackMenu context menu
- Show replacement option only for owned playlists with unavailable tracks
- Replacement searches by track title + artist
- Shows quality info (bit depth, sample rate) to help user choose
- Supports preview playback before confirming
- Replace old track with new one in playlist

Also fix tooltip for unavailable tracks to show a complete message
instead of "is no longer available" (now shows "Track no longer
available in Qobuz library")
2026-01-31 16:45:23 -06:00
vicrodh faefc68381 fix: maintain column alignment for unavailable tracks
Add placeholders for favorite and download columns when hidden to
prevent column misalignment in unavailable tracks.
2026-01-31 16:36:46 -06:00
vicrodh d46a08465c feat: unavailable track handling with icon in track number column
- Add isUnavailable prop to TrackRow to show AlertCircle instead of track number
- Show unavailable icon only for user's own playlists (not Qobuz official playlists)
- Gray out unavailable tracks in both owned and non-owned playlists
- Remove all interactions for unavailable tracks in non-owned playlists
- Keep only "remove from playlist" option for unavailable tracks in owned playlists
- Create unavailableTracksStore for persisting unavailable track IDs to localStorage
- Load unavailable tracks on app startup in bootstrap.ts
- Auto-mark tracks as unavailable when playback fails with TrackUnavailable error
2026-01-31 16:20:23 -06:00
vicrodh 503e86eeb4 feat: gray out unavailable tracks with info icon in playlist view
- Add streamable field to PlaylistTrack and DisplayTrack interfaces
- Add isTrackRemovedFromQobuz() check for tracks with streamable: false
- Show red AlertCircle icon for unavailable tracks
- Gray out and apply grayscale filter to unavailable track rows
- Limit menu actions to only 'Remove from Playlist' for removed tracks
- Hide favorite and download buttons for removed tracks
- Keep wrapper interactive for context menu access
2026-01-31 16:15:04 -06:00
vicrodh e68c3128b6 feat: auto-skip unavailable tracks with user-friendly error
Backend:
- Add TrackUnavailable error type for tracks removed from Qobuz
- Validate stream URL response - detect missing URL with restrictions
- Add SampleRestrictedByRightHolders to restriction check
- Return specific error when track is unavailable vs quality unavailable

Frontend:
- Detect track unavailable errors in playTrack()
- Show friendly toast: Track title is no longer available
- Auto-skip to next track in queue after 500ms delay
- Add i18n translations (en/es) for trackUnavailable message
2026-01-31 16:10:26 -06:00
vicrodh 1483c05913 Fix: Validate stream URL response before making HEAD request
- Add validation to check if URL is empty before returning StreamUrl
- Add debug logging for JSON response keys
- Return proper error instead of silently using empty URL
- This prevents 'builder error' from HEAD request to empty URL
2026-01-31 15:58:36 -06:00
vicrodh 5ecf9ce24f Fix intermittent HEAD request builder error in streaming playback
- Use lazy_static to create a single reusable HTTP client instead of
  creating a new client for each stream info request
- Add retry logic (3 attempts with 100ms delay) to handle transient
  network/TLS initialization failures
- This fixes 'Failed HEAD request: builder error' toasts that required
  pressing play button twice
2026-01-31 15:54:57 -06:00
vicrodh 3fa34b0594 Fix @const placement in SuggestionsPanel
Move {@const} to be direct child of {#each} block as required by Svelte 5
2026-01-31 15:49:21 -06:00
vicrodh c1877cde75 Fix visual size matching for icons in SuggestionsPanel
- Adjust badge icons: QBZ 17px (was 22px), Qobuz 20px (was 18px)
  QBZ fills its viewBox completely while Qobuz has whitespace,
  so QBZ needs to be smaller to appear visually equal

- Adjust glyph icons: Playlist 32px (was 28px), Radio 26px (was 24px)
  Playlist SVG only fills ~77% of its 20x20 viewBox, needs larger
  pixel size to match Lucide Radio which fills its box completely
2026-01-31 14:55:15 -06:00
vicrodh 14f0cae1c1 feat(suggestions): major UX overhaul with popular tracks fallback
Backend:
- Add get_artist_tracks command for fetching artist's popular tracks

Frontend:
- Fallback to artist's popular tracks when tracks_appears_on is sparse
- Remove card hover movement, only image moves up on hover
- Add hover overlay with (add to queue) (play) (play next) buttons
- Use playlist.svg icon for playlist cards and glyph
- Radio glyph shown by default, replaced by action buttons on hover
- Fix icon sizes: QBZ (22px) vs Qobuz (18px) for visual balance
- Track playlist.svg asset
2026-01-31 14:48:26 -06:00
vicrodh d7c0af6297 fix(suggestions): relax deduplication to keep more variety
- Change from aggressive title normalization to exact title match only
- Keeps different versions (Remaster, Live, etc.) as valid options
- Add debug logging for sparse recommendation data
- This should fix the "only one recommendation" issue for some artists
2026-01-31 14:10:18 -06:00
vicrodh bcbd8ce27f fix(suggestions): fix CPU spike and improve card UX
- Fix $derived to $derived.by for complex logic (was causing CPU spike)
- Remove badge backgrounds from QBZ and Qobuz icons
- Move info icon (i) to top-left corner of radio card
- Add play button to radio card
- Increase badge icon sizes for visibility
2026-01-31 14:08:21 -06:00
vicrodh 1361f257f9 feat(suggestions): improve UX with deduplication, icons, and radio collage
- Dedupe recommended tracks by normalized title (filters remasters/editions)
- Use actual QBZ logo SVG instead of text "Q"
- Add playlist icon and "Playlist" label for clarity
- Add diamond-style collage layout for Song Radio card
- Pass currentArtwork for radio collage images
- Clean up unused error-text CSS in LyricsPanel
2026-01-31 13:59:05 -06:00
vicrodh 9c35c22567 fix: pass artistId to ImmersivePlayer for SuggestionsPanel
The SuggestionsPanel was showing "No track selected" because artistId
was not being passed from the page to ImmersivePlayer component.
2026-01-31 13:49:31 -06:00
vicrodh c0242356a1 fix(lyrics): show user-friendly message when lyrics unavailable
Replace technical error 'LRCLIB search request failed...' with
'No lyrics available' in both LyricsPanel and LyricsFocusPanel.
2026-01-31 12:31:02 -06:00
vicrodh 3228a6c76c fix(suggestions): use correct qobuz-logo-filled.svg path 2026-01-31 12:24:53 -06:00
vicrodh e479705803 feat(immersive): implement Suggestions panel with artist playlists and radio
Layout:
- Top section: Artist curated playlists (from Qobuz) + Song Radio card (QBZ)
- Bottom section: Recommended tracks from artist's discography

Features:
- Artist playlists fetched via get_artist_detail (includes curated playlists)
- Song Radio card with experimental badge and tooltip
- Recommended tracks shuffled from artist's tracks_appears_on
- Single API call per artist (efficient loading)
- Loading state with spinner, empty state handling
- Play buttons with hover effects

Technical:
- Uses existing create_track_radio command for radio generation
- Tracks loadedArtistId to prevent duplicate requests
- Added translations for songRadio, radioExperimental, recommendedTracks
2026-01-31 12:22:39 -06:00
vicrodh 2058fab287 fix(immersive): prevent multiple unnecessary track info requests
- Track loadedTrackId to avoid re-fetching same track
- Only request when trackId actually changes from loaded one
- Clear state only when track ends (trackId becomes null)
- Remove broken common.loading translation (spinner is enough)
2026-01-31 11:19:03 -06:00