switched to rust 2021 edition, using cookie jar
This commit is contained in:
parent
4773b190b2
commit
89a9303321
|
@ -142,6 +142,17 @@ version = "0.4.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7"
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.15.1"
|
||||
|
@ -153,6 +164,22 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie_store"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3"
|
||||
dependencies = [
|
||||
"cookie 0.14.4",
|
||||
"idna",
|
||||
"log",
|
||||
"publicsuffix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"time",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.1"
|
||||
|
@ -803,6 +830,16 @@ dependencies = [
|
|||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "publicsuffix"
|
||||
version = "1.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95b4ce31ff0a27d93c8de1849cf58162283752f065a90d508f1105fa6c9a213f"
|
||||
dependencies = [
|
||||
"idna",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
|
@ -916,6 +953,8 @@ dependencies = [
|
|||
"async-compression",
|
||||
"base64",
|
||||
"bytes",
|
||||
"cookie 0.14.4",
|
||||
"cookie_store",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
|
@ -934,6 +973,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-util",
|
||||
|
@ -1021,7 +1061,7 @@ version = "0.5.0-rc.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23c8b7d512d2fcac2316ebe590cde67573844b99e6cc9ee0f53375fa16e25ebd"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"cookie 0.15.1",
|
||||
"either",
|
||||
"http",
|
||||
"hyper",
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
[package]
|
||||
name = "dzmedia"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rocket = { version = "0.5.0-rc.1", features = ["json"], default-features = false }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
reqwest = { version = "0.11", features = ["json", "rustls-tls", "gzip"], default-features = false }
|
||||
reqwest = { version = "0.11", features = ["json", "rustls-tls", "cookies", "gzip"], default-features = false }
|
||||
serde_json = "1.0"
|
||||
thiserror = "1.0"
|
||||
regex = "1"
|
82
src/api.rs
82
src/api.rs
|
@ -1,8 +1,8 @@
|
|||
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
||||
use std::{env, marker::Sized, time::Instant};
|
||||
use std::{env, marker::Sized, time::Instant, sync::Arc};
|
||||
use thiserror::Error;
|
||||
use serde_json::{json, value::from_value};
|
||||
use regex::Regex;
|
||||
use reqwest::{Client, Response, cookie::Jar, Url};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DeezerResponse {
|
||||
|
@ -52,23 +52,28 @@ pub enum APIError {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct APIClient {
|
||||
client: reqwest::Client,
|
||||
license_token: String,
|
||||
client: Client,
|
||||
pub license_token: String,
|
||||
check_form: String,
|
||||
pub sid: String,
|
||||
arl: String,
|
||||
renew_instant: Option<Instant>,
|
||||
}
|
||||
|
||||
impl APIClient {
|
||||
pub fn new() -> Self {
|
||||
if let Ok(arl) = env::var("ARL") {
|
||||
let builder = Client::builder();
|
||||
|
||||
let cookie = format!("arl={}; Domain=.deezer.com", arl);
|
||||
let url = "https://www.deezer.com".parse::<Url>().unwrap();
|
||||
|
||||
let jar = Jar::default();
|
||||
jar.add_cookie_str(&cookie, &url);
|
||||
let builder = builder.cookie_provider(Arc::new(jar));
|
||||
|
||||
Self {
|
||||
client: reqwest::Client::new(),
|
||||
client: builder.build().unwrap(),
|
||||
license_token: String::new(),
|
||||
check_form: String::new(),
|
||||
sid: String::new(),
|
||||
arl,
|
||||
renew_instant: None,
|
||||
}
|
||||
} else {
|
||||
|
@ -76,8 +81,9 @@ impl APIClient {
|
|||
}
|
||||
}
|
||||
|
||||
async fn raw_api_call<T>(&self, method: &str, params: &T) -> Result<reqwest::Response, reqwest::Error>
|
||||
where T: Serialize + ?Sized
|
||||
async fn no_renew_api_call<P, T>(&mut self, method: &str, params: &P) -> Result<T, APIError>
|
||||
where P: Serialize + ?Sized,
|
||||
T: DeserializeOwned
|
||||
{
|
||||
let check_form;
|
||||
if method == "deezer.getUserData" {
|
||||
|
@ -86,13 +92,7 @@ impl APIClient {
|
|||
check_form = &self.check_form;
|
||||
}
|
||||
|
||||
let mut cookies = format!("arl={}", self.arl);
|
||||
|
||||
if self.sid != "" && method != "deezer.getUserData" {
|
||||
cookies.push_str(&format!("; sid={}", self.sid))
|
||||
}
|
||||
|
||||
self.client.post("https://www.deezer.com/ajax/gw-light.php")
|
||||
let json: DeezerResponse = self.client.post("https://www.deezer.com/ajax/gw-light.php")
|
||||
.query(&[
|
||||
("method", method),
|
||||
("input", "3"),
|
||||
|
@ -100,26 +100,9 @@ impl APIClient {
|
|||
("api_token", check_form)
|
||||
])
|
||||
.json(params)
|
||||
.header("cookie", &cookies)
|
||||
.send()
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn api_call<P, T>(&mut self, method: &str, params: &P) -> Result<T, APIError>
|
||||
where P: Serialize + ?Sized,
|
||||
T: DeserializeOwned
|
||||
{
|
||||
if let Some(i) = self.renew_instant {
|
||||
if i.elapsed().as_secs() >= 3600 {
|
||||
self.renew().await?;
|
||||
}
|
||||
} else {
|
||||
self.renew().await?;
|
||||
}
|
||||
|
||||
let json = self.raw_api_call(method, params)
|
||||
.await?
|
||||
.json::<DeezerResponse>()
|
||||
.json()
|
||||
.await?;
|
||||
|
||||
if let Some(error) = json.error.as_object() {
|
||||
|
@ -134,24 +117,33 @@ impl APIClient {
|
|||
Ok(from_value(json.results)?)
|
||||
}
|
||||
|
||||
async fn renew(&mut self) -> Result<(), reqwest::Error> {
|
||||
let resp = self.raw_api_call("deezer.getUserData", &json!({})).await?;
|
||||
pub async fn api_call<P, T>(&mut self, method: &str, params: &P) -> Result<T, APIError>
|
||||
where P: Serialize + ?Sized,
|
||||
T: DeserializeOwned
|
||||
{
|
||||
if let Some(i) = self.renew_instant {
|
||||
if i.elapsed().as_secs() >= 3600 {
|
||||
self.renew().await?;
|
||||
}
|
||||
} else {
|
||||
self.renew().await?;
|
||||
}
|
||||
|
||||
let sid = resp.headers().get("set-cookie").unwrap().to_str().unwrap();
|
||||
let sid = Regex::new("^sid=(fr[\\da-f]+)").unwrap().captures(sid).unwrap();
|
||||
self.sid = (&sid[1]).to_string();
|
||||
self.no_renew_api_call(method, params).await
|
||||
}
|
||||
|
||||
let json = resp.json::<DeezerResponse>().await?.results;
|
||||
async fn renew(&mut self) -> Result<(), APIError> {
|
||||
let user_data: serde_json::Value = self.no_renew_api_call("deezer.getUserData", &json!({})).await?;
|
||||
|
||||
self.check_form = json["checkForm"].as_str().unwrap().to_string();
|
||||
self.license_token = json["USER"]["OPTIONS"]["license_token"].as_str().unwrap().to_string();
|
||||
self.check_form = user_data["checkForm"].as_str().unwrap().to_string();
|
||||
self.license_token = user_data["USER"]["OPTIONS"]["license_token"].as_str().unwrap().to_string();
|
||||
|
||||
self.renew_instant = Some(Instant::now());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_media(&self, formats: &Vec<Format>, track_tokens: Vec<&str>) -> Result<reqwest::Response, reqwest::Error> {
|
||||
pub async fn get_media(&self, formats: &Vec<Format>, track_tokens: Vec<&str>) -> Result<Response, reqwest::Error> {
|
||||
let formats: Vec<DeezerFormat> = formats.iter().map(|f| DeezerFormat { cipher: "BF_CBC_STRIPE", format: f }).collect();
|
||||
|
||||
let req = json!({
|
||||
|
|
|
@ -46,10 +46,10 @@ async fn get_url(req: Json<RequestParams>, state_data: &State<RwLock<StateData>>
|
|||
}
|
||||
|
||||
let mut client: APIClient;
|
||||
let old_sid: String;
|
||||
let old_license: String;
|
||||
{
|
||||
let state_data_read = state_data.read().unwrap();
|
||||
old_sid = state_data_read.client.sid.clone();
|
||||
old_license = state_data_read.client.license_token.clone();
|
||||
client = state_data_read.client.clone();
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ async fn get_url(req: Json<RequestParams>, state_data: &State<RwLock<StateData>>
|
|||
Err(_) => return (Status::InternalServerError, "Error while getting response from media.deezer.com".to_string())
|
||||
};
|
||||
|
||||
if client.sid != old_sid {
|
||||
if client.license_token != old_license {
|
||||
let mut state_data_write = state_data.write().unwrap();
|
||||
state_data_write.client = client;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue