mirror of
https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced.git
synced 2026-10-20 14:41:23 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7822ab08d3 | ||
|
|
41bd6d82ce | ||
|
|
6f8dd1d971 | ||
|
|
ddd0af5474 | ||
|
|
fbd2e06419 | ||
|
|
35d1c61cb4 | ||
|
|
a183e153ef | ||
|
|
2fa78c3826 | ||
|
|
5ae1eab14c | ||
|
|
321c25bd7d | ||
|
|
f527c1ef73 | ||
|
|
0a5a1242f2 |
@@ -0,0 +1,36 @@
|
||||
// 获取广告
|
||||
|
||||
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', 'v3')
|
||||
|
||||
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 res = await request(
|
||||
`/api/ad/listening/rights/gain`,
|
||||
data,
|
||||
createOption(query, 'xeapi', 'v3'),
|
||||
)
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: 200,
|
||||
data: res.body,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// 发送安全验证码
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
ctcode: query.ctcode || '86',
|
||||
}
|
||||
return request(
|
||||
`/api/sms/captcha/safe/sent`,
|
||||
data,
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// 发送验证码
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
ctcode: query.ctcode || '86',
|
||||
secrete: 'music_middleuser_pclogin',
|
||||
cellphone: query.phone,
|
||||
scene: '0',
|
||||
}
|
||||
return request(
|
||||
`/api/middle/captcha/sent/v1`,
|
||||
data,
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
@@ -6,5 +6,9 @@ module.exports = (query, request) => {
|
||||
cellphone: query.phone,
|
||||
countrycode: query.countrycode,
|
||||
}
|
||||
return request(`/api/cellphone/existence/check`, data, createOption(query))
|
||||
return request(
|
||||
`/api/cellphone/existence/check`,
|
||||
data,
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,6 +25,6 @@ module.exports = (query, request) => {
|
||||
return request(
|
||||
`/api/resource/comments/${query.t}`,
|
||||
data,
|
||||
createOption(query, 'weapi'),
|
||||
createOption(query, 'eapi', 'v2'),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
const { resourceTypeMap } = require('../util/config.json')
|
||||
// 发送评论
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
threadId: resourceTypeMap[query.type] + query.id,
|
||||
content: query.content,
|
||||
resourceType: '0',
|
||||
expressionPicId: '-1',
|
||||
bubbleId: '-1',
|
||||
}
|
||||
return request(
|
||||
`/api/resource/comments/add`,
|
||||
data,
|
||||
createOption(query, 'xeapi', 'v3'),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
const { resourceTypeMap } = require('../util/config.json')
|
||||
// 删除评论
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
commentId: query.cid,
|
||||
threadId: resourceTypeMap[query.type] + query.id,
|
||||
}
|
||||
return request(
|
||||
`/api/resource/comments/delete`,
|
||||
data,
|
||||
createOption(query, 'xeapi'),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
const { resourceTypeMap } = require('../util/config.json')
|
||||
// 发送评论
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
threadId: resourceTypeMap[query.type] + query.id,
|
||||
commentId: query.cid,
|
||||
content: query.content,
|
||||
resourceType: '0',
|
||||
}
|
||||
return request(
|
||||
`/api/v1/resource/comments/reply`,
|
||||
data,
|
||||
createOption(query, 'xeapi', 'v3'),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// 强制下线设备
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
key: query.deviceKey,
|
||||
captcha: query.captcha || '',
|
||||
}
|
||||
return request(
|
||||
`/api/middle/user/security/device/kickoff`,
|
||||
data,
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// 登录设备列表
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
excStatus: '9',
|
||||
}
|
||||
return request(
|
||||
`/api/middle/user/device/list`,
|
||||
data,
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
@@ -14,6 +14,7 @@ module.exports = async (query, request) => {
|
||||
? query.captcha
|
||||
: query.md5_password || CryptoJS.MD5(query.password).toString(),
|
||||
remember: 'true',
|
||||
secureCaptcha: query.sca || '',
|
||||
}
|
||||
let result = await request(
|
||||
`/api/w/login/cellphone`,
|
||||
|
||||
@@ -9,6 +9,6 @@ module.exports = (query, request) => {
|
||||
? { checkToken: query.checkToken || APP_CONF.checkToken }
|
||||
: {}),
|
||||
}
|
||||
query.checkToken = true // 强制开启checkToken
|
||||
query.checkToken = 'v2' // 强制开启checkToken
|
||||
return request(`/api/playlist/${path}`, data, createOption(query, 'eapi'))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// 易盾反作弊 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.dunDomainV2 + '/v2/config/js?pn=YD00000558929251'
|
||||
let _token = ''
|
||||
|
||||
async function fetch() {
|
||||
const res = await axios.get(URL, { timeout: 10000 })
|
||||
const data = res.data
|
||||
if (data && data.code === 200 && data.result && data.result.conf) {
|
||||
return data.result.conf
|
||||
}
|
||||
throw new Error('易盾返回异常: ' + JSON.stringify(data).substring(0, 200))
|
||||
}
|
||||
|
||||
// 端点处理
|
||||
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,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.dunDomainV3 + '/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,17 @@
|
||||
// 云小编领取任务积分
|
||||
//
|
||||
// activityId:
|
||||
// 调用 rep/ugc/activity/get 获取
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
activityId: query.activityId || '5001',
|
||||
}
|
||||
return request(
|
||||
`/api/rep/ugc/activity/collect`,
|
||||
data,
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// 云小编活动信息
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
|
||||
module.exports = (query, request) => {
|
||||
return request(`/api/rep/ugc/activity/get`, {}, createOption(query, 'eapi'))
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// 云小编领取一日会员
|
||||
//
|
||||
// 注:前提条件见 rep/ugc/user/vip
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
activityId: query.activityId || '5001',
|
||||
}
|
||||
return request(
|
||||
`/api/rep/ugc/user/collect-vip`,
|
||||
data,
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// 云小编获取用户详情
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
|
||||
module.exports = (query, request) => {
|
||||
return request(`/api/rep/ugc/user/get`, {}, createOption(query, 'eapi'))
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// 云小编每日签到
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
|
||||
module.exports = (query, request) => {
|
||||
return request(`/api/rep/ugc/user/sign`, {}, createOption(query, 'eapi'))
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// 云小编查询会员任务状态
|
||||
//
|
||||
// 状态 (data.status)
|
||||
// 10: 用户积分达50,可免费领取1日黑胶会员
|
||||
// 20: 用户积分已达50,可免费领取1日黑胶会员
|
||||
// 30: 已领取1日黑胶会员,明天再来吧~
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
|
||||
module.exports = (query, request) => {
|
||||
return request(`/api/rep/ugc/user/vip`, {}, createOption(query, 'eapi'))
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// 此版本不再采用 br 作为音质区分的标准
|
||||
// 而是采用 standard, exhigh, lossless, hires, jyeffect(高清环绕声), sky(沉浸环绕声), jymaster(超清母带) 进行音质判断
|
||||
// 当unblock为true时, 会尝试使用unblockmusic-utils进行解锁, 同时音质设置不会生效, 但仍然为必须传入参数
|
||||
// 当level为sky时, 可通过 immerseType 选择沉浸声类型, 支持 c51(c51类型)、ste(环绕立体声类型)、aac(aac类型), 默认为 c51
|
||||
|
||||
const logger = require('../util/logger.js')
|
||||
const createOption = require('../util/option.js')
|
||||
@@ -51,7 +52,7 @@ module.exports = async (query, request) => {
|
||||
}
|
||||
}
|
||||
if (data.level == 'sky') {
|
||||
data.immerseType = 'c51'
|
||||
data.immerseType = query.immerseType || 'c51'
|
||||
}
|
||||
return request(
|
||||
`/api/song/enhance/player/url/v1`,
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// 云小编获取任务
|
||||
//
|
||||
// type:
|
||||
// 1: 歌曲曲风审核 musicalStyleEnter
|
||||
// 2: 歌曲语种审核 languageEnter
|
||||
// 3: 歌曲原唱审核 oriSingerEnter
|
||||
// 4: 情绪标签审核 emotionEnter
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
|
||||
module.exports = (query, request) => {
|
||||
const data = {
|
||||
type: query.type || '4',
|
||||
}
|
||||
return request(
|
||||
`/api/thinktank/audit/resource/detail`,
|
||||
data,
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// 云小编提交任务
|
||||
//
|
||||
// type:
|
||||
// 1: 歌曲曲风审核 musicalStyleEnter
|
||||
// 2: 歌曲语种审核 languageEnter
|
||||
// 3: 歌曲原唱审核 oriSingerEnter
|
||||
// 4: 情绪标签审核 emotionEnter
|
||||
//
|
||||
// taskId:
|
||||
// 调用 thinktank/audit/resource/detail 获取
|
||||
//
|
||||
// judgement:
|
||||
// 1: 同意, 2: 否决, 3: 跳过 (不算次数)
|
||||
|
||||
const createOption = require('../util/option.js')
|
||||
|
||||
module.exports = (query, request) => {
|
||||
if (!query.taskId || !query.judgement)
|
||||
return Promise.reject({
|
||||
status: 400,
|
||||
body: {
|
||||
code: 400,
|
||||
message: '参数不足',
|
||||
},
|
||||
})
|
||||
const data = {
|
||||
type: query.type || '4',
|
||||
taskId: query.taskId,
|
||||
judgement: query.judgement,
|
||||
}
|
||||
return request(
|
||||
`/api/thinktank/audit/resource/update`,
|
||||
data,
|
||||
createOption(query, 'eapi'),
|
||||
)
|
||||
}
|
||||
+8
-8
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@neteasecloudmusicapienhanced/api",
|
||||
"version": "4.36.2",
|
||||
"version": "4.38.0",
|
||||
"description": "全网最全的网易云音乐API接口 || A revival project for NeteaseCloudMusicApi Node.js Services (Half Refactor & Enhanced) || 网易云音乐 API 备份 + 增强 || 本项目自原版v4.28.0版本后开始自行维护",
|
||||
"scripts": {
|
||||
"dev": "nodemon app.js",
|
||||
@@ -82,7 +82,7 @@
|
||||
"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,15 +92,15 @@
|
||||
"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.62.1",
|
||||
"@typescript-eslint/parser": "^8.62.1",
|
||||
"eslint": "^9.39.4",
|
||||
"@typescript-eslint/eslint-plugin": "^8.65.0",
|
||||
"@typescript-eslint/parser": "^8.65.0",
|
||||
"eslint": "^9.39.5",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-html": "^8.1.4",
|
||||
"eslint-plugin-prettier": "^5.5.6",
|
||||
@@ -112,7 +112,7 @@
|
||||
"nodemon": "^3.1.14",
|
||||
"pkg": "^5.8.1",
|
||||
"power-assert": "^1.6.1",
|
||||
"prettier": "^3.9.4",
|
||||
"prettier": "^3.9.6",
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
Generated
+152
-157
@@ -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,23 +73,23 @@ importers:
|
||||
specifier: 25.9.2
|
||||
version: 25.9.2
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^8.62.1
|
||||
version: 8.62.1(@typescript-eslint/parser@8.62.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)
|
||||
specifier: ^8.65.0
|
||||
version: 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^8.62.1
|
||||
version: 8.62.1(eslint@9.39.4)(typescript@5.9.3)
|
||||
specifier: ^8.65.0
|
||||
version: 8.65.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.9.4)
|
||||
version: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.6)
|
||||
globals:
|
||||
specifier: ^17.7.0
|
||||
version: 17.7.0
|
||||
@@ -115,8 +115,8 @@ importers:
|
||||
specifier: ^1.6.1
|
||||
version: 1.6.1
|
||||
prettier:
|
||||
specifier: ^3.9.4
|
||||
version: 3.9.4
|
||||
specifier: ^3.9.6
|
||||
version: 3.9.6
|
||||
typescript:
|
||||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
@@ -147,9 +147,9 @@ packages:
|
||||
'@borewit/text-codec@0.2.2':
|
||||
resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==}
|
||||
|
||||
'@eslint-community/eslint-utils@4.9.1':
|
||||
resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
'@eslint-community/eslint-utils@4.10.0':
|
||||
resolution: {integrity: sha512-rd6n9Sefya1R1Vd594TRwzeHq2VnmICbvh3jebyt1Hs/6OoCSYNVpjGRRsKSTwAq3SKl09w0AfRCU57hoDLmxg==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
peerDependencies:
|
||||
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
|
||||
|
||||
@@ -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':
|
||||
@@ -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.62.1':
|
||||
resolution: {integrity: sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==}
|
||||
'@typescript-eslint/eslint-plugin@8.65.0':
|
||||
resolution: {integrity: sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^8.62.1
|
||||
'@typescript-eslint/parser': ^8.65.0
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/parser@8.62.1':
|
||||
resolution: {integrity: sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==}
|
||||
'@typescript-eslint/parser@8.65.0':
|
||||
resolution: {integrity: sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==}
|
||||
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.62.1':
|
||||
resolution: {integrity: sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==}
|
||||
'@typescript-eslint/project-service@8.65.0':
|
||||
resolution: {integrity: sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/scope-manager@8.62.1':
|
||||
resolution: {integrity: sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==}
|
||||
'@typescript-eslint/scope-manager@8.65.0':
|
||||
resolution: {integrity: sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.62.1':
|
||||
resolution: {integrity: sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==}
|
||||
'@typescript-eslint/tsconfig-utils@8.65.0':
|
||||
resolution: {integrity: sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/type-utils@8.62.1':
|
||||
resolution: {integrity: sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==}
|
||||
'@typescript-eslint/type-utils@8.65.0':
|
||||
resolution: {integrity: sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==}
|
||||
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.62.1':
|
||||
resolution: {integrity: sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==}
|
||||
'@typescript-eslint/types@8.65.0':
|
||||
resolution: {integrity: sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.62.1':
|
||||
resolution: {integrity: sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==}
|
||||
'@typescript-eslint/typescript-estree@8.65.0':
|
||||
resolution: {integrity: sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/utils@8.62.1':
|
||||
resolution: {integrity: sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==}
|
||||
'@typescript-eslint/utils@8.65.0':
|
||||
resolution: {integrity: sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==}
|
||||
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.62.1':
|
||||
resolution: {integrity: sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==}
|
||||
'@typescript-eslint/visitor-keys@8.65.0':
|
||||
resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@unblockneteasemusic/server@0.28.0':
|
||||
@@ -509,19 +509,19 @@ 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.7:
|
||||
resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==}
|
||||
@@ -973,10 +973,6 @@ packages:
|
||||
resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
eslint-visitor-keys@3.4.3:
|
||||
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
||||
eslint-visitor-keys@4.2.1:
|
||||
resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -985,8 +981,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:
|
||||
@@ -1354,8 +1350,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 +1364,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:
|
||||
@@ -1741,8 +1737,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 +1762,8 @@ packages:
|
||||
next-tick@1.1.0:
|
||||
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
|
||||
|
||||
node-abi@3.93.0:
|
||||
resolution: {integrity: sha512-Cu6yUpX5Iavugm8BeX7c0wgU9CvOqfd1yM6A1d2q2ZMjym7GjpASv2GdRcTq3Fx+Sb5OgBkEEpw4VnAbY6Y5RA==}
|
||||
node-abi@3.94.0:
|
||||
resolution: {integrity: sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
node-fetch@2.7.0:
|
||||
@@ -1833,8 +1829,8 @@ packages:
|
||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
own-keys@1.0.1:
|
||||
resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
|
||||
own-keys@1.0.2:
|
||||
resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
p-is-promise@3.0.0:
|
||||
@@ -1916,8 +1912,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 +2002,8 @@ packages:
|
||||
resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
prettier@3.9.4:
|
||||
resolution: {integrity: sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==}
|
||||
prettier@3.9.6:
|
||||
resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
@@ -2328,8 +2324,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:
|
||||
@@ -2687,10 +2683,10 @@ snapshots:
|
||||
|
||||
'@borewit/text-codec@0.2.2': {}
|
||||
|
||||
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.4)':
|
||||
'@eslint-community/eslint-utils@4.10.0(eslint@9.39.5)':
|
||||
dependencies:
|
||||
eslint: 9.39.4
|
||||
eslint-visitor-keys: 3.4.3
|
||||
eslint: 9.39.5
|
||||
eslint-visitor-keys: 5.0.1
|
||||
|
||||
'@eslint-community/regexpp@4.12.2': {}
|
||||
|
||||
@@ -2710,7 +2706,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
|
||||
@@ -2724,7 +2720,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@eslint/js@9.39.4': {}
|
||||
'@eslint/js@9.39.5': {}
|
||||
|
||||
'@eslint/object-schema@2.1.7': {}
|
||||
|
||||
@@ -2831,7 +2827,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
|
||||
@@ -2841,7 +2837,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': {}
|
||||
@@ -2867,72 +2863,72 @@ snapshots:
|
||||
'@types/http-errors': 2.0.5
|
||||
'@types/node': 25.9.2
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)':
|
||||
'@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.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.62.1(eslint@9.39.4)(typescript@5.9.3)
|
||||
'@typescript-eslint/scope-manager': 8.62.1
|
||||
'@typescript-eslint/type-utils': 8.62.1(eslint@9.39.4)(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.62.1(eslint@9.39.4)(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.62.1
|
||||
eslint: 9.39.4
|
||||
ignore: 7.0.5
|
||||
'@typescript-eslint/parser': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
|
||||
'@typescript-eslint/scope-manager': 8.65.0
|
||||
'@typescript-eslint/type-utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.65.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.62.1(eslint@9.39.4)(typescript@5.9.3)':
|
||||
'@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.62.1
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.62.1
|
||||
'@typescript-eslint/scope-manager': 8.65.0
|
||||
'@typescript-eslint/types': 8.65.0
|
||||
'@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.65.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.62.1(typescript@5.9.3)':
|
||||
'@typescript-eslint/project-service@8.65.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/tsconfig-utils': 8.62.1(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.65.0
|
||||
debug: 4.4.3
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/scope-manager@8.62.1':
|
||||
'@typescript-eslint/scope-manager@8.65.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/visitor-keys': 8.62.1
|
||||
'@typescript-eslint/types': 8.65.0
|
||||
'@typescript-eslint/visitor-keys': 8.65.0
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.62.1(typescript@5.9.3)':
|
||||
'@typescript-eslint/tsconfig-utils@8.65.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
typescript: 5.9.3
|
||||
|
||||
'@typescript-eslint/type-utils@8.62.1(eslint@9.39.4)(typescript@5.9.3)':
|
||||
'@typescript-eslint/type-utils@8.65.0(eslint@9.39.5)(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.62.1(eslint@9.39.4)(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.65.0
|
||||
'@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.65.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.62.1': {}
|
||||
'@typescript-eslint/types@8.65.0': {}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.62.1(typescript@5.9.3)':
|
||||
'@typescript-eslint/typescript-estree@8.65.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/project-service': 8.62.1(typescript@5.9.3)
|
||||
'@typescript-eslint/tsconfig-utils': 8.62.1(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/visitor-keys': 8.62.1
|
||||
'@typescript-eslint/project-service': 8.65.0(typescript@5.9.3)
|
||||
'@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.65.0
|
||||
'@typescript-eslint/visitor-keys': 8.65.0
|
||||
debug: 4.4.3
|
||||
minimatch: 10.2.5
|
||||
semver: 7.8.5
|
||||
@@ -2942,20 +2938,20 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.62.1(eslint@9.39.4)(typescript@5.9.3)':
|
||||
'@typescript-eslint/utils@8.65.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.62.1
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3)
|
||||
eslint: 9.39.4
|
||||
'@eslint-community/eslint-utils': 4.10.0(eslint@9.39.5)
|
||||
'@typescript-eslint/scope-manager': 8.65.0
|
||||
'@typescript-eslint/types': 8.65.0
|
||||
'@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3)
|
||||
eslint: 9.39.5
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.62.1':
|
||||
'@typescript-eslint/visitor-keys@8.65.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/types': 8.65.0
|
||||
eslint-visitor-keys: 5.0.1
|
||||
|
||||
'@unblockneteasemusic/server@0.28.0':
|
||||
@@ -3098,7 +3094,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
|
||||
@@ -3121,7 +3117,7 @@ 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.3
|
||||
raw-body: 3.0.2
|
||||
@@ -3129,12 +3125,12 @@ snapshots:
|
||||
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
|
||||
|
||||
@@ -3229,7 +3225,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:
|
||||
@@ -3527,7 +3523,7 @@ snapshots:
|
||||
object-inspect: 1.13.4
|
||||
object-keys: 1.1.1
|
||||
object.assign: 4.1.7
|
||||
own-keys: 1.0.1
|
||||
own-keys: 1.0.2
|
||||
regexp.prototype.flags: 1.5.4
|
||||
safe-array-concat: 1.1.4
|
||||
safe-push-apply: 1.0.0
|
||||
@@ -3648,43 +3644,41 @@ 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.9.4):
|
||||
eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.6):
|
||||
dependencies:
|
||||
eslint: 9.39.4
|
||||
prettier: 3.9.4
|
||||
eslint: 9.39.5
|
||||
prettier: 3.9.6
|
||||
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:
|
||||
esrecurse: 4.3.0
|
||||
estraverse: 5.3.0
|
||||
|
||||
eslint-visitor-keys@3.4.3: {}
|
||||
|
||||
eslint-visitor-keys@4.2.1: {}
|
||||
|
||||
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.10.0(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
|
||||
@@ -3810,7 +3804,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
|
||||
@@ -3903,9 +3897,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:
|
||||
@@ -4179,7 +4173,7 @@ snapshots:
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
|
||||
iconv-lite@0.7.2:
|
||||
iconv-lite@0.7.3:
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
|
||||
@@ -4189,7 +4183,7 @@ snapshots:
|
||||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
ignore@7.0.5: {}
|
||||
ignore@7.0.6: {}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
dependencies:
|
||||
@@ -4416,7 +4410,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
|
||||
@@ -4504,11 +4498,11 @@ snapshots:
|
||||
|
||||
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: {}
|
||||
|
||||
@@ -4555,7 +4549,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
|
||||
@@ -4582,7 +4576,7 @@ snapshots:
|
||||
|
||||
next-tick@1.1.0: {}
|
||||
|
||||
node-abi@3.93.0:
|
||||
node-abi@3.94.0:
|
||||
dependencies:
|
||||
semver: 7.8.5
|
||||
|
||||
@@ -4662,8 +4656,9 @@ snapshots:
|
||||
type-check: 0.4.0
|
||||
word-wrap: 1.2.5
|
||||
|
||||
own-keys@1.0.1:
|
||||
own-keys@1.0.2:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
get-intrinsic: 1.3.0
|
||||
object-keys: 1.1.1
|
||||
safe-push-apply: 1.0.0
|
||||
@@ -4737,7 +4732,7 @@ snapshots:
|
||||
|
||||
picomatch@2.3.2: {}
|
||||
|
||||
picomatch@4.0.4: {}
|
||||
picomatch@4.0.5: {}
|
||||
|
||||
pino-abstract-transport@0.5.0:
|
||||
dependencies:
|
||||
@@ -4884,7 +4879,7 @@ snapshots:
|
||||
minimist: 1.2.8
|
||||
mkdirp-classic: 0.5.3
|
||||
napi-build-utils: 1.0.2
|
||||
node-abi: 3.93.0
|
||||
node-abi: 3.94.0
|
||||
pump: 3.0.4
|
||||
rc: 1.2.8
|
||||
simple-get: 4.0.1
|
||||
@@ -4899,7 +4894,7 @@ snapshots:
|
||||
dependencies:
|
||||
fast-diff: 1.3.0
|
||||
|
||||
prettier@3.9.4: {}
|
||||
prettier@3.9.6: {}
|
||||
|
||||
process-nextick-args@2.0.1: {}
|
||||
|
||||
@@ -4957,7 +4952,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:
|
||||
@@ -5294,7 +5289,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
|
||||
@@ -5390,8 +5385,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: {}
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB |
+249
-5
@@ -283,7 +283,9 @@ AI 生成的图,仅供娱乐()
|
||||
|
||||
`md5_password`: md5 加密后的密码,传入后 `password` 参数将失效
|
||||
|
||||
`captcha`: 验证码,使用 [`/captcha/sent`](#发送验证码)接口传入手机号获取验证码,调用此接口传入验证码,可使用验证码登录,传入后 `password` 参数将失效
|
||||
`captcha`: 验证码,使用 `/captcha/sent` 或 `/captcha/sent/v1`接口传入手机号获取验证码,调用此接口传入验证码,可使用验证码登录,传入后 `password` 参数将失效
|
||||
|
||||
`sca`: 网易易盾滑块验证token, 获取方式未知
|
||||
|
||||
**接口地址 :** `/login/cellphone`
|
||||
|
||||
@@ -397,6 +399,19 @@ body {
|
||||
|
||||
**调用例子 :** `/captcha/sent?phone=13xxx`
|
||||
|
||||
### 新版发送验证码
|
||||
|
||||
说明 : 调用此接口 ,传入手机号码, 可发送验证码
|
||||
|
||||
**必选参数 :** `phone`: 手机号码
|
||||
|
||||
**可选参数 :**
|
||||
`ctcode`: 国家区号,默认 86 即中国
|
||||
|
||||
**接口地址 :** `/captcha/sent/v1`
|
||||
|
||||
**调用例子 :** `/captcha/sent/v1?phone=13xxx`
|
||||
|
||||
### 验证验证码
|
||||
|
||||
说明 : 调用此接口 ,传入手机号码和验证码, 可校验验证码是否正确
|
||||
@@ -1259,9 +1274,11 @@ tags: 歌单标签
|
||||
`lossless`=>`无损`, `hires`=>`Hi-Res`, `jyeffect` => `高清环绕声`, `sky` => `沉浸环绕声`, `dolby` => `杜比全景声`, `jymaster` => `超清母带`
|
||||
`unblock`: 是否使用使用歌曲解锁, 分为`true`和`false`
|
||||
|
||||
**可选参数 :** `immerseType`: 沉浸声环绕声类型, 分为 `c51` => `c51类型`, `ste` => `环绕立体声类型`, `aac` => `aac类型`, 仅在 `level=sky` 时生效, 默认为 `c51`
|
||||
|
||||
**接口地址 :** `/song/url/v1`
|
||||
|
||||
**调用例子 :** `/song/url/v1?id=1969519579&level=exhigh` `/song/url/v1?id=1969519579,33894312&level=lossless`
|
||||
**调用例子 :** `/song/url/v1?id=1969519579&level=exhigh` `/song/url/v1?id=1969519579,33894312&level=lossless` `/song/url/v1?id=1969519579&level=sky&immerseType=ste`
|
||||
|
||||
说明:`杜比全景声`音质需要设备支持,不同的设备可能会返回不同码率的 url。cookie 需要传入`os=pc`保证返回正常码率的 url。
|
||||
|
||||
@@ -1395,8 +1412,6 @@ tags: 歌单标签
|
||||
|
||||
说明 : 调用此接口 , 传入类型和歌单 id 可收藏歌单或者取消收藏歌单
|
||||
|
||||
!> 警告: 在`v4.29.7`版本后, 在网易云登陆后请求要带上`timestamp`字段, 否则会导致请求不合法
|
||||
|
||||
**必选参数 :**
|
||||
|
||||
`t` : 类型,1:收藏,2:取消收藏
|
||||
@@ -5473,7 +5488,236 @@ let data = encodeURIComponent(
|
||||
|
||||
**接口地址 :** `/song/cloud/download`
|
||||
|
||||
**调用例子 :** `/song/cloud/download?id=123456789`
|
||||
**调用例子 :** `/song/cloud/download?id=123456789`'
|
||||
|
||||
### 获取广告
|
||||
|
||||
说明 : 调用此接口, 可获取广告
|
||||
|
||||
**接口地址 :** `/ad/get`
|
||||
|
||||
**调用例子 :** `/ad/get`
|
||||
|
||||
### 获取30分钟免费听歌时长
|
||||
|
||||
说明 : 登录后调用此接口, 获取30分钟免费听歌时长
|
||||
|
||||
!> 警告: 通过调取接口出现的任何问题由调用者自行承担
|
||||
|
||||
**可选参数 :** `reqUid` 通过`/ad/get` 获取的广告ID
|
||||
|
||||
**接口地址 :** `/ad/listening/rights/gain`
|
||||
|
||||
**调用例子 :** `/ad/listening/rights/gain`
|
||||
|
||||
### 云小编 - 获取用户详情
|
||||
|
||||
说明: 登录后调用此接口, 获取云小编用户详情
|
||||
|
||||
**接口地址:** `/rep/ugc/user/get`
|
||||
|
||||
**调用例子:** `/rep/ugc/user/get`
|
||||
|
||||
### 云小编 - 每日签到
|
||||
|
||||
说明: 登录后调用此接口, 进行云小编签到, 领取 5 积分, 签到后 `/rep/ugc/user/get` 返回 `data.signed = 1`
|
||||
|
||||
**接口地址:** `/rep/ugc/user/sign`
|
||||
|
||||
**调用例子:** `/rep/ugc/user/sign`
|
||||
|
||||
### 云小编 - 查询会员任务状态
|
||||
|
||||
说明: 登录后调用此接口, 查询云小编会员任务状态, 当 `data.status = 20` 时, 可调用 `/rep/ugc/user/collect-vip` 领取会员
|
||||
|
||||
**接口地址:** `/rep/ugc/user/vip`
|
||||
|
||||
**调用例子:** `/rep/ugc/user/vip`
|
||||
|
||||
### 云小编 - 活动信息
|
||||
|
||||
说明: 登录后调用此接口, 查询云小编会员活动信息
|
||||
|
||||
**接口地址:** `/rep/ugc/activity/get`
|
||||
|
||||
**调用例子:** `/rep/ugc/activity/get`
|
||||
|
||||
### 云小编 - 获取任务
|
||||
|
||||
> 注意: 调用前请先使用官方客户端完成云小编“情绪标签审核”入站考试
|
||||
|
||||
**可选参数:**
|
||||
|
||||
`type`: 任务类型, 1: 歌曲曲风审核, 2: 歌曲语种审核, 3: 歌曲原唱审核, 4: 情绪标签审核, 默认 `4`
|
||||
|
||||
**接口地址:** `/thinktank/audit/resource/detail`
|
||||
|
||||
**调用例子:** `/thinktank/audit/resource/detail?type=4`
|
||||
|
||||
### 云小编 - 提交任务
|
||||
|
||||
> 注意: 投票结果会在后台审核, 一致 +3 积分, 不一致 -2 积分
|
||||
|
||||
**可选参数:**
|
||||
|
||||
`type`: 任务类型, 1: 歌曲曲风审核, 2: 歌曲语种审核, 3: 歌曲原唱审核, 4: 情绪标签审核, 默认 `4`
|
||||
|
||||
**必选参数:**
|
||||
|
||||
`taskId`: 任务 ID, 调用 `/thinktank/audit/resource/detail` 获取 `data.taskId`
|
||||
|
||||
`judgement`: 审核结果, 1: 同意, 2: 否决, 3: 跳过 (不算次数)
|
||||
|
||||
**接口地址:** `/thinktank/audit/resource/update`
|
||||
|
||||
**调用例子:** `/thinktank/audit/resource/update?type=4&taskId=123456&judgement=1`
|
||||
|
||||
### 云小编 - 领取任务积分
|
||||
|
||||
说明: 完成任务后调用此接口, 领取云小编任务积分
|
||||
|
||||
**可选参数:**
|
||||
|
||||
`activityId`: 活动 ID, 调用 `/rep/ugc/activity/get` 获取, 默认 `5001`
|
||||
|
||||
**接口地址:** `/rep/ugc/activity/collect`
|
||||
|
||||
**调用例子:** `/rep/ugc/activity/collect?activityId=5001`
|
||||
|
||||
### 云小编 - 领取一日会员
|
||||
|
||||
说明: 达成领取条件 (`/rep/ugc/user/vip`) 后调用此接口, 领取一日会员
|
||||
|
||||
**可选参数:**
|
||||
|
||||
`activityId`: 活动 ID, 调用 `/rep/ugc/activity/get` 获取, 默认 `5001`
|
||||
|
||||
**接口地址:** `/rep/ugc/user/collect-vip`
|
||||
|
||||
**调用例子:** `/rep/ugc/user/collect-vip?activityId=5001`
|
||||
|
||||
### 发送/删除评论
|
||||
|
||||
说明 : 调用此接口,可发送评论或者删除评论
|
||||
|
||||
1. 发送评论
|
||||
|
||||
**必选参数**
|
||||
|
||||
`type`: 数字,资源类型,对应歌曲,mv,专辑,歌单,电台,视频对应以下类型
|
||||
|
||||
```
|
||||
0: 歌曲
|
||||
|
||||
1: mv
|
||||
|
||||
2: 歌单
|
||||
|
||||
3: 专辑
|
||||
|
||||
4: 电台
|
||||
|
||||
5: 视频
|
||||
|
||||
6: 动态
|
||||
```
|
||||
|
||||
`id`: 对应资源 id
|
||||
|
||||
`content`: 要发送的内容
|
||||
|
||||
**调用例子** : `/comment/add?type=1&id=5436712&content=test` (往广岛之恋 mv 发送评论: test)
|
||||
|
||||
2. 回复评论
|
||||
|
||||
**必选参数**
|
||||
|
||||
`type`: 数字,资源类型,对应歌曲,mv,专辑,歌单,电台,视频对应以下类型
|
||||
|
||||
```
|
||||
0: 歌曲
|
||||
|
||||
1: mv
|
||||
|
||||
2: 歌单
|
||||
|
||||
3: 专辑
|
||||
|
||||
4: 电台
|
||||
|
||||
5: 视频
|
||||
|
||||
6: 动态
|
||||
```
|
||||
|
||||
`id`: 对应资源 id
|
||||
|
||||
`cid`: 评论 id
|
||||
|
||||
`content`: 要发送的内容
|
||||
|
||||
**调用例子** : `/comment/add?type=1&id=5436712&cid=1535550516319&content=test` (往广岛之恋 mv 回复test评论: test)
|
||||
|
||||
3. 删除评论
|
||||
|
||||
**必选参数**
|
||||
|
||||
`type`: 数字,资源类型,对应歌曲,mv,专辑,歌单,电台,视频对应以下类型
|
||||
|
||||
```
|
||||
0: 歌曲
|
||||
|
||||
1: mv
|
||||
|
||||
2: 歌单
|
||||
|
||||
3: 专辑
|
||||
|
||||
4: 电台节目
|
||||
|
||||
5: 视频
|
||||
|
||||
6: 动态
|
||||
|
||||
7: 电台
|
||||
|
||||
```
|
||||
|
||||
`id`: 对应资源 id
|
||||
|
||||
`cid`: 评论 id
|
||||
|
||||
**调用例子** : `/comment?type=1&id=5436712&cid=1535550516319` (在广岛之恋 mv 删除评论)
|
||||
|
||||
### 获取在线设备列表
|
||||
|
||||
说明: 登录后调用此接口, 获取在线设备列表
|
||||
|
||||
**接口地址:** `/device/list`
|
||||
|
||||
**调用例子:** `/device/list`
|
||||
|
||||
### 发送安全验证码
|
||||
|
||||
说明: 登录后调用此接口, 传入手机号, 可发送安全验证码
|
||||
|
||||
**必选参数 :** `phone`: 手机号
|
||||
|
||||
**接口地址 :** `/captcha/safe/sent`
|
||||
|
||||
**调用例子 :** `/captcha/safe/sent?phone=13XXXXXXXXX`
|
||||
|
||||
### 强制下线设备
|
||||
|
||||
说明: 登录后调用此接口, 传入设备 id, 可强制下线设备的登录会话
|
||||
|
||||
**必选参数 :** `key`: 设备的 `deviceKey`, 可通过 `/device/list` 获取
|
||||
|
||||
`captcha`: 安全验证码, 可通过 `/captcha/safe/sent` 获取
|
||||
|
||||
**接口地址 :** `/device/kickoff`
|
||||
|
||||
**调用例子 :** `/device/kickoff?key=00ALDFGEXXXXXXXXXXXXXXXXX&captcha=1234`
|
||||
|
||||
## 离线访问此文档
|
||||
|
||||
|
||||
@@ -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/v3?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>
|
||||
+4
-1
@@ -96,7 +96,10 @@ 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> ·
|
||||
<a href="/ugc.html">云小编任务中心</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
+701
@@ -0,0 +1,701 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>云小编任务中心 - 网易云音乐 API Enhanced</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 40px auto;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 32px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-link {
|
||||
display: block;
|
||||
margin-bottom: 20px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-link:hover {
|
||||
color: #333;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* ---- Section ---- */
|
||||
.section {
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.section:last-of-type {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* ---- Form ---- */
|
||||
.form-group {
|
||||
margin-bottom: 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #555;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
label .tag {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
padding: 1px 6px;
|
||||
border-radius: 3px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
label .tag.r {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
label .tag.o {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
label .tag.g {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 14px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
input[type="text"]:focus,
|
||||
input[type="number"]:focus,
|
||||
textarea:focus {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.row .form-group {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.quick-fill {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.quick-fill span {
|
||||
color: #0066cc;
|
||||
cursor: pointer;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.quick-fill span:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background: #333;
|
||||
color: white;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease;
|
||||
border: none;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
padding: 6px 16px;
|
||||
background: #333;
|
||||
color: white;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease;
|
||||
border: none;
|
||||
text-align: center;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.btn-sm:hover {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
.btn-sm:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-sm.green {
|
||||
background: #059669;
|
||||
}
|
||||
|
||||
.btn-sm.green:hover {
|
||||
background: #047857;
|
||||
}
|
||||
|
||||
.btn-sm.green:disabled {
|
||||
background: #a7f3d0;
|
||||
}
|
||||
|
||||
.btn-sm.red {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
.btn-sm.red:hover {
|
||||
background: #b91c1c;
|
||||
}
|
||||
|
||||
.btn-sm.red:disabled {
|
||||
background: #fca5a5;
|
||||
}
|
||||
|
||||
.btn-sm.gray {
|
||||
background: #6b7280;
|
||||
}
|
||||
|
||||
.btn-sm.gray:hover {
|
||||
background: #4b5563;
|
||||
}
|
||||
|
||||
.btn-sm.gray:disabled {
|
||||
background: #d1d5db;
|
||||
}
|
||||
|
||||
.result {
|
||||
margin-top: 16px;
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.result.success {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
}
|
||||
|
||||
.result.error {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.result.info {
|
||||
background: #e0f2fe;
|
||||
color: #0369a1;
|
||||
}
|
||||
|
||||
.footer-link {
|
||||
text-align: center;
|
||||
margin-top: 24px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.footer-link a {
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer-link a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* ---- Info Card ---- */
|
||||
.info-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: #f9fafb;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
|
||||
.info-card .avatar {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
background: #e5e7eb;
|
||||
}
|
||||
|
||||
.info-card .info-text {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.info-card .btn-sm {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ---- Song Review ---- */
|
||||
.song-review {
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
background: #f9fafb;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
|
||||
.song-review .cover {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 6px;
|
||||
object-fit: cover;
|
||||
background: #e5e7eb;
|
||||
display: block;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.song-review .song-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.song-review audio {
|
||||
width: 100%;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.song-review .song-tag {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.song-review .btn-group {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.song-review .lyric {
|
||||
font-size: 13px;
|
||||
color: #555;
|
||||
background: #fff;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e5e7eb;
|
||||
white-space: pre-wrap;
|
||||
max-height: 120px;
|
||||
overflow-y: auto;
|
||||
font-family: monospace;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>云小编任务中心</h1>
|
||||
<p class="subtitle">管理云音乐审核任务、签到与会员权益领取</p>
|
||||
|
||||
<a href="/qrlogin-nocookie.html" class="login-link">还没登录?点击登录</a>
|
||||
|
||||
<!-- Cookie -->
|
||||
<div class="form-group">
|
||||
<label for="cookie">Cookie <span class="tag o">可选</span></label>
|
||||
<textarea id="cookie" placeholder="留空则默认读取本地存储的登录态" rows="2"></textarea>
|
||||
<div class="quick-fill">
|
||||
<span onclick="loadLocalCookie()">读取本地 Cookie</span>
|
||||
<span onclick="clearCookie()">清除 Cookie</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-header">
|
||||
<span class="section-title">用户信息</span>
|
||||
<button class="btn-sm" id="userGet">获取用户详情</button>
|
||||
</div>
|
||||
<div class="info-card" id="user">
|
||||
<img alt="头像" class="avatar" id="userAvatar" />
|
||||
<span class="info-text" id="userName">未登录</span>
|
||||
<button class="btn-sm green" id="userSign" disabled>签到</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-header">
|
||||
<span class="section-title">会员领取</span>
|
||||
<button class="btn-sm" id="vipGet">获取会员详情</button>
|
||||
</div>
|
||||
<div class="info-card" id="vip">
|
||||
<span class="info-text" id="vipStatus">未载入</span>
|
||||
<button class="btn-sm" id="vipCollect" disabled>领取</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-header">
|
||||
<span class="section-title">审核任务</span>
|
||||
<button class="btn-sm" id="taskGet">获取任务详情</button>
|
||||
</div>
|
||||
<div class="info-card" id="task">
|
||||
<span class="info-text" id="taskInfo">[<span id="taskCount">0</span>/<span id="taskGoal">0</span>] 审核歌曲赚贡献分 (+66)</span>
|
||||
<button class="btn-sm" id="taskStart" disabled>去完成</button>
|
||||
</div>
|
||||
|
||||
<!-- Song Review -->
|
||||
<div class="song-review" id="song" style="display: none;">
|
||||
<img alt="封面" class="cover" id="songCover" />
|
||||
<div class="song-title" id="songTitle">未载入</div>
|
||||
<audio controls id="songAudio"></audio>
|
||||
<div class="song-tag" id="songTag"></div>
|
||||
<div class="btn-group">
|
||||
<button class="btn-sm green" id="songApprove" disabled>同意</button>
|
||||
<button class="btn-sm red" id="songReject" disabled>否决</button>
|
||||
<button class="btn-sm gray" id="songSkip" disabled>跳过 (不计次数)</button>
|
||||
</div>
|
||||
<div class="lyric" id="songLyric">[00:00.00] 暂无歌词</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="result" class="result" style="display: none;"></div>
|
||||
|
||||
<div class="footer-link">
|
||||
<a href="/">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
var k_cookie = 'ncm_cookie';
|
||||
var cookie = localStorage.getItem(k_cookie) || '';
|
||||
|
||||
/* ---- DOM refs ---- */
|
||||
var cookieInput = document.getElementById('cookie');
|
||||
var resultDiv = document.getElementById('result');
|
||||
|
||||
/* ---- Init ---- */
|
||||
if (cookie) {
|
||||
cookieInput.value = cookie;
|
||||
}
|
||||
|
||||
/* ---- Cookie ---- */
|
||||
window.loadLocalCookie = function () {
|
||||
var local = localStorage.getItem(k_cookie);
|
||||
if (local) {
|
||||
cookie = local;
|
||||
cookieInput.value = local;
|
||||
showResult('已成功读取本地 Cookie', 'success');
|
||||
} else {
|
||||
showResult('未在本地发现登录 Cookie,请先登录或手动粘贴', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
window.clearCookie = function () {
|
||||
cookie = '';
|
||||
cookieInput.value = '';
|
||||
localStorage.removeItem(k_cookie);
|
||||
showResult('已清除本地 Cookie', 'info');
|
||||
};
|
||||
|
||||
/* ---- Result ---- */
|
||||
function hideResult() {
|
||||
resultDiv.style.display = 'none';
|
||||
}
|
||||
|
||||
function showResult(message, type) {
|
||||
resultDiv.textContent = message;
|
||||
resultDiv.className = 'result ' + type;
|
||||
resultDiv.style.display = 'block';
|
||||
}
|
||||
|
||||
function getCookie() {
|
||||
var ck = cookieInput.value.trim();
|
||||
if (ck) cookie = ck;
|
||||
return ck || cookie || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起请求 (兼容旧版)
|
||||
* @param {string} url
|
||||
* @param {Record<string,string>} params
|
||||
* @param {(resp:Record<string,any>)=>void} done
|
||||
*/
|
||||
function request(url, params, done) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.responseType = 'json';
|
||||
xhr.timeout = 1e4;
|
||||
xhr.onload = function () {
|
||||
var r = xhr.response;
|
||||
if (r.code !== 200) {
|
||||
showResult('错误 ' + r.code + ': ' + (r.message || '未知错误'), 'error');
|
||||
} else {
|
||||
done(r);
|
||||
}
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
showResult('网络请求失败: ' + xhr.statusText, 'error');
|
||||
};
|
||||
var ck = getCookie();
|
||||
if (ck) params.cookie = ck;
|
||||
var s = '?_=' + Date.now();
|
||||
for (var k in params) {
|
||||
s += '&' + k + '=' + encodeURIComponent(params[k]);
|
||||
}
|
||||
xhr.open('GET', url + s);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
/// 用户信息 ///
|
||||
var userAvatar = document.getElementById('userAvatar');
|
||||
var userName = document.getElementById('userName');
|
||||
var userSign = document.getElementById('userSign');
|
||||
var userGet = document.getElementById('userGet');
|
||||
|
||||
userGet.onclick = function () {
|
||||
request('rep/ugc/user/get', {}, function (res) {
|
||||
var d = res.data;
|
||||
if (d.imgUrl) userAvatar.src = d.imgUrl + '?param=50y50';
|
||||
userName.textContent = d.name || '游客' + d.id;
|
||||
userSign.disabled = d.signed;
|
||||
showResult('用户信息加载成功', 'success');
|
||||
});
|
||||
};
|
||||
|
||||
userSign.onclick = function () {
|
||||
if (!userSign.disabled) {
|
||||
userSign.disabled = true;
|
||||
request('rep/ugc/user/sign', {}, function (res) {
|
||||
var d = res.data;
|
||||
userSign.disabled = d;
|
||||
showResult('签到' + (d ? '成功 ✓' : '失败 ✗'), d ? 'success' : 'error');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/// 会员领取 ///
|
||||
var vipStatus = document.getElementById('vipStatus');
|
||||
var vipCollect = document.getElementById('vipCollect');
|
||||
var vipGet = document.getElementById('vipGet');
|
||||
|
||||
vipGet.onclick = function () {
|
||||
request('rep/ugc/user/vip', {}, function (res) {
|
||||
var d = res.data;
|
||||
vipStatus.textContent = d.status + ': ' + d.title;
|
||||
vipCollect.disabled = d.status !== 20;
|
||||
showResult('会员详情加载成功', 'success');
|
||||
});
|
||||
};
|
||||
|
||||
vipCollect.onclick = function () {
|
||||
if (!vipCollect.disabled) {
|
||||
vipCollect.disabled = true;
|
||||
request('rep/ugc/user/collect-vip', {}, function (res) {
|
||||
var d = res.data;
|
||||
vipCollect.disabled = d;
|
||||
showResult('领取' + (d ? '成功 ✓' : '失败 ✗'), d ? 'success' : 'error');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/// 审核任务 ///
|
||||
var taskCount = document.getElementById('taskCount');
|
||||
var taskGoal = document.getElementById('taskGoal');
|
||||
var taskStartBtn = document.getElementById('taskStart');
|
||||
var taskGetBtn = document.getElementById('taskGet');
|
||||
|
||||
taskGetBtn.onclick = function () {
|
||||
request('/rep/ugc/activity/get', {}, function (res) {
|
||||
var d = res.data;
|
||||
taskCount.textContent = d.count;
|
||||
taskGoal.textContent = d.goalCount;
|
||||
taskStartBtn.disabled = d.activityId !== 5001;
|
||||
showResult('任务详情加载成功', 'success');
|
||||
});
|
||||
};
|
||||
|
||||
taskStartBtn.onclick = function () {
|
||||
if (!taskStartBtn.disabled) taskStart();
|
||||
};
|
||||
|
||||
/// 歌曲审核区域 ///
|
||||
var song = document.getElementById('song');
|
||||
var songCover = document.getElementById('songCover');
|
||||
var songTitle = document.getElementById('songTitle');
|
||||
var songAudio = document.getElementById('songAudio');
|
||||
var songTag = document.getElementById('songTag');
|
||||
var songApprove = document.getElementById('songApprove');
|
||||
var songReject = document.getElementById('songReject');
|
||||
var songSkip = document.getElementById('songSkip');
|
||||
var songLyric = document.getElementById('songLyric');
|
||||
|
||||
/**
|
||||
* 获取任务
|
||||
*/
|
||||
function taskStart() {
|
||||
song.style.display = 'none';
|
||||
request('/thinktank/audit/resource/detail', { type: '4' }, function (res) {
|
||||
var d = res.data;
|
||||
|
||||
if (d.auditCount >= 50) {
|
||||
request('rep/ugc/activity/collect', { activityId: '5001' }, function (res) {
|
||||
showResult('积分领取' + (res.data ? '成功,可以兑换会员了!' : '失败'), res.data ? 'success' : 'error');
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
songCover.src = d.coverUrl + '?param=100y100';
|
||||
songTitle.textContent = '[' + d.resId + '] ' + d.resName + ' - ' + d.artists;
|
||||
songTag.textContent = '[' + (d.auditCount + 1) + '/' + d.auditTaskCount + '] 当前结果: ' + d.initResult + '?';
|
||||
songLyric.textContent = (d.lyric || '') + (d.transLyric || '');
|
||||
if (!songLyric.textContent.trim()) songLyric.textContent = '[00:00.00] 暂无歌词';
|
||||
songAudio.src = d.songUrl;
|
||||
songAudio.play().catch(function () { /* 自动播放被浏览器阻止 */ });
|
||||
|
||||
songApprove.onclick = function () { if (!songApprove.disabled) taskSubmit(d.taskId, '1'); };
|
||||
songReject.onclick = function () { if (!songReject.disabled) taskSubmit(d.taskId, '2'); };
|
||||
songSkip.onclick = function () { if (!songSkip.disabled) taskSubmit(d.taskId, '3'); };
|
||||
|
||||
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||||
song.style.display = 'block';
|
||||
|
||||
setTimeout(function () {
|
||||
songApprove.disabled = songReject.disabled = songSkip.disabled = false;
|
||||
}, 3e3);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交任务
|
||||
* @param {string} taskId
|
||||
* @param {'1'|'2'|'3'} judgement
|
||||
*/
|
||||
function taskSubmit(taskId, judgement) {
|
||||
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||||
request(
|
||||
'thinktank/audit/resource/update',
|
||||
{ type: '4', taskId: taskId, judgement: judgement },
|
||||
function (res) {
|
||||
var d = res.data;
|
||||
if (d.result) {
|
||||
showResult('审核提交成功,加载下一首...', 'success');
|
||||
taskStart();
|
||||
} else {
|
||||
showResult('未知状态: ' + JSON.stringify(d), 'error');
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 一键载入 ///
|
||||
document.getElementById('loadall').onclick = function () {
|
||||
userGet.click();
|
||||
vipGet.click();
|
||||
taskGetBtn.click();
|
||||
showResult('正在载入所有数据...', 'info');
|
||||
};
|
||||
|
||||
window.loadLocalCookie();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -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/v2' + (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>
|
||||
@@ -11,10 +11,13 @@
|
||||
},
|
||||
"APP_CONF": {
|
||||
"apiDomain": "https://interface.music.163.com",
|
||||
"eapiDomain": "https://interfacepc.music.163.com",
|
||||
"xeapiDomain": "https://interface3.music.163.com",
|
||||
"domain": "https://music.163.com",
|
||||
"clDomian": "https://clientlog.music.163.com",
|
||||
"clDomian3": "https://clientlog3.music.163.com",
|
||||
"dunDomainV3": "https://ac.dun.163yun.com",
|
||||
"dunDomainV2": "https://ac.dun.163.com",
|
||||
"encrypt": true,
|
||||
"encryptResponse": false,
|
||||
"clientSign": "18:C0:4D:B9:8F:FE@@@453832335F384641365F424635335F303030315F303031425F343434415F343643365F333638332@@@@@@6ff673ef74955b38bce2fa8562d95c976ed4758b1227c4e9ee345987cee17bc9",
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
const createOption = (query, crypto = '') => {
|
||||
const createOption = (query, crypto = '', checkToken = false) => {
|
||||
return {
|
||||
crypto: query.crypto || crypto || '',
|
||||
cookie: query.cookie || process.env.NETEASE_COOKIE,
|
||||
@@ -11,7 +11,7 @@ const createOption = (query, crypto = '') => {
|
||||
: ['true', true].includes(query.randomCNIP),
|
||||
e_r: query.e_r || undefined,
|
||||
domain: query.domain || '',
|
||||
checkToken: query.checkToken || false,
|
||||
checkToken: query.checkToken || checkToken,
|
||||
headers: query.headers || {},
|
||||
timeout: query.timeout || 0,
|
||||
}
|
||||
|
||||
+25
-5
@@ -18,6 +18,12 @@ const {
|
||||
} = require('./index')
|
||||
const { URLSearchParams, URL } = require('url')
|
||||
const { APP_CONF } = require('../util/config.json')
|
||||
const {
|
||||
getToken: antiCheatTokenV2,
|
||||
} = require('../module/register_checktoken_v2')
|
||||
const {
|
||||
getToken: antiCheatTokenV3,
|
||||
} = require('../module/register_checktoken_v3')
|
||||
|
||||
// 预先读取匿名token并缓存
|
||||
const anonymous_token = fs.readFileSync(
|
||||
@@ -106,7 +112,7 @@ const userAgentMap = {
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
||||
},
|
||||
api: {
|
||||
pc: 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36 Chrome/91.0.4472.164 NeteaseMusicDesktop/3.0.18.203152',
|
||||
pc: 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36 Chrome/91.0.4472.164 NeteaseMusicDesktop/3.1.29.205117',
|
||||
android:
|
||||
'NeteaseMusic/9.1.65.240927161425(9001065);Dalvik/2.1.0 (Linux; U; Android 14; 23013RK75C Build/UKQ1.230804.001)',
|
||||
iphone: 'NeteaseMusic 9.0.90/5038 (iPhone; iOS 16.2; zh_CN)',
|
||||
@@ -116,6 +122,7 @@ const userAgentMap = {
|
||||
// 预先定义常量
|
||||
const DOMAIN = APP_CONF.domain
|
||||
const API_DOMAIN = APP_CONF.apiDomain
|
||||
const EAPI_DOMAIN = APP_CONF.eapiDomain
|
||||
const XEAPI_DOMAIN = APP_CONF.xeapiDomain
|
||||
const ENCRYPT_RESPONSE = APP_CONF.encryptResponse
|
||||
const SPECIAL_STATUS_CODES = new Set([201, 302, 400, 502, 800, 801, 802, 803])
|
||||
@@ -181,6 +188,16 @@ const generateRequestId = () => {
|
||||
}
|
||||
|
||||
const createRequest = (uri, data, options) => {
|
||||
let token = ''
|
||||
switch (options.checkToken) {
|
||||
case 'v2':
|
||||
token = antiCheatTokenV2()
|
||||
break
|
||||
case 'v3':
|
||||
token = antiCheatTokenV3()
|
||||
break
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// 变量声明和初始化
|
||||
const headers = options.headers ? { ...options.headers } : {}
|
||||
@@ -264,6 +281,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 +322,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'] =
|
||||
@@ -323,7 +343,7 @@ const createRequest = (uri, data, options) => {
|
||||
data.header = header
|
||||
|
||||
encryptData = encrypt.eapi(uri, data)
|
||||
url = (options.domain || API_DOMAIN) + '/eapi/' + uri.substr(5)
|
||||
url = (options.domain || EAPI_DOMAIN) + '/eapi/' + uri.substr(5)
|
||||
} else if (crypto === 'api') {
|
||||
url = (options.domain || API_DOMAIN) + uri
|
||||
encryptData = data
|
||||
|
||||
Reference in New Issue
Block a user