摘要:之前我們已經(jīng)開發(fā)過一款小程序適用的音樂庫,這次開發(fā)網(wǎng)易云音樂庫的原因是音樂庫在小程序中環(huán)境下無法使用小程序提供的背景音頻播放器播放的問題網(wǎng)易云的加密算法真的比其他幾家復(fù)雜太多了。。。
之前我們已經(jīng)開發(fā)過一款小程序適用的qq音樂api庫https://github.com/FisherWY/Q...,這次開發(fā)網(wǎng)易云音樂api庫的原因是qq音樂api庫在小程序中iOS環(huán)境下無法使用小程序提供的背景音頻播放器播放的問題依賴網(wǎng)易云的加密算法真的比其他幾家api復(fù)雜太多了。。。完爆QQ和酷狗
想要直接用的話可以到Github直接取我封裝好的api庫。
Github地址https://github.com/JabinGP/Ne...
本api庫參考了Github上面開源的node庫,因?yàn)槲覀冎幌胍檎乙魳泛筒シ乓魳愤@兩個(gè)功能,雖然Github那個(gè)庫很方便,但是我們不想為了兩個(gè)接口特意去跑一個(gè)node.js服務(wù)。Github上的庫
big-integer.js
這里注意,不要使用最新版的,最新版的庫再模擬器上運(yùn)行沒有問題,但是在真機(jī)調(diào)試的上傳包階段會(huì)報(bào)錯(cuò)說無法識(shí)別big-integer.js,最后在我的嘗試下,選用了一個(gè)老版本的庫解決了這個(gè)問題。
crypto-js
這個(gè)庫是用來aes加密的,在node上面有一個(gè)原生的crypto,但是在小程序里我們沒有,所以我照著Github上的源碼一點(diǎn)一點(diǎn)用這個(gè)庫翻譯過來的,還有Buffer在小程序里也沒有,我使用這個(gè)庫的方法代替了。
獲取api的原理網(wǎng)上很多帖子講的很清楚了,這里推薦幾篇文章,我只做一個(gè)簡(jiǎn)單的總結(jié),方便大家理解這個(gè)庫。
網(wǎng)易云的加密算法大概使用了兩個(gè):
AES加密+BASE64編碼
RSA加密
加密大致流程:
api請(qǐng)求信息先被轉(zhuǎn)成json字符串格式,然后再使用一個(gè)固定的密鑰aes+base64編碼加密,得到了第一個(gè)加密結(jié)果a。
客戶端從abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/隨機(jī)生成一個(gè)新的16位密鑰,然后用這個(gè)密鑰去加密加密結(jié)果a,得到加密結(jié)果b。
3.這樣我們的數(shù)據(jù)就被雙重加密了,但是我們要發(fā)給服務(wù)器去查詢對(duì)應(yīng)的數(shù)據(jù),服務(wù)器知道第一個(gè)固定的密鑰是多少,可以解開第一個(gè)加密結(jié)果,但是服務(wù)器可不知道我們第二次加密用的是什么,所以服務(wù)器還需要得到我們的第二個(gè)生成的隨機(jī)加密密鑰。
第二個(gè)隨機(jī)加密密鑰要是直接發(fā)給服務(wù)器好像就不太安全了,所以客戶端對(duì)第二個(gè)隨機(jī)加密密鑰也進(jìn)行了加密,使用的就是RSA加密,加密后得到的數(shù)據(jù)我們稱為c
將b和c發(fā)送給服務(wù)器,服務(wù)器就會(huì)返回給我們對(duì)應(yīng)的結(jié)果了。
加密核心代碼這段代碼傳入對(duì)象后可以直接加密成符合網(wǎng)易云api加密的結(jié)果。
// 生成隨機(jī)數(shù),size默認(rèn)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); //十六位十六進(jìn)制數(shù)作為密鑰 let iv = CryptoJS.enc.Utf8.parse(aes_mv); //十六位十六進(jìn)制數(shù)作為密鑰偏移量 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) } // 加密總?cè)肟?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...
下載完成后,這個(gè)庫應(yīng)該是可以直接導(dǎo)入微信小程序開發(fā)工具運(yùn)行的,但是有幾個(gè)注意事項(xiàng)
這個(gè)庫是用TypeScript寫的,但是最后編譯成了JS運(yùn)行,但是編譯后JS代碼可讀性很差,所以我保留了TypeScript源文件,就在NetEaseCloudMusicApi/ts_src里面,應(yīng)用庫的時(shí)候不需要使用到
關(guān)閉小程序開發(fā)工具的詳情頁的ES6轉(zhuǎn)ES5,可以使用await處理異步請(qǐng)求(因?yàn)閹焓怯?b>Promise寫的,起碼要能用Promise,實(shí)例代碼使用的是await/async)
await關(guān)鍵字只能在async修飾過的函數(shù)體內(nèi)部使用,不懂的可以查一下await和async的用法。
NetEaseCloudMusicApi/Libary文件夾里面包含了項(xiàng)目依賴的js文件,應(yīng)用的時(shí)候最好整個(gè)NetEaseCloudMusicApi文件夾復(fù)制到項(xiàng)目里面使用。
測(cè)試的時(shí)候可以勾選不校驗(yàn)合法域名。
開始使用之前的準(zhǔn)備找到NetEaseCloudMusicApi這個(gè)文件夾,里面應(yīng)該包括Libary、src、ts_src三個(gè)文件夾,Libary是我引用的開源庫,ts_src中是TypeScript源文件,src是ts_src編譯后產(chǎn)生的JavaScript文件夾,也就是說不考慮讀ts源文件的話,可以把ts_src刪了,但是17.4 KB 的大小對(duì)應(yīng)用包體積應(yīng)該沒有什么影響吧,留著也行。
在要使用到的庫中如下引用
const {MusicManager} = require("../../NetEaseCloudMusicApi/src/MusicManager");
注意要用花括號(hào)吧MusicManager括起來,這一句可以需要變化的地方只有
../../NetEaseCloudMusicApi/src/MusicManager中的../../,后面的路徑都代表了NetEaseCloudMusicApi文件夾和NetEaseCloudMusicApi里面文件的路徑,因?yàn)槲业膸炀褪沁@樣的結(jié)構(gòu),所以不需要改變,../../就要根據(jù)你項(xiàng)目中實(shí)際結(jié)構(gòu)來改變了。
該類有以下方法:該類提供了所有獲取其他對(duì)象的方法,可以通過該類獲取其他需要的對(duì)象而不是new
getMusicSearchHelper()
需要參數(shù):{keyword:"搜索歌曲關(guān)鍵詞",limit:數(shù)字}
返回:MusicSearchHelper搜索器
getMusicUrlHelper()
需要參數(shù):musicId(數(shù)字類型的歌曲id)
返回:MusicUrlHelperUrl獲取器
getUserSearchHelper()
需要參數(shù):{userName:"搜索用戶的用戶名關(guān)鍵詞",limit:數(shù)字}
返回:UserSearchHelper用戶查詢器
getUserListHelper()
需要參數(shù):userId(數(shù)字類型的用戶id值)
返回:UserListHelper用戶列表查詢器
getUserListDetailHelper()
需要參數(shù):listId(數(shù)字類型的列表id)
返回:UserListDetailHelper用戶列表詳情信息獲取器
用于搜索音樂
可用方法:
getSearchResult()---獲取數(shù)據(jù)(默認(rèn)第一頁)
nextPage()--- 下一頁
previousPage()---上一頁
getCurrentPage()---查看當(dāng)前頁數(shù)的
執(zhí)行完切換頁數(shù)后需要再次調(diào)用getSearchResult方法查看新的查詢結(jié)果。
MusicUrlHelper用于將搜索音樂結(jié)果中的id轉(zhuǎn)換為url播放鏈接
可用方法:
getUrlResult() ---獲取url播放鏈接
UserSearchHelper用于根據(jù)用戶名關(guān)鍵字搜索用戶
可用方法:
getSearchResult()---獲取搜索結(jié)果
UserListHelper用于獲取用戶id后根據(jù)id獲取用戶歌單信息
可用方法:
getAllLists()---獲取用戶所有歌單
getILikeList()---獲取用戶的我喜歡歌單
UserListDetailHelper用于獲取歌單id后獲取歌單內(nèi)歌曲列表
可用方法:
getDeatil()---獲取歌單內(nèi)列表
搜索歌曲通過MusicManager獲取一個(gè)MusicSearchHelper搜索器
MusicSearchHelper的方法:
getSearchResult()---獲取數(shù)據(jù)(默認(rèn)第一頁)
nextPage()--- 下一頁
previousPage()---上一頁
getCurrentPage()---查看當(dāng)前頁數(shù)的
執(zhí)行完切換頁數(shù)后需要再次調(diào)用getSearchResult方法查看新的查詢結(jié)果。
代碼實(shí)例
const {MusicManager} = require("../../NetEaseCloudMusicApi/src/MusicManager"); async function test(){ // 搜索歌曲 let musicSearchHelper = MusicManager.getMusicSearchHelper({ keyword: "one more time one more chance", limit: 10 }); console.log(`現(xiàn)在是第${musicSearchHelper.getCurrentPage()}頁`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.nextPage(); console.log(`現(xiàn)在是第${musicSearchHelper.getCurrentPage()}頁`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.previousPage(); console.log(`現(xiàn)在是第${musicSearchHelper.getCurrentPage()}頁`); console.log(await musicSearchHelper.getSearchResult()); console.log(musicSearchHelper); } test();通過搜索歌曲的結(jié)果獲取音樂Url
有了搜索結(jié)果,我們還需要url才能播放資源
通過MusicManager獲取一個(gè)MusicUrlHelperUrl獲取器
通過MusicUrlHelper的getUrlResult方法獲取url
需要注意的是,由于網(wǎng)易云接口時(shí)常返回空回復(fù),所以這里我通過20以內(nèi)的重復(fù)次請(qǐng)求直到有結(jié)果就停止,如果20次以后還是沒有結(jié)果(據(jù)我測(cè)試20次以內(nèi)都請(qǐng)求到結(jié)果了),也就是返回一個(gè)空的字符串"",需要使用者自己重新調(diào)用一次urlHelper的getUrlResult方法(2019.04.27)現(xiàn)在不會(huì)返回空值了,返回空值發(fā)現(xiàn)問題出在使用微信請(qǐng)求時(shí)自作聰明將json轉(zhuǎn)成了a=xxxx&b=xxx的格式,導(dǎo)致微信不能正常轉(zhuǎn)換請(qǐng)求數(shù)據(jù),現(xiàn)在每次請(qǐng)求都能獲取結(jié)果。
代碼實(shí)例
const {MusicManager} = require("../../NetEaseCloudMusicApi/src/MusicManager"); async function test(){ // 搜索歌曲 let musicSearchHelper = MusicManager.getMusicSearchHelper({ keyword: "one more time one more chance", limit: 10 }); console.log(`現(xiàn)在是第${musicSearchHelper.getCurrentPage()}頁`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.nextPage(); console.log(`現(xiàn)在是第${musicSearchHelper.getCurrentPage()}頁`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.previousPage(); console.log(`現(xiàn)在是第${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獲取一個(gè)UserSearchHelper用戶查詢器
通過UserSearchHelper的getSearchResult()方法獲取搜索結(jié)果
async function test(){ // 搜索用戶 let userSearchHelper = MusicManager.getUserSearchHelper({ userName: "JabinGP", limit: 20 }); let users = await userSearchHelper.getSearchResult(); console.log(users); }獲取用戶歌單
通過MusicManager獲取一個(gè)UserListHelper用戶查詢器
通過UserListHelper的
getILikeList() ---獲取我喜歡歌單,返回一個(gè)列表對(duì)象
getAllLists() ---獲取所有歌單,返回一個(gè)列表對(duì)象的數(shù)組
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
與前面一致,不再贅述
完整實(shí)例完整實(shí)例代碼在項(xiàng)目page下的index.js中,運(yùn)行項(xiàng)目就會(huì)自動(dòng)執(zhí)行輸出結(jié)果。
async function test(){ // 搜索歌曲 let musicSearchHelper = MusicManager.getMusicSearchHelper({ keyword: "one more time one more chance", limit: 10 }); console.log(`現(xiàn)在是第${musicSearchHelper.getCurrentPage()}頁`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.nextPage(); console.log(`現(xiàn)在是第${musicSearchHelper.getCurrentPage()}頁`); console.log(await musicSearchHelper.getSearchResult()); musicSearchHelper.previousPage(); console.log(`現(xiàn)在是第${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();結(jié)尾
2019 4.25目前就只有這兩個(gè)接口,因?yàn)槲覀冺?xiàng)目就只需要這兩個(gè)接口,如果有需要更多接口的,可以在下方評(píng)論,以上示例代碼都在Github項(xiàng)目上的index.js中,也就是你把文件導(dǎo)入微信開發(fā)者工具后,取消勾選一下詳情的ES6轉(zhuǎn)ES5以及取消勾選合法域名檢驗(yàn),就可以在控制臺(tái)看到以上示例代碼的輸出了2019 4.26更新搜索用戶和獲取用戶歌單以及獲取歌單詳細(xì)三個(gè)接口。
如果對(duì)你有幫助,點(diǎn)個(gè)Star吧~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/104093.html
摘要:下一步準(zhǔn)備使用網(wǎng)易云代替音樂。已經(jīng)開發(fā)新的網(wǎng)易云代替音樂了,需要的可以看看這篇文章為微信小程序開發(fā)的網(wǎng)易云音樂庫 項(xiàng)目要做一個(gè)可以為日記添加音樂的小程序,所以要用到音樂api,參考了一些文章后我們封裝了一個(gè)qq音樂api庫(完成了動(dòng)態(tài)token獲取,音樂搜索,音樂專輯圖片,音樂名稱,歌手名稱,播放),有需要的可以到Github自提。 小程序qq音樂api庫Gihub地址https://...
awesome-github-wechat-weapp 是由OpenDigg整理并維護(hù)的微信小程序開源項(xiàng)目庫集合。我們會(huì)定期同步上的項(xiàng)目到這里,也歡迎各位 UI組件開發(fā)框架實(shí)用庫開發(fā)工具服務(wù)端項(xiàng)目實(shí)例Demo UI組件 weui-wxss ★1873 - 同微信原生視覺體驗(yàn)一致的基礎(chǔ)樣式庫zanui-weapp ★794 - 好用易擴(kuò)展的小程序 UI 庫wx-charts ★449 - 微信小程...
摘要:傳統(tǒng)的網(wǎng)頁編程采用的三劍客來實(shí)現(xiàn),在微信小程序中同樣有三劍客。觀察者模式不難實(shí)現(xiàn),重點(diǎn)是如何在微信小程序中搭配其特有的生命周期來使用。交互事件傳統(tǒng)的事件傳遞類型有冒泡型與捕獲型,微信小程序中自然也有。 本文由作者鄒永勝授權(quán)網(wǎng)易云社區(qū)發(fā)布。 簡(jiǎn)介為了更好的展示我們即時(shí)通訊SDK強(qiáng)悍的能力,網(wǎng)易云信IM SDK微信小程序DEMO的開發(fā)就提上了日程。用產(chǎn)品的話說就是: 云信 IM 小程序 S...
摘要:狗蛋狗蛋是基于微信小程序開發(fā)的一款。請(qǐng)?jiān)谖⑿砰_發(fā)設(shè)置中加入合法域名或者在開發(fā)設(shè)置中勾選不校驗(yàn)合法域名業(yè)務(wù)域名版本以及證書。感謝與支持狗蛋豆瓣音樂項(xiàng)目介紹狗蛋是基于微信小程序進(jìn)行開發(fā),能同時(shí)運(yùn)行在環(huán)境下。 狗蛋TV showImg(https://segmentfault.com/img/bVbazwL); 狗蛋TV是基于微信小程序開發(fā)的一款A(yù)pp。gordanLee每天都會(huì)推薦一首歌、...
閱讀 2237·2021-09-24 10:31
閱讀 3887·2021-09-22 15:16
閱讀 3408·2021-09-22 10:02
閱讀 1022·2021-09-22 10:02
閱讀 1837·2021-09-08 09:36
閱讀 1982·2019-08-30 14:18
閱讀 616·2019-08-30 10:51
閱讀 1876·2019-08-29 11:08