Skip to content

Instantly share code, notes, and snippets.

@bloatfan
Created June 12, 2017 08:52
Show Gist options
  • Save bloatfan/939ff70d2acd3c27262f02fc40778720 to your computer and use it in GitHub Desktop.
Save bloatfan/939ff70d2acd3c27262f02fc40778720 to your computer and use it in GitHub Desktop.
Netease.js
const http = require('http');
const pack = require('./pack.js');
const crypto = require('crypto');
const querystring = require('querystring');
// 私有方法
const neteaseAESECB = Symbol('neteaseAESECB');
const getHttpOption = Symbol('getHttpOption');
const makeRequest = Symbol('makeRequest');
const onResponse = Symbol('onResponse');
// 参数加密秘钥,不要改变 !!!
const secret = '7246674226682325323F5E6544673A51';
class Netease {
constructor () {
}
/**
* 根据歌曲 id 获取歌曲信息
*
* @param {Integer} id 歌曲 id
*
* @return {Promise}
*/
song (id) {
var body = {
"method": "POST",
"params": {
"c": "[{\"id\":" + id + "}]"
},
"url": "http://music.163.com/api/v3/song/detail"
};
var form = this[neteaseAESECB](body);
var options = this[getHttpOption]('POST', '/api/linux/forward', Buffer.byteLength(form));
return this[makeRequest](options, form);
}
/**
* 根据歌曲 id 获取歌词
*
* @param {Integer} id 歌曲 id
*
* @return {Object}
*/
lyric (id) {
var body = {
'method': 'POST',
'params': {
'id': id,
'os': 'linux',
'lv': -1,
'kv': -1,
'tv': -1,
},
'url': 'http://music.163.com/api/song/lyric',
};
var form = this[neteaseAESECB](body);
var options = this[getHttpOption]('POST', '/api/linux/forward', Buffer.byteLength(form));
return this[makeRequest](options, form);
}
/**
* 私有方法,加密
*
* @param {Object} body 表单数据
*
* @return {String} 加密后的表单数据
*/
[neteaseAESECB] (body) {
body = JSON.stringify(body);
var password = pack('H*', secret);
var cipher = crypto.createCipheriv('aes-128-ecb', password, '');
body = cipher.update(body, 'utf8', 'base64') + cipher.final('base64');
var hex = new Buffer(body, 'base64').toString('hex');
body = hex.toUpperCase();
var form = {
'eparams': body
};
form = querystring.stringify(form);
return form;
}
/**
* 获取请求选项
*
* @param {String} method GET | POST
* @param {String} path http 请求路径
* @param {Integer} contentLength 如何是 POST 请求,参数长度
*
* @return Object
*/
[getHttpOption] (method, path, contentLength) {
var options = {
hostname: 'music.163.com',
port: 80,
path: path,
method: method,
headers: {
'referer': 'https://music.163.com/',
'cookie': 'os=linux; appver=1.0.0.1026; osver=Ubuntu%2016.10; MUSIC_U=78d411095f4b022667bc8ec49e9a44cca088df057d987f5feaf066d37458e41c4a7d9447977352cf27ea9fee03f6ec4441049cea1c6bb9b6; __remember_me=true',
'useragent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
}
};
if ('POST' == method) {
options['headers']['Content-Type'] = 'application/x-www-form-urlencoded';
options['headers']['Content-Length'] = contentLength
}
return options;
}
/**
* 发送请求
*
* @param {Object} options 请求选项
* @param {String} form 表单数据
*
* @return Promise
*/
[makeRequest] (options, form) {
return new Promise((resolve, reject) => {
const req = http.request(options, (res) => {
res.setEncoding('utf8');
this[onResponse](res, resolve, reject)
});
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
// write data to request body
req.write(form);
req.end();
});
}
/**
* 回应处理
*
* @param {http.ServerResponse} response
* @param {Promise.resolve} resolve
* @param {Promise.reject} reject
*/
[onResponse] (response, resolve, reject) {
const hasResponseFailed = response.status >= 400;
var responseBody = '';
if (hasResponseFailed) {
reject(`Request to ${response.url} failed with HTTP ${response.status}`);
}
/* the response stream's (an instance of Stream) current data. See:
* https://nodejs.org/api/stream.html#stream_event_data */
response.on('data', chunk => responseBody += chunk.toString());
// once all the data has been read, resolve the Promise
response.on('end', () => resolve(responseBody));
}
}
module.exports = Netease;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment