diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b5edbe5 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,23 @@ +# Agent Instructions for NeteaseCloudMusicApiEnhanced + +## Quick Start +- **Package Manager**: Use `pnpm` (not npm or yarn). +- **Node Version**: Requires Node.js 18 or later. + +## Developer Commands +- **Install dependencies**: `pnpm i` +- **Start server**: `pnpm start` or `node app.js` +- **Start dev server**: `pnpm dev` (uses nodemon) +- **Run tests**: `pnpm test` (uses Mocha) +- **Linting**: `pnpm lint` (check) or `pnpm lint-fix` (auto-fix) + +## Architecture & Entrypoints +- **Executable Server**: `app.js` is the main entrypoint for running the API server. +- **Module Exports**: `main.js` is the entrypoint when the project is imported as a Node.js dependency. +- **API Endpoints**: Located in the `module/` directory. Each file typically corresponds to an API route. +- **Core Utilities**: Request handling, encryption, and core utilities are found in the `util/` directory. + +## Important Gotchas & Quirks +- **Environment Variables**: The server defaults to port 3000 but can be overridden with the `PORT` environment variable. +- **Proxy Variables**: Be very careful with proxy environment variables (`http_proxy`, `https_proxy`, `no_proxy`). The request library (like axios) will automatically pick these up. If they point to an unavailable proxy (especially common in Docker environments), requests will fail silently or throw connection errors. +- **Code Style**: The project uses ESLint and Prettier. Always run `pnpm lint-fix` before committing changes to ensure formatting consistency. diff --git a/module/scrobble.js b/module/scrobble.js index 2cf9fb6..f8948c1 100644 --- a/module/scrobble.js +++ b/module/scrobble.js @@ -1,8 +1,40 @@ // 听歌打卡 const createOption = require('../util/option.js') -module.exports = (query, request) => { - const data = { +module.exports = async (query, request) => { + // 注入 os=osx 的 cookie + let cookie = query.cookie || '' + if (typeof cookie === 'object') { + cookie = Object.assign({ os: 'osx' }, cookie) + } else if (typeof cookie === 'string') { + if (cookie.indexOf('os=') > -1) { + cookie = cookie.replace(/os=[^;]+/g, 'os=osx') + } else { + cookie = cookie + '; os=osx' + } + } else { + cookie = 'os=osx' + } + query.cookie = cookie + + // 1) startplay → 进「最近播放」 + const startplayData = { + logs: JSON.stringify([ + { + action: 'startplay', + json: { + id: query.id, + type: 'song', + mainsite: '1', + mainsiteWeb: '1', + content: `id=${query.sourceid}`, + }, + }, + ]), + } + + // 2) play → 涨「听歌排行」计数 + const playData = { logs: JSON.stringify([ { action: 'play', @@ -15,12 +47,30 @@ module.exports = (query, request) => { type: 'song', wifi: 0, source: 'list', - mainsite: 1, - content: '', + mainsite: '1', + mainsiteWeb: '1', + content: `id=${query.sourceid}`, }, }, ]), } - return request(`/api/feedback/weblog`, data, createOption(query, 'weapi')) + const option = createOption(query, 'eapi') + option.domain = 'https://clientlog.music.163.com' + + // 发送两次请求 + const res1 = await request(`/api/feedback/weblog`, startplayData, option) + const res2 = await request(`/api/feedback/weblog`, playData, option) + + return { + status: 200, + body: { + code: 200, + data: 'success', + details: { + startplay: res1.body, + play: res2.body, + }, + }, + } } diff --git a/package.json b/package.json index 880f040..fd8b385 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@neteasecloudmusicapienhanced/api", - "version": "4.35.1", + "version": "4.35.2", "description": "全网最全的网易云音乐API接口 || A revival project for NeteaseCloudMusicApi Node.js Services (Half Refactor & Enhanced) || 网易云音乐 API 备份 + 增强 || 本项目自原版v4.28.0版本后开始自行维护", "scripts": { "dev": "nodemon app.js", diff --git a/util/request.js b/util/request.js index 1b12d2e..4d6ef4a 100644 --- a/util/request.js +++ b/util/request.js @@ -88,6 +88,12 @@ const osMap = { osver: '16.2', channel: 'distribution', }, + osx: { + os: 'osx', + appver: '3.1.10.5100', + osver: '15.5', + channel: 'netease', + }, } // 预先定义userAgentMap @@ -306,7 +312,11 @@ const createRequest = (uri, data, options) => { if (cookie.MUSIC_A) header['MUSIC_A'] = cookie.MUSIC_A headers['Cookie'] = createHeaderCookie(header) - headers['User-Agent'] = options.ua || chooseUserAgent('api', 'iphone') + headers['User-Agent'] = + options.ua || + (cookie.os === 'osx' + ? 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36' + : chooseUserAgent('api', 'iphone')) if (crypto === 'eapi') { // headers['x-aeapi'] = true // 服务器会使用gzip压缩返回值