第三⽅库_⽹易云⾳乐_NetEaseCloudMusicApi NetEaseCloudMusicApi
项⽬源地址:
⼩程序⽹易云⾳乐api模块
这次开发⽹易云⾳乐api库的原因是qq⾳乐api库在⼩程序中iOS环境下⽆法使⽤⼩程序提供的背景⾳频播放器播放的问题
⽹易云的加密算法真的⽐其他⼏家api复杂太多了完爆QQ和酷狗
依赖
本api库参考了Github上⾯开源的node库,因为我们只想要查⾳乐和播放⾳乐这两个功能
虽然Github那个库很⽅便,但是我们不想为了两个接⼝特意去跑⼀个node.js服务。Github上的库
1. big-integer.js
这⾥注意,不要使⽤最新版的,最新版的库再模拟器上运⾏没有问题,但是在真机调试的上传包阶段会报错说⽆法识别big-integer.js
最后在我的尝试下,选⽤了⼀个⽼版本的库解决了这个问题。
2. crypto.js
这个库是⽤来aes加密的,在node上⾯有⼀个原⽣的crypto,但是在⼩程序⾥我们没有,所以我照着Github上的源码⼀点⼀点⽤这个库翻译过来的
还有Buffer在⼩程序⾥也没有,我使⽤这个库的⽅法代替了。
获取api的原理
⽹上很多帖⼦讲的很清楚了,这⾥推荐⼏篇⽂章,我只做⼀个简单的总结,⽅便⼤家理解这个库。
⽹易云的加密算法⼤概使⽤了两个:
1. AES加密+BASE64编码
2. RSA加密
加密⼤致流程:
1. api请求信息先被转成json字符串格式,然后再使⽤⼀个固定的密钥aes+base64编码加密,得到了第⼀个加密结果a。
2. 客户端从abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/随机⽣成⼀个新的16位密钥,然后⽤这个密钥去加
密加密结果a,得到加密结果b。
3.这样我们的数据就被双重加密了,但是我们要发给服务器去查询对应的数据,服务器知道第⼀个固定的密钥是多少,可以解开第⼀个加密结
果,但是服务器可不知道我们第⼆次加密⽤的是什么,所以服务器还需要得到我们的第⼆个⽣成的随机加密密钥。
3. 第⼆个随机加密密钥要是直接发给服务器好像就不太安全了,所以客户端对第⼆个随机加密密钥也进⾏了加密,使⽤的就是RSA加密,加密后
得到的数据我们称为c
4. 将b和c发送给服务器,服务器就会返回给我们对应的结果了。
加密核⼼代码
这段代码传⼊对象后可以直接加密成符合⽹易云api加密的结果。
// ⽣成随机数,size默认16
function createSecretKey(size) {
const keys = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let key = ""
for (let i = 0; i < size; i++) {
let pos = Math.random() * keys.length
pos = Math.floor(pos)
key = key + keys.charAt(pos)
}
return key
}
// aes加密⽅法
function aesEncrypt(word, secKey) {
let key = Utf8.parse(secKey);  //⼗六位⼗六进制数作为密钥
let iv = Utf8.parse(aes_mv);  //⼗六位⼗六进制数作为密钥偏移量
let srcs = Utf8.parse(word);
let encrypted = pt(srcs, key, { iv: iv, mode: de.CBC, padding: CryptoJS.pad.Pkcs7 });
let res = String();
console.log(res);
return res;
}
// 填充⽅法
function zfill(str, size) {
while (str.length < size) str = "0" + str
return str
}
// rsa加密⽅法
function rsaEncrypt(text, pubKey, modulus) {
const _text = text.split('').reverse().join('')
const biText = Utf8.parse(_text).toString(), 16),
biEx = bigInt(pubKey, 16),
biMod = bigInt(modulus, 16),
biRet = dPow(biEx, biMod)
return String(16), 256)
}
// 加密总⼊⼝
function Encrypt(obj) {
const text = JSON.stringify(obj)
const secKey = createSecretKey(16)
const encText = aesEncrypt(aesEncrypt(text, nonce), secKey)
const encSecKey = rsaEncrypt(secKey, pubKey, modulus)
return {
params: encText,
encSecKey: encSecKey
}
}
封装好的Api库介绍:
1. 这个库是⽤TypeScript写的,但是最后编译成了JS运⾏,但是编译后JS代码可读性很差,所以我保留了TypeScript源⽂件,就在
NetEaseCloudMusicApi/ts_src⾥⾯,应⽤库的时候不需要使⽤到
2. 关闭⼩程序开发⼯具的详情页的ES6转ES5,可以使⽤await处理异步请求(因为库是⽤Promise写的,起码要能⽤Promise,实例代码使⽤的
是await/async)
3. await关键字只能在async修饰过的函数体内部使⽤,不懂的可以查⼀下await和async的⽤法。
4. NetEaseCloudMusicApi/Libary⽂件夹⾥⾯包含了项⽬依赖的js⽂件,应⽤的时候最好整个NetEaseCloudMusicApi⽂件夹复制到项⽬⾥⾯使⽤。
5. 测试的时候可以勾选不校验合法域名。
开始使⽤之前的准备(源⽂件⽬录结构/如何导⼊)
1. 到NetEaseCloudMusicApi这个⽂件夹,⾥⾯应该包括Libary、src、ts_src三个⽂件夹,
1. Libary是我引⽤的开源库
2. ts_src中是TypeScript源⽂件(源⽂件可删除)
3. src是ts_src编译后产⽣的JavaScript⽂件夹,不考虑读ts源⽂件的话,可以把ts_src删了,但17.4 KB 的⼤⼩对应⽤包体积没有什么影响
吧,留也⾏。
2. 在要使⽤到的库中如下引⽤
const {MusicManager} = require("../../NetEaseCloudMusicApi/src/MusicManager");
    注意要⽤花括号吧MusicManager括起来,这⼀句可以需要变化的地⽅只有
../../NetEaseCloudMusicApi/src/MusicManager中的../../
后⾯的路径都代表了NetEaseCloudMusicApi⽂件夹和NetEaseCloudMusicApi⾥⾯⽂件的路径,因为我的库就是这样的结构,所以不需要改变
../../就要根据你项⽬中实际结构来改变了。
MusicManager
该类有以下⽅法:该类提供了所有获取其他对象的⽅法,可以通过该类获取其他需要的对象⽽不是new
搜索歌曲: getMusicSearchHelper()
需要参数:{keyword:"搜索歌曲关键词",limit:数字}
返回:MusicSearchHelper搜索器
例如: let musicSearchHelper = MusicSearchHelper({ keyword: "李志", limit: 10 });
获取歌曲url: getMusicUrlHelper()
需要参数:musicId(数字类型的歌曲id)
返回:MusicUrlHelperUrl获取器
搜索⽤户: getUserSearchHelper()
需要参数:{userName:"搜索⽤户的⽤户名关键词",limit:数字}
返回:UserSearchHelper⽤户查询器
获取⽤户歌单: getUserListHelper()
需要参数:userId(数字类型的⽤户id值)
返回:UserListHelper⽤户列表查询器
获取我喜欢的歌单: getUserListDetailHelper()
需要参数:listId(数字类型的列表id)
返回:UserListDetailHelper⽤户列表详情信息获取器
MusicSearchHelper
⽤于搜索⾳乐
可⽤⽅法:
getSearchResult()---获取数据(默认第⼀页)
nextPage()--- 下⼀页
previousPage()---上⼀页
getCurrentPage()---查看当前页数的
执⾏完切换页数后需要再次调⽤getSearchResult⽅法查看新的查询结果。
MusicUrlHelper
⽤于将搜索⾳乐结果中的id转换为url播放链接
可⽤⽅法:
网易云怎么一起听音乐
getUrlResult() ---获取url播放链接
UserSearchHelper
⽤于根据⽤户名关键字搜索⽤户
可⽤⽅法:
getSearchResult()---获取搜索结果
UserListHelper
⽤于获取⽤户id后根据id获取⽤户歌单信息
可⽤⽅法:
getAllLists()---获取⽤户所有歌单
getILikeList()---获取⽤户的我喜欢歌单
UserListDetailHelper
⽤于获取歌单id后获取歌单内歌曲列表
可⽤⽅法:
getDeatil()---获取歌单内列表
搜索歌曲
1. 通过MusicManager获取⼀个MusicSearchHelper搜索器
2. MusicSearchHelper的⽅法:
getSearchResult()---获取数据(默认第⼀页)
nextPage()--- 下⼀页
previousPage()---上⼀页
getCurrentPage()---查看当前页数的
3. 执⾏完切换页数后需要再次调⽤getSearchResult⽅法查看新的查询结果。
代码实例
const {MusicManager} = require("../../NetEaseCloudMusicApi/src/MusicManager");
async function test(){
// 搜索歌曲
let musicSearchHelper = MusicSearchHelper({ keyword: "one more time one more chance", limit: 10 });
console.log(`现在是第${CurrentPage()}页`);
console.log(SearchResult());
console.log(`现在是第${CurrentPage()}页`);
console.log(SearchResult());
musicSearchHelper.previousPage();
console.log(`现在是第${CurrentPage()}页`);
console.log(SearchResult());
console.log(musicSearchHelper);
}
test();
通过搜索歌曲的结果获取⾳乐Url
有了搜索结果,我们还需要url才能播放资源
1. 通过MusicManager获取⼀个MusicUrlHelperUrl获取器
2. 通过MusicUrlHelper的getUrlResult⽅法获取url
3. 需要注意的是,由于⽹易云接⼝时常返回空回复,所以这⾥我通过20以内的重复次请求直到有结果就停⽌,如果20次以后还是没有结果(据我
测试20次以内都请求到结果了),也就是返回⼀个空的字符串"",需要使⽤者⾃⼰重新调⽤⼀次urlHelper的getUrlResult⽅法(2019.04.27)现在不会返回空值了,返回空值发现问题出在使⽤请求时⾃作聪明将json转成了a=xxxx&b=xxx的格式,导致不能正常转换请求数据,现在每次请求都能获取结果。
代码实例
const {MusicManager} = require("../../NetEaseCloudMusicApi/src/MusicManager");
async function test(){
// 搜索歌曲
let musicSearchHelper = MusicSearchHelper({ keyword: "one more time one more chance", limit: 10 });
console.log(`现在是第${CurrentPage()}页`);
console.log(SearchResult());
console.log(`现在是第${CurrentPage()}页`);
console.log(SearchResult());
musicSearchHelper.previousPage();
console.log(`现在是第${CurrentPage()}页`);
console.log(SearchResult());
console.log(musicSearchHelper);
// 获取歌曲url
let songs = SearchResult();
let musicId  = songs[0].id;
let musicUrlHelper = MusicUrlHelper(musicId);
console.log(`歌曲的ID是:${musicId}`);
let url = UrlResult();
console.log(`歌曲的url链接是:${url}`);
}
test();
4.26更新
新增搜索⽤户以及⽤户歌单获取接⼝
搜索⽤户
1. 通过MusicManager获取⼀个UserSearchHelper⽤户查询器
2. 通过UserSearchHelper的getSearchResult()⽅法获取搜索结果
async function test(){
/
/ 搜索⽤户
let userSearchHelper = UserSearchHelper({ userName: "JabinGP", limit: 20 });
let users = SearchResult();
console.log(users);
}
获取⽤户歌单
1. 通过MusicManager获取⼀个UserListHelper⽤户查询器
2. 通过UserListHelper的
getILikeList() ---获取我喜欢歌单,返回⼀个列表对象
getAllLists()---获取所有歌单,返回⼀个列表对象的数组
async function test(){
/
/ 搜索⽤户
let userSearchHelper = UserSearchHelper({ userName: "JabinGP", limit: 20 });
let users = SearchResult();
console.log(users);
// 获取我喜欢歌单
let userListHelper = UserListHelper(users[0].userId);
let iLikeList = ILikeList()
console.log(iLikeList);
}
通过歌单⾥的Id获取歌曲url
与前⾯⼀致,不再赘述
完整实例
完整实例代码在项⽬page下的index.js中,运⾏项⽬就会⾃动执⾏输出结果。
async function test(){
// 搜索歌曲
let musicSearchHelper = MusicSearchHelper({ keyword: "one more time one more chance", limit: 10 });    console.log(`现在是第${CurrentPage()}页`);
console.log(SearchResult());
console.log(`现在是第${CurrentPage()}页`);
console.log(SearchResult());
musicSearchHelper.previousPage();
console.log(`现在是第${CurrentPage()}页`);
console.log(SearchResult());
console.log(musicSearchHelper);
// 获取歌曲url
let songs = SearchResult();
let musicId  = songs[0].id;
let musicUrlHelper = MusicUrlHelper(musicId);
console.log(`歌曲的ID是:${musicId}`);
let url = UrlResult();
console.log(`歌曲的url链接是:${url}`);
// 搜索⽤户
let userSearchHelper = UserSearchHelper({ userName: "JabinGP", limit: 20 });
let users = SearchResult();
console.log(users);