fix(library): read "DSD" back out of the database as DSD, not Unknown

`LibraryDatabase::parse_format` is the inverse of `AudioFormat`'s Display,
which is what the scanner stores. It had no arm for "DSD", so every DSD row
came back out of the DB as `Unknown`: the album header printed "UNKNOWN" as
its format, the quality badge said CD (depth 1 IS a known depth below 24) and
the detail line read "1-bit / 2822.4 kHz". The now-playing bar was right all
along because it reads the decoder, not the row — which is exactly the clue
that separated the two data sources.

A fold to `Unknown` is a VALID answer, so nothing failed: not the build, not
`cargo check` (it cannot see the match at all), not a single test.

Three sites had the same hole and all three are fixed:
  - `database.rs`, the one that bit;
  - `local_plex.rs`, same fold for a Plex server serving DSD;
  - `media_servers_qt.rs`, worse than the others — its fallback is `Flac`, so
    a .dsf from Jellyfin or Navidrome was not losing its format, it was being
    mislabelled as lossless PCM.

The guard is a round-trip over EVERY variant rather than a "DSD parses" test:
adding a variant without an arm now fails here instead of shipping the same
silent loss again. Verified against the real rows: format is stored as "DSD",
so this is a READ-side fix and no rescan is needed.

cc
This commit is contained in:
vicrodh committed 2026-08-20 21:13:51 -06:00
1 parent a7b7c1b236
commit 6328994c00
3 files changed
+80 -1

No files matched your search

+6
View File
@@ -303,6 +303,11 @@ pub fn thumb_url(path: &str, size: Option<u32>) -> String {
// Cache reads, mapped into the local-library shapes
// ---------------------------------------------------------------------------
/// Plex reports a codec/container word. The DSD arm is not decoration: the
/// identical omission in `LibraryDatabase::parse_format` is what made every
/// local DSD track read back as `Unknown`, print "UNKNOWN" as its format and
/// wear the CD badge. A Plex server serving DSD hits the same fold, and a fold
/// to `Unknown` is a VALID answer — which is why no test ever sees it.
fn parse_audio_format(s: &str) -> qbz_library::AudioFormat {
use qbz_library::AudioFormat;
match s.to_ascii_lowercase().as_str() {
@@ -312,6 +317,7 @@ fn parse_audio_format(s: &str) -> qbz_library::AudioFormat {
"aiff" | "aif" => AudioFormat::Aiff,
"ape" => AudioFormat::Ape,
"mp3" => AudioFormat::Mp3,
"dsd" | "dsf" | "dff" => AudioFormat::Dsd,
_ => AudioFormat::Unknown,
}
}
+9 -1
View File
@@ -369,7 +369,15 @@ fn parse_audio_format(container: &str, codec: Option<&str>) -> qbz_library::Audi
use qbz_library::AudioFormat as F;
let probe = |s: &str| -> Option<F> {
let s = s.to_ascii_lowercase();
if s.contains("flac") {
// DSD first, and it matters MORE here than in the sibling parsers:
// this one falls back to `Flac`, not `Unknown`, so an unrecognised DSD
// track from Jellyfin/Navidrome does not merely lose its format — it
// is actively mislabelled lossless-PCM, with a "24-bit / …" badge it
// never had. Jellyfin reports `Container: "dsf"`, Subsonic a `suffix`
// of `dsf`/`dff` and a MIME of `audio/x-dsf`.
if s.contains("dsd") || s.contains("dsf") || s.contains("dff") {
Some(F::Dsd)
} else if s.contains("flac") {
Some(F::Flac)
} else if s.contains("mp3") || s.contains("mpeg") {
Some(F::Mp3)