1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//! # Prawn - Rust Client Library for the Tidal API
//!
//! Prawns (shrimp, really) are one of the most common crustacean you will see in a tide pool :)
//!
//! Prawn is a Rust library exposing a thin wrapper client around generated API clients and models for the Tidal V2 API. The wrapper client is intended to make managing authenticating via OAuth 2.0 with Tidal easier by exposing a few simple additional methods and managing refresh tokens. The OAuth methods rely on the [oauth2 crate](https://!github.com/ramosbugs/oauth2-rs).
//!
//! The API clients/models/docs were (mostly, with some modifications) generated by the [OpenAPI Generator](https://!openapi-generator.tech) project.
//!
//! Prawn currently supports the Authorization Code flow and the Client Credentials flow, which are the only ones documented as supported [in Tidal's public docs](https://!developer.tidal.com/documentation/api-sdk/api-sdk-authorization)
//!
//! I developed this library because the other most comprehensive Tidal library for Rust is [tidalrs](https://!github.com/phayes/tidalrs). However, tidalrs only supports device authorization, does not support the authorization code or client credentials flow, and only interacts with the V1 Tidal API. Changing these assumptions felt big enough to warrant its own library in the end.
//!
//! ## Examples
//!
//! ### Generate an authorize URL
//!
//! ```
//! use prawn::client::{TidalClient, TidalClientConfig, OAuthConfig};
//! let client_id = "<your client id>";
//!
//! let redirect_uri = "https://example.com/callback";
//!
//! let config = TidalClientConfig {
//! oauth_config: OAuthConfig {
//! redirect_uri: redirect_uri.to_string(),
//! client_id: client_id.to_string(),
//! client_secret: None
//! },
//! auth_token: None, // we haven't authorized yet, so we don't have this.
//! retry_config: None,
//! };
//
//! let client = TidalClient::new(config)?;
//!
//! let (challenge, verifier) = client.generate_pkce_challenge_and_verifier();
//!
//! let scopes = vec!["user.read"];
//!
//! let (auth_url, state) = client.get_authorize_url_and_state(challenge, scopes.to_vec());
//!
//! println!("visit {} to authorize", auth_url);
//!
//! # Ok::<(), String>(())
//! ```
//!
//! ### Exchange url for token and call API, retry rate limited requests
//!
//! ```no_run
//! # smol::block_on( async {
//!
//! use prawn::client::{TidalClient, TidalClientConfig, OAuthConfig, Token, RetryConfig};
//! # use prawn::apis::Api;
//! // ... /callback implementation ...
//! let code = "<extract from query params>";
//! let verifier = "<stored verifier somewher>";
//!
//! let client_id = "<your client id>";
//!
//! let redirect_uri = "https://example.com/callback";
//!
//! let config = TidalClientConfig {
//! oauth_config: OAuthConfig {
//! redirect_uri: redirect_uri.to_string(),
//! client_id: client_id.to_string(),
//! client_secret: None
//! },
//! auth_token: None, // we haven't authorized yet, so we don't have this.
//! retry_config: Some(RetryConfig{}), // enables retries with exponential backoff when we get 429 response codes from Tidal.
//! };
//!
//! let client = TidalClient::new(config)?;
//!
//! let token: Token = client.exchange_code_for_token(verifier.to_string(), code.to_string()).await?;
//!
//! let client_with_token = client.with_token(token)?;
//!
//! let resp = client_with_token.tracks_api().get_track("<some track id>", None, None, None).await;
//! # Ok::<(), String>(())
//! # });
//! ```
//!
//! ### Client Credentials flow
//!
//! ```no_run
//! # smol::block_on(async {
//! use prawn::client::{TidalClient, TidalClientConfig, OAuthConfig};
//! # use prawn::apis::Api;
//! let client_id = "<your client id>";
//! let client_secret = "<your client secret>";
//!
//! let redirect_uri = "https://example.com/callback";
//!
//! let config = TidalClientConfig {
//! oauth_config: OAuthConfig {
//! redirect_uri: redirect_uri.to_string(),
//! client_id: client_id.to_string(),
//! client_secret: Some(client_secret.to_string()),
//! },
//! auth_token: None, // we haven't authorized yet, so we don't have this.
//! retry_config: None
//! };
//!
//! let client = TidalClient::new(config)?;
//! let scopes = vec!["user.read"];
//! let token = client.exchange_client_credentials_for_token(scopes.to_vec()).await?;
//!
//! let client_with_token = client.with_token(token)?;
//!
//! let resp = client_with_token.tracks_api().get_track("some track id", None, None, None).await;
//! # Ok::<(), String>(())
//! # });
//! ```
extern crate serde;
extern crate serde_json;
extern crate serde_repr;
extern crate url;
/// For comprehensive documentation of API endpoints and payloads, visit https://!tidal-music.github.io/tidal-api-reference