摘要:之前我们已经开发过一款小程序适用的音乐库,这次开发网易云音乐库的原因是音乐库在小程序中环境下无法使用小程序提供的背景音频播放器播放的问题网易云的加密算法真的比其他几家复杂太多了。。。
之前我们已经开发过一款小程序适用的qq音乐api库https://github.com/FisherWY/Q...,这次开发网易云音乐api库的原因是qq音乐api库在小程序中iOS环境下无法使用小程序提供的背景音频播放器播放的问题依赖网易云的加密算法真的比其他几家api复杂太多了。。。完爆QQ和酷狗
想要直接用的话可以到Github直接取我封装好的api库。
Github地址https://github.com/JabinGP/Ne...
本api库参考了Github上面开源的node库,因为我们只想要查找音乐和播放音乐这两个功能,虽然Github那个库很方便,但是我们不想为了两个接口特意去跑一个node.js服务。Github上的库
big-integer.js
这里注意,不要使用最新版的,最新版的库再模拟器上运行没有问题,但是在真机调试的上传包阶段会报错说无法识别big-integer.js,最后在我的尝试下,选用了一个老版本的库解决了这个问题。
crypto-js
这个库是用来aes加密的,在node上面有一个原生的crypto,但是在小程序里我们没有,所以我照着Github上的源码一点一点用这个库翻译过来的,还有Buffer在小程序里也没有,我使用这个库的方法代替了。
获取api的原理网上很多帖子讲的很清楚了,这里推荐几篇文章,我只做一个简单的总结,方便大家理解这个库。
网易云的加密算法大概使用了两个:
AES加密+BASE64编码
RSA加密
加密大致流程:
api请求信息先被转成json字符串格式,然后再使用一个固定的密钥aes+base64编码加密,得到了第一个加密结果a。
客户端从abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/随机生成一个新的16位密钥,然后用这个密钥去加密加密结果a,得到加密结果b。
3.这样我们的数据就被双重加密了,但是我们要发给服务器去查询对应的数据,服务器知道第一个固定的密钥是多少,可以解开第一个加密结果,但是服务器可不知道我们第二次加密用的是什么,所以服务器还需要得到我们的第二个生成的随机加密密钥。
第二个随机加密密钥要是直接发给服务器好像就不太安全了,所以客户端对第二个随机加密密钥也进行了加密,使用的就是RSA加密,加密后得到的数据我们称为c
将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 = CryptoJS.enc.Utf8.parse(secKey); //十六位十六进制数作为密钥 let iv = CryptoJS.enc.Utf8.parse(aes_mv); //十六位十六进制数作为密钥偏移量 let srcs = CryptoJS.enc.Utf8.parse(word); let encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); let res = encrypted.toString(); 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 = bigInt(CryptoJS.enc.Utf8.parse(_text).toString(), 16), biEx = bigInt(pubKey, 16), biMod = bigInt(modulus, 16), biRet = biText.modPow(biEx, biMod) return zfill(biRet.toString(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库
首先到Github下载我的Api库https://github.com/JabinGP/Ne...
下载完成后,这个库应该是可以直接导入微信小程序开发工具运行的,但是有几个注意事项
这个库是用TypeScript写的,但是最后编译成了JS运行,但是编译后JS代码可读性很差,所以我保留了TypeScript源文件,就在NetEaseCloudMusicApi/ts_src里面,应用库的时候不需要使用到
关闭小程序开发工具的详情页的ES6转ES5,可以使用await处理异步请求(因为库是用Promise写的,起码要能用Promise,实例代码使用的是await/async)
await关键字只能在async修饰过的函数体内部使用,不懂的可以查一下await和async的用法。
NetEaseCloudMusicApi/Libary文件夹里面包含了项目依赖的js文件,应用的时候最好整个NetEaseCloudMusicApi文件夹复制到项目里面使用。
测试的时候可以勾选不校验合法域名。
开始使用之前的准备找到NetEaseCloudMusicApi这个文件夹,里面应该包括Libary、src、ts_src三个文件夹,Libary是我引用的开源库,ts_src中是TypeScript源文件,src是ts_src编译后产生的JavaScript文件夹,也就是说不考虑读ts源文件的话,可以把ts_src删了,但是17.4 KB 的大小对应用包体积应该没有什么影响吧,留着也行。
在要使用到的库中如下引用
const {MusicManager} = require("../../NetEaseCloudMusicApi/src/MusicManager");
注意要用花括号吧MusicManager括起来,这一句可以需要变化的地方只有
../../NetEaseCloudMusicApi/src/MusicManager中的../../,后面的路径都代表了NetEaseCloudMusicApi文件夹和NetEaseCloudMusicApi里面文件的路径,因为我的库就是这样的结构,所以不需要改变,../../就要根据你项目中实际结构来改变了。
该类有以下方法:该类提供了所有获取其他对象的方法,可以通过该类获取其他需要的对象而不是new
getMusicSearchHelper()
需要参数:{keyword:"搜索歌曲关键词",limit:数字}
返回:MusicSearchHelper搜索器
getMusicUrlHelper()
需要参数:musicId(数字类型的歌曲id)
返回:MusicUrlHelperUrl获取器
getUserSearchHelper()
需要参数:{userName:"搜索用户的用户名关键词",limit:数字}
返回:UserSearchHelper用户查询器
getUserListHelper()
需要参数:userId(数字类型的用户id值)
返回:UserListHelper用户列表查询器
getUserListDetailHelper()
需要参数:listId(数字类型的列表id)
返回:UserListDetailHelper用户列表详情信息获取器
用于搜索音乐
可用方法:
getSearchResult()---获取数据(默认第一页)
nextPage()--- 下一页
previousPage()---上一页
getCurrentPage()---查看当前页数的
执行完切换页数后需要再次调用getSearchResult方法查看新的查询结果。
MusicUrlHelper用于将搜索音乐结果中的id转换为url播放链接
可用方法:
getUrlResult() ---获取url播放链接
UserSearchHelper用于根据用户名关键字搜索用户
可用方法:
getSearchResult()---获取搜索结果
UserListHelper用于获取用户id后根据id获取用户歌单信息
可用方法:
getAllLists()---获取用户所有歌单
getILikeList()---获取用户的我喜欢歌单
UserListDetailHelper用于获取歌单id后获取歌单内歌曲列表
可用方法:
getDeatil()---获取歌单内列表
搜索歌曲通过MusicManager获取一个MusicSearchHelper搜索器
MusicSearchHelper的方法:
getSearchResult()---获取数据(默认第一页)
nextPage()--- 下一页
previousPage()---上一页
getCurrentPage()---查看当前页数的
执行完切换页数后需要再次调用getSearchResult方法查看新的查询结果。
代码实例
const {MusicManager} = require("../../NetEaseCloudMusicApi/src/MusicManager"); async function test(){ // 搜索歌曲 let musicSearchHelper = MusicManager.getMusicSearchHelper({ keyword: "one more time one more chance", limit: 10 }); console.log(`现在是第${musicSearchHelper.getCurrentPage()}页`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.nextPage(); console.log(`现在是第${musicSearchHelper.getCurrentPage()}页`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.previousPage(); console.log(`现在是第${musicSearchHelper.getCurrentPage()}页`); console.log(await musicSearchHelper.getSearchResult()); console.log(musicSearchHelper); } test();通过搜索歌曲的结果获取音乐Url
有了搜索结果,我们还需要url才能播放资源
通过MusicManager获取一个MusicUrlHelperUrl获取器
通过MusicUrlHelper的getUrlResult方法获取url
需要注意的是,由于网易云接口时常返回空回复,所以这里我通过20以内的重复次请求直到有结果就停止,如果20次以后还是没有结果(据我测试20次以内都请求到结果了),也就是返回一个空的字符串"",需要使用者自己重新调用一次urlHelper的getUrlResult方法(2019.04.27)现在不会返回空值了,返回空值发现问题出在使用微信请求时自作聪明将json转成了a=xxxx&b=xxx的格式,导致微信不能正常转换请求数据,现在每次请求都能获取结果。
代码实例
const {MusicManager} = require("../../NetEaseCloudMusicApi/src/MusicManager"); async function test(){ // 搜索歌曲 let musicSearchHelper = MusicManager.getMusicSearchHelper({ keyword: "one more time one more chance", limit: 10 }); console.log(`现在是第${musicSearchHelper.getCurrentPage()}页`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.nextPage(); console.log(`现在是第${musicSearchHelper.getCurrentPage()}页`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.previousPage(); console.log(`现在是第${musicSearchHelper.getCurrentPage()}页`); console.log(await musicSearchHelper.getSearchResult()); console.log(musicSearchHelper); // 获取歌曲url let songs = await musicSearchHelper.getSearchResult(); let musicId = songs[0].id; let musicUrlHelper = MusicManager.getMusicUrlHelper(musicId); console.log(`歌曲的ID是:${musicId}`); let url = await musicUrlHelper.getUrlResult(); console.log(`歌曲的url链接是:${url}`); } test();4.26更新
新增搜索用户以及用户歌单获取接口
搜索用户通过MusicManager获取一个UserSearchHelper用户查询器
通过UserSearchHelper的getSearchResult()方法获取搜索结果
async function test(){ // 搜索用户 let userSearchHelper = MusicManager.getUserSearchHelper({ userName: "JabinGP", limit: 20 }); let users = await userSearchHelper.getSearchResult(); console.log(users); }获取用户歌单
通过MusicManager获取一个UserListHelper用户查询器
通过UserListHelper的
getILikeList() ---获取我喜欢歌单,返回一个列表对象
getAllLists() ---获取所有歌单,返回一个列表对象的数组
async function test(){ // 搜索用户 let userSearchHelper = MusicManager.getUserSearchHelper({ userName: "JabinGP", limit: 20 }); let users = await userSearchHelper.getSearchResult(); console.log(users); // 获取我喜欢歌单 let userListHelper = MusicManager.getUserListHelper(users[0].userId); let iLikeList = await userListHelper.getILikeList() console.log(iLikeList); }通过歌单里的Id获取歌曲url
与前面一致,不再赘述
完整实例完整实例代码在项目page下的index.js中,运行项目就会自动执行输出结果。
async function test(){ // 搜索歌曲 let musicSearchHelper = MusicManager.getMusicSearchHelper({ keyword: "one more time one more chance", limit: 10 }); console.log(`现在是第${musicSearchHelper.getCurrentPage()}页`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.nextPage(); console.log(`现在是第${musicSearchHelper.getCurrentPage()}页`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.previousPage(); console.log(`现在是第${musicSearchHelper.getCurrentPage()}页`); console.log(await musicSearchHelper.getSearchResult()); console.log(musicSearchHelper); // 获取歌曲url let songs = await musicSearchHelper.getSearchResult(); let musicId = songs[0].id; let musicUrlHelper = MusicManager.getMusicUrlHelper(musicId); console.log(`歌曲的ID是:${musicId}`); let url = await musicUrlHelper.getUrlResult(); console.log(`歌曲的url链接是:${url}`); // 搜索用户 let userSearchHelper = MusicManager.getUserSearchHelper({ userName: "JabinGP", limit: 20 }); let users = await userSearchHelper.getSearchResult(); console.log(users); // 获取用户歌单 let userListHelper = MusicManager.getUserListHelper(users[0].userId); let iLikeList = await userListHelper.getILikeList() console.log(iLikeList); // 获取我喜欢歌单 let userListDeatilHelper = MusicManager.getUserListDetailHelper(iLikeList.id); let listDetail = await userListDeatilHelper.getDeatil(); console.log(listDetail); let timer=0; for(let song of listDetail.tracks){ musicUrlHelper.musicId=song.id; console.log(`歌曲的ID是:${musicUrlHelper.musicId}`); let url2 = await musicUrlHelper.getUrlResult(); console.log(`歌曲的url链接是:${url2}`); if(timer++>20)break; } } test();结尾
2019 4.25目前就只有这两个接口,因为我们项目就只需要这两个接口,如果有需要更多接口的,可以在下方评论,以上示例代码都在Github项目上的index.js中,也就是你把文件导入微信开发者工具后,取消勾选一下详情的ES6转ES5以及取消勾选合法域名检验,就可以在控制台看到以上示例代码的输出了2019 4.26更新搜索用户和获取用户歌单以及获取歌单详细三个接口。
如果对你有帮助,点个Star吧~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/104093.html
摘要:下一步准备使用网易云代替音乐。已经开发新的网易云代替音乐了,需要的可以看看这篇文章为微信小程序开发的网易云音乐库 项目要做一个可以为日记添加音乐的小程序,所以要用到音乐api,参考了一些文章后我们封装了一个qq音乐api库(完成了动态token获取,音乐搜索,音乐专辑图片,音乐名称,歌手名称,播放),有需要的可以到Github自提。 小程序qq音乐api库Gihub地址https://...
摘要:传统的网页编程采用的三剑客来实现,在微信小程序中同样有三剑客。观察者模式不难实现,重点是如何在微信小程序中搭配其特有的生命周期来使用。交互事件传统的事件传递类型有冒泡型与捕获型,微信小程序中自然也有。 本文由作者邹永胜授权网易云社区发布。 简介为了更好的展示我们即时通讯SDK强悍的能力,网易云信IM SDK微信小程序DEMO的开发就提上了日程。用产品的话说就是: 云信 IM 小程序 S...
摘要:狗蛋狗蛋是基于微信小程序开发的一款。请在微信开发设置中加入合法域名或者在开发设置中勾选不校验合法域名业务域名版本以及证书。感谢与支持狗蛋豆瓣音乐项目介绍狗蛋是基于微信小程序进行开发,能同时运行在环境下。 狗蛋TV showImg(https://segmentfault.com/img/bVbazwL); 狗蛋TV是基于微信小程序开发的一款App。gordanLee每天都会推荐一首歌、...
阅读 2222·2021-09-24 10:31
阅读 3875·2021-09-22 15:16
阅读 3395·2021-09-22 10:02
阅读 1010·2021-09-22 10:02
阅读 1822·2021-09-08 09:36
阅读 1974·2019-08-30 14:18
阅读 608·2019-08-30 10:51
阅读 1862·2019-08-29 11:08