提交 5826b245 编写于 作者: B binaryify 提交者: GitHub

Merge pull request #330 from nondanee/bandage

中秋节翌日大礼包😂
...@@ -45,11 +45,20 @@ app.use(express.static(path.resolve(__dirname, 'public'))) ...@@ -45,11 +45,20 @@ app.use(express.static(path.resolve(__dirname, 'public')))
app.use(function(req, res, next) { app.use(function(req, res, next) {
const proxy = req.query.proxy const proxy = req.query.proxy
if (proxy) { if (proxy) {
req.headers.cookie = req.headers.cookie + `__proxy__${proxy}` req.headers.cookie += `__proxy__${proxy}`
} }
next() next()
}) })
// 补全缺失的cookie
const { completeCookie } = require('./util/init')
app.use(function(req, res, next) {
let cookie = completeCookie(req.headers.cookie)
req.headers.cookie = cookie.map(x => x[0]).concat(req.headers.cookie || []).join('; ')
res.append('Set-Cookie', cookie.map(x => (x.concat('Path=/').join('; '))))
next()
})
// 因为这几个文件对外所注册的路由 和 其他文件对外注册的路由规则不一样, 所以专门写个MAP对这些文件做特殊处理 // 因为这几个文件对外所注册的路由 和 其他文件对外注册的路由规则不一样, 所以专门写个MAP对这些文件做特殊处理
const UnusualRouteFileMap = { const UnusualRouteFileMap = {
// key 为文件名, value 为对外注册的路由 // key 为文件名, value 为对外注册的路由
...@@ -80,9 +89,6 @@ fs.readdirSync(path.resolve(__dirname, 'router')) ...@@ -80,9 +89,6 @@ fs.readdirSync(path.resolve(__dirname, 'router'))
file file
.replace(/\.js$/i, '') .replace(/\.js$/i, '')
.replace(/_/g, '/') .replace(/_/g, '/')
.replace(/[A-Z]/g, a => {
return '/' + a.toLowerCase()
})
} }
app.use(route, Wrap(require('./router/' + file))) app.use(route, Wrap(require('./router/' + file)))
...@@ -90,7 +96,7 @@ fs.readdirSync(path.resolve(__dirname, 'router')) ...@@ -90,7 +96,7 @@ fs.readdirSync(path.resolve(__dirname, 'router'))
const port = process.env.PORT || 3000 const port = process.env.PORT || 3000
app.listen(port, () => { app.server = app.listen(port, () => {
console.log(`server running @ http://localhost:${port}`) console.log(`server running @ http://localhost:${port}`)
}) })
......
const fs = require('fs')
const path = require('path')
let app
before(() => {
app = require('./app.js')
global.host = 'http://localhost:' + app.server.address().port
})
after((done) => {
app.server.close(done)
})
fs.readdirSync(path.resolve(__dirname, 'test'))
.forEach(file => {
require('./test/' + file)
})
\ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"description": "网易云音乐 NodeJS 版 API", "description": "网易云音乐 NodeJS 版 API",
"scripts": { "scripts": {
"start": "node app.js", "start": "node app.js",
"test": "mocha -r intelli-espower-loader -t 20000 test" "test": "mocha -r intelli-espower-loader -t 20000 app.test.js --exit"
}, },
"keywords": [ "keywords": [
"网易云音乐", "网易云音乐",
......
...@@ -3,9 +3,8 @@ module.exports = (req, res, createWebAPIRequest, request) => { ...@@ -3,9 +3,8 @@ module.exports = (req, res, createWebAPIRequest, request) => {
url: "http://music.163.com/discover", url: "http://music.163.com/discover",
method: "GET", method: "GET",
headers: { headers: {
Referer: "http://music.163.com", "Referer": "http://music.163.com",
"User-Agent": "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3380.0 Safari/537.36"
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3380.0 Safari/537.36"
} }
}; };
request(options, (error, response, body) => { request(options, (error, response, body) => {
...@@ -13,8 +12,7 @@ module.exports = (req, res, createWebAPIRequest, request) => { ...@@ -13,8 +12,7 @@ module.exports = (req, res, createWebAPIRequest, request) => {
res.status(502).send("fetch error"); res.status(502).send("fetch error");
} else { } else {
try { try {
const pattern = /<script[^>]*>\s*window\.Gbanners\s*=\s*([^;]+?);\s*<\/script>/g; const banners = /Gbanners\s*=\s*([^;]+);/.exec(body)[1];
const banners = pattern.exec(body)[1];
res.send(JSON.stringify(eval(`({code:200,banners:${banners}})`))); res.send(JSON.stringify(eval(`({code:200,banners:${banners}})`)));
} catch (error) { } catch (error) {
res.status(502).send("fetch error"); res.status(502).send("fetch error");
......
...@@ -15,8 +15,11 @@ module.exports = (req, res, createWebAPIRequest, request) => { ...@@ -15,8 +15,11 @@ module.exports = (req, res, createWebAPIRequest, request) => {
data, data,
cookie, cookie,
music_req => { music_req => {
if (JSON.parse(music_req).code == 200) { music_req = JSON.parse(music_req)
return res.send({ success: true, message: 'ok' }) if (music_req.code == 200) {
if (music_req.data[0].code == 200){
return res.send({ success: true, message: 'ok' })
}
} }
return res.send({ success: false, message: '亲爱的,暂无版权' }) return res.send({ success: false, message: '亲爱的,暂无版权' })
}, },
......
...@@ -21,10 +21,7 @@ module.exports = (req, res, createWebAPIRequest, request) => { ...@@ -21,10 +21,7 @@ module.exports = (req, res, createWebAPIRequest, request) => {
cookie, cookie,
(music_req, cookie) => { (music_req, cookie) => {
// console.log(music_req) // console.log(music_req)
cookie = cookie && cookie.map(x => x.replace('Domain=.music.163.com', '')) res.append("Set-Cookie", cookie)
res.set({
'Set-Cookie': cookie
})
res.send(music_req) res.send(music_req)
}, },
err => res.status(502).send('fetch error') err => res.status(502).send('fetch error')
......
...@@ -17,15 +17,8 @@ module.exports = (req, res, createWebAPIRequest, request) => { ...@@ -17,15 +17,8 @@ module.exports = (req, res, createWebAPIRequest, request) => {
"POST", "POST",
data, data,
cookie, cookie,
(music_req, cookie = []) => { (music_req, cookie) => {
const cookieStr = res.append("Set-Cookie", cookie);
"appver=1.5.9;os=osx; channel=netease;osver=%E7%89%88%E6%9C%AC%2010.13.2%EF%BC%88%E7%89%88%E5%8F%B7%2017C88%EF%BC%89";
cookieStr.split(";").forEach(item => {
cookie.push(item + ";Path=/");
});
res.set({
"Set-Cookie": cookie
});
res.send(music_req); res.send(music_req);
}, },
err => res.status(502).send("fetch error") err => res.status(502).send("fetch error")
......
...@@ -11,9 +11,7 @@ module.exports = (req, res, createWebAPIRequest, request) => { ...@@ -11,9 +11,7 @@ module.exports = (req, res, createWebAPIRequest, request) => {
data, data,
cookie, cookie,
(music_req, cookie) => { (music_req, cookie) => {
res.set({ res.append("Set-Cookie", cookie);
"Set-Cookie": cookie
});
res.send(music_req); res.send(music_req);
}, },
err => res.status(502).send("fetch error") err => res.status(502).send("fetch error")
......
...@@ -7,14 +7,13 @@ module.exports = (req, res, createWebAPIRequest, request) => { ...@@ -7,14 +7,13 @@ module.exports = (req, res, createWebAPIRequest, request) => {
"GET", "GET",
{}, {},
cookie, cookie,
(music_req, cookie) => { music_req => {
try { try {
var userInfo = (/var GUser=([^;]+);/g).exec(music_req)[1]; var profile = /GUser\s*=\s*([^;]+);/.exec(music_req)[1];
var bindInfo = (/var GBinds=([^;]+);/g).exec(music_req)[1]; var bindings = /GBinds\s*=\s*([^;]+);/.exec(music_req)[1];
userInfo = eval(`(${userInfo})`); profile = eval(`(${profile})`);
userInfo.userBind = eval(`(${bindInfo})`); bindings = eval(`(${bindings})`);
userInfo.userBind.forEach((item) => {item.tokenJsonStr = JSON.parse(item.tokenJsonStr)}); res.send({code: 200, profile: profile, bindings: bindings});
res.send(userInfo);
} catch (error) { } catch (error) {
res.status(502).send("fetch error"); res.status(502).send("fetch error");
} }
......
//登出
module.exports = (req, res, createWebAPIRequest, request) => {
const cookie = req.get('Cookie') ? req.get('Cookie') : ''
createWebAPIRequest(
'music.163.com',
'/weapi/logout',
'POST',
{},
cookie,
(music_req, cookie) => {
res.append("Set-Cookie", cookie)
res.send(music_req)
},
err => res.status(502).send('fetch error')
)
}
const assert = require('assert') const assert = require('assert')
const crypto = require('crypto') const request = require('request')
const { createRequest } = require('../util/util') host = global.host || 'http://localhost:3000'
describe('测试获取歌手专辑列表是否正常', () => { describe('测试获取歌手专辑列表是否正常', () => {
it('数据的 code 应该为200', done => { it('数据的 code 应该为200', done => {
const id = 32311 const qs = {
createRequest(`/api/album/${id}`, 'GET', null) id: 32311
.then(result => { }
const code = JSON.parse(result).code
console.log('code:' + code) request.get({url: `${host}/album`,qs: qs}, (err, res, body) => {
assert(code === 200) if (!err && res.statusCode == 200) {
body = JSON.parse(body)
assert(body.code === 200)
done() done()
}) }
.catch(err => done(err)) else{
done(err)
}
})
}) })
}) })
const assert = require('assert') const assert = require('assert')
const crypto = require('crypto') const request = require('request')
const { createWebAPIRequest } = require('../util/util') host = global.host || 'http://localhost:3000'
describe('测试获取评论是否正常', () => { describe('测试获取评论是否正常', () => {
it('数据的 code 应该为200', done => { it('数据的 code 应该为200', done => {
const rid = 32311 const qs = {
const cookie = '' id: 32311
const data = {
offset: 0,
rid: rid,
limit: 20,
csrf_token: ''
} }
createWebAPIRequest(
'music.163.com', request.get({url: `${host}/comment/album`,qs: qs}, (err, res, body) => {
`/weapi/v1/resource/comments/R_SO_4_${rid}/?csrf_token=`, if (!err && res.statusCode == 200) {
'POST', body = JSON.parse(body)
data, assert(body.code === 200)
cookie,
music_req => {
console.log({
code: JSON.parse(music_req).code
})
assert(JSON.parse(music_req).code === 200)
done() done()
}, }
err => done(err) else{
) done(err)
}
})
}) })
}) })
const assert = require("assert"); const assert = require('assert')
const crypto = require("crypto"); const request = require('request')
const { createWebAPIRequest } = require("../util/util"); host = global.host || 'http://localhost:3000'
console.log("注意:测试登陆需要替换这里的账号密码!!!"); console.log("注意: 测试登录需在 test/login.test.js 中填写账号密码!!!");
describe("测试登录是否正常", () => { describe("测试登录是否正常", () => {
it("手机登录 code 应该等于200", done => { it("手机登录 code 应该等于200", done => {
const phone = "换成你的手机号"; const qs = {
const password = "换成你的密码";
let cookie = "";
const md5sum = crypto.createHash("md5");
md5sum.update(password);
const data = {
phone: phone, phone: phone,
password: md5sum.digest("hex"), password: password
rememberLogin: "true" }
};
createWebAPIRequest( request.get({url: `${host}/login/cellphone`,qs: qs}, (err, res, body) => {
"music.163.com", if (!err && res.statusCode == 200) {
"/weapi/login/cellphone", body = JSON.parse(body)
"POST", assert(body.code === 200)
data, done()
cookie, }
(music_req, cookie) => { else{
const result = JSON.parse(music_req); done(err)
console.log({ }
loginType: result.loginType, })
code: result.code, })
account: result.account })
});
assert(result.code === 200);
done();
},
err => done(err)
);
});
});
const assert = require("assert"); const assert = require('assert')
const crypto = require("crypto"); const request = require('request')
const { createWebAPIRequest } = require("../util/util"); host = global.host || 'http://localhost:3000'
describe("测试获取歌词是否正常", () => { describe("测试获取歌词是否正常", () => {
it("数据应该有 lrc 字段", done => { it("数据应该有 lrc 字段", done => {
const cookie = ""; const qs = {
const data = {}; id: 347230
const id = 347230; }
createWebAPIRequest(
"music.163.com", request.get({url: `${host}/lyric`,qs: qs}, (err, res, body) => {
"/weapi/song/lyric?os=osx&id=" + id + "&lv=-1&kv=-1&tv=-1", if (!err && res.statusCode == 200) {
"POST", body = JSON.parse(body)
data, assert(typeof body.lrc !== "undefined")
cookie, done()
music_req => { }
console.log(music_req); else{
assert(typeof JSON.parse(music_req).lrc !== "undefined"); done(err)
done(); }
// res.send(music_req) })
}, })
err => res.status(502).send("fetch error") })
);
});
});
const assert = require("assert");
const crypto = require("crypto");
const { createWebAPIRequest } = require("../util/util");
describe("测试获取歌曲是否正常", () => {
it("歌曲的 url 不应该为空", done => {
const id = 462791935;
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(music_req);
console.log(JSON.parse(music_req).data[0].url);
assert(!!JSON.parse(music_req).data[0].url);
done();
},
err => {
done(err);
}
);
});
});
const assert = require('assert')
const request = require('request')
host = global.host || 'http://localhost:3000'
describe("测试获取歌曲是否正常", () => {
it("歌曲的 url 不应该为空", done => {
const qs = {
id: 462791935,
br: 999000
}
request.get({url: `${host}/music/url`,qs: qs}, (err, res, body) => {
if (!err && res.statusCode == 200) {
body = JSON.parse(body)
assert(!!body.data[0].url)
done()
}
else{
done(err)
}
})
});
});
const assert = require('assert') const assert = require('assert')
const crypto = require('crypto') const request = require('request')
const { createRequest } = require('../util/util') host = global.host || 'http://localhost:3000'
describe('测试搜索是否正常', () => { describe('测试搜索是否正常', () => {
it('获取到的数据的 name 应该和搜索关键词一致', done => { it('获取到的数据的 name 应该和搜索关键词一致', done => {
const keywords = '海阔天空' const qs = {
const type = 1 keywords: '海阔天空',
const limit = 30 type: 1
const data = }
's=' + keywords + '&limit=' + limit + '&type=' + type + '&offset=0' request.get({url: `${host}/search`,qs: qs}, (err, res, body) => {
createRequest('/api/search/pc/', 'POST', data) if (!err && res.statusCode == 200) {
.then(result => { body = JSON.parse(body)
console.log(JSON.parse(result).result.songs[0].mp3Url) assert(body.result.songs[0].name === '海阔天空')
assert(JSON.parse(result).result.songs[0].name === '海阔天空')
done() done()
}) }
.catch(err => { else{
done(err) done(err)
}) }
})
}) })
}) })
function randomString(pattern, length){ function randomString(pattern, length){
return Array.apply(null, {length: length}).map(() => (pattern[Math.floor(Math.random() * pattern.length)])).join(''); return Array.apply(null, {length: length}).map(() => (pattern[Math.floor(Math.random() * pattern.length)])).join('')
} }
const jsessionid = randomString('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ\\/+',176) + ':' + (new Date).getTime(); function completeCookie(cookie){
const nuid = randomString('0123456789abcdefghijklmnopqrstuvwxyz',32); let origin = (cookie || '').split(/;\s*/).map(element => (element.split('=')[0])), extra = []
let now = (new Date).getTime()
module.exports = `JSESSIONID-WYYY=${jsessionid}; _iuqxldmzr_=32; _ntes_nnid=${nuid},${(new Date).getTime()}; _ntes_nuid=${nuid}`; if(!origin.includes('JSESSIONID-WYYY')){
\ No newline at end of file let expire = new Date(now + 1800000) //30 minutes
let jessionid = randomString('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ\\/+',176) + ':' + expire.getTime()
extra.push(['JSESSIONID-WYYY=' + jessionid, 'Expires=' + expire.toGMTString()])
}
if(!origin.includes('_iuqxldmzr_')){
let expire = new Date(now + 157680000000) //5 years
extra.push(['_iuqxldmzr_=32', 'Expires=' + expire.toGMTString()])
}
if((!origin.includes('_ntes_nnid'))||(!origin.includes('_ntes_nuid'))){
let expire = new Date(now + 3153600000000) //100 years
let nnid = randomString('0123456789abcdefghijklmnopqrstuvwxyz',32) + ',' + now
extra.push(['_ntes_nnid=' + nnid, 'Expires=' + expire.toGMTString()])
extra.push(['_ntes_nuid=' + nnid.slice(0,32), 'Expires=' + expire.toGMTString()])
}
return extra
}
module.exports = {
completeCookie
}
\ No newline at end of file
const Encrypt = require("./crypto.js"); const Encrypt = require("./crypto.js");
const request = require("request"); const request = require("request");
const querystring = require("querystring"); const queryString = require("querystring");
const baseCookie = require("./init.js");
request.debug = true; request.debug = true;
...@@ -38,31 +37,34 @@ function createWebAPIRequest( ...@@ -38,31 +37,34 @@ function createWebAPIRequest(
data, data,
cookie, cookie,
callback, callback,
errorcallback errorCallback
) { ) {
// console.log(cookie); const csrfToken = cookie.match(/_csrf=([^(;|$)]+)/);
if (cookie.match(/_csrf=[^(;|$)]+/g)) if (csrfToken)
data.csrf_token = cookie.match(/_csrf=[^(;|$)]+/g)[0].slice(6); data.csrf_token = csrfToken[1];
else data.csrf_token = ""; else
data.csrf_token = "";
const proxy = cookie.split("__proxy__")[1]; const proxy = cookie.split("__proxy__")[1];
cookie = cookie.split("__proxy__")[0]; cookie = cookie.split("__proxy__")[0];
const cryptoreq = Encrypt(data);
const encryptedData = Encrypt(data);
const options = { const options = {
url: `http://${host}${path}`, url: `http://${host}${path}`,
method: method, method: method,
headers: { headers: {
Accept: "*/*", "Accept": "*/*",
"Accept-Language": "zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4", "Accept-Language": "zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4",
Connection: "keep-alive", "Connection": "keep-alive",
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": "application/x-www-form-urlencoded",
Referer: "http://music.163.com", "Referer": "http://music.163.com",
Host: "music.163.com", "Host": "music.163.com",
Cookie: baseCookie + (cookie ? "; " : "") + cookie, "Cookie": cookie,
"User-Agent": randomUserAgent() "User-Agent": randomUserAgent()
}, },
body: querystring.stringify({ body: queryString.stringify({
params: cryptoreq.params, params: encryptedData.params,
encSecKey: cryptoreq.encSecKey encSecKey: encryptedData.encSecKey
}), }),
proxy: proxy proxy: proxy
}; };
...@@ -73,49 +75,16 @@ function createWebAPIRequest( ...@@ -73,49 +75,16 @@ function createWebAPIRequest(
request(options, function(error, res, body) { request(options, function(error, res, body) {
if (error) { if (error) {
console.error(error); console.error(error);
errorcallback(error); errorCallback(error);
} else { } else {
//解决 网易云 cookie 添加 .music.163.com 域设置。 let cookie = res.headers["set-cookie"] || [];
//如: Domain=.music.163.com cookie = cookie.map(x => x.replace(/\s*Domain=[^(;|$)]+;*/, ""));
let cookie = res.headers["set-cookie"];
if (Array.isArray(cookie)) {
cookie = cookie
.map(x => x.replace(/.music.163.com/g, ""))
.sort((a, b) => a.length - b.length);
}
callback(body, cookie); callback(body, cookie);
} }
}); });
} }
function createRequest(path, method, data) {
return new Promise((resolve, reject) => {
const options = {
url: `http://music.163.com${path}`,
method: method,
headers: {
Referer: "http://music.163.com",
Cookie: "appver=1.5.2",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": randomUserAgent()
}
};
if (method.toLowerCase() === "post") {
options.body = data;
}
request(options, function(error, res, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
});
}
module.exports = { module.exports = {
request, request,
createWebAPIRequest, createWebAPIRequest
createRequest
}; };
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册