mirror of
https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced.git
synced 2026-06-27 21:25:08 +00:00
Compare commits
No commits in common. "6fc4231142e2a91913cdf54f27cc9722391e30c0" and "395a80e74b9e69b8bfadfc19d77d57121f68087d" have entirely different histories.
6fc4231142
...
395a80e74b
9
app.js
9
app.js
@ -8,11 +8,16 @@ async function start() {
|
||||
if (!fs.existsSync(path.resolve(tmpPath, 'anonymous_token'))) {
|
||||
fs.writeFileSync(path.resolve(tmpPath, 'anonymous_token'), '', 'utf-8')
|
||||
}
|
||||
// 启动时更新anonymous_token
|
||||
// 启动时更新anonymous_token(Vercel 构建环境下跳过网络请求喵~)
|
||||
if (!process.env.VERCEL_ENV) {
|
||||
const generateConfig = require('./generateConfig')
|
||||
await generateConfig()
|
||||
}
|
||||
require('./server').serveNcmApi({
|
||||
checkVersion: true,
|
||||
})
|
||||
}
|
||||
start()
|
||||
start().catch((err) => {
|
||||
console.error('[FATAL] 启动失败:', err)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
@ -4,12 +4,36 @@ const { register_anonimous } = require('./main')
|
||||
const { cookieToJson, generateRandomChineseIP } = require('./util/index')
|
||||
const { getXeapiPublicKey } = require('./util/xeapiKey')
|
||||
const tmpPath = require('os').tmpdir()
|
||||
const logger = require('./util/logger')
|
||||
|
||||
async function generateConfig() {
|
||||
global.cnIp = generateRandomChineseIP()
|
||||
const MAX_RETRIES = 10
|
||||
const RETRY_DELAY_MS = 1000
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
function isRetryableError(err) {
|
||||
const status =
|
||||
(err && err.status) || (err && err.response && err.response.status)
|
||||
if (status && status >= 500) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/** @returns {{ success: boolean, error?: Error }} */
|
||||
async function fetchAnonymousToken() {
|
||||
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
||||
try {
|
||||
const res = await register_anonimous()
|
||||
const cookie = res.body.cookie
|
||||
const body = res.body
|
||||
if (body.code && body.code !== 200) {
|
||||
const err = new Error(`匿名注册返回错误码 ${body.code}`)
|
||||
err.status = 502
|
||||
throw err
|
||||
}
|
||||
const cookie = body.cookie
|
||||
if (cookie) {
|
||||
const cookieObj = cookieToJson(cookie)
|
||||
fs.writeFileSync(
|
||||
@ -17,25 +41,122 @@ async function generateConfig() {
|
||||
cookieObj.MUSIC_A,
|
||||
'utf-8',
|
||||
)
|
||||
logger.success('[generateConfig] 匿名 token 注册成功')
|
||||
return { success: true }
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
|
||||
logger.warn(
|
||||
`[generateConfig] 匿名注册返回了空 cookie (attempt ${attempt})`,
|
||||
)
|
||||
return {
|
||||
success: false,
|
||||
error: new Error('empty cookie from anonymous register'),
|
||||
}
|
||||
} catch (err) {
|
||||
if (isRetryableError(err) && attempt < MAX_RETRIES) {
|
||||
const delay = RETRY_DELAY_MS * Math.pow(2, attempt - 1)
|
||||
logger.warn(
|
||||
`[generateConfig] 获取匿名 token 失败 (attempt ${attempt}/${MAX_RETRIES}), ${delay}ms 后重试...`,
|
||||
)
|
||||
await sleep(delay)
|
||||
continue
|
||||
}
|
||||
if (attempt >= MAX_RETRIES) {
|
||||
logger.error(
|
||||
`[generateConfig] 获取匿名 token 已达最大重试次数 (${MAX_RETRIES}):`,
|
||||
err.message,
|
||||
)
|
||||
} else {
|
||||
logger.error(
|
||||
`[generateConfig] 获取匿名 token 失败 (不可重试):`,
|
||||
err.message,
|
||||
)
|
||||
}
|
||||
return { success: false, error: err }
|
||||
}
|
||||
}
|
||||
return { success: false, error: new Error('unreachable') }
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 xeapi public key,带重试
|
||||
* @returns {{ success: boolean, error?: Error }}
|
||||
*/
|
||||
async function fetchXeapiPublicKey() {
|
||||
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
||||
try {
|
||||
let currentPublicKey = {}
|
||||
try {
|
||||
currentPublicKey = JSON.parse(
|
||||
fs.readFileSync(path.resolve(tmpPath, 'xeapi_public_key'), 'utf-8'),
|
||||
)
|
||||
} catch (_) {}
|
||||
const publicKey = await getXeapiPublicKey(currentPublicKey, global.deviceId)
|
||||
} catch (_) {
|
||||
// 本地无缓存文件,用空对象正常请求
|
||||
}
|
||||
const publicKey = await getXeapiPublicKey(
|
||||
currentPublicKey,
|
||||
global.deviceId,
|
||||
)
|
||||
fs.writeFileSync(
|
||||
path.resolve(tmpPath, 'xeapi_public_key'),
|
||||
JSON.stringify(publicKey),
|
||||
'utf-8',
|
||||
)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
logger.success('[generateConfig] xeapi public key 获取成功')
|
||||
return { success: true }
|
||||
} catch (err) {
|
||||
if (isRetryableError(err) && attempt < MAX_RETRIES) {
|
||||
const delay = RETRY_DELAY_MS * Math.pow(2, attempt - 1)
|
||||
logger.warn(
|
||||
`[generateConfig] 获取 xeapi public key 失败 (attempt ${attempt}/${MAX_RETRIES}), ${delay}ms 后重试...`,
|
||||
)
|
||||
await sleep(delay)
|
||||
continue
|
||||
}
|
||||
if (attempt >= MAX_RETRIES) {
|
||||
logger.error(
|
||||
`[generateConfig] 获取 xeapi public key 已达最大重试次数 (${MAX_RETRIES}):`,
|
||||
err.message,
|
||||
)
|
||||
} else {
|
||||
logger.error(
|
||||
`[generateConfig] 获取 xeapi public key 失败 (不可重试):`,
|
||||
err.message,
|
||||
)
|
||||
}
|
||||
return { success: false, error: err }
|
||||
}
|
||||
}
|
||||
return { success: false, error: new Error('unreachable') }
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成配置(匿名 token + xeapi public key),带容错重试
|
||||
* @returns {{ tokenOk: boolean, keyOk: boolean }}
|
||||
*/
|
||||
async function generateConfig() {
|
||||
global.cnIp = generateRandomChineseIP()
|
||||
|
||||
// 两个任务并行执行,互不影响喵~
|
||||
const [tokenResult, keyResult] = await Promise.all([
|
||||
fetchAnonymousToken(),
|
||||
fetchXeapiPublicKey(),
|
||||
])
|
||||
|
||||
if (!tokenResult.success) {
|
||||
logger.warn('[generateConfig] 匿名 token 获取失败')
|
||||
}
|
||||
if (!keyResult.success) {
|
||||
logger.warn('[generateConfig] xeapi public key 获取失败')
|
||||
}
|
||||
|
||||
if (tokenResult.success && keyResult.success) {
|
||||
logger.success('[generateConfig] 配置初始化完成')
|
||||
}
|
||||
|
||||
return {
|
||||
tokenOk: tokenResult.success,
|
||||
keyOk: keyResult.success,
|
||||
}
|
||||
}
|
||||
module.exports = generateConfig
|
||||
|
||||
@ -26,7 +26,6 @@ function cloudmusic_dll_encode_id(some_id) {
|
||||
|
||||
module.exports = async (query, request) => {
|
||||
const deviceId = generateDeviceId()
|
||||
logger.info(`Successfully registered anonimous token, deviceId: ${deviceId}`)
|
||||
global.deviceId = deviceId
|
||||
const encodedId = CryptoJS.enc.Base64.stringify(
|
||||
CryptoJS.enc.Utf8.parse(
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
"prepare": "husky install",
|
||||
"docs:format": "node scripts/format-docs.js",
|
||||
"docs:check": "node scripts/format-docs.js --check",
|
||||
"docs:toc": "node scripts/format-docs.js --toc",
|
||||
"docs:all": "node scripts/format-docs.js --dir public/docs --toc --verbose",
|
||||
"pkgwin": "pkg . -t node18-win-x64 -C GZip -o precompiled/app",
|
||||
"pkglinux": "pkg . -t node18-linux-x64 -C GZip -o precompiled/app",
|
||||
"pkgmacos": "pkg . -t node18-macos-x64 -C GZip -o precompiled/app"
|
||||
@ -52,7 +54,7 @@
|
||||
},
|
||||
"homepage": "https://neteasecloudmusicapienhanced.js.org/",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=22"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
## 目录
|
||||
|
||||
- [NeteaseCloudMusicAPI Enhanced](#neteasecloudmusicapi-enhanced)
|
||||
|
||||
---
|
||||
|
||||
# NeteaseCloudMusicAPI Enhanced
|
||||
|
||||
> 🎉 全网收集最全的网易云音乐api接口 基于[NeteaseCloudMusicAPI](https://github.com/binaryify/NeteaseCloudMusicApi)的复刻版本
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* 📝 Markdown 文档格式化工具喵~
|
||||
* 支持格式化标题、代码块、空行和缩进!
|
||||
* 支持格式化标题、代码块、空行、缩进,还能生成目录!
|
||||
*
|
||||
* 用法:
|
||||
* node scripts/format-docs.js # 格式化默认文档 (public/docs/home.md)
|
||||
* node scripts/format-docs.js <文件路径> # 格式化指定文件
|
||||
* node scripts/format-docs.js --dir <目录> # 格式化整个目录的 .md 文件
|
||||
* node scripts/format-docs.js --check # 只检查不写入 (dry-run)
|
||||
*
|
||||
* node scripts/format-docs.js --toc # 同时生成目录
|
||||
*/
|
||||
|
||||
const fs = require('fs')
|
||||
@ -23,6 +23,7 @@ const CONFIG = {
|
||||
listIndent: 2, // 列表缩进空格数
|
||||
encodeSpecialChars: false, // 是否编码特殊字符
|
||||
removeTrailingSpaces: true, // 是否删除行尾空格
|
||||
tocMaxLevel: 3, // 目录最大标题层级
|
||||
}
|
||||
|
||||
const DEFAULT_FILE = path.resolve(__dirname, '..', 'public', 'docs', 'home.md')
|
||||
@ -106,10 +107,7 @@ function parseBlocks(lines) {
|
||||
i++
|
||||
while (i < lines.length) {
|
||||
const t = lines[i].trim()
|
||||
if (/-->/.test(t) || /<\/\w+>/.test(t)) {
|
||||
i++
|
||||
break
|
||||
}
|
||||
if (/-->/.test(t) || /<\/\w+>/.test(t)) { i++; break }
|
||||
i++
|
||||
}
|
||||
const htmlLines = lines.slice(start, i)
|
||||
@ -125,31 +123,17 @@ function parseBlocks(lines) {
|
||||
i++
|
||||
}
|
||||
const quoteLines = lines.slice(start, i)
|
||||
blocks.push({
|
||||
type: 'blockquote',
|
||||
lines: quoteLines,
|
||||
raw: quoteLines.join('\n'),
|
||||
})
|
||||
blocks.push({ type: 'blockquote', lines: quoteLines, raw: quoteLines.join('\n') })
|
||||
continue
|
||||
}
|
||||
|
||||
// 表格
|
||||
if (
|
||||
/\|/.test(trimmed) &&
|
||||
lines[i + 1] &&
|
||||
/^\|[\s\-:]+\|/.test(lines[i + 1].trim())
|
||||
) {
|
||||
if (/\|/.test(trimmed) && lines[i + 1] && /^\|[\s\-:]+\|/.test(lines[i + 1].trim())) {
|
||||
const start = i
|
||||
i += 2
|
||||
while (i < lines.length && /\|/.test(lines[i].trim())) {
|
||||
i++
|
||||
}
|
||||
while (i < lines.length && /\|/.test(lines[i].trim())) { i++ }
|
||||
const tableLines = lines.slice(start, i)
|
||||
blocks.push({
|
||||
type: 'table',
|
||||
lines: tableLines,
|
||||
raw: tableLines.join('\n'),
|
||||
})
|
||||
blocks.push({ type: 'table', lines: tableLines, raw: tableLines.join('\n') })
|
||||
continue
|
||||
}
|
||||
|
||||
@ -159,19 +143,10 @@ function parseBlocks(lines) {
|
||||
i++
|
||||
while (i < lines.length) {
|
||||
const t = lines[i].trim()
|
||||
if (t === '') {
|
||||
i++
|
||||
break
|
||||
}
|
||||
if (/^(\s*[-*+]\s|\s*\d+\.\s)/.test(lines[i])) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (t === '') { i++; break }
|
||||
if (/^(\s*[-*+]\s|\s*\d+\.\s)/.test(lines[i])) { i++; continue }
|
||||
// 缩进 continuation
|
||||
if (/^\s{2,}/.test(lines[i])) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (/^\s{2,}/.test(lines[i])) { i++; continue }
|
||||
break
|
||||
}
|
||||
const listLines = lines.slice(start, i)
|
||||
@ -185,23 +160,13 @@ function parseBlocks(lines) {
|
||||
while (i < lines.length && lines[i].trim() !== '') {
|
||||
// 如果遇到新的块元素则停止
|
||||
const t = lines[i].trim()
|
||||
if (
|
||||
/^#{1,6}\s/.test(t) ||
|
||||
/^```/.test(t) ||
|
||||
/^~~~/.test(t) ||
|
||||
/^(\s*[-*+]\s|\s*\d+\.\s)/.test(lines[i])
|
||||
)
|
||||
break
|
||||
if (/^#{1,6}\s/.test(t) || /^```/.test(t) || /^~~~/.test(t) || /^(\s*[-*+]\s|\s*\d+\.\s)/.test(lines[i])) break
|
||||
// 分割线
|
||||
if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(t)) break
|
||||
i++
|
||||
}
|
||||
const paraLines = lines.slice(start, i)
|
||||
blocks.push({
|
||||
type: 'paragraph',
|
||||
lines: paraLines,
|
||||
raw: paraLines.join('\n'),
|
||||
})
|
||||
blocks.push({ type: 'paragraph', lines: paraLines, raw: paraLines.join('\n') })
|
||||
}
|
||||
|
||||
return blocks
|
||||
@ -225,20 +190,12 @@ function formatMarkdown(input, options = {}) {
|
||||
const newLines = [...block.lines]
|
||||
|
||||
// 标题前加空行(如果不是第一个块且前一个不是空行)
|
||||
if (
|
||||
cfg.headingSpaceBefore &&
|
||||
idx > 0 &&
|
||||
blocks[idx - 1].type !== 'empty'
|
||||
) {
|
||||
if (cfg.headingSpaceBefore && idx > 0 && blocks[idx - 1].type !== 'empty') {
|
||||
newLines.unshift('')
|
||||
}
|
||||
|
||||
// 标题后加空行(如果不是最后一个块且后一个不是空行)
|
||||
if (
|
||||
cfg.headingSpaceAfter &&
|
||||
idx < blocks.length - 1 &&
|
||||
blocks[idx + 1].type !== 'empty'
|
||||
) {
|
||||
if (cfg.headingSpaceAfter && idx < blocks.length - 1 && blocks[idx + 1].type !== 'empty') {
|
||||
newLines.push('')
|
||||
}
|
||||
|
||||
@ -263,18 +220,10 @@ function formatMarkdown(input, options = {}) {
|
||||
newLines[0] = lang ? `${indent}${marker}${lang}` : `${indent}${marker}`
|
||||
|
||||
// 确保代码块前后有空行(插在标准化之后,因为只动第一行)
|
||||
if (
|
||||
idx > 0 &&
|
||||
blocks[idx - 1].type !== 'empty' &&
|
||||
blocks[idx - 1].type !== 'code'
|
||||
) {
|
||||
if (idx > 0 && blocks[idx - 1].type !== 'empty' && blocks[idx - 1].type !== 'code') {
|
||||
newLines.unshift('')
|
||||
}
|
||||
if (
|
||||
idx < blocks.length - 1 &&
|
||||
blocks[idx + 1].type !== 'empty' &&
|
||||
blocks[idx + 1].type !== 'code'
|
||||
) {
|
||||
if (idx < blocks.length - 1 && blocks[idx + 1].type !== 'empty' && blocks[idx + 1].type !== 'code') {
|
||||
newLines.push('')
|
||||
}
|
||||
|
||||
@ -304,8 +253,7 @@ function formatMarkdown(input, options = {}) {
|
||||
const indent = line.length - line.trimStart().length
|
||||
// 如果是顶层列表项,确保缩进为0
|
||||
if (indent % cfg.listIndent !== 0) {
|
||||
const normalizedIndent =
|
||||
Math.round(indent / cfg.listIndent) * cfg.listIndent
|
||||
const normalizedIndent = Math.round(indent / cfg.listIndent) * cfg.listIndent
|
||||
return ' '.repeat(normalizedIndent) + trimmed
|
||||
}
|
||||
}
|
||||
@ -319,8 +267,7 @@ function formatMarkdown(input, options = {}) {
|
||||
|
||||
// 处理文件开头和结尾的空行
|
||||
while (resultLines.length > 0 && resultLines[0] === '') resultLines.shift()
|
||||
while (resultLines.length > 0 && resultLines[resultLines.length - 1] === '')
|
||||
resultLines.pop()
|
||||
while (resultLines.length > 0 && resultLines[resultLines.length - 1] === '') resultLines.pop()
|
||||
resultLines.push('') // 文件结尾留一个空行
|
||||
|
||||
return resultLines.join('\n')
|
||||
@ -348,6 +295,41 @@ function compressEmptyLines(blocks, maxBlank) {
|
||||
return result
|
||||
}
|
||||
|
||||
// ======================== 目录生成 ========================
|
||||
|
||||
/**
|
||||
* 从文档中提取标题生成目录
|
||||
*/
|
||||
function generateTOC(input, maxLevel = 3) {
|
||||
const lines = input.split('\n')
|
||||
const headings = []
|
||||
|
||||
for (const line of lines) {
|
||||
const match = line.match(/^(#{1,6})\s+(.+)$/)
|
||||
if (match) {
|
||||
const level = match[1].length
|
||||
if (level <= maxLevel) {
|
||||
headings.push({ level, text: match[2].trim() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (headings.length === 0) return ''
|
||||
|
||||
let toc = '\n## 目录\n\n'
|
||||
for (const h of headings) {
|
||||
const indent = ' '.repeat(h.level - 1)
|
||||
const anchor = h.text
|
||||
.toLowerCase()
|
||||
.replace(/[^\w\u4e00-\u9fa5]+/g, '-')
|
||||
.replace(/^-|-$/g, '')
|
||||
toc += `${indent}- [${h.text}](#${anchor})\n`
|
||||
}
|
||||
toc += '\n---\n'
|
||||
|
||||
return toc
|
||||
}
|
||||
|
||||
// ======================== 统计信息 ========================
|
||||
|
||||
function getStats(input) {
|
||||
@ -435,7 +417,20 @@ function processFile(filePath, options) {
|
||||
}
|
||||
|
||||
if (hasChanges) {
|
||||
writeFile(filePath, formatted)
|
||||
// 如果指定了 --toc,在文档开头插入目录
|
||||
let output = formatted
|
||||
if (options.toc) {
|
||||
const tocPlaceholder = '<!-- TOC -->'
|
||||
if (output.includes(tocPlaceholder)) {
|
||||
output = output.replace(
|
||||
new RegExp(`${tocPlaceholder}[\\s\\S]*?${tocPlaceholder}`),
|
||||
`${tocPlaceholder}\n${generateTOC(output, options.tocMaxLevel || CONFIG.tocMaxLevel)}${tocPlaceholder}`
|
||||
)
|
||||
} else {
|
||||
output = generateTOC(output, options.tocMaxLevel || CONFIG.tocMaxLevel) + '\n' + output
|
||||
}
|
||||
}
|
||||
writeFile(filePath, output)
|
||||
console.log(green(' ✨ 格式化完成!'))
|
||||
if (options.verbose) {
|
||||
printStats(statsAfter)
|
||||
@ -459,9 +454,7 @@ function processDirectory(dirPath, options) {
|
||||
return 0
|
||||
}
|
||||
|
||||
console.log(
|
||||
bold(`\n📁 扫描目录: ${cyan(dirPath)} (${files.length} 个文件)\n`),
|
||||
)
|
||||
console.log(bold(`\n📁 扫描目录: ${cyan(dirPath)} (${files.length} 个文件)\n`))
|
||||
|
||||
for (const file of files) {
|
||||
const ret = processFile(file, options)
|
||||
@ -474,8 +467,7 @@ function processDirectory(dirPath, options) {
|
||||
// ======================== CLI ========================
|
||||
|
||||
function printHelp() {
|
||||
console.log(
|
||||
bold(`
|
||||
console.log(bold(`
|
||||
📝 Markdown 文档格式化工具 v1.0.0
|
||||
|
||||
${cyan('用法:')}
|
||||
@ -487,6 +479,7 @@ ${cyan('参数:')}
|
||||
${cyan('选项:')}
|
||||
--dir, -d <目录> 格式化整个目录下的所有 .md 文件
|
||||
--check, -c dry-run 模式,只检查不写入
|
||||
--toc, -t 在文档中生成目录
|
||||
--verbose, -v 显示详细统计信息
|
||||
--help, -h 显示帮助信息
|
||||
|
||||
@ -495,8 +488,8 @@ ${cyan('示例:')}
|
||||
node scripts/format-docs.js README.md
|
||||
node scripts/format-docs.js --dir docs/
|
||||
node scripts/format-docs.js --check
|
||||
`),
|
||||
)
|
||||
node scripts/format-docs.js --toc --verbose
|
||||
`))
|
||||
}
|
||||
|
||||
function parseArgs() {
|
||||
@ -505,6 +498,7 @@ function parseArgs() {
|
||||
file: null,
|
||||
dir: null,
|
||||
check: false,
|
||||
toc: false,
|
||||
verbose: false,
|
||||
help: false,
|
||||
}
|
||||
@ -519,6 +513,10 @@ function parseArgs() {
|
||||
case '-c':
|
||||
options.check = true
|
||||
break
|
||||
case '--toc':
|
||||
case '-t':
|
||||
options.toc = true
|
||||
break
|
||||
case '--verbose':
|
||||
case '-v':
|
||||
options.verbose = true
|
||||
@ -574,4 +572,4 @@ if (require.main === module) {
|
||||
process.exit(exitCode)
|
||||
}
|
||||
|
||||
module.exports = { formatMarkdown, getStats, parseBlocks }
|
||||
module.exports = { formatMarkdown, generateTOC, getStats, parseBlocks }
|
||||
|
||||
16
server.js
16
server.js
@ -10,6 +10,7 @@ const { cookieToJson } = require('./util/index')
|
||||
const fileUpload = require('express-fileupload')
|
||||
const decode = require('safe-decode-uri-component')
|
||||
const logger = require('./util/logger.js')
|
||||
const { APP_CONF } = require('./util/config.json')
|
||||
|
||||
/**
|
||||
* The version check result.
|
||||
@ -299,15 +300,15 @@ async function constructServer(moduleDefs) {
|
||||
)
|
||||
|
||||
try {
|
||||
let usedCrypto = ''
|
||||
const moduleResponse = await moduleDef.module(query, (...params) => {
|
||||
// 参数注入客户端IP
|
||||
const obj = [...params]
|
||||
const options = obj[2] || {}
|
||||
usedCrypto = options.crypto || ''
|
||||
let ip = ''
|
||||
|
||||
if (options.randomCNIP) {
|
||||
ip = global.cnIp
|
||||
// logger.info('Using random Chinese IP for request:', ip)
|
||||
} else {
|
||||
ip = req.ip
|
||||
|
||||
@ -317,7 +318,6 @@ async function constructServer(moduleDefs) {
|
||||
if (ip == '::1') {
|
||||
ip = global.cnIp
|
||||
}
|
||||
// logger.info('Requested from ip:', ip)
|
||||
}
|
||||
|
||||
obj[2] = {
|
||||
@ -327,7 +327,10 @@ async function constructServer(moduleDefs) {
|
||||
|
||||
return request(...obj)
|
||||
})
|
||||
logger.info(`Request Success: ${decode(req.originalUrl)}`)
|
||||
const displayCrypto = usedCrypto || (APP_CONF.encrypt ? 'eapi' : 'api')
|
||||
logger.info(
|
||||
`Request Success: [${displayCrypto}] ${decode(req.originalUrl)}`,
|
||||
)
|
||||
|
||||
// 夹带私货部分:如果开启了通用解锁,并且是获取歌曲URL的接口,则尝试解锁(如果需要的话)ヾ(≧▽≦*)o
|
||||
if (
|
||||
@ -445,10 +448,7 @@ async function serveNcmApi(options) {
|
||||
╩ ╩╩ ╩ ╚═╝╝╚╝╩ ╩╩ ╩╝╚╝╚═╝╚═╝═╩╝
|
||||
`)
|
||||
logger.info(`
|
||||
- Server started successfully @ http://${host ? host : 'localhost'}:${port}
|
||||
- Environment: ${process.env.NODE_ENV || 'development'}
|
||||
- Node Version: ${process.version}
|
||||
- Process ID: ${process.pid}`)
|
||||
- Server started successfully @ http://${host ? host : 'localhost'}:${port}`)
|
||||
})
|
||||
|
||||
return appExt
|
||||
|
||||
@ -16,9 +16,5 @@
|
||||
"Access-Control-Allow-Headers": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version"
|
||||
}
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"NODE_ENV": "production",
|
||||
"ENABLE_FLAC": "true"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user