feat(auth): member accounts are valid sessions; typed entitlements

Qobuz answers `/user/login` with 200 for an account without an active
subscription and the web player signs it in as a "Qobuz member" with its
favorites, playlists, purchases and 30-second previews. QBZ threw that
session away: `parse_login_response` returned `IneligibleUser` whenever
`credential.parameters` was empty (verified 2026-09-02 with a lapsed
account). The gate was ours, not Qobuz's.

The parser now reads the entitlement flags (`lossy/lossless/hires/
hires_purchases/offline/mobile_streaming`) into a typed `Entitlements`
on `UserSession`, labels a member "Member", and keeps `subscription.
end_date`/`offer` as information (the embedded Qobuz fixture has a past
end_date with every flag true: the flags are the verdict, the date is
not). `StreamUrl` gains `sample`, the flag Qobuz sets when it serves a
preview instead of the track. `IneligibleUser` stays in the enum for its
existing matchers; nothing emits it from this path any more. Persisted
pre-member sessions still load (`serde(default)`).

cc
This commit is contained in:
vicrodh committed 2026-09-02 07:27:38 -06:00
1 parent 89efde792a
commit 2b7d804f09
8 files changed
+243 -36

No files matched your search

+1 -3
View File
@@ -1269,9 +1269,7 @@ mod tests {
email: "a@b.c".into(),
display_name: "Tester".into(),
subscription_label: "studio".into(),
subscription_valid_until: None,
country_code: None,
language_code: None,
..UserSession::default()
};
set_logged_in(&shared, &session);
let s = shared.lock().unwrap();