diff --git a/README.MD b/README.MD index b83f6ed..5a8bd7c 100644 --- a/README.MD +++ b/README.MD @@ -225,6 +225,8 @@ pnpm test [chaunsin/netease-cloud-music](https://github.com/chaunsin/netease-cloud-music) +[folltoshe/netease-report-listen-song](https://github.com/folltoshe/netease-report-listen-song) + ### SDK 生态 | 语言 | 作者 | 地址 | 类型 | diff --git a/module/scrobble.js b/module/scrobble.js index f8948c1..7adf91e 100644 --- a/module/scrobble.js +++ b/module/scrobble.js @@ -1,6 +1,8 @@ // 听歌打卡 const createOption = require('../util/option.js') +const { APP_CONF } = require('../util/config.json') +const DOMAIN = APP_CONF.clDomian module.exports = async (query, request) => { // 注入 os=osx 的 cookie let cookie = query.cookie || '' @@ -56,7 +58,7 @@ module.exports = async (query, request) => { } const option = createOption(query, 'eapi') - option.domain = 'https://clientlog.music.163.com' + option.domain = DOMAIN // 发送两次请求 const res1 = await request(`/api/feedback/weblog`, startplayData, option) diff --git a/module/scrobble_v1.js b/module/scrobble_v1.js new file mode 100644 index 0000000..84c3658 --- /dev/null +++ b/module/scrobble_v1.js @@ -0,0 +1,128 @@ +// 听歌打卡 - NCBL 加密版 (仿桌面客户端 PLV/PLD 上报) +// 复制自 https://github.com/folltoshe/netease-report-listen-song 的 PC 端日志上报方式 +// +// PLV 和 PLD 分两次独立上传 + +const { + buildPlv, + buildPld, + buildRecords, + extractContext, + parseCookie, + buildCookieStr, + buildMetaJson, + doUpload, +} = require('../util/ncbl') + +module.exports = async (query, request) => { + // --- 参数校验 --- + const songId = Number(query.id) + if (!songId || isNaN(songId)) { + return { status: 400, body: { code: 400, msg: '缺少有效的 id (歌曲ID)' } } + } + const playTime = Number(query.time) + if (isNaN(playTime) || playTime <= 0) { + return { + status: 400, + body: { code: 400, msg: '缺少有效的 time (播放时长)' }, + } + } + const totalTime = Number(query.total) || playTime + const sourceId = String(query.sourceid || query.sourceId || '') + const sourceName = query.source || 'list' + + // --- 解析认证上下文 --- + const rawCookie = query.cookie || '' + const cookieObj = parseCookie(rawCookie) + cookieObj.os = 'pc' + const ctx = extractContext(cookieObj) + + // 兜底取 token + if (!ctx.auth.token && rawCookie) { + const parsed = + typeof rawCookie === 'string' ? parseCookie(rawCookie) : rawCookie + ctx.auth.token = parsed.MUSIC_U || '' + } + + if (!ctx.auth.token) { + return { status: 401, body: { code: 401, msg: '缺少 MUSIC_U 鉴权令牌' } } + } + + // --- 构建歌曲和来源 --- + const song = { + id: songId, + name: query.name || '', + artist: query.artist || '', + bitrate: Number(query.bitrate) || 320, + level: query.level || 'exhigh', + vip: query.vip === 'true' || query.vip === true, + time: totalTime, + } + const source = { + id: sourceId || String(songId), + type: 'track', + name: sourceName, + } + + const metaJson = buildMetaJson(ctx) + const cookieStr = buildCookieStr(ctx) + + const ts = Math.floor(Date.now() / 1000) + const played = Math.min(playTime, totalTime) + + const plvBody = buildRecords([ + { time: ts, action: '_plv', data: buildPlv(ctx, song, source) }, + ]) + const pldBody = buildRecords([ + { time: ts, action: '_pld', data: buildPld(ctx, song, source, played) }, + ]) + + try { + // 1) 上传 PLV + const plv = await doUpload(ctx, metaJson, plvBody, cookieStr, 'PLV') + if (!plv.success) { + const rateMsg = + plv.respBody?.data?.rate != null + ? ` (rate=${plv.respBody.data.rate})` + : '' + return { + status: 200, + body: { + code: plv.respBody?.code || -1, + msg: `PLV 上报失败${rateMsg}`, + details: plv.respBody, + }, + } + } + + // 2) 上传 PLD + const pld = await doUpload(ctx, metaJson, pldBody, cookieStr, 'PLD') + if (!pld.success) { + return { + status: 200, + body: { + code: pld.respBody?.code || -1, + msg: 'PLV 成功但 PLD 失败', + details: { plv: plv.respBody, pld: pld.respBody }, + }, + } + } + + return { + status: 200, + body: { + code: 200, + data: 'scrobble_v1 上报成功', + details: { + plv: { fileName: plv.fileName, payloadSize: plv.payload.length }, + pld: { fileName: pld.fileName, payloadSize: pld.payload.length }, + }, + }, + } + } catch (err) { + return { + status: 502, + body: { code: 502, msg: `请求异常: ${err.message || err}` }, + } + } +} diff --git a/package.json b/package.json index fd8b385..b3cf41a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@neteasecloudmusicapienhanced/api", - "version": "4.35.2", + "version": "4.36.0", "description": "全网最全的网易云音乐API接口 || A revival project for NeteaseCloudMusicApi Node.js Services (Half Refactor & Enhanced) || 网易云音乐 API 备份 + 增强 || 本项目自原版v4.28.0版本后开始自行维护", "scripts": { "dev": "nodemon app.js", @@ -75,8 +75,8 @@ "data" ], "dependencies": { - "@neteasecloudmusicapienhanced/unblockmusic-utils": "^0.3.2", - "axios": "^1.17.0", + "@neteasecloudmusicapienhanced/unblockmusic-utils": "^0.3.3", + "axios": "^1.18.0", "crypto-js": "^4.2.0", "dotenv": "^17.4.2", "express": "^5.2.1", @@ -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.60.1", - "@typescript-eslint/parser": "^8.60.1", + "@typescript-eslint/eslint-plugin": "^8.61.1", + "@typescript-eslint/parser": "^8.61.1", "eslint": "^9.39.4", "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.8.3", + "prettier": "^3.8.4", "typescript": "^5.9.3" }, "publishConfig": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98f628c..3da8f13 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,11 +9,11 @@ importers: .: dependencies: '@neteasecloudmusicapienhanced/unblockmusic-utils': - specifier: ^0.3.2 - version: 0.3.2 + specifier: ^0.3.3 + version: 0.3.3 axios: - specifier: ^1.17.0 - version: 1.17.0 + specifier: ^1.18.0 + version: 1.18.0 crypto-js: specifier: ^4.2.0 version: 4.2.0 @@ -73,11 +73,11 @@ importers: specifier: 25.9.2 version: 25.9.2 '@typescript-eslint/eslint-plugin': - specifier: ^8.60.1 - version: 8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + specifier: ^8.61.1 + version: 8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: ^8.60.1 - version: 8.60.1(eslint@9.39.4)(typescript@5.9.3) + specifier: ^8.61.1 + version: 8.61.1(eslint@9.39.4)(typescript@5.9.3) eslint: specifier: ^9.39.4 version: 9.39.4 @@ -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.4))(eslint@9.39.4)(prettier@3.8.3) + version: 5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4))(eslint@9.39.4)(prettier@3.8.4) globals: specifier: ^17.6.0 version: 17.6.0 @@ -115,8 +115,8 @@ importers: specifier: ^1.6.1 version: 1.6.1 prettier: - specifier: ^3.8.3 - version: 3.8.3 + specifier: ^3.8.4 + version: 3.8.4 typescript: specifier: ^5.9.3 version: 5.9.3 @@ -222,8 +222,8 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@neteasecloudmusicapienhanced/unblockmusic-utils@0.3.2': - resolution: {integrity: sha512-H1ckEDXxR+sLUZKzCPhlP8kfSKgEZZp8GSL4+2BZcmCyerwCbSZzMxX9doacHfFjThRjmq90DbsrRnhnKAvrzA==} + '@neteasecloudmusicapienhanced/unblockmusic-utils@0.3.3': + resolution: {integrity: sha512-Lm2Zxod4Qfhp3HNDmaHxzJPLiMfMNkUT2PXp0VVrDW+/dDZBfSANO+pnCHx+MkK7tDUb3wGwYp5q2w9Kw1+4OA==} hasBin: true '@nodelib/fs.scandir@2.1.5': @@ -301,63 +301,63 @@ packages: '@types/serve-static@2.2.0': resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - '@typescript-eslint/eslint-plugin@8.60.1': - resolution: {integrity: sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==} + '@typescript-eslint/eslint-plugin@8.61.1': + resolution: {integrity: sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.60.1 + '@typescript-eslint/parser': ^8.61.1 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.60.1': - resolution: {integrity: sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==} + '@typescript-eslint/parser@8.61.1': + resolution: {integrity: sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==} 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.60.1': - resolution: {integrity: sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==} + '@typescript-eslint/project-service@8.61.1': + resolution: {integrity: sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.60.1': - resolution: {integrity: sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==} + '@typescript-eslint/scope-manager@8.61.1': + resolution: {integrity: sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.60.1': - resolution: {integrity: sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==} + '@typescript-eslint/tsconfig-utils@8.61.1': + resolution: {integrity: sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.60.1': - resolution: {integrity: sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==} + '@typescript-eslint/type-utils@8.61.1': + resolution: {integrity: sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==} 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.60.1': - resolution: {integrity: sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==} + '@typescript-eslint/types@8.61.1': + resolution: {integrity: sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.60.1': - resolution: {integrity: sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==} + '@typescript-eslint/typescript-estree@8.61.1': + resolution: {integrity: sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.60.1': - resolution: {integrity: sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==} + '@typescript-eslint/utils@8.61.1': + resolution: {integrity: sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==} 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.60.1': - resolution: {integrity: sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==} + '@typescript-eslint/visitor-keys@8.61.1': + resolution: {integrity: sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unblockneteasemusic/server@0.28.0': @@ -386,8 +386,8 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} engines: {node: '>=0.4.0'} hasBin: true @@ -485,8 +485,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axios@1.17.0: - resolution: {integrity: sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==} + axios@1.18.0: + resolution: {integrity: sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -513,8 +513,8 @@ packages: resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} engines: {node: '>=18'} brace-expansion@1.1.15: @@ -864,6 +864,10 @@ packages: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} + es-abstract-get@1.0.0: + resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} + engines: {node: '>= 0.4'} + es-abstract@1.24.2: resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} engines: {node: '>= 0.4'} @@ -884,8 +888,8 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + es-to-primitive@1.3.1: + resolution: {integrity: sha512-CxN9N56HYfd2m/acc/NOFrZQsN9kU4eh+2kk6A707Kz1krH8tKmfrs5RnftB8WNX80T0NS7vSQsDOlg23diR2g==} engines: {node: '>= 0.4'} es5-ext@0.10.64: @@ -1169,8 +1173,8 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} engines: {node: '>= 6'} forwarded@0.2.0: @@ -1203,8 +1207,8 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + function.prototype.name@1.2.0: + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} engines: {node: '>= 0.4'} functions-have-names@1.2.3: @@ -1447,6 +1451,10 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-document.all@1.0.0: + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1998,8 +2006,8 @@ packages: resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} - prettier@3.8.3: - resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + prettier@3.8.4: + resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} engines: {node: '>=14'} hasBin: true @@ -2153,8 +2161,8 @@ packages: secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} - semver@7.8.3: - resolution: {integrity: sha512-wnilbGyMxzbY7dNOl7jpKbLSjcfeweJWU5j4+u5qW+6/wuGD9KzIGOyZnQVSBM9E7DtWaaH3CyHkppYrKYoxwg==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true @@ -2215,8 +2223,8 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} engines: {node: '>= 0.4'} signal-exit@4.1.0: @@ -2635,12 +2643,12 @@ packages: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} - yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + yargs@16.2.2: + resolution: {integrity: sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==} engines: {node: '>=10'} - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + yargs@17.7.3: + resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} engines: {node: '>=12'} yargs@18.0.0: @@ -2760,10 +2768,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@neteasecloudmusicapienhanced/unblockmusic-utils@0.3.2': + '@neteasecloudmusicapienhanced/unblockmusic-utils@0.3.3': dependencies: '@unblockneteasemusic/server': 0.28.0 - axios: 1.17.0 + axios: 1.18.0 dotenv: 17.4.2 express: 4.22.2 https: 1.0.0 @@ -2855,14 +2863,14 @@ snapshots: '@types/http-errors': 2.0.5 '@types/node': 25.9.2 - '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.60.1(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/type-utils': 8.60.1(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/utils': 8.60.1(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.60.1 + '@typescript-eslint/parser': 8.61.1(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.61.1 + '@typescript-eslint/type-utils': 8.61.1(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.1(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.61.1 eslint: 9.39.4 ignore: 7.0.5 natural-compare: 1.4.0 @@ -2871,41 +2879,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.60.1(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/parser@8.61.1(eslint@9.39.4)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.60.1 + '@typescript-eslint/scope-manager': 8.61.1 + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.61.1 debug: 4.4.3 eslint: 9.39.4 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.60.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.61.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@5.9.3) - '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/tsconfig-utils': 8.61.1(typescript@5.9.3) + '@typescript-eslint/types': 8.61.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.60.1': + '@typescript-eslint/scope-manager@8.61.1': dependencies: - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/visitor-keys': 8.60.1 + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/visitor-keys': 8.61.1 - '@typescript-eslint/tsconfig-utils@8.60.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.61.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.60.1(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.61.1(eslint@9.39.4)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.60.1(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.1(eslint@9.39.4)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.4 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -2913,37 +2921,37 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.60.1': {} + '@typescript-eslint/types@8.61.1': {} - '@typescript-eslint/typescript-estree@8.60.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.61.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.60.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@5.9.3) - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/visitor-keys': 8.60.1 + '@typescript-eslint/project-service': 8.61.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.61.1(typescript@5.9.3) + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/visitor-keys': 8.61.1 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.8.3 + semver: 7.8.5 tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.60.1(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/utils@8.61.1(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/types': 8.60.1 - '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.61.1 + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) eslint: 9.39.4 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.60.1': + '@typescript-eslint/visitor-keys@8.61.1': dependencies: - '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/types': 8.61.1 eslint-visitor-keys: 5.0.1 '@unblockneteasemusic/server@0.28.0': @@ -2964,13 +2972,13 @@ snapshots: acorn-es7-plugin@1.1.7: {} - acorn-jsx@5.3.2(acorn@8.16.0): + acorn-jsx@5.3.2(acorn@8.17.0): dependencies: - acorn: 8.16.0 + acorn: 8.17.0 acorn@5.7.4: {} - acorn@8.16.0: {} + acorn@8.17.0: {} agent-base@6.0.2: dependencies: @@ -3060,10 +3068,10 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axios@1.17.0: + axios@1.18.0: dependencies: follow-redirects: 1.16.0 - form-data: 4.0.5 + form-data: 4.0.6 https-proxy-agent: 5.0.1 proxy-from-env: 2.1.0 transitivePeerDependencies: @@ -3103,10 +3111,10 @@ snapshots: transitivePeerDependencies: - supports-color - body-parser@2.2.2: + body-parser@2.3.0: dependencies: bytes: 3.1.2 - content-type: 1.0.5 + content-type: 2.0.0 debug: 4.4.3 http-errors: 2.0.1 iconv-lite: 0.7.2 @@ -3468,6 +3476,13 @@ snapshots: environment@1.1.0: {} + es-abstract-get@1.0.0: + dependencies: + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + is-callable: 1.2.7 + object-inspect: 1.13.4 + es-abstract@1.24.2: dependencies: array-buffer-byte-length: 1.0.2 @@ -3482,8 +3497,8 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.2 es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 + es-to-primitive: 1.3.1 + function.prototype.name: 1.2.0 get-intrinsic: 1.3.0 get-proto: 1.0.1 get-symbol-description: 1.1.0 @@ -3540,8 +3555,10 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.4 - es-to-primitive@1.3.0: + es-to-primitive@1.3.1: dependencies: + es-abstract-get: 1.0.0 + es-errors: 1.3.0 is-callable: 1.2.7 is-date-object: 1.1.0 is-symbol: 1.1.1 @@ -3634,10 +3651,10 @@ snapshots: dependencies: htmlparser2: 10.1.0 - eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4))(eslint@9.39.4)(prettier@3.8.3): + eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@9.39.4))(eslint@9.39.4)(prettier@3.8.4): dependencies: eslint: 9.39.4 - prettier: 3.8.3 + prettier: 3.8.4 prettier-linter-helpers: 1.0.1 synckit: 0.11.13 optionalDependencies: @@ -3743,8 +3760,8 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) eslint-visitor-keys: 4.2.1 esprima@2.7.3: {} @@ -3823,7 +3840,7 @@ snapshots: express@5.2.1: dependencies: accepts: 2.0.0 - body-parser: 2.2.2 + body-parser: 2.3.0 content-disposition: 1.1.0 content-type: 1.0.5 cookie: 0.7.2 @@ -3957,7 +3974,7 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data@4.0.5: + form-data@4.0.6: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 @@ -3990,14 +4007,17 @@ snapshots: function-bind@1.1.2: {} - function.prototype.name@1.1.8: + function.prototype.name@1.2.0: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 - define-properties: 1.2.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 hasown: 2.0.4 is-callable: 1.2.7 + is-document.all: 1.0.0 functions-have-names@1.2.3: {} @@ -4187,7 +4207,7 @@ snapshots: dependencies: es-errors: 1.3.0 hasown: 2.0.4 - side-channel: 1.1.0 + side-channel: 1.1.1 into-stream@6.0.0: dependencies: @@ -4251,6 +4271,10 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-document.all@1.0.0: + dependencies: + call-bound: 1.0.4 + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -4507,7 +4531,7 @@ snapshots: strip-json-comments: 3.1.1 supports-color: 8.1.1 workerpool: 9.3.4 - yargs: 17.7.2 + yargs: 17.7.3 yargs-parser: 21.1.1 yargs-unparser: 2.0.0 @@ -4555,7 +4579,7 @@ snapshots: node-abi@3.92.0: dependencies: - semver: 7.8.3 + semver: 7.8.5 node-fetch@2.7.0: dependencies: @@ -4566,7 +4590,7 @@ snapshots: node-windows@1.0.0-beta.8: dependencies: xml: 1.0.1 - yargs: 17.7.2 + yargs: 17.7.3 nodemon@3.1.14: dependencies: @@ -4575,7 +4599,7 @@ snapshots: ignore-by-default: 1.0.1 minimatch: 10.2.5 pstree.remy: 1.1.8 - semver: 7.8.3 + semver: 7.8.5 simple-update-notifier: 2.0.0 supports-color: 5.5.0 touch: 3.1.1 @@ -4750,9 +4774,9 @@ snapshots: https-proxy-agent: 5.0.1 node-fetch: 2.7.0 progress: 2.0.3 - semver: 7.8.3 + semver: 7.8.5 tar-fs: 2.1.4 - yargs: 16.2.0 + yargs: 16.2.2 transitivePeerDependencies: - encoding - supports-color @@ -4870,7 +4894,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.8.3: {} + prettier@3.8.4: {} process-nextick-args@2.0.1: {} @@ -4902,7 +4926,7 @@ snapshots: qs@6.15.2: dependencies: - side-channel: 1.1.0 + side-channel: 1.1.1 queue-microtask@1.2.3: {} @@ -5044,7 +5068,7 @@ snapshots: secure-json-parse@2.7.0: {} - semver@7.8.3: {} + semver@7.8.5: {} send@0.19.2: dependencies: @@ -5154,7 +5178,7 @@ snapshots: object-inspect: 1.13.4 side-channel-map: 1.0.1 - side-channel@1.1.0: + side-channel@1.1.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -5174,7 +5198,7 @@ snapshots: simple-update-notifier@2.0.0: dependencies: - semver: 7.8.3 + semver: 7.8.5 slash@3.0.0: {} @@ -5517,7 +5541,7 @@ snapshots: which-builtin-type@1.2.1: dependencies: call-bound: 1.0.4 - function.prototype.name: 1.1.8 + function.prototype.name: 1.2.0 has-tostringtag: 1.0.2 is-async-function: 2.1.1 is-date-object: 1.1.0 @@ -5634,7 +5658,7 @@ snapshots: y18n: 4.0.3 yargs-parser: 18.1.3 - yargs@16.2.0: + yargs@16.2.2: dependencies: cliui: 7.0.4 escalade: 3.2.0 @@ -5644,7 +5668,7 @@ snapshots: y18n: 5.0.8 yargs-parser: 20.2.9 - yargs@17.7.2: + yargs@17.7.3: dependencies: cliui: 8.0.1 escalade: 3.2.0 diff --git a/public/docs/home.md b/public/docs/home.md index f8ef27b..5d1f87a 100644 --- a/public/docs/home.md +++ b/public/docs/home.md @@ -2500,6 +2500,18 @@ privilege:权限相关信息 **调用例子 :** `/scrobble?id=518066366&sourceid=36780169&time=291` +#### 听歌打卡 V2 (NCBL 加密版) + +说明 : 调用此接口,使用桌面客户端 NCBL 加密日志格式上报听歌记录 + +**必选参数 :** `id`: 歌曲 id, `time`: 播放时长(秒) + +**可选参数 :** `sourceid`: 来源列表 id, `source`: 来源名称(默认 list), `name`: 歌曲名, `artist`: 艺术家, `bitrate`: 码率(默认 320), `level`: 音质等级(默认 exhigh), `total`: 歌曲总时长(秒) + +**接口地址 :** `/scrobble/v1` + +**调用例子 :** `/scrobble/v1?id=518066366&sourceid=36780169&time=291` + ### 提交歌曲播放状态 说明 : 调用此接口可提交歌曲播放状态,支持会话追踪和播放模式记录,未传入 `sessionId` 时后端会自动生成 diff --git a/public/scrobble.html b/public/scrobble.html index 4b8d790..bb3f7d1 100644 --- a/public/scrobble.html +++ b/public/scrobble.html @@ -20,7 +20,7 @@ } .container { - max-width: 500px; + max-width: 520px; margin: 40px auto; background: white; border-radius: 12px; @@ -39,13 +39,13 @@ .subtitle { font-size: 14px; color: #666; - margin-bottom: 32px; + margin-bottom: 24px; text-align: center; } .login-link { display: block; - margin-bottom: 24px; + margin-bottom: 20px; color: #666; font-size: 14px; text-decoration: none; @@ -57,17 +57,76 @@ text-decoration: underline; } + /* ---- Tabs ---- */ + .tabs { + display: flex; + gap: 0; + margin-bottom: 24px; + border-bottom: 2px solid #eee; + } + + .tab-btn { + flex: 1; + padding: 10px 0; + background: none; + border: none; + border-bottom: 2px solid transparent; + margin-bottom: -2px; + font-size: 14px; + font-weight: 500; + color: #999; + cursor: pointer; + transition: color 0.2s, border-color 0.2s; + } + + .tab-btn:hover { + color: #555; + } + + .tab-btn.active { + color: #333; + border-bottom-color: #333; + } + + .tab-content { + display: none; + } + + .tab-content.active { + display: block; + } + + /* ---- Form ---- */ .form-group { - margin-bottom: 20px; + margin-bottom: 16px; text-align: left; } label { display: block; - font-size: 14px; + font-size: 13px; font-weight: 500; color: #555; - margin-bottom: 8px; + margin-bottom: 6px; + } + + label .tag { + display: inline-block; + font-size: 11px; + font-weight: 400; + padding: 1px 6px; + border-radius: 3px; + margin-left: 6px; + } + + label .tag.r { + background: #fee2e2; + color: #991b1b; + } + + label .tag.o { + background: #fef3c7; + color: #92400e; } input[type="text"], @@ -80,6 +139,7 @@ font-size: 14px; outline: none; font-family: inherit; + transition: border-color 0.2s; } input[type="text"]:focus, @@ -92,8 +152,17 @@ resize: vertical; } + .row { + display: flex; + gap: 12px; + } + + .row .form-group { + flex: 1; + } + .quick-fill { - margin-top: 6px; + margin-top: 5px; font-size: 12px; color: #666; } @@ -121,7 +190,7 @@ transition: background 0.2s ease; border: none; text-align: center; - margin-top: 24px; + margin-top: 20px; } .btn:hover { @@ -134,7 +203,7 @@ } .result { - margin-top: 20px; + margin-top: 16px; padding: 12px 16px; border-radius: 6px; font-size: 14px; @@ -183,37 +252,92 @@ 还没登录?点击登录 +