diff --git a/module/ad_listening_rights.js b/module/ad_listening_rights.js new file mode 100644 index 0000000..6fd20fa --- /dev/null +++ b/module/ad_listening_rights.js @@ -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'), + ) +} diff --git a/module/captcha_safe_sent.js b/module/captcha_safe_sent.js new file mode 100644 index 0000000..2f5be2a --- /dev/null +++ b/module/captcha_safe_sent.js @@ -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'), + ) +} diff --git a/module/captcha_sent_v1.js b/module/captcha_sent_v1.js new file mode 100644 index 0000000..b5a6ad6 --- /dev/null +++ b/module/captcha_sent_v1.js @@ -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'), + ) +} diff --git a/module/cellphone_existence_check.js b/module/cellphone_existence_check.js index 5d43126..6cf19a1 100644 --- a/module/cellphone_existence_check.js +++ b/module/cellphone_existence_check.js @@ -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'), + ) } diff --git a/module/comment_add.js b/module/comment_add.js new file mode 100644 index 0000000..9a5ba06 --- /dev/null +++ b/module/comment_add.js @@ -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'), + ) +} diff --git a/module/comment_delete.js b/module/comment_delete.js new file mode 100644 index 0000000..e25fa47 --- /dev/null +++ b/module/comment_delete.js @@ -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'), + ) +} diff --git a/module/comment_reply.js b/module/comment_reply.js new file mode 100644 index 0000000..7bc8f3b --- /dev/null +++ b/module/comment_reply.js @@ -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'), + ) +} diff --git a/module/device_kickoff.js b/module/device_kickoff.js new file mode 100644 index 0000000..c3b9c76 --- /dev/null +++ b/module/device_kickoff.js @@ -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'), + ) +} diff --git a/module/device_list.js b/module/device_list.js new file mode 100644 index 0000000..4134917 --- /dev/null +++ b/module/device_list.js @@ -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'), + ) +} diff --git a/module/login_cellphone.js b/module/login_cellphone.js index c1d8d45..66c0ce8 100644 --- a/module/login_cellphone.js +++ b/module/login_cellphone.js @@ -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`, diff --git a/module/middle_play_do_lottery.js b/module/middle_play_do_lottery.js index f2a8e89..6ef5d9d 100644 --- a/module/middle_play_do_lottery.js +++ b/module/middle_play_do_lottery.js @@ -16,15 +16,9 @@ module.exports = (query, request) => { activityId: query.activityId || '6501202', drawCount: query.drawCount || '1', } - // TODO: 如何传递 checkToken - const optionQuery = { ...query } - if (query.checkToken) { - data.checkToken = query.checkToken - delete query.checkToken - } return request( `/api/middle/play/do/lottery`, data, - createOption(optionQuery, 'eapi', 'v2'), + createOption(query, 'eapi', 'v3'), ) } diff --git a/module/register_checktoken_v2.js b/module/register_checktoken_v2.js index f2b47aa..86faf23 100644 --- a/module/register_checktoken_v2.js +++ b/module/register_checktoken_v2.js @@ -34,5 +34,24 @@ module.exports = async (query) => { } } +// 模块加载时自动获取一次 Token,确保 request.js 使用时不为空 +fetch() + .then((token) => { + _token = token + }) + .catch(() => { + // 静默失败,后续请求时会重试 + }) + // 给 request.js 读取用 -module.exports.getToken = () => _token +module.exports.getToken = () => { + if (!_token) { + // 如果 Token 为空,异步触发获取 + fetch() + .then((token) => { + _token = token + }) + .catch(() => {}) + } + return _token +} diff --git a/module/rep_ugc_exam_info_get.js b/module/rep_ugc_exam_info_get.js new file mode 100644 index 0000000..62fee45 --- /dev/null +++ b/module/rep_ugc_exam_info_get.js @@ -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'), + ) +} diff --git a/module/rep_ugc_exam_question_single_get.js b/module/rep_ugc_exam_question_single_get.js new file mode 100644 index 0000000..7a35921 --- /dev/null +++ b/module/rep_ugc_exam_question_single_get.js @@ -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'), + ) +} diff --git a/module/rep_ugc_exam_result_get.js b/module/rep_ugc_exam_result_get.js new file mode 100644 index 0000000..9d21f43 --- /dev/null +++ b/module/rep_ugc_exam_result_get.js @@ -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'), + ) +} diff --git a/module/rep_ugc_exam_start.js b/module/rep_ugc_exam_start.js new file mode 100644 index 0000000..b19347b --- /dev/null +++ b/module/rep_ugc_exam_start.js @@ -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')) +} diff --git a/module/rep_ugc_exam_submit.js b/module/rep_ugc_exam_submit.js new file mode 100644 index 0000000..2b38f8f --- /dev/null +++ b/module/rep_ugc_exam_submit.js @@ -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')) +} diff --git a/module/song_url_v1.js b/module/song_url_v1.js index 3a9c326..d5d9c1a 100644 --- a/module/song_url_v1.js +++ b/module/song_url_v1.js @@ -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`, diff --git a/package.json b/package.json index 84fe8f3..2de4a07 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "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版本后开始自行维护", "scripts": { "dev": "nodemon app.js", @@ -98,8 +98,8 @@ "@types/express-fileupload": "^1.5.1", "@types/mocha": "^10.0.10", "@types/node": "25.9.2", - "@typescript-eslint/eslint-plugin": "^8.64.0", - "@typescript-eslint/parser": "^8.64.0", + "@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", @@ -112,7 +112,7 @@ "nodemon": "^3.1.14", "pkg": "^5.8.1", "power-assert": "^1.6.1", - "prettier": "^3.9.5", + "prettier": "^3.9.6", "typescript": "^5.9.3" }, "publishConfig": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 30a9e02..fb3e32f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -73,11 +73,11 @@ importers: specifier: 25.9.2 version: 25.9.2 '@typescript-eslint/eslint-plugin': - specifier: ^8.64.0 - version: 8.64.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3) + 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.64.0 - version: 8.64.0(eslint@9.39.5)(typescript@5.9.3) + specifier: ^8.65.0 + version: 8.65.0(eslint@9.39.5)(typescript@5.9.3) eslint: specifier: ^9.39.5 version: 9.39.5 @@ -89,7 +89,7 @@ importers: version: 8.1.4 eslint-plugin-prettier: 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: 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.5 - version: 3.9.5 + 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 @@ -301,63 +301,63 @@ packages: '@types/serve-static@2.2.0': resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - '@typescript-eslint/eslint-plugin@8.64.0': - resolution: {integrity: sha512-CGvQPBxN3wZLu6Rz2kFUpZeoCm78xUic92ck39KPePkO1NPOwjCqdQnm5Q87tpWw9vcBvW8XLrDXjH9PWYtJ3Q==} + '@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.64.0 + '@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.64.0': - resolution: {integrity: sha512-KA0OshtlcCCXmbfqyZkM5pV3/WNraJf7DkJRLpyrmwPtud57H5BDX7C3k0LPSPxpprfRL+cJDGabF10mvNCoCw==} + '@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.64.0': - resolution: {integrity: sha512-tk4WpOJ6IEbGrVHaNmM0YRrwAD3exZlIK3iadQNAxh4YKk6jvUQ4ecq18n+v7+meh+cJ3j+D8nbk8sRKhlwLQg==} + '@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.64.0': - resolution: {integrity: sha512-CXEaFdYXjSTgKhisNkwCcJwTP8Pl+fmRrEQrri4nm3vU743bALrxzLmq7fHG/7e6a5xO0lDYeURpZmBuhHk54w==} + '@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.64.0': - resolution: {integrity: sha512-2yo8rRNKuzbVWQp5kslhANqZ2uDAeROQHBRZNPu8JDsHmeFNj/XJJhX/FhNUWmkHHvoNsKa6+tHJiig87EzsQw==} + '@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.64.0': - resolution: {integrity: sha512-XWG4Fmmv/6SvyS9nH8jWrKs6terwJvE8cyRt1CzYYqzp9OrPhCT4cMc/f7C6RZCwG+qMmiffJS1/qJP8G1URtg==} + '@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.64.0': - resolution: {integrity: sha512-qjhfuTfLXjA4IOzXvz0rTjT01BqEiIgPoUeMwiEjnaHKJMTNo8rH5pYW1a2L/0Dnux2fPC85AeyJoWaGa8WxTA==} + '@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.64.0': - resolution: {integrity: sha512-Pztpsn1aCE1oWDvDEfUk31nngvvF7vUB5SwHFEaZIFpvw7WJtqUHHL4plBZDA9HfWJJjL13BdG0YrJInTUvoVA==} + '@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.64.0': - resolution: {integrity: sha512-aJUGVB3+U0htrrCjoA8qukw8cm8fNCGAxK/tVoS70k8aeb7DETKeFozRiVFIwEeN9WJLsjaP3ph8I60tY2XZoQ==} + '@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.64.0': - resolution: {integrity: sha512-mrtuL8Nsn6gi2H4mo5KMTp823M+3Q19Ew/i+Zlikq20tIMm99C3Ez0dCmkWWnxut20esQvTg8aUSEhMcAOXhEw==} + '@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': @@ -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} @@ -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: @@ -2006,8 +2002,8 @@ packages: resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} - prettier@3.9.5: - resolution: {integrity: sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==} + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} engines: {node: '>=14'} hasBin: true @@ -2687,10 +2683,10 @@ snapshots: '@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: eslint: 9.39.5 - eslint-visitor-keys: 3.4.3 + eslint-visitor-keys: 5.0.1 '@eslint-community/regexpp@4.12.2': {} @@ -2867,14 +2863,14 @@ snapshots: '@types/http-errors': 2.0.5 '@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: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.64.0(eslint@9.39.5)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.64.0 - '@typescript-eslint/type-utils': 8.64.0(eslint@9.39.5)(typescript@5.9.3) - '@typescript-eslint/utils': 8.64.0(eslint@9.39.5)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.64.0 + '@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 @@ -2883,41 +2879,41 @@ snapshots: transitivePeerDependencies: - 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: - '@typescript-eslint/scope-manager': 8.64.0 - '@typescript-eslint/types': 8.64.0 - '@typescript-eslint/typescript-estree': 8.64.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.64.0 + '@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.5 typescript: 5.9.3 transitivePeerDependencies: - 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: - '@typescript-eslint/tsconfig-utils': 8.64.0(typescript@5.9.3) - '@typescript-eslint/types': 8.64.0 + '@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.64.0': + '@typescript-eslint/scope-manager@8.65.0': dependencies: - '@typescript-eslint/types': 8.64.0 - '@typescript-eslint/visitor-keys': 8.64.0 + '@typescript-eslint/types': 8.65.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: 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: - '@typescript-eslint/types': 8.64.0 - '@typescript-eslint/typescript-estree': 8.64.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.64.0(eslint@9.39.5)(typescript@5.9.3) + '@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.5 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -2925,14 +2921,14 @@ snapshots: transitivePeerDependencies: - 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: - '@typescript-eslint/project-service': 8.64.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.64.0(typescript@5.9.3) - '@typescript-eslint/types': 8.64.0 - '@typescript-eslint/visitor-keys': 8.64.0 + '@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.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: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5) - '@typescript-eslint/scope-manager': 8.64.0 - '@typescript-eslint/types': 8.64.0 - '@typescript-eslint/typescript-estree': 8.64.0(typescript@5.9.3) + '@eslint-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.64.0': + '@typescript-eslint/visitor-keys@8.65.0': dependencies: - '@typescript-eslint/types': 8.64.0 + '@typescript-eslint/types': 8.65.0 eslint-visitor-keys: 5.0.1 '@unblockneteasemusic/server@0.28.0': @@ -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 @@ -3656,10 +3652,10 @@ snapshots: dependencies: 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: eslint: 9.39.5 - prettier: 3.9.5 + prettier: 3.9.6 prettier-linter-helpers: 1.0.1 synckit: 0.11.13 optionalDependencies: @@ -3670,15 +3666,13 @@ snapshots: 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.5: 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/config-array': 0.21.2 '@eslint/config-helpers': 0.4.2 @@ -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 @@ -4899,7 +4894,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.9.5: {} + prettier@3.9.6: {} process-nextick-args@2.0.1: {} diff --git a/public/docs/home.md b/public/docs/home.md index 67feb22..d9e97c5 100644 --- a/public/docs/home.md +++ b/public/docs/home.md @@ -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。 @@ -5493,6 +5510,14 @@ let data = encodeURIComponent( **调用例子 :** `/ad/listening/rights/gain` +### 获取免费听时长状态 + +说明 : 登录后调用此接口, 获取免费听剩余时长 + +**接口地址 :** `/ad/listening/rights` + +**调用例子 :** `/ad/listening/rights` + ### 云小编 - 获取用户详情 说明: 登录后调用此接口, 获取云小编用户详情 @@ -5603,12 +5628,203 @@ let data = encodeURIComponent( `drawCount`: 未知, 默认 `1` -`checkToken`: 易盾反作弊 Token, 默认自动获取 - **接口地址:** `/middle/play/do/lottery` **调用例子:** `/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, 可离线访问 diff --git a/public/ugc.html b/public/ugc.html index 8876c3a..288c8ce 100644 --- a/public/ugc.html +++ b/public/ugc.html @@ -6,6 +6,8 @@ + +