recycleactor commited on
Commit
2d79e80
·
verified ·
1 Parent(s): a85c8b6

Upload 2 files

Browse files
Files changed (1) hide show
  1. src/main.rs +181 -116
src/main.rs CHANGED
@@ -10,7 +10,7 @@ use http::{Method, header::CONTENT_TYPE};
10
  use serde_json::json;
11
  use serde::Deserialize;
12
  use std::collections::HashMap;
13
- use std::sync::{Arc, RwLock};
14
  use bytes::Bytes;
15
  use futures_util::StreamExt;
16
  use axum::body::Body;
@@ -22,6 +22,7 @@ use reqwest::{cookie::Jar, Url};
22
  use reqwest::cookie::CookieStore;
23
  use reqwest::header::ACCEPT;
24
  use std::time::{SystemTime, UNIX_EPOCH};
 
25
 
26
  type BoxErr = Box<dyn std::error::Error + Send + Sync + 'static>;
27
 
@@ -30,7 +31,8 @@ use api::{APIClient, APIError, Format};
30
 
31
  #[derive(Clone)]
32
  struct AppState {
33
- api: Arc<RwLock<APIClient>>,
 
34
  pair: Arc<RwLock<HashMap<String, PairSession>>>,
35
  }
36
 
@@ -38,6 +40,23 @@ fn json_error(status: StatusCode, message: impl Into<String>) -> axum::response:
38
  (status, Json(json!({ "error": message.into() }))).into_response()
39
  }
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  #[derive(Deserialize)]
42
  struct DeezerTrackList {
43
  data: Vec<DeezerTrack>
@@ -68,38 +87,36 @@ async fn get_url(State(state): State<AppState>, Json(req): Json<RequestParams>)
68
  return (StatusCode::BAD_REQUEST, "ID list cannot be empty".to_string());
69
  }
70
 
71
- let mut client = if let Some(arl) = req.arl.clone().filter(|s| !s.trim().is_empty()) {
72
- APIClient::new_with_arl(arl)
73
- } else {
74
- state.api.read().unwrap().clone()
75
- };
76
- let old_license = client.license_token.clone();
77
-
78
- let resp: Result<DeezerTrackList, APIError> = client.api_call("song.getListData", &json!({"sng_ids":req.ids,"array_default":["SNG_ID","TRACK_TOKEN"]})).await;
79
- let track_list;
80
- match resp {
81
- Ok(t) => track_list = t,
82
- Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
83
- };
84
 
85
- if track_list.data.is_empty() {
86
- return (StatusCode::BAD_REQUEST, "No valid IDs found".to_string());
87
- }
88
 
89
- let track_tokens: Vec<&str> = track_list.data.iter().map(|t| t.TRACK_TOKEN.as_str()).collect();
 
 
 
 
90
 
91
- let media_result = client.get_media(&req.formats, track_tokens).await;
92
- let media_resp;
93
- match media_result {
94
- Ok(r) => media_resp = r,
95
- Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "Error while getting response from media.deezer.com".to_string()),
96
  };
97
 
98
- if req.arl.is_none() && client.license_token != old_license {
99
- let mut client_write = state.api.write().unwrap();
100
- *client_write = client;
101
- }
102
-
103
  (StatusCode::OK, media_resp.text().await.unwrap())
104
  }
105
 
@@ -183,47 +200,74 @@ async fn stream(State(state): State<AppState>, Query(q): Query<StreamParams>) ->
183
  "AUTO" | _ => vec![Format::FLAC, Format::MP3_320, Format::MP3_128],
184
  };
185
 
186
- let mut client = if let Some(arl) = q.arl.clone().filter(|s| !s.trim().is_empty()) {
187
- APIClient::new_with_arl(arl)
188
- } else {
189
- state.api.read().unwrap().clone()
190
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
- let resp: Result<DeezerTrackList, APIError> = client
193
- .api_call(
194
- "song.getListData",
195
- &json!({"sng_ids":[q.id],"array_default":["SNG_ID","TRACK_TOKEN"]}),
196
- )
197
- .await;
 
 
 
198
 
199
- let track_list = match resp {
200
- Ok(t) => t,
201
- Err(e) => return (StatusCode::BAD_GATEWAY, e.to_string()).into_response(),
202
- };
203
 
204
- if track_list.data.is_empty() {
205
- return (StatusCode::BAD_REQUEST, "No valid ID".to_string()).into_response();
206
- }
207
 
208
- let track_token = track_list.data[0].TRACK_TOKEN.as_str();
209
- let media_resp = match client.get_media(&formats, vec![track_token]).await {
210
- Ok(r) => r,
211
- Err(e) => return (StatusCode::BAD_GATEWAY, e.to_string()).into_response(),
212
- };
213
 
214
- let media_json: serde_json::Value = match media_resp.json().await {
215
- Ok(v) => v,
216
- Err(_) => return (StatusCode::BAD_GATEWAY, "Bad media response".to_string()).into_response(),
217
- };
 
 
 
218
 
219
- let url = media_json["data"][0]["media"][0]["sources"][0]["url"]
220
- .as_str()
221
- .unwrap_or("")
222
- .to_string();
223
 
224
- if url.is_empty() {
225
- return (StatusCode::BAD_GATEWAY, "No url in media response".to_string()).into_response();
226
- }
 
 
 
 
 
 
227
 
228
  let http = reqwest::Client::builder()
229
  .timeout(std::time::Duration::from_secs(60))
@@ -232,11 +276,18 @@ async fn stream(State(state): State<AppState>, Query(q): Query<StreamParams>) ->
232
 
233
  let upstream = match http.get(url).send().await {
234
  Ok(r) => r,
235
- Err(_) => return (StatusCode::BAD_GATEWAY, "Upstream request failed".to_string()).into_response(),
 
 
 
236
  };
237
 
238
  if !upstream.status().is_success() {
239
- return (StatusCode::BAD_GATEWAY, "Upstream status not OK".to_string()).into_response();
 
 
 
 
240
  }
241
 
242
  let key = blowfish_key(q.id);
@@ -281,16 +332,19 @@ struct UserDataReq {
281
  arl: String,
282
  }
283
 
284
- async fn user_data(Json(req): Json<UserDataReq>) -> impl IntoResponse {
285
  let arl = req.arl.trim().to_string();
286
  if arl.is_empty() {
287
  return json_error(StatusCode::BAD_REQUEST, "ARL required");
288
  }
289
 
290
- let mut client = APIClient::new_with_arl(arl);
291
- let data = match client.user_data().await {
292
- Ok(v) => v,
293
- Err(e) => return json_error(StatusCode::BAD_GATEWAY, e.to_string()),
 
 
 
294
  };
295
 
296
  let token = data["checkForm"].as_str().unwrap_or("").to_string();
@@ -306,33 +360,37 @@ struct PlaylistsReq {
306
  nb: Option<u32>,
307
  }
308
 
309
- async fn playlists(Json(req): Json<PlaylistsReq>) -> impl IntoResponse {
310
  let arl = req.arl.trim().to_string();
311
  if arl.is_empty() {
312
  return json_error(StatusCode::BAD_REQUEST, "ARL required");
313
  }
314
 
315
- let mut client = APIClient::new_with_arl(arl);
316
- let ud = match client.user_data().await {
317
- Ok(v) => v,
318
- Err(e) => return json_error(StatusCode::BAD_GATEWAY, e.to_string()),
319
- };
 
 
320
 
321
- let uid = ud["USER"]["USER_ID"].as_i64().unwrap_or(0);
322
- if uid <= 0 {
323
- return json_error(StatusCode::BAD_GATEWAY, "No USER_ID");
324
- }
325
 
326
- let start = req.start.unwrap_or(0);
327
- let nb = req.nb.unwrap_or(50);
328
 
329
- let res: Result<serde_json::Value, APIError> = client
330
- .api_call("playlist.getList", &json!({"user_id":uid,"nb":nb,"start":start}))
331
- .await;
 
 
332
 
333
  match res {
334
  Ok(v) => (StatusCode::OK, Json(v)).into_response(),
335
- Err(e) => json_error(StatusCode::BAD_GATEWAY, e.to_string()),
336
  }
337
  }
338
 
@@ -344,32 +402,38 @@ struct PlaylistTracksReq {
344
  nb: Option<u32>,
345
  }
346
 
347
- async fn playlist_tracks(Json(req): Json<PlaylistTracksReq>) -> impl IntoResponse {
 
 
 
348
  let arl = req.arl.trim().to_string();
349
  if arl.is_empty() {
350
  return json_error(StatusCode::BAD_REQUEST, "ARL required");
351
  }
352
 
353
- let mut client = APIClient::new_with_arl(arl);
354
- let _ = client.user_data().await;
355
 
356
  let start = req.start.unwrap_or(0);
357
  let nb = req.nb.unwrap_or(100);
358
 
359
- let res: Result<serde_json::Value, APIError> = client
360
- .api_call(
361
- "playlist.getSongs",
362
- &json!({
363
- "playlist_id": req.playlist_id,
364
- "start": start,
365
- "nb": nb
366
- }),
367
- )
368
- .await;
 
 
 
 
369
 
370
  match res {
371
  Ok(v) => (StatusCode::OK, Json(v)).into_response(),
372
- Err(e) => json_error(StatusCode::BAD_GATEWAY, e.to_string()),
373
  }
374
  }
375
 
@@ -660,7 +724,7 @@ async fn pair_start(State(state): State<AppState>) -> impl IntoResponse {
660
  .map(|d| d.as_millis())
661
  .unwrap_or(0);
662
  {
663
- let mut map = state.pair.write().unwrap();
664
  map.insert(
665
  code.clone(),
666
  PairSession {
@@ -682,7 +746,7 @@ async fn pair_status(State(state): State<AppState>, Query(q): Query<PairStatusQu
682
  return json_error(StatusCode::BAD_REQUEST, "code required");
683
  }
684
 
685
- let map = state.pair.read().unwrap();
686
  let Some(sess) = map.get(&code) else {
687
  return json_error(StatusCode::NOT_FOUND, "no such code");
688
  };
@@ -794,7 +858,7 @@ async fn pair_complete(State(state): State<AppState>, Form(f): Form<PairComplete
794
  }
795
 
796
  {
797
- let map = state.pair.read().unwrap();
798
  if !map.contains_key(&code) {
799
  return Html("<h3>Код не найден или истёк</h3>".to_string()).into_response();
800
  }
@@ -813,7 +877,7 @@ async fn pair_complete(State(state): State<AppState>, Form(f): Form<PairComplete
813
  let access_token = match oauth_access_token(&client, &email, &pass_md5).await {
814
  Ok(t) => t,
815
  Err(e) => {
816
- let mut map = state.pair.write().unwrap();
817
  if let Some(s) = map.get_mut(&code) {
818
  s.error = Some(e.clone());
819
  }
@@ -830,7 +894,7 @@ async fn pair_complete(State(state): State<AppState>, Form(f): Form<PairComplete
830
  let me = match api_deezer_get(&client, "/user/me", &access_token, &[]).await {
831
  Ok(v) => v,
832
  Err(e) => {
833
- let mut map = state.pair.write().unwrap();
834
  if let Some(s) = map.get_mut(&code) {
835
  s.error = Some(e.clone());
836
  }
@@ -876,7 +940,7 @@ async fn pair_complete(State(state): State<AppState>, Form(f): Form<PairComplete
876
  }
877
 
878
  {
879
- let mut map = state.pair.write().unwrap();
880
  if let Some(s) = map.get_mut(&code) {
881
  s.access_token = Some(access_token);
882
  s.user_id = uid;
@@ -905,7 +969,7 @@ async fn oauth_me(Json(req): Json<OauthMeReq>) -> impl IntoResponse {
905
  .unwrap();
906
  match api_deezer_get(&client, "/user/me", &token, &[]).await {
907
  Ok(v) => (StatusCode::OK, Json(v)).into_response(),
908
- Err(e) => json_error(StatusCode::BAD_GATEWAY, e),
909
  }
910
  }
911
 
@@ -929,17 +993,17 @@ async fn oauth_playlists(Json(req): Json<OauthPlaylistsReq>) -> impl IntoRespons
929
  .unwrap();
930
  let me = match api_deezer_get(&client, "/user/me", &token, &[]).await {
931
  Ok(v) => v,
932
- Err(e) => return json_error(StatusCode::BAD_GATEWAY, e),
933
  };
934
  let uid = me.get("id").and_then(|x| x.as_i64()).unwrap_or(0);
935
  if uid <= 0 {
936
- return json_error(StatusCode::BAD_GATEWAY, "api:no_user_id");
937
  }
938
  let path = format!("/user/{uid}/playlists");
939
  let extra = [("index", index), ("limit", limit)];
940
  match api_deezer_get(&client, &path, &token, &extra).await {
941
  Ok(v) => (StatusCode::OK, Json(v)).into_response(),
942
- Err(e) => json_error(StatusCode::BAD_GATEWAY, e),
943
  }
944
  }
945
 
@@ -969,7 +1033,7 @@ async fn oauth_playlist_tracks(Json(req): Json<OauthPlaylistTracksReq>) -> impl
969
  let extra = [("index", index), ("limit", limit)];
970
  match api_deezer_get(&client, &path, &token, &extra).await {
971
  Ok(v) => (StatusCode::OK, Json(v)).into_response(),
972
- Err(e) => json_error(StatusCode::BAD_GATEWAY, e),
973
  }
974
  }
975
 
@@ -1001,21 +1065,21 @@ async fn oauth_arl(Json(req): Json<OauthArlReq>) -> impl IntoResponse {
1001
 
1002
  let ud = match gw_light_call(&client, "deezer.getUserData", "null", json!({})).await {
1003
  Ok(v) => v,
1004
- Err(e) => return json_error(StatusCode::BAD_GATEWAY, e),
1005
  };
1006
 
1007
  let check_form = ud["checkForm"].as_str().unwrap_or("").to_string();
1008
  if check_form.is_empty() {
1009
- return json_error(StatusCode::BAD_GATEWAY, "no checkForm");
1010
  }
1011
 
1012
  let arl_v = match gw_light_call(&client, "user.getArl", &check_form, json!({})).await {
1013
  Ok(v) => v,
1014
- Err(e) => return json_error(StatusCode::BAD_GATEWAY, e),
1015
  };
1016
  let arl = arl_v.as_str().unwrap_or("").to_string();
1017
  if arl.len() < 20 {
1018
- return json_error(StatusCode::BAD_GATEWAY, "no arl");
1019
  }
1020
 
1021
  (StatusCode::OK, Json(json!({ "arl": arl }))).into_response()
@@ -1028,7 +1092,8 @@ async fn main() {
1028
  let port: u16 = port.parse().unwrap_or(8000);
1029
 
1030
  let state = AppState {
1031
- api: Arc::new(RwLock::new(APIClient::new())),
 
1032
  pair: Arc::new(RwLock::new(HashMap::new())),
1033
  };
1034
 
 
10
  use serde_json::json;
11
  use serde::Deserialize;
12
  use std::collections::HashMap;
13
+ use std::sync::Arc;
14
  use bytes::Bytes;
15
  use futures_util::StreamExt;
16
  use axum::body::Body;
 
22
  use reqwest::cookie::CookieStore;
23
  use reqwest::header::ACCEPT;
24
  use std::time::{SystemTime, UNIX_EPOCH};
25
+ use tokio::sync::{Mutex, RwLock};
26
 
27
  type BoxErr = Box<dyn std::error::Error + Send + Sync + 'static>;
28
 
 
31
 
32
  #[derive(Clone)]
33
  struct AppState {
34
+ api: Arc<Mutex<APIClient>>,
35
+ api_by_arl: Arc<RwLock<HashMap<String, Arc<Mutex<APIClient>>>>>,
36
  pair: Arc<RwLock<HashMap<String, PairSession>>>,
37
  }
38
 
 
40
  (status, Json(json!({ "error": message.into() }))).into_response()
41
  }
42
 
43
+ async fn api_client_for_arl(state: &AppState, arl: Option<String>) -> Arc<Mutex<APIClient>> {
44
+ let Some(arl) = arl.map(|s| s.trim().to_string()).filter(|s| !s.is_empty()) else {
45
+ return state.api.clone();
46
+ };
47
+
48
+ let mut map = state.api_by_arl.write().await;
49
+ if let Some(c) = map.get(&arl) {
50
+ return c.clone();
51
+ }
52
+ if map.len() >= 32 {
53
+ map.clear();
54
+ }
55
+ let c = Arc::new(Mutex::new(APIClient::new_with_arl(arl.clone())));
56
+ map.insert(arl, c.clone());
57
+ c
58
+ }
59
+
60
  #[derive(Deserialize)]
61
  struct DeezerTrackList {
62
  data: Vec<DeezerTrack>
 
87
  return (StatusCode::BAD_REQUEST, "ID list cannot be empty".to_string());
88
  }
89
 
90
+ let client = api_client_for_arl(&state, req.arl.clone()).await;
91
+ let media_resp = {
92
+ let mut client = client.lock().await;
93
+ let resp: Result<DeezerTrackList, APIError> = client
94
+ .api_call(
95
+ "song.getListData",
96
+ &json!({"sng_ids":req.ids,"array_default":["SNG_ID","TRACK_TOKEN"]}),
97
+ )
98
+ .await;
99
+ let track_list = match resp {
100
+ Ok(t) => t,
101
+ Err(e) => return (StatusCode::SERVICE_UNAVAILABLE, e.to_string()),
102
+ };
103
 
104
+ if track_list.data.is_empty() {
105
+ return (StatusCode::BAD_REQUEST, "No valid IDs found".to_string());
106
+ }
107
 
108
+ let track_tokens: Vec<&str> = track_list
109
+ .data
110
+ .iter()
111
+ .map(|t| t.TRACK_TOKEN.as_str())
112
+ .collect();
113
 
114
+ match client.get_media(&req.formats, track_tokens).await {
115
+ Ok(r) => r,
116
+ Err(e) => return (StatusCode::SERVICE_UNAVAILABLE, e.to_string()),
117
+ }
 
118
  };
119
 
 
 
 
 
 
120
  (StatusCode::OK, media_resp.text().await.unwrap())
121
  }
122
 
 
200
  "AUTO" | _ => vec![Format::FLAC, Format::MP3_320, Format::MP3_128],
201
  };
202
 
203
+ fn extract_media_url(media_json: &serde_json::Value) -> String {
204
+ let data = media_json.get("data").and_then(|v| v.as_array());
205
+ let Some(data0) = data.and_then(|a| a.get(0)) else {
206
+ return String::new();
207
+ };
208
+ let media_arr = data0.get("media").and_then(|v| v.as_array());
209
+ let Some(media_arr) = media_arr else {
210
+ return String::new();
211
+ };
212
+ for m in media_arr {
213
+ if let Some(sources) = m.get("sources").and_then(|v| v.as_array()) {
214
+ for s in sources {
215
+ if let Some(url) = s.get("url").and_then(|v| v.as_str()) {
216
+ let url = url.trim();
217
+ if !url.is_empty() {
218
+ return url.to_string();
219
+ }
220
+ }
221
+ }
222
+ }
223
+ }
224
+ String::new()
225
+ }
226
 
227
+ let client = api_client_for_arl(&state, q.arl.clone()).await;
228
+ let url = {
229
+ let mut client = client.lock().await;
230
+ let resp: Result<DeezerTrackList, APIError> = client
231
+ .api_call(
232
+ "song.getListData",
233
+ &json!({"sng_ids":[q.id],"array_default":["SNG_ID","TRACK_TOKEN"]}),
234
+ )
235
+ .await;
236
 
237
+ let track_list = match resp {
238
+ Ok(t) => t,
239
+ Err(e) => return (StatusCode::SERVICE_UNAVAILABLE, e.to_string()).into_response(),
240
+ };
241
 
242
+ if track_list.data.is_empty() {
243
+ return (StatusCode::BAD_REQUEST, "No valid ID".to_string()).into_response();
244
+ }
245
 
246
+ let track_token = track_list.data[0].TRACK_TOKEN.as_str();
247
+ let media_resp = match client.get_media(&formats, vec![track_token]).await {
248
+ Ok(r) => r,
249
+ Err(e) => return (StatusCode::SERVICE_UNAVAILABLE, e.to_string()).into_response(),
250
+ };
251
 
252
+ let media_json: serde_json::Value = match media_resp.json().await {
253
+ Ok(v) => v,
254
+ Err(_) => {
255
+ return (StatusCode::SERVICE_UNAVAILABLE, "Bad media response".to_string())
256
+ .into_response()
257
+ }
258
+ };
259
 
260
+ let url = extract_media_url(&media_json);
 
 
 
261
 
262
+ if url.is_empty() {
263
+ return (
264
+ StatusCode::SERVICE_UNAVAILABLE,
265
+ "No url in media response".to_string(),
266
+ )
267
+ .into_response();
268
+ }
269
+ url
270
+ };
271
 
272
  let http = reqwest::Client::builder()
273
  .timeout(std::time::Duration::from_secs(60))
 
276
 
277
  let upstream = match http.get(url).send().await {
278
  Ok(r) => r,
279
+ Err(_) => {
280
+ return (StatusCode::SERVICE_UNAVAILABLE, "Upstream request failed".to_string())
281
+ .into_response()
282
+ }
283
  };
284
 
285
  if !upstream.status().is_success() {
286
+ return (
287
+ StatusCode::SERVICE_UNAVAILABLE,
288
+ "Upstream status not OK".to_string(),
289
+ )
290
+ .into_response();
291
  }
292
 
293
  let key = blowfish_key(q.id);
 
332
  arl: String,
333
  }
334
 
335
+ async fn user_data(State(state): State<AppState>, Json(req): Json<UserDataReq>) -> impl IntoResponse {
336
  let arl = req.arl.trim().to_string();
337
  if arl.is_empty() {
338
  return json_error(StatusCode::BAD_REQUEST, "ARL required");
339
  }
340
 
341
+ let client = api_client_for_arl(&state, Some(arl)).await;
342
+ let data = {
343
+ let mut client = client.lock().await;
344
+ match client.user_data().await {
345
+ Ok(v) => v,
346
+ Err(e) => return json_error(StatusCode::SERVICE_UNAVAILABLE, e.to_string()),
347
+ }
348
  };
349
 
350
  let token = data["checkForm"].as_str().unwrap_or("").to_string();
 
360
  nb: Option<u32>,
361
  }
362
 
363
+ async fn playlists(State(state): State<AppState>, Json(req): Json<PlaylistsReq>) -> impl IntoResponse {
364
  let arl = req.arl.trim().to_string();
365
  if arl.is_empty() {
366
  return json_error(StatusCode::BAD_REQUEST, "ARL required");
367
  }
368
 
369
+ let client = api_client_for_arl(&state, Some(arl)).await;
370
+ let res = {
371
+ let mut client = client.lock().await;
372
+ let ud = match client.user_data().await {
373
+ Ok(v) => v,
374
+ Err(e) => return json_error(StatusCode::SERVICE_UNAVAILABLE, e.to_string()),
375
+ };
376
 
377
+ let uid = ud["USER"]["USER_ID"].as_i64().unwrap_or(0);
378
+ if uid <= 0 {
379
+ return json_error(StatusCode::SERVICE_UNAVAILABLE, "No USER_ID");
380
+ }
381
 
382
+ let start = req.start.unwrap_or(0);
383
+ let nb = req.nb.unwrap_or(50);
384
 
385
+ let res: Result<serde_json::Value, APIError> = client
386
+ .api_call("playlist.getList", &json!({"user_id":uid,"nb":nb,"start":start}))
387
+ .await;
388
+ res
389
+ };
390
 
391
  match res {
392
  Ok(v) => (StatusCode::OK, Json(v)).into_response(),
393
+ Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e.to_string()),
394
  }
395
  }
396
 
 
402
  nb: Option<u32>,
403
  }
404
 
405
+ async fn playlist_tracks(
406
+ State(state): State<AppState>,
407
+ Json(req): Json<PlaylistTracksReq>,
408
+ ) -> impl IntoResponse {
409
  let arl = req.arl.trim().to_string();
410
  if arl.is_empty() {
411
  return json_error(StatusCode::BAD_REQUEST, "ARL required");
412
  }
413
 
414
+ let client = api_client_for_arl(&state, Some(arl)).await;
 
415
 
416
  let start = req.start.unwrap_or(0);
417
  let nb = req.nb.unwrap_or(100);
418
 
419
+ let res: Result<serde_json::Value, APIError> = {
420
+ let mut client = client.lock().await;
421
+ let _ = client.user_data().await;
422
+ client
423
+ .api_call(
424
+ "playlist.getSongs",
425
+ &json!({
426
+ "playlist_id": req.playlist_id,
427
+ "start": start,
428
+ "nb": nb
429
+ }),
430
+ )
431
+ .await
432
+ };
433
 
434
  match res {
435
  Ok(v) => (StatusCode::OK, Json(v)).into_response(),
436
+ Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e.to_string()),
437
  }
438
  }
439
 
 
724
  .map(|d| d.as_millis())
725
  .unwrap_or(0);
726
  {
727
+ let mut map = state.pair.write().await;
728
  map.insert(
729
  code.clone(),
730
  PairSession {
 
746
  return json_error(StatusCode::BAD_REQUEST, "code required");
747
  }
748
 
749
+ let map = state.pair.read().await;
750
  let Some(sess) = map.get(&code) else {
751
  return json_error(StatusCode::NOT_FOUND, "no such code");
752
  };
 
858
  }
859
 
860
  {
861
+ let map = state.pair.read().await;
862
  if !map.contains_key(&code) {
863
  return Html("<h3>Код не найден или истёк</h3>".to_string()).into_response();
864
  }
 
877
  let access_token = match oauth_access_token(&client, &email, &pass_md5).await {
878
  Ok(t) => t,
879
  Err(e) => {
880
+ let mut map = state.pair.write().await;
881
  if let Some(s) = map.get_mut(&code) {
882
  s.error = Some(e.clone());
883
  }
 
894
  let me = match api_deezer_get(&client, "/user/me", &access_token, &[]).await {
895
  Ok(v) => v,
896
  Err(e) => {
897
+ let mut map = state.pair.write().await;
898
  if let Some(s) = map.get_mut(&code) {
899
  s.error = Some(e.clone());
900
  }
 
940
  }
941
 
942
  {
943
+ let mut map = state.pair.write().await;
944
  if let Some(s) = map.get_mut(&code) {
945
  s.access_token = Some(access_token);
946
  s.user_id = uid;
 
969
  .unwrap();
970
  match api_deezer_get(&client, "/user/me", &token, &[]).await {
971
  Ok(v) => (StatusCode::OK, Json(v)).into_response(),
972
+ Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e),
973
  }
974
  }
975
 
 
993
  .unwrap();
994
  let me = match api_deezer_get(&client, "/user/me", &token, &[]).await {
995
  Ok(v) => v,
996
+ Err(e) => return json_error(StatusCode::SERVICE_UNAVAILABLE, e),
997
  };
998
  let uid = me.get("id").and_then(|x| x.as_i64()).unwrap_or(0);
999
  if uid <= 0 {
1000
+ return json_error(StatusCode::SERVICE_UNAVAILABLE, "api:no_user_id");
1001
  }
1002
  let path = format!("/user/{uid}/playlists");
1003
  let extra = [("index", index), ("limit", limit)];
1004
  match api_deezer_get(&client, &path, &token, &extra).await {
1005
  Ok(v) => (StatusCode::OK, Json(v)).into_response(),
1006
+ Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e),
1007
  }
1008
  }
1009
 
 
1033
  let extra = [("index", index), ("limit", limit)];
1034
  match api_deezer_get(&client, &path, &token, &extra).await {
1035
  Ok(v) => (StatusCode::OK, Json(v)).into_response(),
1036
+ Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e),
1037
  }
1038
  }
1039
 
 
1065
 
1066
  let ud = match gw_light_call(&client, "deezer.getUserData", "null", json!({})).await {
1067
  Ok(v) => v,
1068
+ Err(e) => return json_error(StatusCode::SERVICE_UNAVAILABLE, e),
1069
  };
1070
 
1071
  let check_form = ud["checkForm"].as_str().unwrap_or("").to_string();
1072
  if check_form.is_empty() {
1073
+ return json_error(StatusCode::SERVICE_UNAVAILABLE, "no checkForm");
1074
  }
1075
 
1076
  let arl_v = match gw_light_call(&client, "user.getArl", &check_form, json!({})).await {
1077
  Ok(v) => v,
1078
+ Err(e) => return json_error(StatusCode::SERVICE_UNAVAILABLE, e),
1079
  };
1080
  let arl = arl_v.as_str().unwrap_or("").to_string();
1081
  if arl.len() < 20 {
1082
+ return json_error(StatusCode::SERVICE_UNAVAILABLE, "no arl");
1083
  }
1084
 
1085
  (StatusCode::OK, Json(json!({ "arl": arl }))).into_response()
 
1092
  let port: u16 = port.parse().unwrap_or(8000);
1093
 
1094
  let state = AppState {
1095
+ api: Arc::new(Mutex::new(APIClient::new())),
1096
+ api_by_arl: Arc::new(RwLock::new(HashMap::new())),
1097
  pair: Arc::new(RwLock::new(HashMap::new())),
1098
  };
1099