Skip to content

网易云音乐API分析 weapi

METO edited this page Sep 22, 2016 · 2 revisions

0. 状态

该第二版 API 为最新版本,返回结构有大幅度变动,交互地址有个特征 weapi

1. 总览

所有交互需要指定两个参数:

key value
referer http://music.163.com
Cookie os=uwp; osver=10.0.10586.318; appver=1.2.1;

下面列出的所有参数均为明文参数,实际提交需要进行加密,详见最下方第 7 条目

2. 搜索

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
}

3. 专辑

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"
        }
    }
}

4. 歌单

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
        }
    ]
}

5. 单曲信息

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
}

6. URL 分析

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
}

URL 特征

http://m8.music.126.net/[expTime]/[token]/ymusic/[key1]/[key2]/[key3]/[MD5].mp3

参数

expTime: 过期时间戳,标识本 URL 只能在过期时间前请求,否则返回 403 token: 随 expTime 变动,为校验码,加密方式尚不清楚 key123: 固定值,随歌曲 md5 而改变,我还没搞明白,求大神们指教 MD5: 该歌曲的 MD5 校验码,小写

7. 加密请求

实际请求的参数应当加密为如下形式:

params: Db3xGrqMzXwQqWAIe7AlqILYssUuypZlUS+6Dr8g//OEK8SPpjsZht2j+/C+UZ/rAh1bsXoFDEZxQUwdVB5oc1nSRRT3gpmRgzmwhR8yBCboIk+Uf8PvV2azs2WQ10zewCEps4IAIW1Dbes4jxGcEh7pmUXurQQcrjf9VjzOp64XwKuzunQbb0JG8CwybMIyHjWAC6osTnopHVkSikLsMggTLCVADoK3s+a75VWaYY0srdCoS3FJq8tvvnVGim6k3TpsFkiII/r5DCm8EyvfLrZcsiB5Kpx96ZjxZXYw4yU=

encSecKey: 8ac3219a491bfde0c81532fb4d6c8cd919cc2613631f11a82a72a1fd02e535eb5fbce3c51e7bb8ad2ba06590c391ddec326aa6d6535f36bcb2dd074cf9601f1e874fbfe96787f341d824ea8f03781713355e745472949cb44d8b4c6ed1c76944e2d684add7e746f8ab6119caa7270dd3373320345d946dfb2647c66ab6ef51e5

其中 params 为 AES 对称加密后的参数,encSecKey 为 RSA 加密后的 AES 密钥。 所有公钥等参数详见代码,这里不列出。

1. 生成 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;
}

2. AES 加密

在上述 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

3. RSA 加密

最后对第一步生成的 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