Skip to main content

ncm_api_rs/api/
song_url_v1_302.rs

1use super::Query;
2use crate::error::Result;
3/// 获取客户端歌曲下载链接 - v1 (302 重定向)
4/// 对应 Node.js module/song_url_v1_302.js
5use crate::request::{ApiClient, ApiResponse, CryptoType};
6use serde_json::json;
7
8impl ApiClient {
9    /// 获取客户端歌曲下载链接 (302 重定向)
10    /// 对应 /song/url/v1/302
11    ///
12    /// 先尝试 download/url/v1,若无 url 则 fallback 到 player/url/v1,
13    /// 最终返回带有 redirectUrl 的 302 响应。
14    pub async fn song_url_v1_302(&self, query: &Query) -> Result<ApiResponse> {
15        let id = query.get_or("id", "0");
16        let level = query.get_or("level", "standard");
17
18        // 第一次请求: download url
19        let data = json!({
20            "id": &id,
21            "immerseType": "c51",
22            "level": &level,
23        });
24        let response = self
25            .request(
26                "/api/song/enhance/download/url/v1",
27                data,
28                query.to_option(CryptoType::default()),
29            )
30            .await?;
31
32        // 检查第一次请求是否有 url
33        let url = response
34            .body
35            .get("data")
36            .and_then(|d| d.get(0))
37            .and_then(|item| item.get("url"))
38            .and_then(|u| u.as_str())
39            .map(|s| s.to_string());
40
41        if let Some(url) = url {
42            return Ok(ApiResponse {
43                status: 302,
44                body: json!({ "redirectUrl": url }),
45                cookie: response.cookie,
46            });
47        }
48
49        // Fallback: player url v1
50        let mut fallback_data = json!({
51            "ids": format!("[{}]", id),
52            "level": &level,
53            "encodeType": "flac",
54        });
55        if level == "sky" {
56            fallback_data["immerseType"] = json!("c51");
57        }
58        let fallback = self
59            .request(
60                "/api/song/enhance/player/url/v1",
61                fallback_data,
62                query.to_option(CryptoType::default()),
63            )
64            .await?;
65
66        let fallback_url = fallback
67            .body
68            .get("data")
69            .and_then(|d| d.get(0))
70            .and_then(|item| item.get("url"))
71            .and_then(|u| u.as_str())
72            .map(|s| s.to_string());
73
74        match fallback_url {
75            Some(url) => Ok(ApiResponse {
76                status: 302,
77                body: json!({ "redirectUrl": url }),
78                cookie: fallback.cookie,
79            }),
80            None => Ok(fallback),
81        }
82    }
83}