网易云歌单添加到php,给自己的网站添加网易云音乐歌单吧^ ^

7c6c9b97ce6677b24a8af407d9882114.png

这个是怎么实现的?一起来看看吧

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链接

网易云音乐API

这部分我找到了网上有人分享的API,这种官方不可能给公开API,所以还是要小心使用,说不定哪天就被修改了

我们现在其实想要两个,一个是歌单的列表,还有一个是歌词。

# 歌单

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页面,可以直接文章开头的方式引用

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 (

{...props}

onInit={this.onInit}

onPlay={this.onPlay}

onPause={this.onPause}

/>

{/* example of access aplayer instance API */}

this.ap.toggle()}>toggle

);

}

}

如果是vue项目,可以使用vue-aplayer

: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'

}"

/>

小节

这里的歌单,我选择了自己收藏的歌曲。每次用网易云音乐客户端播放听歌的时候,收藏的歌曲,在我的博客上也可以同步进行更新。

差不多就这些了,可能对于专业后端开发来说,这些完全就是小学生操作,但是对于一个前端来说,做这些事就感觉闯入了一片新天地,还是有很多感悟的。很多以前前端做不了的事,现在nodeJS也能帮我们解决,进一步打通了前后端的天然屏障,离全栈也越来越近了 ^ ^

大家如果喜欢我的博客,可以多多关注一下

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/543161.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python学完面向对象之后_Python学完基础语法后,再往后应该学什么?

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼第一阶段:Python语言及应用课程内容:Python语言基础,面向对象设计,多线程编程,数据库交互技术,前端特效,Web框架,爬虫框架,…

百度应用部署秘籍

2019独角兽企业重金招聘Python工程师标准>>> 【背景介绍】 传统PaaS采用sandbox实现app间的资源安全隔离,sandbox需要对运行环境和编程语言进行底层的功能限制,例如:禁止创建进程和线程,禁止部分系统调用,禁…

php新闻删除功能设计,php原生开发新闻站之删除新闻

我们前两篇文章都完成了新闻的添加、修改。那么我们这个节课程就给大家介绍删除新闻,这个比之前的两个都要简单点!首先创建一个new_delete.php,接着我们要在新闻列表页找到删除的按钮,给这个按钮加一个连接,我们同样需要通过id来传…

java8新特性_JAVA8十大新特性详解

一、接口的默认方法Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:interface Formula { double calculate(int a); default double sqrt(int a) { return Math.sq…

spark1.6.1 on yarn搭建部署

注:本文是建立在hadoop已经搭建完成的基础上进行的。 Apache Spark是一个分布式计算框架,旨在简化运行于计算机集群上的并行程序的编写。该框架对资源调度,任务的提交、执行和跟踪,节点间的通信以及数据并行处理的内在底层操作都进…

php 精度问题怎么解决,JavaScript 中精度问题以及解决方案

JavaScript 中的数字按照 IEEE 754 的标准,使用 64 位双精度浮点型来表示。其中符号位 S,指数位 E,尾数位M分别占了 1,11,52 位,并且在 ES5 规范 中指出了指数位E的取值范围是 [-1074, 971]。精度问题汇总想…

主线程是如何向子线程传递数据的?_c++ 利用thread创建线程

用进行多线程开发小时候,老师总是教育我们上课要专心,“一心不可二用”。可是CPU这个不听话的“熊孩子”偏偏却在一个芯片中加入了两个甚至多个运算核心,想要一“芯”二用。从硬件厂商的角度,通过增加CPU的运算核心,突…

php多维数组交集,求数组差/交集函数-php数组函数(二)

求数组差集函数函数只检查了多维数组中的一维。可以用 array_diff($array1[0], $array2[0]) 检查更深的维度。u:自定义函数比较,a(association):同时比较键和值。自定义函数callable $value_compare_func必须返回一个小于零,等于零…

寻找水王(2)

求解内容极其相似,相同的思路进行求解即可。同时删除4个不同的ID后,剩余数据中3个多数id仍然是多数ID。 上题只需要一个结果,而现在需要3个结果,上题用到的nTimes,也应改为3个计数器。现在我们需要3个变量来记录当前遍…

centos7.4php测试,CentOS7.4 通过yum安装php7.0

一、删除旧版本如果已经安装过php就先删除之前的版本。检查方法如下:yum list installed | grep php然后将安装的包进行删除比如 yum remove php.x86_64 php-cli.x86_64 php-common.x86_64 php-gd.x86_64 php-ldap.x86_64 php-mbstring.x86_64 php-mcrypt.x86_64 ph…

正则过滤符号_多角度理解正则项

过拟合和欠拟合什么是过拟合和欠拟合过拟合:模型在训练集上效果好,在测试集上效果差欠拟合:在训练集上效果就不好产生过拟合的原因参数太多,模型复杂度太高数据量少,训练轮次过多样本中噪声较大,模型拟合了…

PHP页面中嵌套go语言,go语言嵌套类型的使用细节

1. 定义在Go语言中,嵌套类型是将已有的类型直接声明在新的结构类型里。被嵌入的类型被称为新的外部类型的内部类型。通过嵌入类型,与内部类型相关的成员变量会提升到外部类型上。就好像这些成员变量直接声明在外部类型一样。如下图所示:外部类…

jvm内存模型_JVM内存模型的相关概念

1.前言Android的虚拟机是根据移动设备的特点基于Java虚拟机(JVM)改进而来,虽然没有保留规范,但作为Java语言的使用者,了解一下JVM的规范还是有必要的。2.JVM内存模型JVM在执行Java程序时,会把它管理的内存划分为若干个的区域&…

php session bug,thinkphp2.x中session的BUG及解决办法

很多人出现一个TP构建的APP,出现SESSION相同导致用户未经授权就登陆了其它项目,N久没有找到原因。今天晚上跟踪了一下代码,找到了问题。主要原因在于TP在项目实例化的时候没有对SESSION进行配置就直接初始化了。/Core/App.class.php中看到这段…

LNMP/LEMP(PHP7.0.04+mysql5.7.12+nginx1.10.0)

预览:Installing Nginx with PHP 7 and MySQL 5.7 (LEMP) on Ubuntu 16.04 LTSThis tutorial exists for these OS versionsUbuntu 15.10 (Wily Werewolf)Ubuntu 14.04 LTS (Trusty Tahr)Ubuntu 13.04 (Raring Ringtail)Ubuntu 12.10 (Quantal Quetzal)Ubuntu 12.04 LTS (Preci…

length函数的头文件_Framebuffer 应用编程中涉及的 API 函数

本节程序的目的是&#xff1a;打开 LCD 设备节点&#xff0c;获取分辨率等参数&#xff0c;映射 Framebuffer&#xff0c;最后实现描点函数。5.2.1 open 函数在 Ubuntu 中执行“man 2 open”&#xff0c;可以看到 open 函数的说明&#xff1a;头文件&#xff1a;#include <s…

xib中UIScrollView固定底部内容

UIScrollView的高度在xib中设置 需要固定的部分用代码添加: UIImageView *textLogo [[UIImageView alloc] initWithFrame:CGRectMake((kMSScreenWith - 153)/2, (kMSScreenHeight - 118 > 549 ? kMSScreenHeight : 667) - 173, 153, 35)]; textLogo.image [UIImage image…

java 陷阱,java 中的陷阱。

看了一段北风网的视频&#xff0c;总结几个经典的java陷阱给大家。答案在博客中&#xff1a;http://blog.csdn.net/ol_beta/archive/2010/05/17/5598867.aspx欢迎大家讨论&#xff01;1、找奇数&#xff1a;Java codepublic static boolean isOdd(int i){return i % 2 0;}上面…

python上传本地文件到ftp_python实现的简单FTP上传下载文件实例

本文实例讲述了python实现的简单FTP上传下载文件的方法。分享给大家供大家参考。具体如下&#xff1a;python本身自带一个FTP模块&#xff0c;可以实现上传下载的函数功能。#!/usr/bin/env python# -*- coding: utf-8 -*-from ftplib import FTPdef ftp_up(filename "201…

hive

hive 的 表与hdfs数据关系映射放在元数据库中&#xff0c;也就是mysql中&#xff0c;而真正的数据放在 hdfs中&#xff0c;通过mysql中表 &#xff0c;字段等与hdfs上数据的映射来查询 1.hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张数据库…