mirror of
https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced.git
synced 2026-10-20 22:51:23 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a5a1242f2 | ||
|
|
6946dc8e14 | ||
|
|
22b78779ca | ||
|
|
35607f5050 | ||
|
|
60af95ac06 | ||
|
|
46073e5f50 | ||
|
|
bf12abe2f1 | ||
|
|
1491b91829 | ||
|
|
63f669d7f8 | ||
|
|
d525204dda | ||
|
|
6eb31984fd | ||
|
|
9faeb0aa25 | ||
|
|
f6db3e76e9 | ||
|
|
9163d48f0a |
@@ -45,14 +45,14 @@
|
||||
|
||||
### 环境要求
|
||||
|
||||
- Node.js 18 及以上
|
||||
- Node.js 22 及以上
|
||||
- 推荐使用 pnpm 进行依赖管理
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
git clone https://github.com/neteasecloudmusicapienhanced/api-enhanced.git
|
||||
cd api
|
||||
cd api-enhanced
|
||||
pnpm i
|
||||
```
|
||||
|
||||
|
||||
Vendored
+25
@@ -1474,6 +1474,20 @@ export function artist_new_song(
|
||||
} & RequestBaseConfig,
|
||||
): Promise<Response>
|
||||
|
||||
export function artist_new_song_playall(
|
||||
params: RequestBaseConfig,
|
||||
): Promise<Response>
|
||||
|
||||
export function artist_new_song_mv_list_v2(
|
||||
params: {
|
||||
startTimestamp?: number | string
|
||||
before?: number | string
|
||||
sourceType?: number | string
|
||||
limit?: number | string
|
||||
firstRequest?: boolean | string
|
||||
} & RequestBaseConfig,
|
||||
): Promise<Response>
|
||||
|
||||
export function artist_detail(
|
||||
params: {
|
||||
id: number | string
|
||||
@@ -1594,6 +1608,10 @@ export function vip_growthpoint_get(
|
||||
} & RequestBaseConfig,
|
||||
): Promise<Response>
|
||||
|
||||
export function vip_growthpoint_getall(
|
||||
params: RequestBaseConfig,
|
||||
): Promise<Response>
|
||||
|
||||
export function artist_fans(
|
||||
params: { id: number | string } & MultiPageConfig & RequestBaseConfig,
|
||||
): Promise<Response>
|
||||
@@ -2049,6 +2067,13 @@ export function listen_data_report(
|
||||
} & RequestBaseConfig,
|
||||
): Promise<Response>
|
||||
|
||||
export function listen_data_song_play_rank(
|
||||
params: {
|
||||
type?: string
|
||||
endTime?: string | number
|
||||
} & RequestBaseConfig,
|
||||
): Promise<Response>
|
||||
|
||||
export function listen_data_today_song(
|
||||
params: RequestBaseConfig,
|
||||
): Promise<Response>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// 获取广告
|
||||
// 基于逆向网易云音乐 v9.5.45 RN Hermes 源码:
|
||||
// - adService.getAd() → Network.nativeRequest → /api/ad/get
|
||||
// - 需要 X-antiCheatToken 易盾反作弊头
|
||||
// - 使用 xeapi 加密
|
||||
//
|
||||
// 返回 extra.reqId 可用于 ad_listening_rights_gain 的 reqUid
|
||||
//
|
||||
const createOption = require('../util/option.js')
|
||||
|
||||
module.exports = async (query, request) => {
|
||||
const data = {
|
||||
type_ids: query.type_ids || '["400002_0"]',
|
||||
}
|
||||
|
||||
const option = createOption(query, 'xeapi')
|
||||
option.checkToken = true
|
||||
|
||||
const res = await request(`/api/ad/get`, data, option)
|
||||
const raw = res.body
|
||||
|
||||
// 提取广告中的 req_id (用于领取权益)
|
||||
let reqId = ''
|
||||
try {
|
||||
if (raw?.ads) {
|
||||
const ad = Object.values(raw.ads)[0]
|
||||
if (ad?.extJson) {
|
||||
const ext = JSON.parse(ad.extJson)
|
||||
reqId = ext?.contextInfo?.req_id || ''
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: 200,
|
||||
ads: raw?.ads || null,
|
||||
message: raw?.message || null,
|
||||
extra: { reqId },
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// 看广告免费听歌 - 领取免费听权益
|
||||
// 请求流程(基于逆向网易云音乐 v9.5.45 RN Hermes 源码):
|
||||
// 1. 从广告平台拉广告 → 用户看完/点击广告 → 获取 ad 对象的 extJson.contextInfo.req_id 作为 reqUid
|
||||
// 2. 调用本接口传入 reqUid 及相关权益参数,领取免费听权益
|
||||
// 3. 服务器返回 gainFlag 等标识,用于展示领取结果
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
const adGet = require('./ad_get.js')
|
||||
|
||||
module.exports = async (query, request) => {
|
||||
const time = Date.now()
|
||||
|
||||
// 如果未传入 reqUid,自动从 ad_get 获取最新广告的 req_id
|
||||
let reqUid = query.reqUid || ''
|
||||
if (!reqUid) {
|
||||
try {
|
||||
const adRes = await adGet(
|
||||
{ ...query, type_ids: query.type_ids || '["400002_0"]' },
|
||||
request,
|
||||
)
|
||||
reqUid = adRes?.body?.extra?.reqId || ''
|
||||
console.log(`自动获取 reqUid: ${reqUid}`)
|
||||
} catch (e) {
|
||||
// 获取广告失败,后续请求会因缺少 reqUid 被拒绝
|
||||
}
|
||||
}
|
||||
|
||||
const rightsParam = {
|
||||
// 必填: 广告请求 ID,自动从 ad_get 获取
|
||||
reqUid,
|
||||
|
||||
// 广告创意类型 (默认 1)
|
||||
creativeType: parseInt(query.creativeType || 2),
|
||||
|
||||
// 时间戳
|
||||
exposureTime: query.exposureTime || time,
|
||||
clickTime: query.clickTime || time,
|
||||
|
||||
// 权益领取方式
|
||||
rightsGainMethod: parseInt(query.rightsGainMethod || 2),
|
||||
|
||||
// 权益时长相关
|
||||
rightsGainDuration: query.rightsGainDuration
|
||||
? parseInt(query.rightsGainDuration)
|
||||
: undefined,
|
||||
extraRightsGainMethod: query.extraRightsGainMethod
|
||||
? parseInt(query.extraRightsGainMethod)
|
||||
: undefined,
|
||||
extraRightsGainDuration: query.extraRightsGainDuration
|
||||
? parseInt(query.extraRightsGainDuration)
|
||||
: undefined,
|
||||
nextRightsGainDuration: query.nextRightsGainDuration
|
||||
? parseInt(query.nextRightsGainDuration)
|
||||
: undefined,
|
||||
|
||||
// 来源标识 | 权益扩展信息
|
||||
source: query.source || undefined,
|
||||
rightsExtJson: query.rightsExtJson || undefined,
|
||||
|
||||
// 应用信息(下载类广告)
|
||||
appInfo: query.appInfo ? JSON.parse(query.appInfo) : undefined,
|
||||
installed: query.installed ? parseInt(query.installed) : undefined,
|
||||
}
|
||||
|
||||
// 清理 undefined 字段
|
||||
Object.keys(rightsParam).forEach((key) => {
|
||||
if (rightsParam[key] === undefined) delete rightsParam[key]
|
||||
})
|
||||
|
||||
// 将参数序列化为 reqParam 字符串 (与 RN 源码完全一致)
|
||||
const data = {
|
||||
reqParam: JSON.stringify(rightsParam),
|
||||
}
|
||||
|
||||
const option = createOption(query, 'xeapi')
|
||||
// 关键: 开启 X-antiCheatToken 头
|
||||
option.checkToken = true
|
||||
|
||||
const res = await request(`/api/ad/listening/rights/gain`, data, option)
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: 200,
|
||||
data: res.body,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// 获取关注歌手的新歌曲和 MV
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
startTimestamp: query.startTimestamp || query.before || Date.now(),
|
||||
sourceType: query.sourceType || 1,
|
||||
limit: query.limit || 10,
|
||||
firstRequest: query.firstRequest ?? true,
|
||||
}
|
||||
return request(
|
||||
`/api/sub/artist/new/works/song-mv/list/v2`,
|
||||
data,
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// 获取所有关注歌手最近的 50 首新歌
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
return request(
|
||||
`/api/sub/artist/new/works/song/playall`,
|
||||
{},
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// 听歌足迹 - 歌曲播放排行 (Top20)
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
return request(
|
||||
`/api/content/activity/listen/data/song/play/rank`,
|
||||
{
|
||||
type: query.type || 'month', //周 week 月 month
|
||||
endTime: query.endTime, // 不填就是本周/月的
|
||||
},
|
||||
createOption(query),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// 易盾反作弊 Token 注册端点
|
||||
// 调用后获取实时 token 并存入共享存储,供后续带 checkToken 的请求使用
|
||||
//
|
||||
// GET /register/checktoken → 返回当前 token(尚无则自动获取)
|
||||
// POST /register/checktoken → 强制刷新 token
|
||||
// GET /register/checktoken?refresh=1 → 强制刷新
|
||||
//
|
||||
const { default: axios } = require('axios')
|
||||
const { APP_CONF } = require('../util/config.json')
|
||||
|
||||
const URL = APP_CONF.dunDomain + '/v3/b?pn=YD00000558929251'
|
||||
let _token = ''
|
||||
|
||||
async function fetch() {
|
||||
const res = await axios.get(URL, { timeout: 10000 })
|
||||
const body = String(res.data)
|
||||
const m = body.match(/null\(\[(\d+),\d+,\"([^\"]+)\"\]\)/)
|
||||
if (m && m[1] === '200') return m[2]
|
||||
throw new Error('易盾返回异常: ' + body.substring(0, 100))
|
||||
}
|
||||
|
||||
// 端点处理
|
||||
module.exports = async (query) => {
|
||||
const refresh = query.refresh === '1' || query.refresh === 'true'
|
||||
let token = refresh ? null : _token
|
||||
if (!token) {
|
||||
token = await fetch()
|
||||
_token = token
|
||||
}
|
||||
return {
|
||||
status: 200,
|
||||
body: { code: 200, token, registered: !!token },
|
||||
}
|
||||
}
|
||||
|
||||
// 给 request.js 读取用
|
||||
module.exports.getToken = () => _token
|
||||
@@ -0,0 +1,11 @@
|
||||
// 一键领取所有会员成长值
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {}
|
||||
return request(
|
||||
`/api/vipnewcenter/app/level/task/reward/getall`,
|
||||
data,
|
||||
createOption(query, 'xeapi'),
|
||||
)
|
||||
}
|
||||
+34
-5
@@ -1,11 +1,40 @@
|
||||
// 黑胶乐签打卡
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {}
|
||||
return request(
|
||||
`/api/vip-center-bff/task/sign`,
|
||||
data,
|
||||
|
||||
module.exports = async (query, request) => {
|
||||
const results = {}
|
||||
|
||||
const taskSign = await request(
|
||||
'/api/vip-center-bff/task/sign',
|
||||
{},
|
||||
createOption(query, 'weapi'),
|
||||
)
|
||||
results.taskSign = taskSign.body
|
||||
|
||||
const checkinDetail = await request(
|
||||
'/api/vipnewcenter/app/level/user/checkin/history/detail',
|
||||
{
|
||||
signDayTime: Date.now(),
|
||||
type: 1,
|
||||
},
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
results.checkinDetail = checkinDetail.body
|
||||
|
||||
// 两个接口都返回 code=200 即视为打卡成功
|
||||
const signed =
|
||||
Number(results.taskSign?.code) === 200 &&
|
||||
Number(results.checkinDetail?.code) === 200
|
||||
|
||||
return {
|
||||
body: {
|
||||
code: 200,
|
||||
...results,
|
||||
signed,
|
||||
message: signed ? '黑胶乐签打卡成功' : '黑胶乐签打卡失败',
|
||||
},
|
||||
cookie: taskSign.cookie,
|
||||
status: 200,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
// 黑胶乐签打卡历史
|
||||
// 黑胶乐签打卡历史 / 状态查询
|
||||
// 支持传入 type=0(用户信息栏)或 type=1(黑胶乐签)
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
type: '0',
|
||||
type: query.type || '0',
|
||||
}
|
||||
return request(
|
||||
`/api/vipnewcenter/app/minidesk/music/sign/pc`,
|
||||
data,
|
||||
createOption(query, 'xeapi'),
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
|
||||
+11
-11
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@neteasecloudmusicapienhanced/api",
|
||||
"version": "4.36.1",
|
||||
"version": "4.37.0",
|
||||
"description": "全网最全的网易云音乐API接口 || A revival project for NeteaseCloudMusicApi Node.js Services (Half Refactor & Enhanced) || 网易云音乐 API 备份 + 增强 || 本项目自原版v4.28.0版本后开始自行维护",
|
||||
"scripts": {
|
||||
"dev": "nodemon app.js",
|
||||
@@ -75,14 +75,14 @@
|
||||
"data"
|
||||
],
|
||||
"dependencies": {
|
||||
"@neteasecloudmusicapienhanced/unblockmusic-utils": "^0.3.3",
|
||||
"axios": "^1.18.0",
|
||||
"@neteasecloudmusicapienhanced/unblockmusic-utils": "^0.3.4",
|
||||
"axios": "^1.18.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dotenv": "^17.4.2",
|
||||
"express": "^5.2.1",
|
||||
"express-fileupload": "^1.5.2",
|
||||
"gzip": "^0.1.0",
|
||||
"music-metadata": "^11.13.0",
|
||||
"music-metadata": "^11.14.0",
|
||||
"node-forge": "^1.4.0",
|
||||
"pac-proxy-agent": "^7.2.0",
|
||||
"qrcode": "^1.5.4",
|
||||
@@ -92,19 +92,19 @@
|
||||
"yargs": "^18.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.5",
|
||||
"@eslint/js": "^9.39.4",
|
||||
"@eslint/eslintrc": "^3.3.6",
|
||||
"@eslint/js": "^9.39.5",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/express-fileupload": "^1.5.1",
|
||||
"@types/mocha": "^10.0.10",
|
||||
"@types/node": "25.9.2",
|
||||
"@typescript-eslint/eslint-plugin": "^8.61.1",
|
||||
"@typescript-eslint/parser": "^8.61.1",
|
||||
"eslint": "^9.39.4",
|
||||
"@typescript-eslint/eslint-plugin": "^8.64.0",
|
||||
"@typescript-eslint/parser": "^8.64.0",
|
||||
"eslint": "^9.39.5",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-html": "^8.1.4",
|
||||
"eslint-plugin-prettier": "^5.5.6",
|
||||
"globals": "^17.6.0",
|
||||
"globals": "^17.7.0",
|
||||
"husky": "^9.1.7",
|
||||
"intelli-espower-loader": "^1.1.0",
|
||||
"lint-staged": "^16.4.0",
|
||||
@@ -112,7 +112,7 @@
|
||||
"nodemon": "^3.1.14",
|
||||
"pkg": "^5.8.1",
|
||||
"power-assert": "^1.6.1",
|
||||
"prettier": "^3.8.4",
|
||||
"prettier": "^3.9.5",
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
Generated
+194
-186
@@ -9,11 +9,11 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@neteasecloudmusicapienhanced/unblockmusic-utils':
|
||||
specifier: ^0.3.3
|
||||
version: 0.3.3
|
||||
specifier: ^0.3.4
|
||||
version: 0.3.4
|
||||
axios:
|
||||
specifier: ^1.18.0
|
||||
version: 1.18.0
|
||||
specifier: ^1.18.1
|
||||
version: 1.18.1
|
||||
crypto-js:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
@@ -30,8 +30,8 @@ importers:
|
||||
specifier: ^0.1.0
|
||||
version: 0.1.0
|
||||
music-metadata:
|
||||
specifier: ^11.13.0
|
||||
version: 11.13.0
|
||||
specifier: ^11.14.0
|
||||
version: 11.14.0
|
||||
node-forge:
|
||||
specifier: ^1.4.0
|
||||
version: 1.4.0
|
||||
@@ -55,11 +55,11 @@ importers:
|
||||
version: 18.0.0
|
||||
devDependencies:
|
||||
'@eslint/eslintrc':
|
||||
specifier: ^3.3.5
|
||||
version: 3.3.5
|
||||
specifier: ^3.3.6
|
||||
version: 3.3.6
|
||||
'@eslint/js':
|
||||
specifier: ^9.39.4
|
||||
version: 9.39.4
|
||||
specifier: ^9.39.5
|
||||
version: 9.39.5
|
||||
'@types/express':
|
||||
specifier: ^5.0.6
|
||||
version: 5.0.6
|
||||
@@ -73,26 +73,26 @@ importers:
|
||||
specifier: 25.9.2
|
||||
version: 25.9.2
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^8.61.1
|
||||
version: 8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)
|
||||
specifier: ^8.64.0
|
||||
version: 8.64.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^8.61.1
|
||||
version: 8.61.1(eslint@9.39.4)(typescript@5.9.3)
|
||||
specifier: ^8.64.0
|
||||
version: 8.64.0(eslint@9.39.5)(typescript@5.9.3)
|
||||
eslint:
|
||||
specifier: ^9.39.4
|
||||
version: 9.39.4
|
||||
specifier: ^9.39.5
|
||||
version: 9.39.5
|
||||
eslint-config-prettier:
|
||||
specifier: ^10.1.8
|
||||
version: 10.1.8(eslint@9.39.4)
|
||||
version: 10.1.8(eslint@9.39.5)
|
||||
eslint-plugin-html:
|
||||
specifier: ^8.1.4
|
||||
version: 8.1.4
|
||||
eslint-plugin-prettier:
|
||||
specifier: ^5.5.6
|
||||
version: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4))(eslint@9.39.4)(prettier@3.8.4)
|
||||
version: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.5)
|
||||
globals:
|
||||
specifier: ^17.6.0
|
||||
version: 17.6.0
|
||||
specifier: ^17.7.0
|
||||
version: 17.7.0
|
||||
husky:
|
||||
specifier: ^9.1.7
|
||||
version: 9.1.7
|
||||
@@ -115,8 +115,8 @@ importers:
|
||||
specifier: ^1.6.1
|
||||
version: 1.6.1
|
||||
prettier:
|
||||
specifier: ^3.8.4
|
||||
version: 3.8.4
|
||||
specifier: ^3.9.5
|
||||
version: 3.9.5
|
||||
typescript:
|
||||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
@@ -169,12 +169,12 @@ packages:
|
||||
resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@eslint/eslintrc@3.3.5':
|
||||
resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==}
|
||||
'@eslint/eslintrc@3.3.6':
|
||||
resolution: {integrity: sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@eslint/js@9.39.4':
|
||||
resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==}
|
||||
'@eslint/js@9.39.5':
|
||||
resolution: {integrity: sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@eslint/object-schema@2.1.7':
|
||||
@@ -222,8 +222,8 @@ packages:
|
||||
'@jridgewell/trace-mapping@0.3.31':
|
||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||
|
||||
'@neteasecloudmusicapienhanced/unblockmusic-utils@0.3.3':
|
||||
resolution: {integrity: sha512-Lm2Zxod4Qfhp3HNDmaHxzJPLiMfMNkUT2PXp0VVrDW+/dDZBfSANO+pnCHx+MkK7tDUb3wGwYp5q2w9Kw1+4OA==}
|
||||
'@neteasecloudmusicapienhanced/unblockmusic-utils@0.3.4':
|
||||
resolution: {integrity: sha512-3Lu/eYnDqf9/rHxa5G38TZxM7QVUBZpzKMWBmT6STHaMb6ztFRfrVrejIC1r7IUvtCWkoRulD+8UlllNTEsd6g==}
|
||||
hasBin: true
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
@@ -271,8 +271,8 @@ packages:
|
||||
'@types/express-fileupload@1.5.1':
|
||||
resolution: {integrity: sha512-DllImBVI1lCyjl2klky/TEwk60mbNebgXv1669h66g9TfptWSrEFq5a/raHSutaFzjSm1tmn9ypdNfu4jPSixQ==}
|
||||
|
||||
'@types/express-serve-static-core@5.1.1':
|
||||
resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==}
|
||||
'@types/express-serve-static-core@5.1.2':
|
||||
resolution: {integrity: sha512-d3KvEXBSo/lOAMc2u6fkyDHBvetBHeqD7wm/AcXfLpSOQwlmG9D/aQ0SFswVjv05p7ullQS7Mjohj6/VdbZuTg==}
|
||||
|
||||
'@types/express@5.0.6':
|
||||
resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==}
|
||||
@@ -301,63 +301,63 @@ packages:
|
||||
'@types/serve-static@2.2.0':
|
||||
resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.61.1':
|
||||
resolution: {integrity: sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==}
|
||||
'@typescript-eslint/eslint-plugin@8.64.0':
|
||||
resolution: {integrity: sha512-CGvQPBxN3wZLu6Rz2kFUpZeoCm78xUic92ck39KPePkO1NPOwjCqdQnm5Q87tpWw9vcBvW8XLrDXjH9PWYtJ3Q==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^8.61.1
|
||||
'@typescript-eslint/parser': ^8.64.0
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/parser@8.61.1':
|
||||
resolution: {integrity: sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==}
|
||||
'@typescript-eslint/parser@8.64.0':
|
||||
resolution: {integrity: sha512-KA0OshtlcCCXmbfqyZkM5pV3/WNraJf7DkJRLpyrmwPtud57H5BDX7C3k0LPSPxpprfRL+cJDGabF10mvNCoCw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/project-service@8.61.1':
|
||||
resolution: {integrity: sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==}
|
||||
'@typescript-eslint/project-service@8.64.0':
|
||||
resolution: {integrity: sha512-tk4WpOJ6IEbGrVHaNmM0YRrwAD3exZlIK3iadQNAxh4YKk6jvUQ4ecq18n+v7+meh+cJ3j+D8nbk8sRKhlwLQg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/scope-manager@8.61.1':
|
||||
resolution: {integrity: sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==}
|
||||
'@typescript-eslint/scope-manager@8.64.0':
|
||||
resolution: {integrity: sha512-CXEaFdYXjSTgKhisNkwCcJwTP8Pl+fmRrEQrri4nm3vU743bALrxzLmq7fHG/7e6a5xO0lDYeURpZmBuhHk54w==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.61.1':
|
||||
resolution: {integrity: sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==}
|
||||
'@typescript-eslint/tsconfig-utils@8.64.0':
|
||||
resolution: {integrity: sha512-2yo8rRNKuzbVWQp5kslhANqZ2uDAeROQHBRZNPu8JDsHmeFNj/XJJhX/FhNUWmkHHvoNsKa6+tHJiig87EzsQw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/type-utils@8.61.1':
|
||||
resolution: {integrity: sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==}
|
||||
'@typescript-eslint/type-utils@8.64.0':
|
||||
resolution: {integrity: sha512-XWG4Fmmv/6SvyS9nH8jWrKs6terwJvE8cyRt1CzYYqzp9OrPhCT4cMc/f7C6RZCwG+qMmiffJS1/qJP8G1URtg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/types@8.61.1':
|
||||
resolution: {integrity: sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==}
|
||||
'@typescript-eslint/types@8.64.0':
|
||||
resolution: {integrity: sha512-qjhfuTfLXjA4IOzXvz0rTjT01BqEiIgPoUeMwiEjnaHKJMTNo8rH5pYW1a2L/0Dnux2fPC85AeyJoWaGa8WxTA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.61.1':
|
||||
resolution: {integrity: sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==}
|
||||
'@typescript-eslint/typescript-estree@8.64.0':
|
||||
resolution: {integrity: sha512-Pztpsn1aCE1oWDvDEfUk31nngvvF7vUB5SwHFEaZIFpvw7WJtqUHHL4plBZDA9HfWJJjL13BdG0YrJInTUvoVA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/utils@8.61.1':
|
||||
resolution: {integrity: sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==}
|
||||
'@typescript-eslint/utils@8.64.0':
|
||||
resolution: {integrity: sha512-aJUGVB3+U0htrrCjoA8qukw8cm8fNCGAxK/tVoS70k8aeb7DETKeFozRiVFIwEeN9WJLsjaP3ph8I60tY2XZoQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.61.1':
|
||||
resolution: {integrity: sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==}
|
||||
'@typescript-eslint/visitor-keys@8.64.0':
|
||||
resolution: {integrity: sha512-mrtuL8Nsn6gi2H4mo5KMTp823M+3Q19Ew/i+Zlikq20tIMm99C3Ez0dCmkWWnxut20esQvTg8aUSEhMcAOXhEw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@unblockneteasemusic/server@0.28.0':
|
||||
@@ -485,8 +485,8 @@ packages:
|
||||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
axios@1.18.0:
|
||||
resolution: {integrity: sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==}
|
||||
axios@1.18.1:
|
||||
resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==}
|
||||
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
@@ -509,22 +509,22 @@ packages:
|
||||
bl@4.1.0:
|
||||
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
|
||||
|
||||
body-parser@1.20.5:
|
||||
resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==}
|
||||
body-parser@1.20.6:
|
||||
resolution: {integrity: sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==}
|
||||
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
|
||||
|
||||
body-parser@2.3.0:
|
||||
resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
brace-expansion@1.1.15:
|
||||
resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==}
|
||||
brace-expansion@1.1.16:
|
||||
resolution: {integrity: sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==}
|
||||
|
||||
brace-expansion@2.1.1:
|
||||
resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==}
|
||||
brace-expansion@2.1.2:
|
||||
resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==}
|
||||
|
||||
brace-expansion@5.0.6:
|
||||
resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==}
|
||||
brace-expansion@5.0.7:
|
||||
resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
|
||||
braces@3.0.3:
|
||||
@@ -888,8 +888,8 @@ packages:
|
||||
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-to-primitive@1.3.1:
|
||||
resolution: {integrity: sha512-CxN9N56HYfd2m/acc/NOFrZQsN9kU4eh+2kk6A707Kz1krH8tKmfrs5RnftB8WNX80T0NS7vSQsDOlg23diR2g==}
|
||||
es-to-primitive@1.3.4:
|
||||
resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es5-ext@0.10.64:
|
||||
@@ -985,8 +985,8 @@ packages:
|
||||
resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
|
||||
eslint@9.39.4:
|
||||
resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==}
|
||||
eslint@9.39.5:
|
||||
resolution: {integrity: sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -1262,8 +1262,8 @@ packages:
|
||||
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
globals@17.6.0:
|
||||
resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==}
|
||||
globals@17.7.0:
|
||||
resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
globalthis@1.0.4:
|
||||
@@ -1354,8 +1354,8 @@ packages:
|
||||
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
iconv-lite@0.7.2:
|
||||
resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
|
||||
iconv-lite@0.7.3:
|
||||
resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
ieee754@1.2.1:
|
||||
@@ -1368,8 +1368,8 @@ packages:
|
||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
ignore@7.0.5:
|
||||
resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
|
||||
ignore@7.0.6:
|
||||
resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
@@ -1565,8 +1565,8 @@ packages:
|
||||
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
js-yaml@4.2.0:
|
||||
resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==}
|
||||
js-yaml@4.3.0:
|
||||
resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==}
|
||||
hasBin: true
|
||||
|
||||
jsesc@2.5.2:
|
||||
@@ -1741,8 +1741,8 @@ packages:
|
||||
multistream@4.1.0:
|
||||
resolution: {integrity: sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==}
|
||||
|
||||
music-metadata@11.13.0:
|
||||
resolution: {integrity: sha512-uXRaov9dfjSpQufXIU7sMxVZnh+FilCQv2mXn+K5EJ/decP3dTWrgvPYa5r6MtRbieNSCE708Da4J0u1UGfQIw==}
|
||||
music-metadata@11.14.0:
|
||||
resolution: {integrity: sha512-RyOSq98kuVfXB1emJ+NjBF0av8Ph3oBuqNy+Z5sFFfLhjYrkBQEB53V8u+U0RNTVwNo20WoPUwNkfKwZfrOqmQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
napi-build-utils@1.0.2:
|
||||
@@ -1766,8 +1766,8 @@ packages:
|
||||
next-tick@1.1.0:
|
||||
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
|
||||
|
||||
node-abi@3.92.0:
|
||||
resolution: {integrity: sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==}
|
||||
node-abi@3.94.0:
|
||||
resolution: {integrity: sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
node-fetch@2.7.0:
|
||||
@@ -1916,8 +1916,8 @@ packages:
|
||||
resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
picomatch@4.0.4:
|
||||
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
|
||||
picomatch@4.0.5:
|
||||
resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
pino-abstract-transport@0.5.0:
|
||||
@@ -2006,8 +2006,8 @@ packages:
|
||||
resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
prettier@3.8.4:
|
||||
resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==}
|
||||
prettier@3.9.5:
|
||||
resolution: {integrity: sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
@@ -2044,8 +2044,8 @@ packages:
|
||||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
|
||||
qs@6.15.2:
|
||||
resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==}
|
||||
qs@6.15.3:
|
||||
resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
queue-microtask@1.2.3:
|
||||
@@ -2061,6 +2061,10 @@ packages:
|
||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
range-parser@1.3.0:
|
||||
resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
raw-body@2.5.3:
|
||||
resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -2324,8 +2328,8 @@ packages:
|
||||
resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
string-width@8.2.1:
|
||||
resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==}
|
||||
string-width@8.2.2:
|
||||
resolution: {integrity: sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
string.prototype.trim@1.2.11:
|
||||
@@ -2389,8 +2393,8 @@ packages:
|
||||
resolution: {integrity: sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
|
||||
tar-fs@2.1.4:
|
||||
resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==}
|
||||
tar-fs@2.1.5:
|
||||
resolution: {integrity: sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==}
|
||||
|
||||
tar-stream@2.2.0:
|
||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||
@@ -2683,9 +2687,9 @@ snapshots:
|
||||
|
||||
'@borewit/text-codec@0.2.2': {}
|
||||
|
||||
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.4)':
|
||||
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.5)':
|
||||
dependencies:
|
||||
eslint: 9.39.4
|
||||
eslint: 9.39.5
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
'@eslint-community/regexpp@4.12.2': {}
|
||||
@@ -2706,7 +2710,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/json-schema': 7.0.15
|
||||
|
||||
'@eslint/eslintrc@3.3.5':
|
||||
'@eslint/eslintrc@3.3.6':
|
||||
dependencies:
|
||||
ajv: 6.15.0
|
||||
debug: 4.4.3
|
||||
@@ -2714,13 +2718,13 @@ snapshots:
|
||||
globals: 14.0.0
|
||||
ignore: 5.3.2
|
||||
import-fresh: 3.3.1
|
||||
js-yaml: 4.2.0
|
||||
js-yaml: 4.3.0
|
||||
minimatch: 3.1.5
|
||||
strip-json-comments: 3.1.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@eslint/js@9.39.4': {}
|
||||
'@eslint/js@9.39.5': {}
|
||||
|
||||
'@eslint/object-schema@2.1.7': {}
|
||||
|
||||
@@ -2768,10 +2772,10 @@ snapshots:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
'@neteasecloudmusicapienhanced/unblockmusic-utils@0.3.3':
|
||||
'@neteasecloudmusicapienhanced/unblockmusic-utils@0.3.4':
|
||||
dependencies:
|
||||
'@unblockneteasemusic/server': 0.28.0
|
||||
axios: 1.18.0
|
||||
axios: 1.18.1
|
||||
dotenv: 17.4.2
|
||||
express: 4.22.2
|
||||
https: 1.0.0
|
||||
@@ -2827,7 +2831,7 @@ snapshots:
|
||||
'@types/busboy': 1.5.4
|
||||
'@types/express': 5.0.6
|
||||
|
||||
'@types/express-serve-static-core@5.1.1':
|
||||
'@types/express-serve-static-core@5.1.2':
|
||||
dependencies:
|
||||
'@types/node': 25.9.2
|
||||
'@types/qs': 6.15.1
|
||||
@@ -2837,7 +2841,7 @@ snapshots:
|
||||
'@types/express@5.0.6':
|
||||
dependencies:
|
||||
'@types/body-parser': 1.19.6
|
||||
'@types/express-serve-static-core': 5.1.1
|
||||
'@types/express-serve-static-core': 5.1.2
|
||||
'@types/serve-static': 2.2.0
|
||||
|
||||
'@types/http-errors@2.0.5': {}
|
||||
@@ -2863,72 +2867,72 @@ snapshots:
|
||||
'@types/http-errors': 2.0.5
|
||||
'@types/node': 25.9.2
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)':
|
||||
'@typescript-eslint/eslint-plugin@8.64.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@typescript-eslint/parser': 8.61.1(eslint@9.39.4)(typescript@5.9.3)
|
||||
'@typescript-eslint/scope-manager': 8.61.1
|
||||
'@typescript-eslint/type-utils': 8.61.1(eslint@9.39.4)(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.61.1(eslint@9.39.4)(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.61.1
|
||||
eslint: 9.39.4
|
||||
ignore: 7.0.5
|
||||
'@typescript-eslint/parser': 8.64.0(eslint@9.39.5)(typescript@5.9.3)
|
||||
'@typescript-eslint/scope-manager': 8.64.0
|
||||
'@typescript-eslint/type-utils': 8.64.0(eslint@9.39.5)(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.64.0(eslint@9.39.5)(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.64.0
|
||||
eslint: 9.39.5
|
||||
ignore: 7.0.6
|
||||
natural-compare: 1.4.0
|
||||
ts-api-utils: 2.5.0(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.61.1(eslint@9.39.4)(typescript@5.9.3)':
|
||||
'@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.61.1
|
||||
'@typescript-eslint/types': 8.61.1
|
||||
'@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.61.1
|
||||
'@typescript-eslint/scope-manager': 8.64.0
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
'@typescript-eslint/typescript-estree': 8.64.0(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.64.0
|
||||
debug: 4.4.3
|
||||
eslint: 9.39.4
|
||||
eslint: 9.39.5
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/project-service@8.61.1(typescript@5.9.3)':
|
||||
'@typescript-eslint/project-service@8.64.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/tsconfig-utils': 8.61.1(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.61.1
|
||||
'@typescript-eslint/tsconfig-utils': 8.64.0(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
debug: 4.4.3
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/scope-manager@8.61.1':
|
||||
'@typescript-eslint/scope-manager@8.64.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.61.1
|
||||
'@typescript-eslint/visitor-keys': 8.61.1
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
'@typescript-eslint/visitor-keys': 8.64.0
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.61.1(typescript@5.9.3)':
|
||||
'@typescript-eslint/tsconfig-utils@8.64.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
typescript: 5.9.3
|
||||
|
||||
'@typescript-eslint/type-utils@8.61.1(eslint@9.39.4)(typescript@5.9.3)':
|
||||
'@typescript-eslint/type-utils@8.64.0(eslint@9.39.5)(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.61.1
|
||||
'@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.61.1(eslint@9.39.4)(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
'@typescript-eslint/typescript-estree': 8.64.0(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.64.0(eslint@9.39.5)(typescript@5.9.3)
|
||||
debug: 4.4.3
|
||||
eslint: 9.39.4
|
||||
eslint: 9.39.5
|
||||
ts-api-utils: 2.5.0(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/types@8.61.1': {}
|
||||
'@typescript-eslint/types@8.64.0': {}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.61.1(typescript@5.9.3)':
|
||||
'@typescript-eslint/typescript-estree@8.64.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/project-service': 8.61.1(typescript@5.9.3)
|
||||
'@typescript-eslint/tsconfig-utils': 8.61.1(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.61.1
|
||||
'@typescript-eslint/visitor-keys': 8.61.1
|
||||
'@typescript-eslint/project-service': 8.64.0(typescript@5.9.3)
|
||||
'@typescript-eslint/tsconfig-utils': 8.64.0(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
'@typescript-eslint/visitor-keys': 8.64.0
|
||||
debug: 4.4.3
|
||||
minimatch: 10.2.5
|
||||
semver: 7.8.5
|
||||
@@ -2938,20 +2942,20 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.61.1(eslint@9.39.4)(typescript@5.9.3)':
|
||||
'@typescript-eslint/utils@8.64.0(eslint@9.39.5)(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4)
|
||||
'@typescript-eslint/scope-manager': 8.61.1
|
||||
'@typescript-eslint/types': 8.61.1
|
||||
'@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3)
|
||||
eslint: 9.39.4
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5)
|
||||
'@typescript-eslint/scope-manager': 8.64.0
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
'@typescript-eslint/typescript-estree': 8.64.0(typescript@5.9.3)
|
||||
eslint: 9.39.5
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.61.1':
|
||||
'@typescript-eslint/visitor-keys@8.64.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.61.1
|
||||
'@typescript-eslint/types': 8.64.0
|
||||
eslint-visitor-keys: 5.0.1
|
||||
|
||||
'@unblockneteasemusic/server@0.28.0':
|
||||
@@ -3068,7 +3072,7 @@ snapshots:
|
||||
dependencies:
|
||||
possible-typed-array-names: 1.1.0
|
||||
|
||||
axios@1.18.0:
|
||||
axios@1.18.1:
|
||||
dependencies:
|
||||
follow-redirects: 1.16.0
|
||||
form-data: 4.0.6
|
||||
@@ -3094,7 +3098,7 @@ snapshots:
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
|
||||
body-parser@1.20.5:
|
||||
body-parser@1.20.6:
|
||||
dependencies:
|
||||
bytes: 3.1.2
|
||||
content-type: 1.0.5
|
||||
@@ -3104,7 +3108,7 @@ snapshots:
|
||||
http-errors: 2.0.1
|
||||
iconv-lite: 0.4.24
|
||||
on-finished: 2.4.1
|
||||
qs: 6.15.2
|
||||
qs: 6.15.3
|
||||
raw-body: 2.5.3
|
||||
type-is: 1.6.18
|
||||
unpipe: 1.0.0
|
||||
@@ -3117,24 +3121,24 @@ snapshots:
|
||||
content-type: 2.0.0
|
||||
debug: 4.4.3
|
||||
http-errors: 2.0.1
|
||||
iconv-lite: 0.7.2
|
||||
iconv-lite: 0.7.3
|
||||
on-finished: 2.4.1
|
||||
qs: 6.15.2
|
||||
qs: 6.15.3
|
||||
raw-body: 3.0.2
|
||||
type-is: 2.1.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
brace-expansion@1.1.15:
|
||||
brace-expansion@1.1.16:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
concat-map: 0.0.1
|
||||
|
||||
brace-expansion@2.1.1:
|
||||
brace-expansion@2.1.2:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
|
||||
brace-expansion@5.0.6:
|
||||
brace-expansion@5.0.7:
|
||||
dependencies:
|
||||
balanced-match: 4.0.4
|
||||
|
||||
@@ -3225,7 +3229,7 @@ snapshots:
|
||||
cli-truncate@5.2.0:
|
||||
dependencies:
|
||||
slice-ansi: 8.0.0
|
||||
string-width: 8.2.1
|
||||
string-width: 8.2.2
|
||||
|
||||
cliui@6.0.0:
|
||||
dependencies:
|
||||
@@ -3497,7 +3501,7 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.1.2
|
||||
es-set-tostringtag: 2.1.0
|
||||
es-to-primitive: 1.3.1
|
||||
es-to-primitive: 1.3.4
|
||||
function.prototype.name: 1.2.0
|
||||
get-intrinsic: 1.3.0
|
||||
get-proto: 1.0.1
|
||||
@@ -3555,9 +3559,10 @@ snapshots:
|
||||
has-tostringtag: 1.0.2
|
||||
hasown: 2.0.4
|
||||
|
||||
es-to-primitive@1.3.1:
|
||||
es-to-primitive@1.3.4:
|
||||
dependencies:
|
||||
es-abstract-get: 1.0.0
|
||||
es-define-property: 1.0.1
|
||||
es-errors: 1.3.0
|
||||
is-callable: 1.2.7
|
||||
is-date-object: 1.1.0
|
||||
@@ -3643,22 +3648,22 @@ snapshots:
|
||||
esrecurse: 4.3.0
|
||||
estraverse: 4.3.0
|
||||
|
||||
eslint-config-prettier@10.1.8(eslint@9.39.4):
|
||||
eslint-config-prettier@10.1.8(eslint@9.39.5):
|
||||
dependencies:
|
||||
eslint: 9.39.4
|
||||
eslint: 9.39.5
|
||||
|
||||
eslint-plugin-html@8.1.4:
|
||||
dependencies:
|
||||
htmlparser2: 10.1.0
|
||||
|
||||
eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4))(eslint@9.39.4)(prettier@3.8.4):
|
||||
eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.5):
|
||||
dependencies:
|
||||
eslint: 9.39.4
|
||||
prettier: 3.8.4
|
||||
eslint: 9.39.5
|
||||
prettier: 3.9.5
|
||||
prettier-linter-helpers: 1.0.1
|
||||
synckit: 0.11.13
|
||||
optionalDependencies:
|
||||
eslint-config-prettier: 10.1.8(eslint@9.39.4)
|
||||
eslint-config-prettier: 10.1.8(eslint@9.39.5)
|
||||
|
||||
eslint-scope@8.4.0:
|
||||
dependencies:
|
||||
@@ -3671,15 +3676,15 @@ snapshots:
|
||||
|
||||
eslint-visitor-keys@5.0.1: {}
|
||||
|
||||
eslint@9.39.4:
|
||||
eslint@9.39.5:
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4)
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5)
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@eslint/config-array': 0.21.2
|
||||
'@eslint/config-helpers': 0.4.2
|
||||
'@eslint/core': 0.17.0
|
||||
'@eslint/eslintrc': 3.3.5
|
||||
'@eslint/js': 9.39.4
|
||||
'@eslint/eslintrc': 3.3.6
|
||||
'@eslint/js': 9.39.5
|
||||
'@eslint/plugin-kit': 0.4.1
|
||||
'@humanfs/node': 0.16.8
|
||||
'@humanwhocodes/module-importer': 1.0.1
|
||||
@@ -3805,7 +3810,7 @@ snapshots:
|
||||
dependencies:
|
||||
accepts: 1.3.8
|
||||
array-flatten: 1.1.1
|
||||
body-parser: 1.20.5
|
||||
body-parser: 1.20.6
|
||||
content-disposition: 0.5.4
|
||||
content-type: 1.0.5
|
||||
cookie: 0.7.2
|
||||
@@ -3824,7 +3829,7 @@ snapshots:
|
||||
parseurl: 1.3.3
|
||||
path-to-regexp: 0.1.13
|
||||
proxy-addr: 2.0.7
|
||||
qs: 6.15.2
|
||||
qs: 6.15.3
|
||||
range-parser: 1.2.1
|
||||
safe-buffer: 5.2.1
|
||||
send: 0.19.2
|
||||
@@ -3859,8 +3864,8 @@ snapshots:
|
||||
once: 1.4.0
|
||||
parseurl: 1.3.3
|
||||
proxy-addr: 2.0.7
|
||||
qs: 6.15.2
|
||||
range-parser: 1.2.1
|
||||
qs: 6.15.3
|
||||
range-parser: 1.3.0
|
||||
router: 2.2.0
|
||||
send: 1.2.1
|
||||
serve-static: 2.2.1
|
||||
@@ -3898,9 +3903,9 @@ snapshots:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
|
||||
fdir@6.5.0(picomatch@4.0.4):
|
||||
fdir@6.5.0(picomatch@4.0.5):
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.4
|
||||
picomatch: 4.0.5
|
||||
|
||||
file-entry-cache@8.0.0:
|
||||
dependencies:
|
||||
@@ -4080,7 +4085,7 @@ snapshots:
|
||||
|
||||
globals@14.0.0: {}
|
||||
|
||||
globals@17.6.0: {}
|
||||
globals@17.7.0: {}
|
||||
|
||||
globalthis@1.0.4:
|
||||
dependencies:
|
||||
@@ -4174,7 +4179,7 @@ snapshots:
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
|
||||
iconv-lite@0.7.2:
|
||||
iconv-lite@0.7.3:
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
|
||||
@@ -4184,7 +4189,7 @@ snapshots:
|
||||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
ignore@7.0.5: {}
|
||||
ignore@7.0.6: {}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
dependencies:
|
||||
@@ -4373,7 +4378,7 @@ snapshots:
|
||||
|
||||
joycon@3.1.1: {}
|
||||
|
||||
js-yaml@4.2.0:
|
||||
js-yaml@4.3.0:
|
||||
dependencies:
|
||||
argparse: 2.0.1
|
||||
|
||||
@@ -4411,7 +4416,7 @@ snapshots:
|
||||
dependencies:
|
||||
commander: 14.0.3
|
||||
listr2: 9.0.5
|
||||
picomatch: 4.0.4
|
||||
picomatch: 4.0.5
|
||||
string-argv: 0.3.2
|
||||
tinyexec: 1.2.4
|
||||
yaml: 2.9.0
|
||||
@@ -4495,15 +4500,15 @@ snapshots:
|
||||
|
||||
minimatch@10.2.5:
|
||||
dependencies:
|
||||
brace-expansion: 5.0.6
|
||||
brace-expansion: 5.0.7
|
||||
|
||||
minimatch@3.1.5:
|
||||
dependencies:
|
||||
brace-expansion: 1.1.15
|
||||
brace-expansion: 1.1.16
|
||||
|
||||
minimatch@9.0.9:
|
||||
dependencies:
|
||||
brace-expansion: 2.1.1
|
||||
brace-expansion: 2.1.2
|
||||
|
||||
minimist@1.2.8: {}
|
||||
|
||||
@@ -4522,7 +4527,7 @@ snapshots:
|
||||
glob: 10.5.0
|
||||
he: 1.2.0
|
||||
is-path-inside: 3.0.3
|
||||
js-yaml: 4.2.0
|
||||
js-yaml: 4.3.0
|
||||
log-symbols: 4.1.0
|
||||
minimatch: 9.0.9
|
||||
ms: 2.1.3
|
||||
@@ -4550,7 +4555,7 @@ snapshots:
|
||||
once: 1.4.0
|
||||
readable-stream: 3.6.2
|
||||
|
||||
music-metadata@11.13.0:
|
||||
music-metadata@11.14.0:
|
||||
dependencies:
|
||||
'@borewit/text-codec': 0.2.2
|
||||
'@tokenizer/token': 0.3.0
|
||||
@@ -4577,7 +4582,7 @@ snapshots:
|
||||
|
||||
next-tick@1.1.0: {}
|
||||
|
||||
node-abi@3.92.0:
|
||||
node-abi@3.94.0:
|
||||
dependencies:
|
||||
semver: 7.8.5
|
||||
|
||||
@@ -4732,7 +4737,7 @@ snapshots:
|
||||
|
||||
picomatch@2.3.2: {}
|
||||
|
||||
picomatch@4.0.4: {}
|
||||
picomatch@4.0.5: {}
|
||||
|
||||
pino-abstract-transport@0.5.0:
|
||||
dependencies:
|
||||
@@ -4775,7 +4780,7 @@ snapshots:
|
||||
node-fetch: 2.7.0
|
||||
progress: 2.0.3
|
||||
semver: 7.8.5
|
||||
tar-fs: 2.1.4
|
||||
tar-fs: 2.1.5
|
||||
yargs: 16.2.2
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
@@ -4879,11 +4884,11 @@ snapshots:
|
||||
minimist: 1.2.8
|
||||
mkdirp-classic: 0.5.3
|
||||
napi-build-utils: 1.0.2
|
||||
node-abi: 3.92.0
|
||||
node-abi: 3.94.0
|
||||
pump: 3.0.4
|
||||
rc: 1.2.8
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.4
|
||||
tar-fs: 2.1.5
|
||||
tunnel-agent: 0.6.0
|
||||
|
||||
prelude-ls@1.1.2: {}
|
||||
@@ -4894,7 +4899,7 @@ snapshots:
|
||||
dependencies:
|
||||
fast-diff: 1.3.0
|
||||
|
||||
prettier@3.8.4: {}
|
||||
prettier@3.9.5: {}
|
||||
|
||||
process-nextick-args@2.0.1: {}
|
||||
|
||||
@@ -4924,8 +4929,9 @@ snapshots:
|
||||
pngjs: 5.0.0
|
||||
yargs: 15.4.1
|
||||
|
||||
qs@6.15.2:
|
||||
qs@6.15.3:
|
||||
dependencies:
|
||||
es-define-property: 1.0.1
|
||||
side-channel: 1.1.1
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
@@ -4938,6 +4944,8 @@ snapshots:
|
||||
|
||||
range-parser@1.2.1: {}
|
||||
|
||||
range-parser@1.3.0: {}
|
||||
|
||||
raw-body@2.5.3:
|
||||
dependencies:
|
||||
bytes: 3.1.2
|
||||
@@ -4949,7 +4957,7 @@ snapshots:
|
||||
dependencies:
|
||||
bytes: 3.1.2
|
||||
http-errors: 2.0.1
|
||||
iconv-lite: 0.7.2
|
||||
iconv-lite: 0.7.3
|
||||
unpipe: 1.0.0
|
||||
|
||||
rc@1.2.8:
|
||||
@@ -5099,7 +5107,7 @@ snapshots:
|
||||
mime-types: 3.0.2
|
||||
ms: 2.1.3
|
||||
on-finished: 2.4.1
|
||||
range-parser: 1.2.1
|
||||
range-parser: 1.3.0
|
||||
statuses: 2.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5286,7 +5294,7 @@ snapshots:
|
||||
get-east-asian-width: 1.6.0
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
string-width@8.2.1:
|
||||
string-width@8.2.2:
|
||||
dependencies:
|
||||
get-east-asian-width: 1.6.0
|
||||
strip-ansi: 7.2.0
|
||||
@@ -5363,7 +5371,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@pkgr/core': 0.3.6
|
||||
|
||||
tar-fs@2.1.4:
|
||||
tar-fs@2.1.5:
|
||||
dependencies:
|
||||
chownr: 1.1.4
|
||||
mkdirp-classic: 0.5.3
|
||||
@@ -5382,8 +5390,8 @@ snapshots:
|
||||
|
||||
tinyglobby@0.2.17:
|
||||
dependencies:
|
||||
fdir: 6.5.0(picomatch@4.0.4)
|
||||
picomatch: 4.0.4
|
||||
fdir: 6.5.0(picomatch@4.0.5)
|
||||
picomatch: 4.0.5
|
||||
|
||||
to-fast-properties@2.0.0: {}
|
||||
|
||||
|
||||
+494
-44
@@ -115,6 +115,182 @@
|
||||
textarea:focus {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
/* ===== 自定义选项区域 ===== */
|
||||
.section-container {
|
||||
margin-top: 20px;
|
||||
padding: 16px 20px;
|
||||
background: #fafafa;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.section-container + .section-container {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #555;
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.section-title .count-badge {
|
||||
font-size: 11px;
|
||||
background: #ddd;
|
||||
color: #666;
|
||||
padding: 1px 8px;
|
||||
border-radius: 10px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.dynamic-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dynamic-row .key-input {
|
||||
flex: 0 0 200px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.dynamic-row .value-input {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.dynamic-row .key-input:focus,
|
||||
.dynamic-row .value-input:focus {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
background: #fff;
|
||||
color: #999;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.remove-btn:hover {
|
||||
background: #fee;
|
||||
color: #e33;
|
||||
border-color: #fcc;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
border: 1px dashed #ccc;
|
||||
padding: 6px 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.add-btn:hover {
|
||||
border-color: #999;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
/* ===== 参数编辑区 Tab ===== */
|
||||
.param-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.param-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.param-header-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.param-tabs {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
background: #f0f0f0;
|
||||
border-radius: 6px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
padding: 4px 14px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.param-panel {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.param-panel textarea {
|
||||
flex: 1;
|
||||
padding: 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
resize: vertical;
|
||||
min-height: 350px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.param-panel textarea:focus {
|
||||
border-color: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -125,6 +301,16 @@
|
||||
<label for="uri">URI</label>
|
||||
<input type="text" id="uri" name="uri" value="/api/song/lyric/v1">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="method">请求方法</label>
|
||||
<select id="method" name="method">
|
||||
<option value="POST" selected>POST</option>
|
||||
<option value="GET">GET</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
<option value="PATCH">PATCH</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="crypto">加密方式</label>
|
||||
<select id="crypto" name="crypto">
|
||||
@@ -136,19 +322,41 @@
|
||||
<option value="" selected>(默认)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="timeout">超时(ms)</label>
|
||||
<input type="number" id="timeout" name="timeout" value="30000" min="0" step="1000" placeholder="0 表示无超时">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label></label>
|
||||
<button type="submit">发送请求</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- ===== 自定义请求头 ===== -->
|
||||
<div class="section-container" id="headersSection">
|
||||
<div class="section-title">
|
||||
请求头 (Headers)
|
||||
<span class="count-badge" id="headerCount">4</span>
|
||||
</div>
|
||||
<div id="headersList"></div>
|
||||
<button class="add-btn" onclick="addHeaderRow('', '')">+ 添加请求头</button>
|
||||
</div>
|
||||
|
||||
<div class="data-result">
|
||||
<div>
|
||||
<label for="result">响应结果</label>
|
||||
<textarea id="result" name="result" readonly></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label for="data">请求数据</label>
|
||||
<textarea id="data" name="data">
|
||||
<div class="param-container">
|
||||
<div class="param-header">
|
||||
<span class="param-header-title">请求参数</span>
|
||||
<div class="param-tabs">
|
||||
<button class="tab-btn active" data-mode="json" onclick="switchParamTab('json')">JSON</button>
|
||||
<button class="tab-btn" data-mode="kv" onclick="switchParamTab('kv')">键值对</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="param-panel" id="jsonPanel">
|
||||
<textarea id="data" name="data">
|
||||
{
|
||||
"cp": false,
|
||||
"id": "2058263032",
|
||||
@@ -160,64 +368,306 @@
|
||||
"ytv": 0,
|
||||
"yv": 0
|
||||
}</textarea>
|
||||
</div>
|
||||
<div class="param-panel" id="kvPanel" style="display:none">
|
||||
<div id="kvList"></div>
|
||||
<button class="add-btn" onclick="addKvRow('', '')">+ 添加参数</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://fastly.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||
<script>
|
||||
async function sendRequest() {
|
||||
document.getElementById('result').value = ""
|
||||
// ===== 动态行管理 =====
|
||||
function escapeHtml(str) {
|
||||
if (!str) return '';
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
const uri = document.getElementById('uri').value;
|
||||
const crypto = document.getElementById('crypto').value;
|
||||
const data = document.getElementById('data').value;
|
||||
function addHeaderRow(key, value) {
|
||||
const list = document.getElementById('headersList');
|
||||
const row = document.createElement('div');
|
||||
row.className = 'dynamic-row';
|
||||
row.innerHTML =
|
||||
'<input type="text" class="key-input" placeholder="Header 名称" value="' +
|
||||
escapeHtml(key) +
|
||||
'">' +
|
||||
'<input type="text" class="value-input" placeholder="值" value="' +
|
||||
escapeHtml(value) +
|
||||
'">' +
|
||||
'<button class="remove-btn" onclick="removeRow(this)" title="删除">✕</button>';
|
||||
list.appendChild(row);
|
||||
updateCount();
|
||||
}
|
||||
|
||||
function addKvRow(key, value) {
|
||||
const list = document.getElementById('kvList');
|
||||
const row = document.createElement('div');
|
||||
row.className = 'dynamic-row';
|
||||
row.innerHTML =
|
||||
'<input type="text" class="key-input" placeholder="参数名" value="' +
|
||||
escapeHtml(key) +
|
||||
'">' +
|
||||
'<input type="text" class="value-input" placeholder="值" value="' +
|
||||
escapeHtml(value) +
|
||||
'">' +
|
||||
'<button class="remove-btn" onclick="removeRow(this)" title="删除">✕</button>';
|
||||
list.appendChild(row);
|
||||
}
|
||||
|
||||
function removeRow(btn) {
|
||||
btn.parentElement.remove();
|
||||
}
|
||||
|
||||
function collectHeaders() {
|
||||
const headers = {};
|
||||
document.querySelectorAll('#headersList .dynamic-row').forEach(function (row) {
|
||||
var key = row.querySelector('.key-input').value.trim();
|
||||
var value = row.querySelector('.value-input').value;
|
||||
if (key) headers[key] = value;
|
||||
});
|
||||
return headers;
|
||||
}
|
||||
|
||||
function collectKvData() {
|
||||
var obj = {};
|
||||
document.querySelectorAll('#kvList .dynamic-row').forEach(function (row) {
|
||||
var key = row.querySelector('.key-input').value.trim();
|
||||
var val = row.querySelector('.value-input').value;
|
||||
if (!key) return;
|
||||
// 自动类型转换
|
||||
if (val === 'true') obj[key] = true;
|
||||
else if (val === 'false') obj[key] = false;
|
||||
else if (val === 'null') obj[key] = null;
|
||||
else if (/^-?\d+(\.\d+)?$/.test(val) && !isNaN(Number(val))) obj[key] = Number(val);
|
||||
else obj[key] = val;
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
// ===== Tab 切换 =====
|
||||
function syncJsonToKv() {
|
||||
try {
|
||||
const res = await axios({
|
||||
url: `/api?timestamp=${Date.now()}`,
|
||||
method: 'post',
|
||||
data: {
|
||||
uri: uri,
|
||||
data: JSON.parse(data),
|
||||
crypto: crypto,
|
||||
},
|
||||
var data = JSON.parse(document.getElementById('data').value);
|
||||
var list = document.getElementById('kvList');
|
||||
list.innerHTML = '';
|
||||
Object.keys(data).forEach(function (k) {
|
||||
addKvRow(k, String(data[k]));
|
||||
});
|
||||
|
||||
document.getElementById('result').value = JSON.stringify(res.data, null, 2);
|
||||
} catch (error) {
|
||||
document.getElementById('result').value = 'Request failed: ' + error.message;
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
(function fillFromQuery() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (!params.toString()) return;
|
||||
const uri = params.get('uri');
|
||||
const crypto = params.get('crypto');
|
||||
const dataParam = params.get('data');
|
||||
if (uri) {
|
||||
document.getElementById('uri').value = uri;
|
||||
function syncKvToJson() {
|
||||
var obj = collectKvData();
|
||||
document.getElementById('data').value = JSON.stringify(obj, null, 2);
|
||||
}
|
||||
|
||||
function switchParamTab(mode) {
|
||||
var jsonPanel = document.getElementById('jsonPanel');
|
||||
var kvPanel = document.getElementById('kvPanel');
|
||||
|
||||
if (mode === 'kv') {
|
||||
if (!syncJsonToKv()) {
|
||||
alert('JSON 格式有误,无法切换到键值对模式,请先修正 JSON');
|
||||
return;
|
||||
}
|
||||
jsonPanel.style.display = 'none';
|
||||
kvPanel.style.display = 'block';
|
||||
} else {
|
||||
syncKvToJson();
|
||||
kvPanel.style.display = 'none';
|
||||
jsonPanel.style.display = 'block';
|
||||
}
|
||||
if (crypto) {
|
||||
const cryptoSelect = document.getElementById('crypto');
|
||||
if ([...cryptoSelect.options].some((opt) => opt.value === crypto)) {
|
||||
cryptoSelect.value = crypto;
|
||||
}
|
||||
|
||||
document.querySelectorAll('.tab-btn').forEach(function (btn) {
|
||||
btn.classList.toggle('active', btn.dataset.mode === mode);
|
||||
});
|
||||
}
|
||||
|
||||
// ===== 默认请求头(直接套用后端预设值)=====
|
||||
var defaultHeaders = [
|
||||
{ key: 'Cookie', value: '' },
|
||||
{
|
||||
key: 'User-Agent',
|
||||
value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0',
|
||||
},
|
||||
{ key: 'Referer', value: 'https://music.163.com' },
|
||||
{ key: 'Content-Type', value: 'application/json' },
|
||||
];
|
||||
|
||||
// ===== 发送请求 =====
|
||||
async function sendRequest() {
|
||||
document.getElementById('result').value = '';
|
||||
|
||||
var uri = document.getElementById('uri').value;
|
||||
var method = document.getElementById('method').value;
|
||||
var crypto = document.getElementById('crypto').value;
|
||||
var timeout = parseInt(document.getElementById('timeout').value, 10) || 0;
|
||||
var headers = collectHeaders();
|
||||
|
||||
// 根据当前激活的 tab 读取数据
|
||||
var parsedData;
|
||||
var activeTab = document.querySelector('.tab-btn.active');
|
||||
if (activeTab && activeTab.dataset.mode === 'kv') {
|
||||
parsedData = collectKvData();
|
||||
} else {
|
||||
var rawData = document.getElementById('data').value;
|
||||
try {
|
||||
parsedData = rawData.trim() ? JSON.parse(rawData) : {};
|
||||
} catch (e) {
|
||||
document.getElementById('result').value =
|
||||
'请求数据格式错误:' + e.message;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (dataParam) {
|
||||
const decoded = dataParam;
|
||||
try {
|
||||
document.getElementById('data').value = JSON.stringify(
|
||||
JSON.parse(decoded),
|
||||
null,
|
||||
2,
|
||||
|
||||
var axiosConfig = {
|
||||
url: '/api?timestamp=' + Date.now(),
|
||||
method: method,
|
||||
};
|
||||
|
||||
if (timeout > 0) {
|
||||
axiosConfig.timeout = timeout;
|
||||
}
|
||||
|
||||
if (method === 'GET') {
|
||||
axiosConfig.params = {
|
||||
uri: uri,
|
||||
crypto: crypto,
|
||||
data: JSON.stringify(parsedData),
|
||||
headers: Object.keys(headers).length ? JSON.stringify(headers) : undefined,
|
||||
};
|
||||
} else {
|
||||
axiosConfig.data = {
|
||||
uri: uri,
|
||||
crypto: crypto,
|
||||
data: parsedData,
|
||||
headers: Object.keys(headers).length ? headers : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
var res = await axios(axiosConfig);
|
||||
document.getElementById('result').value = JSON.stringify(
|
||||
res.data,
|
||||
null,
|
||||
2,
|
||||
);
|
||||
} catch (error) {
|
||||
document.getElementById('data').value = decoded;
|
||||
}
|
||||
} catch (error) {
|
||||
document.getElementById('result').value =
|
||||
'Request failed: ' + error.message;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
// ===== 从 URL 查询参数恢复 =====
|
||||
(function fillFromQuery() {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
if (!params.toString()) {
|
||||
// 没有查询参数,用默认 header
|
||||
defaultHeaders.forEach(function (h) {
|
||||
addHeaderRow(h.key, h.value);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var uri = params.get('uri');
|
||||
var crypto = params.get('crypto');
|
||||
var dataParam = params.get('data');
|
||||
var method = params.get('method');
|
||||
var timeout = params.get('timeout');
|
||||
var headersParam = params.get('headers');
|
||||
var kvParams = params.get('kvParams');
|
||||
var paramMode = params.get('paramMode');
|
||||
|
||||
if (uri) document.getElementById('uri').value = uri;
|
||||
if (method) {
|
||||
var methodSelect = document.getElementById('method');
|
||||
if (
|
||||
[].slice.call(methodSelect.options).some(function (opt) {
|
||||
return opt.value === method;
|
||||
})
|
||||
) {
|
||||
methodSelect.value = method;
|
||||
}
|
||||
}
|
||||
if (timeout) document.getElementById('timeout').value = timeout;
|
||||
|
||||
if (crypto) {
|
||||
var cryptoSelect = document.getElementById('crypto');
|
||||
if (
|
||||
[].slice.call(cryptoSelect.options).some(function (opt) {
|
||||
return opt.value === crypto;
|
||||
})
|
||||
) {
|
||||
cryptoSelect.value = crypto;
|
||||
}
|
||||
}
|
||||
|
||||
if (dataParam) {
|
||||
try {
|
||||
document.getElementById('data').value = JSON.stringify(
|
||||
JSON.parse(dataParam),
|
||||
null,
|
||||
2,
|
||||
);
|
||||
} catch (_) {
|
||||
document.getElementById('data').value = dataParam;
|
||||
}
|
||||
}
|
||||
|
||||
if (headersParam) {
|
||||
try {
|
||||
var parsed = JSON.parse(headersParam);
|
||||
Object.keys(parsed).forEach(function (k) {
|
||||
addHeaderRow(k, parsed[k]);
|
||||
});
|
||||
} catch (_) {
|
||||
// fallback: 用默认 header
|
||||
defaultHeaders.forEach(function (h) {
|
||||
addHeaderRow(h.key, h.value);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
defaultHeaders.forEach(function (h) {
|
||||
addHeaderRow(h.key, h.value);
|
||||
});
|
||||
}
|
||||
|
||||
if (kvParams) {
|
||||
try {
|
||||
var parsed = JSON.parse(kvParams);
|
||||
// 先填充 kv 列表,再切换到 kv 模式
|
||||
Object.keys(parsed).forEach(function (k) {
|
||||
addKvRow(k, String(parsed[k]));
|
||||
});
|
||||
if (paramMode === 'kv') {
|
||||
switchParamTab('kv');
|
||||
}
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
} else if (paramMode === 'kv' && dataParam) {
|
||||
// 从 data 参数同步到键值对模式
|
||||
try {
|
||||
var data = JSON.parse(dataParam);
|
||||
Object.keys(data).forEach(function (k) {
|
||||
addKvRow(k, String(data[k]));
|
||||
});
|
||||
switchParamTab('kv');
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3612,6 +3612,32 @@ type='1009' 获取其 id, 如`/search?keywords= 代码时间 &type=1009`
|
||||
|
||||
**调用例子 :** `/artist/new/song?limit=1` `/artist/new/song?limit=1&before=1602777625000`
|
||||
|
||||
### 关注歌手最近新歌 - 播放全部
|
||||
|
||||
说明 : 登录后调用此接口可获取所有关注歌手最近的 50 首新歌
|
||||
|
||||
**接口地址 :** `/artist/new/song/playall`
|
||||
|
||||
**调用例子 :** `/artist/new/song/playall`
|
||||
|
||||
### 关注歌手新作品(歌曲/MV)
|
||||
|
||||
说明 : 登录后调用此接口可分页获取关注歌手的新歌曲和 MV
|
||||
|
||||
**可选参数 :** `limit`: 返回数量,默认为 10
|
||||
|
||||
`startTimestamp`: 时间游标,首次请求默认为当前时间,后续请求传入上一页返回的时间游标
|
||||
|
||||
`before`: `startTimestamp` 的别名
|
||||
|
||||
`sourceType`: 作品来源类型,已确认 `1` 表示新歌,其他取值待确认,默认为 `1`
|
||||
|
||||
`firstRequest`: 是否首次请求,默认为 `true`,翻页时传 `false`
|
||||
|
||||
**接口地址 :** `/artist/new/song/mv/list/v2`
|
||||
|
||||
**调用例子 :** `/artist/new/song/mv/list/v2` `/artist/new/song/mv/list/v2?startTimestamp=1783680576099&sourceType=1&limit=10&firstRequest=false`
|
||||
|
||||
### 关注歌手新 MV
|
||||
|
||||
说明 :登录后调用此接口可获取关注歌手新 MV
|
||||
@@ -3742,6 +3768,14 @@ type='1009' 获取其 id, 如`/search?keywords= 代码时间 &type=1009`
|
||||
|
||||
**调用例子 :** `/vip/growthpoint/get?ids=7043206830_7` `/vip/growthpoint/get?ids=8613118351_1,8607552957_1`
|
||||
|
||||
### 一键领取所有 vip 成长值
|
||||
|
||||
说明 : 登录后调用此接口 , 一键领取所有已完成的会员任务成长值奖励
|
||||
|
||||
**接口地址 :** `/vip/growthpoint/getall`
|
||||
|
||||
**调用例子 :** `/vip/growthpoint/getall`
|
||||
|
||||
### 歌手粉丝
|
||||
|
||||
说明 : 调用此接口 , 传入歌手 id, 可获取歌手粉丝
|
||||
@@ -4810,6 +4844,23 @@ bitrate = Math.floor(br / 1000)
|
||||
|
||||
**接口地址 :** `/listen/data/today/song`
|
||||
|
||||
### 听歌足迹 - 歌曲播放排行
|
||||
|
||||
说明 : 登录后调用此接口, 获取歌曲播放排行, 返回每首歌的播放次数 (playCount); 默认返回前 20 名 (Top20), 不足则返回全部
|
||||
|
||||
**必选参数 :**
|
||||
|
||||
`type`: 维度类型 周 week 月 month
|
||||
|
||||
**可选参数 :**
|
||||
|
||||
`endTime` : 周: 每周周六 0 点的时间戳 月: 每月最后一天 0 点的时间戳
|
||||
不填就是本周/月的
|
||||
|
||||
**接口地址 :** `/listen/data/song/play/rank`
|
||||
|
||||
**调用例子 :** `/listen/data/song/play/rank?type=month`
|
||||
|
||||
### 听歌足迹 - 总收听时长
|
||||
|
||||
说明 : 登录后调用此接口, 获取总收听时长; 相关接口可能需要 vip 权限
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>免费听 — 网易云音乐 API Enhanced</title>
|
||||
<style>
|
||||
:root {
|
||||
--fg: #333;
|
||||
--muted: #666;
|
||||
--border: #ddd;
|
||||
--bg: #f5f5f5;
|
||||
--panel: #ffffff;
|
||||
--accent: #333;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
html, body { height: 100%; }
|
||||
body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: var(--fg); background: var(--bg); line-height: 1.6; }
|
||||
.container { max-width: 800px; margin: 40px auto; padding: 0 20px; }
|
||||
@media (max-width: 480px) {
|
||||
.container { margin: 20px auto; padding: 0 16px; }
|
||||
header.site-header h1 { font-size: 22px; }
|
||||
.block { padding: 16px; }
|
||||
}
|
||||
header.site-header { margin-bottom: 24px; }
|
||||
header.site-header h1 { font-size: 24px; font-weight: 600; margin: 0; }
|
||||
.sub { margin-top: 4px; color: var(--muted); font-size: 14px; }
|
||||
.block { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 20px; margin-bottom: 16px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); }
|
||||
.block h3 { margin: 0 0 4px; font-size: 15px; font-weight: 600; }
|
||||
.block .desc { margin: 0 0 12px; color: var(--muted); font-size: 13px; }
|
||||
pre { margin: 0; background: #f9f9f9; border: 1px solid var(--border); border-radius: 6px; padding: 12px; overflow-x: auto; white-space: pre-wrap; word-break: break-all; font-family: 'Courier New', monospace; font-size: 13px; max-height: 200px; overflow: auto; }
|
||||
pre.data { max-height: 360px; }
|
||||
.row { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
|
||||
button { padding: 8px 18px; border-radius: 8px; border: 1px solid var(--border); font-size: 14px; font-weight: 500; cursor: pointer; background: var(--panel); color: var(--fg); transition: all .15s; }
|
||||
button:hover { background: #eee; }
|
||||
button.primary { background: var(--fg); color: var(--panel); border-color: var(--fg); }
|
||||
button.primary:hover { opacity: .85; }
|
||||
button:disabled { opacity: .4; cursor: not-allowed; }
|
||||
button.danger { background: #a11; color: #fff; border-color: #a11; }
|
||||
button.danger:hover { opacity: .85; }
|
||||
.tag { display: inline-block; padding: 2px 10px; border-radius: 20px; font-size: 12px; font-weight: 500; border: 1px solid var(--border); }
|
||||
.tag.ok { background: #e6f7e6; color: #1a7a1a; border-color: #b7e6b7; }
|
||||
.tag.no { background: #ffe6e6; color: #a11; border-color: #f5c6c6; }
|
||||
.tag.busy { background: #fff3cd; color: #856404; border-color: #ffeeba; }
|
||||
.flex { display: flex; align-items: center; gap: 10px; }
|
||||
.flex.sb { justify-content: space-between; }
|
||||
.step { display: flex; gap: 12px; align-items: flex-start; }
|
||||
.step .num { width: 26px; height: 26px; border-radius: 50%; background: var(--fg); color: var(--panel); display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 600; flex-shrink: 0; margin-top: 1px; }
|
||||
.step .num.done { background: #1a7a1a; }
|
||||
.step .body { flex: 1; min-width: 0; }
|
||||
input[type=text] { width: 100%; padding: 8px 12px; border-radius: 6px; border: 1px solid var(--border); font-size: 14px; font-family: inherit; margin-top: 6px; }
|
||||
input[type=text]:focus { outline: 2px solid var(--fg); outline-offset: -1px; border-color: transparent; }
|
||||
footer.site-footer { margin-top: 32px; padding-top: 12px; border-top: 1px solid var(--border); color: var(--muted); text-align: center; font-size: 13px; }
|
||||
footer.site-footer a { color: var(--fg); text-decoration: none; }
|
||||
footer.site-footer a:hover { border-bottom: 1px dotted var(--fg); }
|
||||
.info-grid { display: grid; grid-template-columns: 80px 1fr; gap: 4px 12px; font-size: 13px; margin-top: 8px; }
|
||||
.info-grid .lbl { color: var(--muted); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<header class="site-header">
|
||||
<h1>🎧 免费听 · 看广告获取时长</h1>
|
||||
<p class="sub">模拟 App 内看激励视频广告 → 领取免费听权益的完整流程</p>
|
||||
</header>
|
||||
|
||||
<!-- 步骤 1: 注册 Token -->
|
||||
<div class="block">
|
||||
<div class="step">
|
||||
<div class="num" id="s1num">1</div>
|
||||
<div class="body">
|
||||
<div class="flex sb">
|
||||
<h3>注册反作弊 Token</h3>
|
||||
<span id="s1tag" class="tag no">未开始</span>
|
||||
</div>
|
||||
<p class="desc">调用易盾接口获取实时 token,广告接口需要此 token 才能正常响应</p>
|
||||
<pre id="s1pre">(尚未执行)</pre>
|
||||
<div class="row">
|
||||
<button id="step1" class="primary">① 注册 Token</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 步骤 2: 获取广告 -->
|
||||
<div class="block">
|
||||
<div class="step">
|
||||
<div class="num" id="s2num">2</div>
|
||||
<div class="body">
|
||||
<div class="flex sb">
|
||||
<h3>获取广告 & 提取 reqId</h3>
|
||||
<span id="s2tag" class="tag no">未开始</span>
|
||||
</div>
|
||||
<p class="desc">请求广告位,从返回的 extJson.contextInfo.req_id 提取用于领取权益的标识</p>
|
||||
<pre id="s2pre" class="data">(尚未执行)</pre>
|
||||
<div class="row">
|
||||
<button id="step2" class="primary" disabled>② 获取广告</button>
|
||||
<button id="step2b" disabled>换一个广告位</button>
|
||||
</div>
|
||||
<div class="info-grid" id="s2info" style="display:none">
|
||||
<div class="lbl">广告 ID</div><div id="s2adId">-</div>
|
||||
<div class="lbl">reqId</div><div id="s2reqId">-</div>
|
||||
<div class="lbl">文案</div><div id="s2text">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 步骤 3: 领取权益 -->
|
||||
<div class="block">
|
||||
<div class="step">
|
||||
<div class="num" id="s3num">3</div>
|
||||
<div class="body">
|
||||
<div class="flex sb">
|
||||
<h3>领取免费听权益</h3>
|
||||
<span id="s3tag" class="tag no">未开始</span>
|
||||
</div>
|
||||
<p class="desc">传入 reqId 及相关参数,领取免费听权益(模拟点击广告后的领取请求)</p>
|
||||
<pre id="s3pre" class="data">(尚未执行)</pre>
|
||||
<div class="row">
|
||||
<button id="step3" class="primary" disabled>③ 领取权益</button>
|
||||
</div>
|
||||
<div class="info-grid" id="s3info" style="display:none">
|
||||
<div class="lbl">结果</div><div id="s3result">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 一键全流程 -->
|
||||
<div class="block">
|
||||
<div class="flex sb">
|
||||
<h3>一键运行</h3>
|
||||
<span id="allTag" class="tag no">就绪</span>
|
||||
</div>
|
||||
<p class="desc" style="margin-top:4px">按顺序自动执行以上三个步骤</p>
|
||||
<div class="row">
|
||||
<button id="runAll" class="primary">▶ 一键获取免费听时长</button>
|
||||
<button id="clearAll" class="danger">✕ 清空</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="site-footer">
|
||||
<a href="/">← 返回首页</a>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const $ = (id) => document.getElementById(id)
|
||||
const base = location.origin
|
||||
|
||||
function setTag(id, type, text) {
|
||||
const el = $(id)
|
||||
el.className = 'tag ' + type
|
||||
el.textContent = text
|
||||
}
|
||||
|
||||
function setNum(id, done) {
|
||||
$(id).className = 'num' + (done ? ' done' : '')
|
||||
}
|
||||
|
||||
function nocache(url) {
|
||||
const sep = url.indexOf('?') > -1 ? '&' : '?'
|
||||
return url + sep + '_t=' + Date.now()
|
||||
}
|
||||
|
||||
// ===== 步骤 1: 注册 Token =====
|
||||
async function step1() {
|
||||
const btn = $('step1')
|
||||
btn.disabled = true
|
||||
setTag('s1tag', 'busy', '注册中…')
|
||||
setNum('s1num', false)
|
||||
try {
|
||||
const res = await fetch(nocache(base + '/register/checktoken?refresh=1'))
|
||||
const data = await res.json()
|
||||
$('s1pre').textContent = JSON.stringify(data, null, 2)
|
||||
if (data.token) {
|
||||
setTag('s1tag', 'ok', '已注册')
|
||||
setNum('s1num', true)
|
||||
$('step2').disabled = false
|
||||
$('step2b').disabled = false
|
||||
return data.token
|
||||
}
|
||||
setTag('s1tag', 'no', '失败')
|
||||
return null
|
||||
} catch (e) {
|
||||
$('s1pre').textContent = JSON.stringify({ error: e.message }, null, 2)
|
||||
setTag('s1tag', 'no', e.message)
|
||||
return null
|
||||
} finally {
|
||||
btn.disabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 步骤 2: 获取广告 =====
|
||||
async function step2(typeId) {
|
||||
const btn = $('step2')
|
||||
const btnB = $('step2b')
|
||||
btn.disabled = btnB.disabled = true
|
||||
setTag('s2tag', 'busy', '获取中…')
|
||||
setNum('s2num', false)
|
||||
$('s2info').style.display = 'none'
|
||||
try {
|
||||
let url = base + '/ad/get' + (typeId ? '?type_ids=' + encodeURIComponent(typeId) : '')
|
||||
const res = await fetch(nocache(url))
|
||||
const data = await res.json()
|
||||
$('s2pre').textContent = JSON.stringify(data, null, 2)
|
||||
|
||||
if (data.code === 200 && data.extra && data.extra.reqId) {
|
||||
setTag('s2tag', 'ok', '已获取')
|
||||
setNum('s2num', true)
|
||||
$('s2info').style.display = 'grid'
|
||||
|
||||
const adKeys = data.ads ? Object.keys(data.ads) : []
|
||||
let adId = '-', text = '-'
|
||||
if (adKeys.length > 0) {
|
||||
const ad = data.ads[adKeys[0]]
|
||||
adId = ad.ad_id || '-'
|
||||
text = ad.text || '-'
|
||||
}
|
||||
|
||||
$('s2adId').textContent = adId
|
||||
$('s2reqId').textContent = data.extra.reqId
|
||||
$('s2text').textContent = text
|
||||
|
||||
$('step3').disabled = false
|
||||
return data.extra.reqId
|
||||
}
|
||||
setTag('s2tag', 'no', '未获取到 reqId')
|
||||
return null
|
||||
} catch (e) {
|
||||
$('s2pre').textContent = JSON.stringify({ error: e.message }, null, 2)
|
||||
setTag('s2tag', 'no', e.message)
|
||||
return null
|
||||
} finally {
|
||||
btn.disabled = false
|
||||
btnB.disabled = false
|
||||
}
|
||||
}
|
||||
|
||||
$('step2').onclick = () => step2()
|
||||
$('step2b').onclick = () => step2('["400002_0"]')
|
||||
|
||||
// ===== 步骤 3: 领取权益 =====
|
||||
async function step3() {
|
||||
const btn = $('step3')
|
||||
btn.disabled = true
|
||||
setTag('s3tag', 'busy', '领取中…')
|
||||
setNum('s3num', false)
|
||||
$('s3info').style.display = 'none'
|
||||
try {
|
||||
const res = await fetch(nocache(base + '/ad/listening/rights/gain'))
|
||||
const data = await res.json()
|
||||
$('s3pre').textContent = JSON.stringify(data, null, 2)
|
||||
|
||||
if (data.code === 200) {
|
||||
setTag('s3tag', 'ok', '已领取')
|
||||
setNum('s3num', true)
|
||||
$('s3info').style.display = 'grid'
|
||||
const body = data.data || {}
|
||||
$('s3result').textContent = JSON.stringify(body).substring(0, 200)
|
||||
return true
|
||||
}
|
||||
setTag('s3tag', 'no', '领取失败')
|
||||
return false
|
||||
} catch (e) {
|
||||
$('s3pre').textContent = JSON.stringify({ error: e.message }, null, 2)
|
||||
setTag('s3tag', 'no', e.message)
|
||||
return false
|
||||
} finally {
|
||||
btn.disabled = false
|
||||
}
|
||||
}
|
||||
|
||||
$('step3').onclick = step3
|
||||
|
||||
// ===== 一键运行 =====
|
||||
$('runAll').onclick = async function () {
|
||||
const btn = this
|
||||
btn.disabled = true
|
||||
setTag('allTag', 'busy', '运行中…')
|
||||
|
||||
await step1()
|
||||
await step2()
|
||||
await step3()
|
||||
|
||||
setTag('allTag', 'ok', '完成')
|
||||
btn.disabled = false
|
||||
}
|
||||
|
||||
// ===== 清空 =====
|
||||
$('clearAll').onclick = function () {
|
||||
const steps = ['s1', 's2', 's3']
|
||||
const tags = { s1: '未开始', s2: '未开始', s3: '未开始' }
|
||||
steps.forEach(s => {
|
||||
setTag(s + 'tag', 'no', tags[s])
|
||||
setNum(s + 'num', false)
|
||||
$(s + 'pre').textContent = '(尚未执行)'
|
||||
const info = $(s + 'info')
|
||||
if (info) info.style.display = 'none'
|
||||
})
|
||||
$('step1').disabled = false
|
||||
$('step2').disabled = true
|
||||
$('step2b').disabled = true
|
||||
$('step3').disabled = true
|
||||
setTag('allTag', 'no', '就绪')
|
||||
$('runAll').disabled = false
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+3
-1
@@ -96,7 +96,9 @@ curl -s {origin}/search?keywords=网易云</code></pre>
|
||||
<a href="/listen_together_host.html">一起听示例</a> ·
|
||||
<a href="/playlist_cover_update.html">更新歌单封面示例</a> ·
|
||||
<a href="/avatar_update.html">头像更新示例</a> ·
|
||||
<a href="/scrobble.html">听歌打卡示例</a>
|
||||
<a href="/scrobble.html">听歌打卡示例</a> ·
|
||||
<a href="/yidun.html">获取 CheckToken</a> ·
|
||||
<a href="/free_listen.html">免费听权益</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Token 注册器 — 网易云音乐 API Enhanced</title>
|
||||
<style>
|
||||
:root {
|
||||
--fg: #333;
|
||||
--muted: #666;
|
||||
--border: #ddd;
|
||||
--bg: #f5f5f5;
|
||||
--panel: #ffffff;
|
||||
--accent: #333;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
html, body { height: 100%; }
|
||||
body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: var(--fg); background: var(--bg); line-height: 1.6; }
|
||||
.container { max-width: 720px; margin: 40px auto; padding: 0 20px; }
|
||||
@media (max-width: 480px) {
|
||||
.container { margin: 20px auto; padding: 0 16px; }
|
||||
header.site-header h1 { font-size: 22px; }
|
||||
.block { padding: 16px; }
|
||||
}
|
||||
header.site-header { margin-bottom: 24px; }
|
||||
header.site-header h1 { font-size: 24px; font-weight: 600; margin: 0; }
|
||||
.sub { margin-top: 4px; color: var(--muted); font-size: 14px; }
|
||||
.block { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 20px; margin-bottom: 16px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); }
|
||||
.block h3 { margin: 0 0 12px; font-size: 15px; font-weight: 600; }
|
||||
pre { margin: 0; background: #f9f9f9; border: 1px solid var(--border); border-radius: 6px; padding: 12px; overflow-x: auto; white-space: pre-wrap; word-break: break-all; font-family: 'Courier New', monospace; font-size: 13px; max-height: 160px; overflow: auto; }
|
||||
.row { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
|
||||
button { padding: 8px 18px; border-radius: 8px; border: 1px solid var(--border); font-size: 14px; font-weight: 500; cursor: pointer; background: var(--panel); color: var(--fg); transition: all .15s; }
|
||||
button:hover { background: #eee; }
|
||||
button.primary { background: var(--fg); color: var(--panel); border-color: var(--fg); }
|
||||
button.primary:hover { opacity: .85; }
|
||||
button:disabled { opacity: .4; cursor: not-allowed; }
|
||||
.tag { display: inline-block; padding: 2px 10px; border-radius: 20px; font-size: 12px; font-weight: 500; border: 1px solid var(--border); }
|
||||
.tag.ok { background: #e6f7e6; color: #1a7a1a; border-color: #b7e6b7; }
|
||||
.tag.no { background: #ffe6e6; color: #a11; border-color: #f5c6c6; }
|
||||
.tag.busy { background: #fff3cd; color: #856404; border-color: #ffeeba; }
|
||||
.flex { display: flex; align-items: center; gap: 10px; }
|
||||
.flex.sb { justify-content: space-between; }
|
||||
.mt-2 { margin-top: 14px; }
|
||||
footer.site-footer { margin-top: 24px; padding-top: 12px; border-top: 1px solid var(--border); color: var(--muted); text-align: center; font-size: 13px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<header class="site-header">
|
||||
<h1>🔑 Token 注册器</h1>
|
||||
<p class="sub">从易盾获取反作弊 token 并注册到服务器,供广告等需要 checkToken 的接口使用</p>
|
||||
</header>
|
||||
|
||||
<div class="block">
|
||||
<div class="flex sb">
|
||||
<h3>当前 Token</h3>
|
||||
<span id="statusTag" class="tag no">未注册</span>
|
||||
</div>
|
||||
<pre id="tokenDisplay">(空)</pre>
|
||||
<div class="row">
|
||||
<button id="btnGet" class="primary">获取 Token</button>
|
||||
<button id="btnRefresh">强制刷新</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
<h3>服务器响应</h3>
|
||||
<pre id="respDisplay">{}</pre>
|
||||
</div>
|
||||
|
||||
<footer class="site-footer">
|
||||
<a href="/">← 返回首页</a>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const $ = (id) => document.getElementById(id)
|
||||
const base = location.origin
|
||||
|
||||
async function call(refresh) {
|
||||
const btn = $('btnGet')
|
||||
const btnR = $('btnRefresh')
|
||||
btn.disabled = btnR.disabled = true
|
||||
|
||||
const tag = $('statusTag')
|
||||
tag.className = 'tag busy'
|
||||
tag.textContent = '获取中…'
|
||||
|
||||
try {
|
||||
const url = base + '/register/checktoken' + (refresh ? '?refresh=1' : '')
|
||||
const res = await fetch(url)
|
||||
const data = await res.json()
|
||||
$('respDisplay').textContent = JSON.stringify(data, null, 2)
|
||||
|
||||
if (data.token) {
|
||||
$('tokenDisplay').textContent = data.token
|
||||
tag.className = 'tag ok'
|
||||
tag.textContent = '已注册'
|
||||
} else {
|
||||
$('tokenDisplay').textContent = '(获取失败)'
|
||||
tag.className = 'tag no'
|
||||
tag.textContent = '失败'
|
||||
}
|
||||
} catch (e) {
|
||||
$('respDisplay').textContent = JSON.stringify({ error: e.message }, null, 2)
|
||||
tag.className = 'tag no'
|
||||
tag.textContent = e.message
|
||||
}
|
||||
|
||||
btn.disabled = btnR.disabled = false
|
||||
}
|
||||
|
||||
$('btnGet').onclick = () => call(false)
|
||||
$('btnRefresh').onclick = () => call(true)
|
||||
call(false)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -15,6 +15,7 @@
|
||||
"domain": "https://music.163.com",
|
||||
"clDomian": "https://clientlog.music.163.com",
|
||||
"clDomian3": "https://clientlog3.music.163.com",
|
||||
"dunDomain": "https://ac.dun.163yun.com",
|
||||
"encrypt": true,
|
||||
"encryptResponse": false,
|
||||
"clientSign": "18:C0:4D:B9:8F:FE@@@453832335F384641365F424635335F303030315F303031425F343434415F343643365F333638332@@@@@@6ff673ef74955b38bce2fa8562d95c976ed4758b1227c4e9ee345987cee17bc9",
|
||||
|
||||
@@ -12,6 +12,8 @@ const createOption = (query, crypto = '') => {
|
||||
e_r: query.e_r || undefined,
|
||||
domain: query.domain || '',
|
||||
checkToken: query.checkToken || false,
|
||||
headers: query.headers || {},
|
||||
timeout: query.timeout || 0,
|
||||
}
|
||||
}
|
||||
module.exports = createOption
|
||||
|
||||
+14
-3
@@ -18,6 +18,7 @@ const {
|
||||
} = require('./index')
|
||||
const { URLSearchParams, URL } = require('url')
|
||||
const { APP_CONF } = require('../util/config.json')
|
||||
const { getToken: antiCheatToken } = require('../module/register_checktoken')
|
||||
|
||||
// 预先读取匿名token并缓存
|
||||
const anonymous_token = fs.readFileSync(
|
||||
@@ -181,6 +182,8 @@ const generateRequestId = () => {
|
||||
}
|
||||
|
||||
const createRequest = (uri, data, options) => {
|
||||
const token = options.checkToken ? antiCheatToken() : ''
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// 变量声明和初始化
|
||||
const headers = options.headers ? { ...options.headers } : {}
|
||||
@@ -264,6 +267,9 @@ const createRequest = (uri, data, options) => {
|
||||
headers['x-sdeviceid'] = cookie.sDeviceId || cookie.deviceId
|
||||
headers['x-buildver'] = xeapiBuildver
|
||||
if (cookie.MUSIC_U) headers['x-music-u'] = cookie.MUSIC_U
|
||||
if (options.checkToken) {
|
||||
headers['X-antiCheatToken'] = token
|
||||
}
|
||||
const xeapiCookie = {
|
||||
...cookie,
|
||||
os: xeapiOs,
|
||||
@@ -302,14 +308,14 @@ const createRequest = (uri, data, options) => {
|
||||
__csrf: csrfToken,
|
||||
channel: cookie.channel,
|
||||
requestId: generateRequestId(),
|
||||
...(options.checkToken
|
||||
? { 'X-antiCheatToken': APP_CONF.checkToken }
|
||||
: {}),
|
||||
// clientSign: APP_CONF.clientSign,
|
||||
}
|
||||
|
||||
if (cookie.MUSIC_U) header['MUSIC_U'] = cookie.MUSIC_U
|
||||
if (cookie.MUSIC_A) header['MUSIC_A'] = cookie.MUSIC_A
|
||||
if (options.checkToken) {
|
||||
header['X-antiCheatToken'] = token
|
||||
}
|
||||
|
||||
headers['Cookie'] = createHeaderCookie(header)
|
||||
headers['User-Agent'] =
|
||||
@@ -344,6 +350,11 @@ const createRequest = (uri, data, options) => {
|
||||
httpsAgent: createHttpsAgent(),
|
||||
}
|
||||
|
||||
// 自定义超时
|
||||
if (options.timeout > 0) {
|
||||
settings.timeout = options.timeout
|
||||
}
|
||||
|
||||
// 使用返回值加密
|
||||
const use_e_r = (crypto === 'eapi' || crypto === 'weapi') && data.e_r
|
||||
const use_xeapi = crypto === 'xeapi'
|
||||
|
||||
Reference in New Issue
Block a user