-
Notifications
You must be signed in to change notification settings - Fork 44
网易云音乐API分析 weapi
该第二版 API 为最新版本,返回结构有大幅度变动,交互地址有个特征 weapi
所有交互需要指定两个参数:
key | value |
---|---|
referer | http://music.163.com |
Cookie | os=uwp; osver=10.0.10586.318; appver=1.2.1; |
下面列出的所有参数均为明文参数,实际提交需要进行加密,详见最下方第 7 条目
POST http://music.163.com/weapi/cloudsearch/get/web?csrf_token=
s: 关键字
limit: 返回数据条数限制
offset: 偏移数量,用于分页
total: true
csrf_token: 非关键操作,值可为空
type: 搜索类型
- 1 单曲
- 10 专辑
- 100 歌手
- 1000 歌单
- 1002 用户
- 1009 电台
- NULL 推荐(实测失效)
{
"result": {
"songs": [
{
"rtUrls": [],
"ar": [
{
"id": 46487,
"name": "Adele"
}
],
"al": {
"id": 3377030,
"name": "Hello",
"pic_str": "3388694837506899",
"pic": 3388694837506899
},
"st": 0,
"a": null,
"m": {
"br": 160000,
"fid": 3294136840472685,
"size": 5911554,
"vd": -2.95
},
"no": 1,
"cd": "",
"fee": 0,
"mst": 9,
"cp": 390012,
"mv": 501053,
"cf": "",
"dt": 295502,
"h": {
"br": 320000,
"fid": 3294136840472684,
"size": 11823063,
"vd": -3.39
},
"l": {
"br": 96000,
"fid": 3294136840472686,
"size": 3546950,
"vd": -2.97
},
"ftype": 0,
"rtype": 0,
"rurl": null,
"t": 0,
"djId": 0,
"crbt": null,
"rtUrl": null,
"pst": 0,
"alia": [],
"pop": 100,
"rt": null,
"v": 11,
"name": "Hello",
"id": 35847388,
"privilege": {
"id": 35847388,
"fee": 0,
"payed": 0,
"st": 0,
"pl": 320000,
"dl": 320000,
"sp": 7,
"cp": 1,
"subp": 1,
"cs": false,
"maxbr": 999000,
"fl": 320000,
"toast": false,
"flag": 0
}
},
...
],
"songCount": 9999
},
"code": 200
}
POST http://music.163.com/weapi/v1/album/{album_id}?csrf_token=
album_id: 专辑 ID,在 url 也需要包含
csrf_token: 非关键操作,值可为空
{
"songs": [
{
"rtUrls": [],
"ar": [
{
"id": 46487,
"name": "Adele"
}
],
"al": {
"id": 3377030,
"name": "Hello",
"pic_str": "3388694837506899",
"pic": 3388694837506899
},
"st": 0,
"no": 1,
"a": null,
"m": {
"br": 160000,
"fid": 3294136840472685,
"size": 5911554,
"vd": -2.95
},
"rtUrl": null,
"alia": [],
"pop": 100,
"rt": null,
"mst": 9,
"cp": 390012,
"mv": 501053,
"cf": "",
"dt": 295502,
"h": {
"br": 320000,
"fid": 3294136840472684,
"size": 11823063,
"vd": -3.39
},
"l": {
"br": 96000,
"fid": 3294136840472686,
"size": 3546950,
"vd": -2.97
},
"pst": 0,
"crbt": null,
"ftype": 0,
"rtype": 0,
"rurl": null,
"t": 0,
"djId": 0,
"v": 11,
"cd": "",
"fee": 0,
"name": "Hello",
"id": 35847388,
"privilege": {
"id": 35847388,
"fee": 0,
"payed": 0,
"st": 0,
"pl": 320000,
"dl": 320000,
"sp": 7,
"cp": 1,
"subp": 1,
"cs": false,
"maxbr": 999000,
"fl": 320000,
"toast": false,
"flag": 0
}
}
],
"code": 200,
"album": {
"songs": [],
"paid": false,
"onSale": false,
"status": 0,
"copyrightId": 390012,
"alias": [],
"picId": 3388694837506899,
"publishTime": 1445529600007,
"company": "XL Recordings",
"briefDesc": null,
"tags": "",
"blurPicUrl": "http://p1.music.126.net/br3IrdCvT7-GjCyUVNONiA==/3388694837506899.jpg",
"companyId": 0,
"pic": 3388694837506899,
"artists": [
{
"img1v1Id": 0,
"alias": [],
"picId": 0,
"briefDesc": "",
"albumSize": 0,
"img1v1Url": "http://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg",
"trans": "",
"musicSize": 0,
"picUrl": "",
"name": "Adele",
"id": 46487
}
],
"artist": {
"img1v1Id": 0,
"alias": [
"Adele Laurie Blue Adkins"
],
"picId": 3263350518850889,
"briefDesc": "",
"albumSize": 27,
"img1v1Url": "http://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg",
"trans": "阿黛尔",
"musicSize": 286,
"picUrl": "http://p1.music.126.net/_cSzHw9F-Nkgy9gb2QPI_A==/3263350518850889.jpg",
"name": "Adele",
"id": 46487,
"transNames": [
"阿黛尔"
]
},
"picUrl": "http://p1.music.126.net/br3IrdCvT7-GjCyUVNONiA==/3388694837506899.jpg",
"description": "Adele新专辑《25》首发单曲《Hello》于2015年10月23日发行。",
"subType": "录音室版",
"commentThreadId": "R_AL_3_3377030",
"name": "Hello",
"id": 3377030,
"type": "EP/Single",
"size": 1,
"info": {
"latestLikedUsers": null,
"liked": false,
"comments": null,
"resourceType": 3,
"resourceId": 3377030,
"likedCount": 0,
"commentCount": 1007,
"shareCount": 436,
"threadId": "R_AL_3_3377030"
}
}
}
POST http://music.163.com/weapi/v3/playlist/detail?csrf_token=
id: 歌单 ID
csrf_token: 非关键操作,值可为空
{
"playlist": {
"subscribers": [],
"subscribed": false,
"creator": {
"signature": "爱1D,Zayn,Westlife,Shane,Troye,IU,比伯,断眉…(同时也是个二次元的隐宅哟~)本质欧美粉…",
"authority": 0,
"defaultAvatar": false,
"avatarImgId": 18619129905085787,
"province": 1000000,
"authStatus": 0,
"followed": false,
"avatarUrl": "http://p4.music.126.net/2r_UtxkTrllDY0d7BUwkWg==/18619129905085787.jpg",
"accountStatus": 0,
"gender": 2,
"city": 1007700,
"birthday": 1020441600000,
"userId": 76696522,
"userType": 0,
"nickname": "ZAYN-MALIK-",
"description": "",
"detailDescription": "",
"backgroundImgId": 2946691222527501,
"backgroundUrl": "http://p1.music.126.net/CMOcuWJIWBKDuIIcfv6myg==/2946691222527501.jpg",
"mutual": false,
"expertTags": null,
"djStatus": 0,
"vipType": 0,
"remarkName": null
},
"tracks": [
{
"name": "Hello",
"id": 35847388,
"pst": 0,
"t": 0,
"ar": [
{
"id": 46487,
"name": "Adele"
}
],
"alia": [],
"pop": 100,
"st": 0,
"rt": null,
"fee": 0,
"v": 11,
"crbt": null,
"cf": "",
"al": {
"id": 3377030,
"name": "Hello",
"pic_str": "3388694837506899",
"pic": 3388694837506899
},
"dt": 295502,
"h": {
"br": 320000,
"fid": 3294136840472684,
"size": 11823063,
"vd": -3.39
},
"m": {
"br": 160000,
"fid": 3294136840472685,
"size": 5911554,
"vd": -2.95
},
"l": {
"br": 96000,
"fid": 3294136840472686,
"size": 3546950,
"vd": -2.97
},
"a": null,
"cd": "",
"no": 1,
"rtUrl": null,
"ftype": 0,
"rtUrls": [],
"mst": 9,
"cp": 390012,
"mv": 501053,
"rtype": 0,
"rurl": null,
"privilege": {
"id": 35847388,
"fee": 0,
"payed": 0,
"st": 0,
"pl": 320000,
"dl": 320000,
"sp": 7,
"cp": 1,
"subp": 1,
"cs": false,
"maxbr": 999000,
"fl": 320000,
"pc": null,
"toast": false,
"flag": 0
}
}
],
"trackIds": [
{
"id": 35847388,
"v": 12
}
],
"description": null,
"tags": [],
"privacy": 0,
"newImported": false,
"userId": 76696522,
"createTime": 1446884412646,
"trackCount": 1,
"specialType": 0,
"updateTime": 1446884413425,
"commentThreadId": "A_PL_0_124394335",
"trackUpdateTime": 1467984278182,
"coverImgId": 3388694837506899,
"highQuality": false,
"playCount": 10,
"status": 10,
"cloudTrackCount": 0,
"subscribedCount": 0,
"trackNumberUpdateTime": 1446884413425,
"adType": 0,
"name": "Hello,Adele",
"id": 124394335,
"shareCount": 0,
"commentCount": 0
},
"code": 200,
"privileges": [
{
"id": 35847388,
"fee": 0,
"payed": 0,
"st": 0,
"pl": 320000,
"dl": 320000,
"sp": 7,
"cp": 1,
"subp": 1,
"cs": false,
"maxbr": 999000,
"fl": 320000,
"toast": false,
"flag": 0
}
]
}
POST http://music.163.com/weapi/v3/song/detail
c: Json 格式字符串,格式如:[{"id":"35847388"}]
csrf_token: 非关键操作,值可为空
{
"songs": [
{
"rtUrls": [],
"ar": [
{
"id": 46487,
"name": "Adele"
}
],
"al": {
"id": 3377030,
"name": "Hello",
"pic_str": "3388694837506899",
"pic": 3388694837506899
},
"st": 0,
"cd": "",
"no": 1,
"djId": 0,
"fee": 0,
"ftype": 0,
"rtype": 0,
"rurl": null,
"t": 0,
"a": null,
"m": {
"br": 160000,
"fid": 3294136840472685,
"size": 5911554,
"vd": -2.95
},
"v": 11,
"dt": 295502,
"h": {
"br": 320000,
"fid": 3294136840472684,
"size": 11823063,
"vd": -3.39
},
"l": {
"br": 96000,
"fid": 3294136840472686,
"size": 3546950,
"vd": -2.97
},
"crbt": null,
"rtUrl": null,
"pst": 0,
"alia": [],
"pop": 100,
"rt": null,
"mst": 9,
"cp": 390012,
"mv": 501053,
"cf": "",
"name": "Hello",
"id": 35847388
}
],
"privileges": [
{
"id": 35847388,
"fee": 0,
"payed": 0,
"st": 0,
"pl": 320000,
"dl": 320000,
"sp": 7,
"cp": 1,
"subp": 1,
"cs": false,
"maxbr": 999000,
"fl": 320000,
"toast": false,
"flag": 0
}
],
"code": 200
}
POST http://music.163.com/weapi/song/enhance/player/url?csrf_token=
id: 歌单 ID
br: 比特率,320000
csrf_token: 非关键操作,值可为空
{
"data": [
{
"id": 35847388,
"url": "http://m8.music.126.net/20160922184157/d7544ebef6691ad36de6f4d85f035a11/ymusic/a3bc/b02c/b25b/7a1f79bb4c732d4bd2a2ab967c2bb7d1.mp3",
"br": 320000,
"size": 11823063,
"md5": "7a1f79bb4c732d4bd2a2ab967c2bb7d1",
"code": 200,
"expi": 1200,
"type": "mp3",
"gain": -3.38,
"fee": 0,
"uf": null,
"payed": 0,
"flag": 0,
"canExtend": false
}
],
"code": 200
}
http://m8.music.126.net/[expTime]/[token]/ymusic/[key1]/[key2]/[key3]/[MD5].mp3
expTime: 过期时间戳,标识本 URL 只能在过期时间前请求,否则返回 403 token: 随 expTime 变动,为校验码,加密方式尚不清楚 key123: 固定值,随歌曲 md5 而改变,我还没搞明白,求大神们指教 MD5: 该歌曲的 MD5 校验码,小写
实际请求的参数应当加密为如下形式:
params: Db3xGrqMzXwQqWAIe7AlqILYssUuypZlUS+6Dr8g//OEK8SPpjsZht2j+/C+UZ/rAh1bsXoFDEZxQUwdVB5oc1nSRRT3gpmRgzmwhR8yBCboIk+Uf8PvV2azs2WQ10zewCEps4IAIW1Dbes4jxGcEh7pmUXurQQcrjf9VjzOp64XwKuzunQbb0JG8CwybMIyHjWAC6osTnopHVkSikLsMggTLCVADoK3s+a75VWaYY0srdCoS3FJq8tvvnVGim6k3TpsFkiII/r5DCm8EyvfLrZcsiB5Kpx96ZjxZXYw4yU=
encSecKey: 8ac3219a491bfde0c81532fb4d6c8cd919cc2613631f11a82a72a1fd02e535eb5fbce3c51e7bb8ad2ba06590c391ddec326aa6d6535f36bcb2dd074cf9601f1e874fbfe96787f341d824ea8f03781713355e745472949cb44d8b4c6ed1c76944e2d684add7e746f8ab6119caa7270dd3373320345d946dfb2647c66ab6ef51e5
其中 params 为 AES 对称加密后的参数,encSecKey 为 RSA 加密后的 AES 密钥。 所有公钥等参数详见代码,这里不列出。
AES 密钥需要随机,否则服务器会 dump 掉相同密钥的请求(数量多的话)。
密钥的形式为 16 位随机字母或数字,[0-9a-zA-Z]
function createSecretKey($length=16){
$str='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$r='';
for($i=0;$i<$length;$i++){
$r.=$str[rand(0,strlen($str)-1)];
}
return $r;
}
在上述 API 中,首先将 POST 参数值拼写为如下形式,以搜索 hello
为例:
{"s":"hello","type":"1","limit":"1000","offset":"0","csrf_token":""}
然后对上面的明文进行两次 AES 加密,第一次密钥为 nonce,第二次为第一步生成的密钥。
$data['params']=$this->aes_encode($string,$this->_nonce);
$data['params']=$this->aes_encode($data['params'],$this->_secretKey);
AES 加密的具体算法为:AES-128-CBC
,输出格式为 base64
AES 加密时需要指定 iv:0102030405060708
本步骤加密后的结果即为 params
最后对第一步生成的 secretKey 进行 RSA 加密,不过这个加密非常诡异,不是标准的形式。下面引用 darknessomi
的结论
RSA 加密采用非常规填充方式,既不是
PKCS1
也不是PKCS1_OAEP
,网易的做法是直接向前补0
这样加密出来的密文有个特点:加密过程没有随机因素,明文多次加密后得到的密文是相同的
然而,我们常用的RSA
加密模块均不支持此种加密,所以需要手写一段简单的RSA
加密
加密过程convertUtf8toHex(reversedText)^e%N
输入过程中需要对加密字符串进行hex
格式转码
PHP 中需要使用大数运算类,如果嫌不够清真的话可以自己实现,需要使用快速幂算法加速
function rsa_encode($text){
$rtext=strrev(utf8_encode($text));
$keytext=$this->bchexdec($this->strToHex($rtext));
$a=new Math_BigInteger($keytext);
$b=new Math_BigInteger($this->bchexdec($this->_pubKey));
$c=new Math_BigInteger($this->bchexdec($this->_modulus));
$key=$a->modPow($b, $c)->toHex();
return str_pad($key,256,'0',STR_PAD_LEFT);
}
function bchexdec($hex){
$dec=0;
$len=strlen($hex);
for($i=0;$i<$len;$i++) {
$dec=bcadd($dec,bcmul(strval(hexdec($hex[$i])),bcpow('16',strval($len-$i-1))));
}
return $dec;
}
function strToHex($str){
$hex='';
for($i=0;$i<strlen($str);$i++){
$hex.=dechex(ord($str[$i]));
}
return $hex;
}
本步骤加密后的结果即为 encSecKey