- Rust 100%
|
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Signed-off-by: Tomkoid <tomkoid@tomkoid.cz> |
||
|---|---|---|
| .github | ||
| assets | ||
| examples | ||
| src | ||
| .gitignore | ||
| .woodpecker.yml | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| LICENSE.txt | ||
| README.md | ||
Tidlers
A Rust library for interacting with the TIDAL music streaming API.
Features
- OAuth 2.0 authentication
- Access token management and refresh
- Support for all TIDAL audio quality levels (Low, High, Lossless, HiRes)
- DASH manifest parsing for HiRes audio streaming
- API coverage:
- Track information and playback
- Album and playlist management
- Artist information
- User profile and subscription details
- Mixes and recommendations
- Session persistence for seamless re-authentication
- Type-safe API with serde-based deserialization
Projects using Tidlers
Tidlers is still very WIP, but here is my project that uses it:
- yadal - Command-line downloader with parallel downloads and all quality support
Installation
Add this to your Cargo.toml:
[dependencies]
tidlers = "0.1.0"
Or use the git version for the latest features:
[dependencies]
tidlers = { git = "https://codeberg.org/tomkoid/tidlers.git" }
Quick Start
use tidlers::{
TidalClient,
auth::init::TidalAuth,
client::models::playback::AudioQuality,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create client with OAuth authentication
let auth = TidalAuth::with_oauth();
let mut client = TidalClient::new(&auth);
// Get OAuth link for user to authorize
let oauth = client.get_oauth_link().await?;
println!("Visit: https://{}", oauth.verification_uri_complete);
// Wait for authorization
client.wait_for_oauth(
&oauth.device_code,
oauth.expires_in,
oauth.interval,
None,
).await?;
// Get user information
client.refresh_user_info().await?;
println!("Logged in as: {}", client.user_info.unwrap().username);
// Get track information
let track = client.get_track("66035607".to_string()).await?;
println!("Track: {} by {}", track.title, track.artist.name);
// Get playback info for HiRes audio
client.set_audio_quality(AudioQuality::HiRes);
let playback = client.get_track_postpaywall_playback_info("66035607".to_string()).await?;
// Access stream URLs
if let Some(urls) = playback.get_stream_urls() {
println!("Stream URLs: {:?}", urls);
}
Ok(())
}
Audio Quality Support
Tidlers supports all TIDAL audio quality tiers:
- Low: 96 kbps AAC
- High: 320 kbps AAC
- Lossless: 44.1 KHz FLAC (CD quality)
- HiRes: 192 KHz FLAC (High-Res)
HiRes audio uses DASH (Dynamic Adaptive Streaming over HTTP) manifests, which are automatically parsed by the library.
Session Persistence
Save and restore sessions to avoid re-authentication:
// Save session
let session_json = client.get_json();
std::fs::write("session.json", session_json)?;
// Load session
let session_data = std::fs::read_to_string("session.json")?;
let mut client = TidalClient::from_serialized(&session_data)?;
// Refresh token if needed
client.refresh_access_token().await?;
API Examples
Get Track Information
let track = client.get_track("track_id".to_string()).await?;
println!("Title: {}", track.title);
println!("Artist: {}", track.artist.name);
println!("Duration: {}s", track.duration);
Get Album Details
let album = client.get_album("album_id".to_string()).await?;
// Takes in the album id with optional limit and offset for pagination
let items = client.get_album_items("album_id".to_string(), Some(50), Some(0)).await?;
Get Playlist
let playlist = client.get_playlist("playlist_uuid".to_string()).await?;
// Takes in the playlist uuid with optional limit and offset for pagination
let items = client.get_playlist_items("playlist_uuid".to_string(), Some(50), Some(0)).await?;
Get Track Mixes (Recommendations)
let mix = client.get_track_mix("track_id".to_string()).await?;
Check Subscription
let subscription = client.subscription().await?;
println!("Type: {:?}", subscription.subscription.subscription_type);
DASH Manifest Support
For HiRes audio, TIDAL uses DASH streaming. Tidlers parses these manifests automatically:
let playback_info = client.get_track_postpaywall_playback_info(track_id).await?;
match &playback_info.manifest_parsed {
Some(ManifestType::Dash(dash)) => {
println!("Codec: {}", dash.codecs);
println!("Bitrate: {} bps", dash.bitrate.unwrap_or(0));
// Get initialization segment
if let Some(init_url) = dash.get_init_url() {
// Download init segment
}
// Get individual segments
for i in 1..=10 {
if let Some(segment_url) = dash.get_segment_url(i) {
// Download segment i
}
}
}
Some(ManifestType::Json(json)) => {
// Standard JSON manifest for non-HiRes
println!("Direct URL: {}", json.urls[0]);
}
None => {}
}
Examples
The repository includes several examples demonstrating different use cases:
testing_client
Basic example showing authentication, API calls, and data retrieval:
cargo run -p testing-client
This example is also where I test new features during development.
hires_streamer
Complete audio streaming example with playback support:
cargo run -p hires-streamer
Error Handling
The library uses the TidalError enum for error handling:
use tidlers::error::TidalError;
match client.get_track(track_id).await {
Ok(track) => println!("Got track: {}", track.title),
Err(TidalError::NotAuthenticated) => println!("Please login first"),
Err(TidalError::Request(e)) => println!("Network error: {}", e),
Err(e) => println!("Other error: {}", e),
}
Requirements
- Rust 2024 edition
- TIDAL account with active subscription
- Network connection for API access (obviously)
Dependencies
Core dependencies:
reqwest- HTTP clientserde/serde_json- Serializationtokio- Async runtimebase64- Base64 encoding/decodingquick-xml- XML parsing for DASH manifeststhiserror- Error handling
Development
Build the library:
cargo build
Run tests:
cargo test
Run an example:
cargo run -p testing-client
cargo run -p hires-streamer
Notes
- OAuth device code flow requires user interaction via browser
- DASH segments for HiRes audio are MP4 fragments that need to be combined
- Rate limiting is not implemented; use responsibly
- Some parts of code and documentation are written using AI
License
This project is for educational and personal use. Ensure compliance with TIDAL's Terms of Service.
Disclaimer
This is an unofficial library and is not affiliated with or endorsed by TIDAL. Use at your own risk.