Files
qbz/src-tauri
vicrodh ca17ad4da0 feat(ephemeral): CUE support, format whitelist, artwork cache, gapless prefetch
Backend additions for the ephemeral folder feature, all gated behind the
existing track_id >= EPHEMERAL_ID_FLOOR discriminator so library/Qobuz
paths stay untouched.

CUE handling
- Iterate scan.cue_files alongside audio_files. Parse via CueParser,
  resolve + canonicalize the referenced audio file, extract properties +
  format via MetadataExtractor, expand into virtual tracks via
  cue_to_tracks. The referenced audio file is added to a HashSet so the
  audio_files loop skips it (otherwise we'd list both N CUE-derived
  tracks and a single-row entry for the underlying FLAC).
- Whitelist of decoder-friendly extensions (flac/mp3/m4a/alac/wav/aiff/aif).
  Symphonia can't decode APE or raw BIN — those used to ride through
  silently and produce white noise on play; now they're skipped with a
  warn log and counted in skipped_files.
- v2_library_play_track ephemeral branch now honours track.cue_start_secs
  with a post-play_data seek, mirroring the regular local-file branch.

Artwork perf
- Cache extracted artwork by album_group_key. Most CUE-album folders
  share one cover across every virtual track, so calling extract_artwork
  + generate_thumbnail 155 times for a 155-track album was wasted work
  (the bottleneck behind the prior ~2-minute opens). The folder-level
  cache is kept as a secondary fallback for find_folder_artwork lookups.
- Skip standalone APE files entirely from the ephemeral pane — Symphonia
  can't decode them so showing them as a row that explodes on click is
  worse than not showing them at all. Counted in skipped_files.

Gapless
- v2_play_next_gapless gets an ephemeral branch at the top: track ids
  in the high range resolve through EphemeralLibraryState and feed the
  player.play_next path directly. Without this, gapless prefetch always
  reported "not in any cache" because the lookup keyed off DB rows.
- CUE-derived ephemeral tracks (cue_start_secs is Some) return false
  from the gapless branch — they share an audio file, so a play_next
  swap with no seek would start the next virtual track from the FILE's
  beginning instead of the CUE offset.

cc
2026-05-09 05:13:53 -06:00
..