給本身的網站添加網易雲音樂歌單吧^ ^

最近應該發現,個人博客https://blog.codelabo.cn左下角多了一個音樂播放器css

aplayer

這個是怎麼實現的?一塊兒來看看吧html

APlayer

首先咱們須要一個音頻播放器,這裏我用到了APlayer,這是由bilibili前端大神DIYgod開源的播放器,有興趣的能夠去TA的主頁看看,很是驚豔,這裏我就很少說了前端

咱們看一下APlayer的官方文檔,方法很簡單vue

<link rel="stylesheet" href="APlayer.min.css">
<div id="aplayer"></div>
<script src="APlayer.min.js"></script>
const ap = new APlayer({
    container: document.getElementById('aplayer'),
    audio: [{
        name: 'name',
        artist: 'artist',
        url: 'url.mp3',
        cover: 'cover.jpg'
    }]
});

這裏的audio是一個音頻列表,能夠是一個對象或對象數組node

對象具體的參數以下react

名稱 描述
name 音頻名稱
artist 音頻藝術家
url 音頻連接
cover 音頻封面
lrc 音頻歌詞

LRC一共有三種方式來給 APlayer 傳遞歌詞,詳情可參考https://aplayer.js.org/#/home?id=lrcgit

這裏咱們選擇最方便的一種,直接給LRC連接github

網易雲音樂API

這部分我找到了網上有人分享的API,這種官方不可能給公開API,因此仍是要當心使用,說不定哪天就被修改了shell

http://moonlib.com/606.htmlnpm

咱們如今其實想要兩個,一個是歌單的列表,還有一個是歌詞。

# 歌單

https://music.163.com/api/playlist/detail?id=37880978
id爲歌單ID
# 歌詞

https://music.163.com/api/song/lyric?os=pc&id=93920&lv=-1&kv=-1&tv=-1
id爲歌曲ID
lv:值爲-1,我猜想應該是判斷是否搜索lyric格式
kv:值爲-1,這個值貌似並不影響結果,意義不明
tv:值爲-1,是否搜索tlyric格式

接口實現

雖然咱們已經找到了網易雲音樂API,可是返回的數據不是咱們所須要的呀

好比這個歌單的接口

# Request

https://music.163.com/api/playlist/detail?id=2119983629

# Response

{
  "result":{
      "subscribers":[],
      "subscribed": false,
      "creator":{...},
      "artists": null,
      "tracks":[
        {
          album: {
              name: "メトロノーム", 
              id: 36787278, type: "專輯", 
              size: 12, picId:18419018788768520,
          }
          alias: [],
          artists: [{name: "MACO", id: 901025, picId: 0, img1v1Id: 0, briefDesc: "",…}],
          audition: null,
          bMusic: {...},
          commentThreadId: "R_SO_4_515573221",
          copyFrom: "",
          copyright: 1,
          copyrightId: 7003,
          crbt: null,
          ...
        }
      ]
  }
}

裏面字段不少,我上面只列舉了一部分,tracks就是歌單列表,可是很顯然,和咱們須要的格式還差不少

那麼怎麼來轉換一下,變成咱們須要的數據格式呢?

[{
    name: 'name',
    artist: 'artist',
    url: 'url.mp3',
    cover: 'cover.jpg',
    lrc: 'a.lrc'
}]

這裏咱們就須要在服務端來完成了,思路很簡單,在服務器上請求https://music.163.com/api/playlist/detail?id=2119983629這個接口,而後拿到結果後手動處理一下,最後再返給客戶端,至關於作了一次中轉

我這裏服務端是用 koa實現的,其餘框架應該差很少

服務端發起請求

在服務端發起請求也能夠用咱們熟悉的fetch,不過你須要先安裝node-fetch這個庫

yarn add node-fetch

而後你就能夠像前端同樣發起請求了

const fetch = require('node-fetch');

//...

const getPlayList = (id) => {
    return fetch(`http://music.163.com/api/playlist/detail?id=${id}`)
    .then((response) => {
        if (response.ok) {
            return response.json();
        }
    })
    .catch((err) => {
        console.warn(err);
    })
}

接口定義

如今咱們須要新增一個接口用來處理歌單,返回出咱們須要的格式

//獲取音樂列表
router.get('/playlist/:id', async (ctx, next) => {
    const responseData = {
        "success": false,
        "data":[],
        "message": "",
    }
    const { id } = ctx.params;
    try {
        const data = await getPlayList(id);
        if(data.code===200){
            const playList = data.result.tracks.map(item=>({
                id: item.id,
                name: item.name,
                artist: item.artists.map(el=>el.name).join(','),//因爲歌手是一個數組,這裏咱們把它轉換成字符串拼接
                url: `https://music.163.com/song/media/outer/url?id=${item.id}.mp3`,//歌曲地址
                cover: item.album.picUrl.replace(/http:/,'https:'),
                lrc:null
            }))
            responseData.success = true;
            responseData.message = '操做成功';
            responseData.data = playList;
            ctx.body = responseData;
        }
    } catch (error) {
        responseData.success = false;
        responseData.message = error.message;
        responseData.data = [];
        ctx.body = responseData;
    }
});

注意這裏的歌曲連接url,原本返回信息裏面是不包含的,只有歌曲ID,不過咱們發現經過https://music.163.com/song/media/outer/url?id=ID能夠直接在線播放指定ID的歌曲,因此咱們這裏直接寫在返回結果上。

歌詞處理

還有一個問題就是歌詞,上面的接口中,歌詞返回結果也不是咱們須要的格式

# Request

https://music.163.com/api/song/lyric?os=pc&id=93920&lv=-1&kv=-1&tv=-1

# Response

{
  "sgc": true,
  "sfy": false,
  "qfy": false,
  "lrc": {
    "version": 7,
    "lyric": "[00:29.620]細雨帶風溼透黃昏的街道\n[00:35.050]抹去雨水雙眼無幫地仰望\n[00:40.240]望向孤單的晚燈是那傷感的記憶\n[00:48.630]再次泛起內心無數的思念\n[00:54.000]以往片刻歡笑仍掛在臉上\n[00:58.770]願你此刻可會知是我衷心的說聲\n[01:06.310]喜歡你\n[01:08.940]那雙眼動人笑聲更迷人\n[01:14.330]願再可輕撫你那可愛面容\n[01:22.490]挽手說夢話象昨天你共我\n[01:42.970]滿帶理想的我曾經多衝動\n[01:48.340]埋怨與她相愛難有自由\n[01:53.040]願你此刻可會知是我衷心的說聲\n[02:00.420]喜歡你\n[02:03.230]那雙眼動人笑聲更迷人\n[02:08.540]願再可輕撫你那可愛面容\n[02:16.750]挽手說夢話象昨天你共我\n[02:24.740]每晚夜裏自我獨行\n[02:27.670]隨處蕩 多冰冷\n[02:35.070]以往爲了自我掙扎從不知她的痛苦\n[02:49.380]喜歡你\n[02:52.020]那雙眼動人笑聲更迷人\n[02:57.420]願再可輕撫你那可愛面容\n[03:05.590]挽手說夢話象昨天你共我\n[03:13.870]挽手說夢話象昨天你共我\n"
  },
  "klyric": {...},
  "code": 200
}

反正就是很全面,可是咱們須要的僅僅是裏面的內容部分,好比上面我就只須要這一段

[00:29.620]細雨帶風溼透黃昏的街道
[00:35.050]抹去雨水雙眼無幫地仰望
[00:40.240]望向孤單的晚燈是那傷感的記憶
[00:48.630]再次泛起內心無數的思念
[00:54.000]以往片刻歡笑仍掛在臉上
[00:58.770]願你此刻可會知是我衷心的說聲
...

因此咱們須要再次作一箇中介處理

const getLyric = (id) => {
    return fetch(`http://music.163.com/api/song/lyric?os=pc&id=${id}&lv=-1&kv=-1&tv=-1`)
    .then((response) => {
        if (response.ok) {
            return response.json();
        }
    })
    .catch((err) => {
        console.warn(err);
    })
}

//獲取音樂歌詞
router.get('/lyric/:id', async (ctx, next) => {
    const { id } = ctx.params;
    try {
        const lyric = await getLyric(id);
        ctx.body = lyric.lrc.lyric;//返回指定部分
    } catch (error) {
        ctx.body = '';
    }
});

這樣在上面歌詞列表中就能夠直接用/api/lyric/:ID來獲取歌詞了

//...
{
  id: item.id,
  name: item.name,
  artist: item.artists.map(el=>el.name).join(','),
  url: `https://music.163.com/song/media/outer/url?id=${item.id}.mp3`,
  cover: item.album.picUrl.replace(/http:/,'https:'),
  lrc:`/api/lyric/${item.id}`//這裏歌詞寫上咱們定義的接口地址
}
//...

測試一下吧

經過以上處理,咱們接口就返回咱們自定義的數據格式了

# Request

https://localhost:3000/api/playlist/2119983629

# Response

{
  "success": true,
  "data": [
     {
      "id": 515573221,
      "name": "Sweet Memory",
      "artist": "MACO",
      "url": "https://music.163.com/song/media/outer/url?id=515573221.mp3",
      "cover": "https://p1.music.126.net/-U7mfaIjENUu8G_O0Dhv8g==/18419018788768520.jpg",
      "lrc": "/api/lyric/515573221"
    },
    {
      "id": 488388942,
      "name": "願い~あの頃のキミへ~",
      "artist": "當山みれい",
      "url": "https://music.163.com/song/media/outer/url?id=488388942.mp3",
      "cover": "https://p1.music.126.net/kbLlBkGfEcA3RJyC5JhkDA==/18346451021830743.jpg",
      "lrc": "/api/lyric/488388942"
    },
    ...
  ],
  "message": "操做成功"
}

添加到博客

其實上面對接口的數據改造纔是關鍵,下面添加到本身的頁面就很簡單了。

若是你是傳統HTML頁面,能夠直接文章開頭的方式引用

<link rel="stylesheet" href="APlayer.min.css">
<div id="aplayer"></div>
<script src="APlayer.min.js"></script>
const ap = new APlayer({
    container: document.getElementById('aplayer'),
    audio: [{
        name: 'name',
        artist: 'artist',
        url: 'url.mp3',
        cover: 'cover.jpg'
    }]
});

若是使用了使用模塊管理器:

import 'APlayer/dist/APlayer.min.css';
import APlayer from 'APlayer';

const ap = new APlayer(options);

若是是react項目,那麼能夠用封裝好的react-aplayer

import React from 'react';
import ReactAplayer from 'react-aplayer';

export default class App extends React.Component {
  // event binding example
  onPlay = () => {
    console.log('on play');
  };

  onPause = () => {
    console.log('on pause');
  };

  // example of access aplayer instance
  onInit = ap => {
    this.ap = ap;
  };

  render() {
    const props = {
      theme: '#F57F17',
      lrcType: 3,
      audio: [
        {
          name: '光るなら',
          artist: 'Goose house',
          url: 'https://moeplayer.b0.upaiyun.com/aplayer/hikarunara.mp3',
          cover: 'https://moeplayer.b0.upaiyun.com/aplayer/hikarunara.jpg',
          lrc: 'https://moeplayer.b0.upaiyun.com/aplayer/hikarunara.lrc',
          theme: '#ebd0c2'
        }
      ]
    };

    return (
      <div>
        <ReactAplayer
          {...props}
          onInit={this.onInit}
          onPlay={this.onPlay}
          onPause={this.onPause}
        />
        {/* example of access aplayer instance API */}
        <button onClick={() => this.ap.toggle()}>toggle</button>
      <div>
    );
  }
}

若是是vue項目,可使用vue-aplayer

<aplayer autoplay
  :music="{
    title: 'secret base~君がくれたもの~',
    artist: 'Silent Siren',
    src: 'https://moeplayer.b0.upaiyun.com/aplayer/secretbase.mp3',
    pic: 'https://moeplayer.b0.upaiyun.com/aplayer/secretbase.jpg'
  }"
/>

其餘更多能夠參考Aplayer生態

小節

這裏的歌單,我選擇了本身收藏的歌曲。每次用網易雲音樂客戶端播放聽歌的時候,收藏的歌曲,在個人博客上也能夠同步進行更新。

差很少就這些了,可能對於專業後端開發來講,這些徹底就是小學生操做,可是對於一個前端來講,作這些事就感受闖入了一片新天地,仍是有不少感悟的。不少之前前端作不了的事,如今nodeJS也能幫咱們解決,進一步打通了先後端的自然屏障,離全棧也愈來愈近了 ^ ^

你們若是喜歡個人博客,能夠多多關注一下

相關文章
相關標籤/搜索