提交 a2e4d264 编写于 作者: B binaryify

upgrade version 2.0,add login api,upgrade api verison,add document and unit test

上级 35f37afd
无法预览此类型文件
{
"presets": ["es2015"]
}
\ No newline at end of file
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# Change these settings to your own preference
indent_style = space
indent_size = 2
# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
language: node_js
node_js:
- 4.0
- 6.2
The MIT License (MIT)
Copyright (c) 2013-2016 Binaryify
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
\ No newline at end of file
# NeteaseCloudMusicApi
一个调用网易云音乐 API 的 node 模块
网易云音乐 nodejs 接口
<p>
<a href="https://www.npmjs.com/package/NeteaseCloudMusicApi"><img src="https://img.shields.io/npm/v/NeteaseCloudMusicApi.svg" alt="Version"></a>
<a href="https://www.npmjs.com/package/NeteaseCloudMusicApi"><img src="https://img.shields.io/npm/l/NeteaseCloudMusicApi.svg" alt="License"></a>
......@@ -9,64 +9,35 @@
<a href="https://travis-ci.org/Binaryify/NeteaseCloudMusicApi"><img src="https://api.travis-ci.org/Binaryify/NeteaseCloudMusicApi.svg?branch=master" /></a>
</p>
![](http://binaryify.github.io/images/api.jpg)
## Start
``` shell
npm install NeteaseCloudMusicApi
```
## Usage
``` javascript
var api = require('NeteaseCloudMusicApi').api
api.search('年度之歌',function(data){
console.log(data)
})
```
or
``` javascript
import {api} from 'NeteaseCloudMusicApi'
api.search('年度之歌',data => {
console.log(data)
})
```
## API
## 版本新特性
增加使用文档,完成项目重构,增加更完善的单元测试,版本升级到2.0,升级 api 到 v2+,支持登录并获取用户信息和创建的歌单,可通过获取音乐 url 接口获取用户歌单里的的音乐,获取每日推荐歌单和每日推荐音乐
### search
``` javascript
api.search(name:String,[callback:function,onlySong:Boolean default:true,limit:Number default:3, offset:Number default:0])
```
说明:onlySong默认为true,如果为false,则返回一个对象,包含songs和mvs,songs和mvs均为数组
## 环境要求
需要 NodeJS 6.0+ 环境
### lrc
``` javascript
api.lrc(id:Number,[callback:function,lv:Number default:-1])
## 安装
``` shell
$ git clone git@github.com:Binaryify/NeteaseCloudMusicApi.git
$ npm install
```
### song
``` javascript
api.song(id:Number,[callback:function])
## 运行
``` shell
$ node app.js
```
### getArtistAlbums
## 使用文档
``` javascript
api.getArtistAlbums(id:Number,[callback:function,limit:Number default:3, offset:Number default:0])
```
[文档地址](https://binaryify.github.io/NeteaseCloudMusicApi)
## getAlbums
## 单元测试
``` javascript
api.getAlbums(id:Number,[callback:function])
``` shell
$ npm test
```
## getPlaylists
``` javascript
api.Playlists(id:Number,[callback:function])
```
![单元测试](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/screenshot1.png)
![单元测试](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/screenshot2.png)
## License
[The MIT License (MIT)](LICENSE)
const express = require('express')
const http = require('http')
const app = express()
//手机登录
app.use('/login/cellphone', require('./router/loginCellphone'))
app.use('/login', require('./router/login'))
// 获取每日推荐歌曲
app.use('/recommend/songs', require('./router/recommendSongs'))
// 获取每日推荐歌单
app.use('/recommend/resource', require('./router/recommendResource'))
app.use('/lyric', require('./router/lyric'))
app.use('/user/playlist', require('./router/userPlaylist'))
app.use('/playlist/detail', require('./router/playlistDetail'))
app.use('/playlist/tracks', require('./router/playlistTracks'))
// 获取音乐 url
app.use('/music/url', require('./router/musicUrl'))
// 搜歌
app.use('/search', require('.//router/search'))
app.use('/log/web', require('./router/logWeb'))
process.on('SIGHUP', () => {
console.log('server: bye bye')
process.exit()
})
const port = process.env.PORT || 3000
app.listen(port, () => {
console.log(`server running @${port}`)
})
module.exports = app
\ No newline at end of file
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.api = undefined;
var _search = require('./component/search');
var _song = require('./component/song');
var _lrc = require('./component/lrc');
var _getArtistAlbums = require('./component/getArtistAlbums');
var _getAlbums = require('./component/getAlbums');
var _getPlaylists = require('./component/getPlaylists');
var api = {
search: _search.search,
song: _song.song,
lrc: _lrc.lrc,
getArtistAlbums: _getArtistAlbums.getArtistAlbums,
getAlbums: _getAlbums.getAlbums,
getPlaylists: _getPlaylists.getPlaylists
};
exports.api = api;
\ No newline at end of file
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getAlbums = undefined;
var _request = require('request');
var _request2 = _interopRequireDefault(_request);
var _config = require('../config');
var _util = require('../util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var getAlbums = function getAlbums(id, callback) {
var option = (0, _util.deepCopy)(_config.globalOption);
var url = _config.origin + '/api/album/' + id;
var method = 'get';
Object.assign(option, { url: url, method: method });
(0, _request2.default)(option, function (err, res, body) {
if (!err && res.statusCode == 200) {
var info = JSON.parse(body);
callback && callback(JSON.stringify(info, '', 2));
} else {
console.error(err);
}
});
};
exports.getAlbums = getAlbums;
\ No newline at end of file
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getArtistAlbums = undefined;
var _request = require('request');
var _request2 = _interopRequireDefault(_request);
var _config = require('../config');
var _util = require('../util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var getArtistAlbums = function getArtistAlbums(id, callback) {
var limit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 3;
var offset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
var option = (0, _util.deepCopy)(_config.globalOption);
var url = _config.origin + '/api/artist/albums/' + id + '?offset=' + offset + '&limit=' + limit;
var method = 'GET';
Object.assign(option, { url: url, method: method });
(0, _request2.default)(option, function (err, res, body) {
if (!err && res.statusCode == 200) {
var info = JSON.parse(body);
callback && callback(JSON.stringify(info, '', 2));
} else {
console.error(err);
}
});
};
exports.getArtistAlbums = getArtistAlbums;
\ No newline at end of file
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getAlbums = undefined;
var _request = require('request');
var _request2 = _interopRequireDefault(_request);
var _config = require('../config');
var _util = require('../util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var getPlaylists = function getPlaylists(id, callback) {
var option = (0, _util.deepCopy)(_config.globalOption);
var url = _config.origin + '/api/playlist/detail?id=' + id;
var method = 'get';
Object.assign(option, { url: url, method: method });
(0, _request2.default)(option, function (err, res, body) {
if (!err && res.statusCode == 200) {
var info = JSON.parse(body);
callback && callback(JSON.stringify(info, '', 2));
} else {
console.error(err);
}
});
};
exports.getPlaylists = getPlaylists;
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getPlaylists = undefined;
var _request = require('request');
var _request2 = _interopRequireDefault(_request);
var _config = require('../config');
var _util = require('../util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var getPlaylists = function getPlaylists(id, callback) {
var option = (0, _util.deepCopy)(_config.globalOption);
var url = _config.origin + '/api/playlist/detail?id=' + id;
var method = 'get';
Object.assign(option, { url: url, method: method });
(0, _request2.default)(option, function (err, res, body) {
if (!err && res.statusCode == 200) {
var info = JSON.parse(body);
callback && callback(JSON.stringify(info, '', 2));
} else {
console.error(err);
}
});
};
exports.getPlaylists = getPlaylists;
\ No newline at end of file
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.lrc = undefined;
var _request = require('request');
var _request2 = _interopRequireDefault(_request);
var _config = require('../config');
var _util = require('../util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var lrc = function lrc(id) {
var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var lv = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : -1;
var option = (0, _util.deepCopy)(_config.globalOption);
var url = _config.origin + '/api/song/lyric?lv=' + lv + '&id=' + id;
var method = 'GET';
Object.assign(option, { url: url, method: method });
(0, _request2.default)(option, function (err, res, body) {
if (!err && res.statusCode == 200) {
var info = JSON.parse(body);
callback && callback(JSON.stringify(info, '', 2));
} else {
console.error(err);
}
});
};
exports.lrc = lrc;
\ No newline at end of file
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.search = undefined;
var _request = require('request');
var _request2 = _interopRequireDefault(_request);
var _config = require('../config');
var _util = require('../util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var search = function search() {
var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var onlySong = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
var limit = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 3;
var offset = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
var option = (0, _util.deepCopy)(_config.globalOption);
var url = _config.origin + '/api/search/get';
var form = {
s: name,
limit: limit,
type: 1,
offset: offset
};
var method = 'POST';
Object.assign(option, { url: url, form: form, method: method });
(0, _request2.default)(option, function (err, res, body) {
if (!err && res.statusCode == 200) {
var info = JSON.parse(body);
var data = void 0;
if (onlySong) {
data = info.result.songs;
} else {
data = { songs: info.result.songs, mvs: info.result.mvs };
}
callback && callback(JSON.stringify(data, '', 2));
} else {
console.error(err);
}
});
};
exports.search = search;
\ No newline at end of file
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.song = undefined;
var _request = require('request');
var _request2 = _interopRequireDefault(_request);
var _config = require('../config');
var _util = require('../util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var song = function song(id) {
var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var option = (0, _util.deepCopy)(_config.globalOption);
var url = _config.origin + '/api/song/detail?ids=%5B' + id + '%5d';
var method = 'GET';
Object.assign(option, { url: url, method: method });
(0, _request2.default)(option, function (err, res, body) {
if (!err && res.statusCode == 200) {
var info = JSON.parse(body);
callback && callback(JSON.stringify(info, '', 2));
} else {
console.error(err);
}
});
};
exports.song = song;
\ No newline at end of file
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var origin = 'http://music.163.com';
var globalOption = {
headers: {
'Origin': origin,
'Referer': origin,
'Content-Type': 'application/x-www-form-urlencoded'
},
proxy: false
};
exports.origin = origin;
exports.globalOption = globalOption;
\ No newline at end of file
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var deepCopy = function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
};
exports.deepCopy = deepCopy;
\ No newline at end of file
......@@ -7,17 +7,18 @@
## 安装
``` shell
npm install NeteaseCloudMusicApi
$ git clone git@github.com:Binaryify/NeteaseCloudMusicApi.git
$ npm install
```
## 使用
## 运行
``` shell
node app.js
$ node app.js
```
服务器启动,默认端口为3000
## 接口
## 接口文档
### 登录
登录有两个接口
......@@ -89,6 +90,7 @@ node app.js
`/recommend/resource`
返回数据如下图:
![搜索音乐](https://raw.githubusercontent.com/Binaryify/NeteaseCloudMusicApi/master/static/%E6%8E%A8%E8%8D%90%E6%AD%8C%E5%8D%95.png)
### 获取每日推荐歌曲
说明:调用此接口,可获得每日推荐歌曲(需要登录)
接口地址:
......
{
"name": "NeteaseCloudMusicApi",
"version": "1.5.2",
"description": "网易云音乐nodejs版接口模块",
"main": "build/app.js",
"version": "2.0.0",
"description": "",
"scripts": {
"test": "node test/test.js",
"build": "babel src/ -d build/"
"start": "node app.js",
"test": "mocha -r intelli-espower-loader -t 20000 test"
},
"keywords": ["NeteaseCloudMusic","网易云音乐","网易云"],
"author": "traveller",
"license": "MIT",
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"request": "^2.72.0"
"big-integer": "^1.6.17",
"express": "^4.15.2"
},
"devDependencies": {
"babel-core": "^6.9.1",
"babel-preset-es2015": "^6.9.0"
"intelli-espower-loader": "^1.0.1",
"mocha": "^3.2.0",
"power-assert": "^1.4.2"
}
}
}
\ No newline at end of file
const express = require("express")
const router = express()
const { createWebAPIRequest } = require("../util/util")
router.get("/", (req, res) => {
const cookie = req.get('Cookie') ? req.get('Cookie') : ''
const data = {
"action": req.query.action,
"json": req.query.json,
"csrf_token": "",
}
createWebAPIRequest(
'music.163.com',
'/weapi/log/web',
'POST',
data,
cookie,
music_req => res.send(music_req),
err => res.status(502).send('fetch error')
)
})
module.exports = router
\ No newline at end of file
const express = require("express")
const crypto = require('crypto')
const router = express()
const { createWebAPIRequest } = require("../util/util")
router.get("/", (req, res) => {
const email = req.query.email
const cookie = req.get('Cookie') ? req.get('Cookie') : ''
const md5sum = crypto.createHash('md5')
md5sum.update(req.query.password)
const data = {
'username': email,
'password': md5sum.digest('hex'),
'rememberLogin': 'true'
}
createWebAPIRequest(
'music.163.com',
'/weapi/login',
'POST',
data,
cookie,
(music_req, cookie) => {
console.log(music_req)
res.set({
'Set-Cookie': cookie,
})
res.send(music_req)
},
err => res.status(502).send('fetch error')
)
})
module.exports = router
\ No newline at end of file
const express = require("express")
const crypto = require('crypto')
const router = express()
const { createWebAPIRequest } = require("../util/util")
router.get("/", (req, res) => {
const phone = req.query.phone
const cookie = req.get('Cookie') ? req.get('Cookie') : ''
const md5sum = crypto.createHash('md5')
md5sum.update(req.query.password)
const data = {
'phone': phone,
'password': md5sum.digest('hex'),
'rememberLogin': 'true'
}
createWebAPIRequest(
'music.163.com',
'/weapi/login/cellphone',
'POST',
data,
cookie,
(music_req, cookie) => {
console.log(music_req)
res.set({
'Set-Cookie': cookie,
})
res.send(music_req)
},
err => res.status(502).send('fetch error')
)
})
module.exports = router
\ No newline at end of file
const express = require("express")
const router = express()
const { createRequest } = require("../util/util")
router.get("/", (req, res) => {
const id = req.query.id
createRequest('/api/song/lyric?os=osx&id=' + id + '&lv=-1&kv=-1&tv=-1', 'GET', null)
.then(result => {
res.setHeader("Content-Type", "application/json")
res.send(result)
})
.catch(err => {
res.status(502).send('fetch error')
})
})
module.exports = router
\ No newline at end of file
const express = require("express")
const router = express()
const { createWebAPIRequest } = require("../util/util")
router.get("/", (req, res) => {
const id = parseInt(req.query.id)
const br = parseInt(req.query.br || 999000)
const data = {
"ids": [id],
"br": br,
"csrf_token": ""
}
const cookie = req.get('Cookie') ? req.get('Cookie') : ''
createWebAPIRequest(
'music.163.com',
'/weapi/song/enhance/player/url',
'POST',
data,
cookie,
music_req => {
res.setHeader("Content-Type", "application/json")
res.send(music_req)
},
err => {
res.status(502).send('fetch error')
}
)
})
module.exports = router
\ No newline at end of file
const http = require('http')
const express = require("express")
const router = express()
const { createWebAPIRequest } = require("../util/util")
router.get("/", (req, res) => {
const cookie = req.get('Cookie') ? req.get('Cookie') : ''
let detail, imgurl
const data = {
"id": req.query.id,
"offset": 0,
"total": true,
"limit": 1000,
"n": 1000,
"csrf_token": ""
}
createWebAPIRequest(
'music.163.com',
'/weapi/v3/playlist/detail',
'POST',
data,
cookie,
music_req=> {
console.log(music_req)
detail = music_req
mergeRes()
},
err =>{
res.status(502).send('fetch error')
}
)
// FIXME:i dont know the api to get coverimgurl
// so i get it by parsing html
const http_client = http.get({
hostname: 'music.163.com',
path: '/playlist?id=' + req.query.id,
headers: {
'Referer': 'http://music.163.com',
},
}, function (res) {
res.setEncoding('utf8')
let html = ''
res.on('data', function (chunk) {
html += chunk
})
res.on('end', function () {
console.log('end', html)
const regImgCover = /\<img src=\"(.*)\" class="j-img"/ig
imgurl = regImgCover.exec(html)[1]
mergeRes()
})
})
function mergeRes() {
if (imgurl != undefined && detail != undefined) {
detail = JSON.parse(detail)
detail.playlist.picUrl = imgurl
res.send(detail)
}
}
})
module.exports = router
\ No newline at end of file
const express = require("express")
const router = express()
const { createWebAPIRequest } = require("../util/util")
router.get("/", (req, res) => {
const op = req.query.op
const pid = req.query.pid
const tracks = req.query.tracks
const cookie = req.get('Cookie') ? req.get('Cookie') : ''
// console.log('COOKIESS', cookie)
const data = {
"op": op,
"pid": pid,
"tracks": tracks,
"trackIds": JSON.stringify([tracks]),
"csrf_token": "",
}
createWebAPIRequest(
'music.163.com',
'/weapi/playlist/manipulate/tracks',
'POST',
data,
cookie,
music_req => res.send(music_req),
err => res.status(502).send('fetch error')
)
})
module.exports = router
\ No newline at end of file
const express = require("express")
const router = express()
const { createWebAPIRequest } = require("../util/util")
router.get("/", (req, res) => {
const cookie = req.get('Cookie') ? req.get('Cookie') : ''
const data = {
"csrf_token": ""
}
createWebAPIRequest(
'music.163.com',
'/weapi/v1/discovery/recommend/resource',
'POST',
data,
cookie,
music_req => res.send(music_req),
err => res.status(502).send('fetch error')
)
})
module.exports = router
\ No newline at end of file
const express = require("express")
const router = express()
const { createWebAPIRequest } = require("../util/util")
router.get("/",(req,res)=>{
const cookie = req.get('Cookie') ? req.get('Cookie') : ''
const data = {
"offset": 0,
"total": true,
"limit": 20,
"csrf_token": ""
}
createWebAPIRequest(
'music.163.com',
'/weapi/v1/discovery/recommend/songs',
'POST',
data,
cookie,
music_req => res.send(music_req),
err => res.status(502).send('fetch error')
)
})
module.exports=router
\ No newline at end of file
const express = require("express")
const router = express()
const { createRequest } = require("../util/util")
router.get("/", (req, res) => {
const keywords = req.query.keywords
const type = req.query.type || 1
const limit = req.query.limit || 30
const data = 's=' + keywords + '&limit=' + limit + '&type=' + type + '&offset=0'
createRequest('/api/search/pc/', 'POST', data)
.then(result => {
res.setHeader("Content-Type", "application/json")
res.send(result)
})
.catch(err => {
res.status(502).send('fetch error')
})
})
module.exports = router
\ No newline at end of file
const express = require("express")
const router = express()
const { createWebAPIRequest } = require("../util/util")
router.get("/", (req, res) => {
const cookie = req.get('Cookie') ? req.get('Cookie') : ''
const data = {
"offset": 0,
"uid": req.query.uid,
"limit": 1000,
"csrf_token": ""
}
createWebAPIRequest(
'music.163.com',
'/weapi/user/playlist',
'POST',
data,
cookie,
music_req => res.send(music_req),
err => res.status(502).send('fetch error')
)
})
module.exports = router
\ No newline at end of file
import { search } from './component/search'
import { song } from './component/song'
import { lrc } from './component/lrc'
import { getArtistAlbums } from './component/getArtistAlbums'
import { getAlbums } from './component/getAlbums'
import { getPlaylists } from './component/getPlaylists'
let api = {
search: search,
song: song,
lrc: lrc,
getArtistAlbums: getArtistAlbums,
getAlbums: getAlbums,
getPlaylists: getPlaylists
}
export {api}
import request from 'request'
import { origin, globalOption } from '../config'
import { deepCopy } from '../util'
const getAlbums = (id, callback) => {
const option = deepCopy(globalOption)
const url = `${origin}/api/album/${id}`
const method = 'get'
Object.assign(option, {url, method})
request(option, (err, res, body) => {
if(!err && res.statusCode == 200) {
let info = JSON.parse(body)
callback && callback(JSON.stringify(info, '', 2))
} else {
console.error(err)
}
})
}
export { getAlbums }
import request from 'request'
import { origin, globalOption } from '../config'
import { deepCopy } from '../util'
const getArtistAlbums = (id, callback, limit = 3, offset = 0) => {
const option = deepCopy(globalOption)
const url = `${origin}/api/artist/albums/${id}?offset=${offset}&limit=${limit}`
const method = 'GET'
Object.assign(option, {url, method})
request(option, (err, res, body) => {
if(!err && res.statusCode == 200) {
let info = JSON.parse(body)
callback && callback(JSON.stringify(info, '', 2))
} else {
console.error(err)
}
})
}
export { getArtistAlbums }
import request from 'request'
import { origin, globalOption } from '../config'
import { deepCopy } from '../util'
const getPlaylists = (id, callback) => {
const option = deepCopy(globalOption)
const url = `${origin}/api/playlist/detail?id=${id}`
const method = 'get'
Object.assign(option, {url, method})
request(option, (err, res, body) => {
if(!err && res.statusCode == 200) {
let info = JSON.parse(body)
callback && callback(JSON.stringify(info, '', 2))
} else {
console.error(err)
}
})
}
export { getPlaylists }
import request from 'request'
import { origin, globalOption } from '../config'
import { deepCopy } from '../util'
const lrc = (id, callback = null, lv = -1) => {
const option = deepCopy(globalOption)
const url = `${origin}/api/song/lyric?lv=${lv}&id=${id}`
const method = 'GET'
Object.assign(option, { url, method })
request(option, (err, res, body) => {
if (!err && res.statusCode == 200) {
let info = JSON.parse(body)
callback && callback(JSON.stringify(info, '', 2))
} else {
console.error(err)
}
})
}
export { lrc }
import request from 'request'
import { origin, globalOption } from '../config'
import { deepCopy } from '../util'
const search = (name = null, callback = null,onlySong=true, limit = 3, offset = 0) => {
const option = deepCopy(globalOption)
const url = `${origin}/api/search/get`
const form = {
s: name,
limit,
type: 1,
offset
}
const method = 'POST'
Object.assign(option, { url, form, method })
request(option, (err, res, body) => {
if (!err && res.statusCode == 200) {
let info = JSON.parse(body)
let data
if(onlySong){
data=info.result.songs
}else{
data={songs:info.result.songs,mvs:info.result.mvs}
}
callback&&callback(JSON.stringify(data,'',2))
} else {
console.error(err)
}
})
}
export { search }
import request from 'request'
import { origin, globalOption } from '../config'
import { deepCopy } from '../util'
const song = (id, callback = null) => {
const option = deepCopy(globalOption)
const url = `${origin}/api/song/detail?ids=%5B${id}%5d`
const method = 'GET'
Object.assign(option, { url, method })
request(option, (err, res, body) => {
if (!err && res.statusCode == 200) {
let info = JSON.parse(body);
callback && callback(JSON.stringify(info, '', 2))
} else {
console.error(err)
}
})
}
export { song }
const origin = 'http://music.163.com'
const globalOption = {
headers: {
'Origin': origin,
'Referer': origin,
'Content-Type': 'application/x-www-form-urlencoded'
},
proxy:false
}
export { origin, globalOption }
const deepCopy = obj => JSON.parse(JSON.stringify(obj))
export { deepCopy }
const assert = require('assert')
const crypto = require('crypto')
const { createWebAPIRequest } = require("../util/util")
describe('测试登录是否正常', () => {
it('手机登录 code 应该等于200', done => {
const phone = "换成你的手机号"
const password = "换成你的密码"
let cookie = ''
const md5sum = crypto.createHash('md5')
md5sum.update(password)
const data = {
'phone': phone,
'password': md5sum.digest('hex'),
'rememberLogin': 'true'
}
createWebAPIRequest(
'music.163.com',
'/weapi/login/cellphone',
'POST',
data,
cookie,
(music_req, cookie) => {
const result = JSON.parse(music_req)
console.log({
loginType: result.loginType,
code: result.code,
account: result.account
})
assert(result.code === 200)
done()
},
err => done(err)
)
})
it('邮箱登录 code 应该等于200', done => {
const email = "换成你的163网易邮箱"
const password = "换成你的密码"
const cookie = ''
const md5sum = crypto.createHash('md5')
md5sum.update(password)
const data = {
'username': email,
'password': md5sum.digest('hex'),
'rememberLogin': 'true'
}
createWebAPIRequest(
'music.163.com',
'/weapi/login',
'POST',
data,
cookie,
(music_req, cookie) => {
const result = JSON.parse(music_req)
console.log({
loginType: result.loginType,
code: result.code,
account: result.account
})
assert(result.code === 200)
done()
},
err => done(err)
)
})
})
\ No newline at end of file
const assert = require('assert')
const crypto = require('crypto')
const { createRequest } = require("../util/util")
const phone = "换成你的账号"
const password = "换成你的密码"
describe('测试获取歌词是否正常', () => {
it('数据应该有 lrc 字段', done => {
const id = 347230
createRequest('/api/song/lyric?os=osx&id=' + id + '&lv=-1&kv=-1&tv=-1', 'GET', null)
.then(result => {
console.log(JSON.parse(result).lrc)
assert(typeof JSON.parse(result).lrc!=='undefined')
done()
})
.catch(err => {
done(err)
})
})
})
\ No newline at end of file
const assert = require('assert')
const crypto = require('crypto')
const { createWebAPIRequest } = require("../util/util")
const phone = "换成你的账号"
const password = "换成你的密码"
describe('测试获取歌曲是否正常', () => {
it('歌曲的 url 不应该为空', done => {
const id = 347230
const br = 999000
const data = {
"ids": [id],
"br": br,
"csrf_token": ""
}
const cookie = ''
createWebAPIRequest(
'music.163.com',
'/weapi/song/enhance/player/url',
'POST',
data,
cookie,
music_req => {
console.log(JSON.parse(music_req).data[0].url)
assert(!!JSON.parse(music_req).data[0].url)
done()
},
err => {
done(err)
}
)
})
})
\ No newline at end of file
const assert = require('assert')
const crypto = require('crypto')
const { createRequest } = require("../util/util")
const phone = "换成你的账号"
const password = "换成你的密码"
describe('测试搜索是否正常', () => {
it('获取到的数据的 name 应该和搜索关键词一致', done => {
const keywords = "海阔天空"
const type = 1
const limit = 30
const data = 's=' + keywords + '&limit=' + limit + '&type=' + type + '&offset=0'
createRequest('/api/search/pc/', 'POST', data)
.then(result => {
console.log(JSON.parse(result).result.songs[0].mp3Url)
assert(JSON.parse(result).result.songs[0].name === '海阔天空')
done()
})
.catch(err => {
done(err)
})
})
})
\ No newline at end of file
// import { api } from '../src/app.js'
// const { api } =require('../src/app.js')
var api=require('../build/app.js').api
api.search("年度之歌",data => {
console.log("################Search API#################")
console.log(data)
})
api.song('308169',data => {
console.log("################Song API#################")
console.log(data)
})
api.lrc('5243023',data => {
console.log("################Lrc API#################")
console.log(data)
})
api.getArtistAlbums('9952', data => {
console.log('####################Artist Albums##############')
console.log(data)
})
api.getAlbums('32311', data => {
console.log("####################Albums####################")
console.log(data)
})
api.getPlaylists('311785002', data => {
console.log("####################Playlists####################")
console.log(data)
})
// 参考 https://github.com/darknessomi/musicbox/wiki/
'use strict'
const crypto = require('crypto')
const bigInt = require('big-integer')
const modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
const nonce = '0CoJUm6Qyw8W8jud'
const pubKey = '010001'
String.prototype.hexEncode = function(){
let hex, i
let result = ""
for (i=0; i<this.length; i++) {
hex = this.charCodeAt(i).toString(16)
result += (""+hex).slice(-4)
}
return result
}
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
}
function aesEncrypt(text, secKey) {
const _text = text
const lv = new Buffer('0102030405060708', "binary")
const _secKey = new Buffer(secKey, "binary")
const cipher = crypto.createCipheriv('AES-128-CBC', _secKey, lv)
let encrypted = cipher.update(_text, 'utf8', 'base64')
encrypted += cipher.final('base64')
return encrypted
}
function zfill(str, size) {
while (str.length < size) str = "0" + str
return str
}
function rsaEncrypt(text, pubKey, modulus) {
const _text = text.split('').reverse().join('')
const biText = bigInt(new Buffer(_text).toString('hex'), 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
}
}
module.exports = Encrypt
\ No newline at end of file
const Encrypt = require('./crypto.js')
const http = require('http')
function createWebAPIRequest(host, path, method, data, cookie, callback, errorcallback) {
let music_req = ''
const cryptoreq = Encrypt(data)
const http_client = http.request({
hostname: host,
method: method,
path: path,
headers: {
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': 'http://music.163.com',
'Host': 'music.163.com',
'Cookie': cookie,
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36',
},
}, function (res) {
res.on('error', function (err) {
errorcallback(err)
})
res.setEncoding('utf8')
if (res.statusCode != 200) {
createWebAPIRequest(host, path, method, data, cookie, callback)
return
} else {
res.on('data', function (chunk) {
music_req += chunk
})
res.on('end', function () {
if (music_req == '') {
createWebAPIRequest(host, path, method, data, cookie, callback)
return
}
if (res.headers['set-cookie']) {
callback(music_req, res.headers['set-cookie'])
} else {
callback(music_req)
}
})
}
})
http_client.write('params=' + cryptoreq.params + '&encSecKey=' + cryptoreq.encSecKey)
http_client.end()
}
function createRequest(path, method, data, callback, errorcallback) {
return new Promise((resolve, reject) => {
let ne_req = ''
const http_client = http.request({
hostname: 'music.163.com',
method: method,
path: path,
headers: {
'Referer': 'http://music.163.com',
'Cookie': 'appver=2.0.2',
'Content-Type': 'application/x-www-form-urlencoded',
},
}, res => {
res.setEncoding('utf8')
res.on('error', err => {
reject(err)
})
res.on('data', chunk => {
ne_req += chunk
})
res.on('end', () => {
resolve(ne_req)
})
})
if (method == 'POST') {
http_client.write(data)
}
http_client.end()
})
}
module.exports = {
createWebAPIRequest,
createRequest
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册