提交 8df5d7a7 编写于 作者: B binaryify

新增`更新头像`,`歌单封面上传`接口和相关例子 #403 #857

上级 0ad746da
# 更新日志
### 3.37.0 | 2020.08.03
- 新增`更新头像`,`歌单封面上传`接口和相关例子 [#403](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/403) [#857](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/857)
- 加入`axios`依赖
### 3.36.0 | 2020.07.26
- 新增`全部新碟`,`数字专辑-新碟上架`,`数字专辑&数字单曲-榜单`,`数字专辑-语种风格馆`,`数字专辑详情`接口 [#852](https://github.com/Binaryify/NeteaseCloudMusicApi/issues/852)
- 更新`新碟上架`接口,修改传入参数,返回数据结构有变化
......
......@@ -182,6 +182,8 @@
161. 数字专辑&数字单曲-榜单
162. 数字专辑-语种风格馆
163. 数字专辑详情
164. 更新头像
165. 歌单封面上传
## 环境要求
......
......@@ -7,6 +7,7 @@ const packageJSON = require('./package.json')
const exec = require('child_process').exec
const cache = require('./util/apicache').middleware
const { cookieToJson } = require('./util/index')
const fileUpload = require('express-fileupload');
// version check
exec('npm info NeteaseCloudMusicApi version', (err, stdout, stderr) => {
if(!err){
......@@ -47,12 +48,15 @@ app.use((req, res, next) => {
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: false}))
// cache
app.use(cache('2 minutes', ((req, res) => res.statusCode === 200)))
app.use(fileUpload());
// static
app.use(express.static(path.join(__dirname, 'public')))
// cache
app.use(cache('2 minutes', ((req, res) => res.statusCode === 200)))
// router
const special = {
'daily_signin.js': '/daily_signin',
......@@ -69,7 +73,7 @@ fs.readdirSync(path.join(__dirname, 'module')).reverse().forEach(file => {
if(typeof req.query.cookie === 'string'){
req.query.cookie = cookieToJson(req.query.cookie)
}
let query = Object.assign({}, {cookie: req.cookies}, req.query, req.body )
let query = Object.assign({}, {cookie: req.cookies}, req.query, req.body, req.files )
question(query, request)
.then(answer => {
......
......@@ -179,6 +179,8 @@
161. 数字专辑&数字单曲-榜单
162. 数字专辑-语种风格馆
163. 数字专辑详情
164. 更新头像
165. 歌单封面上传
## 安装
......@@ -525,6 +527,20 @@ signature:用户签名
**调用例子 :** `/user/update?gender=0&signature=测试签名&city=440300&nickname=binary&birthday=1525918298004&province=440000`
### 更新头像
说明 : 登陆后调用此接口,使用`'Content-Type': 'multipart/form-data'`上传图片formData(name为'imgFile'),可更新头像(参考:https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/public/upload.html)
**可选参数 :**
`imgSize` : 图片尺寸,默认为300
`imgX` : 水平裁剪偏移,方形图片可不传,默认为0
`imgY` : 垂直裁剪偏移,方形图片可不传,默认为0
**接口地址 :** `/avatar/upload`
**调用例子 :** `/avatar/upload?imgSize=200`
### 国家编码列表
说明 : 调用此接口,可获取国家编码列表
......@@ -607,6 +623,25 @@ tags: 歌单标签
**调用例子 :** `/playlist/tags/update?id=24381616&tags=学习`
### 歌单封面上传
说明 : 登陆后调用此接口,使用`'Content-Type': 'multipart/form-data'`上传图片formData(name为'imgFile'),可更新歌单封面(参考:https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/public//playlist_cover_update.html)
**必选参数 :**
`id`: 歌单id 3143833470
**可选参数 :**
`imgSize` : 图片尺寸,默认为300
`imgX` : 水平裁剪偏移,方形图片可不传,默认为0
`imgY` : 垂直裁剪偏移,方形图片可不传,默认为0
**接口地址 :** `/playlist/cover/update`
**调用例子 :** `/playlist/cover/update?id=3143833470&imgSize=200`
### 调整歌单顺序
说明 : 登陆后调用此接口,可以根据歌单id顺序调整歌单顺序
......
const uploadPlugin = require('../plugins/upload')
module.exports = async (query, request) => {
const uploadInfo = await uploadPlugin(query, request)
const res = await request(
'POST',
`https://music.163.com/weapi/user/avatar/upload/v1`,
{
imgid: uploadInfo.imgId
},
{ crypto: 'weapi', cookie: query.cookie, proxy: query.proxy }
)
return {
status: 200,
body: {
code: 200,
data: {
...uploadInfo,
...res.body,
},
},
}
}
const uploadPlugin = require('../plugins/upload')
module.exports = async (query, request) => {
const uploadInfo = await uploadPlugin(query, request)
const res = await request(
'POST',
`https://music.163.com/weapi/playlist/cover/update`,
{
id: query.id,
coverImgId: uploadInfo.imgId
},
{ crypto: 'weapi', cookie: query.cookie, proxy: query.proxy }
)
return {
status: 200,
body: {
code: 200,
data: {
...uploadInfo,
...res.body,
},
},
}
}
......@@ -7,7 +7,6 @@ module.exports = (query, request) => {
need_preview_url: 'true',
total: true
}
console.log({data})
// /api/videotimeline/otherclient/get
return request(
'POST', `https://music.163.com/api/videotimeline/otherclient/get`, data, {
......
{
"name": "NeteaseCloudMusicApi",
"version": "3.36.0",
"description": "网易云音乐 NodeJS 版 API",
"scripts": {
"start": "node app.js",
"test": "mocha -r intelli-espower-loader -t 20000 app.test.js --exit",
"lint-fix": "eslint --fix --ext .js app.js module/ util/ test/ "
},
"keywords": [
"网易云音乐",
"网易云",
"音乐",
"网易云音乐nodejs"
],
"main": "main.js",
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"engines": {
"node": ">=12"
},
"lint-staged": {
"*.js": [
"eslint --fix",
"git add"
]
},
"author": "binaryify",
"license": "MIT",
"files": [
"module",
"util"
],
"dependencies": {
"express": "^4.17.1",
"pac-proxy-agent": "^3.0.1",
"request": "^2.88.0"
},
"devDependencies": {
"eslint": "^6.6.0",
"eslint-plugin-html": "^6.0.0",
"husky": "^3.0.9",
"intelli-espower-loader": "^1.0.1",
"lint-staged": "^9.4.2",
"mocha": "^6.2.2",
"power-assert": "^1.6.1"
"name": "NeteaseCloudMusicApi",
"version": "3.37.0",
"description": "网易云音乐 NodeJS 版 API",
"scripts": {
"start": "node app.js",
"test": "mocha -r intelli-espower-loader -t 20000 app.test.js --exit",
"lint-fix": "eslint --fix --ext .js app.js module/ util/ test/ "
},
"keywords": [
"网易云音乐",
"网易云",
"音乐",
"网易云音乐nodejs"
],
"main": "main.js",
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"engines": {
"node": ">=12"
},
"lint-staged": {
"*.js": [
"eslint --fix",
"git add"
]
},
"author": "binaryify",
"license": "MIT",
"files": [
"module",
"util"
],
"dependencies": {
"axios": "^0.19.2",
"express": "^4.17.1",
"pac-proxy-agent": "^3.0.1",
"request": "^2.88.0"
},
"devDependencies": {
"eslint": "^6.6.0",
"eslint-plugin-html": "^6.0.0",
"husky": "^3.0.9",
"intelli-espower-loader": "^1.0.1",
"lint-staged": "^9.4.2",
"mocha": "^6.2.2",
"power-assert": "^1.6.1"
}
}
const axios = require('axios')
module.exports = async (query, request) => {
const data = {
bucket: 'yyimgs',
ext: 'jpg',
filename: query.imgFile.name,
local: false,
nos_product: 0,
return_body: `{"code":200,"size":"$(ObjectSize)"}`,
type: 'other',
}
// 获取key和token
const res = await request(
'POST',
`https://music.163.com/weapi/nos/token/alloc`,
data,
{ crypto: 'weapi', cookie: query.cookie, proxy: query.proxy }
)
// 上传图片
const res2 = await axios({
method: 'post',
url: `https://nosup-hz1.127.net/yyimgs/${res.body.result.objectKey}?offset=0&complete=true&version=1.0`,
headers: {
'x-nos-token': res.body.result.token,
'Content-Type': 'image/jpeg',
},
data: query.imgFile.data,
})
// 获取裁剪后图片的id
const imgSize = query.imgSize || 300
const imgX = query.imgX || 0
const imgY = query.imgY || 0
const res3 = await request(
'POST',
`https://music.163.com/upload/img/op?id=${res.body.result.docId}&op=${imgX}y${imgY}y${imgSize}y${imgSize}`,
{},
{ crypto: 'weapi', cookie: query.cookie, proxy: query.proxy }
)
return {
// ...res.body.result,
// ...res2.data,
// ...res3.body,
url_pre: 'https://p1.music.126.net/' + res.body.result.objectKey,
url: res3.body.url,
imgId: res3.body.id
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>更新头像</title>
</head>
<body>
<input id="file" type="file" name="filename" />
<img id="avatar" style="height: 200px; width: 200px; border-radius: 50%;" />
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.20.0-0/axios.min.js
"></script>
<script>
const phone = ''
const password = ''
const port = 3000
let cookieToken = ''
if (!phone || !password) {
const msg = '请设置你的手机号码和密码'
alert(msg)
throw new Error(msg)
}
main()
login()
async function main() {
document.querySelector('input[type="file"]').addEventListener(
'change',
function (e) {
var file = this.files[0]
upload(file)
},
false
)
const res = await axios({
url: `http://localhost:${port}/user/detail?uid=32953014`,
withCredentials: true, //关键
})
document.querySelector('#avatar').src = res.data.profile.avatarUrl
}
async function login() {
const res = await axios({
url: `http://localhost:${port}/login/cellphone?phone=${phone}&password=${password}`,
withCredentials: true, //关键
})
cookieToken = res.data.cookie
}
async function upload(file) {
var formData = new FormData()
formData.append('imgFile', file)
const imgSize = await getImgSize(file)
const res = await axios({
method: 'post',
url: `http://localhost:3000/avatar/upload?cookie=${cookieToken}&imgSize=${imgSize.width}&imgX=0&imgY=0`,
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
})
document.querySelector('#avatar').src = res.data.data.url
}
function getImgSize(file) {
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = function (theFile) {
let image = new Image()
image.src = theFile.target.result
image.onload = function () {
resolve({
width: this.width,
height: this.height
})
}
}
})
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>歌单封面上传</title>
</head>
<body>
<input id="file" type="file" name="filename" />
<img id="avatar" style="height: 200px; width: 200px; border-radius: 50%;" />
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.20.0-0/axios.min.js
"></script>
<script>
const phone = ''
const password = ''
const playlist_id = ''
const port = 3000
let cookieToken = ''
if (!phone || !password) {
const msg = '请设置你的手机号码和密码'
alert(msg)
throw new Error(msg)
}
if (!playlist_id) {
const msg = '请设置你的歌单id'
alert(msg)
throw new Error(msg)
}
main()
login()
async function main() {
document.querySelector('input[type="file"]').addEventListener(
'change',
function (e) {
var file = this.files[0]
upload(file)
},
false
)
const res = await axios({
url: `http://localhost:${port}/playlist/detail?id=${playlist_id}`,
})
document.querySelector('#avatar').src = res.data.playlist.coverImgUrl
}
async function login() {
const res = await axios({
url: `http://localhost:${port}/login/cellphone?phone=${phone}&password=${password}`,
withCredentials: true, //关键
})
cookieToken = res.data.cookie
}
async function upload(file) {
var formData = new FormData()
formData.append('imgFile', file)
const imgSize = await getImgSize(file)
const res = await axios({
method: 'post',
url: `http://localhost:3000/playlist/cover/update?id=${playlist_id}&cookie=${cookieToken}&imgSize=${imgSize.width}&imgX=0&imgY=0`,
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
})
document.querySelector('#avatar').src = res.data.data.url
}
function getImgSize(file) {
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = function (theFile) {
let image = new Image()
image.src = theFile.target.result
image.onload = function () {
resolve({
width: this.width,
height: this.height,
})
}
}
})
}
</script>
</body>
</html>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册