Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Qobuz API Rust Client
An unofficial Rust client library for the Qobuz music streaming API, migrated from the C# implementation by DJDoubleD. Provides comprehensive access to Qobuz's features including authentication, content search and retrieval (albums, artists, tracks, playlists), user favorites management, streaming URL generation, track/album/artist/playlist downloads with automatic metadata embedding, and web player credential extraction.
Overview
This project is a migration of an existing C# Qobuz API library to Rust. The original C# project is written in .NET Framework 4.8.1, which is not compatible with Linux, making this Rust implementation particularly valuable for cross-platform use. The goal is to leverage Rust's strengths in memory safety, performance, and concurrency while maintaining the full functionality of the original C# version.
Features
- Authentication:
- Email/password, user ID/auth token, and automatic environment variable-based authentication
- Web player credential extraction and caching
- Automatic credential refresh on signature expiry
- Content Search & Browse:
- Unified catalog search and dedicated search for albums, artists, tracks, playlists, and articles
- Fetch detailed information for albums, artists, tracks, and playlists
- Artist release list retrieval
- User Favorites:
- Add, delete, and retrieve favorites
- Retrieve favorite IDs
- Downloads:
- Download individual tracks
- Download entire albums, artist discographies, and playlists with concurrent fetching
- Cancellation support via
AtomicBool - Automatic retry with exponential backoff on rate limiting
- Track file URL generation for streaming
- Metadata Embedding:
- Comprehensive metadata (artist, album, track details, cover art, performer roles) embedded into downloaded audio files
- Configurable metadata options
- Error Handling:
- 12 typed error variants via
thiserrorcovering auth, HTTP, I/O, API errors, rate limiting, cancellation, and more - All errors satisfy
Send + Sync + 'staticfor use in async Tokio tasks
- 12 typed error variants via
- Testability:
HttpClienttrait abstraction enables deterministic testing with mock HTTP servers- Integration tests with a sequential mock server
- Benchmark suite with
criterion
Architecture
src/
├── api/ # API client layer
│ ├── auth.rs # Authentication methods
│ ├── content/ # Content operations (search, browse, download)
│ ├── favorites.rs # User favorites management
│ ├── http_client.rs# HTTP client trait + reqwest implementation
│ ├── macros.rs # delegate! / delegate_with_retry! macros
│ ├── requests.rs # Signed request primitives, retry with backoff
│ ├── response.rs # Response parsing, error handling
│ ├── service.rs # Central QobuzApiService
│ └── service_download.rs # Download delegates
├── credentials/ # .env I/O and web player credential extraction
├── errors.rs # QobuzApiError enum (12 variants)
├── metadata/ # Audio metadata extraction and embedding
│ ├── config.rs # Metadata configuration
│ ├── embedder/ # Tag embedding (artist, basic, performer fields)
│ └── extractor.rs # Metadata extraction from API responses
├── models/ # Serde data models for API responses
├── sanitize.rs # Cross-platform filename sanitization
└── signing.rs # MD5-based request signature generation
Key design decisions:
- Synchronous API surface: The service exposes synchronous methods. Async API functions are called via a per-call Tokio runtime (
Runtime::new().block_on(...)). This keeps the public API simple while enabling concurrent downloads internally. HttpClienttrait: All HTTP requests go through adyn HttpClienttrait, enabling mock-based deterministic tests without network I/O.- Delegate macros:
delegate!anddelegate_with_retry!generate the sync-to-async bridge, with the latter automatically refreshing web player credentials on"Invalid Request Signature"errors. - Cancellation: Long-running downloads accept an
Option<&AtomicBool>for cooperative cancellation.
Dependencies
| Crate | Purpose |
|---|---|
reqwest |
Async HTTP client with connection pooling |
serde + serde_json |
JSON serialization/deserialization |
tokio |
Async runtime (fs, sync, time) |
lofty |
Audio metadata reading/writing |
md-5 |
MD5 hashing for request signing |
regex |
Web player JS bundle parsing |
base64 |
Decoding during credential extraction |
thiserror |
Typed error derivation |
tracing + tracing-subscriber |
Structured observability |
rayon |
Data parallelism for concurrent downloads |
anyhow |
Binary-level error context |
Development: criterion (benchmarks), tempfile (test fixtures).
Usage
Instantiation
use QobuzApiService;
// Auto-detect credentials (from .env or web player extraction)
let mut service = new?;
// Or provide credentials explicitly
let mut service = with_credentials?;
Authentication
// From environment variables (QOBUZ_USER_ID + QOBUZ_USER_AUTH_TOKEN,
// or QOBUZ_EMAIL + QOBUZ_PASSWORD, or QOBUZ_USERNAME + QOBUZ_PASSWORD)
service.authenticate_with_env?;
// With explicit credentials
service.login?;
service.login_with_token?;
Search
let albums = service.search_albums?;
let tracks = service.search_tracks?;
let catalog = service.search_catalog?;
Browse
let album = service.get_album?;
let artist = service.get_artist?;
let track = service.get_track?;
let releases = service.get_release_list?;
Download
Track format IDs: 5 (MP3 320), 6 (FLAC Lossless), 7 (FLAC Hi-Res ≤96 kHz), 27 (FLAC Hi-Res >96 kHz).
use Path;
// Download a single track
let path = service.download_track?;
// Download an entire album with concurrent fetching
let paths = service.download_album?;
// Download with cancellation
use ;
let cancel = new;
let cancel_clone = cancel.clone;
spawn;
let result = service.download_album_cancellable;
Favorites
service.add_user_favorites?;
let favorites = service.get_user_favorites?;
service.delete_user_favorites?;
Testing
# Unit tests (no network)
# Integration tests with mock HTTP server
# Live integration tests (requires valid .env credentials)
# Benchmarks
Acknowledgements
This project is inspired by and built upon the excellent work of DJDoubleD. Special thanks to him and his projects:
- DJDoubleD/QobuzApiSharp: The original C# Qobuz API library that served as the foundation and migration source for this Rust client.
- DJDoubleD/QobuzDownloaderX-MOD: For insights into Qobuz API interactions and related tooling.
License
GNU General Public License v3.0 — see LICENSE for details.