mirror of
https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced.git
synced 2025-12-09 09:13:09 +00:00
Compare commits
4 Commits
97980b5ac3
...
8bb68accee
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bb68accee | ||
|
|
55858d89d9 | ||
|
|
597ac1498f | ||
|
|
398f410109 |
57
.eslintrc.js
57
.eslintrc.js
@ -1,57 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
root: true,
|
|
||||||
|
|
||||||
ignorePatterns: ['public/'],
|
|
||||||
parserOptions: {
|
|
||||||
parser: 'babel-eslint',
|
|
||||||
ecmaVersion: 2018,
|
|
||||||
sourceType: 'module',
|
|
||||||
},
|
|
||||||
plugins: ['html'],
|
|
||||||
extends: ['plugin:prettier/recommended'],
|
|
||||||
env: {
|
|
||||||
browser: true,
|
|
||||||
node: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
rules: {
|
|
||||||
'prettier/prettier': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
endOfLine: 'auto',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
indent: ['error', 2, { SwitchCase: 1 }],
|
|
||||||
'space-infix-ops': ['error', { int32Hint: false }],
|
|
||||||
'key-spacing': [
|
|
||||||
2,
|
|
||||||
{
|
|
||||||
beforeColon: false,
|
|
||||||
afterColon: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'no-octal': 2,
|
|
||||||
'no-redeclare': 2,
|
|
||||||
'comma-spacing': 2,
|
|
||||||
'no-new-object': 2,
|
|
||||||
'arrow-spacing': 2,
|
|
||||||
quotes: [
|
|
||||||
2,
|
|
||||||
'single',
|
|
||||||
{
|
|
||||||
avoidEscape: true,
|
|
||||||
allowTemplateLiterals: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['**/*.ts'],
|
|
||||||
parser: '@typescript-eslint/parser',
|
|
||||||
extends: [
|
|
||||||
'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
|
|
||||||
// 'prettier/@typescript-eslint',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
73
.github/workflows/node.js.yml
vendored
73
.github/workflows/node.js.yml
vendored
@ -2,9 +2,9 @@ name: Node.js CI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main ]
|
branches: [main]
|
||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches: [main]
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
@ -14,46 +14,43 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [14.x, 16.x, 18.x ]
|
node-version: [16.x, 18.x, 22.x]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- uses: actions/cache@v4
|
# Use built-in package manager cache for pnpm
|
||||||
with:
|
cache: 'pnpm'
|
||||||
path: ~/.npm
|
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
- name: Install pnpm
|
||||||
restore-keys: |
|
run: npm install -g pnpm
|
||||||
${{ runner.os }}-node-
|
- name: Install dependencies (pnpm)
|
||||||
- run: npm ci
|
run: pnpm install --frozen-lockfile
|
||||||
name: Install dependencies
|
- name: Test
|
||||||
- name: Test
|
env:
|
||||||
env:
|
NCM_API_TEST_LOGIN_COUNTRY_CODE: ${{ secrets.NCM_API_TEST_LOGIN_COUNTRY_CODE }}
|
||||||
NCM_API_TEST_LOGIN_COUNTRY_CODE: ${{ secrets.NCM_API_TEST_LOGIN_COUNTRY_CODE }}
|
NCM_API_TEST_LOGIN_PHONE: ${{ secrets.NCM_API_TEST_LOGIN_PHONE }}
|
||||||
NCM_API_TEST_LOGIN_PHONE: ${{ secrets.NCM_API_TEST_LOGIN_PHONE }}
|
NCM_API_TEST_LOGIN_PASSWORD: ${{ secrets.NCM_API_TEST_LOGIN_PASSWORD }}
|
||||||
NCM_API_TEST_LOGIN_PASSWORD: ${{ secrets.NCM_API_TEST_LOGIN_PASSWORD }}
|
run: pnpm test
|
||||||
run: npm test
|
|
||||||
lint:
|
lint:
|
||||||
name: Lint
|
name: Lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [14.x]
|
node-version: [18.x]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- uses: actions/cache@v4
|
cache: 'pnpm'
|
||||||
with:
|
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||||
path: ~/.npm
|
- name: Install pnpm
|
||||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
run: npm install -g pnpm
|
||||||
restore-keys: |
|
- name: Install dependencies (pnpm)
|
||||||
${{ runner.os }}-node-
|
run: pnpm install --frozen-lockfile
|
||||||
- run: npm ci
|
- name: Lint
|
||||||
name: Install dependencies
|
run: pnpm run lint
|
||||||
- name: Lint
|
|
||||||
run: npm run lint
|
|
||||||
|
|||||||
91
eslint.config.js
Normal file
91
eslint.config.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
const { defineConfig, globalIgnores } = require('eslint/config')
|
||||||
|
|
||||||
|
const html = require('eslint-plugin-html')
|
||||||
|
const globals = require('globals')
|
||||||
|
const tsParser = require('@typescript-eslint/parser')
|
||||||
|
const js = require('@eslint/js')
|
||||||
|
|
||||||
|
const { FlatCompat } = require('@eslint/eslintrc')
|
||||||
|
|
||||||
|
const compat = new FlatCompat({
|
||||||
|
baseDirectory: __dirname,
|
||||||
|
recommendedConfig: js.configs.recommended,
|
||||||
|
allConfig: js.configs.all,
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = defineConfig([
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2018,
|
||||||
|
sourceType: 'module',
|
||||||
|
parserOptions: {
|
||||||
|
parser: 'babel-eslint',
|
||||||
|
},
|
||||||
|
globals: {
|
||||||
|
...globals.browser,
|
||||||
|
...globals.node,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: {
|
||||||
|
html,
|
||||||
|
},
|
||||||
|
|
||||||
|
extends: compat.extends('plugin:prettier/recommended'),
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
'prettier/prettier': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
endOfLine: 'auto',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
indent: [
|
||||||
|
'error',
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
SwitchCase: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'space-infix-ops': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
int32Hint: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'key-spacing': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
beforeColon: false,
|
||||||
|
afterColon: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'no-octal': 2,
|
||||||
|
'no-redeclare': 2,
|
||||||
|
'comma-spacing': 2,
|
||||||
|
'no-new-object': 2,
|
||||||
|
'arrow-spacing': 2,
|
||||||
|
|
||||||
|
quotes: [
|
||||||
|
2,
|
||||||
|
'single',
|
||||||
|
{
|
||||||
|
avoidEscape: true,
|
||||||
|
allowTemplateLiterals: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
globalIgnores(['**/public/']),
|
||||||
|
{
|
||||||
|
files: ['**/*.ts'],
|
||||||
|
languageOptions: {
|
||||||
|
parser: tsParser,
|
||||||
|
},
|
||||||
|
extends: compat.extends('plugin:@typescript-eslint/recommended'),
|
||||||
|
},
|
||||||
|
])
|
||||||
@ -5,31 +5,34 @@ const createOption = require('../util/option.js')
|
|||||||
const logger = require('../util/logger.js')
|
const logger = require('../util/logger.js')
|
||||||
|
|
||||||
module.exports = async (query, request) => {
|
module.exports = async (query, request) => {
|
||||||
try {
|
try {
|
||||||
const match = require("@unblockneteasemusic/server")
|
const match = require('@unblockneteasemusic/server')
|
||||||
const source = query.source
|
const source = query.source
|
||||||
? query.source.split(',') : ['pyncmd', 'bodian','kuwo', 'qq', 'migu', 'kugou']
|
? query.source.split(',')
|
||||||
const server = query.server ? query.server.split(',') : query.server
|
: ['pyncmd', 'bodian', 'kuwo', 'qq', 'migu', 'kugou']
|
||||||
const result = await match(query.id, !server? source : server)
|
const server = query.server ? query.server.split(',') : query.server
|
||||||
const proxy = process.env.PROXY_URL;
|
const result = await match(query.id, !server ? source : server)
|
||||||
logger.info("开始解灰", query.id, result)
|
const proxy = process.env.PROXY_URL
|
||||||
const useProxy = process.env.ENABLE_PROXY || "false"
|
logger.info('开始解灰', query.id, result)
|
||||||
if (result.url.includes('kuwo')) { result.proxyUrl = useProxy === 'true' ? proxy + result.url : result.url }
|
const useProxy = process.env.ENABLE_PROXY || 'false'
|
||||||
return {
|
if (result.url.includes('kuwo')) {
|
||||||
status: 200,
|
result.proxyUrl = useProxy === 'true' ? proxy + result.url : result.url
|
||||||
body: {
|
|
||||||
code: 200,
|
|
||||||
data: result,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return {
|
|
||||||
status: 500,
|
|
||||||
body: {
|
|
||||||
code: 500,
|
|
||||||
msg: e.message || 'unblock error',
|
|
||||||
data: [],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: {
|
||||||
|
code: 200,
|
||||||
|
data: result,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
status: 500,
|
||||||
|
body: {
|
||||||
|
code: 500,
|
||||||
|
msg: e.message || 'unblock error',
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -5,71 +5,73 @@
|
|||||||
const createOption = require('../util/option.js')
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
module.exports = async (query, request) => {
|
module.exports = async (query, request) => {
|
||||||
try {
|
try {
|
||||||
const { id, br = "320" } = query;
|
const { id, br = '320' } = query
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return {
|
return {
|
||||||
status: 400,
|
status: 400,
|
||||||
body: {
|
body: {
|
||||||
code: 400,
|
code: 400,
|
||||||
message: "缺少必要参数 id",
|
message: '缺少必要参数 id',
|
||||||
data: [],
|
data: [],
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
}
|
|
||||||
const validBR = ["128", "192", "320", "740", "999"];
|
|
||||||
// const covertBR = ["128000", "192000", "320000","740000", "999000"];
|
|
||||||
if (!validBR.includes(br)) {
|
|
||||||
return {
|
|
||||||
status: 400,
|
|
||||||
body: {
|
|
||||||
code: 400,
|
|
||||||
message: "无效音质参数",
|
|
||||||
allowed_values: validBR,
|
|
||||||
data: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const apiUrl = new URL("https://music-api.gdstudio.xyz/api.php");
|
|
||||||
apiUrl.searchParams.append("types", "url");
|
|
||||||
apiUrl.searchParams.append("id", id);
|
|
||||||
apiUrl.searchParams.append("br", br);
|
|
||||||
|
|
||||||
const response = await fetch(apiUrl.toString());
|
|
||||||
if (!response.ok) throw new Error(`API 响应状态: ${response.status}`);
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
// 代理逻辑
|
|
||||||
const useProxy = process.env.ENABLE_PROXY || false;
|
|
||||||
const proxy = process.env.PROXY_URL;
|
|
||||||
if (useProxy && result.url && result.url.includes("kuwo")) {
|
|
||||||
result.proxyUrl = proxy + result.url.replace(/^http:\/\//, "http/");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
status: 200,
|
|
||||||
body: {
|
|
||||||
code: 200,
|
|
||||||
message: "请求成功",
|
|
||||||
data: {
|
|
||||||
id,
|
|
||||||
br,
|
|
||||||
url: result.url,
|
|
||||||
...(proxy && result.proxyUrl ? { proxyUrl: result.proxyUrl } : {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error in song_url_ncmget:", error);
|
|
||||||
return {
|
|
||||||
status: 500,
|
|
||||||
body: {
|
|
||||||
code: 500,
|
|
||||||
message: "服务器处理请求失败",
|
|
||||||
...(process.env.NODE_ENV === "development" ? { error: error.message } : {}),
|
|
||||||
data: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
const validBR = ['128', '192', '320', '740', '999']
|
||||||
|
// const covertBR = ['128000', '192000', '320000','740000', '999000']
|
||||||
|
if (!validBR.includes(br)) {
|
||||||
|
return {
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '无效音质参数',
|
||||||
|
allowed_values: validBR,
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiUrl = new URL('https://music-api.gdstudio.xyz/api.php')
|
||||||
|
apiUrl.searchParams.append('types', 'url')
|
||||||
|
apiUrl.searchParams.append('id', id)
|
||||||
|
apiUrl.searchParams.append('br', br)
|
||||||
|
|
||||||
|
const response = await fetch(apiUrl.toString())
|
||||||
|
if (!response.ok) throw new Error(`API 响应状态: ${response.status}`)
|
||||||
|
const result = await response.json()
|
||||||
|
|
||||||
|
// 代理逻辑
|
||||||
|
const useProxy = process.env.ENABLE_PROXY || false
|
||||||
|
const proxy = process.env.PROXY_URL
|
||||||
|
if (useProxy && result.url && result.url.includes('kuwo')) {
|
||||||
|
result.proxyUrl = proxy + result.url.replace(/^http:\/\//, 'http/')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: {
|
||||||
|
code: 200,
|
||||||
|
message: '请求成功',
|
||||||
|
data: {
|
||||||
|
id,
|
||||||
|
br,
|
||||||
|
url: result.url,
|
||||||
|
...(proxy && result.proxyUrl ? { proxyUrl: result.proxyUrl } : {}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in song_url_ncmget:', error)
|
||||||
|
return {
|
||||||
|
status: 500,
|
||||||
|
body: {
|
||||||
|
code: 500,
|
||||||
|
message: '服务器处理请求失败',
|
||||||
|
...(process.env.NODE_ENV === 'development'
|
||||||
|
? { error: error.message }
|
||||||
|
: {}),
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,31 +5,34 @@ const createOption = require('../util/option.js')
|
|||||||
const logger = require('../util/logger.js')
|
const logger = require('../util/logger.js')
|
||||||
|
|
||||||
module.exports = async (query, request) => {
|
module.exports = async (query, request) => {
|
||||||
try {
|
try {
|
||||||
const match = require("@unblockneteasemusic/server")
|
const match = require('@unblockneteasemusic/server')
|
||||||
const source = query.source
|
const source = query.source
|
||||||
? query.source.split(',') : ['pyncmd', 'bodian', 'kuwo', 'qq', 'migu', 'kugou']
|
? query.source.split(',')
|
||||||
const server = query.server ? query.server.split(',') : query.server
|
: ['pyncmd', 'bodian', 'kuwo', 'qq', 'migu', 'kugou']
|
||||||
const result = await match(query.id, !server? source : server)
|
const server = query.server ? query.server.split(',') : query.server
|
||||||
const proxy = process.env.PROXY_URL;
|
const result = await match(query.id, !server ? source : server)
|
||||||
logger.info("开始解灰", query.id, result)
|
const proxy = process.env.PROXY_URL
|
||||||
const useProxy = process.env.ENABLE_PROXY || "false"
|
logger.info('开始解灰', query.id, result)
|
||||||
if (result.url.includes('kuwo') && useProxy === "true") { result.proxyUrl = proxy + result.url }
|
const useProxy = process.env.ENABLE_PROXY || 'false'
|
||||||
return {
|
if (result.url.includes('kuwo')) {
|
||||||
status: 200,
|
result.proxyUrl = useProxy === 'true' ? proxy + result.url : result.url
|
||||||
body: {
|
|
||||||
code: 200,
|
|
||||||
data: result,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return {
|
|
||||||
status: 500,
|
|
||||||
body: {
|
|
||||||
code: 500,
|
|
||||||
msg: e.message || 'unblock error',
|
|
||||||
data: [],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: {
|
||||||
|
code: 200,
|
||||||
|
data: result,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
status: 500,
|
||||||
|
body: {
|
||||||
|
code: 500,
|
||||||
|
msg: e.message || 'unblock error',
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -18,12 +18,24 @@ module.exports = async (query, request) => {
|
|||||||
try {
|
try {
|
||||||
const result = await match(query.id, source)
|
const result = await match(query.id, source)
|
||||||
logger.info('开始解灰', query.id, result)
|
logger.info('开始解灰', query.id, result)
|
||||||
if (result.url.includes('kuwo')) {
|
// avoid optional chaining for compatibility
|
||||||
const useProxy = process.env.ENABLE_PROXY || 'false'
|
let url
|
||||||
var proxyUrl = useProxy === 'true' ? process.env.PROXY_URL + result.url : result.url
|
if (Array.isArray(result)) {
|
||||||
|
url = result[0] && result[0].url ? result[0].url : result[0]
|
||||||
|
} else {
|
||||||
|
url = result && result.url ? result.url : result
|
||||||
}
|
}
|
||||||
let url = Array.isArray(result) ? (result[0]?.url || result[0]) : (result.url || result)
|
// decide proxyUrl after we resolved the actual url value
|
||||||
|
let proxyUrl = ''
|
||||||
if (url) {
|
if (url) {
|
||||||
|
if (url.includes('kuwo')) {
|
||||||
|
const useProxy = process.env.ENABLE_PROXY || 'false'
|
||||||
|
if (useProxy === 'true' && process.env.PROXY_URL) {
|
||||||
|
proxyUrl = process.env.PROXY_URL + url
|
||||||
|
} else {
|
||||||
|
proxyUrl = url
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
status: 200,
|
status: 200,
|
||||||
body: {
|
body: {
|
||||||
|
|||||||
17
package.json
17
package.json
@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "@neteasecloudmusicapienhanced/api",
|
"name": "@neteasecloudmusicapienhanced/api",
|
||||||
"version": "4.29.12",
|
"version": "4.29.13",
|
||||||
"description": "为停更的网易云音乐 NodeJs API 提供持续的维护!",
|
"description": "为停更的网易云音乐 NodeJs API 提供持续的维护!",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev": "nodemon app.js",
|
||||||
"start": "node app.js",
|
"start": "node app.js",
|
||||||
"test": "mocha -r intelli-espower-loader -t 60000 server.test.js main.test.js --exit",
|
"test": "mocha -r intelli-espower-loader -t 60000 server.test.js main.test.js --exit",
|
||||||
"lint": "eslint \"**/*.{js,ts}\"",
|
"lint": "eslint \"**/*.{js,ts}\"",
|
||||||
@ -66,7 +67,7 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@unblockneteasemusic/server": "^0.28.0",
|
"@unblockneteasemusic/server": "^0.28.0",
|
||||||
"axios": "^1.12.2",
|
"axios": "^1.13.1",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
@ -82,20 +83,24 @@
|
|||||||
"yargs": "^18.0.0"
|
"yargs": "^18.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^5.0.4",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
|
"@eslint/js": "^9.39.0",
|
||||||
|
"@types/express": "^5.0.5",
|
||||||
"@types/express-fileupload": "^1.5.1",
|
"@types/express-fileupload": "^1.5.1",
|
||||||
"@types/mocha": "^10.0.10",
|
"@types/mocha": "^10.0.10",
|
||||||
"@types/node": "24.9.1",
|
"@types/node": "24.9.1",
|
||||||
"@typescript-eslint/eslint-plugin": "5.62.0",
|
"@typescript-eslint/eslint-plugin": "8.46.2",
|
||||||
"@typescript-eslint/parser": "5.62.0",
|
"@typescript-eslint/parser": "8.46.2",
|
||||||
"eslint": "8.7.0",
|
"eslint": "9.39.0",
|
||||||
"eslint-config-prettier": "10.1.8",
|
"eslint-config-prettier": "10.1.8",
|
||||||
"eslint-plugin-html": "8.1.3",
|
"eslint-plugin-html": "8.1.3",
|
||||||
"eslint-plugin-prettier": "5.5.4",
|
"eslint-plugin-prettier": "5.5.4",
|
||||||
|
"globals": "^16.4.0",
|
||||||
"husky": "9.1.7",
|
"husky": "9.1.7",
|
||||||
"intelli-espower-loader": "1.1.0",
|
"intelli-espower-loader": "1.1.0",
|
||||||
"lint-staged": "16.2.6",
|
"lint-staged": "16.2.6",
|
||||||
"mocha": "11.7.4",
|
"mocha": "11.7.4",
|
||||||
|
"nodemon": "^3.1.10",
|
||||||
"pkg": "^5.8.1",
|
"pkg": "^5.8.1",
|
||||||
"power-assert": "1.6.1",
|
"power-assert": "1.6.1",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.6.2",
|
||||||
|
|||||||
769
pnpm-lock.yaml
generated
769
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -60,7 +60,7 @@
|
|||||||
<section class="block">
|
<section class="block">
|
||||||
<h2>常用接口</h2>
|
<h2>常用接口</h2>
|
||||||
<ul class="links">
|
<ul class="links">
|
||||||
<li><a href="/search?keywords=这么可爱真是抱歉">搜索音乐: <code>GET /search</code></a></li>
|
<li><a href="/search?keywords=妖精小姐的魔法邀约">搜索音乐: <code>GET /search</code></a></li>
|
||||||
<li><a href="/song/detail?ids=2756058128">获取音乐详情: <code>GET /song/detail</code></a></li>
|
<li><a href="/song/detail?ids=2756058128">获取音乐详情: <code>GET /song/detail</code></a></li>
|
||||||
<li><a href="/comment/music?id=2756058128&limit=1">获取音乐评论: <code>GET /comment/music</code></a></li>
|
<li><a href="/comment/music?id=2756058128&limit=1">获取音乐评论: <code>GET /comment/music</code></a></li>
|
||||||
<li><a href="/song/url/v1?id=2756058128&level=exhigh">获取音乐播放链接: <code>GET /song/url/v1</code></a></li>
|
<li><a href="/song/url/v1?id=2756058128&level=exhigh">获取音乐播放链接: <code>GET /song/url/v1</code></a></li>
|
||||||
@ -71,7 +71,7 @@
|
|||||||
<h2>调试部分</h2>
|
<h2>调试部分</h2>
|
||||||
<pre><code>curl -s {origin}/inner/version
|
<pre><code>curl -s {origin}/inner/version
|
||||||
curl -s {origin}/search?keywords=网易云</code></pre>
|
curl -s {origin}/search?keywords=网易云</code></pre>
|
||||||
<p style="margin-top:10px"> · <a href="/api.html">交互式调试</a> · <a href="/qrlogin.html">二维码登录示例</a> · <a href="/unblock_test.html">解灰测试</a></p> · <a href="/audio_match_demo/index.html">听歌识曲 Demo</a></p> · <a href="/unblock_test.html">云盘上传</a></p> · <a href="/playlist_import.html">歌单导入</a></p> · <a href="/eapi_decrypt.html">EAPI 解密</p>
|
<p style="margin-top:10px"> · <a href="/api.html">交互式调试</a> · <a href="/qrlogin.html">二维码登录示例</a> · <a href="/unblock_test.html">解灰测试</a></p> · <a href="/audio_match_demo/index.html">听歌识曲 Demo</a></p> · <a href="/cloud.html">云盘上传</a></p> · <a href="/playlist_import.html">歌单导入</a></p> · <a href="/eapi_decrypt.html">EAPI 解密</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<footer class="site-footer">
|
<footer class="site-footer">
|
||||||
|
|||||||
34
server.js
34
server.js
@ -1,4 +1,4 @@
|
|||||||
require("dotenv").config();
|
require('dotenv').config()
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
@ -248,20 +248,28 @@ async function consturctServer(moduleDefs) {
|
|||||||
(req.baseUrl === '/song/url/v1' || req.baseUrl === '/song/url') &&
|
(req.baseUrl === '/song/url/v1' || req.baseUrl === '/song/url') &&
|
||||||
process.env.ENABLE_GENERAL_UNBLOCK === 'true'
|
process.env.ENABLE_GENERAL_UNBLOCK === 'true'
|
||||||
) {
|
) {
|
||||||
const song = moduleResponse['body']['data'][0]
|
const song = moduleResponse.body.data[0]
|
||||||
if (song.freeTrialInfo !== null || !song.url || [1, 4].includes(song.fee)) {
|
if (
|
||||||
const match = require('@unblockneteasemusic/server')
|
song.freeTrialInfo !== null ||
|
||||||
const source = process.env.UNBLOCK_SOURCE ? process.env.UNBLOCK_SOURCE.split(',') : ['pyncmd', 'bodian', 'kuwo', 'qq', 'migu', 'kugou']
|
!song.url ||
|
||||||
logger.info("开始解灰", source)
|
[1, 4].includes(song.fee)
|
||||||
const { url } = await match(req.query.id, source)
|
) {
|
||||||
song.url = url
|
const match = require('@unblockneteasemusic/server')
|
||||||
song.freeTrialInfo = 'null'
|
const source = process.env.UNBLOCK_SOURCE
|
||||||
logger.info("解灰成功!")
|
? process.env.UNBLOCK_SOURCE.split(',')
|
||||||
|
: ['pyncmd', 'bodian', 'kuwo', 'qq', 'migu', 'kugou']
|
||||||
|
logger.info('开始解灰', source)
|
||||||
|
const { url } = await match(req.query.id, source)
|
||||||
|
song.url = url
|
||||||
|
song.freeTrialInfo = 'null'
|
||||||
|
logger.info('解灰成功!')
|
||||||
}
|
}
|
||||||
if (song.url.includes('kuwo')) {
|
if (song.url && song.url.includes('kuwo')) {
|
||||||
const proxy = process.env.PROXY_URL;
|
const proxy = process.env.PROXY_URL
|
||||||
const useProxy = process.env.ENABLE_PROXY || 'false'
|
const useProxy = process.env.ENABLE_PROXY || 'false'
|
||||||
if (useProxy === 'true' && proxy) {song.proxyUrl = proxy + song.url}
|
if (useProxy === 'true' && proxy) {
|
||||||
|
song.proxyUrl = proxy + song.url
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ const host = global.host || 'http://localhost:3000'
|
|||||||
describe('测试获取歌曲是否正常', () => {
|
describe('测试获取歌曲是否正常', () => {
|
||||||
it('歌曲的 url 不应该为空', (done) => {
|
it('歌曲的 url 不应该为空', (done) => {
|
||||||
const qs = {
|
const qs = {
|
||||||
id: 1969519579,
|
id: 2756058128,
|
||||||
br: 999000,
|
br: 999000,
|
||||||
realIP: global.cnIp,
|
realIP: global.cnIp,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -155,9 +155,12 @@ function ApiCache() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add automatic cache clearing from duration, includes max limit on setTimeout
|
// add automatic cache clearing from duration, includes max limit on setTimeout
|
||||||
timers[key] = setTimeout(function () {
|
timers[key] = setTimeout(
|
||||||
instance.clear(key, true)
|
function () {
|
||||||
}, Math.min(duration, 2147483647))
|
instance.clear(key, true)
|
||||||
|
},
|
||||||
|
Math.min(duration, 2147483647),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function accumulateContent(res, content) {
|
function accumulateContent(res, content) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
const crypto = require("crypto");
|
const crypto = require('crypto')
|
||||||
const os = require("os");
|
const os = require('os')
|
||||||
|
|
||||||
class AdvancedClientSignGenerator {
|
class AdvancedClientSignGenerator {
|
||||||
/**
|
/**
|
||||||
@ -7,25 +7,25 @@ class AdvancedClientSignGenerator {
|
|||||||
*/
|
*/
|
||||||
static getRealMacAddress() {
|
static getRealMacAddress() {
|
||||||
try {
|
try {
|
||||||
const interfaces = os.networkInterfaces();
|
const interfaces = os.networkInterfaces()
|
||||||
for (let interfaceName in interfaces) {
|
for (let interfaceName in interfaces) {
|
||||||
const interface = interfaces[interfaceName];
|
const networkInterface = interfaces[interfaceName]
|
||||||
for (let i = 0; i < interface.length; i++) {
|
for (let i = 0; i < networkInterface.length; i++) {
|
||||||
const alias = interface[i];
|
const alias = networkInterface[i]
|
||||||
// 排除内部地址和无效地址
|
// 排除内部地址和无效地址
|
||||||
if (
|
if (
|
||||||
alias.mac &&
|
alias.mac &&
|
||||||
alias.mac !== "00:00:00:00:00:00" &&
|
alias.mac !== '00:00:00:00:00:00' &&
|
||||||
!alias.internal
|
!alias.internal
|
||||||
) {
|
) {
|
||||||
return alias.mac.toUpperCase();
|
return alias.mac.toUpperCase()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn("获取MAC地址失败:", error.message);
|
console.warn('获取MAC地址失败:', error.message)
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,108 +33,108 @@ class AdvancedClientSignGenerator {
|
|||||||
* 生成随机MAC地址
|
* 生成随机MAC地址
|
||||||
*/
|
*/
|
||||||
static generateRandomMac() {
|
static generateRandomMac() {
|
||||||
const chars = "0123456789ABCDEF";
|
const chars = '0123456789ABCDEF'
|
||||||
let mac = "";
|
let mac = ''
|
||||||
for (let i = 0; i < 6; i++) {
|
for (let i = 0; i < 6; i++) {
|
||||||
if (i > 0) mac += ":";
|
if (i > 0) mac += ':'
|
||||||
mac +=
|
mac +=
|
||||||
chars[Math.floor(Math.random() * 16)] +
|
chars[Math.floor(Math.random() * 16)] +
|
||||||
chars[Math.floor(Math.random() * 16)];
|
chars[Math.floor(Math.random() * 16)]
|
||||||
}
|
}
|
||||||
// 确保第一个字节是单播地址(最低位为0)
|
// 确保第一个字节是单播地址(最低位为0)
|
||||||
const firstByte = parseInt(mac.substring(0, 2), 16);
|
const firstByte = parseInt(mac.substring(0, 2), 16)
|
||||||
const unicastFirstByte = (firstByte & 0xfe)
|
const unicastFirstByte = (firstByte & 0xfe)
|
||||||
.toString(16)
|
.toString(16)
|
||||||
.padStart(2, "0")
|
.padStart(2, '0')
|
||||||
.toUpperCase();
|
.toUpperCase()
|
||||||
return unicastFirstByte + mac.substring(2);
|
return unicastFirstByte + mac.substring(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取MAC地址(优先真实,否则随机)
|
* 获取MAC地址(优先真实,否则随机)
|
||||||
*/
|
*/
|
||||||
static getMacAddress() {
|
static getMacAddress() {
|
||||||
const realMac = this.getRealMacAddress();
|
const realMac = this.getRealMacAddress()
|
||||||
if (realMac) {
|
if (realMac) {
|
||||||
return realMac;
|
return realMac
|
||||||
}
|
}
|
||||||
console.warn("无法获取真实MAC地址,使用随机生成");
|
console.warn('无法获取真实MAC地址,使用随机生成')
|
||||||
return this.generateRandomMac();
|
return this.generateRandomMac()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串转HEX编码
|
* 字符串转HEX编码
|
||||||
*/
|
*/
|
||||||
static stringToHex(str) {
|
static stringToHex(str) {
|
||||||
return Buffer.from(str, "utf8").toString("hex").toUpperCase();
|
return Buffer.from(str, 'utf8').toString('hex').toUpperCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SHA-256哈希
|
* SHA-256哈希
|
||||||
*/
|
*/
|
||||||
static sha256(data) {
|
static sha256(data) {
|
||||||
return crypto.createHash("sha256").update(data, "utf8").digest("hex");
|
return crypto.createHash('sha256').update(data, 'utf8').digest('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成随机设备ID
|
* 生成随机设备ID
|
||||||
*/
|
*/
|
||||||
static generateRandomDeviceId() {
|
static generateRandomDeviceId() {
|
||||||
const partLengths = [4, 4, 4, 4, 4, 4, 4, 5]; // 各部分长度
|
const partLengths = [4, 4, 4, 4, 4, 4, 4, 5] // 各部分长度
|
||||||
const chars = "0123456789ABCDEF";
|
const chars = '0123456789ABCDEF'
|
||||||
|
|
||||||
const parts = partLengths.map((length) => {
|
const parts = partLengths.map((length) => {
|
||||||
let part = "";
|
let part = ''
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
part += chars[Math.floor(Math.random() * 16)];
|
part += chars[Math.floor(Math.random() * 16)]
|
||||||
}
|
}
|
||||||
return part;
|
return part
|
||||||
});
|
})
|
||||||
|
|
||||||
return parts.join("_");
|
return parts.join('_')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成随机clientSign(优先使用真实MAC,否则随机)
|
* 生成随机clientSign(优先使用真实MAC,否则随机)
|
||||||
*/
|
*/
|
||||||
static generateRandomClientSign(secretKey = "") {
|
static generateRandomClientSign(secretKey = '') {
|
||||||
// 获取MAC地址(优先真实,否则随机)
|
// 获取MAC地址(优先真实,否则随机)
|
||||||
const macAddress = this.getMacAddress();
|
const macAddress = this.getMacAddress()
|
||||||
|
|
||||||
// 生成随机设备ID
|
// 生成随机设备ID
|
||||||
const deviceId = this.generateRandomDeviceId();
|
const deviceId = this.generateRandomDeviceId()
|
||||||
|
|
||||||
// 转换设备ID为HEX
|
// 转换设备ID为HEX
|
||||||
const hexDeviceId = this.stringToHex(deviceId);
|
const hexDeviceId = this.stringToHex(deviceId)
|
||||||
|
|
||||||
// 构造签名字符串
|
// 构造签名字符串
|
||||||
const signString = `${macAddress}@@@${hexDeviceId}`;
|
const signString = `${macAddress}@@@${hexDeviceId}`
|
||||||
|
|
||||||
// 生成哈希
|
// 生成哈希
|
||||||
const hash = this.sha256(signString + secretKey);
|
const hash = this.sha256(signString + secretKey)
|
||||||
|
|
||||||
return `${signString}@@@@@@${hash}`;
|
return `${signString}@@@@@@${hash}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量生成多个随机签名
|
* 批量生成多个随机签名
|
||||||
*/
|
*/
|
||||||
static generateMultipleRandomSigns(count, secretKey = "") {
|
static generateMultipleRandomSigns(count, secretKey = '') {
|
||||||
const signs = [];
|
const signs = []
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
signs.push(this.generateRandomClientSign(secretKey));
|
signs.push(this.generateRandomClientSign(secretKey))
|
||||||
}
|
}
|
||||||
return signs;
|
return signs
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用指定参数生成签名
|
* 使用指定参数生成签名
|
||||||
*/
|
*/
|
||||||
static generateWithCustomDeviceId(macAddress, deviceId, secretKey = "") {
|
static generateWithCustomDeviceId(macAddress, deviceId, secretKey = '') {
|
||||||
const hexDeviceId = this.stringToHex(deviceId);
|
const hexDeviceId = this.stringToHex(deviceId)
|
||||||
const signString = `${macAddress}@@@${hexDeviceId}`;
|
const signString = `${macAddress}@@@${hexDeviceId}`
|
||||||
const hash = this.sha256(signString + secretKey);
|
const hash = this.sha256(signString + secretKey)
|
||||||
return `${signString}@@@@@@${hash}`;
|
return `${signString}@@@@@@${hash}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,28 +142,28 @@ class AdvancedClientSignGenerator {
|
|||||||
*/
|
*/
|
||||||
static validateClientSign(clientSign) {
|
static validateClientSign(clientSign) {
|
||||||
try {
|
try {
|
||||||
const parts = clientSign.split("@@@@@@");
|
const parts = clientSign.split('@@@@@@')
|
||||||
if (parts.length !== 2) return false;
|
if (parts.length !== 2) return false
|
||||||
|
|
||||||
const [infoPart, hash] = parts;
|
const [infoPart, hash] = parts
|
||||||
const infoParts = infoPart.split("@@@");
|
const infoParts = infoPart.split('@@@')
|
||||||
if (infoParts.length !== 2) return false;
|
if (infoParts.length !== 2) return false
|
||||||
|
|
||||||
const [mac, hexDeviceId] = infoParts;
|
const [mac, hexDeviceId] = infoParts
|
||||||
|
|
||||||
// 验证MAC地址格式
|
// 验证MAC地址格式
|
||||||
const macRegex = /^([0-9A-F]{2}:){5}[0-9A-F]{2}$/;
|
const macRegex = /^([0-9A-F]{2}:){5}[0-9A-F]{2}$/
|
||||||
if (!macRegex.test(mac)) return false;
|
if (!macRegex.test(mac)) return false
|
||||||
|
|
||||||
// 验证哈希格式
|
// 验证哈希格式
|
||||||
const hashRegex = /^[0-9a-f]{64}$/;
|
const hashRegex = /^[0-9a-f]{64}$/
|
||||||
if (!hashRegex.test(hash)) return false;
|
if (!hashRegex.test(hash)) return false
|
||||||
|
|
||||||
return true;
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = AdvancedClientSignGenerator;
|
module.exports = AdvancedClientSignGenerator
|
||||||
|
|||||||
@ -1,28 +1,42 @@
|
|||||||
// ANSI 颜色代码
|
// ANSI 颜色代码
|
||||||
const colors = {
|
const colors = {
|
||||||
reset: '\x1b[0m',
|
reset: '\x1b[0m',
|
||||||
bright: '\x1b[1m',
|
bright: '\x1b[1m',
|
||||||
dim: '\x1b[2m',
|
dim: '\x1b[2m',
|
||||||
black: '\x1b[30m',
|
black: '\x1b[30m',
|
||||||
red: '\x1b[31m',
|
red: '\x1b[31m',
|
||||||
green: '\x1b[32m',
|
green: '\x1b[32m',
|
||||||
yellow: '\x1b[33m',
|
yellow: '\x1b[33m',
|
||||||
blue: '\x1b[34m',
|
blue: '\x1b[34m',
|
||||||
magenta: '\x1b[35m',
|
magenta: '\x1b[35m',
|
||||||
cyan: '\x1b[36m',
|
cyan: '\x1b[36m',
|
||||||
white: '\x1b[37m',
|
white: '\x1b[37m',
|
||||||
bgRed: '\x1b[41m',
|
bgRed: '\x1b[41m',
|
||||||
bgGreen: '\x1b[42m',
|
bgGreen: '\x1b[42m',
|
||||||
bgYellow: '\x1b[43m'
|
bgYellow: '\x1b[43m',
|
||||||
};
|
}
|
||||||
|
|
||||||
const logger = {
|
const logger = {
|
||||||
debug: (msg, ...args) => console.info(`${colors.cyan}[DEBUG]${colors.reset}`, msg, ...args),
|
debug: (msg, ...args) =>
|
||||||
info: (msg, ...args) => console.info(`${colors.green}[INFO]${colors.reset}`, msg, ...args),
|
console.info(`${colors.cyan}[DEBUG]${colors.reset}`, msg, ...args),
|
||||||
warn: (msg, ...args) => console.info(`${colors.yellow}[WARN]${colors.reset}`, msg, ...args),
|
info: (msg, ...args) =>
|
||||||
error: (msg, ...args) => console.error(`${colors.red}[ERROR]${colors.reset}`, msg, ...args),
|
console.info(`${colors.green}[INFO]${colors.reset}`, msg, ...args),
|
||||||
success: (msg, ...args) => console.log(`${colors.bright}${colors.green}[SUCCESS]${colors.reset}`, msg, ...args),
|
warn: (msg, ...args) =>
|
||||||
critical: (msg, ...args) => console.error(`${colors.bright}${colors.bgRed}[CRITICAL]${colors.reset}`, msg, ...args)
|
console.info(`${colors.yellow}[WARN]${colors.reset}`, msg, ...args),
|
||||||
};
|
error: (msg, ...args) =>
|
||||||
|
console.error(`${colors.red}[ERROR]${colors.reset}`, msg, ...args),
|
||||||
|
success: (msg, ...args) =>
|
||||||
|
console.log(
|
||||||
|
`${colors.bright}${colors.green}[SUCCESS]${colors.reset}`,
|
||||||
|
msg,
|
||||||
|
...args,
|
||||||
|
),
|
||||||
|
critical: (msg, ...args) =>
|
||||||
|
console.error(
|
||||||
|
`${colors.bright}${colors.bgRed}[CRITICAL]${colors.reset}`,
|
||||||
|
msg,
|
||||||
|
...args,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = logger;
|
module.exports = logger
|
||||||
|
|||||||
@ -101,7 +101,7 @@ const SPECIAL_STATUS_CODES = new Set([201, 302, 400, 502, 800, 801, 802, 803])
|
|||||||
|
|
||||||
// chooseUserAgent函数
|
// chooseUserAgent函数
|
||||||
const chooseUserAgent = (crypto, uaType = 'pc') => {
|
const chooseUserAgent = (crypto, uaType = 'pc') => {
|
||||||
return userAgentMap[crypto]?.[uaType] || ''
|
return (userAgentMap[crypto] && userAgentMap[crypto][uaType]) || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// cookie处理
|
// cookie处理
|
||||||
@ -153,15 +153,17 @@ const createHeaderCookie = (header) => {
|
|||||||
const generateRequestId = () => {
|
const generateRequestId = () => {
|
||||||
return `${now()}_${floor(random() * 1000)
|
return `${now()}_${floor(random() * 1000)
|
||||||
.toString()
|
.toString()
|
||||||
.padStart(4, "0")}`;
|
.padStart(4, '0')}`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const createRequest = (uri, data, options) => {
|
const createRequest = (uri, data, options) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// 变量声明和初始化
|
// 变量声明和初始化
|
||||||
const headers = options.headers ? { ...options.headers } : {}
|
const headers = options.headers ? { ...options.headers } : {}
|
||||||
const ip = options.realIP || options.ip || (options.randomCNIP ? generateRandomChineseIP() : '')
|
const ip =
|
||||||
|
options.realIP ||
|
||||||
|
options.ip ||
|
||||||
|
(options.randomCNIP ? generateRandomChineseIP() : '')
|
||||||
// IP头设置
|
// IP头设置
|
||||||
if (ip) {
|
if (ip) {
|
||||||
headers['X-Real-IP'] = ip
|
headers['X-Real-IP'] = ip
|
||||||
@ -243,8 +245,8 @@ const createRequest = (uri, data, options) => {
|
|||||||
options.e_r !== undefined
|
options.e_r !== undefined
|
||||||
? options.e_r
|
? options.e_r
|
||||||
: data.e_r !== undefined
|
: data.e_r !== undefined
|
||||||
? data.e_r
|
? data.e_r
|
||||||
: ENCRYPT_RESPONSE,
|
: ENCRYPT_RESPONSE,
|
||||||
)
|
)
|
||||||
encryptData = encrypt.eapi(uri, data)
|
encryptData = encrypt.eapi(uri, data)
|
||||||
url = API_DOMAIN + '/eapi/' + uri.substr(5)
|
url = API_DOMAIN + '/eapi/' + uri.substr(5)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user