Skip to content

Qobuz: allow free accounts to download purchased (download-store) content#1007

Open
jrejaud wants to merge 1 commit into
nathom:devfrom
jrejaud:sc-3674-streamrip-conditional-qobuz-download-store-support
Open

Qobuz: allow free accounts to download purchased (download-store) content#1007
jrejaud wants to merge 1 commit into
nathom:devfrom
jrejaud:sc-3674-streamrip-conditional-qobuz-download-store-support

Conversation

@jrejaud

@jrejaud jrejaud commented Jun 25, 2026

Copy link
Copy Markdown

Problem

A Qobuz account with no streaming subscription returns an empty credential.parameters on login. Today QobuzClient.login() unconditionally raises IneligibleError in that case, so the account cannot download albums it has purchased from the Qobuz download store — even though Qobuz serves those files fine via intent=download.

This is the long-standing #673 (open since Apr 2024) and #918.

Fix

Make the behavior conditional so streaming for subscribers is untouched:

  1. login() — on empty credential.parameters, set self.download_only = True and log a WARNING instead of raising. Genuine auth failures (401/400) still raise as before; only the free-but-owns-content case is reclassified.
  2. _request_file_url() — pick intent = "download" if self.download_only else "stream", applied to both the signed request_sig preimage and the params dict (they must agree or Qobuz returns HTTP 400).
  3. get_downloadable() — purchased content is sold in exactly one format and Qobuz offers no automatic fallback. When download_only and the response is FormatRestrictedByFormatAvailability, retry one quality tier down so a too-high configured quality clamps instead of erroring.

download_only is auto-detected from the login response — no new config flag, existing configs keep working. Subscribers keep intent=stream exactly as before.

Security note

This only enables downloading content the account already owns. There is no entitlement bypass: Qobuz still gates track/getFileUrl on ownership server-side, so a non-owned track returns a restriction regardless of intent.

Tests

Added tests/test_qobuz_download_only.py (fully mocked, no credentials needed):

  • subscriber login (non-empty parameters) → download_only is False, no raise
  • free login (empty parameters) → download_only is True, no raise
  • download_only=Trueintent=download in the params dict and the signed preimage (verified by reconstructing the md5)
  • download_only=Falseintent=stream in both

Verified end-to-end against a real free Qobuz account with purchased albums: a 12-track 24-bit/44.1 kHz album downloads all 12 FLACs at full quality (ffprobe: bits_per_raw_sample=24, sample_rate=44100, full track durations), and the quality-clamp path retries down correctly when a higher tier is requested.

Existing suite passes with no new failures.

Closes #673
Closes #918

A Qobuz account with no streaming subscription returns an empty
credential.parameters on login. Previously login() raised IneligibleError,
so such an account could not download albums it had *purchased* from the
Qobuz download store (nathom#673, nathom#918).

Make the behavior conditional instead of regressing streaming for subscribers:

- login() flags the client download_only=True (WARNING log) on empty
  credential.parameters instead of raising. Genuine 401/400 auth failures
  still raise.
- _request_file_url() selects intent=download when download_only else
  intent=stream, in both the signed request_sig preimage and the params dict.
- get_downloadable() clamps quality for purchased content: on a
  FormatRestrictedByFormatAvailability restriction it retries one tier down
  (Qobuz offers no automatic fallback for owned content).

Adds unit tests covering both account types and both intent paths.

This only enables downloading content the account already owns; Qobuz still
gates getFileUrl on ownership server-side.

Closes nathom#673
Closes nathom#918

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] qobuz: null credential.parameters for seemingly valid token [FEATURE] Downloading from Download Store

1 participant