This repository has been archived by the owner on Apr 16, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #351 from nondanee/bandage
又是我😂
- Loading branch information
Showing
15 changed files
with
129 additions
and
216 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,114 +1,86 @@ | ||
const express = require('express') | ||
const apicache = require('apicache') | ||
const path = require('path') | ||
const fs = require('fs') | ||
const app = express() | ||
let cache = apicache.middleware | ||
const { exec } = require('child_process'); | ||
exec('npm info NeteaseCloudMusicApi version', (err, stdout, stderr) => { | ||
if (err) { | ||
console.error(err); | ||
return; | ||
} | ||
const onlinePackageVersion = stdout.trim(); | ||
const package = require('./package.json') | ||
if (package.version < onlinePackageVersion) { | ||
console.log( | ||
'最新版:Version:' + | ||
onlinePackageVersion + | ||
',当前版本:' + | ||
package.version + | ||
',请及时更新' | ||
) | ||
} | ||
}) | ||
const path = require('path') | ||
const express = require('express') | ||
const request = require('./util/request') | ||
const package = require('./package.json') | ||
const exec = require('child_process').exec | ||
const cache = require('apicache').middleware | ||
|
||
// 跨域设置 | ||
app.all('*', function(req, res, next) { | ||
if (req.path !== '/' && !req.path.includes('.')) { | ||
res.header('Access-Control-Allow-Credentials', true) | ||
// 这里获取 origin 请求头 而不是用 * | ||
res.header('Access-Control-Allow-Origin', req.headers['origin'] || '*') | ||
res.header('Access-Control-Allow-Headers', 'X-Requested-With') | ||
res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS') | ||
res.header('Content-Type', 'application/json;charset=utf-8') | ||
} | ||
next() | ||
// version check | ||
exec('npm info NeteaseCloudMusicApi version', (err, stdout, stderr) => { | ||
if(!err){ | ||
let version = stdout.trim() | ||
if(package.version < version){ | ||
console.log(`最新版本: ${version}, 当前版本: ${package.version}, 请及时更新`) | ||
} | ||
} | ||
}) | ||
|
||
const onlyStatus200 = (req, res) => res.statusCode === 200 | ||
|
||
app.use(cache('2 minutes', onlyStatus200)) | ||
|
||
app.use(express.static(path.resolve(__dirname, 'public'))) | ||
const app = express() | ||
|
||
// 补全缺失的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() | ||
// CORS | ||
app.use((req, res, next) => { | ||
if(req.path !== '/' && !req.path.includes('.')){ | ||
res.header({ | ||
'Access-Control-Allow-Credentials': true, | ||
'Access-Control-Allow-Origin': req.headers.origin || '*', | ||
'Access-Control-Allow-Headers': 'X-Requested-With', | ||
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS', | ||
'Content-Type': 'application/json; charset=utf-8' | ||
}) | ||
} | ||
next() | ||
}) | ||
|
||
// cookie parser | ||
app.use(function(req, res, next) { | ||
req.cookies = {}, (req.headers.cookie || '').split(/\s*;\s*/).forEach(pair => { | ||
let crack = pair.indexOf('=') | ||
if(crack < 1 || crack == pair.length - 1) return | ||
req.cookies[decodeURIComponent(pair.slice(0, crack)).trim()] = decodeURIComponent(pair.slice(crack + 1)).trim() | ||
}) | ||
next() | ||
app.use((req, res, next) => { | ||
req.cookies = {}, (req.headers.cookie || '').split(/\s*;\s*/).forEach(pair => { | ||
let crack = pair.indexOf('=') | ||
if(crack < 1 || crack == pair.length - 1) return | ||
req.cookies[decodeURIComponent(pair.slice(0, crack)).trim()] = decodeURIComponent(pair.slice(crack + 1)).trim() | ||
}) | ||
next() | ||
}) | ||
|
||
app.use(function(req, res, next) { | ||
const proxy = req.query.proxy | ||
if (proxy) { | ||
req.headers.cookie += `__proxy__${proxy}` | ||
} | ||
next() | ||
}) | ||
// cache | ||
app.use(cache('2 minutes', ((req, res) => res.statusCode === 200))) | ||
|
||
// 因为这几个文件对外所注册的路由 和 其他文件对外注册的路由规则不一样, 所以专门写个MAP对这些文件做特殊处理 | ||
const UnusualRouteFileMap = { | ||
// key 为文件名, value 为对外注册的路由 | ||
'daily_signin.js': '/daily_signin', | ||
'fm_trash.js': '/fm_trash', | ||
'personal_fm.js': '/personal_fm' | ||
} | ||
// static | ||
app.use(express.static(path.join(__dirname, 'public'))) | ||
|
||
// router | ||
const special = { | ||
'daily_signin.js': '/daily_signin', | ||
'fm_trash.js': '/fm_trash', | ||
'personal_fm.js': '/personal_fm' | ||
} | ||
|
||
// 改写router为module | ||
const requestMod = require('./util/request') | ||
let dev = express() | ||
fs.readdirSync(path.join(__dirname, 'module')) | ||
.reverse() | ||
.forEach(file => { | ||
if (!(/\.js$/i.test(file))) return | ||
let route = (file in UnusualRouteFileMap) ? UnusualRouteFileMap[file] : '/' + file.replace(/\.js$/i, '').replace(/_/g, '/') | ||
let question = require(path.join(__dirname, 'module', file)) | ||
|
||
dev.use(route, (req, res) => { | ||
let query = {...req.query, cookie: req.cookies} | ||
question(query, requestMod) | ||
.then(answer => { | ||
console.log('[OK]', decodeURIComponent(req.originalUrl)) | ||
res.append('Set-Cookie', answer.cookie) | ||
res.status(answer.status).send(answer.body) | ||
}) | ||
.catch(answer => { | ||
console.log('[ERR]', decodeURIComponent(req.originalUrl)) | ||
res.append('Set-Cookie', answer.cookie) | ||
res.status(answer.status).send(answer.body) | ||
fs.readdirSync(path.join(__dirname, 'module')).reverse().forEach(file => { | ||
if(!(/\.js$/i.test(file))) return | ||
let route = (file in special) ? special[file] : '/' + file.replace(/\.js$/i, '').replace(/_/g, '/') | ||
let question = require(path.join(__dirname, 'module', file)) | ||
|
||
app.use(route, (req, res) => { | ||
let query = {...req.query, ...req.body, cookie: req.cookies} | ||
question(query, request) | ||
.then(answer => { | ||
console.log('[OK]', decodeURIComponent(req.originalUrl)) | ||
res.append('Set-Cookie', answer.cookie) | ||
res.status(answer.status).send(answer.body) | ||
}) | ||
.catch(answer => { | ||
console.log('[ERR]', decodeURIComponent(req.originalUrl)) | ||
if(answer.body.code =='301') answer.body.msg = '需要登录' | ||
res.append('Set-Cookie', answer.cookie) | ||
res.status(answer.status).send(answer.body) | ||
}) | ||
}) | ||
}) | ||
}) | ||
app.use('/', dev) | ||
|
||
const port = process.env.PORT || 3000 | ||
|
||
app.server = app.listen(port, () => { | ||
console.log(`server running @ http://localhost:${port}`) | ||
console.log(`server running @ http://localhost:${port}`) | ||
}) | ||
|
||
module.exports = app |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// 我的歌手列表 | ||
// 关注歌手列表 | ||
|
||
module.exports = (query, request) => { | ||
const data = { | ||
|
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// 我的电台列表 | ||
// 订阅电台列表 | ||
|
||
module.exports = (query, request) => { | ||
const data = { | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// 红心取消红心歌曲 | ||
// 红心与取消红心歌曲 | ||
|
||
module.exports = (query, request) => { | ||
query.like = (query.like ? true : false) | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
// MV链接 | ||
|
||
module.exports = (query, request) => { | ||
const data = { | ||
id: query.id, | ||
|
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,14 @@ | ||
// 最新单曲(暂时废弃?) | ||
// 新歌速递 | ||
|
||
module.exports = (query, request) => { | ||
const data = { | ||
areaId: query.type || 0, // 全部:0 华语:7 欧美:96 日本:8 韩国:16 | ||
limit: query.limit || 100, | ||
offset: query.offset || 0, | ||
total: true | ||
} | ||
return request( | ||
'POST', `http://music.163.com/weapi/v1/discovery/new/songs`, {}, | ||
'POST', `http://music.163.com/weapi/v1/discovery/new/songs`, data, | ||
{crypto: 'weapi', cookie: query.cookie, proxy: query.proxy} | ||
) | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// 云盘数据详情?(暂时不要使用) | ||
// 云盘数据详情(暂时不要使用) | ||
|
||
module.exports = (query, request) => { | ||
const data = { | ||
|
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,34 @@ | ||
// 参考 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 | ||
const iv = Buffer.from('0102030405060708') | ||
const presetKey = Buffer.from('0CoJUm6Qyw8W8jud') | ||
const linuxapiKey = Buffer.from('rFgB&h#%2?^eDg:Q') | ||
const base62 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' | ||
const publicKey = '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgtQn2JZ34ZC28NWYpAUd98iZ37BUrX/aKzmFbt7clFSs6sXqHauqKWqdtLkF2KexO40H1YTX8z2lSgBBOAxLsvaklV8k4cBFK9snQXE9/DDaFt6Rr7iVZMldczhC0JNgTz+SHXT6CBHuX3e9SdB1Ua44oncaTWz7OBGLbCiK45wIDAQAB\n-----END PUBLIC KEY-----' | ||
|
||
const aesEncrypt = (buffer, mode, key, iv) => { | ||
const cipher = crypto.createCipheriv('aes-128-' + mode, key, iv) | ||
return Buffer.concat([cipher.update(buffer),cipher.final()]) | ||
} | ||
|
||
function zfill(str, size) { | ||
while (str.length < size) str = '0' + str | ||
return str | ||
const rsaEncrypt = (buffer, key) => { | ||
buffer = Buffer.concat([Buffer.alloc(128 - buffer.length), buffer]) | ||
return crypto.publicEncrypt({key: key, padding: crypto.constants.RSA_NO_PADDING}, buffer) | ||
} | ||
|
||
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) | ||
const weapi = (object) => { | ||
const text = JSON.stringify(object) | ||
const secretKey = crypto.randomBytes(16).map(n => (base62.charAt(n % 62).charCodeAt())) | ||
return { | ||
params: aesEncrypt(Buffer.from(aesEncrypt(Buffer.from(text), 'cbc', presetKey, iv).toString('base64')), 'cbc', secretKey, iv).toString('base64'), | ||
encSecKey: rsaEncrypt(secretKey.reverse(), publicKey).toString('hex') | ||
} | ||
} | ||
|
||
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 | ||
} | ||
const linuxapi = (object) => { | ||
const text = JSON.stringify(object) | ||
return { | ||
eparams: aesEncrypt(Buffer.from(text), 'ecb', linuxapiKey, '').toString('hex').toUpperCase() | ||
} | ||
} | ||
|
||
module.exports = Encrypt | ||
module.exports = {weapi, linuxapi} |
Oops, something went wrong.