├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── public ├── index.html └── test.html ├── src ├── crypto.rs ├── macros.rs ├── main.rs ├── music_api.rs ├── request.rs └── server.rs └── test.rest /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Build 13 | run: cargo build --verbose 14 | - name: Run tests 15 | run: cargo test --verbose 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /Cargo.lock 3 | /target/ 4 | /.idea/ 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "RustNeteaseCloudMusicApi" 3 | version = "0.1.0" 4 | authors = ["zmant "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies.actix-files] 10 | version = "0.4.1" 11 | 12 | [dependencies.actix-web] 13 | version = "3.3" 14 | 15 | [dependencies.actix-rt] 16 | version = "1" 17 | 18 | [dependencies.base64] 19 | version = "0.13" 20 | 21 | [dependencies.hex] 22 | version = "0.4" 23 | 24 | [dependencies.lazy_static] 25 | version = "1.4" 26 | 27 | [dependencies.openssl] 28 | version = "0.10" 29 | 30 | [dependencies.percent-encoding] 31 | version = "2.1.0" 32 | 33 | [dependencies.rand] 34 | version = "0.7" 35 | 36 | [dependencies.regex] 37 | version = "1.4" 38 | 39 | [dependencies.reqwest] 40 | version = "0.10" 41 | features = [ "json" ] 42 | 43 | [dependencies.serde] 44 | version = "1.0" 45 | 46 | [dependencies.serde_json] 47 | version = "1.0" 48 | 49 | [dependencies.structopt] 50 | version = "0.3" 51 | 52 | [dependencies.urlqstring] 53 | verion = "0.3.5" 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 zmant 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 网易云音乐 API 2 | 网易云音乐 Rust API Service 3 | 4 | ## 实现说明 5 | 此实现是为了学习Rust和actix-web框架而写的,是对[Binaryify](https://github.com/Binaryify/NeteaseCloudMusicApi)大神Node.js版的网易云音乐API的Rust实现, 6 | 7 | ## 环境要求 8 | 9 | 需要 Rust1.39+, actix_web2.0 10 | 11 | ## 安装运行 12 | 13 | ```shell 14 | $ git clone git@github.com:Itanq/NeteaseCloudMusicRustApi.git 15 | $ cargo run 16 | ``` 17 | 服务器启动默认端口为 8000 18 | 19 | ## 使用文档 20 | [文档地址](https://binaryify.github.io/NeteaseCloudMusicApi) 21 | 22 | 23 | ## License 24 | [The MIT License (MIT)](https://github.com/Itanq/NeteaseCloudMusicRustApi/blob/master/LICENSE) 25 | 26 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 网易云音乐 API 8 | 9 | 10 |

网易云音乐 API

11 | 当你看到这个页面时,这个服务已经成功跑起来了~ 12 | 查看文档 13 |

例子:

14 | 19 | 47 | 48 | -------------------------------------------------------------------------------- /public/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | test 8 | 9 | 10 | 11 |

请在控制台看结果

12 | 13 | 14 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/crypto.rs: -------------------------------------------------------------------------------- 1 | 2 | use base64; 3 | use lazy_static::lazy_static; 4 | use openssl::rsa::{ Rsa, Padding, }; 5 | use openssl::symm::{ encrypt, Cipher, }; 6 | use openssl::hash::{hash, MessageDigest, DigestBytes}; 7 | use rand::RngCore; 8 | use rand::rngs::OsRng; 9 | use urlqstring::QueryParams; 10 | use crate::crypto::AesMode::{cbc, ecb}; 11 | 12 | lazy_static!{ 13 | static ref IV: Vec = "0102030405060708".as_bytes().to_vec(); 14 | static ref PRESET_KEY: Vec = "0CoJUm6Qyw8W8jud".as_bytes().to_vec(); 15 | static ref LINUX_API_KEY: Vec = "rFgB&h#%2?^eDg:Q".as_bytes().to_vec(); 16 | static ref BASE62: Vec = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".as_bytes().to_vec(); 17 | static ref RSA_PUBLIC_KEY: Vec = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgtQn2JZ34ZC28NWYpAUd98iZ37BUrX/aKzmFbt7clFSs6sXqHauqKWqdtLkF2KexO40H1YTX8z2lSgBBOAxLsvaklV8k4cBFK9snQXE9/DDaFt6Rr7iVZMldczhC0JNgTz+SHXT6CBHuX3e9SdB1Ua44oncaTWz7OBGLbCiK45wIDAQAB\n-----END PUBLIC KEY-----".as_bytes().to_vec(); 18 | static ref EAPIKEY: Vec = "e82ckenh8dichen8".as_bytes().to_vec(); 19 | } 20 | 21 | #[allow(non_snake_case)] 22 | pub struct Crypto; 23 | 24 | #[allow(non_camel_case_types)] 25 | pub enum HashType { 26 | md5 27 | } 28 | 29 | #[allow(non_camel_case_types)] 30 | pub enum AesMode { 31 | cbc, 32 | ecb, 33 | } 34 | 35 | impl Crypto { 36 | pub fn hex_random_bytes(n: usize) -> String { 37 | let mut data: Vec = Vec::with_capacity(n); 38 | OsRng.fill_bytes(&mut data); 39 | hex::encode(data) 40 | } 41 | 42 | pub fn eapi(url: &str, text: &str) -> String { 43 | let message = format!( "nobody{}use{}md5forencrypt", url, text ); 44 | let digest = hex::encode(hash(MessageDigest::md5(), message.as_bytes()).unwrap()); 45 | let data = format!( "{}-36cd479b6b5-{}-36cd479b6b5-{}", url, text, digest ); 46 | let params = Crypto::aes_encrypt( 47 | &data, 48 | &*EAPIKEY, 49 | ecb, 50 | Some(&*IV), 51 | |t: &Vec| hex::encode_upper(t) 52 | ); 53 | println!("params={}", params); 54 | QueryParams::from(vec![("params", params.as_str())]).stringify() 55 | } 56 | 57 | pub fn weapi(text: &str) -> String { 58 | println!("text={}", text); 59 | let mut secret_key = [0u8; 16]; 60 | OsRng.fill_bytes(&mut secret_key); 61 | let key: Vec = secret_key.iter().map(|i| { 62 | BASE62[ (i % 62) as usize ] 63 | }).collect(); 64 | 65 | println!("key={}", String::from_utf8(key.clone()).unwrap()); 66 | 67 | let params1 = Crypto::aes_encrypt( 68 | text, 69 | &*PRESET_KEY, 70 | cbc, 71 | Some(&*IV), 72 | |t: &Vec| base64::encode( t ) 73 | ); 74 | 75 | let params = Crypto::aes_encrypt( 76 | ¶ms1, 77 | &key, 78 | cbc, 79 | Some(&*IV), 80 | |t: &Vec| base64::encode( t ) 81 | ); 82 | 83 | let enc_sec_key = Crypto::rsa_encrypt( 84 | std::str::from_utf8( 85 | &key.iter().rev().map(|n|*n) 86 | .collect::>() 87 | ).unwrap(), 88 | &*RSA_PUBLIC_KEY 89 | ); 90 | 91 | QueryParams::from(vec![ 92 | ("params", params.as_str()), 93 | ("encSecKey", enc_sec_key.as_str()) 94 | ]).stringify() 95 | } 96 | 97 | pub fn linuxapi(text: &str) -> String { 98 | let params = Crypto::aes_encrypt( 99 | text, 100 | &*LINUX_API_KEY, 101 | ecb, 102 | None, 103 | |t:&Vec| hex::encode(t) 104 | ).to_uppercase(); 105 | println!("text={},prams={}", text, params); 106 | QueryParams::from(vec![ 107 | ("eparams", params.as_str()) 108 | ]).stringify() 109 | } 110 | 111 | pub fn aes_encrypt ( 112 | data: &str, 113 | key: &Vec, 114 | mode: AesMode, 115 | iv: Option<&[u8]>, 116 | encode: fn(&Vec) -> String 117 | ) -> String { 118 | let cipher = match mode { 119 | cbc => Cipher::aes_128_cbc(), 120 | ecb => Cipher::aes_128_ecb(), 121 | }; 122 | let cipher_text = encrypt( 123 | cipher, 124 | key, 125 | iv, 126 | data.as_bytes() 127 | ).unwrap(); 128 | 129 | encode(&cipher_text) 130 | } 131 | 132 | pub fn rsa_encrypt(data: &str, key: &Vec) -> String { 133 | let rsa = Rsa::public_key_from_pem(key).unwrap(); 134 | 135 | let prefix = vec![0u8; 128-data.len()]; 136 | 137 | let data = [&prefix[..], &data.as_bytes()[..]].concat(); 138 | 139 | let mut buf = vec![0; rsa.size() as usize]; 140 | 141 | rsa.public_encrypt(&data, &mut buf, Padding::NONE).unwrap(); 142 | 143 | hex::encode(buf) 144 | } 145 | 146 | pub fn hash_encrypt(data: &str, algorithm: HashType, encode: fn(DigestBytes) -> String) -> String { 147 | match algorithm { 148 | HashType::md5 => { 149 | encode(hash(MessageDigest::md5(), data.as_bytes()).unwrap()) 150 | } 151 | } 152 | } 153 | } 154 | 155 | #[cfg(test)] 156 | mod tests { 157 | 158 | use super::Crypto; 159 | use crate::crypto::{ 160 | IV, PRESET_KEY, RSA_PUBLIC_KEY, HashType, AesMode, 161 | }; 162 | use urlqstring::QueryParams; 163 | 164 | #[test] 165 | fn test_aes_encrypt() { 166 | let msg1 = r#"{"ids":"[347230]","br":999000}"#; 167 | let key1 = "gLiwKFot44HYFRAy"; 168 | let res = Crypto::aes_encrypt( 169 | msg1, 170 | &*PRESET_KEY, 171 | AesMode::cbc, 172 | Some(&*IV), 173 | |t: &Vec| base64::encode( t ) ); 174 | assert_eq!(res, "pgHP1O/hr+IboRMAq6HzpHjyYwNlv1x0G4BBjd1ohdM="); 175 | 176 | let res2 = Crypto::aes_encrypt( 177 | &res, 178 | &key1.as_bytes().to_vec(), 179 | AesMode::cbc, 180 | Some(&*IV), 181 | |t: &Vec| base64::encode( t ) ); 182 | assert_eq!(res2, "3EC4ojigTl0OgjyYtcd+97P7YKarculWrOxSgNO5clkQftvO1jOvS8aAhK6diyOb"); 183 | 184 | let msg2 = r#"{"s":"海阔天空"}"#; 185 | let key2 = "05EBdrdgLjgiqaRc"; 186 | let res = Crypto::aes_encrypt( 187 | msg2, 188 | &*PRESET_KEY, 189 | AesMode::cbc, 190 | Some(&*IV), 191 | |t: &Vec| base64::encode( t ) 192 | ); 193 | assert_eq!(res, "1CH1yTIZN/TXvOMJWH3yAe+iY8c9VfW36l3IfOm58l0="); 194 | 195 | let res2 = Crypto::aes_encrypt( 196 | &res, 197 | &key2.as_bytes().to_vec(), 198 | AesMode::cbc, 199 | Some(&*IV), 200 | |t: &Vec| base64::encode( t ) 201 | ); 202 | assert_eq!(res2, "uPCj4YGmXlMcix5LDAGFb0ynzwPFpFet8dZZ6ia8d2mS47OlnguVmNjGDWPJY1G3"); 203 | } 204 | 205 | #[test] 206 | fn test_rsa_encrypt() { 207 | let key2 = "yARFYH44toFKwiLg"; 208 | let res = Crypto::rsa_encrypt(key2, &*RSA_PUBLIC_KEY); 209 | assert_eq!(res, "5ff8bdb3ed3dd15a26e9025e9abcff0d7a3764dafbc70e33859a892584c681f1aab314b8ad1f3418650ff851bdb0685fc5136a88e059c592da104bbeaba666fbe89eb405c7b66eab4db8ee3ab13a3f98cb41b2ac9981ed4e441ed8e1870524d001ee6ebc1c09f7a945677e5b56a3e964a224c3ee75ac43fbf513f6a8bf7472ee"); 210 | } 211 | 212 | #[test] 213 | fn test_hash_encrypt() { 214 | let msg = "password=uitKHY29LJ28jlFJFwoWiu1098f"; 215 | assert_eq!(Crypto::hash_encrypt( 216 | msg, 217 | HashType::md5, 218 | hex::encode ), "1a72fd2483743c6b1af60041af3edd20"); 219 | 220 | let pw = "email2158"; 221 | 222 | assert_eq!(Crypto::hash_encrypt( 223 | pw, 224 | HashType::md5, 225 | hex::encode ), "afafe22f87fb761d97b8897e00e98fac"); 226 | } 227 | 228 | #[test] 229 | fn test_weapi() { 230 | let text = r#"{"ids":"[\"89ADDE33C0AAE8EC14B99F6750DB954D\"]","resolution":"1080"}"#; 231 | let key: Vec = "IJGckGcNzgsdFNZu".as_bytes().to_vec(); 232 | 233 | let params1 = Crypto::aes_encrypt( 234 | text, 235 | &*PRESET_KEY, 236 | AesMode::cbc, 237 | Some(&*IV), 238 | |t: &Vec| base64::encode( t ) 239 | ); 240 | 241 | let params = Crypto::aes_encrypt( 242 | ¶ms1, 243 | &key, 244 | AesMode::cbc, 245 | Some(&*IV), 246 | |t: &Vec| base64::encode( t ) 247 | ); 248 | 249 | println!("params1={}\nparams={}", params1, params); 250 | 251 | let enc_sec_key = Crypto::rsa_encrypt( 252 | std::str::from_utf8( 253 | &key.iter().rev().map(|n|*n) 254 | .collect::>() 255 | ).unwrap(), 256 | &*RSA_PUBLIC_KEY 257 | ); 258 | 259 | let res = QueryParams::from(vec![ 260 | ("params", params.as_str()), 261 | ("encSecKey", enc_sec_key.as_str()) 262 | ]).stringify(); 263 | println!("res={}", res); 264 | } 265 | 266 | #[test] 267 | fn test_linuxapi() { 268 | let msg = r#"{"method":"POST","url":"https://music.163.com/api/song/lyric?lv=-1&kv=-1&tv=-1","params":{"id":"347230"}}"#; 269 | println!("msg={}", msg); 270 | let res = Crypto::linuxapi(msg); 271 | assert_eq!(res, "eparams=A0D9583F4C5FF68DE851D2893A49DE98FAFB24399F27B4F7E74C64B6FC49A965CFA972FA5EA3D6247CD6247C8198CB873B98A81F6838B428B103E7871611EAC556D5DBE4408FD2751C0E2AD139004A718B72FE3E65ECD467E96A996D93F627A05EB0AAB74EC2E68145C014D505562560&"); 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | 2 | #[macro_export(local_inner_macros)] 3 | macro_rules! json_object { 4 | ($($obj:tt)+) => { 5 | json_object_internal!($($obj)+) 6 | }; 7 | } 8 | 9 | #[macro_export(local_inner_macros)] 10 | #[doc(hidden)] 11 | macro_rules! json_object_internal { 12 | (@map $obj:ident () () ()) => {}; 13 | 14 | (@map $obj:ident [$($key:tt)+] ($val:expr) , $($rest:tt)*) => { 15 | $obj.insert($($key)+, $val); 16 | json_object_internal!(@map $obj () ($($rest)*) ($($rest)*)); 17 | }; 18 | 19 | (@map $obj:ident [$($key:tt)+] ($val:expr)) => { 20 | $obj.insert($($key)+, $val); 21 | }; 22 | 23 | (@map $obj:ident ($($key:tt)+) (: $val:expr, $($rest:tt)*) $copy:tt) => { 24 | json_object_internal!(@map $obj [$($key)+] ($val), $($rest)*); 25 | }; 26 | 27 | (@map $obj:ident ($($key:tt)+) (: $val:expr) $copy:tt) => { 28 | json_object_internal!(@map $obj [$($key)+] ($val)); 29 | }; 30 | 31 | (@map $obj:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { 32 | json_object_internal!(@map $obj ($key) (: $($rest)*) (: $($rest)*)); 33 | }; 34 | 35 | (@map $obj:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { 36 | json_object_internal!(@map $obj ($($key)* $tt) ($($rest)*) ($($rest)*)); 37 | }; 38 | 39 | ({ $($tt:tt)+ }) => { 40 | { 41 | let mut map = std::collections::HashMap::new(); 42 | json_object_internal!(@map map () ($($tt)+) ($($tt)+) ); 43 | map 44 | } 45 | }; 46 | 47 | ({ }) => { 48 | std::collections::HashMap::new() 49 | }; 50 | } 51 | 52 | #[test] 53 | fn test_cookie_map_macro() { 54 | use std::collections::HashMap; 55 | 56 | let cookie = json_object!({ 57 | "cpp": "hi", 58 | "rust": "hello world!", 59 | }); 60 | 61 | let mut map = HashMap::new(); 62 | map.insert("cpp", "hi"); 63 | map.insert("rust", "hello world!"); 64 | 65 | assert_eq!(cookie, map); 66 | } 67 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | #[macro_use] 3 | mod macros; 4 | 5 | mod crypto; 6 | mod music_api; 7 | mod request; 8 | mod server; 9 | 10 | use structopt::StructOpt; 11 | use crate::server::{ 12 | Opt, 13 | start_server 14 | }; 15 | 16 | #[actix_rt::main] 17 | async fn main() -> std::io::Result<()> { 18 | let opt = Opt::from_args(); 19 | start_server(&opt).await 20 | } 21 | -------------------------------------------------------------------------------- /src/music_api.rs: -------------------------------------------------------------------------------- 1 | 2 | use actix_web::{HttpResponse, HttpServer, HttpRequest, Responder, HttpMessage, get, web, App}; 3 | use urlqstring::QueryParams; 4 | use percent_encoding::percent_decode_str; 5 | use std::borrow::Cow; 6 | 7 | use crate::crypto::{Crypto, HashType}; 8 | 9 | use crate::request::generate_response; 10 | use std::collections::HashMap; 11 | 12 | fn get_cookie_string(req: &HttpRequest) -> String { 13 | req.cookies().unwrap().iter().fold(String::from(""),|acc,val| { 14 | val.to_string() + ";" + &acc 15 | }) 16 | } 17 | 18 | async fn empty_query_params_handler(url: &str, crypto: &str, req: HttpRequest) -> impl Responder { 19 | let query_params = json_object!({}); 20 | 21 | let cookies = get_cookie_string(&req); 22 | let request_params = json_object!({ 23 | "crypto": crypto, 24 | "cookie": &cookies, 25 | "proxy": "" 26 | }); 27 | 28 | generate_response( 29 | url, 30 | "POST", 31 | query_params, 32 | request_params 33 | ).await 34 | } 35 | 36 | async fn request_handler( 37 | url: &str, 38 | crypto: &str, 39 | query_params: HashMap<&str,&str>, 40 | cookies: &str, 41 | req: &HttpRequest) -> impl Responder 42 | { 43 | 44 | let request_params = json_object!({ 45 | "crypto": crypto, 46 | "cookie": cookies, 47 | "proxy": "" 48 | }); 49 | 50 | generate_response( 51 | url, 52 | "POST", 53 | query_params, 54 | request_params 55 | ).await 56 | } 57 | 58 | #[get("/album/detail/dynamic")] 59 | pub(crate) async fn index_album_detail_dynamic(req: HttpRequest) -> impl Responder { 60 | let url = "https://music.163.com/api/album/detail/dynamic"; 61 | let cookies = get_cookie_string(&req); 62 | let query_string = QueryParams::from(req.query_string()); 63 | 64 | let query_params = json_object!({ 65 | "id": query_string.value("id").unwrap() 66 | }); 67 | let cookies = get_cookie_string(&req); 68 | request_handler(url, "weapi", query_params, &cookies, &req).await 69 | } 70 | 71 | #[get("/album/newest")] 72 | pub(crate) async fn index_album_newest(req: HttpRequest) -> impl Responder { 73 | let url = "https://music.163.com/api/discovery/newAlbum"; 74 | empty_query_params_handler(url, "weapi", req).await 75 | } 76 | 77 | #[get("/album/sub")] 78 | pub(crate) async fn index_album_sub(req: HttpRequest) -> impl Responder { 79 | let query_string = QueryParams::from(req.query_string()); 80 | let sub = query_string.value("t").unwrap_or("0").parse::().unwrap(); 81 | let url = &format!("https://music.163.com/api/album/{}", if sub == 1 { "sub" } else { "unsub" }); 82 | 83 | let cookies = get_cookie_string(&req); 84 | let query_params = json_object!({ 85 | "id": query_string.value("id").unwrap() 86 | }); 87 | let cookies = get_cookie_string(&req); 88 | request_handler(url, "weapi", query_params, &cookies, &req).await 89 | } 90 | 91 | #[get("/album/sublist")] 92 | pub(crate) async fn index_album_sublist(req: HttpRequest) -> impl Responder { 93 | let url = "https://music.163.com/weapi/album/sublist"; 94 | let cookies = get_cookie_string(&req); 95 | let query_string = QueryParams::from(req.query_string()); 96 | let query_params = json_object!({ 97 | "limit": query_string.value("limit").unwrap_or("25"), 98 | "offset": query_string.value("offset").unwrap_or("0"), 99 | "total": "true" 100 | }); 101 | let cookie = get_cookie_string(&req); 102 | request_handler(url, "weapi", query_params, &cookie, &req).await 103 | } 104 | 105 | #[get("/album")] 106 | pub(crate) async fn index_album(req: HttpRequest) -> impl Responder { 107 | let query_string = QueryParams::from(req.query_string()); 108 | let url = &format!("https://music.163.com/weapi/v1/album/{}", query_string.value("id").unwrap_or("0")); 109 | empty_query_params_handler(url, "weapi", req).await 110 | } 111 | 112 | #[get("/artist/album")] 113 | pub(crate) async fn index_artist_album(req: HttpRequest) -> impl Responder { 114 | let query_string = QueryParams::from(req.query_string()); 115 | let url = &format!("https://music.163.com/weapi/artist/albums/{}", query_string.value("id").unwrap_or("0")); 116 | 117 | let cookies = get_cookie_string(&req); 118 | let query_params = json_object!({ 119 | "limit": query_string.value("limit").unwrap_or("30"), 120 | "offset": query_string.value("offset").unwrap_or("0"), 121 | "total": "true" 122 | }); 123 | let cookies = get_cookie_string(&req); 124 | request_handler(url, "weapi", query_params, &cookies, &req).await 125 | } 126 | 127 | #[get("/artist/desc")] 128 | pub(crate) async fn index_artist_desc(req: HttpRequest) -> impl Responder { 129 | let url = "https://music.163.com/weapi/artist/introduction"; 130 | let query_string = QueryParams::from(req.query_string()); 131 | let query_params = json_object!({ 132 | "id": query_string.value("id").unwrap() 133 | }); 134 | let cookies = get_cookie_string(&req); 135 | request_handler(url, "weapi", query_params, &cookies, &req).await 136 | } 137 | 138 | // 歌手分类 139 | /* 140 | categoryCode 取值 141 | 入驻歌手 5001 142 | 华语男歌手 1001 143 | 华语女歌手 1002 144 | 华语组合/乐队 1003 145 | 欧美男歌手 2001 146 | 欧美女歌手 2002 147 | 欧美组合/乐队 2003 148 | 日本男歌手 6001 149 | 日本女歌手 6002 150 | 日本组合/乐队 6003 151 | 韩国男歌手 7001 152 | 韩国女歌手 7002 153 | 韩国组合/乐队 7003 154 | 其他男歌手 4001 155 | 其他女歌手 4002 156 | 其他组合/乐队 4003 157 | initial 取值 a-z/A-Z 158 | */ 159 | 160 | #[get("/artist/list")] 161 | pub(crate) async fn index_artist_list(req: HttpRequest) -> impl Responder { 162 | let url = "https://music.163.com/weapi/artist/list"; 163 | let query_string = QueryParams::from(req.query_string()); 164 | let query_params = json_object!({ 165 | "categoryCode": query_string.value("cat").unwrap_or("1001"), 166 | "initial": "undefined", 167 | "offset": query_string.value("offset").unwrap_or("0"), 168 | "total": "true" 169 | }); 170 | let cookies = get_cookie_string(&req); 171 | request_handler(url, "weapi", query_params, &cookies, &req).await 172 | } 173 | 174 | #[get("/artist/mv")] 175 | pub(crate) async fn index_artist_mv(req: HttpRequest) -> impl Responder { 176 | let url = "https://music.163.com/weapi/artist/mvs"; 177 | let query_string = QueryParams::from(req.query_string()); 178 | 179 | let query_params = json_object!({ 180 | "artistId": query_string.value("id").unwrap(), 181 | "limit": query_string.value("limit").unwrap_or("25"), 182 | "offset": query_string.value("offset").unwrap_or("0"), 183 | "total": "true" 184 | }); 185 | 186 | let cookies = get_cookie_string(&req); 187 | request_handler(url, "weapi", query_params, &cookies, &req).await 188 | } 189 | 190 | #[get("/artist/sub")] 191 | pub(crate) async fn index_artist_sub(req: HttpRequest) -> impl Responder { 192 | let query_string = QueryParams::from(req.query_string()); 193 | let sub = query_string.value("t").unwrap_or("0").parse::().unwrap(); 194 | let url = &format!("https://music.163.com/weapi/artist/{}", if sub == 1 { "sub" } else { "unsub" }); 195 | 196 | let ids = "[".to_owned() + query_string.value("id").unwrap() + "]"; 197 | let query_params = json_object!({ 198 | "artistId": query_string.value("id").unwrap(), 199 | "artistIds": &ids, 200 | }); 201 | 202 | let cookies = get_cookie_string(&req); 203 | request_handler(url, "weapi", query_params, &cookies, &req).await 204 | } 205 | 206 | #[get("/artist/sublist")] 207 | pub(crate) async fn index_artist_sublist(req: HttpRequest) -> impl Responder { 208 | let url = "https://music.163.com/weapi/artist/sublist"; 209 | let query_string = QueryParams::from(req.query_string()); 210 | 211 | let query_params = json_object!({ 212 | "limit": query_string.value("cat").unwrap_or("25"), 213 | "offset": query_string.value("offset").unwrap_or("0"), 214 | "total": "true" 215 | }); 216 | 217 | let cookies = get_cookie_string(&req); 218 | request_handler(url, "weapi", query_params, &cookies, &req).await 219 | } 220 | 221 | #[get("/artist/top/song")] 222 | pub(crate) async fn index_artist_top_song(req: HttpRequest) -> impl Responder { 223 | let url = "https://music.163.com/api/artist/top/song"; 224 | let query_string = QueryParams::from(req.query_string()); 225 | 226 | let query_params = json_object!({ 227 | "id": query_string.value("id").unwrap() 228 | }); 229 | 230 | let cookies = get_cookie_string(&req); 231 | request_handler(url, "weapi", query_params, &cookies, &req).await 232 | } 233 | 234 | #[get("/artists")] 235 | pub(crate) async fn index_artists(req: HttpRequest) -> impl Responder { 236 | let query_string = QueryParams::from(req.query_string()); 237 | let url = &format!("https://music.163.com/weapi/v1/artist/{}", query_string.value("id").unwrap()); 238 | empty_query_params_handler(url, "weapi", req).await 239 | } 240 | 241 | #[get("/banner")] 242 | pub(crate) async fn index_banner(req: HttpRequest) -> impl Responder { 243 | let query_string = QueryParams::from(req.query_string()); 244 | let url = "https://music.163.com/api/v2/banner/get"; 245 | let type_arr = ["pc", "android", "iphone", "ipad"]; 246 | let query_params = json_object!({ 247 | "clientType": type_arr[query_string.value("type").unwrap_or("0").parse::().unwrap()] 248 | }); 249 | 250 | let cookies = get_cookie_string(&req); 251 | request_handler(url, "linuxapi", query_params, &cookies, &req).await 252 | } 253 | 254 | #[get("/check/music")] 255 | pub(crate) async fn index_check_music(req: HttpRequest) -> impl Responder { 256 | let url = "https://music.163.com/weapi/song/enhance/player/url"; 257 | 258 | let query_string = QueryParams::from(req.query_string()); 259 | let ids = "[".to_owned() + query_string.value("id").unwrap() + "]"; 260 | let query_params = json_object!({ 261 | "ids": query_string.value("id").unwrap(), 262 | "br": query_string.value("br").unwrap_or("999000"), 263 | }); 264 | 265 | let cookies = get_cookie_string(&req); 266 | request_handler(url, "weapi", query_params, &cookies, &req).await 267 | } 268 | 269 | async fn comment_common(url: &str, req: HttpRequest) -> impl Responder { 270 | let query_string = QueryParams::from(req.query_string()); 271 | let query_params = json_object!({ 272 | "rid": query_string.value("id").unwrap(), 273 | "limit": query_string.value("limit").unwrap_or("20"), 274 | "offset": query_string.value("offset").unwrap_or("0"), 275 | "beforeTime": query_string.value("before").unwrap_or("0"), 276 | }); 277 | 278 | let cookies = get_cookie_string(&req); 279 | request_handler(url, "weapi", query_params, &cookies, &req).await 280 | } 281 | 282 | #[get("/comment/album")] 283 | pub(crate) async fn index_comment_album(req: HttpRequest) -> impl Responder { 284 | let query_string = QueryParams::from(req.query_string()); 285 | let url = &format!("https://music.163.com/weapi/v1/resource/comments/R_AL_3_{}", query_string.value("id").unwrap()); 286 | comment_common(url, req).await 287 | } 288 | 289 | #[get("/comment/dj")] 290 | pub(crate) async fn index_comment_dj(req: HttpRequest) -> impl Responder { 291 | let query_string = QueryParams::from(req.query_string()); 292 | let url = &format!("https://music.163.com/weapi/v1/resource/comments/A_DJ_1_{}", query_string.value("id").unwrap()); 293 | comment_common(url, req).await 294 | } 295 | 296 | #[get("/comment/event")] 297 | pub(crate) async fn index_comment_event(req: HttpRequest) -> impl Responder { 298 | let query_string = QueryParams::from(req.query_string()); 299 | let url = &format!("https://music.163.com/weapi/v1/resource/comments/{}", query_string.value("threadId").unwrap()); 300 | let query_params = json_object!({ 301 | "limit": query_string.value("limit").unwrap_or("20"), 302 | "offset": query_string.value("offset").unwrap_or("0"), 303 | "beforeTime": query_string.value("before").unwrap_or("0"), 304 | }); 305 | 306 | let cookies = get_cookie_string(&req); 307 | request_handler(url, "weapi", query_params, &cookies, &req).await 308 | } 309 | 310 | #[get("/comment/hot")] 311 | pub(crate) async fn index_comment_hot(req: HttpRequest) -> impl Responder { 312 | let query_string = QueryParams::from(req.query_string()); 313 | let _type:&str = ["R_SO_4_", "R_MV_5_", "A_PL_0_", "R_AL_3_", "A_DJ_1_", "R_VI_62_"][query_string.value("type").unwrap_or("0").parse::().unwrap()]; 314 | let url = &format!("https://music.163.com/weapi/v1/resource/hotcomments/{}{}", _type, query_string.value("id").unwrap()); 315 | comment_common(url, req).await 316 | } 317 | 318 | #[get("/comment/hotwall/list")] 319 | pub(crate) async fn index_comment_hotwall_list(req: HttpRequest) -> impl Responder { 320 | let url = "https://music.163.com/api/comment/hotwall/list/get"; 321 | empty_query_params_handler(url, "weapi", req).await 322 | } 323 | 324 | #[get("/comment/like")] 325 | pub(crate) async fn index_comment_like(req: HttpRequest) -> impl Responder { 326 | let query_string = QueryParams::from(req.query_string()); 327 | let like = if query_string.value("t").unwrap_or("0") == "1" { 328 | "like" 329 | } else { 330 | "unlike" 331 | }; 332 | let url = &format!("https://music.163.com/weapi/v1/comment/{}", like); 333 | let _type:&str = ["R_SO_4_", "R_MV_5_", "A_PL_0_", "R_AL_3_", "A_DJ_1_", "R_VI_62_", "A_EV_2_"][query_string.value("type").unwrap_or("0").parse::().unwrap()]; 334 | let thread_id = _type.to_owned() + query_string.value("id").unwrap(); 335 | let query_params = json_object!({ 336 | "commentId": query_string.value("cid").unwrap(), 337 | "threadId": &thread_id, 338 | }); 339 | let cookies = get_cookie_string(&req); 340 | request_handler(url, "weapi", query_params, &cookies, &req).await 341 | } 342 | 343 | #[get("/comment/music")] 344 | pub(crate) async fn index_comment_music(req: HttpRequest) -> impl Responder { 345 | let query_string = QueryParams::from(req.query_string()); 346 | let url = &format!("https://music.163.com/api/v1/resource/comments/R_SO_4_{}",query_string.value("id").unwrap()); 347 | comment_common(url, req).await 348 | } 349 | 350 | #[get("/comment/mv")] 351 | pub(crate) async fn index_comment_mv(req: HttpRequest) -> impl Responder { 352 | let query_string = QueryParams::from(req.query_string()); 353 | let url = &format!("https://music.163.com/weapi/v1/resource/comments/R_MV_5_{}",query_string.value("id").unwrap()); 354 | comment_common(url, req).await 355 | } 356 | 357 | 358 | #[get("/comment/playlist")] 359 | pub(crate) async fn index_comment_playlist(req: HttpRequest) -> impl Responder { 360 | let query_string = QueryParams::from(req.query_string()); 361 | let url = &format!("https://music.163.com/weapi/v1/resource/comments/A_PL_0_{}",query_string.value("id").unwrap()); 362 | comment_common(url, req).await 363 | } 364 | 365 | #[get("/comment")] 366 | pub(crate) async fn index_comment(req: HttpRequest) -> impl Responder { 367 | let query_string = QueryParams::from(req.query_string()); 368 | let _t = ["add", "delete", "reply"][query_string.value("t").unwrap_or("0").parse::().unwrap()]; 369 | 370 | let url = &format!("https://music.163.com/weapi/resource/comments/{}", _t); 371 | 372 | let _type:&str = ["R_SO_4_", "R_MV_5_", "A_PL_0_", "R_AL_3_", "A_DJ_1_", "R_VI_62_", "A_EV_2_"][query_string.value("type").unwrap_or("0").parse::().unwrap()]; 373 | 374 | let mut query_params = json_object!({}); 375 | let _td = _type.to_owned() + query_string.value("id").unwrap(); 376 | if _type == "A_EV_2_" { 377 | query_params.insert("threadId", query_string.value("threadId").unwrap()); 378 | } else { 379 | query_params.insert("threadId", &_td); 380 | }; 381 | if _t == "add" { 382 | query_params.insert("content", query_string.value("content").unwrap()); 383 | } else if _t == "delete" { 384 | query_params.insert("commentId", query_string.value("commentId").unwrap()); 385 | } else if _t == "reply" { 386 | query_params.insert("commentId", query_string.value("commentId").unwrap()); 387 | query_params.insert("content", query_string.value("content").unwrap()); 388 | }; 389 | 390 | let cookies = get_cookie_string(&req) + ";os=pc;"; 391 | request_handler(url, "weapi", query_params, &cookies, &req).await 392 | } 393 | 394 | #[get("/daily_signin")] 395 | pub(crate) async fn index_daily_sigin(req: HttpRequest) -> impl Responder { 396 | let url = "https://music.163.com/weapi/point/dailyTask"; 397 | 398 | let query_string = QueryParams::from(req.query_string()); 399 | let query_params = json_object!({ 400 | "type": query_string.value("type").unwrap_or("0"), 401 | }); 402 | let cookies = get_cookie_string(&req); 403 | let request_params = json_object!({ 404 | "crypto": "weapi", 405 | "cookie": &cookies, 406 | "proxy": "" 407 | }); 408 | 409 | generate_response( 410 | url, 411 | "POST", 412 | query_params, 413 | request_params 414 | ).await 415 | } 416 | 417 | #[get("/digitalAlbum/purchased")] 418 | pub(crate) async fn index_digitalAlbum_purchased(req: HttpRequest) -> impl Responder { 419 | let url = "https://music.163.com/api/digitalAlbum/purchased"; 420 | 421 | let query_string = QueryParams::from(req.query_string()); 422 | let query_params = json_object!({ 423 | "limit": query_string.value("limit").unwrap_or("30"), 424 | "offset": query_string.value("offset").unwrap_or("0"), 425 | "total": "true" 426 | }); 427 | let cookies = get_cookie_string(&req); 428 | let request_params = json_object!({ 429 | "crypto": "weapi", 430 | "cookie": &cookies, 431 | "proxy": "" 432 | }); 433 | 434 | generate_response( 435 | url, 436 | "POST", 437 | query_params, 438 | request_params 439 | ).await 440 | } 441 | 442 | #[get("/dj/banner")] 443 | pub(crate) async fn index_dj_banner(req: HttpRequest) -> impl Responder { 444 | let url = "http://music.163.com/weapi/djradio/banner/get"; 445 | empty_query_params_handler(url, "weapi", req).await 446 | } 447 | 448 | #[get("/dj/category/excludehot")] 449 | pub(crate) async fn index_dj_category_excludehot(req: HttpRequest) -> impl Responder { 450 | let url = "http://music.163.com/weapi/djradio/category/excludehot"; 451 | empty_query_params_handler(url, "weapi", req).await 452 | } 453 | 454 | #[get("/dj/category/recommend")] 455 | pub(crate) async fn index_dj_category_recommend(req: HttpRequest) -> impl Responder { 456 | let url = "http://music.163.com/weapi/djradio/home/category/recommend"; 457 | empty_query_params_handler(url, "weapi", req).await 458 | } 459 | 460 | #[get("/dj/catelist")] 461 | pub(crate) async fn index_dj_catelist(req: HttpRequest) -> impl Responder { 462 | let url = "https://music.163.com/weapi/djradio/category/get"; 463 | empty_query_params_handler(url, "weapi", req).await 464 | } 465 | 466 | #[get("/dj/detail")] 467 | pub(crate) async fn index_dj_detail(req: HttpRequest) -> impl Responder { 468 | let url = "https://music.163.com/weapi/djradio/get"; 469 | let query = QueryParams::from(req.query_string()); 470 | let _params = json_object!({ 471 | "id": query.value("rid").unwrap(), 472 | }); 473 | let cookies = get_cookie_string(&req); 474 | request_handler(url, "weapi", _params, &cookies, &req).await 475 | } 476 | 477 | #[get("/dj/hot")] 478 | pub(crate) async fn index_dj_hot(req: HttpRequest) -> impl Responder { 479 | let url = "https://music.163.com/weapi/djradio/hot/v1"; 480 | let query = QueryParams::from(req.query_string()); 481 | let _params = json_object!({ 482 | "limit": query.value("limit").unwrap_or("30"), 483 | "offset": query.value("offset").unwrap_or("0"), 484 | }); 485 | let cookies = get_cookie_string(&req); 486 | request_handler(url, "weapi", _params, &cookies, &req).await 487 | } 488 | 489 | #[get("/dj/paygift")] 490 | pub(crate) async fn index_dj_paygift(req: HttpRequest) -> impl Responder { 491 | let url = "https://music.163.com/weapi/djradio/home/paygift/list?_nmclfl=1"; 492 | let query = QueryParams::from(req.query_string()); 493 | let _params = json_object!({ 494 | "limit": query.value("limit").unwrap_or("30"), 495 | "offset": query.value("offset").unwrap_or("0"), 496 | }); 497 | let cookies = get_cookie_string(&req); 498 | request_handler(url, "weapi", _params, &cookies, &req).await 499 | } 500 | 501 | #[get("/dj/program/detail")] 502 | pub(crate) async fn index_dj_program_detail(req: HttpRequest) -> impl Responder { 503 | let url = "https://music.163.com/weapi/dj/program/detail"; 504 | let query = QueryParams::from(req.query_string()); 505 | let _params = json_object!({ 506 | "id": query.value("id").unwrap(), 507 | }); 508 | let cookies = get_cookie_string(&req); 509 | request_handler(url, "weapi", _params, &cookies, &req).await 510 | } 511 | 512 | #[get("/dj/program/toplist/hours")] 513 | pub(crate) async fn index_dj_program_toplist_hours(req: HttpRequest) -> impl Responder { 514 | let url = "https://music.163.com/api/djprogram/toplist/hours"; 515 | let query = QueryParams::from(req.query_string()); 516 | let _params = json_object!({ 517 | "limit": query.value("limit").unwrap_or("30"), 518 | }); 519 | let cookies = get_cookie_string(&req); 520 | request_handler(url, "weapi", _params, &cookies, &req).await 521 | } 522 | 523 | #[get("/dj/program/toplist")] 524 | pub(crate) async fn index_dj_program_toplist(req: HttpRequest) -> impl Responder { 525 | let url = "https://music.163.com/api/program/toplist/v1"; 526 | let query = QueryParams::from(req.query_string()); 527 | let _params = json_object!({ 528 | "limit": query.value("limit").unwrap_or("100"), 529 | "offset": query.value("offset").unwrap_or("0"), 530 | }); 531 | let cookies = get_cookie_string(&req); 532 | request_handler(url, "weapi", _params, &cookies, &req).await 533 | } 534 | 535 | #[get("/dj/program")] 536 | pub(crate) async fn index_dj_program(req: HttpRequest) -> impl Responder { 537 | let url = "https://music.163.com/weapi/dj/program/byradio"; 538 | let query = QueryParams::from(req.query_string()); 539 | let _params = json_object!({ 540 | "radioId": query.value("rid").unwrap(), 541 | "limit": query.value("limit").unwrap_or("30"), 542 | "offset": query.value("offset").unwrap_or("0"), 543 | "asc": query.value("asc").unwrap_or("false") 544 | }); 545 | let cookies = get_cookie_string(&req); 546 | request_handler(url, "weapi", _params, &cookies, &req).await 547 | } 548 | 549 | #[get("/dj/radio/hot")] 550 | pub(crate) async fn index_dj_radio_hot(req: HttpRequest) -> impl Responder { 551 | let url = "https://music.163.com/api/djradio/hot"; 552 | let query = QueryParams::from(req.query_string()); 553 | let _params = json_object!({ 554 | "cateId": query.value("cateId").unwrap(), 555 | "limit": query.value("limit").unwrap_or("30"), 556 | "offset": query.value("offset").unwrap_or("0"), 557 | }); 558 | let cookies = get_cookie_string(&req); 559 | request_handler(url, "weapi", _params, &cookies, &req).await 560 | } 561 | 562 | // 精选电台分类 563 | /* 564 | 有声书 10001 565 | 知识技能 453050 566 | 商业财经 453051 567 | 人文历史 11 568 | 外语世界 13 569 | 亲子宝贝 14 570 | 创作|翻唱 2001 571 | 音乐故事 2 572 | 3D|电子 10002 573 | 相声曲艺 8 574 | 情感调频 3 575 | 美文读物 6 576 | 脱口秀 5 577 | 广播剧 7 578 | 二次元 3001 579 | 明星做主播 1 580 | 娱乐|影视 4 581 | 科技科学 453052 582 | 校园|教育 4001 583 | 旅途|城市 12 584 | */ 585 | 586 | #[get("/dj/recommend/type")] 587 | pub(crate) async fn index_dj_recommend_type(req: HttpRequest) -> impl Responder { 588 | let url = "https://music.163.com/weapi/djradio/recommend"; 589 | let query = QueryParams::from(req.query_string()); 590 | let _params = json_object!({ 591 | "cateId": query.value("type").unwrap(), 592 | }); 593 | let cookies = get_cookie_string(&req); 594 | request_handler(url, "weapi", _params, &cookies, &req).await 595 | } 596 | 597 | #[get("/dj/recommend")] 598 | pub(crate) async fn index_dj_recommend(req: HttpRequest) -> impl Responder { 599 | let url = "https://music.163.com/weapi/djradio/recommend/v1"; 600 | empty_query_params_handler(url, "weapi", req).await 601 | } 602 | 603 | #[get("/dj/sub")] 604 | pub(crate) async fn index_dj_sub(req: HttpRequest) -> impl Responder { 605 | let query = QueryParams::from(req.query_string()); 606 | let sub = if query.value("t").unwrap_or("0") == "1" { "sub" } else { "unsub" }; 607 | let url = &format!("https://music.163.com/weapi/djradio/{}", sub); 608 | let _params = json_object!({ 609 | "id": query.value("rid").unwrap(), 610 | }); 611 | let cookies = get_cookie_string(&req); 612 | request_handler(url, "weapi", _params, &cookies, &req).await 613 | } 614 | 615 | #[get("/dj/sublist")] 616 | pub(crate) async fn index_dj_sublist(req: HttpRequest) -> impl Responder { 617 | let url = "https://music.163.com/weapi/djradio/get/subed"; 618 | let query = QueryParams::from(req.query_string()); 619 | let _params = json_object!({ 620 | "limit": query.value("limit").unwrap_or("30"), 621 | "offset": query.value("offset").unwrap_or("0"), 622 | "total": "true" 623 | }); 624 | let cookies = get_cookie_string(&req); 625 | request_handler(url, "weapi", _params, &cookies, &req).await 626 | } 627 | 628 | #[get("/dj/today/perfered")] 629 | pub(crate) async fn index_dj_today_perfered(req: HttpRequest) -> impl Responder { 630 | let url = "http://music.163.com/weapi/djradio/home/today/perfered"; 631 | let query = QueryParams::from(req.query_string()); 632 | let _params = json_object!({ 633 | "page": query.value("page").unwrap_or("0"), 634 | }); 635 | let cookies = get_cookie_string(&req); 636 | request_handler(url, "weapi", _params, &cookies, &req).await 637 | } 638 | 639 | #[get("/dj/toplist/hours")] 640 | pub(crate) async fn index_dj_toplist_hours(req: HttpRequest) -> impl Responder { 641 | let url = "https://music.163.com/api/dj/toplist/hours"; 642 | let query = QueryParams::from(req.query_string()); 643 | let _params = json_object!({ 644 | "limit": query.value("limit").unwrap_or("100"), 645 | }); 646 | let cookies = get_cookie_string(&req); 647 | request_handler(url, "weapi", _params, &cookies, &req).await 648 | } 649 | 650 | #[get("/dj/toplist/newcomer")] 651 | pub(crate) async fn index_dj_toplist_newcomer(req: HttpRequest) -> impl Responder { 652 | let url = "https://music.163.com/api/dj/toplist/newcomer"; 653 | let query = QueryParams::from(req.query_string()); 654 | let _params = json_object!({ 655 | "limit": query.value("limit").unwrap_or("100"), 656 | "offset": query.value("offset").unwrap_or("0"), 657 | }); 658 | let cookies = get_cookie_string(&req); 659 | request_handler(url, "weapi", _params, &cookies, &req).await 660 | } 661 | 662 | #[get("/dj/toplist/pay")] 663 | pub(crate) async fn index_dj_toplist_pay(req: HttpRequest) -> impl Responder { 664 | let url = "https://music.163.com/api/djradio/toplist/pay"; 665 | let query = QueryParams::from(req.query_string()); 666 | let _params = json_object!({ 667 | "limit": query.value("limit").unwrap_or("100"), 668 | }); 669 | let cookies = get_cookie_string(&req); 670 | request_handler(url, "weapi", _params, &cookies, &req).await 671 | } 672 | 673 | #[get("/dj/toplist/popular")] 674 | pub(crate) async fn index_dj_toplist_popular(req: HttpRequest) -> impl Responder { 675 | let url = "https://music.163.com/api/dj/toplist/popular"; 676 | let query = QueryParams::from(req.query_string()); 677 | let _params = json_object!({ 678 | "limit": query.value("limit").unwrap_or("100"), 679 | }); 680 | let cookies = get_cookie_string(&req); 681 | request_handler(url, "weapi", _params, &cookies, &req).await 682 | } 683 | 684 | #[get("/dj/toplist")] 685 | pub(crate) async fn index_dj_toplist(req: HttpRequest) -> impl Responder { 686 | let url = "https://music.163.com/api/djradio/toplist"; 687 | let query = QueryParams::from(req.query_string()); 688 | let _type = if query.value("type").unwrap_or("new") == "new" { 689 | "0" 690 | } else { 691 | "1" 692 | }; 693 | let _params = json_object!({ 694 | "limit": query.value("limit").unwrap_or("0"), 695 | "offset": query.value("offset").unwrap_or("0"), 696 | "type": _type 697 | }); 698 | let cookies = get_cookie_string(&req); 699 | request_handler(url, "weapi", _params, &cookies, &req).await 700 | } 701 | 702 | #[get("/event/del")] 703 | pub(crate) async fn index_event_del(req: HttpRequest) -> impl Responder { 704 | let url = "https://music.163.com/eapi/event/delete"; 705 | let query = QueryParams::from(req.query_string()); 706 | let _params = json_object!({ 707 | "id": query.value("evId").unwrap(), 708 | }); 709 | let cookies = get_cookie_string(&req); 710 | request_handler(url, "weapi", _params, &cookies, &req).await 711 | } 712 | 713 | #[get("/event/forward")] 714 | pub(crate) async fn index_event_forward(req: HttpRequest) -> impl Responder { 715 | let url = "https://music.163.com/weapi/event/forward"; 716 | let query = QueryParams::from(req.query_string()); 717 | let _params = json_object!({ 718 | "id": query.value("evId").unwrap(), 719 | "forwards": query.value("forwards").unwrap(), 720 | "eventUserId": query.value("uid").unwrap() 721 | }); 722 | let cookies = get_cookie_string(&req); 723 | request_handler(url, "weapi", _params, &cookies, &req).await 724 | } 725 | 726 | #[get("/event")] 727 | pub(crate) async fn index_event(req: HttpRequest) -> impl Responder { 728 | let url = "https://music.163.com/weapi/v1/event/get"; 729 | let query = QueryParams::from(req.query_string()); 730 | let _params = json_object!({ 731 | "pagesize": query.value("pagesize").unwrap_or("20"), 732 | "lasttime": query.value("lasttime").unwrap_or("-1"), 733 | }); 734 | let cookies = get_cookie_string(&req); 735 | request_handler(url, "weapi", _params, &cookies, &req).await 736 | } 737 | 738 | #[get("/fm/trash")] 739 | pub(crate) async fn index_fm_trash(req: HttpRequest) -> impl Responder { 740 | let query = QueryParams::from(req.query_string()); 741 | let url = &format!("https://music.163.com/weapi/radio/trash/add?alg=RT&songId={}&time={}", query.value("id").unwrap(), query.value("time").unwrap_or("25")); 742 | let _params = json_object!({ 743 | "songId": query.value("id").unwrap(), 744 | }); 745 | let cookies = get_cookie_string(&req); 746 | request_handler(url, "weapi", _params, &cookies, &req).await 747 | } 748 | 749 | #[get("/follow")] 750 | pub(crate) async fn index_follow(req: HttpRequest) -> impl Responder { 751 | let query = QueryParams::from(req.query_string()); 752 | let _t = if query.value("t").unwrap_or("0") == "1" { "follow" } else { "delfollow" }; 753 | let url = &format!("https://music.163.com/weapi/user/{}/{}", _t, query.value("id").unwrap()); 754 | let _params = json_object!({}); 755 | let cookies = get_cookie_string(&req) + ";os=pc;"; 756 | request_handler(url, "weapi", _params, &cookies, &req).await 757 | } 758 | 759 | #[get("/hot/topic")] 760 | pub(crate) async fn index_hot_topic(req: HttpRequest) -> impl Responder { 761 | let url = "http://music.163.com/weapi/act/hot"; 762 | let query = QueryParams::from(req.query_string()); 763 | let _params = json_object!({ 764 | "limit": query.value("limit").unwrap_or("20"), 765 | "offset": query.value("offset").unwrap_or("0"), 766 | }); 767 | let cookies = get_cookie_string(&req); 768 | request_handler(url, "weapi", _params, &cookies, &req).await 769 | } 770 | 771 | #[get("/like")] 772 | pub(crate) async fn index_like(req: HttpRequest) -> impl Responder { 773 | let query = QueryParams::from(req.query_string()); 774 | let url = &format!( 775 | "https://music.163.com/weapi/radio/like?alg={}&trackId={}&time={}", 776 | query.value("alg").unwrap_or("itembased"), 777 | query.value("id").unwrap(), 778 | query.value("time").unwrap_or("25") 779 | ); 780 | let _params = json_object!({ 781 | "trackId": query.value("id").unwrap(), 782 | "like": query.value("like").unwrap_or("false") 783 | }); 784 | let cookies = get_cookie_string(&req); 785 | request_handler(url, "weapi", _params, &cookies, &req).await 786 | } 787 | 788 | #[get("/likelist")] 789 | pub(crate) async fn index_likelist(req: HttpRequest) -> impl Responder { 790 | let url = "https://music.163.com/weapi/song/like/get"; 791 | let query = QueryParams::from(req.query_string()); 792 | let _params = json_object!({ 793 | "uid": query.value("uid").unwrap(), 794 | }); 795 | let cookies = get_cookie_string(&req); 796 | request_handler(url, "weapi", _params, &cookies, &req).await 797 | } 798 | 799 | #[get("/login/cellphone")] 800 | pub(crate) async fn index_login_cellphone(req: HttpRequest) -> impl Responder { 801 | let url = "https://music.163.com/weapi/login/cellphone"; 802 | let query_string = QueryParams::from(req.query_string()); 803 | let pw = Crypto::hash_encrypt( 804 | query_string.value("password").unwrap(), 805 | HashType::md5, 806 | hex::encode 807 | ); 808 | let query_params = json_object!({ 809 | "phone": query_string.value("phone").unwrap(), 810 | "countrycode": query_string.value("countrycode").unwrap_or("86"), 811 | "password": &pw, 812 | "rememberLogin": "true", 813 | }); 814 | 815 | let cookies = get_cookie_string(&req); 816 | request_handler(url, "weapi", query_params, &cookies, &req).await 817 | } 818 | 819 | #[get("/login/refresh")] 820 | pub(crate) async fn index_login_refresh(req: HttpRequest) -> impl Responder { 821 | let url = "https://music.163.com/weapi/login/token/refresh"; 822 | empty_query_params_handler(url, "weapi", req).await 823 | } 824 | 825 | #[get("/logout")] 826 | pub(crate) async fn index_logout(req: HttpRequest) -> impl Responder { 827 | let url = "https://music.163.com/weapi/logout"; 828 | let query_params = json_object!({}); 829 | let cookies = get_cookie_string(&req); 830 | let request_params = json_object!({ 831 | "crypto": "weapi", 832 | "ua": "pc", 833 | "cookie": &cookies, 834 | "proxy": "" 835 | }); 836 | generate_response( 837 | url, 838 | "POST", 839 | query_params, 840 | request_params 841 | ).await 842 | } 843 | 844 | #[get("/lyric")] 845 | pub(crate) async fn index_lyric(req: HttpRequest) -> impl Responder { 846 | let url = "https://music.163.com/weapi/song/lyric?lv=-1&kv=-1&tv=-1"; 847 | let query = QueryParams::from(req.query_string()); 848 | let query_params = json_object!({ 849 | "id": query.value("id").unwrap() 850 | }); 851 | 852 | let cookies = get_cookie_string(&req); 853 | request_handler(url, "linuxapi", query_params, &cookies, &req).await 854 | } 855 | 856 | #[get("/msg/comments")] 857 | pub(crate) async fn index_msg_comments(req: HttpRequest) -> impl Responder { 858 | let query = QueryParams::from(req.query_string()); 859 | let url = &format!("https://music.163.com/api/v1/user/comments/{}", query.value("uid").unwrap()); 860 | let query_params = json_object!({ 861 | "beforeTime": query.value("before").unwrap_or("-1"), 862 | "limit": query.value("limit").unwrap_or("30"), 863 | "total": "true", 864 | "uid": query.value("uid").unwrap(), 865 | }); 866 | let cookies = get_cookie_string(&req); 867 | request_handler(url, "weapi", query_params, &cookies, &req).await 868 | } 869 | 870 | #[get("/msg/forwards")] 871 | pub(crate) async fn index_msg_forwards(req: HttpRequest) -> impl Responder { 872 | let url = "https://music.163.com/api/forwards/get"; 873 | let query = QueryParams::from(req.query_string()); 874 | let query_params = json_object!({ 875 | "offset": query.value("offset").unwrap_or("0"), 876 | "limit": query.value("limit").unwrap_or("30"), 877 | "total": "true", 878 | }); 879 | let cookies = get_cookie_string(&req); 880 | request_handler(url, "weapi", query_params, &cookies, &req).await 881 | } 882 | 883 | #[get("/msg/notices")] 884 | pub(crate) async fn index_msg_notices(req: HttpRequest) -> impl Responder { 885 | let url = "https://music.163.com/api/msg/notices"; 886 | let query = QueryParams::from(req.query_string()); 887 | let query_params = json_object!({ 888 | "offset": query.value("offset").unwrap_or("0"), 889 | "limit": query.value("limit").unwrap_or("30"), 890 | "total": "true", 891 | }); 892 | let cookies = get_cookie_string(&req); 893 | request_handler(url, "weapi", query_params, &cookies, &req).await 894 | } 895 | 896 | #[get("/msg/private/history")] 897 | pub(crate) async fn index_msg_private_history(req: HttpRequest) -> impl Responder { 898 | let url = "https://music.163.com/api/msg/private/history"; 899 | let query = QueryParams::from(req.query_string()); 900 | let query_params = json_object!({ 901 | "userId": query.value("uid").unwrap(), 902 | "limit": query.value("limit").unwrap_or("30"), 903 | "time": query.value("before").unwrap_or("0"), 904 | "total": "true", 905 | }); 906 | let cookies = get_cookie_string(&req); 907 | request_handler(url, "weapi", query_params, &cookies, &req).await 908 | } 909 | 910 | #[get("/msg/private")] 911 | pub(crate) async fn index_msg_private(req: HttpRequest) -> impl Responder { 912 | let url = "https://music.163.com/api/msg/private/users"; 913 | let query = QueryParams::from(req.query_string()); 914 | let query_params = json_object!({ 915 | "offset": query.value("offset").unwrap_or("0"), 916 | "limit": query.value("limit").unwrap_or("30"), 917 | "total": "true", 918 | }); 919 | let cookies = get_cookie_string(&req); 920 | request_handler(url, "weapi", query_params, &cookies, &req).await 921 | } 922 | 923 | #[get("/mv/all")] 924 | pub(crate) async fn index_mv_all(req: HttpRequest) -> impl Responder { 925 | let url = "https://interface.music.163.com/api/mv/all"; 926 | let query = QueryParams::from(req.query_string()); 927 | let tags = &format!("地区:{};类型:{};排序:{}", 928 | query.value("area").unwrap_or("全部"), 929 | query.value("type").unwrap_or("全部"), 930 | query.value("order").unwrap_or("上升最快"), 931 | ); 932 | let query_params = json_object!({ 933 | "offset": query.value("offset").unwrap_or("0"), 934 | "limit": query.value("limit").unwrap_or("30"), 935 | "tags": tags, 936 | "total": "true", 937 | }); 938 | let cookies = get_cookie_string(&req); 939 | request_handler(url, "weapi", query_params, &cookies, &req).await 940 | } 941 | 942 | #[get("/mv/detail")] 943 | pub(crate) async fn index_mv_detail(req: HttpRequest) -> impl Responder { 944 | let url = "https://music.163.com/weapi/mv/detail"; 945 | let query = QueryParams::from(req.query_string()); 946 | let query_params = json_object!({ 947 | "id": query.value("mvid").unwrap() 948 | }); 949 | let cookies = get_cookie_string(&req); 950 | request_handler(url, "weapi", query_params, &cookies, &req).await 951 | } 952 | 953 | #[get("/mv/exclusive/rcmd")] 954 | pub(crate) async fn index_mv_exclusive_rcmd(req: HttpRequest) -> impl Responder { 955 | let url = "https://interface.music.163.com/api/mv/exclusive/rcmd"; 956 | let query = QueryParams::from(req.query_string()); 957 | let query_params = json_object!({ 958 | "offset": query.value("offset").unwrap_or("0"), 959 | "limit": query.value("limit").unwrap_or("30") 960 | }); 961 | let cookies = get_cookie_string(&req); 962 | request_handler(url, "weapi", query_params, &cookies, &req).await 963 | } 964 | 965 | #[get("/mv/first")] 966 | pub(crate) async fn index_mv_first(req: HttpRequest) -> impl Responder { 967 | let url = "https://interface.music.163.com/weapi/mv/first"; 968 | let query = QueryParams::from(req.query_string()); 969 | let query_params = json_object!({ 970 | "area": query.value("area").unwrap_or(""), 971 | "limit": query.value("limit").unwrap_or("30"), 972 | "total": "true", 973 | }); 974 | let cookies = get_cookie_string(&req); 975 | request_handler(url, "weapi", query_params, &cookies, &req).await 976 | } 977 | 978 | #[get("/mv/sub")] 979 | pub(crate) async fn index_mv_sub(req: HttpRequest) -> impl Responder { 980 | let query = QueryParams::from(req.query_string()); 981 | let _t = if query.value("t").unwrap_or("0") == "1" { "sub" } else { "unsub" }; 982 | let url = &format!("https://music.163.com/weapi/mv/{}", _t); 983 | let mv_ids = r#"[""#.to_owned() + query.value("mvid").unwrap() + r#""]"#; 984 | let query_params = json_object!({ 985 | "mvId": query.value("mvId").unwrap(), 986 | "mvIds": &mv_ids, 987 | }); 988 | let cookies = get_cookie_string(&req); 989 | request_handler(url, "weapi", query_params, &cookies, &req).await 990 | } 991 | 992 | #[get("/mv/sublist")] 993 | pub(crate) async fn index_mv_sublist(req: HttpRequest) -> impl Responder { 994 | let url = "https://music.163.com/weapi/cloudvideo/allvideo/sublist"; 995 | let query = QueryParams::from(req.query_string()); 996 | let query_params = json_object!({ 997 | "limit": query.value("limit").unwrap_or("25"), 998 | "offset": query.value("offset").unwrap_or("0"), 999 | "total": "true" 1000 | }); 1001 | let cookies = get_cookie_string(&req); 1002 | request_handler(url, "weapi", query_params, &cookies, &req).await 1003 | } 1004 | 1005 | #[get("/mv/url")] 1006 | pub(crate) async fn index_mv_url(req: HttpRequest) -> impl Responder { 1007 | let url = "https://music.163.com/weapi/song/enhance/play/mv/url"; 1008 | let query = QueryParams::from(req.query_string()); 1009 | let query_params = json_object!({ 1010 | "id": query.value("id").unwrap(), 1011 | "r": query.value("res").unwrap_or("1080"), 1012 | }); 1013 | let cookies = get_cookie_string(&req); 1014 | request_handler(url, "weapi", query_params, &cookies, &req).await 1015 | } 1016 | 1017 | #[get("/personal/fm")] 1018 | pub(crate) async fn index_personal_fm(req: HttpRequest) -> impl Responder { 1019 | let url = "https://music.163.com/weapi/v1/radio/get"; 1020 | empty_query_params_handler(url, "weapi", req).await 1021 | } 1022 | 1023 | #[get("/personalized/djprogram")] 1024 | pub(crate) async fn index_personalized_djprogram(req: HttpRequest) -> impl Responder { 1025 | let url = "https://music.163.com/weapi/personalized/djprogram"; 1026 | empty_query_params_handler(url, "weapi", req).await 1027 | } 1028 | 1029 | #[get("/personalized/mv")] 1030 | pub(crate) async fn index_personalized_mv(req: HttpRequest) -> impl Responder { 1031 | let url = "https://music.163.com/weapi/personalized/mv"; 1032 | empty_query_params_handler(url, "weapi", req).await 1033 | } 1034 | 1035 | #[get("/personalized/newsong")] 1036 | pub(crate) async fn index_personalized_newsong(req: HttpRequest) -> impl Responder { 1037 | let url = "https://music.163.com/weapi/personalized/newsong"; 1038 | let query_params = json_object!({ 1039 | "type": "recommend", 1040 | }); 1041 | let cookies = get_cookie_string(&req); 1042 | request_handler(url, "weapi", query_params, &cookies, &req).await 1043 | } 1044 | 1045 | #[get("/personalized/privatecontent")] 1046 | pub(crate) async fn index_personalized_privatecontent(req: HttpRequest) -> impl Responder { 1047 | let url = "https://music.163.com/weapi/personalized/privatecontent"; 1048 | empty_query_params_handler(url, "weapi", req).await 1049 | } 1050 | 1051 | #[get("/personalized")] 1052 | pub(crate) async fn index_personalized(req: HttpRequest) -> impl Responder { 1053 | let url = "https://music.163.com/weapi/personalized/playlist"; 1054 | let query = QueryParams::from(req.query_string()); 1055 | let query_params = json_object!({ 1056 | "limit": query.value("limit").unwrap_or("30"), 1057 | "total": "true", 1058 | "n": "1000", 1059 | }); 1060 | let cookies = get_cookie_string(&req); 1061 | request_handler(url, "weapi", query_params, &cookies, &req).await 1062 | } 1063 | 1064 | #[get("/playlist/catlist")] 1065 | pub(crate) async fn index_playlist_catlist(req: HttpRequest) -> impl Responder { 1066 | let url = "https://music.163.com/weapi/playlist/catalogue"; 1067 | empty_query_params_handler(url, "weapi", req).await 1068 | } 1069 | 1070 | #[get("/playlist/create")] 1071 | pub(crate) async fn index_playlist_create(req: HttpRequest) -> impl Responder { 1072 | let url = "https://music.163.com/weapi/playlist/create"; 1073 | let query = QueryParams::from(req.query_string()); 1074 | let query_params = json_object!({ 1075 | "name": query.value("name").unwrap(), 1076 | "privacy": query.value("privacy").unwrap(), 1077 | }); 1078 | let cookies = get_cookie_string(&req) + ";os=pc;"; 1079 | request_handler(url, "weapi", query_params, &cookies, &req).await 1080 | } 1081 | 1082 | #[get("/playlist/delete")] 1083 | pub(crate) async fn index_playlist_delete(req: HttpRequest) -> impl Responder { 1084 | let url = "https://music.163.com/weapi/playlist/delete"; 1085 | let query = QueryParams::from(req.query_string()); 1086 | let query_params = json_object!({ 1087 | "pid": query.value("id").unwrap(), 1088 | }); 1089 | let cookies = get_cookie_string(&req) + ";os=pc;"; 1090 | request_handler(url, "weapi", query_params, &cookies, &req).await 1091 | } 1092 | 1093 | #[get("/playlist/desc_update")] 1094 | pub(crate) async fn index_playlist_desc_update(req: HttpRequest) -> impl Responder { 1095 | let url = "http://interface3.music.163.com/eapi/playlist/desc/update"; 1096 | let query = QueryParams::from(req.query_string()); 1097 | let query_params = json_object!({ 1098 | "pid": query.value("id").unwrap(), 1099 | "desc": query.value("desc").unwrap(), 1100 | }); 1101 | let cookies = get_cookie_string(&req) + ";os=pc;"; 1102 | let request_params = json_object!({ 1103 | "crypto": "eapi", 1104 | "cookie": &cookies, 1105 | "proxy": "", 1106 | "url": "/api/playlist/desc/update", 1107 | }); 1108 | generate_response( 1109 | url, 1110 | "POST", 1111 | query_params, 1112 | request_params 1113 | ).await 1114 | } 1115 | 1116 | #[get("/playlist/detail")] 1117 | pub(crate) async fn index_playlist_detail(req: HttpRequest) -> impl Responder { 1118 | let url = "https://music.163.com/weapi/v3/playlist/detail"; 1119 | let query = QueryParams::from(req.query_string()); 1120 | let query_params = json_object!({ 1121 | "id": query.value("id").unwrap(), 1122 | "n": "100000", 1123 | "s": query.value("s").unwrap_or("8"), 1124 | }); 1125 | let cookies = get_cookie_string(&req) + ";os=pc;"; 1126 | request_handler(url, "linuxapi", query_params, &cookies, &req).await 1127 | } 1128 | 1129 | #[get("/playlist/hot")] 1130 | pub(crate) async fn index_playlist_hot(req: HttpRequest) -> impl Responder { 1131 | let url = "https://music.163.com/weapi/playlist/hottags"; 1132 | empty_query_params_handler(url, "weapi", req).await 1133 | } 1134 | 1135 | #[get("/playlist/name/update")] 1136 | pub(crate) async fn index_playlist_name_update(req: HttpRequest) -> impl Responder { 1137 | let url = "http://interface3.music.163.com/eapi/playlist/update/name"; 1138 | let query = QueryParams::from(req.query_string()); 1139 | let query_params = json_object!({ 1140 | "id": query.value("id").unwrap(), 1141 | "name": query.value("name").unwrap(), 1142 | }); 1143 | let cookies = get_cookie_string(&req) + ";os=pc;"; 1144 | let request_params = json_object!({ 1145 | "crypto": "eapi", 1146 | "cookie": &cookies, 1147 | "proxy": "", 1148 | "url": "/api/playlist/update/name", 1149 | }); 1150 | generate_response( 1151 | url, 1152 | "POST", 1153 | query_params, 1154 | request_params 1155 | ).await 1156 | } 1157 | 1158 | #[get("/playlist/subscribe")] 1159 | pub(crate) async fn index_playlist_subscribe(req: HttpRequest) -> impl Responder { 1160 | let query = QueryParams::from(req.query_string()); 1161 | let _t = if query.value("t").unwrap_or("0") == "1" { "subscribe" } else { "unsubscribe" }; 1162 | let url = &format!("https://music.163.com/weapi/playlist/{}", _t); 1163 | let query_params = json_object!({ 1164 | "id": query.value("id").unwrap(), 1165 | }); 1166 | let cookies = get_cookie_string(&req); 1167 | request_handler(url, "weapi", query_params, &cookies, &req).await 1168 | } 1169 | 1170 | #[get("/playlist/subscribers")] 1171 | pub(crate) async fn index_playlist_subscribers(req: HttpRequest) -> impl Responder { 1172 | let url = "https://music.163.com/weapi/playlist/subscribers"; 1173 | let query = QueryParams::from(req.query_string()); 1174 | let query_params = json_object!({ 1175 | "id": query.value("id").unwrap(), 1176 | "limit": query.value("limit").unwrap_or("20"), 1177 | "offset": query.value("offset").unwrap_or("0"), 1178 | }); 1179 | let cookies = get_cookie_string(&req); 1180 | request_handler(url, "weapi", query_params, &cookies, &req).await 1181 | } 1182 | 1183 | #[get("/playlist/tags/update")] 1184 | pub(crate) async fn index_playlist_tags_update(req: HttpRequest) -> impl Responder { 1185 | let url = "http://interface3.music.163.com/eapi/playlist/tags/update"; 1186 | let query = QueryParams::from(req.query_string()); 1187 | let query_params = json_object!({ 1188 | "id": query.value("id").unwrap(), 1189 | "tags": query.value("tags").unwrap(), 1190 | }); 1191 | let cookies = get_cookie_string(&req); 1192 | let request_params = json_object!({ 1193 | "crypto": "eapi", 1194 | "cookie": &cookies, 1195 | "proxy": "", 1196 | "url": "/api/playlist/tags/update", 1197 | }); 1198 | generate_response( 1199 | url, 1200 | "POST", 1201 | query_params, 1202 | request_params 1203 | ).await 1204 | } 1205 | 1206 | #[get("/playlist/tracks")] 1207 | pub(crate) async fn index_playlist_tracks(req: HttpRequest) -> impl Responder { 1208 | let url = "https://music.163.com/weapi/playlist/manipulate/tracks"; 1209 | let query = QueryParams::from(req.query_string()); 1210 | let ids = "[".to_owned() + query.value("trakcs").unwrap() + "]"; 1211 | let query_params = json_object!({ 1212 | "op": query.value("op").unwrap(), 1213 | "pid": query.value("pid").unwrap_or("20"), 1214 | "tackIds": &ids, 1215 | }); 1216 | let cookies = get_cookie_string(&req); 1217 | request_handler(url, "weapi", query_params, &cookies, &req).await 1218 | } 1219 | 1220 | #[get("/playlist/update")] 1221 | pub(crate) async fn index_playlist_update(req: HttpRequest) -> impl Responder { 1222 | let url = "https://music.163.com/weapi/batch"; 1223 | let query = QueryParams::from(req.query_string()); 1224 | let _id = query.value("id").unwrap(); 1225 | let _desc = format!(r#"{{"id":{},"desc":"{}"}}"#, 1226 | _id, 1227 | query.value("desc").unwrap_or(""), 1228 | ); 1229 | let _tags = format!(r#"{{"id":{},"tags":"{}"}}"#, 1230 | _id, 1231 | query.value("tags").unwrap_or(""), 1232 | ); 1233 | let _name = format!(r#"{{"id":{},"name":"{}"}}"#, 1234 | _id, 1235 | query.value("name").unwrap_or("") 1236 | ); 1237 | let query_params = json_object!({ 1238 | "/api/playlist/desc/update": &_desc[..], 1239 | "/api/playlist/tags/update": &_tags[..], 1240 | "/api/playlist/update/name": &_name[..], 1241 | }); 1242 | let cookies = get_cookie_string(&req) + "os=pc;"; 1243 | request_handler(url, "weapi", query_params, &cookies, &req).await 1244 | } 1245 | 1246 | #[get("/playmode/intelligence/list")] 1247 | pub(crate) async fn index_playmode_intelligence_list(req: HttpRequest) -> impl Responder { 1248 | let url = "http://music.163.com/weapi/playmode/intelligence/list"; 1249 | let query = QueryParams::from(req.query_string()); 1250 | let ids = "[".to_owned() + query.value("trakcs").unwrap() + "]"; 1251 | let query_params = json_object!({ 1252 | "songId": query.value("id").unwrap(), 1253 | "type": "fromPlayOne", 1254 | "playlistId": query.value("pid").unwrap(), 1255 | "startMusicId": query.value("sid").unwrap_or(query.value("id").unwrap()), 1256 | "count": query.value("count").unwrap_or("1"), 1257 | }); 1258 | let cookies = get_cookie_string(&req); 1259 | request_handler(url, "weapi", query_params, &cookies, &req).await 1260 | } 1261 | 1262 | #[get("/program/recommend")] 1263 | pub(crate) async fn index_program_recommend(req: HttpRequest) -> impl Responder { 1264 | let url = "https://music.163.com/weapi/program/recommend/v1"; 1265 | let query = QueryParams::from(req.query_string()); 1266 | let query_params = json_object!({ 1267 | "cateId": query.value("type").unwrap(), 1268 | "limit": query.value("limit").unwrap_or("10"), 1269 | "offset": query.value("offset").unwrap_or("0"), 1270 | }); 1271 | let cookies = get_cookie_string(&req); 1272 | request_handler(url, "weapi", query_params, &cookies, &req).await 1273 | } 1274 | 1275 | #[get("/rebind")] 1276 | pub(crate) async fn index_rebind(req: HttpRequest) -> impl Responder { 1277 | let url = "https://music.163.com/api/user/replaceCellphone"; 1278 | let query = QueryParams::from(req.query_string()); 1279 | let query_params = json_object!({ 1280 | "captcha": query.value("captcha").unwrap(), 1281 | "phone": query.value("phone").unwrap(), 1282 | "oldcaptcha": query.value("oldcaptcha").unwrap(), 1283 | "ctcode": query.value("ctcode").unwrap_or("86"), 1284 | }); 1285 | 1286 | let cookies = get_cookie_string(&req); 1287 | request_handler(url, "weapi", query_params, &cookies, &req).await 1288 | } 1289 | 1290 | #[get("/recommend/resource")] 1291 | pub(crate) async fn index_recommend_resource(req: HttpRequest) -> impl Responder { 1292 | let url = "https://music.163.com/weapi/v1/discovery/recommend/resource"; 1293 | empty_query_params_handler(url, "weapi", req).await 1294 | } 1295 | 1296 | #[get("/recommend/songs")] 1297 | pub(crate) async fn index_recommend_songs(req: HttpRequest) -> impl Responder { 1298 | let url = "https://music.163.com/weapi/v1/discovery/recommend/songs"; 1299 | let query_params = json_object!({ 1300 | "total": "true", 1301 | }); 1302 | let cookies = get_cookie_string(&req); 1303 | request_handler(url, "weapi", query_params, &cookies, &req).await 1304 | } 1305 | 1306 | #[get("/register/cellphone")] 1307 | pub(crate) async fn index_register_cellphone(req: HttpRequest) -> impl Responder { 1308 | let url = "https://music.163.com/weapi/register/cellphone"; 1309 | let query = QueryParams::from(req.query_string()); 1310 | let pw = Crypto::hash_encrypt( 1311 | query.value("password").unwrap(), 1312 | HashType::md5, 1313 | hex::encode 1314 | ); 1315 | let query_params = json_object!({ 1316 | "captcha": query.value("captcha").unwrap(), 1317 | "phone": query.value("phone").unwrap(), 1318 | "password": &pw, 1319 | "nickname": query.value("nickname").unwrap(), 1320 | }); 1321 | 1322 | let cookies = get_cookie_string(&req) + "os=pc;"; 1323 | request_handler(url, "weapi", query_params, &cookies, &req).await 1324 | } 1325 | 1326 | #[get("/related/allvideo")] 1327 | pub(crate) async fn index_related_allvideo(req: HttpRequest) -> impl Responder { 1328 | let url = "https://music.163.com/weapi/cloudvideo/v1/allvideo/rcmd"; 1329 | let query = QueryParams::from(req.query_string()); 1330 | let query_params = json_object!({ 1331 | "id": query.value("id").unwrap(), 1332 | "type": "1", 1333 | }); 1334 | let cookies = get_cookie_string(&req); 1335 | request_handler(url, "weapi", query_params, &cookies, &req).await 1336 | } 1337 | 1338 | #[get("/related/playlist")] 1339 | pub(crate) async fn index_related_playlist(req: HttpRequest) -> impl Responder { 1340 | let query = QueryParams::from(req.query_string()); 1341 | let url = &format!("https://music.163.com/playlist?id={}", query.value("id").unwrap()); 1342 | empty_query_params_handler(url, "weapi", req).await 1343 | } 1344 | 1345 | #[get("/resource/like")] 1346 | pub(crate) async fn index_resource_like(req: HttpRequest) -> impl Responder { 1347 | let query = QueryParams::from(req.query_string()); 1348 | let _t = if query.value("t").unwrap_or("0") == "1" { "like" } else { "unlike" }; 1349 | let url = &format!("https://music.163.com/weapi/resource/{}", _t); 1350 | 1351 | let _type = ["", "R_MV_5_", "", "", "A_DJ_1_", "R_VI_62_", "A_EV_2_"][query.value("type").unwrap_or("0").parse::().unwrap()]; 1352 | let _id = _type.to_owned() + query.value("id").unwrap(); 1353 | let query_params = json_object!({ 1354 | "threadId": &_id[..] 1355 | }); 1356 | let cookies = get_cookie_string(&req); 1357 | request_handler(url, "weapi", query_params, &cookies, &req).await 1358 | } 1359 | 1360 | #[get("/search/default")] 1361 | pub(crate) async fn index_search_default(req: HttpRequest) -> impl Responder { 1362 | let url = "http://interface3.music.163.com/eapi/search/defaultkeyword/get"; 1363 | let query_params = json_object!({}); 1364 | let cookies = get_cookie_string(&req); 1365 | let request_params = json_object!({ 1366 | "crypto": "eapi", 1367 | "cookie": &cookies, 1368 | "proxy": "", 1369 | "url": "/api/search/defaultkeyword/get", 1370 | }); 1371 | 1372 | generate_response( 1373 | url, 1374 | "POST", 1375 | query_params, 1376 | request_params 1377 | ).await 1378 | } 1379 | 1380 | #[get("/search/hot/detail")] 1381 | pub(crate) async fn index_search_hot_detail(req: HttpRequest) -> impl Responder { 1382 | let url = "https://music.163.com/weapi/hotsearchlist/get"; 1383 | empty_query_params_handler(url, "weapi", req).await 1384 | } 1385 | 1386 | #[get("/search/hot")] 1387 | pub(crate) async fn index_search_hot(req: HttpRequest) -> impl Responder { 1388 | let url = "https://music.163.com/weapi/search/hot"; 1389 | let query_params = json_object!({ 1390 | "type": "1111", 1391 | }); 1392 | let cookies = get_cookie_string(&req); 1393 | let request_params = json_object!({ 1394 | "crypto": "weapi", 1395 | "ua": "mobile", 1396 | "cookie": &cookies, 1397 | "proxy": "" 1398 | }); 1399 | 1400 | generate_response( 1401 | url, 1402 | "POST", 1403 | query_params, 1404 | request_params 1405 | ).await 1406 | } 1407 | 1408 | #[get("/search/multimatch")] 1409 | pub(crate) async fn index_search_multimatch(req: HttpRequest) -> impl Responder { 1410 | let url = "https://music.163.com/weapi/search/suggest/multimatch"; 1411 | let query = QueryParams::from(req.query_string()); 1412 | let query_params = json_object!({ 1413 | "type": query.value("type").unwrap_or("1"), 1414 | "s": query.value("keywords").unwrap_or(""), 1415 | }); 1416 | 1417 | let cookies = get_cookie_string(&req); 1418 | request_handler(url, "weapi", query_params, &cookies, &req).await 1419 | } 1420 | 1421 | #[get("/search/suggest")] 1422 | pub(crate) async fn index_search_suggest(req: HttpRequest) -> impl Responder { 1423 | let query = QueryParams::from(req.query_string()); 1424 | let _type = if query.value("type").unwrap_or("mobile") == "mobile" { 1425 | "keyword" 1426 | } else { 1427 | "web" 1428 | }; 1429 | let url = &format!("https://music.163.com/weapi/search/suggest/{}", _type); 1430 | let query_params = json_object!({ 1431 | "s": query.value("keywords").unwrap_or(""), 1432 | }); 1433 | 1434 | let cookies = get_cookie_string(&req); 1435 | request_handler(url, "weapi", query_params, &cookies, &req).await 1436 | } 1437 | 1438 | #[get("/search")] 1439 | pub(crate) async fn index_search(req: HttpRequest) -> impl Responder { 1440 | let url = "https://music.163.com/weapi/search/get"; 1441 | 1442 | let qs = percent_decode_str(req.query_string()) 1443 | .decode_utf8().unwrap_or(Cow::Borrowed(&"")); 1444 | let query_string = QueryParams::from(qs.as_ref()); 1445 | let query_params = json_object!({ 1446 | "s": query_string.value("keywords").unwrap_or(""), 1447 | "type": query_string.value("type").unwrap_or("1"), 1448 | "limit": query_string.value("limit").unwrap_or("30"), 1449 | "offset": query_string.value("offset").unwrap_or("0") 1450 | }); 1451 | 1452 | let cookies = get_cookie_string(&req); 1453 | request_handler(url, "weapi", query_params, &cookies, &req).await 1454 | } 1455 | 1456 | #[get("/send/playlist")] 1457 | pub(crate) async fn index_send_playlist(req: HttpRequest) -> impl Responder { 1458 | let url = "https://music.163.com/weapi/msg/private/send"; 1459 | let query = QueryParams::from(req.query_string()); 1460 | let _ids = "[".to_owned() + query.value("user_ids").unwrap() + "]"; 1461 | let query_params = json_object!({ 1462 | "id": query.value("playlist").unwrap(), 1463 | "type": "playlist", 1464 | "msg": query.value("msg").unwrap_or(""), 1465 | "userIds": &_ids, 1466 | }); 1467 | 1468 | let cookies = get_cookie_string(&req) + "os=pc;"; 1469 | request_handler(url, "weapi", query_params, &cookies, &req).await 1470 | } 1471 | 1472 | #[get("/send/text")] 1473 | pub(crate) async fn index_send_text(req: HttpRequest) -> impl Responder { 1474 | let url = "https://music.163.com/weapi/msg/private/send"; 1475 | let query = QueryParams::from(req.query_string()); 1476 | let _ids = "[".to_owned() + query.value("user_ids").unwrap() + "]"; 1477 | let query_params = json_object!({ 1478 | "id": query.value("playlist").unwrap(), 1479 | "type": "text", 1480 | "msg": query.value("msg").unwrap_or(""), 1481 | "userIds": &_ids, 1482 | }); 1483 | 1484 | let cookies = get_cookie_string(&req) + "os=pc;"; 1485 | request_handler(url, "weapi", query_params, &cookies, &req).await 1486 | } 1487 | 1488 | #[get("/setting")] 1489 | pub(crate) async fn index_setting(req: HttpRequest) -> impl Responder { 1490 | let url = "https://music.163.com/api/user/setting"; 1491 | empty_query_params_handler(url, "weapi", req).await 1492 | } 1493 | 1494 | #[get("/share/resource")] 1495 | pub(crate) async fn index_share_resource(req: HttpRequest) -> impl Responder { 1496 | let url = "http://music.163.com/weapi/share/friends/resource"; 1497 | let query = QueryParams::from(req.query_string()); 1498 | let query_params = json_object!({ 1499 | "type": query.value("type").unwrap_or("song"), 1500 | "msg": query.value("msg").unwrap_or(""), 1501 | "id": query.value("id").unwrap_or(""), 1502 | }); 1503 | 1504 | let cookies = get_cookie_string(&req); 1505 | request_handler(url, "weapi", query_params, &cookies, &req).await 1506 | } 1507 | 1508 | #[get("/simi/artist")] 1509 | pub(crate) async fn index_simi_artist(req: HttpRequest) -> impl Responder { 1510 | let url = "https://music.163.com/weapi/discovery/simiArtist"; 1511 | let query = QueryParams::from(req.query_string()); 1512 | let query_params = json_object!({ 1513 | "artistid": query.value("id").unwrap(), 1514 | }); 1515 | 1516 | let cookies = get_cookie_string(&req); 1517 | request_handler(url, "weapi", query_params, &cookies, &req).await 1518 | } 1519 | 1520 | #[get("/simi/mv")] 1521 | pub(crate) async fn index_simi_mv(req: HttpRequest) -> impl Responder { 1522 | let url = "https://music.163.com/weapi/discovery/simiMV"; 1523 | let query = QueryParams::from(req.query_string()); 1524 | let query_params = json_object!({ 1525 | "mvid": query.value("mvid").unwrap(), 1526 | }); 1527 | 1528 | let cookies = get_cookie_string(&req); 1529 | request_handler(url, "weapi", query_params, &cookies, &req).await 1530 | } 1531 | 1532 | #[get("/simi/playlist")] 1533 | pub(crate) async fn index_simi_playlist(req: HttpRequest) -> impl Responder { 1534 | let url = "https://music.163.com/weapi/discovery/simiPlaylist"; 1535 | let query = QueryParams::from(req.query_string()); 1536 | let query_params = json_object!({ 1537 | "songid": query.value("id").unwrap(), 1538 | "limit": query.value("limit").unwrap_or("50"), 1539 | "offset": query.value("offset").unwrap_or("0"), 1540 | }); 1541 | 1542 | let cookies = get_cookie_string(&req); 1543 | request_handler(url, "weapi", query_params, &cookies, &req).await 1544 | } 1545 | 1546 | #[get("/simi/song")] 1547 | pub(crate) async fn index_simi_song(req: HttpRequest) -> impl Responder { 1548 | let url = "https://music.163.com/weapi/v1/discovery/simiSong"; 1549 | let query = QueryParams::from(req.query_string()); 1550 | let query_params = json_object!({ 1551 | "songid": query.value("id").unwrap(), 1552 | "limit": query.value("limit").unwrap_or("51"), 1553 | "offset": query.value("offset").unwrap_or("0"), 1554 | }); 1555 | 1556 | let cookies = get_cookie_string(&req); 1557 | request_handler(url, "weapi", query_params, &cookies, &req).await 1558 | } 1559 | 1560 | #[get("/simi/user")] 1561 | pub(crate) async fn index_simi_user(req: HttpRequest) -> impl Responder { 1562 | let url = "https://music.163.com/weapi/discovery/simiUser"; 1563 | let query = QueryParams::from(req.query_string()); 1564 | let query_params = json_object!({ 1565 | "songid": query.value("id").unwrap(), 1566 | "limit": query.value("limit").unwrap_or("52"), 1567 | "offset": query.value("offset").unwrap_or("0"), 1568 | }); 1569 | 1570 | let cookies = get_cookie_string(&req); 1571 | request_handler(url, "weapi", query_params, &cookies, &req).await 1572 | } 1573 | 1574 | #[get("/song/detail")] 1575 | pub(crate) async fn index_song_detail(req: HttpRequest) -> impl Responder { 1576 | let url = "https://music.163.com/weapi/v3/song/detail"; 1577 | let query = QueryParams::from(req.query_string()); 1578 | let c = &format!(r#""[{{"id":{}}}]""#, query.value("ids").unwrap()); 1579 | let ids = &format!(r#""[{}]""#, query.value("ids").unwrap()); 1580 | let query_params = json_object!({ 1581 | "c": &c[..], 1582 | "ids": &ids[..], 1583 | }); 1584 | let cookies = get_cookie_string(&req); 1585 | request_handler(url, "weapi", query_params, &cookies, &req).await 1586 | } 1587 | 1588 | #[get("/song/url")] 1589 | pub(crate) async fn index_song_url(req: HttpRequest) -> impl Responder { 1590 | let url = "https://music.163.com/api/song/enhance/player/url"; 1591 | let query = QueryParams::from(req.query_string()); 1592 | 1593 | let ids = "[".to_owned() + query.value("id").unwrap() + "]"; 1594 | let query_params = json_object!({ 1595 | "ids": ids.as_str(), 1596 | "br": query.value("br").unwrap_or("999000") 1597 | }); 1598 | 1599 | let cookies = get_cookie_string(&req) + ";os=pc;"; 1600 | request_handler(url, "linuxapi", query_params, &cookies, &req).await 1601 | } 1602 | 1603 | #[get("/top/album")] 1604 | pub(crate) async fn index_top_album(req: HttpRequest) -> impl Responder { 1605 | let url = "https://music.163.com/weapi/album/new"; 1606 | let query = QueryParams::from(req.query_string()); 1607 | let query_params = json_object!({ 1608 | "area": query.value("type").unwrap_or("ALL"), 1609 | "limit": query.value("limit").unwrap_or("50"), 1610 | "offset": query.value("offset").unwrap_or("0"), 1611 | "total": "true", 1612 | }); 1613 | let cookies = get_cookie_string(&req); 1614 | request_handler(url, "weapi", query_params, &cookies, &req).await 1615 | } 1616 | 1617 | #[get("/top/artist")] 1618 | pub(crate) async fn index_top_artist(req: HttpRequest) -> impl Responder { 1619 | let url = "https://music.163.com/weapi/artist/top"; 1620 | let query = QueryParams::from(req.query_string()); 1621 | let query_params = json_object!({ 1622 | "limit": query.value("limit").unwrap_or("50"), 1623 | "offset": query.value("offset").unwrap_or("0"), 1624 | "total": "true", 1625 | }); 1626 | let cookies = get_cookie_string(&req); 1627 | request_handler(url, "weapi", query_params, &cookies, &req).await 1628 | } 1629 | 1630 | #[get("/top/list")] 1631 | pub(crate) async fn index_top_list(req: HttpRequest) -> impl Responder { 1632 | let url = "https://music.163.com/weapi/v3/playlist/detail"; 1633 | let query = QueryParams::from(req.query_string()); 1634 | static topList: [&str;37] = [ 1635 | "3779629", //云音乐新歌榜 1636 | "3778678", //云音乐热歌榜 1637 | "2884035", //云音乐原创榜 1638 | "19723756", //云音乐飙升榜 1639 | "10520166", //云音乐电音榜 1640 | "180106", //UK排行榜周榜 1641 | "60198", //美国Billboard周榜 1642 | "21845217", //KTV嗨榜 1643 | "11641012", //iTunes榜 1644 | "120001", //Hit FM Top榜 1645 | "60131", //日本Oricon周榜 1646 | "3733003", //韩国Melon排行榜周榜 1647 | "60255", //韩国Mnet排行榜周榜 1648 | "46772709", //韩国Melon原声周榜 1649 | "112504", //中国TOP排行榜(港台榜) 1650 | "64016", //中国TOP排行榜(内地榜) 1651 | "10169002", //香港电台中文歌曲龙虎榜 1652 | "4395559", //华语金曲榜 1653 | "1899724", //中国嘻哈榜 1654 | "27135204", //法国 NRJ EuroHot 30周榜 1655 | "112463", //台湾Hito排行榜 1656 | "3812895", //Beatport全球电子舞曲榜 1657 | "71385702", //云音乐ACG音乐榜 1658 | "991319590", //云音乐说唱榜, 1659 | "71384707", //云音乐古典音乐榜 1660 | "1978921795", //云音乐电音榜 1661 | "2250011882", //抖音排行榜 1662 | "2617766278", //新声榜 1663 | "745956260", //云音乐韩语榜 1664 | "2023401535", //英国Q杂志中文版周榜 1665 | "2006508653", //电竞音乐榜 1666 | "2809513713", //云音乐欧美热歌榜 1667 | "2809577409", //云音乐欧美新歌榜 1668 | "2847251561", //说唱TOP榜 1669 | "3001835560", //云音乐ACG动画榜 1670 | "3001795926", //云音乐ACG游戏榜 1671 | "3001890046" //云音乐ACG VOCALOID榜 1672 | ]; 1673 | let query_params = json_object!({ 1674 | "id": topList[query.value("idx").unwrap_or("0").parse::().unwrap()], 1675 | "n": "10000", 1676 | }); 1677 | let cookies = get_cookie_string(&req); 1678 | request_handler(url, "linuxapi", query_params, &cookies, &req).await 1679 | } 1680 | 1681 | #[get("/top/mv")] 1682 | pub(crate) async fn index_top_mv(req: HttpRequest) -> impl Responder { 1683 | let url = "https://music.163.com/weapi/mv/toplist"; 1684 | let query = QueryParams::from(req.query_string()); 1685 | let query_params = json_object!({ 1686 | "area": query.value("area").unwrap_or(""), 1687 | "limit": query.value("limit").unwrap_or("30"), 1688 | "offset": query.value("offset").unwrap_or("0"), 1689 | "total": "true", 1690 | }); 1691 | let cookies = get_cookie_string(&req); 1692 | request_handler(url, "weapi", query_params, &cookies, &req).await 1693 | } 1694 | 1695 | #[get("/top/playlist/highquality")] 1696 | pub(crate) async fn index_top_playlist_highquality(req: HttpRequest) -> impl Responder { 1697 | let url = "https://music.163.com/weapi/playlist/highquality/list"; 1698 | let query = QueryParams::from(req.query_string()); 1699 | let query_params = json_object!({ 1700 | "cat": query.value("cat").unwrap_or("全部"), 1701 | "limit": query.value("limit").unwrap_or("30"), 1702 | "lasttime": query.value("before").unwrap_or("0"), 1703 | "total": "true", 1704 | }); 1705 | let cookies = get_cookie_string(&req); 1706 | request_handler(url, "weapi", query_params, &cookies, &req).await 1707 | } 1708 | 1709 | #[get("/top/playlist")] 1710 | pub(crate) async fn index_top_playlist(req: HttpRequest) -> impl Responder { 1711 | let url = "https://music.163.com/weapi/playlist/list"; 1712 | let query = QueryParams::from(req.query_string()); 1713 | let query_params = json_object!({ 1714 | "cat": query.value("cat").unwrap_or("全部"), 1715 | "order": query.value("order").unwrap_or("hot"), 1716 | "limit": query.value("limit").unwrap_or("30"), 1717 | "lasttime": query.value("before").unwrap_or("0"), 1718 | "total": "true", 1719 | }); 1720 | let cookies = get_cookie_string(&req); 1721 | request_handler(url, "weapi", query_params, &cookies, &req).await 1722 | } 1723 | 1724 | #[get("/top/song")] 1725 | pub(crate) async fn index_top_song(req: HttpRequest) -> impl Responder { 1726 | let url = "https://music.163.com/weapi/v1/discovery/new/songs"; 1727 | let query = QueryParams::from(req.query_string()); 1728 | let query_params = json_object!({ 1729 | "areaId": query.value("type").unwrap_or("0"), 1730 | "total": "true", 1731 | }); 1732 | let cookies = get_cookie_string(&req); 1733 | request_handler(url, "weapi", query_params, &cookies, &req).await 1734 | } 1735 | 1736 | #[get("/toplist/artist")] 1737 | pub(crate) async fn index_toplist_artist(req: HttpRequest) -> impl Responder { 1738 | let url = "https://music.163.com/weapi/toplist/artist"; 1739 | let query_params = json_object!({ 1740 | "type": "1", 1741 | "limit": "100", 1742 | "offset": "0", 1743 | "total": "true", 1744 | }); 1745 | let cookies = get_cookie_string(&req); 1746 | request_handler(url, "weapi", query_params, &cookies, &req).await 1747 | } 1748 | 1749 | #[get("/toplist/detail")] 1750 | pub(crate) async fn index_toplist_detail(req: HttpRequest) -> impl Responder { 1751 | let url = "https://music.163.com/weapi/toplist/detail"; 1752 | empty_query_params_handler(url, "weapi", req).await 1753 | } 1754 | 1755 | #[get("/toplist")] 1756 | pub(crate) async fn index_toplist(req: HttpRequest) -> impl Responder { 1757 | let url = "https://music.163.com/weapi/toplist"; 1758 | empty_query_params_handler(url, "weapi", req).await 1759 | } 1760 | 1761 | #[get("/user/audio")] 1762 | pub(crate) async fn index_user_audio(req: HttpRequest) -> impl Responder { 1763 | let url = "https://music.163.com/weapi/djradio/get/byuser"; 1764 | let query = QueryParams::from(req.query_string()); 1765 | let query_params = json_object!({ 1766 | "userId": query.value("uid").unwrap(), 1767 | }); 1768 | let cookies = get_cookie_string(&req); 1769 | request_handler(url, "weapi", query_params, &cookies, &req).await 1770 | } 1771 | 1772 | #[get("/user/cloud/del")] 1773 | pub(crate) async fn index_user_cloud_del(req: HttpRequest) -> impl Responder { 1774 | let url = "http://music.163.com/weapi/cloud/del"; 1775 | let query = QueryParams::from(req.query_string()); 1776 | let query_params = json_object!({ 1777 | "songIds": query.value("id").unwrap(), 1778 | }); 1779 | let cookies = get_cookie_string(&req); 1780 | request_handler(url, "weapi", query_params, &cookies, &req).await 1781 | } 1782 | 1783 | #[get("/user/cloud/detail")] 1784 | pub(crate) async fn index_user_cloud_detail(req: HttpRequest) -> impl Responder { 1785 | let url = "https://music.163.com/weapi/v1/cloud/get/byids"; 1786 | let query = QueryParams::from(req.query_string()); 1787 | let query_params = json_object!({ 1788 | "songIds": query.value("id").unwrap(), 1789 | }); 1790 | let cookies = get_cookie_string(&req); 1791 | request_handler(url, "weapi", query_params, &cookies, &req).await 1792 | } 1793 | 1794 | #[get("/user/cloud")] 1795 | pub(crate) async fn index_user_cloud(req: HttpRequest) -> impl Responder { 1796 | let url = "https://music.163.com/weapi/v1/cloud/get"; 1797 | let query = QueryParams::from(req.query_string()); 1798 | let query_params = json_object!({ 1799 | "limit": query.value("limit").unwrap_or("30"), 1800 | "offset": query.value("offset").unwrap_or("0"), 1801 | }); 1802 | let cookies = get_cookie_string(&req); 1803 | request_handler(url, "weapi", query_params, &cookies, &req).await 1804 | } 1805 | 1806 | #[get("/user/detail")] 1807 | pub(crate) async fn index_user_detail(req: HttpRequest) -> impl Responder { 1808 | let query = QueryParams::from(req.query_string()); 1809 | let url = &format!("https://music.163.com/weapi/v1/user/detail/{}", query.value("uid").unwrap()); 1810 | empty_query_params_handler(url, "weapi", req).await 1811 | } 1812 | 1813 | #[get("/user/dj")] 1814 | pub(crate) async fn index_user_dj(req: HttpRequest) -> impl Responder { 1815 | let query = QueryParams::from(req.query_string()); 1816 | let url = &format!("https://music.163.com/weapi/dj/program/{}", query.value("uid").unwrap()); 1817 | let query_params = json_object!({ 1818 | "limit": query.value("limit").unwrap_or("30"), 1819 | "offset": query.value("offset").unwrap_or("0"), 1820 | }); 1821 | let cookies = get_cookie_string(&req); 1822 | request_handler(url, "weapi", query_params, &cookies, &req).await 1823 | } 1824 | 1825 | #[get("/user/event")] 1826 | pub(crate) async fn index_user_event(req: HttpRequest) -> impl Responder { 1827 | let query = QueryParams::from(req.query_string()); 1828 | let url = &format!("https://music.163.com/weapi/event/get/{}", query.value("uid").unwrap()); 1829 | let query_params = json_object!({ 1830 | "getcounts": "true", 1831 | "time": query.value("lasttime").unwrap_or("-1"), 1832 | "limit": query.value("limit").unwrap_or("30"), 1833 | "total": "true", 1834 | }); 1835 | let cookies = get_cookie_string(&req); 1836 | request_handler(url, "weapi", query_params, &cookies, &req).await 1837 | } 1838 | 1839 | #[get("/user/followeds")] 1840 | pub(crate) async fn index_user_followeds(req: HttpRequest) -> impl Responder { 1841 | let query = QueryParams::from(req.query_string()); 1842 | let url = &format!("https://music.163.com/eapi/user/getfolloweds/{}", query.value("uid").unwrap()); 1843 | let query_params = json_object!({ 1844 | "userId": query.value("uid").unwrap(), 1845 | "time": query.value("lasttime").unwrap_or("-1"), 1846 | "limit": query.value("limit").unwrap_or("30"), 1847 | }); 1848 | let cookies = get_cookie_string(&req); 1849 | let request_params = json_object!({ 1850 | "crypto": "eapi", 1851 | "cookie": &cookies, 1852 | "proxy": "", 1853 | "url": "/api/user/getfolloweds", 1854 | }); 1855 | 1856 | generate_response( 1857 | url, 1858 | "POST", 1859 | query_params, 1860 | request_params 1861 | ).await 1862 | } 1863 | 1864 | #[get("/user/follows")] 1865 | pub(crate) async fn index_user_follows(req: HttpRequest) -> impl Responder { 1866 | let query = QueryParams::from(req.query_string()); 1867 | let url = &format!("https://music.163.com/weapi/user/getfollows/{}", query.value("uid").unwrap()); 1868 | let query_params = json_object!({ 1869 | "offset": query.value("offset").unwrap_or("0"), 1870 | "limit": query.value("limit").unwrap_or("30"), 1871 | "order": "true", 1872 | }); 1873 | let cookies = get_cookie_string(&req); 1874 | request_handler(url, "weapi", query_params, &cookies, &req).await 1875 | } 1876 | 1877 | #[get("/user/playlist")] 1878 | pub(crate) async fn index_user_playlist(req: HttpRequest) -> impl Responder { 1879 | let url = "https://music.163.com/weapi/user/playlist"; 1880 | let query = QueryParams::from(req.query_string()); 1881 | let query_params = json_object!({ 1882 | "uid": query.value("uid").unwrap(), 1883 | "limit": query.value("limit").unwrap_or("30"), 1884 | "offset": query.value("offset").unwrap_or("0"), 1885 | }); 1886 | let cookies = get_cookie_string(&req); 1887 | request_handler(url, "weapi", query_params, &cookies, &req).await 1888 | } 1889 | 1890 | #[get("/user/record")] 1891 | pub(crate) async fn index_user_record(req: HttpRequest) -> impl Responder { 1892 | let url = "https://music.163.com/weapi/v1/play/record"; 1893 | let query = QueryParams::from(req.query_string()); 1894 | let query_params = json_object!({ 1895 | "uid": query.value("uid").unwrap(), 1896 | "type": query.value("type").unwrap_or("1"), 1897 | }); 1898 | let cookies = get_cookie_string(&req); 1899 | request_handler(url, "weapi", query_params, &cookies, &req).await 1900 | } 1901 | 1902 | #[get("/user/subcount")] 1903 | pub(crate) async fn index_user_subcount(req: HttpRequest) -> impl Responder { 1904 | let url = "https://music.163.com/weapi/subcount"; 1905 | empty_query_params_handler(url, "weapi", req).await 1906 | } 1907 | 1908 | #[get("/user/update")] 1909 | pub(crate) async fn index_user_update(req: HttpRequest) -> impl Responder { 1910 | let url = "https://music.163.com/weapi/user/profile/update"; 1911 | let query = QueryParams::from(req.query_string()); 1912 | let query_params = json_object!({ 1913 | "avatarImgId": "0", 1914 | "birthday": query.value("birthday").unwrap(), 1915 | "city": query.value("city").unwrap(), 1916 | "gender": query.value("gender").unwrap(), 1917 | "nickname": query.value("nickname").unwrap(), 1918 | "province": query.value("province").unwrap(), 1919 | "signature": query.value("signature").unwrap(), 1920 | }); 1921 | let cookies = get_cookie_string(&req); 1922 | request_handler(url, "weapi", query_params, &cookies, &req).await 1923 | } 1924 | 1925 | #[get("/video/detail")] 1926 | pub(crate) async fn index_video_detail(req: HttpRequest) -> impl Responder { 1927 | let url = "https://music.163.com/weapi/cloudvideo/v1/video/detail"; 1928 | let query = QueryParams::from(req.query_string()); 1929 | let query_params = json_object!({ 1930 | "id": query.value("id").unwrap(), 1931 | }); 1932 | let cookies = get_cookie_string(&req); 1933 | request_handler(url, "weapi", query_params, &cookies, &req).await 1934 | } 1935 | 1936 | #[get("/video/group/list")] 1937 | pub(crate) async fn index_video_group_list(req: HttpRequest) -> impl Responder { 1938 | let url = "https://music.163.com/api/cloudvideo/group/list"; 1939 | empty_query_params_handler(url, "weapi", req).await 1940 | } 1941 | 1942 | #[get("/video/group")] 1943 | pub(crate) async fn index_video_group(req: HttpRequest) -> impl Responder { 1944 | let url = "https://music.163.com/weapi/videotimeline/videogroup/get"; 1945 | let query = QueryParams::from(req.query_string()); 1946 | let query_params = json_object!({ 1947 | "groupId": query.value("id").unwrap(), 1948 | "offset": query.value("offset").unwrap_or("0"), 1949 | "needUrl": "true", 1950 | "resolution": query.value("res").unwrap_or("1080"), 1951 | }); 1952 | let cookies = get_cookie_string(&req); 1953 | request_handler(url, "weapi", query_params, &cookies, &req).await 1954 | } 1955 | 1956 | #[get("/video/sub")] 1957 | pub(crate) async fn index_video_sub(req: HttpRequest) -> impl Responder { 1958 | let query = QueryParams::from(req.query_string()); 1959 | let _t = if query.value("t").unwrap_or("0") == "1" { "sub" } else { "unsub" }; 1960 | let url = &format!("https://music.163.com/weapi/cloudvideo/video/{}", _t); 1961 | let query_params = json_object!({ 1962 | "id": query.value("id").unwrap(), 1963 | }); 1964 | let cookies = get_cookie_string(&req); 1965 | request_handler(url, "weapi", query_params, &cookies, &req).await 1966 | } 1967 | 1968 | #[get("/video/url")] 1969 | pub(crate) async fn index_video_url(req: HttpRequest) -> impl Responder { 1970 | let query = QueryParams::from(req.query_string()); 1971 | let url = "https://music.163.com/weapi/cloudvideo/playurl"; 1972 | let ids = r#"[\""#.to_owned() + query.value("id").unwrap() + r#"\"]"#; 1973 | let query_params = json_object!({ 1974 | "ids": &ids[..], 1975 | "resolution": query.value("res").unwrap_or("1080"), 1976 | }); 1977 | let cookies = get_cookie_string(&req); 1978 | request_handler(url, "weapi", query_params, &cookies, &req).await 1979 | } 1980 | 1981 | #[get("/weblog")] 1982 | pub(crate) async fn index_weblog(req: HttpRequest) -> impl Responder { 1983 | let url = "https://music.163.com/weapi/feedback/weblog"; 1984 | empty_query_params_handler(url, "weapi", req).await 1985 | } 1986 | -------------------------------------------------------------------------------- /src/request.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use lazy_static::lazy_static; 3 | use regex::Regex; 4 | use urlqstring::QueryParams; 5 | 6 | 7 | use reqwest::header::{ 8 | CONTENT_TYPE, USER_AGENT, REFERER, CONTENT_ENCODING, COOKIE, 9 | HeaderMap, HeaderValue 10 | }; 11 | 12 | 13 | use crate::crypto::Crypto; 14 | 15 | lazy_static!{ 16 | static ref _CSRF: Regex = Regex::new(r"_csrf=(?P[^(;|$)]+)").unwrap(); 17 | static ref DOMAIN: Regex = Regex::new(r#"\s*Domain=[^(;|$)]+;*"#).unwrap(); 18 | } 19 | 20 | // pub const BANNER_TYPE: [&str; 4] = [ 21 | // "pc", "android", "iphone", "ipad" 22 | // ]; 23 | 24 | // pub const RESOURCE_TYPE: [&str; 7] = [ 25 | // "R_SO_4_", // 歌曲 26 | // "R_MV_5_", // MV 27 | // "A_PL_0_", // 歌单 28 | // "R_AL_3_", // 专辑 29 | // "A_DJ_1_", // 电台, 30 | // "R_VI_62_", // 视频 31 | // "A_EV_2_" // 动态 32 | // ]; 33 | 34 | // pub const OPERATOR: [&str; 3] = [ 35 | // "delete", "add", "reply" 36 | // ]; 37 | 38 | const LINUX_USER_AGNET: &str = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"; 39 | 40 | const USER_AGENT_LIST: [&str; 14] = [ 41 | "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1", 42 | "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1", 43 | "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Mobile Safari/537.36", 44 | "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Mobile Safari/537.36", 45 | "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Mobile Safari/537.36", 46 | "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Mobile/14F89;GameHelper", 47 | "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A300 Safari/602.1", 48 | "Mozilla/5.0 (iPad; CPU OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A300 Safari/602.1", 49 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:46.0) Gecko/20100101 Firefox/46.0", 50 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", 51 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4", 52 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:46.0) Gecko/20100101 Firefox/46.0", 53 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", 54 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/13.1058", 55 | ]; 56 | 57 | // pub const TOP_LIST: [&str; 37] = [ 58 | // "3779629", //云音乐新歌榜 59 | // "3778678", //云音乐热歌榜 60 | // "2884035", //云音乐原创榜 61 | // "19723756", //云音乐飙升榜 62 | // "10520166", //云音乐电音榜 63 | // "180106", //UK排行榜周榜 64 | // "60198", //美国Billboard周榜 65 | // "21845217", //KTV嗨榜 66 | // "11641012", //iTunes榜 67 | // "120001", //Hit FM Top榜 68 | // "60131", //日本Oricon周榜 69 | // "3733003", //韩国Melon排行榜周榜 70 | // "60255", //韩国Mnet排行榜周榜 71 | // "46772709", //韩国Melon原声周榜 72 | // "112504", //中国TOP排行榜(港台榜) 73 | // "64016", //中国TOP排行榜(内地榜) 74 | // "10169002", //香港电台中文歌曲龙虎榜 75 | // "4395559", //华语金曲榜 76 | // "1899724", //中国嘻哈榜 77 | // "27135204", //法国 NRJ EuroHot 30周榜 78 | // "112463", //台湾Hito排行榜 79 | // "3812895", //Beatport全球电子舞曲榜 80 | // "71385702", //云音乐ACG音乐榜 81 | // "991319590", //云音乐说唱榜, 82 | // "71384707", //云音乐古典音乐榜 83 | // "1978921795", //云音乐电音榜 84 | // "2250011882", //抖音排行榜 85 | // "2617766278", //新声榜 86 | // "745956260", //云音乐韩语榜 87 | // "2023401535", //英国Q杂志中文版周榜 88 | // "2006508653", //电竞音乐榜 89 | // "2809513713", //云音乐欧美热歌榜 90 | // "2809577409", //云音乐欧美新歌榜 91 | // "2847251561", //说唱TOP榜 92 | // "3001835560", //云音乐ACG动画榜 93 | // "3001795926", //云音乐ACG游戏榜 94 | // "3001890046", //云音乐ACG VOCALOID榜 95 | // ]; 96 | 97 | pub(crate) async fn generate_response( 98 | url: &str, 99 | method: &str, 100 | query_params: HashMap<&str,&str>, 101 | request_params: HashMap<&str,&str> 102 | ) -> impl actix_web::Responder { 103 | 104 | handle_response( 105 | handle_request(url, method, query_params, request_params).await 106 | ).await 107 | } 108 | 109 | async fn handle_request( 110 | mut url: &str, 111 | method: &str, 112 | query_params: HashMap<&str,&str>, 113 | request_params: HashMap<&str,&str> 114 | ) -> reqwest::Response { 115 | let crypto = request_params.get("crypto").unwrap(); 116 | 117 | let mut headers = HeaderMap::new(); 118 | if crypto == &"linuxapi" { 119 | headers.insert( 120 | USER_AGENT, 121 | LINUX_USER_AGNET.parse().unwrap() 122 | ); 123 | } else { 124 | headers.insert( 125 | USER_AGENT, 126 | serde_json::to_value( 127 | choose_user_agent(request_params.get("ua").unwrap_or(&"")) 128 | ).unwrap().as_str().unwrap().parse().unwrap() 129 | ); 130 | } 131 | if method.to_uppercase() == "POST" { 132 | headers.insert( 133 | CONTENT_TYPE, 134 | "application/x-www-form-urlencoded".parse().unwrap() 135 | ); 136 | } 137 | if url.contains("music.163.com") { 138 | headers.insert( 139 | REFERER, 140 | "https://music.163.com".parse().unwrap() 141 | ); 142 | } 143 | if let Some(cookie) = request_params.get("cookie") { 144 | headers.insert( 145 | COOKIE, 146 | cookie.parse().unwrap() 147 | ); 148 | } 149 | 150 | let empty_cookie = HeaderValue::from_static(""); 151 | let cookie = headers.get(COOKIE) 152 | .unwrap_or(&empty_cookie) 153 | .to_str().unwrap(); 154 | 155 | let body = match crypto { 156 | &"weapi" => { 157 | let csrf_token = if let Some(caps) = _CSRF.captures(cookie) { 158 | caps.name("csrf").unwrap().as_str() 159 | } else { 160 | "" 161 | }; 162 | 163 | let mut _params = query_params; 164 | _params.insert("csrf_token", csrf_token); 165 | Crypto::weapi(&QueryParams::from_map( _params ).json()) 166 | }, 167 | &"linuxapi" => { 168 | let data = format!( 169 | r#"{{"method":"{}","url":"{}","params":{}}}"#, 170 | method, 171 | url.replace("weapi", "api"), 172 | QueryParams::from_map(query_params).json()); 173 | url = "https://music.163.com/api/linux/forward"; 174 | Crypto::linuxapi(&data) 175 | }, 176 | _ => String::from("") 177 | }; 178 | 179 | println!("body={:?}", body); 180 | 181 | let client = reqwest::ClientBuilder::new() 182 | .default_headers(headers) 183 | .build().unwrap(); 184 | 185 | let response = client.post(url) 186 | .body(body) 187 | .send().await.unwrap(); 188 | 189 | println!("response: {:?}", response); 190 | 191 | response 192 | } 193 | 194 | async fn handle_response(response: reqwest::Response) -> impl actix_web::Responder { 195 | let mut res_builder = actix_web::HttpResponse::Ok(); 196 | res_builder.status(response.status()) 197 | .content_type("application/json; charset=utf-8") 198 | .keep_alive(); 199 | 200 | let headers = response.headers(); 201 | 202 | let set_cookies = headers.get_all("set-cookie"); 203 | 204 | let mut cookies_iter = set_cookies.iter(); 205 | while let Some(val) = cookies_iter.next() { 206 | res_builder.header("set-cookie", DOMAIN.replace(val.to_str().unwrap(),"").as_ref()); 207 | } 208 | 209 | println!("response::headers: {:?}", res_builder); 210 | res_builder.json( 211 | response.json::().await.unwrap() 212 | ) 213 | } 214 | 215 | fn choose_user_agent(ua: &str) -> &str { 216 | let index = if ua == "mobile" { 217 | rand::random::() % 7 218 | } else if ua == "pc" { 219 | rand::random::() % 5 + 8 220 | } else if !ua.is_empty() { 221 | return ua; 222 | } else { 223 | rand::random::() % USER_AGENT_LIST.len() 224 | }; 225 | USER_AGENT_LIST[index] 226 | } 227 | 228 | -------------------------------------------------------------------------------- /src/server.rs: -------------------------------------------------------------------------------- 1 | 2 | use actix_web::{ 3 | middleware::Logger, 4 | HttpServer, App, Resource, web, HttpResponse, 5 | get 6 | }; 7 | use structopt::StructOpt; 8 | 9 | use crate::music_api::*; 10 | 11 | #[derive(Debug, StructOpt)] 12 | #[structopt(name = "RustNeteaseCloudMusicApi", about = "A Netease Cloud Music Rust API Service")] 13 | pub(crate) struct Opt { 14 | #[structopt(long, default_value = "localhost")] 15 | ip: String, 16 | 17 | #[structopt(short, long, default_value = "8000")] 18 | port: i32 19 | } 20 | 21 | pub(crate) async fn start_server(opt: &Opt) -> std::io::Result<()> { 22 | let server = HttpServer::new(|| { 23 | App::new() 24 | .wrap(Logger::default()) 25 | .wrap(Logger::new("%a %t %s")) 26 | .service(index_album_detail_dynamic) 27 | .service(index_album_newest) 28 | .service(index_album_sub) 29 | .service(index_album_sublist) 30 | .service(index_album) 31 | .service(index_artist_album) 32 | .service(index_artist_desc) 33 | .service(index_artist_list) 34 | .service(index_artist_mv) 35 | .service(index_artist_sub) 36 | .service(index_artist_sublist) 37 | .service(index_artist_top_song) 38 | .service(index_artists) 39 | .service(index_banner) 40 | .service(index_check_music) 41 | .service(index_comment_album) 42 | .service(index_comment_dj) 43 | .service(index_comment_event) 44 | .service(index_comment_hot) 45 | .service(index_comment_hotwall_list) 46 | .service(index_comment_like) 47 | .service(index_comment_music) 48 | .service(index_comment_mv) 49 | .service(index_comment_playlist) 50 | .service(index_comment) 51 | .service(index_daily_sigin) 52 | .service(index_dj_banner) 53 | .service(index_dj_category_excludehot) 54 | .service(index_dj_category_recommend) 55 | .service(index_dj_catelist) 56 | .service(index_dj_detail) 57 | .service(index_dj_hot) 58 | .service(index_dj_paygift) 59 | .service(index_dj_program_detail) 60 | .service(index_dj_program_toplist_hours) 61 | .service(index_dj_program_toplist) 62 | .service(index_dj_program) 63 | .service(index_dj_radio_hot) 64 | .service(index_dj_recommend_type) 65 | .service(index_dj_recommend) 66 | .service(index_dj_sub) 67 | .service(index_dj_sublist) 68 | .service(index_dj_today_perfered) 69 | .service(index_dj_toplist_hours) 70 | .service(index_dj_toplist_newcomer) 71 | .service(index_dj_toplist_pay) 72 | .service(index_dj_toplist_popular) 73 | .service(index_dj_toplist) 74 | .service(index_event_del) 75 | .service(index_event_forward) 76 | .service(index_event) 77 | .service(index_fm_trash) 78 | .service(index_follow) 79 | .service(index_hot_topic) 80 | .service(index_like) 81 | .service(index_likelist) 82 | .service(index_login_cellphone) 83 | .service(index_login_refresh) 84 | .service(index_logout) 85 | .service(index_lyric) 86 | .service(index_msg_comments) 87 | .service(index_msg_forwards) 88 | .service(index_msg_notices) 89 | .service(index_msg_private_history) 90 | .service(index_msg_private) 91 | .service(index_mv_all) 92 | .service(index_mv_detail) 93 | .service(index_mv_exclusive_rcmd) 94 | .service(index_mv_first) 95 | .service(index_mv_sub) 96 | .service(index_mv_sublist) 97 | .service(index_mv_url) 98 | .service(index_personal_fm) 99 | .service(index_personalized_djprogram) 100 | .service(index_personalized_mv) 101 | .service(index_personalized_newsong) 102 | .service(index_personalized_privatecontent) 103 | .service(index_personalized) 104 | .service(index_playlist_catlist) 105 | .service(index_playlist_create) 106 | .service(index_playlist_delete) 107 | .service(index_playlist_desc_update) 108 | .service(index_playlist_detail) 109 | .service(index_playlist_hot) 110 | .service(index_playlist_name_update) 111 | .service(index_playlist_subscribe) 112 | .service(index_playlist_subscribers) 113 | .service(index_playlist_tags_update) 114 | .service(index_playlist_tracks) 115 | .service(index_playlist_update) 116 | .service(index_playmode_intelligence_list) 117 | .service(index_program_recommend) 118 | .service(index_rebind) 119 | .service(index_recommend_resource) 120 | .service(index_recommend_songs) 121 | .service(index_register_cellphone) 122 | .service(index_related_allvideo) 123 | .service(index_related_playlist) 124 | .service(index_resource_like) 125 | .service(index_search_default) 126 | .service(index_search_hot_detail) 127 | .service(index_search_hot) 128 | .service(index_search_multimatch) 129 | .service(index_search_suggest) 130 | .service(index_search) 131 | .service(index_send_playlist) 132 | .service(index_send_text) 133 | .service(index_setting) 134 | .service(index_share_resource) 135 | .service(index_share_resource) 136 | .service(index_simi_artist) 137 | .service(index_simi_mv) 138 | .service(index_simi_playlist) 139 | .service(index_simi_song) 140 | .service(index_simi_user) 141 | .service(index_song_detail) 142 | .service(index_song_url) 143 | .service(index_top_album) 144 | .service(index_top_artist) 145 | .service(index_top_list) 146 | .service(index_top_mv) 147 | .service(index_top_playlist_highquality) 148 | .service(index_top_playlist) 149 | .service(index_top_song) 150 | .service(index_toplist_artist) 151 | .service(index_toplist_detail) 152 | .service(index_toplist) 153 | .service(index_user_audio) 154 | .service(index_user_cloud_del) 155 | .service(index_user_cloud_detail) 156 | .service(index_user_record) 157 | .service(index_user_update) 158 | .service(index_user_subcount) 159 | .service(index_user_update) 160 | .service(index_video_detail) 161 | .service(index_video_group_list) 162 | .service(index_video_group) 163 | .service(index_video_sub) 164 | .service(index_video_url) 165 | .service(index_weblog) 166 | .service( 167 | actix_files::Files::new("/", "./public/").index_file("index.html") 168 | ) 169 | }); 170 | 171 | println!("{}:{}", opt.ip, opt.port); 172 | 173 | server.bind(format!("{}:{}", opt.ip, opt.port))?.run().await 174 | } -------------------------------------------------------------------------------- /test.rest: -------------------------------------------------------------------------------- 1 | POST http://127.0.0.1:8000/song/url HTTP/1.1 2 | Content-Type: application/json 3 | 4 | { 5 | "id": "347230", 6 | "br": 999000 7 | } 8 | 9 | ### --------------------------------------------------------------------------------