joscha gay
This commit is contained in:
commit
e30854304f
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "dzlib-rs"
|
||||
version = "0.1.0"
|
||||
authors = ["uh_wot <uhwot@protonmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.11", features = ["json", "rustls-tls"], default-features = false }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
md-5 = "0.9"
|
||||
hex = { version = "0.4", optional = true }
|
||||
aes = { version = "0.7", optional = true }
|
||||
block-modes = { version = "0.8", optional = true }
|
||||
thiserror = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-test = "0.4"
|
||||
|
||||
[features]
|
||||
default = ["stream"]
|
||||
stream = ["hex", "aes", "block-modes"]
|
|
@ -0,0 +1,269 @@
|
|||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
|
||||
use reqwest::Method;
|
||||
|
||||
use serde::{Deserialize, Deserializer, de};
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::objects::*;
|
||||
|
||||
use md5::{Digest, Md5};
|
||||
|
||||
use crate::errors::{ErrorKind, DzErr};
|
||||
|
||||
const API_URL: &str = "https://api.deezer.com";
|
||||
// client id and secret are from deezer's chromecast app
|
||||
const CLIENT_ID: &str = "119915";
|
||||
const CLIENT_SECRET: &str = "2f5b4c9785ddc367975b83d90dc46f5c";
|
||||
|
||||
fn from_str<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
||||
where T: FromStr,
|
||||
T::Err: Display,
|
||||
D: Deserializer<'de>
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
T::from_str(&s).map_err(de::Error::custom)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct TokenResp {
|
||||
access_token: String,
|
||||
#[serde(deserialize_with = "from_str")]
|
||||
expires: u64,
|
||||
}
|
||||
|
||||
// needed because deezer's API returns an integer on "expires" instead of a string when logging in
|
||||
// thanks baguette assholes
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct LoginTokenResp {
|
||||
access_token: String,
|
||||
expires: u64,
|
||||
}
|
||||
|
||||
pub struct AccessToken {
|
||||
pub token: String,
|
||||
expires: u64,
|
||||
instant: Instant
|
||||
}
|
||||
|
||||
impl AccessToken {
|
||||
fn new(token: String, expires: u64) -> AccessToken {
|
||||
AccessToken {
|
||||
token,
|
||||
expires,
|
||||
instant: Instant::now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(untagged)]
|
||||
enum DzRespType<T> {
|
||||
Err { error: DzErr },
|
||||
Ok(T),
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
client: reqwest::Client,
|
||||
pub access_token: Option<AccessToken>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
access_token: None,
|
||||
client: reqwest::Client::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_token(&mut self) -> Result<(), ErrorKind> {
|
||||
let resp = self.client.request(Method::GET, "https://connect.deezer.com/oauth/access_token.php")
|
||||
.query(&[
|
||||
("grant_type", "client_credentials"),
|
||||
("client_id", CLIENT_ID),
|
||||
("client_secret", CLIENT_SECRET),
|
||||
("output", "json"),
|
||||
])
|
||||
.send().await.map_err(|e| ErrorKind::Reqwest(e))?
|
||||
.json::<DzRespType<TokenResp>>().await.map_err(|e| ErrorKind::Reqwest(e))?;
|
||||
|
||||
match resp {
|
||||
DzRespType::Ok(token) => {
|
||||
self.access_token = Some(AccessToken::new(token.access_token, token.expires));
|
||||
Ok(())
|
||||
},
|
||||
DzRespType::Err { error } => Err(ErrorKind::API(error)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn check_token(&mut self) -> Result<(), ErrorKind> {
|
||||
match &self.access_token {
|
||||
Some(token) => {
|
||||
if token.instant.elapsed().as_secs() >= token.expires && token.expires != 0 {
|
||||
self.get_token().await
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
None => self.get_token().await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn login(&mut self, email: &str, password: &str) -> Result<(), ErrorKind> {
|
||||
let password = format!("{:x}", Md5::digest(password.as_bytes()));
|
||||
|
||||
let hash = [
|
||||
CLIENT_ID.as_bytes(),
|
||||
email.as_bytes(),
|
||||
password.as_bytes(),
|
||||
CLIENT_SECRET.as_bytes(),
|
||||
].concat();
|
||||
let hash = format!("{:x}", Md5::digest(&hash));
|
||||
|
||||
let url = format!("{}/auth/token", API_URL);
|
||||
let resp = self.client.request(Method::GET, &url)
|
||||
.query(&[
|
||||
("app_id", CLIENT_ID),
|
||||
("login", email),
|
||||
("password", &password),
|
||||
("hash", &hash),
|
||||
])
|
||||
.send().await.map_err(|e| ErrorKind::Reqwest(e))?
|
||||
.json::<DzRespType<LoginTokenResp>>().await.map_err(|e| ErrorKind::Reqwest(e))?;
|
||||
|
||||
match resp {
|
||||
DzRespType::Ok(token) => {
|
||||
self.access_token = Some(AccessToken::new(token.access_token, token.expires));
|
||||
Ok(())
|
||||
},
|
||||
DzRespType::Err { error } => Err(ErrorKind::API(error)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn login_token(&mut self, token: &str) -> Result<(), ErrorKind> {
|
||||
self.access_token = Some(AccessToken::new(token.to_string(), 0));
|
||||
match self.infos().await {
|
||||
Err(e) => {
|
||||
self.access_token = None;
|
||||
Err(e)
|
||||
},
|
||||
Ok(i) => {
|
||||
match i.user_token {
|
||||
Some(_) => Ok(()),
|
||||
None => {
|
||||
self.access_token = None;
|
||||
Err(ErrorKind::NotUserToken)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn api_call<T, Q>(&mut self, method: reqwest::Method, path: &str, query: &Q) -> Result<T, ErrorKind>
|
||||
where T: de::DeserializeOwned,
|
||||
Q: serde::ser::Serialize + ?Sized,
|
||||
{
|
||||
self.check_token().await.map_err(|e| ErrorKind::Token(Box::new(e)))?;
|
||||
let url = format!("{}/{}", API_URL, path);
|
||||
|
||||
let resp = self.client.request(method, &url)
|
||||
.query(&[("access_token", &self.access_token.as_ref().unwrap().token)])
|
||||
.query(query)
|
||||
.body("\n") // needed otherwise some POST requests fail
|
||||
.send().await.map_err(|e| ErrorKind::Reqwest(e))?
|
||||
.json::<DzRespType<T>>().await.map_err(|e| ErrorKind::Reqwest(e))?;
|
||||
|
||||
match resp {
|
||||
DzRespType::Ok(r) => Ok(r),
|
||||
DzRespType::Err { error } => Err(ErrorKind::API(error)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn track(&mut self, id: i64) -> Result<Track, ErrorKind> {
|
||||
Track::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn album(&mut self, id: u64) -> Result<Album, ErrorKind> {
|
||||
Album::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn artist(&mut self, id: u64) -> Result<Artist, ErrorKind> {
|
||||
Artist::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn playlist(&mut self, id: u64) -> Result<Playlist, ErrorKind> {
|
||||
Playlist::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn podcast(&mut self, id: u64) -> Result<Podcast, ErrorKind> {
|
||||
Podcast::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn episode(&mut self, id: u64) -> Result<Episode, ErrorKind> {
|
||||
Episode::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn chart(&mut self, id: u64) -> Result<Chart, ErrorKind> {
|
||||
Chart::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn radio(&mut self, id: u64) -> Result<Radio, ErrorKind> {
|
||||
Radio::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn radio_list(&mut self) -> Result<DzArray<Radio>, ErrorKind> {
|
||||
Radio::list(self).await
|
||||
}
|
||||
|
||||
pub async fn search_track(&mut self, query: &str) -> Result<DzArray<Track>, ErrorKind> {
|
||||
search::track(self, query).await
|
||||
}
|
||||
|
||||
pub async fn search_album(&mut self, query: &str) -> Result<DzArray<Album>, ErrorKind> {
|
||||
search::album(self, query).await
|
||||
}
|
||||
|
||||
pub async fn search_artist(&mut self, query: &str) -> Result<DzArray<Artist>, ErrorKind> {
|
||||
search::artist(self, query).await
|
||||
}
|
||||
|
||||
pub async fn search_playlist(&mut self, query: &str) -> Result<DzArray<Playlist>, ErrorKind> {
|
||||
search::playlist(self, query).await
|
||||
}
|
||||
|
||||
pub async fn genre(&mut self, id: u64) -> Result<Genre, ErrorKind> {
|
||||
Genre::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn editorial(&mut self, id: u64) -> Result<Editorial, ErrorKind> {
|
||||
Editorial::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn lyrics(&mut self, id: u64) -> Result<Lyrics, ErrorKind> {
|
||||
Lyrics::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn user(&mut self, id: u64) -> Result<User, ErrorKind> {
|
||||
User::get(self, id).await
|
||||
}
|
||||
|
||||
pub async fn user_self(&mut self) -> Result<User, ErrorKind> {
|
||||
User::get_self(self).await
|
||||
}
|
||||
|
||||
pub async fn infos(&mut self) -> Result<Infos, ErrorKind> {
|
||||
Infos::get(self).await
|
||||
}
|
||||
|
||||
pub async fn options(&mut self) -> Result<Options, ErrorKind> {
|
||||
Options::get(self).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Client {
|
||||
fn default() -> Self {
|
||||
Client::new()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
use md5::{Md5, Digest};
|
||||
use aes::Aes128;
|
||||
use block_modes::{BlockMode, Ecb};
|
||||
use block_modes::block_padding::ZeroPadding;
|
||||
|
||||
pub fn stream_url(md5_origin: &str, format: u8, id: i64, media_version: u8) -> String {
|
||||
// md5 origin + format num + id + media version
|
||||
let metadata = [
|
||||
md5_origin.as_bytes(),
|
||||
&[b'\xa4'],
|
||||
format.to_string().as_bytes(),
|
||||
&[b'\xa4'],
|
||||
id.to_string().as_bytes(),
|
||||
&[b'\xa4'],
|
||||
media_version.to_string().as_bytes(),
|
||||
].concat();
|
||||
|
||||
let hash = format!("{:x}", Md5::digest(&metadata));
|
||||
|
||||
// md5 hash + previous metadata
|
||||
let metadata_hash = [
|
||||
hash.as_bytes(),
|
||||
&[b'\xa4'],
|
||||
&metadata,
|
||||
&[b'\xa4'],
|
||||
].concat();
|
||||
|
||||
// padding
|
||||
/*
|
||||
let len = metadata_hash.len();
|
||||
if len % 16 > 0 {
|
||||
metadata_hash.resize(len+(16-len%16), b'\x00');
|
||||
}
|
||||
*/
|
||||
|
||||
const AES_KEY: [u8; 16] = [106, 111, 54, 97, 101, 121, 54, 104, 97, 105, 100, 50, 84, 101, 105, 104];
|
||||
|
||||
type Aes128Ecb = Ecb<Aes128, ZeroPadding>;
|
||||
let cipher = Aes128Ecb::new_from_slices(&AES_KEY, Default::default()).unwrap();
|
||||
let ciphertext = cipher.encrypt_vec(&metadata_hash);
|
||||
|
||||
format!("https://cdns-proxy-{}.dzcdn.net/api/1/{}", md5_origin.chars().next().unwrap(), hex::encode(ciphertext))
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
use serde::Deserialize;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ErrorKind {
|
||||
#[error("error from deezer api")]
|
||||
API(DzErr),
|
||||
#[error("error while calling api")]
|
||||
Reqwest(reqwest::Error),
|
||||
#[error("error while getting token")]
|
||||
Token(Box<Self>),
|
||||
#[error("token specified is not an account token")]
|
||||
NotUserToken,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct DzErr {
|
||||
#[serde(rename = "type")]
|
||||
pub err_type: DzErrType,
|
||||
pub message: String,
|
||||
pub code: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub enum DzErrType {
|
||||
Exception,
|
||||
OAuthException,
|
||||
ParameterException,
|
||||
MissingParameterException,
|
||||
InvalidQueryException,
|
||||
DataException,
|
||||
IndividualAccountChangedNotAllowedException,
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
mod client;
|
||||
pub mod objects;
|
||||
pub mod errors;
|
||||
#[cfg(feature = "stream")]
|
||||
pub mod crypto;
|
||||
pub use self::client::Client;
|
|
@ -0,0 +1,63 @@
|
|||
use serde::Deserialize;
|
||||
use super::{DzArray, User, Track, ImgObject};
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
|
||||
// https://developers.deezer.com/api/album
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Album {
|
||||
pub id: u64,
|
||||
pub title: String,
|
||||
pub upc: Option<String>,
|
||||
pub link: Option<String>,
|
||||
pub share: Option<String>,
|
||||
pub cover: Option<String>,
|
||||
pub cover_small: Option<String>,
|
||||
pub cover_medium: Option<String>,
|
||||
pub cover_big: Option<String>,
|
||||
pub cover_xl: Option<String>,
|
||||
pub md5_image: Option<String>,
|
||||
pub genre_id: Option<i32>,
|
||||
pub label: Option<String>,
|
||||
pub nb_tracks: Option<u64>,
|
||||
pub duration: Option<u64>,
|
||||
pub fans: Option<u64>,
|
||||
pub rating: Option<u32>,
|
||||
pub release_date: Option<String>,
|
||||
pub record_type: Option<String>,
|
||||
pub available: Option<bool>,
|
||||
pub tracklist: Option<String>,
|
||||
pub explicit_lyrics: Option<bool>,
|
||||
pub explicit_content_lyrics: Option<u8>,
|
||||
pub explicit_content_cover: Option<u8>,
|
||||
pub alternative: Option<Box<Album>>,
|
||||
pub tracks: Option<DzArray<Track>>,
|
||||
}
|
||||
|
||||
impl Album {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("album/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn get_full(&self, client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
Self::get(client, self.id).await
|
||||
}
|
||||
|
||||
pub async fn fans(client: &mut crate::Client, id: u64) -> Result<DzArray<User>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("album/{}/fans", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn tracks(client: &mut crate::Client, id: u64) -> Result<DzArray<Track>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("album/{}/tracks", id), &()).await
|
||||
}
|
||||
}
|
||||
|
||||
impl ImgObject for Album {
|
||||
fn md5_img(&self) -> Option<&str> {
|
||||
Some(self.md5_image.as_ref()?)
|
||||
}
|
||||
|
||||
fn img_type(&self) -> &'static str {
|
||||
"cover"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
use serde::Deserialize;
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
|
||||
use super::{DzArray, User, Track, Album, Playlist, ImgObject};
|
||||
|
||||
// https://developers.deezer.com/api/artist
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Artist {
|
||||
pub id: Option<u64>,
|
||||
pub name: String,
|
||||
pub link: Option<String>,
|
||||
pub picture: Option<String>,
|
||||
pub picture_small: Option<String>,
|
||||
pub picture_medium: Option<String>,
|
||||
pub picture_big: Option<String>,
|
||||
pub picture_xl: Option<String>,
|
||||
pub md5_image: Option<String>,
|
||||
pub nb_album: Option<u64>,
|
||||
pub nb_fan: Option<u64>,
|
||||
pub radio: Option<bool>,
|
||||
pub tracklist: String,
|
||||
}
|
||||
|
||||
impl Artist {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("artist/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn get_full(&self, client: &mut crate::Client) -> Option<Result<Self, ErrorKind>> {
|
||||
Some(Self::get(client, self.id?).await)
|
||||
}
|
||||
|
||||
pub async fn top(client: &mut crate::Client, id: u64) -> Result<DzArray<Track>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("artist/{}/top", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn albums(client: &mut crate::Client, id: u64) -> Result<DzArray<Album>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("artist/{}/albums", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn fans(client: &mut crate::Client, id: u64) -> Result<DzArray<User>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("artist/{}/fans", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn related(client: &mut crate::Client, id: u64) -> Result<DzArray<Self>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("artist/{}/related", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn radio(client: &mut crate::Client, id: u64) -> Result<DzArray<Track>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("artist/{}/radio", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn playlists(client: &mut crate::Client, id: u64) -> Result<DzArray<Playlist>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("artist/{}/playlists", id), &()).await
|
||||
}
|
||||
}
|
||||
|
||||
impl ImgObject for Artist {
|
||||
fn md5_img(&self) -> Option<&str> {
|
||||
Some(self.md5_image.as_ref()?)
|
||||
}
|
||||
|
||||
fn img_type(&self) -> &'static str {
|
||||
"artist"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
|
||||
pub async fn check(client: &mut crate::Client, field: &str, value: &str) -> Result<bool, ErrorKind> {
|
||||
Ok(
|
||||
client.api_call(Method::GET, "auth/check", &[("field", field), ("value", value)]).await?
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn register(client: &mut crate::Client, email: &str, password: &str, name: &str, birthday: &str, genre: &str) -> Result<u64, ErrorKind> {
|
||||
Ok(
|
||||
client.api_call(Method::POST, "auth/register", &[("email", email), ("password", password), ("name", name), ("birthday", birthday), ("genre", genre)]).await?
|
||||
)
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
use serde::Deserialize;
|
||||
use super::{DzArray, Track, Album, Artist, Playlist, Podcast};
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Chart {
|
||||
pub tracks: DzArray<ChartTrack>,
|
||||
pub albums: DzArray<ChartAlbum>,
|
||||
pub artists: DzArray<ChartArtist>,
|
||||
pub playlists: DzArray<Playlist>,
|
||||
pub podcasts: DzArray<Podcast>,
|
||||
}
|
||||
|
||||
impl Chart {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("chart/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn tracks(client: &mut crate::Client, id: u64) -> Result<DzArray<ChartTrack>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("chart/{}/tracks", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn albums(client: &mut crate::Client, id: u64) -> Result<DzArray<ChartAlbum>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("chart/{}/albums", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn artists(client: &mut crate::Client, id: u64) -> Result<DzArray<ChartArtist>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("chart/{}/artists", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn playlists(client: &mut crate::Client, id: u64) -> Result<DzArray<Playlist>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("chart/{}/playlists", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn podcasts(client: &mut crate::Client, id: u64) -> Result<DzArray<Podcast>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("chart/{}/podcasts", id), &()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ChartTrack {
|
||||
#[serde(flatten)]
|
||||
pub track: Track,
|
||||
|
||||
pub position: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ChartAlbum {
|
||||
#[serde(flatten)]
|
||||
pub album: Album,
|
||||
|
||||
pub position: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ChartArtist {
|
||||
#[serde(flatten)]
|
||||
pub artist: Artist,
|
||||
|
||||
pub position: u64,
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
use serde::Deserialize;
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
use super::{DzArray, Album, Chart, ImgObject};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Editorial {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub picture: String,
|
||||
pub picture_small: String,
|
||||
pub picture_medium: String,
|
||||
pub picture_big: String,
|
||||
pub picture_xl: String,
|
||||
}
|
||||
|
||||
impl Editorial {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("editorial/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn get_full(&self, client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
Self::get(client, self.id).await
|
||||
}
|
||||
|
||||
pub async fn list(client: &mut crate::Client) -> Result<DzArray<Self>, ErrorKind> {
|
||||
client.api_call(Method::GET, "editorial", &()).await
|
||||
}
|
||||
|
||||
pub async fn selection(client: &mut crate::Client, id: u64) -> Result<DzArray<Album>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("editorial/{}/selection", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn charts(client: &mut crate::Client, id: u64) -> Result<Chart, ErrorKind> {
|
||||
super::Chart::get(client, id).await
|
||||
}
|
||||
|
||||
pub async fn releases(client: &mut crate::Client, id: u64) -> Result<DzArray<Album>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("editorial/{}/releases", id), &()).await
|
||||
}
|
||||
}
|
||||
|
||||
impl ImgObject for Editorial {
|
||||
fn md5_img(&self) -> Option<&str> {
|
||||
Some(self.picture_small.split('/').collect::<Vec<&str>>()[5])
|
||||
}
|
||||
|
||||
fn img_type(&self) -> &'static str {
|
||||
"misc"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
use serde::Deserialize;
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
use super::{Podcast, ImgObject};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Episode {
|
||||
pub id: u64,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
pub available: Option<bool>,
|
||||
pub release_date: String,
|
||||
pub duration: u64,
|
||||
pub link: Option<String>,
|
||||
pub share: Option<String>,
|
||||
pub picture: String,
|
||||
pub picture_small: Option<String>,
|
||||
pub picture_medium: Option<String>,
|
||||
pub picture_big: Option<String>,
|
||||
pub picture_xl: Option<String>,
|
||||
pub md5_origin: String,
|
||||
pub md5_32: String,
|
||||
pub md5_64: String,
|
||||
#[serde(deserialize_with = "super::from_str")]
|
||||
pub filesize_32: u64,
|
||||
#[serde(deserialize_with = "super::from_str")]
|
||||
pub filesize_64: u64,
|
||||
pub direct_stream_url: Option<String>,
|
||||
pub podcast: Option<Podcast>,
|
||||
}
|
||||
|
||||
impl Episode {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("episode/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn get_full(&self, client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
Self::get(client, self.id).await
|
||||
}
|
||||
|
||||
pub async fn set_bookmark(client: &mut crate::Client, id: u64, offset: u8) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::POST, &format!("episode/{}/bookmark", id), &[("offset", &offset.to_string())]).await
|
||||
}
|
||||
|
||||
pub async fn delete_bookmark(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::DELETE, &format!("episode/{}/bookmark", id), &()).await
|
||||
}
|
||||
}
|
||||
|
||||
impl ImgObject for Episode {
|
||||
fn md5_img(&self) -> Option<&str> {
|
||||
Some(self.picture_small.as_ref()?.split('/').collect::<Vec<&str>>()[5])
|
||||
}
|
||||
|
||||
fn img_type(&self) -> &'static str {
|
||||
"talk"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
use serde::Deserialize;
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
use super::{DzArray, Artist, Radio, ImgObject};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Genre {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub picture: String,
|
||||
pub picture_small: String,
|
||||
pub picture_medium: String,
|
||||
pub picture_big: String,
|
||||
pub picture_xl: String,
|
||||
}
|
||||
|
||||
impl Genre {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("genre/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn get_full(&self, client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
Self::get(client, self.id).await
|
||||
}
|
||||
|
||||
pub async fn artists(client: &mut crate::Client, id: u64) -> Result<DzArray<Artist>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("genre/{}/artists", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn radios(client: &mut crate::Client, id: u64) -> Result<DzArray<Radio>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("genre/{}/radios", id), &()).await
|
||||
}
|
||||
}
|
||||
|
||||
impl ImgObject for Genre {
|
||||
fn md5_img(&self) -> Option<&str> {
|
||||
Some(self.picture_small.split('/').collect::<Vec<&str>>()[5])
|
||||
}
|
||||
|
||||
fn img_type(&self) -> &'static str {
|
||||
"misc"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
use serde::Deserialize;
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
|
||||
// https://developers.deezer.com/api/infos/
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Infos {
|
||||
pub country_iso: String,
|
||||
pub country: String,
|
||||
pub open: bool,
|
||||
pub pop: String,
|
||||
pub upload_token: String,
|
||||
pub upload_token_lifetime: u64,
|
||||
pub user_token: Option<String>,
|
||||
pub hosts: Hosts,
|
||||
pub has_podcasts: bool,
|
||||
pub offers: Vec<Offer>,
|
||||
pub freemium_available: bool,
|
||||
pub lyrics_available: bool,
|
||||
}
|
||||
|
||||
impl Infos {
|
||||
pub async fn get(client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, "infos", &()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Hosts {
|
||||
pub stream: String,
|
||||
pub images: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Offer {
|
||||
pub id: u32,
|
||||
pub name: String,
|
||||
pub amount: String,
|
||||
pub currency: String,
|
||||
pub displayed_amount: String,
|
||||
pub tc: String,
|
||||
pub tc_html: String,
|
||||
pub tc_txt: String,
|
||||
pub try_and_buy: u32,
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
use serde::Deserialize;
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Lyrics {
|
||||
pub id: u64,
|
||||
pub text: String,
|
||||
pub sync_json: Option<Vec<LyricsSync>>,
|
||||
pub copyrights: String,
|
||||
pub writers: String,
|
||||
}
|
||||
|
||||
impl Lyrics {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("lyrics/{}", id), &()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct LyricsSync {
|
||||
pub lrc_timestamp: Option<String>,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "super::from_str_option")]
|
||||
pub milliseconds: Option<u64>,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "super::from_str_option")]
|
||||
pub duration: Option<u64>,
|
||||
pub line: String
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
mod track;
|
||||
mod album;
|
||||
mod artist;
|
||||
mod playlist;
|
||||
mod podcast;
|
||||
mod episode;
|
||||
mod chart;
|
||||
mod radio;
|
||||
pub mod search;
|
||||
mod genre;
|
||||
mod editorial;
|
||||
mod lyrics;
|
||||
mod user;
|
||||
mod infos;
|
||||
mod options;
|
||||
pub mod auth;
|
||||
|
||||
pub use self::track::*;
|
||||
pub use self::album::*;
|
||||
pub use self::artist::*;
|
||||
pub use self::playlist::*;
|
||||
pub use self::podcast::*;
|
||||
pub use self::episode::*;
|
||||
pub use self::chart::*;
|
||||
pub use self::radio::*;
|
||||
pub use self::genre::*;
|
||||
pub use self::editorial::*;
|
||||
pub use self::lyrics::*;
|
||||
pub use self::user::*;
|
||||
pub use self::infos::*;
|
||||
pub use self::options::*;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::de::{self, Deserializer};
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct DzArray<T> {
|
||||
pub data: Vec<T>,
|
||||
pub checksum: Option<String>,
|
||||
pub count: Option<u64>,
|
||||
pub total: Option<u64>,
|
||||
pub next: Option<String>,
|
||||
}
|
||||
|
||||
pub enum ImgFormat {
|
||||
JPG,
|
||||
PNG,
|
||||
}
|
||||
|
||||
pub trait ImgObject {
|
||||
fn md5_img(&self) -> Option<&str>;
|
||||
fn img_type(&self) -> &'static str;
|
||||
fn img_url(&self, size: u16, format: ImgFormat, jpg_quality: u8) -> Option<String> {
|
||||
let format = match format {
|
||||
ImgFormat::JPG => "jpg",
|
||||
ImgFormat::PNG => "png",
|
||||
};
|
||||
let jpg_quality = {
|
||||
let quality: u8;
|
||||
if format == "png" {
|
||||
quality = 100;
|
||||
} else {
|
||||
quality = jpg_quality;
|
||||
}
|
||||
quality
|
||||
};
|
||||
Some(format!("https://cdns-images.dzcdn.net/images/{}/{}/{}x{}-000000-{}-0-0.{}", self.img_type(), self.md5_img()?, size, size, jpg_quality, format))
|
||||
}
|
||||
}
|
||||
|
||||
fn from_str<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
||||
where T: FromStr,
|
||||
T::Err: Display,
|
||||
D: Deserializer<'de>
|
||||
{
|
||||
let mut s = String::deserialize(deserializer)?;
|
||||
if s.is_empty() {
|
||||
s = String::from("0");
|
||||
}
|
||||
T::from_str(&s).map_err(de::Error::custom)
|
||||
}
|
||||
|
||||
fn from_str_option<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
|
||||
where T: FromStr,
|
||||
T::Err: Display,
|
||||
D: Deserializer<'de>
|
||||
{
|
||||
let s: Option<String> = Option::deserialize(deserializer)?;
|
||||
if let Some(mut s) = s {
|
||||
if s.is_empty() {
|
||||
s = String::from("0");
|
||||
}
|
||||
return Ok(Some(
|
||||
T::from_str(&s).map_err(de::Error::custom)?,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
use serde::Deserialize;
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
|
||||
// https://developers.deezer.com/api/options/
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Options {
|
||||
pub streaming: bool,
|
||||
pub streaming_duration: u64,
|
||||
pub offline: bool,
|
||||
pub hq: bool,
|
||||
pub ads_display: bool,
|
||||
pub ads_audio: bool,
|
||||
pub too_many_devices: bool,
|
||||
pub can_subscribe: bool,
|
||||
pub radio_skips: u32,
|
||||
pub lossless: bool,
|
||||
pub preview: bool,
|
||||
pub radio: bool,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
pub async fn get(client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, "options", &()).await
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
use serde::Deserialize;
|
||||
use super::{DzArray, User, Track, ImgObject};
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
|
||||
// https://developers.deezer.com/api/playlist
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Playlist {
|
||||
pub id: u64,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
pub duration: Option<u64>,
|
||||
pub public: bool,
|
||||
pub is_loved_track: Option<bool>,
|
||||
pub collaborative: Option<bool>,
|
||||
pub nb_tracks: Option<u64>,
|
||||
pub fans: Option<u64>,
|
||||
pub link: Option<String>,
|
||||
pub share: Option<String>,
|
||||
pub picture: String,
|
||||
pub picture_small: String,
|
||||
pub picture_medium: String,
|
||||
pub picture_big: String,
|
||||
pub picture_xl: String,
|
||||
pub checksum: String,
|
||||
pub tracklist: String,
|
||||
pub creation_date: String,
|
||||
pub md5_image: String,
|
||||
pub picture_type: String,
|
||||
pub curator: Option<bool>,
|
||||
pub creator: Option<User>,
|
||||
pub tracks: Option<DzArray<PlaylistTrack>>,
|
||||
}
|
||||
|
||||
impl Playlist {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("playlist/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn get_full(&self, client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
Self::get(client, self.id).await
|
||||
}
|
||||
|
||||
pub async fn seen(client: &mut crate::Client, id: u64) -> Result<bool, ErrorKind> {
|
||||
client.api_call(Method::POST, &format!("playlist/{}/seen", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn fans(client: &mut crate::Client, id: u64) -> Result<DzArray<User>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("playlist/{}/fans", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn tracks(client: &mut crate::Client, id: u64) -> Result<DzArray<PlaylistTrack>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("playlist/{}/tracks", id), &()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct PlaylistTrack {
|
||||
#[serde(flatten)]
|
||||
pub track: Track,
|
||||
|
||||
pub time_add: u64,
|
||||
}
|
||||
|
||||
impl ImgObject for Playlist {
|
||||
fn md5_img(&self) -> Option<&str> {
|
||||
Some(&self.md5_image)
|
||||
}
|
||||
|
||||
fn img_type(&self) -> &'static str {
|
||||
"playlist"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
use serde::Deserialize;
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
use super::{DzArray, Episode, ImgObject};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Podcast {
|
||||
pub id: u64,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
pub available: Option<bool>,
|
||||
pub rating: Option<u32>,
|
||||
pub fans: Option<u64>,
|
||||
pub link: String,
|
||||
pub share: Option<String>,
|
||||
pub picture: String,
|
||||
pub picture_small: String,
|
||||
pub picture_medium: String,
|
||||
pub picture_big: String,
|
||||
pub picture_xl: String,
|
||||
}
|
||||
|
||||
impl Podcast {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("podcast/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn get_full(&self, client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
Self::get(client, self.id).await
|
||||
}
|
||||
|
||||
pub async fn episodes(client: &mut crate::Client, id: u64) -> Result<DzArray<Episode>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("podcast/{}/episodes", id), &()).await
|
||||
}
|
||||
}
|
||||
|
||||
impl ImgObject for Podcast {
|
||||
fn md5_img(&self) -> Option<&str> {
|
||||
Some(self.picture_small.split('/').collect::<Vec<&str>>()[5])
|
||||
}
|
||||
|
||||
fn img_type(&self) -> &'static str {
|
||||
"talk"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
use super::{DzArray, ImgObject};
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Radio {
|
||||
pub id: u64,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
pub share: Option<String>,
|
||||
pub picture: String,
|
||||
pub picture_small: String,
|
||||
pub picture_medium: String,
|
||||
pub picture_big: String,
|
||||
pub picture_xl: String,
|
||||
pub tracklist: String,
|
||||
pub md5_image: String,
|
||||
}
|
||||
|
||||
impl Radio {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("radio/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn get_full(&self, client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
Self::get(client, self.id).await
|
||||
}
|
||||
|
||||
pub async fn list(client: &mut crate::Client) -> Result<DzArray<Self>, ErrorKind> {
|
||||
client.api_call(Method::GET, "radio", &()).await
|
||||
}
|
||||
|
||||
pub async fn genres(client: &mut crate::Client) -> Result<DzArray<RadioGenre>, ErrorKind> {
|
||||
client.api_call(Method::GET, "radio/genres", &()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct RadioGenre {
|
||||
pub id: u64,
|
||||
pub title: String,
|
||||
pub radios: Vec<Radio>,
|
||||
}
|
||||
|
||||
impl ImgObject for Radio {
|
||||
fn md5_img(&self) -> Option<&str> {
|
||||
Some(&self.md5_image)
|
||||
}
|
||||
|
||||
fn img_type(&self) -> &'static str {
|
||||
"misc"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
use serde::Deserialize;
|
||||
use super::{DzArray, Track, Album, Artist, Playlist, Podcast, Radio, User};
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
|
||||
pub async fn track(client: &mut crate::client::Client, query: &str) -> Result<DzArray<Track>, ErrorKind> {
|
||||
Ok(
|
||||
client.api_call(Method::GET, "search/track", &[("q", query)]).await?
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn album(client: &mut crate::client::Client, query: &str) -> Result<DzArray<Album>, ErrorKind> {
|
||||
Ok(
|
||||
client.api_call(Method::GET, "search/album", &[("q", query)]).await?
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn artist(client: &mut crate::client::Client, query: &str) -> Result<DzArray<Artist>, ErrorKind> {
|
||||
Ok(
|
||||
client.api_call(Method::GET, "search/artist", &[("q", query)]).await?
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn playlist(client: &mut crate::client::Client, query: &str) -> Result<DzArray<Playlist>, ErrorKind> {
|
||||
Ok(
|
||||
client.api_call(Method::GET, "search/playlist", &[("q", query)]).await?
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn podcast(client: &mut crate::client::Client, query: &str) -> Result<DzArray<Podcast>, ErrorKind> {
|
||||
Ok(
|
||||
client.api_call(Method::GET, "search/podcast", &[("q", query)]).await?
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn radio(client: &mut crate::client::Client, query: &str) -> Result<DzArray<Radio>, ErrorKind> {
|
||||
Ok(
|
||||
client.api_call(Method::GET, "search/radio", &[("q", query)]).await?
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn user(client: &mut crate::client::Client, query: &str) -> Result<DzArray<User>, ErrorKind> {
|
||||
Ok(
|
||||
client.api_call(Method::GET, "search/user", &[("q", query)]).await?
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn history(client: &mut crate::client::Client) -> Result<DzArray<SearchQuery>, ErrorKind> {
|
||||
Ok(
|
||||
client.api_call(Method::GET, "search/history", &()).await?
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct SearchQuery {
|
||||
pub query: String,
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
use serde::Deserialize;
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
use super::{DzArray, Artist, Album, Genre};
|
||||
|
||||
// https://developers.deezer.com/api/track
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Track {
|
||||
pub id: i64,
|
||||
pub readable: Option<bool>,
|
||||
pub title: String,
|
||||
pub title_short: Option<String>,
|
||||
pub title_version: Option<String>,
|
||||
pub isrc: Option<String>,
|
||||
pub link: Option<String>,
|
||||
pub share: Option<String>,
|
||||
pub duration: u64,
|
||||
pub track_position: Option<u64>,
|
||||
pub disk_number: Option<u64>,
|
||||
pub rank: u32,
|
||||
pub release_date: Option<String>,
|
||||
pub lyrics_id: u64,
|
||||
pub explicit_lyrics: bool,
|
||||
pub explicit_content_lyrics: u8,
|
||||
pub explicit_content_cover: u8,
|
||||
pub preview: Option<String>,
|
||||
pub alternative: Option<Box<Track>>,
|
||||
pub bpm: Option<f32>,
|
||||
pub gain: Option<f32>,
|
||||
pub available_countries: Option<Vec<String>>,
|
||||
pub contributors: Option<Vec<Contributor>>,
|
||||
pub md5_image: String,
|
||||
pub user_id: Option<u64>,
|
||||
pub artist: Option<Artist>,
|
||||
pub album: Option<Album>,
|
||||
|
||||
// stream url gen stuff
|
||||
pub md5_origin: String,
|
||||
pub media_version: u8,
|
||||
|
||||
// stream filesizes
|
||||
#[serde(deserialize_with = "super::from_str")]
|
||||
pub filesize_128: u64,
|
||||
#[serde(deserialize_with = "super::from_str")]
|
||||
pub filesize_320: u64,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "super::from_str_option")]
|
||||
pub filesize_flac: Option<u64>,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "super::from_str_option")]
|
||||
pub filesize_mhm1_ra3: Option<u64>,
|
||||
#[serde(deserialize_with = "super::from_str")]
|
||||
pub filesize_misc: u64,
|
||||
}
|
||||
|
||||
pub enum TrkFormat {
|
||||
AAC96,
|
||||
MP364,
|
||||
MP3128,
|
||||
MP3320,
|
||||
FLAC,
|
||||
MP4RA1,
|
||||
MP4RA2,
|
||||
MP4RA3,
|
||||
SBC256,
|
||||
Misc,
|
||||
}
|
||||
|
||||
pub fn format_to_num(format: TrkFormat) -> u8 {
|
||||
match format {
|
||||
TrkFormat::AAC96 => 8,
|
||||
TrkFormat::MP364 => 10,
|
||||
TrkFormat::MP3128 => 1,
|
||||
TrkFormat::MP3320 => 3,
|
||||
TrkFormat::FLAC => 9,
|
||||
TrkFormat::MP4RA1 => 13,
|
||||
TrkFormat::MP4RA2 => 14,
|
||||
TrkFormat::MP4RA3 => 15,
|
||||
TrkFormat::SBC256 => 12,
|
||||
TrkFormat::Misc => 0,
|
||||
}
|
||||
}
|
||||
|
||||
impl Track {
|
||||
pub async fn get(client: &mut crate::Client, id: i64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("track/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn get_full(&self, client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
Self::get(client, self.id).await
|
||||
}
|
||||
|
||||
pub fn format_to_filesize(&self, format: &TrkFormat) -> Option<u64> {
|
||||
match format {
|
||||
TrkFormat::AAC96 => None,
|
||||
TrkFormat::MP364 => None,
|
||||
TrkFormat::MP3128 => Some(self.filesize_128),
|
||||
TrkFormat::MP3320 => Some(self.filesize_320),
|
||||
TrkFormat::FLAC => self.filesize_flac,
|
||||
TrkFormat::MP4RA1 => None,
|
||||
TrkFormat::MP4RA2 => None,
|
||||
TrkFormat::MP4RA3 => None,
|
||||
TrkFormat::SBC256 => None,
|
||||
TrkFormat::Misc => Some(self.filesize_misc),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stream")]
|
||||
pub fn stream_url(&self, format: TrkFormat) -> Option<String> {
|
||||
if let Some(size) = self.format_to_filesize(&format) {
|
||||
if size == 0 {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let format = format_to_num(format);
|
||||
|
||||
Some(crate::crypto::stream_url(&self.md5_origin, format, self.id, self.media_version))
|
||||
}
|
||||
|
||||
pub async fn genres(client: &mut crate::Client, id: i64) -> Result<DzArray<Genre>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("track/{}/genres", id), &()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Contributor {
|
||||
#[serde(flatten)]
|
||||
pub artist: Artist,
|
||||
|
||||
pub role: String,
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
use serde::Deserialize;
|
||||
use crate::errors::ErrorKind;
|
||||
use reqwest::Method;
|
||||
use super::{DzArray, Album, Artist, Track, Playlist, Podcast, Radio, ImgObject};
|
||||
|
||||
// https://developers.deezer.com/api/user
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct User {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub lastname: Option<String>,
|
||||
pub firstname: Option<String>,
|
||||
pub email: Option<String>,
|
||||
pub status: Option<u8>,
|
||||
pub birthday: Option<String>,
|
||||
pub inscription_date: Option<String>,
|
||||
pub gender: Option<String>,
|
||||
pub link: Option<String>,
|
||||
pub picture: Option<String>,
|
||||
pub picture_small: Option<String>,
|
||||
pub picture_medium: Option<String>,
|
||||
pub picture_big: Option<String>,
|
||||
pub picture_xl: Option<String>,
|
||||
pub country: Option<String>,
|
||||
pub lang: Option<String>,
|
||||
pub explicit_content_level: Option<String>,
|
||||
pub explicit_content_levels_available: Option<Vec<String>>,
|
||||
pub tracklist: String,
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub async fn get(client: &mut crate::Client, id: u64) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn get_full(&self, client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
Self::get(client, self.id).await
|
||||
}
|
||||
|
||||
pub async fn get_self(client: &mut crate::Client) -> Result<Self, ErrorKind> {
|
||||
client.api_call(Method::GET, "user/me", &()).await
|
||||
}
|
||||
|
||||
pub async fn albums(client: &mut crate::Client, id: u64) -> Result<DzArray<UserAlbum>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/albums", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn artists(client: &mut crate::Client, id: u64) -> Result<DzArray<UserArtist>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/artists", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn tracks(client: &mut crate::Client, id: u64) -> Result<DzArray<UserTrack>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/tracks", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn playlists(client: &mut crate::Client, id: u64) -> Result<DzArray<UserPlaylist>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/playlists", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn personal_songs(client: &mut crate::Client) -> Result<DzArray<Track>, ErrorKind> {
|
||||
client.api_call(Method::GET, "user/me/personal_songs", &()).await
|
||||
}
|
||||
|
||||
pub async fn album_chart(client: &mut crate::Client, id: u64) -> Result<DzArray<Album>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/charts/albums", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn artist_chart(client: &mut crate::Client, id: u64) -> Result<DzArray<Artist>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/charts/artists", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn track_chart(client: &mut crate::Client, id: u64) -> Result<DzArray<Track>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/charts/tracks", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn playlist_chart(client: &mut crate::Client, id: u64) -> Result<DzArray<Playlist>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/charts/playlists", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn flow(client: &mut crate::Client, id: u64) -> Result<DzArray<Track>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/flow", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn history(client: &mut crate::Client) -> Result<DzArray<Track>, ErrorKind> {
|
||||
client.api_call(Method::GET, "user/me/history", &()).await
|
||||
}
|
||||
|
||||
pub async fn followings(client: &mut crate::Client, id: u64) -> Result<DzArray<Self>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/followings", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn follow(client: &mut crate::Client, id: u64) -> Result<bool, ErrorKind> {
|
||||
client.api_call(Method::POST, "user/me/followings", &[("user_id", &id.to_string())]).await
|
||||
}
|
||||
|
||||
pub async fn unfollow(client: &mut crate::Client, id: u64) -> Result<bool, ErrorKind> {
|
||||
client.api_call(Method::DELETE, "user/me/followings", &[("user_id", &id.to_string())]).await
|
||||
}
|
||||
|
||||
pub async fn followers(client: &mut crate::Client, id: u64) -> Result<DzArray<Self>, ErrorKind> {
|
||||
client.api_call(Method::GET, &format!("user/{}/followers", id), &()).await
|
||||
}
|
||||
|
||||
pub async fn album_recommendations(client: &mut crate::Client) -> Result<DzArray<RecommendationAlbum>, ErrorKind> {
|
||||
client.api_call(Method::GET, "user/me/recommendations/albums", &()).await
|
||||
}
|
||||
|
||||
pub async fn release_recommendations(client: &mut crate::Client) -> Result<DzArray<RecommendationAlbum>, ErrorKind> {
|
||||
client.api_call(Method::GET, "user/me/recommendations/releases", &()).await
|
||||
}
|
||||
|
||||
pub async fn artist_recommendations(client: &mut crate::Client) -> Result<DzArray<Artist>, ErrorKind> {
|
||||
client.api_call(Method::GET, "user/me/recommendations/artists", &()).await
|
||||
}
|
||||
|
||||
pub async fn playlist_recommendations(client: &mut crate::Client) -> Result<DzArray<Playlist>, ErrorKind> {
|
||||
client.api_call(Method::GET, "user/me/recommendations/playlists", &()).await
|
||||
}
|
||||
|
||||
pub async fn track_recommendations(client: &mut crate::Client) -> Result<DzArray<Track>, ErrorKind> {
|
||||
client.api_call(Method::GET, "user/me/recommendations/tracks", &()).await
|
||||
}
|
||||
|
||||
pub async fn radio_recommendations(client: &mut crate::Client) -> Result<DzArray<Radio>, ErrorKind> {
|
||||
client.api_call(Method::GET, "user/me/recommendations/radios", &()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct UserAlbum {
|
||||
#[serde(flatten)]
|
||||
pub album: Album,
|
||||
|
||||
pub time_add: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct UserArtist {
|
||||
#[serde(flatten)]
|
||||
pub artist: Artist,
|
||||
|
||||
pub time_add: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct UserTrack {
|
||||
#[serde(flatten)]
|
||||
pub track: Track,
|
||||
|
||||
pub time_add: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct UserPlaylist {
|
||||
#[serde(flatten)]
|
||||
pub playlist: Playlist,
|
||||
|
||||
pub time_add: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct UserPodcast {
|
||||
#[serde(flatten)]
|
||||
pub podcast: Podcast,
|
||||
|
||||
pub time_add: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct UserRadio {
|
||||
#[serde(flatten)]
|
||||
pub radio: Radio,
|
||||
|
||||
pub time_add: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct RecommendationAlbum {
|
||||
#[serde(flatten)]
|
||||
pub album: Album,
|
||||
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
impl ImgObject for User {
|
||||
fn md5_img(&self) -> Option<&str> {
|
||||
Some(self.picture_small.as_ref()?.split('/').collect::<Vec<&str>>()[5])
|
||||
}
|
||||
|
||||
fn img_type(&self) -> &'static str {
|
||||
"user"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,570 @@
|
|||
use dzlib_rs::{Client, objects::*, errors::ErrorKind};
|
||||
use tokio_test::block_on;
|
||||
|
||||
const EMAIL: &str = "email";
|
||||
const PASSWORD: &str = "password";
|
||||
|
||||
#[test]
|
||||
fn check_access_token() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.get_token())?;
|
||||
let token = client.access_token.unwrap().token;
|
||||
println!("{}", token);
|
||||
assert_eq!(token.len(), 51);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_track() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let track = block_on(client.track(3135556))?;
|
||||
println!("{:#?}", track);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_track_genres() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let genres = block_on(Track::genres(&mut client, 3135556))?;
|
||||
println!("{:#?}", genres);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_album() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let album = block_on(client.album(302127))?;
|
||||
println!("{:#?}", album);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_album_fans() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let fans = block_on(Album::fans(&mut client, 302127))?;
|
||||
println!("{:#?}", fans);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_album_tracks() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let tracks = block_on(Album::tracks(&mut client, 302127))?;
|
||||
println!("{:#?}", tracks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_artist() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let artist = block_on(client.artist(27))?;
|
||||
println!("{:#?}", artist);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_artist_top() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let top = block_on(Artist::top(&mut client, 27))?;
|
||||
println!("{:#?}", top);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_artist_albums() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let albums = block_on(Artist::fans(&mut client, 27))?;
|
||||
println!("{:#?}", albums);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_artist_fans() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let fans = block_on(Artist::fans(&mut client, 27))?;
|
||||
println!("{:#?}", fans);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_artist_related() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let related = block_on(Artist::related(&mut client, 27))?;
|
||||
println!("{:#?}", related);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_artist_radio() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let radio = block_on(Artist::radio(&mut client, 27))?;
|
||||
println!("{:#?}", radio);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_artist_playlists() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let playlists = block_on(Artist::playlists(&mut client, 27))?;
|
||||
println!("{:#?}", playlists);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_playlist() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let playlist = block_on(client.playlist(2021502402))?;
|
||||
println!("{:#?}", playlist);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_playlist_fans() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let playlist = block_on(Playlist::fans(&mut client, 2021502402))?;
|
||||
println!("{:#?}", playlist);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_playlist_tracks() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let tracks = block_on(Playlist::tracks(&mut client, 2021502402))?;
|
||||
println!("{:#?}", tracks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_playlist_seen() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let seen = block_on(Playlist::seen(&mut client, 2021502402))?;
|
||||
println!("{:#?}", seen);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let user = block_on(client.user(2741487522))?;
|
||||
println!("{:#?}", user);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_self() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let user = block_on(client.user_self())?;
|
||||
println!("{:#?}", user);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_albums() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let albums = block_on(User::albums(&mut client, 5))?;
|
||||
println!("{:#?}", albums);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_artists() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let artists = block_on(User::artists(&mut client, 5))?;
|
||||
println!("{:#?}", artists);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_tracks() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let tracks = block_on(User::tracks(&mut client, 5))?;
|
||||
println!("{:#?}", tracks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_playlists() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let playlists = block_on(User::playlists(&mut client, 5))?;
|
||||
println!("{:#?}", playlists);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_personal_songs() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let songs = block_on(User::personal_songs(&mut client))?;
|
||||
println!("{:#?}", songs);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_album_chart() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let chart = block_on(User::album_chart(&mut client, 5))?;
|
||||
println!("{:#?}", chart);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_artist_chart() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let chart = block_on(User::artist_chart(&mut client, 5))?;
|
||||
println!("{:#?}", chart);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_track_chart() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let chart = block_on(User::track_chart(&mut client, 5))?;
|
||||
println!("{:#?}", chart);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_playlist_chart() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let chart = block_on(User::playlist_chart(&mut client, 5))?;
|
||||
println!("{:#?}", chart);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_flow() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let flow = block_on(User::flow(&mut client, 5))?;
|
||||
println!("{:#?}", flow);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_history() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let history = block_on(User::history(&mut client))?;
|
||||
println!("{:#?}", history);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_followings() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let followings = block_on(User::followings(&mut client, 5))?;
|
||||
println!("{:#?}", followings);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_followers() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let followers = block_on(User::followers(&mut client, 5))?;
|
||||
println!("{:#?}", followers);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_album_rec() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let rec = block_on(User::album_recommendations(&mut client))?;
|
||||
println!("{:#?}", rec);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_release_rec() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let rec = block_on(User::release_recommendations(&mut client))?;
|
||||
println!("{:#?}", rec);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_artist_rec() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let rec = block_on(User::artist_recommendations(&mut client))?;
|
||||
println!("{:#?}", rec);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_playlist_rec() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let rec = block_on(User::playlist_recommendations(&mut client))?;
|
||||
println!("{:#?}", rec);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_track_rec() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let rec = block_on(User::track_recommendations(&mut client))?;
|
||||
println!("{:#?}", rec);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_user_radio_rec() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let rec = block_on(User::radio_recommendations(&mut client))?;
|
||||
println!("{:#?}", rec);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_infos() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let infos = block_on(client.infos())?;
|
||||
println!("{:#?}", infos);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_genre() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let genre = block_on(client.genre(0))?;
|
||||
println!("{:#?}", genre);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_genre_artists() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let artists = block_on(Genre::artists(&mut client, 0))?;
|
||||
println!("{:#?}", artists);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_genre_radios() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let radios = block_on(Genre::radios(&mut client, 0))?;
|
||||
println!("{:#?}", radios);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_options() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let options = block_on(client.options())?;
|
||||
println!("{:#?}", options);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_editorial() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let editorial = block_on(client.editorial(0))?;
|
||||
println!("{:#?}", editorial);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_editorial_list() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let list = block_on(Editorial::list(&mut client))?;
|
||||
println!("{:#?}", list);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_editorial_selection() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let selection = block_on(Editorial::selection(&mut client, 0))?;
|
||||
println!("{:#?}", selection);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_editorial_charts() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let charts = block_on(Editorial::charts(&mut client, 0))?;
|
||||
println!("{:#?}", charts);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_lyrics() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let lyrics = block_on(client.lyrics(2780622))?;
|
||||
println!("{:#?}", lyrics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_radio() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let radio = block_on(client.radio(6))?;
|
||||
println!("{:#?}", radio);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_radio_list() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let radio_list = block_on(client.radio_list())?;
|
||||
println!("{:#?}", radio_list);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_radio_genres() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let genres = block_on(Radio::genres(&mut client))?;
|
||||
println!("{:#?}", genres);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_chart() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let chart = block_on(client.chart(0))?;
|
||||
println!("{:#?}", chart);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_chart_tracks() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let tracks = block_on(Chart::tracks(&mut client, 0))?;
|
||||
println!("{:#?}", tracks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_chart_albums() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let albums = block_on(Chart::albums(&mut client, 0))?;
|
||||
println!("{:#?}", albums);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_chart_artists() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let artists = block_on(Chart::artists(&mut client, 0))?;
|
||||
println!("{:#?}", artists);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_chart_playlists() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let playlists = block_on(Chart::playlists(&mut client, 0))?;
|
||||
println!("{:#?}", playlists);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_chart_podcasts() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let playlists = block_on(Chart::podcasts(&mut client, 0))?;
|
||||
println!("{:#?}", playlists);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_search_track() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let search = block_on(client.search_track("eminem"))?;
|
||||
println!("{:#?}", search);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_search_album() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let search = block_on(client.search_album("eminem"))?;
|
||||
println!("{:#?}", search);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_search_artist() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let search = block_on(client.search_artist("eminem"))?;
|
||||
println!("{:#?}", search);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_search_playlist() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let search = block_on(client.search_playlist("eminem"))?;
|
||||
println!("{:#?}", search);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_search_podcast() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let search = block_on(search::podcast(&mut client, "eminem"))?;
|
||||
println!("{:#?}", search);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_search_radio() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let search = block_on(search::radio(&mut client, "classic"))?;
|
||||
println!("{:#?}", search);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_search_user() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let search = block_on(search::user(&mut client, "eminem"))?;
|
||||
println!("{:#?}", search);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_search_history() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
block_on(client.login(EMAIL, PASSWORD))?;
|
||||
let search = block_on(search::history(&mut client))?;
|
||||
println!("{:#?}", search);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_podcast() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let podcast = block_on(client.podcast(2027))?;
|
||||
println!("{:#?}", podcast);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_podcast_episodes() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let episodes = block_on(Podcast::episodes(&mut client, 2027))?;
|
||||
println!("{:#?}", episodes);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_episode() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let episode = block_on(client.episode(56469))?;
|
||||
println!("{:#?}", episode);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_register() -> Result<(), ErrorKind> {
|
||||
let mut client = Client::new();
|
||||
let user_id = block_on(auth::register(&mut client, "email", "password", "name", "0000-00-00", "M"))?;
|
||||
println!("{:#?}", user_id);
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue