Spaces:
Paused
Paused
Upload main.rs
Browse files- src/main.rs +16 -172
src/main.rs
CHANGED
|
@@ -1008,6 +1008,8 @@ async fn gw_light_call(
|
|
| 1008 |
("cid", cid.as_str()),
|
| 1009 |
])
|
| 1010 |
.header(ACCEPT, "*/*")
|
|
|
|
|
|
|
| 1011 |
.header("Origin", "https://www.deezer.com")
|
| 1012 |
.header("Referer", "https://www.deezer.com/")
|
| 1013 |
.header("Sec-Fetch-Site", "same-origin")
|
|
@@ -1015,6 +1017,9 @@ async fn gw_light_call(
|
|
| 1015 |
.header("Sec-Fetch-Dest", "empty")
|
| 1016 |
.header("X-Requested-With", "XMLHttpRequest")
|
| 1017 |
.header("Accept-Language", "en-US,en;q=0.9")
|
|
|
|
|
|
|
|
|
|
| 1018 |
.header(
|
| 1019 |
"User-Agent",
|
| 1020 |
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36",
|
|
@@ -1388,12 +1393,10 @@ async fn pair_complete(State(state): State<AppState>, Form(f): Form<PairComplete
|
|
| 1388 |
Err(e) => oauth_err = Some(e),
|
| 1389 |
}
|
| 1390 |
|
| 1391 |
-
|
| 1392 |
-
|
| 1393 |
-
|
| 1394 |
-
if
|
| 1395 |
-
gw_err = Some("gw:no_checkForm".to_string());
|
| 1396 |
-
} else if let Err(e) = gw_light_call(
|
| 1397 |
&client,
|
| 1398 |
&jar,
|
| 1399 |
"user.checkCredentials",
|
|
@@ -1406,15 +1409,18 @@ async fn pair_complete(State(state): State<AppState>, Form(f): Form<PairComplete
|
|
| 1406 |
)
|
| 1407 |
.await
|
| 1408 |
{
|
| 1409 |
-
gw_err = Some(format!("gw:checkCredentials:{e}"));
|
| 1410 |
if access_token_out.is_none() {
|
| 1411 |
-
let msg = gw_err.clone().unwrap_or_else(|| "gw:checkCredentials".to_string());
|
| 1412 |
let mut map = state.pair.write().await;
|
| 1413 |
if let Some(s) = map.get_mut(&code) {
|
| 1414 |
-
s.error = Some(
|
| 1415 |
}
|
| 1416 |
-
return Html(format!(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1417 |
}
|
|
|
|
| 1418 |
} else {
|
| 1419 |
gw_token = Some(token.clone());
|
| 1420 |
gw_uid = ud["USER"]["USER_ID"]
|
|
@@ -1431,9 +1437,6 @@ async fn pair_complete(State(state): State<AppState>, Form(f): Form<PairComplete
|
|
| 1431 |
}
|
| 1432 |
}
|
| 1433 |
}
|
| 1434 |
-
Err(e) => {
|
| 1435 |
-
gw_err = Some(format!("gw:getUserData:{e}"));
|
| 1436 |
-
}
|
| 1437 |
}
|
| 1438 |
|
| 1439 |
if gw_token.is_none() && access_token_out.is_none() {
|
|
@@ -1699,160 +1702,6 @@ async fn oauth_flow(Json(req): Json<OauthFlowReq>) -> impl IntoResponse {
|
|
| 1699 |
}
|
| 1700 |
}
|
| 1701 |
|
| 1702 |
-
#[derive(Debug, Deserialize)]
|
| 1703 |
-
struct OauthRecoReq {
|
| 1704 |
-
access_token: String,
|
| 1705 |
-
index: Option<u32>,
|
| 1706 |
-
limit: Option<u32>,
|
| 1707 |
-
}
|
| 1708 |
-
|
| 1709 |
-
async fn oauth_reco_playlists(Json(req): Json<OauthRecoReq>) -> impl IntoResponse {
|
| 1710 |
-
let token = req.access_token.trim().to_string();
|
| 1711 |
-
if token.is_empty() {
|
| 1712 |
-
return json_error(StatusCode::BAD_REQUEST, "access_token required");
|
| 1713 |
-
}
|
| 1714 |
-
let index = req.index.unwrap_or(0).to_string();
|
| 1715 |
-
let limit = req.limit.unwrap_or(20).clamp(1, 50).to_string();
|
| 1716 |
-
let client = reqwest::Client::builder()
|
| 1717 |
-
.timeout(std::time::Duration::from_secs(15))
|
| 1718 |
-
.build()
|
| 1719 |
-
.unwrap();
|
| 1720 |
-
|
| 1721 |
-
let me = match api_deezer_get(&client, "/user/me", &token, &[]).await {
|
| 1722 |
-
Ok(v) => v,
|
| 1723 |
-
Err(e) => return json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 1724 |
-
};
|
| 1725 |
-
let uid = me.get("id").and_then(|x| x.as_i64()).unwrap_or(0);
|
| 1726 |
-
if uid <= 0 {
|
| 1727 |
-
return json_error(StatusCode::SERVICE_UNAVAILABLE, "api:no_user_id");
|
| 1728 |
-
}
|
| 1729 |
-
let path = format!("/user/{uid}/recommendations/playlists");
|
| 1730 |
-
let extra = [("index", index), ("limit", limit)];
|
| 1731 |
-
match api_deezer_get(&client, &path, &token, &extra).await {
|
| 1732 |
-
Ok(v) => (StatusCode::OK, Json(v)).into_response(),
|
| 1733 |
-
Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 1734 |
-
}
|
| 1735 |
-
}
|
| 1736 |
-
|
| 1737 |
-
async fn oauth_reco_albums(Json(req): Json<OauthRecoReq>) -> impl IntoResponse {
|
| 1738 |
-
let token = req.access_token.trim().to_string();
|
| 1739 |
-
if token.is_empty() {
|
| 1740 |
-
return json_error(StatusCode::BAD_REQUEST, "access_token required");
|
| 1741 |
-
}
|
| 1742 |
-
let index = req.index.unwrap_or(0).to_string();
|
| 1743 |
-
let limit = req.limit.unwrap_or(20).clamp(1, 50).to_string();
|
| 1744 |
-
let client = reqwest::Client::builder()
|
| 1745 |
-
.timeout(std::time::Duration::from_secs(15))
|
| 1746 |
-
.build()
|
| 1747 |
-
.unwrap();
|
| 1748 |
-
|
| 1749 |
-
let me = match api_deezer_get(&client, "/user/me", &token, &[]).await {
|
| 1750 |
-
Ok(v) => v,
|
| 1751 |
-
Err(e) => return json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 1752 |
-
};
|
| 1753 |
-
let uid = me.get("id").and_then(|x| x.as_i64()).unwrap_or(0);
|
| 1754 |
-
if uid <= 0 {
|
| 1755 |
-
return json_error(StatusCode::SERVICE_UNAVAILABLE, "api:no_user_id");
|
| 1756 |
-
}
|
| 1757 |
-
let path = format!("/user/{uid}/recommendations/albums");
|
| 1758 |
-
let extra = [("index", index), ("limit", limit)];
|
| 1759 |
-
match api_deezer_get(&client, &path, &token, &extra).await {
|
| 1760 |
-
Ok(v) => (StatusCode::OK, Json(v)).into_response(),
|
| 1761 |
-
Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 1762 |
-
}
|
| 1763 |
-
}
|
| 1764 |
-
|
| 1765 |
-
async fn oauth_reco_artists(Json(req): Json<OauthRecoReq>) -> impl IntoResponse {
|
| 1766 |
-
let token = req.access_token.trim().to_string();
|
| 1767 |
-
if token.is_empty() {
|
| 1768 |
-
return json_error(StatusCode::BAD_REQUEST, "access_token required");
|
| 1769 |
-
}
|
| 1770 |
-
let index = req.index.unwrap_or(0).to_string();
|
| 1771 |
-
let limit = req.limit.unwrap_or(20).clamp(1, 50).to_string();
|
| 1772 |
-
let client = reqwest::Client::builder()
|
| 1773 |
-
.timeout(std::time::Duration::from_secs(15))
|
| 1774 |
-
.build()
|
| 1775 |
-
.unwrap();
|
| 1776 |
-
|
| 1777 |
-
let me = match api_deezer_get(&client, "/user/me", &token, &[]).await {
|
| 1778 |
-
Ok(v) => v,
|
| 1779 |
-
Err(e) => return json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 1780 |
-
};
|
| 1781 |
-
let uid = me.get("id").and_then(|x| x.as_i64()).unwrap_or(0);
|
| 1782 |
-
if uid <= 0 {
|
| 1783 |
-
return json_error(StatusCode::SERVICE_UNAVAILABLE, "api:no_user_id");
|
| 1784 |
-
}
|
| 1785 |
-
let path = format!("/user/{uid}/recommendations/artists");
|
| 1786 |
-
let extra = [("index", index), ("limit", limit)];
|
| 1787 |
-
match api_deezer_get(&client, &path, &token, &extra).await {
|
| 1788 |
-
Ok(v) => (StatusCode::OK, Json(v)).into_response(),
|
| 1789 |
-
Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 1790 |
-
}
|
| 1791 |
-
}
|
| 1792 |
-
|
| 1793 |
-
async fn oauth_reco_tracks(Json(req): Json<OauthRecoReq>) -> impl IntoResponse {
|
| 1794 |
-
let token = req.access_token.trim().to_string();
|
| 1795 |
-
if token.is_empty() {
|
| 1796 |
-
return json_error(StatusCode::BAD_REQUEST, "access_token required");
|
| 1797 |
-
}
|
| 1798 |
-
let index = req.index.unwrap_or(0).to_string();
|
| 1799 |
-
let limit = req.limit.unwrap_or(40).clamp(1, 100).to_string();
|
| 1800 |
-
let client = reqwest::Client::builder()
|
| 1801 |
-
.timeout(std::time::Duration::from_secs(15))
|
| 1802 |
-
.build()
|
| 1803 |
-
.unwrap();
|
| 1804 |
-
|
| 1805 |
-
let me = match api_deezer_get(&client, "/user/me", &token, &[]).await {
|
| 1806 |
-
Ok(v) => v,
|
| 1807 |
-
Err(e) => return json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 1808 |
-
};
|
| 1809 |
-
let uid = me.get("id").and_then(|x| x.as_i64()).unwrap_or(0);
|
| 1810 |
-
if uid <= 0 {
|
| 1811 |
-
return json_error(StatusCode::SERVICE_UNAVAILABLE, "api:no_user_id");
|
| 1812 |
-
}
|
| 1813 |
-
let path = format!("/user/{uid}/recommendations/tracks");
|
| 1814 |
-
let extra = [("index", index), ("limit", limit)];
|
| 1815 |
-
match api_deezer_get(&client, &path, &token, &extra).await {
|
| 1816 |
-
Ok(v) => (StatusCode::OK, Json(v)).into_response(),
|
| 1817 |
-
Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 1818 |
-
}
|
| 1819 |
-
}
|
| 1820 |
-
|
| 1821 |
-
#[derive(Debug, Deserialize)]
|
| 1822 |
-
struct OauthHistoryReq {
|
| 1823 |
-
access_token: String,
|
| 1824 |
-
index: Option<u32>,
|
| 1825 |
-
limit: Option<u32>,
|
| 1826 |
-
}
|
| 1827 |
-
|
| 1828 |
-
async fn oauth_history(Json(req): Json<OauthHistoryReq>) -> impl IntoResponse {
|
| 1829 |
-
let token = req.access_token.trim().to_string();
|
| 1830 |
-
if token.is_empty() {
|
| 1831 |
-
return json_error(StatusCode::BAD_REQUEST, "access_token required");
|
| 1832 |
-
}
|
| 1833 |
-
let index = req.index.unwrap_or(0).to_string();
|
| 1834 |
-
let limit = req.limit.unwrap_or(50).clamp(1, 100).to_string();
|
| 1835 |
-
let client = reqwest::Client::builder()
|
| 1836 |
-
.timeout(std::time::Duration::from_secs(15))
|
| 1837 |
-
.build()
|
| 1838 |
-
.unwrap();
|
| 1839 |
-
|
| 1840 |
-
let me = match api_deezer_get(&client, "/user/me", &token, &[]).await {
|
| 1841 |
-
Ok(v) => v,
|
| 1842 |
-
Err(e) => return json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 1843 |
-
};
|
| 1844 |
-
let uid = me.get("id").and_then(|x| x.as_i64()).unwrap_or(0);
|
| 1845 |
-
if uid <= 0 {
|
| 1846 |
-
return json_error(StatusCode::SERVICE_UNAVAILABLE, "api:no_user_id");
|
| 1847 |
-
}
|
| 1848 |
-
let path = format!("/user/{uid}/history");
|
| 1849 |
-
let extra = [("index", index), ("limit", limit)];
|
| 1850 |
-
match api_deezer_get(&client, &path, &token, &extra).await {
|
| 1851 |
-
Ok(v) => (StatusCode::OK, Json(v)).into_response(),
|
| 1852 |
-
Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 1853 |
-
}
|
| 1854 |
-
}
|
| 1855 |
-
|
| 1856 |
#[tokio::main]
|
| 1857 |
async fn main() {
|
| 1858 |
let bind_addr = std::env::var("BIND_ADDR").unwrap_or("[::]".to_string());
|
|
@@ -1891,11 +1740,6 @@ async fn main() {
|
|
| 1891 |
.route("/oauth/playlist_tracks", post(oauth_playlist_tracks))
|
| 1892 |
.route("/oauth/arl", post(oauth_arl))
|
| 1893 |
.route("/oauth/flow", post(oauth_flow))
|
| 1894 |
-
.route("/oauth/reco_playlists", post(oauth_reco_playlists))
|
| 1895 |
-
.route("/oauth/reco_albums", post(oauth_reco_albums))
|
| 1896 |
-
.route("/oauth/reco_artists", post(oauth_reco_artists))
|
| 1897 |
-
.route("/oauth/reco_tracks", post(oauth_reco_tracks))
|
| 1898 |
-
.route("/oauth/history", post(oauth_history))
|
| 1899 |
.with_state(state)
|
| 1900 |
.layer(cors)
|
| 1901 |
.layer(CompressionLayer::new())
|
|
|
|
| 1008 |
("cid", cid.as_str()),
|
| 1009 |
])
|
| 1010 |
.header(ACCEPT, "*/*")
|
| 1011 |
+
.header("Cache-Control", "max-age=0")
|
| 1012 |
+
.header("Connection", "keep-alive")
|
| 1013 |
.header("Origin", "https://www.deezer.com")
|
| 1014 |
.header("Referer", "https://www.deezer.com/")
|
| 1015 |
.header("Sec-Fetch-Site", "same-origin")
|
|
|
|
| 1017 |
.header("Sec-Fetch-Dest", "empty")
|
| 1018 |
.header("X-Requested-With", "XMLHttpRequest")
|
| 1019 |
.header("Accept-Language", "en-US,en;q=0.9")
|
| 1020 |
+
.header("Content-Language", "en-US")
|
| 1021 |
+
.header("X-User-IP", "1.1.1.1")
|
| 1022 |
+
.header("x-deezer-client-ip", "1.1.1.1")
|
| 1023 |
.header(
|
| 1024 |
"User-Agent",
|
| 1025 |
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36",
|
|
|
|
| 1393 |
Err(e) => oauth_err = Some(e),
|
| 1394 |
}
|
| 1395 |
|
| 1396 |
+
if let Ok(ud) = gw_light_call(&client, &jar, "deezer.getUserData", "null", json!({})).await {
|
| 1397 |
+
let token = ud["checkForm"].as_str().unwrap_or("").to_string();
|
| 1398 |
+
if !token.is_empty() {
|
| 1399 |
+
if let Err(e) = gw_light_call(
|
|
|
|
|
|
|
| 1400 |
&client,
|
| 1401 |
&jar,
|
| 1402 |
"user.checkCredentials",
|
|
|
|
| 1409 |
)
|
| 1410 |
.await
|
| 1411 |
{
|
|
|
|
| 1412 |
if access_token_out.is_none() {
|
|
|
|
| 1413 |
let mut map = state.pair.write().await;
|
| 1414 |
if let Some(s) = map.get_mut(&code) {
|
| 1415 |
+
s.error = Some(format!("gw:checkCredentials:{e}"));
|
| 1416 |
}
|
| 1417 |
+
return Html(format!(
|
| 1418 |
+
"<h3>Ошибка входа</h3><pre>{}</pre>",
|
| 1419 |
+
htmlesc(&format!("gw:checkCredentials:{e}"))
|
| 1420 |
+
))
|
| 1421 |
+
.into_response();
|
| 1422 |
}
|
| 1423 |
+
gw_err = Some(format!("gw:checkCredentials:{e}"));
|
| 1424 |
} else {
|
| 1425 |
gw_token = Some(token.clone());
|
| 1426 |
gw_uid = ud["USER"]["USER_ID"]
|
|
|
|
| 1437 |
}
|
| 1438 |
}
|
| 1439 |
}
|
|
|
|
|
|
|
|
|
|
| 1440 |
}
|
| 1441 |
|
| 1442 |
if gw_token.is_none() && access_token_out.is_none() {
|
|
|
|
| 1702 |
}
|
| 1703 |
}
|
| 1704 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1705 |
#[tokio::main]
|
| 1706 |
async fn main() {
|
| 1707 |
let bind_addr = std::env::var("BIND_ADDR").unwrap_or("[::]".to_string());
|
|
|
|
| 1740 |
.route("/oauth/playlist_tracks", post(oauth_playlist_tracks))
|
| 1741 |
.route("/oauth/arl", post(oauth_arl))
|
| 1742 |
.route("/oauth/flow", post(oauth_flow))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1743 |
.with_state(state)
|
| 1744 |
.layer(cors)
|
| 1745 |
.layer(CompressionLayer::new())
|