Created
June 12, 2017 08:52
-
-
Save bloatfan/939ff70d2acd3c27262f02fc40778720 to your computer and use it in GitHub Desktop.
Netease.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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