recycleactor commited on
Commit
c2658b8
·
verified ·
1 Parent(s): 544a7bc

Upload 2 files

Browse files
Files changed (2) hide show
  1. src/api.rs +17 -6
  2. src/main.rs +80 -36
src/api.rs CHANGED
@@ -1,5 +1,6 @@
1
  use serde::{Serialize, Deserialize, de::DeserializeOwned};
2
  use std::{env, marker::Sized, time::Instant, sync::Arc};
 
3
  use thiserror::Error;
4
  use serde_json::{json, value::from_value};
5
  use reqwest::{Client, Response, cookie::Jar, Url, header::ACCEPT};
@@ -107,21 +108,31 @@ impl APIClient {
107
  }
108
 
109
  let url = "https://www.deezer.com/ajax/gw-light.php";
110
- let req = if method == "deezer.getUserData" {
111
- self.client.get(url)
112
- } else {
113
- self.client.post(url).json(params)
114
- };
115
- let json: DeezerResponse = req
 
 
 
 
 
 
116
  .query(&[
117
  ("method", method),
118
  ("input", "3"),
119
  ("api_version", "1.0"),
120
  ("api_token", check_form),
 
121
  ])
122
  .header(ACCEPT, "*/*")
123
  .header("Origin", "https://www.deezer.com")
124
  .header("Referer", "https://www.deezer.com/")
 
 
 
125
  .header("X-Requested-With", "XMLHttpRequest")
126
  .header("Accept-Language", "en-US,en;q=0.9")
127
  .header(
 
1
  use serde::{Serialize, Deserialize, de::DeserializeOwned};
2
  use std::{env, marker::Sized, time::Instant, sync::Arc};
3
+ use std::time::{SystemTime, UNIX_EPOCH};
4
  use thiserror::Error;
5
  use serde_json::{json, value::from_value};
6
  use reqwest::{Client, Response, cookie::Jar, Url, header::ACCEPT};
 
108
  }
109
 
110
  let url = "https://www.deezer.com/ajax/gw-light.php";
111
+ let cid = SystemTime::now()
112
+ .duration_since(UNIX_EPOCH)
113
+ .map(|d| d.as_millis().to_string())
114
+ .unwrap_or_else(|_| "0".to_string());
115
+
116
+ let body = serde_json::to_string(params)?;
117
+
118
+ let json: DeezerResponse = self
119
+ .client
120
+ .post(url)
121
+ .header("Content-Type", "text/plain;charset=UTF-8")
122
+ .body(body)
123
  .query(&[
124
  ("method", method),
125
  ("input", "3"),
126
  ("api_version", "1.0"),
127
  ("api_token", check_form),
128
+ ("cid", cid.as_str()),
129
  ])
130
  .header(ACCEPT, "*/*")
131
  .header("Origin", "https://www.deezer.com")
132
  .header("Referer", "https://www.deezer.com/")
133
+ .header("Sec-Fetch-Site", "same-origin")
134
+ .header("Sec-Fetch-Mode", "cors")
135
+ .header("Sec-Fetch-Dest", "empty")
136
  .header("X-Requested-With", "XMLHttpRequest")
137
  .header("Accept-Language", "en-US,en;q=0.9")
138
  .header(
src/main.rs CHANGED
@@ -20,6 +20,7 @@ use cbc::Decryptor;
20
  use reqwest::{cookie::Jar, Url};
21
  use reqwest::cookie::CookieStore;
22
  use reqwest::header::ACCEPT;
 
23
 
24
  type BoxErr = Box<dyn std::error::Error + Send + Sync + 'static>;
25
 
@@ -436,46 +437,89 @@ async fn gw_light_call(
436
  params: serde_json::Value,
437
  ) -> Result<serde_json::Value, String> {
438
  let url = "https://www.deezer.com/ajax/gw-light.php";
439
- let req = if method == "deezer.getUserData" {
440
- client.get(url)
441
- } else {
442
- client.post(url).json(&params)
443
- };
444
- let r = req
445
- .query(&[
446
- ("method", method),
447
- ("input", "3"),
448
- ("api_version", "1.0"),
449
- ("api_token", api_token),
450
- ])
451
- .header(ACCEPT, "*/*")
452
- .header("Origin", "https://www.deezer.com")
453
- .header("Referer", "https://www.deezer.com/")
454
- .header("X-Requested-With", "XMLHttpRequest")
455
- .header("Accept-Language", "en-US,en;q=0.9")
456
- .header(
457
- "User-Agent",
458
- "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0",
459
- )
460
- .send()
461
- .await
462
- .map_err(|_| "network".to_string())?;
463
-
464
- let status = r.status();
465
- let text = r.text().await.map_err(|_| "read".to_string())?;
466
- let json: GwResp = serde_json::from_str(&text).map_err(|_| {
467
- let snip: String = text.chars().take(200).collect();
468
- format!("parse:{}:{}", status.as_u16(), snip)
469
- })?;
470
 
471
- if let Some(error) = json.error.as_object() {
472
- for (code, message) in error {
473
- let msg = message.as_str().unwrap_or("");
474
- return Err(format!("{}:{}", code, msg));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  }
 
 
476
  }
477
 
478
- Ok(json.results)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
479
  }
480
 
481
  fn jar_has_cookie(jar: &Jar, url: &Url, cookie_prefix: &str) -> bool {
 
20
  use reqwest::{cookie::Jar, Url};
21
  use reqwest::cookie::CookieStore;
22
  use reqwest::header::ACCEPT;
23
+ use std::time::{SystemTime, UNIX_EPOCH};
24
 
25
  type BoxErr = Box<dyn std::error::Error + Send + Sync + 'static>;
26
 
 
437
  params: serde_json::Value,
438
  ) -> Result<serde_json::Value, String> {
439
  let url = "https://www.deezer.com/ajax/gw-light.php";
440
+ fn cid() -> String {
441
+ SystemTime::now()
442
+ .duration_since(UNIX_EPOCH)
443
+ .map(|d| d.as_millis().to_string())
444
+ .unwrap_or_else(|_| "0".to_string())
445
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
 
447
+ async fn do_req(
448
+ client: &reqwest::Client,
449
+ url: &str,
450
+ method: &str,
451
+ api_token: &str,
452
+ params: &serde_json::Value,
453
+ use_get: bool,
454
+ ) -> Result<serde_json::Value, String> {
455
+ let cid = cid();
456
+ let req = if use_get {
457
+ client.get(url)
458
+ } else {
459
+ client
460
+ .post(url)
461
+ .header("Content-Type", "text/plain;charset=UTF-8")
462
+ .body(params.to_string())
463
+ };
464
+
465
+ let r = req
466
+ .query(&[
467
+ ("method", method),
468
+ ("input", "3"),
469
+ ("api_version", "1.0"),
470
+ ("api_token", api_token),
471
+ ("cid", cid.as_str()),
472
+ ])
473
+ .header(ACCEPT, "*/*")
474
+ .header("Origin", "https://www.deezer.com")
475
+ .header("Referer", "https://www.deezer.com/")
476
+ .header("Sec-Fetch-Site", "same-origin")
477
+ .header("Sec-Fetch-Mode", "cors")
478
+ .header("Sec-Fetch-Dest", "empty")
479
+ .header("X-Requested-With", "XMLHttpRequest")
480
+ .header("Accept-Language", "en-US,en;q=0.9")
481
+ .header(
482
+ "User-Agent",
483
+ "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0",
484
+ )
485
+ .send()
486
+ .await
487
+ .map_err(|_| "network".to_string())?;
488
+
489
+ let status = r.status();
490
+ let text = r.text().await.map_err(|_| "read".to_string())?;
491
+ let json: GwResp = serde_json::from_str(&text).map_err(|_| {
492
+ let snip: String = text.chars().take(200).collect();
493
+ format!("parse:{}:{}", status.as_u16(), snip)
494
+ })?;
495
+
496
+ if let Some(error) = json.error.as_object() {
497
+ for (code, message) in error {
498
+ let msg = message.as_str().unwrap_or("");
499
+ return Err(format!("{}:{}", code, msg));
500
+ }
501
  }
502
+
503
+ Ok(json.results)
504
  }
505
 
506
+ if method == "deezer.getUserData" {
507
+ match do_req(client, url, method, api_token, &params, true).await {
508
+ Ok(v) => Ok(v),
509
+ Err(e1) => match do_req(client, url, method, api_token, &params, false).await {
510
+ Ok(v) => Ok(v),
511
+ Err(e2) => Err(format!("getUserData:{e1}; fallback:{e2}")),
512
+ },
513
+ }
514
+ } else {
515
+ match do_req(client, url, method, api_token, &params, false).await {
516
+ Ok(v) => Ok(v),
517
+ Err(e1) => match do_req(client, url, method, api_token, &params, false).await {
518
+ Ok(v) => Ok(v),
519
+ Err(e2) => Err(format!("{e1}; retry:{e2}")),
520
+ },
521
+ }
522
+ }
523
  }
524
 
525
  fn jar_has_cookie(jar: &Jar, url: &Url, cookie_prefix: &str) -> bool {