爲微信小程序開發的網易雲音樂api庫

以前咱們已經開發過一款小程序適用的qq音樂api庫 https://github.com/FisherWY/Q...,此次開發網易雲音樂api庫的緣由是qq音樂api庫在小程序中iOS環境下沒法使用小程序提供的背景音頻播放器播放的問題

網易雲的加密算法真的比其餘幾家api複雜太多了。。。完爆QQ和酷狗
想要直接用的話能夠到Github直接取我封裝好的api庫。
Github地址https://github.com/JabinGP/Ne...javascript

依賴

本api庫參考了Github上面開源的node庫,由於咱們只想要查找音樂和播放音樂這兩個功能,雖然Github那個庫很方便,可是咱們不想爲了兩個接口特地去跑一個node.js服務。Github上的庫java

  1. big-integer.js
    這裏注意,不要使用最新版的,最新版的庫再模擬器上運行沒有問題,可是在真機調試的上傳包階段會報錯說沒法識別big-integer.js,最後在個人嘗試下,選用了一個老版本的庫解決了這個問題。
  2. crypto-js

這個庫是用來aes加密的,在node上面有一個原生的crypto,可是在小程序裏咱們沒有,因此我照着Github上的源碼一點一點用這個庫翻譯過來的,還有Buffer在小程序裏也沒有,我使用這個庫的方法代替了。node

獲取api的原理

網上不少帖子講的很清楚了,這裏推薦幾篇文章,我只作一個簡單的總結,方便你們理解這個庫。
網易雲的加密算法大概使用了兩個:git

  1. AES加密+BASE64編碼
  2. RSA加密

加密大體流程:github

  1. api請求信息先被轉成json字符串格式,而後再使用一個固定的密鑰aes+base64編碼加密,獲得了第一個加密結果a
  2. 客戶端從abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/隨機生成一個新的16位密鑰,而後用這個密鑰去加密加密結果a,獲得加密結果b

3.這樣咱們的數據就被雙重加密了,可是咱們要發給服務器去查詢對應的數據,服務器知道第一個固定的密鑰是多少,能夠解開第一個加密結果,可是服務器可不知道咱們第二次加密用的是什麼,因此服務器還須要獲得咱們的第二個生成的隨機加密密鑰。算法

  1. 第二個隨機加密密鑰要是直接發給服務器好像就不太安全了,因此客戶端對第二個隨機加密密鑰也進行了加密,使用的就是RSA加密,加密後獲得的數據咱們稱爲c
  2. bc發送給服務器,服務器就會返回給咱們對應的結果了。

加密核心代碼

這段代碼傳入對象後能夠直接加密成符合網易雲api加密的結果。json

// 生成隨機數,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...
下載完成後,這個庫應該是能夠直接導入微信小程序開發工具運行的,可是有幾個注意事項小程序

  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

開始使用以前的準備

  1. 找到NetEaseCloudMusicApi這個文件夾,裏面應該包括Libary、src、ts_src三個文件夾,Libary是我引用的開源庫,ts_src中是TypeScript源文件,src是ts_src編譯後產生的JavaScript文件夾,也就是說不考慮讀ts源文件的話,能夠把ts_src刪了,可是17.4 KB 的大小對應用包體積應該沒有什麼影響吧,留着也行。
  2. 在要使用到的庫中以下引用
const {MusicManager} = require("../../NetEaseCloudMusicApi/src/MusicManager");

注意要用花括號吧MusicManager括起來,這一句能夠須要變化的地方只有
../../NetEaseCloudMusicApi/src/MusicManager中的../../,後面的路徑都表明了NetEaseCloudMusicApi文件夾和NetEaseCloudMusicApi裏面文件的路徑,由於個人庫就是這樣的結構,因此不須要改變,../../就要根據你項目中實際結構來改變了。微信小程序

MusicManager

該類有如下方法:該類提供了全部獲取其餘對象的方法,能夠經過該類獲取其餘須要的對象而不是newapi

  • getMusicSearchHelper()

須要參數:{keyword:"搜索歌曲關鍵詞",limit:數字}
返回:MusicSearchHelper搜索器

  • 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 = 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();

2

經過搜索歌曲的結果獲取音樂Url

有了搜索結果,咱們還須要url才能播放資源

  1. 經過MusicManager獲取一個MusicUrlHelperUrl獲取器
  2. 經過MusicUrlHelpergetUrlResult方法獲取url
  3. 須要注意的是,因爲網易雲接口時常返回空回覆,因此這裏我經過20之內的重複次請求直到有結果就中止,若是20次之後仍是沒有結果(據我測試20次之內都請求到結果了),也就是返回一個空的字符串"",須要使用者本身從新調用一次urlHelpergetUrlResult方法(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();

3

4.26更新

新增搜索用戶以及用戶歌單獲取接口

搜索用戶

  1. 經過MusicManager獲取一個UserSearchHelper用戶查詢器
  2. 經過UserSearchHelpergetSearchResult()方法獲取搜索結果
async function test(){
  // 搜索用戶
  let userSearchHelper = MusicManager.getUserSearchHelper({ userName: "JabinGP", limit: 20 });
  let users = await userSearchHelper.getSearchResult();
  console.log(users);
}

獲取用戶歌單

  1. 經過MusicManager獲取一個UserListHelper用戶查詢器
  2. 經過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吧~

相關文章
相關標籤/搜索