mirror of
https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced.git
synced 2026-08-12 17:10:37 +00:00
Merge branch 'feat-lottery' of https://github.com/ZxwyWebSite/api-enhanced into pr/215
This commit is contained in:
commit
a3287a0180
13
module/ad_listening_rights.js
Normal file
13
module/ad_listening_rights.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// 获取免费听时长状态
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
const data = {
|
||||||
|
entrance: 'FREE_LISTEN_RN',
|
||||||
|
}
|
||||||
|
return request(
|
||||||
|
`/api/ad/homepage/free/tab/extend/v2`,
|
||||||
|
data,
|
||||||
|
createOption(query, 'xeapi'),
|
||||||
|
)
|
||||||
|
}
|
||||||
13
module/captcha_safe_sent.js
Normal file
13
module/captcha_safe_sent.js
Normal file
@ -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'),
|
||||||
|
)
|
||||||
|
}
|
||||||
16
module/captcha_sent_v1.js
Normal file
16
module/captcha_sent_v1.js
Normal file
@ -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,
|
cellphone: query.phone,
|
||||||
countrycode: query.countrycode,
|
countrycode: query.countrycode,
|
||||||
}
|
}
|
||||||
return request(`/api/cellphone/existence/check`, data, createOption(query))
|
return request(
|
||||||
|
`/api/cellphone/existence/check`,
|
||||||
|
data,
|
||||||
|
createOption(query, 'eapi'),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
18
module/comment_add.js
Normal file
18
module/comment_add.js
Normal file
@ -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'),
|
||||||
|
)
|
||||||
|
}
|
||||||
15
module/comment_delete.js
Normal file
15
module/comment_delete.js
Normal file
@ -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'),
|
||||||
|
)
|
||||||
|
}
|
||||||
17
module/comment_reply.js
Normal file
17
module/comment_reply.js
Normal file
@ -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'),
|
||||||
|
)
|
||||||
|
}
|
||||||
14
module/device_kickoff.js
Normal file
14
module/device_kickoff.js
Normal file
@ -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'),
|
||||||
|
)
|
||||||
|
}
|
||||||
13
module/device_list.js
Normal file
13
module/device_list.js
Normal file
@ -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.captcha
|
||||||
: query.md5_password || CryptoJS.MD5(query.password).toString(),
|
: query.md5_password || CryptoJS.MD5(query.password).toString(),
|
||||||
remember: 'true',
|
remember: 'true',
|
||||||
|
secureCaptcha: query.sca || '',
|
||||||
}
|
}
|
||||||
let result = await request(
|
let result = await request(
|
||||||
`/api/w/login/cellphone`,
|
`/api/w/login/cellphone`,
|
||||||
|
|||||||
@ -16,15 +16,9 @@ module.exports = (query, request) => {
|
|||||||
activityId: query.activityId || '6501202',
|
activityId: query.activityId || '6501202',
|
||||||
drawCount: query.drawCount || '1',
|
drawCount: query.drawCount || '1',
|
||||||
}
|
}
|
||||||
// TODO: 如何传递 checkToken
|
|
||||||
const optionQuery = { ...query }
|
|
||||||
if (query.checkToken) {
|
|
||||||
data.checkToken = query.checkToken
|
|
||||||
delete query.checkToken
|
|
||||||
}
|
|
||||||
return request(
|
return request(
|
||||||
`/api/middle/play/do/lottery`,
|
`/api/middle/play/do/lottery`,
|
||||||
data,
|
data,
|
||||||
createOption(optionQuery, 'eapi', 'v2'),
|
createOption(query, 'eapi', 'v3'),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,5 +34,24 @@ module.exports = async (query) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 模块加载时自动获取一次 Token,确保 request.js 使用时不为空
|
||||||
|
fetch()
|
||||||
|
.then((token) => {
|
||||||
|
_token = token
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// 静默失败,后续请求时会重试
|
||||||
|
})
|
||||||
|
|
||||||
// 给 request.js 读取用
|
// 给 request.js 读取用
|
||||||
module.exports.getToken = () => _token
|
module.exports.getToken = () => {
|
||||||
|
if (!_token) {
|
||||||
|
// 如果 Token 为空,异步触发获取
|
||||||
|
fetch()
|
||||||
|
.then((token) => {
|
||||||
|
_token = token
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
return _token
|
||||||
|
}
|
||||||
|
|||||||
28
module/rep_ugc_exam_info_get.js
Normal file
28
module/rep_ugc_exam_info_get.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// 云小编考试状态
|
||||||
|
//
|
||||||
|
// examType:
|
||||||
|
// 1. 歌曲曲风审核: musicalStyleEnter
|
||||||
|
// 2. 歌曲语种审核: languageEnter
|
||||||
|
// 3. 歌曲原唱审核: oriSingerEnter
|
||||||
|
// 4. 情绪标签审核: emotionEnter
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
if (!query.examType)
|
||||||
|
return Promise.reject({
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '参数不足',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = {
|
||||||
|
examType: query.examType,
|
||||||
|
}
|
||||||
|
return request(
|
||||||
|
'/api/rep/ugc/exam/info/get',
|
||||||
|
data,
|
||||||
|
createOption(query, 'eapi'),
|
||||||
|
)
|
||||||
|
}
|
||||||
32
module/rep_ugc_exam_question_single_get.js
Normal file
32
module/rep_ugc_exam_question_single_get.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 云小编考试取题
|
||||||
|
//
|
||||||
|
// examType:
|
||||||
|
// 1. 歌曲曲风审核: musicalStyleEnter
|
||||||
|
// 2. 歌曲语种审核: languageEnter
|
||||||
|
// 3. 歌曲原唱审核: oriSingerEnter
|
||||||
|
// 4. 情绪标签审核: emotionEnter
|
||||||
|
//
|
||||||
|
// taskId:
|
||||||
|
// 首次调用 rep/ugc/exam/start 获取,之后调用 rep/ugc/exam/info/get 获取
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
if (!query.examType || !query.taskId)
|
||||||
|
return Promise.reject({
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '参数不足',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = {
|
||||||
|
examType: query.examType,
|
||||||
|
taskId: query.taskId,
|
||||||
|
}
|
||||||
|
return request(
|
||||||
|
'/api/rep/ugc/exam/question/single/get',
|
||||||
|
data,
|
||||||
|
createOption(query, 'eapi'),
|
||||||
|
)
|
||||||
|
}
|
||||||
32
module/rep_ugc_exam_result_get.js
Normal file
32
module/rep_ugc_exam_result_get.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 云小编考试结果
|
||||||
|
//
|
||||||
|
// examType:
|
||||||
|
// 1. 歌曲曲风审核: musicalStyleEnter
|
||||||
|
// 2. 歌曲语种审核: languageEnter
|
||||||
|
// 3. 歌曲原唱审核: oriSingerEnter
|
||||||
|
// 4. 情绪标签审核: emotionEnter
|
||||||
|
//
|
||||||
|
// taskId:
|
||||||
|
// 首次调用 rep/ugc/exam/start 获取,之后调用 rep/ugc/exam/info/get 获取
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
if (!query.examType || !query.taskId)
|
||||||
|
return Promise.reject({
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '参数不足',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = {
|
||||||
|
examType: query.examType,
|
||||||
|
taskId: query.taskId,
|
||||||
|
}
|
||||||
|
return request(
|
||||||
|
'/api/rep/ugc/exam/result/get',
|
||||||
|
data,
|
||||||
|
createOption(query, 'eapi'),
|
||||||
|
)
|
||||||
|
}
|
||||||
24
module/rep_ugc_exam_start.js
Normal file
24
module/rep_ugc_exam_start.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 云小编考试开始
|
||||||
|
//
|
||||||
|
// examType:
|
||||||
|
// 1. 歌曲曲风审核: musicalStyleEnter
|
||||||
|
// 2. 歌曲语种审核: languageEnter
|
||||||
|
// 3. 歌曲原唱审核: oriSingerEnter
|
||||||
|
// 4. 情绪标签审核: emotionEnter
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
if (!query.examType)
|
||||||
|
return Promise.reject({
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '参数不足',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = {
|
||||||
|
examType: query.examType,
|
||||||
|
}
|
||||||
|
return request('/api/rep/ugc/exam/start', data, createOption(query, 'eapi'))
|
||||||
|
}
|
||||||
36
module/rep_ugc_exam_submit.js
Normal file
36
module/rep_ugc_exam_submit.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 云小编考试提交
|
||||||
|
//
|
||||||
|
// examType:
|
||||||
|
// 1. 歌曲曲风审核: musicalStyleEnter
|
||||||
|
// 2. 歌曲语种审核: languageEnter
|
||||||
|
// 3. 歌曲原唱审核: oriSingerEnter
|
||||||
|
// 4. 情绪标签审核: emotionEnter
|
||||||
|
//
|
||||||
|
// taskId:
|
||||||
|
// 首次调用 rep/ugc/exam/start 获取,之后调用 rep/ugc/exam/info/get 获取
|
||||||
|
//
|
||||||
|
// questionId:
|
||||||
|
// 调用 rep/ugc/exam/question/single/get 获取
|
||||||
|
//
|
||||||
|
// answer:
|
||||||
|
// A 对, B 错
|
||||||
|
|
||||||
|
const createOption = require('../util/option.js')
|
||||||
|
|
||||||
|
module.exports = (query, request) => {
|
||||||
|
if (!query.examType || !query.taskId || !query.questionId || !query.answer)
|
||||||
|
return Promise.reject({
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
code: 400,
|
||||||
|
message: '参数不足',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = {
|
||||||
|
examType: query.examType,
|
||||||
|
taskId: query.taskId,
|
||||||
|
questionId: query.questionId,
|
||||||
|
answer: query.answer,
|
||||||
|
}
|
||||||
|
return request('/api/rep/ugc/exam/submit', data, createOption(query, 'eapi'))
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
// 此版本不再采用 br 作为音质区分的标准
|
// 此版本不再采用 br 作为音质区分的标准
|
||||||
// 而是采用 standard, exhigh, lossless, hires, jyeffect(高清环绕声), sky(沉浸环绕声), jymaster(超清母带) 进行音质判断
|
// 而是采用 standard, exhigh, lossless, hires, jyeffect(高清环绕声), sky(沉浸环绕声), jymaster(超清母带) 进行音质判断
|
||||||
// 当unblock为true时, 会尝试使用unblockmusic-utils进行解锁, 同时音质设置不会生效, 但仍然为必须传入参数
|
// 当unblock为true时, 会尝试使用unblockmusic-utils进行解锁, 同时音质设置不会生效, 但仍然为必须传入参数
|
||||||
|
// 当level为sky时, 可通过 immerseType 选择沉浸声类型, 支持 c51(c51类型)、ste(环绕立体声类型)、aac(aac类型), 默认为 c51
|
||||||
|
|
||||||
const logger = require('../util/logger.js')
|
const logger = require('../util/logger.js')
|
||||||
const createOption = require('../util/option.js')
|
const createOption = require('../util/option.js')
|
||||||
@ -51,7 +52,7 @@ module.exports = async (query, request) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data.level == 'sky') {
|
if (data.level == 'sky') {
|
||||||
data.immerseType = 'c51'
|
data.immerseType = query.immerseType || 'c51'
|
||||||
}
|
}
|
||||||
return request(
|
return request(
|
||||||
`/api/song/enhance/player/url/v1`,
|
`/api/song/enhance/player/url/v1`,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@neteasecloudmusicapienhanced/api",
|
"name": "@neteasecloudmusicapienhanced/api",
|
||||||
"version": "4.37.0",
|
"version": "4.38.0",
|
||||||
"description": "全网最全的网易云音乐API接口 || A revival project for NeteaseCloudMusicApi Node.js Services (Half Refactor & Enhanced) || 网易云音乐 API 备份 + 增强 || 本项目自原版v4.28.0版本后开始自行维护",
|
"description": "全网最全的网易云音乐API接口 || A revival project for NeteaseCloudMusicApi Node.js Services (Half Refactor & Enhanced) || 网易云音乐 API 备份 + 增强 || 本项目自原版v4.28.0版本后开始自行维护",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nodemon app.js",
|
"dev": "nodemon app.js",
|
||||||
@ -98,8 +98,8 @@
|
|||||||
"@types/express-fileupload": "^1.5.1",
|
"@types/express-fileupload": "^1.5.1",
|
||||||
"@types/mocha": "^10.0.10",
|
"@types/mocha": "^10.0.10",
|
||||||
"@types/node": "25.9.2",
|
"@types/node": "25.9.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.64.0",
|
"@typescript-eslint/eslint-plugin": "^8.65.0",
|
||||||
"@typescript-eslint/parser": "^8.64.0",
|
"@typescript-eslint/parser": "^8.65.0",
|
||||||
"eslint": "^9.39.5",
|
"eslint": "^9.39.5",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-html": "^8.1.4",
|
"eslint-plugin-html": "^8.1.4",
|
||||||
@ -112,7 +112,7 @@
|
|||||||
"nodemon": "^3.1.14",
|
"nodemon": "^3.1.14",
|
||||||
"pkg": "^5.8.1",
|
"pkg": "^5.8.1",
|
||||||
"power-assert": "^1.6.1",
|
"power-assert": "^1.6.1",
|
||||||
"prettier": "^3.9.5",
|
"prettier": "^3.9.6",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
163
pnpm-lock.yaml
generated
163
pnpm-lock.yaml
generated
@ -73,11 +73,11 @@ importers:
|
|||||||
specifier: 25.9.2
|
specifier: 25.9.2
|
||||||
version: 25.9.2
|
version: 25.9.2
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: ^8.64.0
|
specifier: ^8.65.0
|
||||||
version: 8.64.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)
|
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':
|
'@typescript-eslint/parser':
|
||||||
specifier: ^8.64.0
|
specifier: ^8.65.0
|
||||||
version: 8.64.0(eslint@9.39.5)(typescript@5.9.3)
|
version: 8.65.0(eslint@9.39.5)(typescript@5.9.3)
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.39.5
|
specifier: ^9.39.5
|
||||||
version: 9.39.5
|
version: 9.39.5
|
||||||
@ -89,7 +89,7 @@ importers:
|
|||||||
version: 8.1.4
|
version: 8.1.4
|
||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^5.5.6
|
specifier: ^5.5.6
|
||||||
version: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.5)
|
version: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.6)
|
||||||
globals:
|
globals:
|
||||||
specifier: ^17.7.0
|
specifier: ^17.7.0
|
||||||
version: 17.7.0
|
version: 17.7.0
|
||||||
@ -115,8 +115,8 @@ importers:
|
|||||||
specifier: ^1.6.1
|
specifier: ^1.6.1
|
||||||
version: 1.6.1
|
version: 1.6.1
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.9.5
|
specifier: ^3.9.6
|
||||||
version: 3.9.5
|
version: 3.9.6
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.9.3
|
specifier: ^5.9.3
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
@ -147,9 +147,9 @@ packages:
|
|||||||
'@borewit/text-codec@0.2.2':
|
'@borewit/text-codec@0.2.2':
|
||||||
resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==}
|
resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==}
|
||||||
|
|
||||||
'@eslint-community/eslint-utils@4.9.1':
|
'@eslint-community/eslint-utils@4.10.0':
|
||||||
resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==}
|
resolution: {integrity: sha512-rd6n9Sefya1R1Vd594TRwzeHq2VnmICbvh3jebyt1Hs/6OoCSYNVpjGRRsKSTwAq3SKl09w0AfRCU57hoDLmxg==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
|
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
|
||||||
|
|
||||||
@ -301,63 +301,63 @@ packages:
|
|||||||
'@types/serve-static@2.2.0':
|
'@types/serve-static@2.2.0':
|
||||||
resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==}
|
resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==}
|
||||||
|
|
||||||
'@typescript-eslint/eslint-plugin@8.64.0':
|
'@typescript-eslint/eslint-plugin@8.65.0':
|
||||||
resolution: {integrity: sha512-CGvQPBxN3wZLu6Rz2kFUpZeoCm78xUic92ck39KPePkO1NPOwjCqdQnm5Q87tpWw9vcBvW8XLrDXjH9PWYtJ3Q==}
|
resolution: {integrity: sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@typescript-eslint/parser': ^8.64.0
|
'@typescript-eslint/parser': ^8.65.0
|
||||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||||
typescript: '>=4.8.4 <6.1.0'
|
typescript: '>=4.8.4 <6.1.0'
|
||||||
|
|
||||||
'@typescript-eslint/parser@8.64.0':
|
'@typescript-eslint/parser@8.65.0':
|
||||||
resolution: {integrity: sha512-KA0OshtlcCCXmbfqyZkM5pV3/WNraJf7DkJRLpyrmwPtud57H5BDX7C3k0LPSPxpprfRL+cJDGabF10mvNCoCw==}
|
resolution: {integrity: sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||||
typescript: '>=4.8.4 <6.1.0'
|
typescript: '>=4.8.4 <6.1.0'
|
||||||
|
|
||||||
'@typescript-eslint/project-service@8.64.0':
|
'@typescript-eslint/project-service@8.65.0':
|
||||||
resolution: {integrity: sha512-tk4WpOJ6IEbGrVHaNmM0YRrwAD3exZlIK3iadQNAxh4YKk6jvUQ4ecq18n+v7+meh+cJ3j+D8nbk8sRKhlwLQg==}
|
resolution: {integrity: sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '>=4.8.4 <6.1.0'
|
typescript: '>=4.8.4 <6.1.0'
|
||||||
|
|
||||||
'@typescript-eslint/scope-manager@8.64.0':
|
'@typescript-eslint/scope-manager@8.65.0':
|
||||||
resolution: {integrity: sha512-CXEaFdYXjSTgKhisNkwCcJwTP8Pl+fmRrEQrri4nm3vU743bALrxzLmq7fHG/7e6a5xO0lDYeURpZmBuhHk54w==}
|
resolution: {integrity: sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@typescript-eslint/tsconfig-utils@8.64.0':
|
'@typescript-eslint/tsconfig-utils@8.65.0':
|
||||||
resolution: {integrity: sha512-2yo8rRNKuzbVWQp5kslhANqZ2uDAeROQHBRZNPu8JDsHmeFNj/XJJhX/FhNUWmkHHvoNsKa6+tHJiig87EzsQw==}
|
resolution: {integrity: sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '>=4.8.4 <6.1.0'
|
typescript: '>=4.8.4 <6.1.0'
|
||||||
|
|
||||||
'@typescript-eslint/type-utils@8.64.0':
|
'@typescript-eslint/type-utils@8.65.0':
|
||||||
resolution: {integrity: sha512-XWG4Fmmv/6SvyS9nH8jWrKs6terwJvE8cyRt1CzYYqzp9OrPhCT4cMc/f7C6RZCwG+qMmiffJS1/qJP8G1URtg==}
|
resolution: {integrity: sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||||
typescript: '>=4.8.4 <6.1.0'
|
typescript: '>=4.8.4 <6.1.0'
|
||||||
|
|
||||||
'@typescript-eslint/types@8.64.0':
|
'@typescript-eslint/types@8.65.0':
|
||||||
resolution: {integrity: sha512-qjhfuTfLXjA4IOzXvz0rTjT01BqEiIgPoUeMwiEjnaHKJMTNo8rH5pYW1a2L/0Dnux2fPC85AeyJoWaGa8WxTA==}
|
resolution: {integrity: sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@typescript-eslint/typescript-estree@8.64.0':
|
'@typescript-eslint/typescript-estree@8.65.0':
|
||||||
resolution: {integrity: sha512-Pztpsn1aCE1oWDvDEfUk31nngvvF7vUB5SwHFEaZIFpvw7WJtqUHHL4plBZDA9HfWJJjL13BdG0YrJInTUvoVA==}
|
resolution: {integrity: sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '>=4.8.4 <6.1.0'
|
typescript: '>=4.8.4 <6.1.0'
|
||||||
|
|
||||||
'@typescript-eslint/utils@8.64.0':
|
'@typescript-eslint/utils@8.65.0':
|
||||||
resolution: {integrity: sha512-aJUGVB3+U0htrrCjoA8qukw8cm8fNCGAxK/tVoS70k8aeb7DETKeFozRiVFIwEeN9WJLsjaP3ph8I60tY2XZoQ==}
|
resolution: {integrity: sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||||
typescript: '>=4.8.4 <6.1.0'
|
typescript: '>=4.8.4 <6.1.0'
|
||||||
|
|
||||||
'@typescript-eslint/visitor-keys@8.64.0':
|
'@typescript-eslint/visitor-keys@8.65.0':
|
||||||
resolution: {integrity: sha512-mrtuL8Nsn6gi2H4mo5KMTp823M+3Q19Ew/i+Zlikq20tIMm99C3Ez0dCmkWWnxut20esQvTg8aUSEhMcAOXhEw==}
|
resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@unblockneteasemusic/server@0.28.0':
|
'@unblockneteasemusic/server@0.28.0':
|
||||||
@ -973,10 +973,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
|
resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
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:
|
eslint-visitor-keys@4.2.1:
|
||||||
resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
|
resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
@ -1833,8 +1829,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
own-keys@1.0.1:
|
own-keys@1.0.2:
|
||||||
resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
|
resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
p-is-promise@3.0.0:
|
p-is-promise@3.0.0:
|
||||||
@ -2006,8 +2002,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==}
|
resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
prettier@3.9.5:
|
prettier@3.9.6:
|
||||||
resolution: {integrity: sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==}
|
resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@ -2687,10 +2683,10 @@ snapshots:
|
|||||||
|
|
||||||
'@borewit/text-codec@0.2.2': {}
|
'@borewit/text-codec@0.2.2': {}
|
||||||
|
|
||||||
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.5)':
|
'@eslint-community/eslint-utils@4.10.0(eslint@9.39.5)':
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.5
|
eslint: 9.39.5
|
||||||
eslint-visitor-keys: 3.4.3
|
eslint-visitor-keys: 5.0.1
|
||||||
|
|
||||||
'@eslint-community/regexpp@4.12.2': {}
|
'@eslint-community/regexpp@4.12.2': {}
|
||||||
|
|
||||||
@ -2867,14 +2863,14 @@ snapshots:
|
|||||||
'@types/http-errors': 2.0.5
|
'@types/http-errors': 2.0.5
|
||||||
'@types/node': 25.9.2
|
'@types/node': 25.9.2
|
||||||
|
|
||||||
'@typescript-eslint/eslint-plugin@8.64.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)':
|
'@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:
|
dependencies:
|
||||||
'@eslint-community/regexpp': 4.12.2
|
'@eslint-community/regexpp': 4.12.2
|
||||||
'@typescript-eslint/parser': 8.64.0(eslint@9.39.5)(typescript@5.9.3)
|
'@typescript-eslint/parser': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
|
||||||
'@typescript-eslint/scope-manager': 8.64.0
|
'@typescript-eslint/scope-manager': 8.65.0
|
||||||
'@typescript-eslint/type-utils': 8.64.0(eslint@9.39.5)(typescript@5.9.3)
|
'@typescript-eslint/type-utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
|
||||||
'@typescript-eslint/utils': 8.64.0(eslint@9.39.5)(typescript@5.9.3)
|
'@typescript-eslint/utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
|
||||||
'@typescript-eslint/visitor-keys': 8.64.0
|
'@typescript-eslint/visitor-keys': 8.65.0
|
||||||
eslint: 9.39.5
|
eslint: 9.39.5
|
||||||
ignore: 7.0.6
|
ignore: 7.0.6
|
||||||
natural-compare: 1.4.0
|
natural-compare: 1.4.0
|
||||||
@ -2883,41 +2879,41 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3)':
|
'@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/scope-manager': 8.64.0
|
'@typescript-eslint/scope-manager': 8.65.0
|
||||||
'@typescript-eslint/types': 8.64.0
|
'@typescript-eslint/types': 8.65.0
|
||||||
'@typescript-eslint/typescript-estree': 8.64.0(typescript@5.9.3)
|
'@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3)
|
||||||
'@typescript-eslint/visitor-keys': 8.64.0
|
'@typescript-eslint/visitor-keys': 8.65.0
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
eslint: 9.39.5
|
eslint: 9.39.5
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/project-service@8.64.0(typescript@5.9.3)':
|
'@typescript-eslint/project-service@8.65.0(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/tsconfig-utils': 8.64.0(typescript@5.9.3)
|
'@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3)
|
||||||
'@typescript-eslint/types': 8.64.0
|
'@typescript-eslint/types': 8.65.0
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/scope-manager@8.64.0':
|
'@typescript-eslint/scope-manager@8.65.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 8.64.0
|
'@typescript-eslint/types': 8.65.0
|
||||||
'@typescript-eslint/visitor-keys': 8.64.0
|
'@typescript-eslint/visitor-keys': 8.65.0
|
||||||
|
|
||||||
'@typescript-eslint/tsconfig-utils@8.64.0(typescript@5.9.3)':
|
'@typescript-eslint/tsconfig-utils@8.65.0(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
|
|
||||||
'@typescript-eslint/type-utils@8.64.0(eslint@9.39.5)(typescript@5.9.3)':
|
'@typescript-eslint/type-utils@8.65.0(eslint@9.39.5)(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 8.64.0
|
'@typescript-eslint/types': 8.65.0
|
||||||
'@typescript-eslint/typescript-estree': 8.64.0(typescript@5.9.3)
|
'@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3)
|
||||||
'@typescript-eslint/utils': 8.64.0(eslint@9.39.5)(typescript@5.9.3)
|
'@typescript-eslint/utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
eslint: 9.39.5
|
eslint: 9.39.5
|
||||||
ts-api-utils: 2.5.0(typescript@5.9.3)
|
ts-api-utils: 2.5.0(typescript@5.9.3)
|
||||||
@ -2925,14 +2921,14 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/types@8.64.0': {}
|
'@typescript-eslint/types@8.65.0': {}
|
||||||
|
|
||||||
'@typescript-eslint/typescript-estree@8.64.0(typescript@5.9.3)':
|
'@typescript-eslint/typescript-estree@8.65.0(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/project-service': 8.64.0(typescript@5.9.3)
|
'@typescript-eslint/project-service': 8.65.0(typescript@5.9.3)
|
||||||
'@typescript-eslint/tsconfig-utils': 8.64.0(typescript@5.9.3)
|
'@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3)
|
||||||
'@typescript-eslint/types': 8.64.0
|
'@typescript-eslint/types': 8.65.0
|
||||||
'@typescript-eslint/visitor-keys': 8.64.0
|
'@typescript-eslint/visitor-keys': 8.65.0
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
minimatch: 10.2.5
|
minimatch: 10.2.5
|
||||||
semver: 7.8.5
|
semver: 7.8.5
|
||||||
@ -2942,20 +2938,20 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/utils@8.64.0(eslint@9.39.5)(typescript@5.9.3)':
|
'@typescript-eslint/utils@8.65.0(eslint@9.39.5)(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5)
|
'@eslint-community/eslint-utils': 4.10.0(eslint@9.39.5)
|
||||||
'@typescript-eslint/scope-manager': 8.64.0
|
'@typescript-eslint/scope-manager': 8.65.0
|
||||||
'@typescript-eslint/types': 8.64.0
|
'@typescript-eslint/types': 8.65.0
|
||||||
'@typescript-eslint/typescript-estree': 8.64.0(typescript@5.9.3)
|
'@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3)
|
||||||
eslint: 9.39.5
|
eslint: 9.39.5
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/visitor-keys@8.64.0':
|
'@typescript-eslint/visitor-keys@8.65.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 8.64.0
|
'@typescript-eslint/types': 8.65.0
|
||||||
eslint-visitor-keys: 5.0.1
|
eslint-visitor-keys: 5.0.1
|
||||||
|
|
||||||
'@unblockneteasemusic/server@0.28.0':
|
'@unblockneteasemusic/server@0.28.0':
|
||||||
@ -3527,7 +3523,7 @@ snapshots:
|
|||||||
object-inspect: 1.13.4
|
object-inspect: 1.13.4
|
||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
object.assign: 4.1.7
|
object.assign: 4.1.7
|
||||||
own-keys: 1.0.1
|
own-keys: 1.0.2
|
||||||
regexp.prototype.flags: 1.5.4
|
regexp.prototype.flags: 1.5.4
|
||||||
safe-array-concat: 1.1.4
|
safe-array-concat: 1.1.4
|
||||||
safe-push-apply: 1.0.0
|
safe-push-apply: 1.0.0
|
||||||
@ -3656,10 +3652,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
htmlparser2: 10.1.0
|
htmlparser2: 10.1.0
|
||||||
|
|
||||||
eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.5))(eslint@9.39.5)(prettier@3.9.5):
|
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:
|
dependencies:
|
||||||
eslint: 9.39.5
|
eslint: 9.39.5
|
||||||
prettier: 3.9.5
|
prettier: 3.9.6
|
||||||
prettier-linter-helpers: 1.0.1
|
prettier-linter-helpers: 1.0.1
|
||||||
synckit: 0.11.13
|
synckit: 0.11.13
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@ -3670,15 +3666,13 @@ snapshots:
|
|||||||
esrecurse: 4.3.0
|
esrecurse: 4.3.0
|
||||||
estraverse: 5.3.0
|
estraverse: 5.3.0
|
||||||
|
|
||||||
eslint-visitor-keys@3.4.3: {}
|
|
||||||
|
|
||||||
eslint-visitor-keys@4.2.1: {}
|
eslint-visitor-keys@4.2.1: {}
|
||||||
|
|
||||||
eslint-visitor-keys@5.0.1: {}
|
eslint-visitor-keys@5.0.1: {}
|
||||||
|
|
||||||
eslint@9.39.5:
|
eslint@9.39.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5)
|
'@eslint-community/eslint-utils': 4.10.0(eslint@9.39.5)
|
||||||
'@eslint-community/regexpp': 4.12.2
|
'@eslint-community/regexpp': 4.12.2
|
||||||
'@eslint/config-array': 0.21.2
|
'@eslint/config-array': 0.21.2
|
||||||
'@eslint/config-helpers': 0.4.2
|
'@eslint/config-helpers': 0.4.2
|
||||||
@ -4662,8 +4656,9 @@ snapshots:
|
|||||||
type-check: 0.4.0
|
type-check: 0.4.0
|
||||||
word-wrap: 1.2.5
|
word-wrap: 1.2.5
|
||||||
|
|
||||||
own-keys@1.0.1:
|
own-keys@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
call-bound: 1.0.4
|
||||||
get-intrinsic: 1.3.0
|
get-intrinsic: 1.3.0
|
||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
safe-push-apply: 1.0.0
|
safe-push-apply: 1.0.0
|
||||||
@ -4899,7 +4894,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fast-diff: 1.3.0
|
fast-diff: 1.3.0
|
||||||
|
|
||||||
prettier@3.9.5: {}
|
prettier@3.9.6: {}
|
||||||
|
|
||||||
process-nextick-args@2.0.1: {}
|
process-nextick-args@2.0.1: {}
|
||||||
|
|
||||||
|
|||||||
@ -283,7 +283,9 @@ AI 生成的图,仅供娱乐()
|
|||||||
|
|
||||||
`md5_password`: md5 加密后的密码,传入后 `password` 参数将失效
|
`md5_password`: md5 加密后的密码,传入后 `password` 参数将失效
|
||||||
|
|
||||||
`captcha`: 验证码,使用 [`/captcha/sent`](#发送验证码)接口传入手机号获取验证码,调用此接口传入验证码,可使用验证码登录,传入后 `password` 参数将失效
|
`captcha`: 验证码,使用 `/captcha/sent` 或 `/captcha/sent/v1`接口传入手机号获取验证码,调用此接口传入验证码,可使用验证码登录,传入后 `password` 参数将失效
|
||||||
|
|
||||||
|
`sca`: 网易易盾滑块验证token, 获取方式未知
|
||||||
|
|
||||||
**接口地址 :** `/login/cellphone`
|
**接口地址 :** `/login/cellphone`
|
||||||
|
|
||||||
@ -397,6 +399,19 @@ body {
|
|||||||
|
|
||||||
**调用例子 :** `/captcha/sent?phone=13xxx`
|
**调用例子 :** `/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` => `超清母带`
|
`lossless`=>`无损`, `hires`=>`Hi-Res`, `jyeffect` => `高清环绕声`, `sky` => `沉浸环绕声`, `dolby` => `杜比全景声`, `jymaster` => `超清母带`
|
||||||
`unblock`: 是否使用使用歌曲解锁, 分为`true`和`false`
|
`unblock`: 是否使用使用歌曲解锁, 分为`true`和`false`
|
||||||
|
|
||||||
|
**可选参数 :** `immerseType`: 沉浸声环绕声类型, 分为 `c51` => `c51类型`, `ste` => `环绕立体声类型`, `aac` => `aac类型`, 仅在 `level=sky` 时生效, 默认为 `c51`
|
||||||
|
|
||||||
**接口地址 :** `/song/url/v1`
|
**接口地址 :** `/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。
|
说明:`杜比全景声`音质需要设备支持,不同的设备可能会返回不同码率的 url。cookie 需要传入`os=pc`保证返回正常码率的 url。
|
||||||
|
|
||||||
@ -5493,6 +5510,14 @@ let data = encodeURIComponent(
|
|||||||
|
|
||||||
**调用例子 :** `/ad/listening/rights/gain`
|
**调用例子 :** `/ad/listening/rights/gain`
|
||||||
|
|
||||||
|
### 获取免费听时长状态
|
||||||
|
|
||||||
|
说明 : 登录后调用此接口, 获取免费听剩余时长
|
||||||
|
|
||||||
|
**接口地址 :** `/ad/listening/rights`
|
||||||
|
|
||||||
|
**调用例子 :** `/ad/listening/rights`
|
||||||
|
|
||||||
### 云小编 - 获取用户详情
|
### 云小编 - 获取用户详情
|
||||||
|
|
||||||
说明: 登录后调用此接口, 获取云小编用户详情
|
说明: 登录后调用此接口, 获取云小编用户详情
|
||||||
@ -5603,12 +5628,203 @@ let data = encodeURIComponent(
|
|||||||
|
|
||||||
`drawCount`: 未知, 默认 `1`
|
`drawCount`: 未知, 默认 `1`
|
||||||
|
|
||||||
`checkToken`: 易盾反作弊 Token, 默认自动获取
|
|
||||||
|
|
||||||
**接口地址:** `/middle/play/do/lottery`
|
**接口地址:** `/middle/play/do/lottery`
|
||||||
|
|
||||||
**调用例子:** `/middle/play/do/lottery?activityId=6501202&drawCount=1`
|
**调用例子:** `/middle/play/do/lottery?activityId=6501202&drawCount=1`
|
||||||
|
|
||||||
|
### 云小编 - 考试状态
|
||||||
|
|
||||||
|
说明: 登录后调用此接口, 查询云小编入站考试状态, 进度 (`data.process`): no: 未开始, process: 考试中, whole_exam_end: 已结束, 此时可检查 `data.hasPassExamination` 确认是否通过
|
||||||
|
|
||||||
|
**必选参数:**
|
||||||
|
|
||||||
|
`examType`: 考试类型, musicalStyleEnter: 歌曲曲风审核, languageEnter: 歌曲语种审核, oriSingerEnter: 歌曲原唱审核, emotionEnter: 情绪标签审核
|
||||||
|
|
||||||
|
**接口地址:** `/rep/ugc/exam/info/get`
|
||||||
|
|
||||||
|
**调用例子:** `/rep/ugc/exam/info/get?examType=emotionEnter`
|
||||||
|
|
||||||
|
### 云小编 - 考试开始
|
||||||
|
|
||||||
|
说明: 未考试或考试失败时调用此接口, 开始新一轮考试
|
||||||
|
|
||||||
|
**必选参数:**
|
||||||
|
|
||||||
|
`examType`: 考试类型, musicalStyleEnter: 歌曲曲风审核, languageEnter: 歌曲语种审核, oriSingerEnter: 歌曲原唱审核, emotionEnter: 情绪标签审核
|
||||||
|
|
||||||
|
**接口地址:** `/rep/ugc/exam/start`
|
||||||
|
|
||||||
|
**调用例子:** `/rep/ugc/exam/start?examType=emotionEnter`
|
||||||
|
|
||||||
|
### 云小编 - 考试取题
|
||||||
|
|
||||||
|
说明: 考试开始后调用此接口, 获取当前试题
|
||||||
|
|
||||||
|
**必选参数:**
|
||||||
|
|
||||||
|
`examType`: 考试类型, musicalStyleEnter: 歌曲曲风审核, languageEnter: 歌曲语种审核, oriSingerEnter: 歌曲原唱审核, emotionEnter: 情绪标签审核
|
||||||
|
|
||||||
|
`taskId`: 任务 ID, 首次调用 `/rep/ugc/exam/start` 获取,之后调用 `/rep/ugc/exam/info/get` 获取
|
||||||
|
|
||||||
|
**接口地址:** `/rep/ugc/exam/question/single/get`
|
||||||
|
|
||||||
|
**调用例子:** `/rep/ugc/exam/question/single/get?examType=emotionEnter&taskId=123456`
|
||||||
|
|
||||||
|
### 云小编 - 考试提交
|
||||||
|
|
||||||
|
说明: 取题后调用此接口, 提交作答结果
|
||||||
|
|
||||||
|
**必选参数:**
|
||||||
|
|
||||||
|
`examType`: 考试类型, musicalStyleEnter: 歌曲曲风审核, languageEnter: 歌曲语种审核, oriSingerEnter: 歌曲原唱审核, emotionEnter: 情绪标签审核
|
||||||
|
|
||||||
|
`taskId`: 任务 ID, 首次调用 `/rep/ugc/exam/start` 获取,之后调用 `/rep/ugc/exam/info/get` 获取
|
||||||
|
|
||||||
|
`questionId`: 试题 ID, 调用 `/rep/ugc/exam/question/single/get` 获取
|
||||||
|
|
||||||
|
`answer`: 判断结果, A: 对, B: 错
|
||||||
|
|
||||||
|
**接口地址:** `/rep/ugc/exam/submit`
|
||||||
|
|
||||||
|
**调用例子:** `/rep/ugc/exam/submit?examType=emotionEnter&taskId=123456&questionId=123456&answer=A`
|
||||||
|
|
||||||
|
### 云小编 - 考试结果
|
||||||
|
|
||||||
|
说明: 考试结束后调用此接口, 获取考试正确数与正确率
|
||||||
|
|
||||||
|
**必选参数:**
|
||||||
|
|
||||||
|
`examType`: 考试类型, musicalStyleEnter: 歌曲曲风审核, languageEnter: 歌曲语种审核, oriSingerEnter: 歌曲原唱审核, emotionEnter: 情绪标签审核
|
||||||
|
|
||||||
|
`taskId`: 任务 ID, 首次调用 `/rep/ugc/exam/start` 获取,之后调用 `/rep/ugc/exam/info/get` 获取
|
||||||
|
|
||||||
|
**接口地址:** `/rep/ugc/exam/result/get`
|
||||||
|
|
||||||
|
**调用例子:** `/rep/ugc/exam/result/get?examType=emotionEnter&taskId=123456`
|
||||||
|
|
||||||
|
### 发送/删除评论
|
||||||
|
|
||||||
|
说明 : 调用此接口,可发送评论或者删除评论
|
||||||
|
|
||||||
|
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`
|
||||||
|
|
||||||
## 离线访问此文档
|
## 离线访问此文档
|
||||||
|
|
||||||
此文档同时也是 Progressive Web Apps(PWA), 加入了 serviceWorker, 可离线访问
|
此文档同时也是 Progressive Web Apps(PWA), 加入了 serviceWorker, 可离线访问
|
||||||
|
|||||||
185
public/ugc.html
185
public/ugc.html
@ -6,6 +6,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="referrer" content="no-referrer" />
|
<meta name="referrer" content="no-referrer" />
|
||||||
<link rel="icon" href="docs/netease.png" />
|
<link rel="icon" href="docs/netease.png" />
|
||||||
|
<meta name="referrer" content="no-referrer" />
|
||||||
|
<link rel="icon" href="docs/netease.png" />
|
||||||
<title>云小编任务中心 - 网易云音乐 API Enhanced</title>
|
<title>云小编任务中心 - 网易云音乐 API Enhanced</title>
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
@ -327,6 +329,10 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#userPoint {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- Song Review ---- */
|
/* ---- Song Review ---- */
|
||||||
.song-review {
|
.song-review {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
@ -379,7 +385,7 @@
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid #e5e7eb;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
max-height: 120px;
|
max-height: 160px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
@ -419,6 +425,7 @@
|
|||||||
<div class="info-card" id="user">
|
<div class="info-card" id="user">
|
||||||
<img src="docs/netease.png" alt="头像" class="avatar" id="userAvatar" />
|
<img src="docs/netease.png" alt="头像" class="avatar" id="userAvatar" />
|
||||||
<span class="info-text" id="userName">未登录</span>
|
<span class="info-text" id="userName">未登录</span>
|
||||||
|
<span id="userPoint">0</span>
|
||||||
<button class="btn-sm green" id="userSign" disabled>签到</button>
|
<button class="btn-sm green" id="userSign" disabled>签到</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -440,7 +447,7 @@
|
|||||||
<button class="btn-sm" id="taskGet">获取任务详情</button>
|
<button class="btn-sm" id="taskGet">获取任务详情</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-card" id="task">
|
<div class="info-card" id="task">
|
||||||
<span class="info-text" id="taskInfo">[<span id="taskCount">0</span>/<span id="taskGoal">0</span>] 审核歌曲赚贡献分 (+66)</span>
|
<span class="info-text" id="taskInfo">[<span id="taskCount">0</span>/<span id="taskGoal">0</span>] 审核歌曲赚贡献分 (+<span id="taskPoint">0</span>)</span>
|
||||||
<button class="btn-sm" id="taskStart" disabled>去完成</button>
|
<button class="btn-sm" id="taskStart" disabled>去完成</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -556,6 +563,7 @@
|
|||||||
/// 用户信息 ///
|
/// 用户信息 ///
|
||||||
var userAvatar = document.getElementById('userAvatar');
|
var userAvatar = document.getElementById('userAvatar');
|
||||||
var userName = document.getElementById('userName');
|
var userName = document.getElementById('userName');
|
||||||
|
var userPoint = document.getElementById('userPoint');
|
||||||
var userSign = document.getElementById('userSign');
|
var userSign = document.getElementById('userSign');
|
||||||
var userGet = document.getElementById('userGet');
|
var userGet = document.getElementById('userGet');
|
||||||
|
|
||||||
@ -564,6 +572,7 @@
|
|||||||
var d = res.data;
|
var d = res.data;
|
||||||
if (d.imgUrl) userAvatar.src = d.imgUrl + '?param=50y50';
|
if (d.imgUrl) userAvatar.src = d.imgUrl + '?param=50y50';
|
||||||
userName.textContent = d.name || '游客' + d.id;
|
userName.textContent = d.name || '游客' + d.id;
|
||||||
|
userPoint.textContent = d.availablePoints;
|
||||||
userSign.disabled = d.signed;
|
userSign.disabled = d.signed;
|
||||||
showResult('用户信息加载成功', 'success');
|
showResult('用户信息加载成功', 'success');
|
||||||
});
|
});
|
||||||
@ -576,6 +585,7 @@
|
|||||||
var d = res.data;
|
var d = res.data;
|
||||||
userSign.disabled = d;
|
userSign.disabled = d;
|
||||||
showResult('签到' + (d ? '成功 ✓' : '失败 ✗'), d ? 'success' : 'error');
|
showResult('签到' + (d ? '成功 ✓' : '失败 ✗'), d ? 'success' : 'error');
|
||||||
|
if (d) userGet.click();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -608,21 +618,36 @@
|
|||||||
/// 审核任务 ///
|
/// 审核任务 ///
|
||||||
var taskCount = document.getElementById('taskCount');
|
var taskCount = document.getElementById('taskCount');
|
||||||
var taskGoal = document.getElementById('taskGoal');
|
var taskGoal = document.getElementById('taskGoal');
|
||||||
|
var taskPoint = document.getElementById('taskPoint');
|
||||||
var taskStartBtn = document.getElementById('taskStart');
|
var taskStartBtn = document.getElementById('taskStart');
|
||||||
var taskGetBtn = document.getElementById('taskGet');
|
var taskGetBtn = document.getElementById('taskGet');
|
||||||
|
|
||||||
taskGetBtn.onclick = function () {
|
taskGetBtn.onclick = function () {
|
||||||
request('/rep/ugc/activity/get', {}, function (res) {
|
request('rep/ugc/activity/get', {}, function (res) {
|
||||||
var d = res.data;
|
var d = res.data;
|
||||||
taskCount.textContent = d.count;
|
taskCount.textContent = d.count;
|
||||||
taskGoal.textContent = d.goalCount;
|
taskGoal.textContent = d.goalCount;
|
||||||
taskStartBtn.disabled = d.activityId !== 5001;
|
taskPoint.textContent = d.points;
|
||||||
|
// 注:超过 100 可能有 bug,导致 thinktank/audit/resource/detail 获取的任务 ID 一直是 5002,目标数量也不对,暂时限制前两个任务
|
||||||
|
taskStartBtn.disabled = d.activityId !== 5001 && d.activityId !== 5002; // 5001: 1-50, 5002: 51-100
|
||||||
showResult('任务详情加载成功', 'success');
|
showResult('任务详情加载成功', 'success');
|
||||||
|
// 任务完成,领取积分
|
||||||
|
if (d.count >= d.goalCount) {
|
||||||
|
request('rep/ugc/activity/collect', { activityId: d.activityId }, function (res) {
|
||||||
|
var d = res.data;
|
||||||
|
showResult('积分领取' + (d ? '成功,可以兑换会员了!' : '失败'), d ? 'success' : 'error');
|
||||||
|
// 刷新任务状态
|
||||||
|
if (d) loadAll();
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
taskStartBtn.onclick = function () {
|
taskStartBtn.onclick = function () {
|
||||||
if (!taskStartBtn.disabled) taskStart();
|
if (!taskStartBtn.disabled) {
|
||||||
|
songAudio.pause();
|
||||||
|
examInit();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 歌曲审核区域 ///
|
/// 歌曲审核区域 ///
|
||||||
@ -636,12 +661,93 @@
|
|||||||
var songSkip = document.getElementById('songSkip');
|
var songSkip = document.getElementById('songSkip');
|
||||||
var songLyric = document.getElementById('songLyric');
|
var songLyric = document.getElementById('songLyric');
|
||||||
|
|
||||||
|
var examType = 'emotionEnter';
|
||||||
|
// 考试初始化、检查状态
|
||||||
|
function examInit() {
|
||||||
|
request('rep/ugc/exam/info/get', { examType: examType }, function (res) {
|
||||||
|
var d = res.data;
|
||||||
|
switch (d.process) {
|
||||||
|
case 'whole_exam_end':
|
||||||
|
// 通过考试
|
||||||
|
if (d.hasPassExamination) {
|
||||||
|
taskStart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
request('rep/ugc/exam/result/get', { examType: examType, taskId: d.taskId }, function (res) {
|
||||||
|
var d = res.data;
|
||||||
|
showResult('考试未通过:正确数:' + d.wrightNum + ',正确率:' + d.wrightRate, 'error');
|
||||||
|
});
|
||||||
|
case 'no':
|
||||||
|
// 未通过或未开始
|
||||||
|
request('rep/ugc/exam/start', { examType: examType }, function (res) {
|
||||||
|
examStart(res.data.taskId);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'process':
|
||||||
|
// 正在考试
|
||||||
|
examStart(d.taskId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
showResult('未知考试进度:' + d.process, 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 在上个信息不为异常时显示考试中提示
|
||||||
|
if (d.process !== 'whole_exam_end' && !resultDiv.className.endsWith('error')) showResult('正在考试,请认真审题!', 'info');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 考试取题开始
|
||||||
|
function examStart(taskId) {
|
||||||
|
request('rep/ugc/exam/question/single/get', { examType: examType, taskId: taskId }, function (res) {
|
||||||
|
var d = res.data;
|
||||||
|
|
||||||
|
songCover.src = d.coverUrl + '?param=100y100';
|
||||||
|
songTitle.textContent = '[' + d.resId + '] ' + d.resName + ' - ' + d.artists;
|
||||||
|
songTag.textContent = '[' + (d.auditCount + 1) + '/' + d.auditTaskCount + '] 当前结果: ' + d.questionContent + '?';
|
||||||
|
songLyric.textContent = d.lyric ? d.transLyric ? lrctran(d.lyric, d.transLyric) : d.lyric : '[00:00.00] 暂无歌词';
|
||||||
|
songLyric.scrollTop = 0;
|
||||||
|
// 有时候就是没有播放链接,只能根据歌词硬审
|
||||||
|
if (d.songUrl) {
|
||||||
|
songAudio.src = d.songUrl;
|
||||||
|
songAudio.play().catch(function () { /* 自动播放被浏览器阻止 */ });
|
||||||
|
} else {
|
||||||
|
songAudio.src = ''; // 清理播放器
|
||||||
|
}
|
||||||
|
songApprove.onclick = function () { if (!songApprove.disabled) examSubmit(taskId, d.questionId, 'A') };
|
||||||
|
songReject.onclick = function () { if (!songReject.disabled) examSubmit(taskId, d.questionId, 'B') };
|
||||||
|
songSkip.onclick = null;
|
||||||
|
|
||||||
|
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||||||
|
song.style.display = 'block';
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
songApprove.disabled = songReject.disabled = false;
|
||||||
|
}, 3e3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 考试提交
|
||||||
|
function examSubmit(taskId, questionId, answer) {
|
||||||
|
songAudio.pause();
|
||||||
|
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||||||
|
request(
|
||||||
|
'rep/ugc/exam/submit',
|
||||||
|
{ examType: examType, taskId: taskId, questionId: questionId, answer: answer },
|
||||||
|
function (res) {
|
||||||
|
var d = res.data;
|
||||||
|
if (d.result) {
|
||||||
|
showResult('回答正确,加载下一首...', 'success');
|
||||||
|
} else {
|
||||||
|
showResult('回答错误:' + d.analysis, 'error');
|
||||||
|
}
|
||||||
|
examInit();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取任务
|
* 获取任务
|
||||||
*/
|
*/
|
||||||
function taskStart() {
|
function taskStart() {
|
||||||
song.style.display = 'none';
|
request('thinktank/audit/resource/detail', { type: '4' }, function (res) {
|
||||||
request('/thinktank/audit/resource/detail', { type: '4' }, function (res) {
|
|
||||||
var d = res.data;
|
var d = res.data;
|
||||||
|
|
||||||
if (d.auditCount >= 50) {
|
if (d.auditCount >= 50) {
|
||||||
@ -661,8 +767,8 @@
|
|||||||
songCover.src = d.coverUrl + '?param=100y100';
|
songCover.src = d.coverUrl + '?param=100y100';
|
||||||
songTitle.textContent = '[' + d.resId + '] ' + d.resName + ' - ' + d.artists;
|
songTitle.textContent = '[' + d.resId + '] ' + d.resName + ' - ' + d.artists;
|
||||||
songTag.textContent = '[' + (d.auditCount + 1) + '/' + d.auditTaskCount + '] 当前结果: ' + d.initResult + '?';
|
songTag.textContent = '[' + (d.auditCount + 1) + '/' + d.auditTaskCount + '] 当前结果: ' + d.initResult + '?';
|
||||||
songLyric.textContent = (d.lyric || '') + (d.transLyric || '');
|
songLyric.textContent = d.lyric ? d.transLyric ? lrctran(d.lyric, d.transLyric) : d.lyric : '[00:00.00] 暂无歌词';
|
||||||
if (!songLyric.textContent.trim()) songLyric.textContent = '[00:00.00] 暂无歌词';
|
songLyric.scrollTop = 0;
|
||||||
songAudio.src = d.songUrl;
|
songAudio.src = d.songUrl;
|
||||||
songAudio.play().catch(function () { /* 自动播放被浏览器阻止 */ });
|
songAudio.play().catch(function () { /* 自动播放被浏览器阻止 */ });
|
||||||
|
|
||||||
@ -685,6 +791,7 @@
|
|||||||
* @param {'1'|'2'|'3'} judgement
|
* @param {'1'|'2'|'3'} judgement
|
||||||
*/
|
*/
|
||||||
function taskSubmit(taskId, judgement) {
|
function taskSubmit(taskId, judgement) {
|
||||||
|
songAudio.pause();
|
||||||
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||||||
request(
|
request(
|
||||||
'thinktank/audit/resource/update',
|
'thinktank/audit/resource/update',
|
||||||
@ -692,7 +799,10 @@
|
|||||||
function (res) {
|
function (res) {
|
||||||
var d = res.data;
|
var d = res.data;
|
||||||
if (d.result) {
|
if (d.result) {
|
||||||
showResult('审核提交成功,加载下一首...', 'success');
|
showResult((d.test ? '抽查' : '审核') + '提交成功,加载下一首...', 'success');
|
||||||
|
taskStart();
|
||||||
|
} else if (d.test) {
|
||||||
|
showResult('抽查失败: [' + d.dayErrorNum + '/' + d.dayErrorNumStandard + '] ' + d.errorAnalysis, 'error');
|
||||||
taskStart();
|
taskStart();
|
||||||
} else {
|
} else {
|
||||||
showResult('未知状态: ' + JSON.stringify(d), 'error');
|
showResult('未知状态: ' + JSON.stringify(d), 'error');
|
||||||
@ -701,6 +811,61 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**解析歌词时间戳和文本 */
|
||||||
|
function lrctrim(lyrics) {
|
||||||
|
var lines = lyrics.split('\n');
|
||||||
|
var data = [];
|
||||||
|
lines.forEach(function (line, index) {
|
||||||
|
var matches = line.match(/\[(\d{2}):(\d{2}[\.:]?\d*)\]/);
|
||||||
|
if (matches) {
|
||||||
|
var minutes = parseInt(matches[1], 10);
|
||||||
|
var seconds = parseFloat(matches[2].replace('.', ':')) || 0;
|
||||||
|
var timestamp = minutes * 6e4 + seconds * 1e3;
|
||||||
|
var text = line.replace(/\[\d{2}:\d{2}[\.:]?\d*\]/g, '').trim();
|
||||||
|
text = text.replace(/\s\s+/g, ' '); // Replace multiple spaces with a single space
|
||||||
|
data.push([timestamp, index, text]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
data.sort(function (a, b) {
|
||||||
|
return a[0] - b[0];
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
/**合并原文歌词和翻译歌词 */
|
||||||
|
function lrctran(lyric, tlyric) {
|
||||||
|
lyric = lrctrim(lyric);
|
||||||
|
tlyric = lrctrim(tlyric);
|
||||||
|
var len1 = lyric.length;
|
||||||
|
var len2 = tlyric.length;
|
||||||
|
var result = '';
|
||||||
|
for (var i = 0, j = 0; i < len1 && j < len2; i++) {
|
||||||
|
while (lyric[i][0] > tlyric[j][0] && j + 1 < len2) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (lyric[i][0] === tlyric[j][0]) {
|
||||||
|
tlyric[j][2] = tlyric[j][2].replace('/', '');
|
||||||
|
if (tlyric[j][2]) {
|
||||||
|
lyric[i][2] += ' (' + tlyric[j][2] + ')';
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var k = 0; k < len1; k++) {
|
||||||
|
var t = lyric[k][0];
|
||||||
|
result += '['.concat(
|
||||||
|
String(Math.floor(t / 6e4)).padStart(2, '0'),
|
||||||
|
':',
|
||||||
|
String(Math.floor((t % 6e4) / 1e3)).padStart(2, '0'),
|
||||||
|
'.',
|
||||||
|
String(t % 1e3).padStart(3, '0'),
|
||||||
|
']',
|
||||||
|
lyric[k][2],
|
||||||
|
'\n',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// 一键载入 ///
|
/// 一键载入 ///
|
||||||
window.loadAll = function () {
|
window.loadAll = function () {
|
||||||
userGet.click();
|
userGet.click();
|
||||||
|
|||||||
@ -9,20 +9,13 @@
|
|||||||
<title>云小编每日抽奖 - 网易云音乐 API Enhanced</title>
|
<title>云小编每日抽奖 - 网易云音乐 API Enhanced</title>
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg-start: #f3f0ff;
|
|
||||||
--bg-end: #e8f4fd;
|
|
||||||
--primary: #7c6cf0;
|
|
||||||
--primary-light: #ede9fe;
|
|
||||||
--accent: #fd79a8;
|
|
||||||
--gold: #fdcb6e;
|
--gold: #fdcb6e;
|
||||||
--text: #2d3436;
|
|
||||||
--text-light: #636e72;
|
--text-light: #636e72;
|
||||||
--card-bg: #ffffff;
|
--fg: #333;
|
||||||
--border: #e8e8f0;
|
--muted: #666;
|
||||||
--shadow: 0 8px 30px rgba(108, 92, 231, 0.08);
|
--border: #ddd;
|
||||||
--radius: 20px;
|
--bg: #f5f5f5;
|
||||||
--radius-sm: 12px;
|
--panel: #ffffff;
|
||||||
--transition: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
@ -33,13 +26,13 @@
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Segoe UI', system-ui, -apple-system, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
font-family: 'Segoe UI', system-ui, -apple-system, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||||
background: linear-gradient(135deg, var(--bg-start) 0%, var(--bg-end) 50%, #fce4ec 100%);
|
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
/* align-items: center; */
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
color: var(--text);
|
color: var(--fg);
|
||||||
|
background: var(--bg);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,65 +44,77 @@
|
|||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 标题编辑卡片 */
|
/* 标题 */
|
||||||
|
.header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header p {
|
||||||
|
margin-top: 4px;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 卡片 */
|
||||||
.card {
|
.card {
|
||||||
background: var(--card-bg);
|
background: var(--panel);
|
||||||
border-radius: var(--radius);
|
|
||||||
padding: 1.8rem 2rem;
|
|
||||||
box-shadow: var(--shadow);
|
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
transition: var(--transition);
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-section {
|
/* 按钮 */
|
||||||
text-align: center;
|
button {
|
||||||
}
|
padding: 8px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
.title-input {
|
|
||||||
width: 100%;
|
|
||||||
border: 2px solid transparent;
|
|
||||||
border-radius: var(--radius-sm);
|
|
||||||
font-size: 1.6rem;
|
|
||||||
font-weight: 700;
|
|
||||||
text-align: center;
|
|
||||||
padding: 0.6rem 1rem;
|
|
||||||
color: var(--text);
|
|
||||||
background: #fafafa;
|
|
||||||
transition: var(--transition);
|
|
||||||
outline: none;
|
|
||||||
font-family: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-input:hover {
|
|
||||||
background: #f5f3ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-input:focus {
|
|
||||||
border-color: var(--primary-light);
|
|
||||||
background: #fff;
|
|
||||||
box-shadow: 0 0 0 4px rgba(124, 108, 240, 0.06);
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-hint {
|
|
||||||
font-size: 0.8rem;
|
|
||||||
color: #b2bec3;
|
|
||||||
margin-top: 0.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 抽奖主卡片 */
|
|
||||||
.lottery-card {
|
|
||||||
background: var(--card-bg);
|
|
||||||
border-radius: var(--radius);
|
|
||||||
padding: 2rem 2rem 2.2rem;
|
|
||||||
box-shadow: var(--shadow);
|
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
background: var(--panel);
|
||||||
|
color: var(--fg);
|
||||||
|
transition: all 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.primary {
|
||||||
|
background: var(--fg);
|
||||||
|
color: var(--panel);
|
||||||
|
border-color: var(--fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.primary:hover {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 页脚 */
|
||||||
|
.footer {
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
color: var(--muted);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a {
|
||||||
|
color: var(--fg);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a:hover {
|
||||||
|
border-bottom: 1px dotted var(--fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rolling-display {
|
.rolling-display {
|
||||||
font-size: 2.4rem;
|
font-size: 2.4rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: var(--primary);
|
color: #c4b5fd;
|
||||||
min-height: 4rem;
|
min-height: 4rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -121,7 +126,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rolling-display.idle {
|
.rolling-display.idle {
|
||||||
color: #c4b5fd;
|
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
@ -134,6 +138,7 @@
|
|||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
margin: 1rem 0 1.5rem;
|
margin: 1rem 0 1.5rem;
|
||||||
animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.winner-label {
|
.winner-label {
|
||||||
@ -152,6 +157,12 @@
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.winner-img {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
margin: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
.confetti-row {
|
.confetti-row {
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -198,59 +209,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 按钮 */
|
|
||||||
.btn {
|
|
||||||
padding: 0.9rem 2.5rem;
|
|
||||||
border: none;
|
|
||||||
border-radius: 50px;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 1.05rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: var(--transition);
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
width: 100%;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-lottery {
|
|
||||||
background: linear-gradient(135deg, #fd79a8, #e84393);
|
|
||||||
color: #fff;
|
|
||||||
box-shadow: 0 6px 20px rgba(253, 121, 168, 0.35);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-lottery:hover:not(:disabled) {
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 10px 28px rgba(253, 121, 168, 0.45);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-lottery:active:not(:disabled) {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-lottery:disabled {
|
|
||||||
background: #b2bec3;
|
|
||||||
box-shadow: none;
|
|
||||||
cursor: not-allowed;
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-reset {
|
|
||||||
background: transparent;
|
|
||||||
border: 2px solid var(--border);
|
|
||||||
color: var(--text-light);
|
|
||||||
margin-top: 0.8rem;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-reset:hover {
|
|
||||||
border-color: var(--primary-light);
|
|
||||||
color: var(--primary);
|
|
||||||
background: #f8f7ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 状态提示 */
|
/* 状态提示 */
|
||||||
.status-bar {
|
.status-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -288,16 +246,6 @@
|
|||||||
|
|
||||||
/* 响应式 */
|
/* 响应式 */
|
||||||
@media (max-width: 500px) {
|
@media (max-width: 500px) {
|
||||||
|
|
||||||
.card,
|
|
||||||
.lottery-card {
|
|
||||||
padding: 1.4rem 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-input {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rolling-display {
|
.rolling-display {
|
||||||
font-size: 1.8rem;
|
font-size: 1.8rem;
|
||||||
min-height: 3rem;
|
min-height: 3rem;
|
||||||
@ -312,20 +260,19 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- 标题编辑区 -->
|
<!-- 标题 -->
|
||||||
<div class="card title-section">
|
<div class="header">
|
||||||
<input type="text" class="title-input" id="titleInput" value="🎉 云小编每日抽奖 🎉" autocomplete="off" disabled>
|
<h1>🎉 云小编每日抽奖</h1>
|
||||||
<div class="title-hint">每次抽奖消耗 <b>200 个曲库编辑部积分</b>,每日最多可抽奖 3 次</div>
|
<p>每次抽奖消耗 <b>200 个曲库编辑部积分</b>,每日最多可抽奖 3 次</p>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 抽奖 -->
|
||||||
<!-- 抽奖主区域 -->
|
<div class="card">
|
||||||
<div class="lottery-card">
|
|
||||||
<div class="rolling-display idle" id="rollingDisplay">等待抽奖</div>
|
<div class="rolling-display idle" id="rollingDisplay">等待抽奖</div>
|
||||||
<div id="resultContainer"></div>
|
<div id="resultContainer"></div>
|
||||||
<button class="btn btn-lottery" id="lotteryBtn">
|
<button id="lotteryBtn" class="primary">
|
||||||
<span>🎲</span> 开始抽奖
|
<span>🎲</span> 开始抽奖
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-reset" id="resetBtn">
|
<button id="resetBtn">
|
||||||
<span>🔄</span> 编辑令牌
|
<span>🔄</span> 编辑令牌
|
||||||
</button>
|
</button>
|
||||||
<div class="status-bar" id="statusBar">
|
<div class="status-bar" id="statusBar">
|
||||||
@ -333,12 +280,15 @@
|
|||||||
<span id="statusText">就绪,点击按钮开始抽奖</span>
|
<span id="statusText">就绪,点击按钮开始抽奖</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 页脚 -->
|
||||||
|
<div class="footer">
|
||||||
|
<a href="/">← 返回首页</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
// ============ DOM 元素 ============
|
// ============ DOM 元素 ============
|
||||||
const titleInput = document.getElementById('titleInput');
|
|
||||||
const rollingDisplay = document.getElementById('rollingDisplay');
|
const rollingDisplay = document.getElementById('rollingDisplay');
|
||||||
const resultContainer = document.getElementById('resultContainer');
|
const resultContainer = document.getElementById('resultContainer');
|
||||||
const lotteryBtn = document.getElementById('lotteryBtn');
|
const lotteryBtn = document.getElementById('lotteryBtn');
|
||||||
@ -420,19 +370,21 @@
|
|||||||
const res = await request('middle/play/do/lottery', '&activityId=6501202&drawCount=1');
|
const res = await request('middle/play/do/lottery', '&activityId=6501202&drawCount=1');
|
||||||
|
|
||||||
// 根据你的后端返回格式提取中奖者名称
|
// 根据你的后端返回格式提取中奖者名称
|
||||||
const winner = res.data?.prizeDetailInfoMap?.['8186002']?.prizeName;
|
const prizeMap = res.data?.prizeDetailInfoMap || {};
|
||||||
if (!winner) {
|
for (var k in prizeMap) break; // 取第一个奖品 ID
|
||||||
|
const prize = k ? prizeMap[k] : null;
|
||||||
|
if (!prize) {
|
||||||
throw new Error('无法解析响应数据');
|
throw new Error('无法解析响应数据');
|
||||||
}
|
}
|
||||||
|
|
||||||
// [抽奖结果, 剩余机会]
|
// [抽奖结果, 剩余机会, 奖品图片]
|
||||||
return [winner, res.data.restChance];
|
return [prize.prizeName, res.data.restChance, prize.prizeImgList[0] || ''];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ 滚动动画 ============
|
// ============ 滚动动画 ============
|
||||||
function startRollingAnimation(finalWinner) {
|
function startRollingAnimation(finalWinner, img) {
|
||||||
const placeholderNames = ['🎰', '🎲', '🎯', '✨', '💫', '🌟', '🎪', '🎭'];
|
const placeholderNames = ['🎰', '🎲', '🎯', '✨', '💫', '🌟', '🎪', '🎭'];
|
||||||
const totalDuration = 2800;
|
const totalDuration = 2000;
|
||||||
const startInterval = 50;
|
const startInterval = 50;
|
||||||
const endInterval = 280;
|
const endInterval = 280;
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
@ -454,7 +406,8 @@
|
|||||||
// 动画结束,显示真实结果
|
// 动画结束,显示真实结果
|
||||||
clearTimeout(rollingTimer);
|
clearTimeout(rollingTimer);
|
||||||
rollingDisplay.textContent = finalWinner;
|
rollingDisplay.textContent = finalWinner;
|
||||||
showWinnerResult(finalWinner);
|
rollingDisplay.style.display = 'none';
|
||||||
|
showWinnerResult(finalWinner, img);
|
||||||
finishDrawing();
|
finishDrawing();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -465,11 +418,12 @@
|
|||||||
roll();
|
roll();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showWinnerResult(winner) {
|
function showWinnerResult(winner, img) {
|
||||||
resultContainer.innerHTML = `
|
resultContainer.innerHTML = `
|
||||||
<div class="winner-display">
|
<div class="winner-display">
|
||||||
<div class="winner-label">🏆 恭喜中奖</div>
|
<div class="winner-label">🏆 恭喜中奖</div>
|
||||||
<div class="winner-name">${escapeHTML(winner)}</div>
|
<div class="winner-name">${escapeHTML(winner)}</div>
|
||||||
|
<img src="${img}" alt="奖品图片" class="winner-img" />
|
||||||
<div class="confetti-row">
|
<div class="confetti-row">
|
||||||
<span class="confetti-emoji">🎉</span>
|
<span class="confetti-emoji">🎉</span>
|
||||||
<span class="confetti-emoji">🎊</span>
|
<span class="confetti-emoji">🎊</span>
|
||||||
@ -503,6 +457,7 @@
|
|||||||
resultContainer.innerHTML = '';
|
resultContainer.innerHTML = '';
|
||||||
rollingDisplay.className = 'rolling-display';
|
rollingDisplay.className = 'rolling-display';
|
||||||
rollingDisplay.textContent = '🎰';
|
rollingDisplay.textContent = '🎰';
|
||||||
|
rollingDisplay.style.display = 'flex';
|
||||||
setStatus('info', '正在获取抽奖结果...');
|
setStatus('info', '正在获取抽奖结果...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -510,7 +465,7 @@
|
|||||||
const res = await fetchLotteryResult();
|
const res = await fetchLotteryResult();
|
||||||
setStatus('info', '抽奖成功,剩余次数 ' + res[1]);
|
setStatus('info', '抽奖成功,剩余次数 ' + res[1]);
|
||||||
// 启动滚动动画,最终定格在中奖者
|
// 启动滚动动画,最终定格在中奖者
|
||||||
startRollingAnimation(res[0]);
|
startRollingAnimation(res[0], res[2]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 请求失败处理
|
// 请求失败处理
|
||||||
rollingDisplay.textContent = '抽奖失败';
|
rollingDisplay.textContent = '抽奖失败';
|
||||||
@ -528,7 +483,7 @@
|
|||||||
|
|
||||||
// 空格键快捷抽奖
|
// 空格键快捷抽奖
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
if (e.key === ' ' && document.activeElement !== titleInput) {
|
if (e.key === ' ') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!isDrawing && !lotteryBtn.disabled) {
|
if (!isDrawing && !lotteryBtn.disabled) {
|
||||||
startLottery();
|
startLottery();
|
||||||
@ -538,6 +493,12 @@
|
|||||||
|
|
||||||
// ============ 初始化 ============
|
// ============ 初始化 ============
|
||||||
resetResult();
|
resetResult();
|
||||||
|
|
||||||
|
window.demo = function (name, chance, img) {
|
||||||
|
rollingDisplay.style.display = 'flex';
|
||||||
|
setStatus('info', '抽奖成功,剩余次数 ' + (chance || '0'));
|
||||||
|
startRollingAnimation(name || '演示', img || 'https://p5.music.126.net/obj/worDmcOCw6HCnzzCmsKx/61891591760/8d1c/528a/e977/10cbaa3fb39e8057be5d2560182cc5c7.png');
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"APP_CONF": {
|
"APP_CONF": {
|
||||||
"apiDomain": "https://interface.music.163.com",
|
"apiDomain": "https://interface.music.163.com",
|
||||||
|
"eapiDomain": "https://interfacepc.music.163.com",
|
||||||
"xeapiDomain": "https://interface3.music.163.com",
|
"xeapiDomain": "https://interface3.music.163.com",
|
||||||
"domain": "https://music.163.com",
|
"domain": "https://music.163.com",
|
||||||
"clDomian": "https://clientlog.music.163.com",
|
"clDomian": "https://clientlog.music.163.com",
|
||||||
|
|||||||
@ -112,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',
|
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
||||||
},
|
},
|
||||||
api: {
|
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:
|
android:
|
||||||
'NeteaseMusic/9.1.65.240927161425(9001065);Dalvik/2.1.0 (Linux; U; Android 14; 23013RK75C Build/UKQ1.230804.001)',
|
'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)',
|
iphone: 'NeteaseMusic 9.0.90/5038 (iPhone; iOS 16.2; zh_CN)',
|
||||||
@ -122,6 +122,7 @@ const userAgentMap = {
|
|||||||
// 预先定义常量
|
// 预先定义常量
|
||||||
const DOMAIN = APP_CONF.domain
|
const DOMAIN = APP_CONF.domain
|
||||||
const API_DOMAIN = APP_CONF.apiDomain
|
const API_DOMAIN = APP_CONF.apiDomain
|
||||||
|
const EAPI_DOMAIN = APP_CONF.eapiDomain
|
||||||
const XEAPI_DOMAIN = APP_CONF.xeapiDomain
|
const XEAPI_DOMAIN = APP_CONF.xeapiDomain
|
||||||
const ENCRYPT_RESPONSE = APP_CONF.encryptResponse
|
const ENCRYPT_RESPONSE = APP_CONF.encryptResponse
|
||||||
const SPECIAL_STATUS_CODES = new Set([201, 302, 400, 502, 800, 801, 802, 803])
|
const SPECIAL_STATUS_CODES = new Set([201, 302, 400, 502, 800, 801, 802, 803])
|
||||||
@ -242,6 +243,9 @@ const createRequest = (uri, data, options) => {
|
|||||||
headers['Referer'] = options.domain || DOMAIN
|
headers['Referer'] = options.domain || DOMAIN
|
||||||
headers['User-Agent'] = options.ua || chooseUserAgent('weapi')
|
headers['User-Agent'] = options.ua || chooseUserAgent('weapi')
|
||||||
data.csrf_token = csrfToken
|
data.csrf_token = csrfToken
|
||||||
|
if (options.checkToken) {
|
||||||
|
headers['X-antiCheatToken'] = token
|
||||||
|
}
|
||||||
encryptData = encrypt.weapi(data)
|
encryptData = encrypt.weapi(data)
|
||||||
url = (options.domain || DOMAIN) + '/weapi/' + uri.substr(5)
|
url = (options.domain || DOMAIN) + '/weapi/' + uri.substr(5)
|
||||||
break
|
break
|
||||||
@ -342,7 +346,7 @@ const createRequest = (uri, data, options) => {
|
|||||||
data.header = header
|
data.header = header
|
||||||
|
|
||||||
encryptData = encrypt.eapi(uri, data)
|
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') {
|
} else if (crypto === 'api') {
|
||||||
url = (options.domain || API_DOMAIN) + uri
|
url = (options.domain || API_DOMAIN) + uri
|
||||||
encryptData = data
|
encryptData = data
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user