摘要:每次用网易云音乐客户端播放听歌的时候,收藏的歌曲,在我的博客上也可以同步进行更新。
最近应该发现,我的博客https://blog.codelabo.cn左下角多了一个音乐播放器
这个是怎么实现的?一起来看看吧
APlayer首先我们需要一个音频播放器,这里我用到了APlayer,这是由bilibili前端大神DIYgod开源的播放器,有兴趣的可以去TA的主页看看,非常惊艳,这里我就不多说了
我们看一下APlayer的官方文档,方法很简单
const ap = new APlayer({ container: document.getElementById("aplayer"), audio: [{ name: "name", artist: "artist", url: "url.mp3", cover: "cover.jpg" }] });
这里的audio是一个音频列表,可以是一个对象或对象数组
对象具体的参数如下
名称 | 描述 |
---|---|
name | 音频名称 |
artist | 音频艺术家 |
url | 音频链接 |
cover | 音频封面 |
lrc | 音频歌词 |
LRC一共有三种方式来给 APlayer 传递歌词,详情可参考https://aplayer.js.org/#/home?id=lrc,
这里我们选择最方便的一种,直接给LRC链接
网易云音乐API这部分我找到了网上有人分享的API,这种官方不可能给公开API,所以还是要小心使用,说不定哪天就被修改了
http://moonlib.com/606.html
我们现在其实想要两个,一个是歌单的列表,还有一个是歌词。
# 歌单 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]细雨带风湿透黄昏的街道 [00:35.050]抹去雨水双眼无帮地仰望 [00:40.240]望向孤单的晚灯是那伤感的记忆 [00:48.630]再次泛起心里无数的思念 [00:54.000]以往片刻欢笑仍挂在脸上 [00:58.770]愿你此刻可会知是我衷心的说声 [01:06.310]喜欢你 [01:08.940]那双眼动人笑声更迷人 [01:14.330]愿再可轻抚你那可爱面容 [01:22.490]挽手说梦话象昨天你共我 [01:42.970]满带理想的我曾经多冲动 [01:48.340]埋怨与她相爱难有自由 [01:53.040]愿你此刻可会知是我衷心的说声 [02:00.420]喜欢你 [02:03.230]那双眼动人笑声更迷人 [02:08.540]愿再可轻抚你那可爱面容 [02:16.750]挽手说梦话象昨天你共我 [02:24.740]每晚夜里自我独行 [02:27.670]随处荡 多冰冷 [02:35.070]以往为了自我挣扎从不知她的痛苦 [02:49.380]喜欢你 [02:52.020]那双眼动人笑声更迷人 [02:57.420]愿再可轻抚你那可爱面容 [03:05.590]挽手说梦话象昨天你共我 [03:13.870]挽手说梦话象昨天你共我 " }, "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页面,可以直接文章开头的方式引用
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 ({/* example of access aplayer instance API */} ); } }如果是vue项目,可以使用vue-aplayer
其他更多可以参考Aplayer生态
小节这里的歌单,我选择了自己收藏的歌曲。每次用网易云音乐客户端播放听歌的时候,收藏的歌曲,在我的博客上也可以同步进行更新。
差不多就这些了,可能对于专业后端开发来说,这些完全就是小学生操作,但是对于一个前端来说,做这些事就感觉闯入了一片新天地,还是有很多感悟的。很多以前前端做不了的事,现在nodeJS也能帮我们解决,进一步打通了前后端的天然屏障,离全栈也越来越近了 ^ ^
大家如果喜欢我的博客,可以多多关注一下
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/98655.html
相关文章
selenium实战-同步网易云音乐歌单到qq音乐
摘要:对于这次的爬虫来说,由于网易云音乐以及音乐网页中大部分元素都是使用渲染生成的,因此选择使用来完成这次的脚本。可以发现网易云音乐的手机版歌单地址是。现在已经支持网易云音乐与音乐歌单的互相同步。 本文主要介绍selenium在爬虫脚本的实际应用。适合刚接触python,没使用过selenium的童鞋。(如果你是老司机路过的话,帮忙点个star吧) 项目地址 https://github.c...
HTML+CSS+JAVASCRIPT 高仿低配网页版网易云音乐播放器
摘要:高仿低配网页版网易云音乐播放器前言没有使用任何框架,只是想用最简单纯的代码实现下前台后台是参考网上的例子写的,代码是在的基础上重新写的还有她的姊妹篇网易云音乐移动端,请查看这里写在前头的话鄙人野生前端一只,专业,自学前端已经一年多了 HTML+CSS+JAVASCRIPT 高仿低配网页版网易云音乐播放器 showImg(https://segmentfault.com/img/remo...
HTML+CSS+JAVASCRIPT 高仿低配网页版网易云音乐播放器
摘要:高仿低配网页版网易云音乐播放器前言没有使用任何框架,只是想用最简单纯的代码实现下前台后台是参考网上的例子写的,代码是在的基础上重新写的还有她的姊妹篇网易云音乐移动端,请查看这里写在前头的话鄙人野生前端一只,专业,自学前端已经一年多了 HTML+CSS+JAVASCRIPT 高仿低配网页版网易云音乐播放器 showImg(https://segmentfault.com/img/remo...
Vue 实现网易云音乐 WebApp
摘要:基于等开发一款移动端音乐,界面参考了安卓版的网易云音乐布局适配常见移动端。图标使用阿里巴巴图标库,中间的唱片旋转动画使用了实现。搜索功能实现功能搜索歌手歌单歌曲热门搜索数据节流上拉刷新保存搜索记录。 基于 Vue(2.5) + vuex + vue-router + vue-axios +better-scroll + Scss + ES6 等开发一款移动端音乐 WebApp,UI ...
发表评论
0条评论
阅读 1819·2023-04-26 02:51
阅读 2852·2021-09-10 10:50
阅读 3030·2021-09-01 10:48
阅读 3599·2019-08-30 15:53
阅读 1817·2019-08-29 18:40
阅读 406·2019-08-29 16:16
阅读 2026·2019-08-29 13:21
阅读 1817·2019-08-29 11:07