Spaces:
Paused
Paused
Upload main.rs
Browse files- src/main.rs +60 -21
src/main.rs
CHANGED
|
@@ -961,11 +961,28 @@ async fn oauth_access_token(
|
|
| 961 |
|
| 962 |
async fn gw_light_call(
|
| 963 |
client: &reqwest::Client,
|
|
|
|
| 964 |
method: &str,
|
| 965 |
api_token: &str,
|
| 966 |
params: serde_json::Value,
|
| 967 |
) -> Result<serde_json::Value, String> {
|
| 968 |
let url = "https://www.deezer.com/ajax/gw-light.php";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 969 |
fn cid() -> String {
|
| 970 |
SystemTime::now()
|
| 971 |
.duration_since(UNIX_EPOCH)
|
|
@@ -975,22 +992,36 @@ async fn gw_light_call(
|
|
| 975 |
|
| 976 |
async fn do_req(
|
| 977 |
client: &reqwest::Client,
|
|
|
|
|
|
|
| 978 |
url: &str,
|
| 979 |
method: &str,
|
| 980 |
api_token: &str,
|
| 981 |
params: &serde_json::Value,
|
| 982 |
use_get: bool,
|
|
|
|
| 983 |
) -> Result<serde_json::Value, String> {
|
| 984 |
let cid = cid();
|
| 985 |
-
let req = if use_get {
|
| 986 |
client.get(url)
|
| 987 |
} else {
|
| 988 |
-
client
|
| 989 |
-
.post(url)
|
| 990 |
-
.header("Content-Type", "application/json")
|
| 991 |
-
.body(params.to_string())
|
| 992 |
};
|
| 993 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 994 |
let r = req
|
| 995 |
.query(&[
|
| 996 |
("method", method),
|
|
@@ -1000,18 +1031,36 @@ async fn gw_light_call(
|
|
| 1000 |
("cid", cid.as_str()),
|
| 1001 |
])
|
| 1002 |
.header(ACCEPT, "*/*")
|
|
|
|
|
|
|
| 1003 |
.header("Origin", "https://www.deezer.com")
|
| 1004 |
.header("Referer", "https://www.deezer.com/")
|
| 1005 |
.header("X-Requested-With", "XMLHttpRequest")
|
| 1006 |
.header("Accept-Language", "en-US,en;q=0.9")
|
|
|
|
|
|
|
|
|
|
| 1007 |
.header(
|
| 1008 |
"User-Agent",
|
| 1009 |
-
"Mozilla/5.0 (X11; Linux x86_64
|
| 1010 |
)
|
| 1011 |
.send()
|
| 1012 |
.await
|
| 1013 |
.map_err(|_| "network".to_string())?;
|
| 1014 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1015 |
let status = r.status();
|
| 1016 |
let text = r.text().await.map_err(|_| "read".to_string())?;
|
| 1017 |
let json: GwResp = serde_json::from_str(&text).map_err(|_| {
|
|
@@ -1029,22 +1078,12 @@ async fn gw_light_call(
|
|
| 1029 |
Ok(json.results)
|
| 1030 |
}
|
| 1031 |
|
| 1032 |
-
|
| 1033 |
-
|
|
|
|
| 1034 |
Ok(v) => Ok(v),
|
| 1035 |
-
Err(
|
| 1036 |
-
|
| 1037 |
-
Err(e2) => Err(format!("getUserData:{e1}; fallback:{e2}")),
|
| 1038 |
-
},
|
| 1039 |
-
}
|
| 1040 |
-
} else {
|
| 1041 |
-
match do_req(client, url, method, api_token, ¶ms, false).await {
|
| 1042 |
-
Ok(v) => Ok(v),
|
| 1043 |
-
Err(e1) => match do_req(client, url, method, api_token, ¶ms, false).await {
|
| 1044 |
-
Ok(v) => Ok(v),
|
| 1045 |
-
Err(e2) => Err(format!("{e1}; retry:{e2}")),
|
| 1046 |
-
},
|
| 1047 |
-
}
|
| 1048 |
}
|
| 1049 |
}
|
| 1050 |
|
|
|
|
| 961 |
|
| 962 |
async fn gw_light_call(
|
| 963 |
client: &reqwest::Client,
|
| 964 |
+
jar: &Arc<Jar>,
|
| 965 |
method: &str,
|
| 966 |
api_token: &str,
|
| 967 |
params: serde_json::Value,
|
| 968 |
) -> Result<serde_json::Value, String> {
|
| 969 |
let url = "https://www.deezer.com/ajax/gw-light.php";
|
| 970 |
+
let url_deezer = "https://www.deezer.com".parse::<Url>().unwrap();
|
| 971 |
+
|
| 972 |
+
fn cookie_value(jar: &Jar, url: &Url, key: &str) -> Option<String> {
|
| 973 |
+
let Some(hv) = jar.cookies(url) else { return None };
|
| 974 |
+
let Ok(s) = hv.to_str() else { return None };
|
| 975 |
+
for part in s.split(';') {
|
| 976 |
+
let p = part.trim();
|
| 977 |
+
if let Some(rest) = p.strip_prefix(&format!("{key}=")) {
|
| 978 |
+
if !rest.is_empty() {
|
| 979 |
+
return Some(rest.to_string());
|
| 980 |
+
}
|
| 981 |
+
}
|
| 982 |
+
}
|
| 983 |
+
None
|
| 984 |
+
}
|
| 985 |
+
|
| 986 |
fn cid() -> String {
|
| 987 |
SystemTime::now()
|
| 988 |
.duration_since(UNIX_EPOCH)
|
|
|
|
| 992 |
|
| 993 |
async fn do_req(
|
| 994 |
client: &reqwest::Client,
|
| 995 |
+
jar: &Arc<Jar>,
|
| 996 |
+
url_deezer: &Url,
|
| 997 |
url: &str,
|
| 998 |
method: &str,
|
| 999 |
api_token: &str,
|
| 1000 |
params: &serde_json::Value,
|
| 1001 |
use_get: bool,
|
| 1002 |
+
user_id: Option<&str>,
|
| 1003 |
) -> Result<serde_json::Value, String> {
|
| 1004 |
let cid = cid();
|
| 1005 |
+
let mut req = if use_get || method == "user.getArl" {
|
| 1006 |
client.get(url)
|
| 1007 |
} else {
|
| 1008 |
+
client.post(url).header("Content-Type", "application/json").body(params.to_string())
|
|
|
|
|
|
|
|
|
|
| 1009 |
};
|
| 1010 |
|
| 1011 |
+
let sid = cookie_value(jar, url_deezer, "sid").unwrap_or_default();
|
| 1012 |
+
let arl = cookie_value(jar, url_deezer, "arl").unwrap_or_default();
|
| 1013 |
+
if !sid.is_empty() || !arl.is_empty() {
|
| 1014 |
+
let mut parts: Vec<String> = Vec::new();
|
| 1015 |
+
parts.push(format!("arl={arl}"));
|
| 1016 |
+
if !sid.is_empty() {
|
| 1017 |
+
parts.push(format!("sid={sid}"));
|
| 1018 |
+
}
|
| 1019 |
+
req = req.header("Cookie", parts.join("; "));
|
| 1020 |
+
}
|
| 1021 |
+
if let Some(uid) = user_id.filter(|s| !s.trim().is_empty()) {
|
| 1022 |
+
req = req.header("x-deezer-user", uid);
|
| 1023 |
+
}
|
| 1024 |
+
|
| 1025 |
let r = req
|
| 1026 |
.query(&[
|
| 1027 |
("method", method),
|
|
|
|
| 1031 |
("cid", cid.as_str()),
|
| 1032 |
])
|
| 1033 |
.header(ACCEPT, "*/*")
|
| 1034 |
+
.header("Cache-Control", "max-age=0")
|
| 1035 |
+
.header("Connection", "keep-alive")
|
| 1036 |
.header("Origin", "https://www.deezer.com")
|
| 1037 |
.header("Referer", "https://www.deezer.com/")
|
| 1038 |
.header("X-Requested-With", "XMLHttpRequest")
|
| 1039 |
.header("Accept-Language", "en-US,en;q=0.9")
|
| 1040 |
+
.header("Content-Language", "en-US")
|
| 1041 |
+
.header("X-User-IP", "1.1.1.1")
|
| 1042 |
+
.header("x-deezer-client-ip", "1.1.1.1")
|
| 1043 |
.header(
|
| 1044 |
"User-Agent",
|
| 1045 |
+
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36",
|
| 1046 |
)
|
| 1047 |
.send()
|
| 1048 |
.await
|
| 1049 |
.map_err(|_| "network".to_string())?;
|
| 1050 |
|
| 1051 |
+
if method == "deezer.getUserData" {
|
| 1052 |
+
for v in r.headers().get_all("set-cookie").iter() {
|
| 1053 |
+
if let Ok(s) = v.to_str() {
|
| 1054 |
+
if s.starts_with("sid=") {
|
| 1055 |
+
let cookie = s.split(';').next().unwrap_or("").trim();
|
| 1056 |
+
if !cookie.is_empty() {
|
| 1057 |
+
jar.add_cookie_str(&format!("{cookie}; Domain=.deezer.com"), url_deezer);
|
| 1058 |
+
}
|
| 1059 |
+
}
|
| 1060 |
+
}
|
| 1061 |
+
}
|
| 1062 |
+
}
|
| 1063 |
+
|
| 1064 |
let status = r.status();
|
| 1065 |
let text = r.text().await.map_err(|_| "read".to_string())?;
|
| 1066 |
let json: GwResp = serde_json::from_str(&text).map_err(|_| {
|
|
|
|
| 1078 |
Ok(json.results)
|
| 1079 |
}
|
| 1080 |
|
| 1081 |
+
match do_req(client, jar, &url_deezer, url, method, api_token, ¶ms, false, None).await {
|
| 1082 |
+
Ok(v) => Ok(v),
|
| 1083 |
+
Err(e1) => match do_req(client, jar, &url_deezer, url, method, api_token, ¶ms, false, None).await {
|
| 1084 |
Ok(v) => Ok(v),
|
| 1085 |
+
Err(e2) => Err(format!("{e1}; retry:{e2}")),
|
| 1086 |
+
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1087 |
}
|
| 1088 |
}
|
| 1089 |
|