|
| 1 | +# AGENTS.md β api-enhanced |
| 2 | + |
| 3 | +**`@neteasecloudmusicapienhanced/api`** (v4.33.0) β Enhanced fork of Binaryify/NeteaseCloudMusicApi. ~250+ dynamically loaded Netease Cloud Music REST API endpoints. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Entrypoints |
| 8 | + |
| 9 | +| Use case | File | Notes | |
| 10 | +|----------|------|-------| |
| 11 | +| CLI/server | `app.js` | Auto-generates anonymous token, then calls `server.serveNcmApi()` | |
| 12 | +| Programmatic | `main.js` | Dynamically loads all `module/*.js` as functions, plus re-exports `server.js` | |
| 13 | +| Express app | `server.js` | Exports `serveNcmApi(options)` and `getModulesDefinitions(path, routeOverrides)` | |
| 14 | +| Vercel | `index.js` | `require('./app.js')` | |
| 15 | +| ESM | `index.mjs` | `import './app.js'` | |
| 16 | + |
| 17 | +## Dev commands |
| 18 | + |
| 19 | +```sh |
| 20 | +npm run dev # nodemon app.js |
| 21 | +npm start # node app.js |
| 22 | +npm test # mocha -r intelli-espower-loader -t 60000 server.test.js main.test.js --exit |
| 23 | +npm run lint # eslint "**/*.{js,ts}" |
| 24 | +npm run lint-fix # eslint --fix "**/*.{js,ts}" |
| 25 | +npm run prepare # husky install (auto on pnpm install) |
| 26 | +npm run pkgwin # pkg . -t node18-win-x64 -C GZip -o precompiled/app |
| 27 | +npm run pkglinux # pkg . -t node18-linux-x64 -C GZip -o precompiled/app |
| 28 | +npm run pkgmacos # pkg . -t node18-macos-x64 -C GZip -o precompiled/app |
| 29 | +``` |
| 30 | + |
| 31 | +**Must-use order when making changes:** `lint-fix β test` (test runs server integration, not just unit). |
| 32 | + |
| 33 | +## Testing quirks |
| 34 | + |
| 35 | +- **Mocha 11** + power-assert. 60s timeout. `--exit` is required (server keeps event loop alive). |
| 36 | +- **Server bootstraps in `server.test.js`** β starts Express on a random port before all tests, then dynamically `require()`s all `test/*.test.js` files. |
| 37 | +- Tests use `global.host` (dynamic port) or fallback to `http://localhost:3000`. |
| 38 | +- **`realIP: global.cnIp`** is sent with every request to avoid Netease rate limiting. `global.cnIp` is a random Chinese IP from `data/china_ip_ranges.txt`. |
| 39 | +- Hardcoded song/album IDs in test files may fail if Netease's catalog changes. |
| 40 | +- Anonymous token is auto-generated to `os.tmpdir()/anonymous_token` before tests run. |
| 41 | +- Tests are **integration tests** requiring live access to `music.163.com` β they will fail offline. |
| 42 | + |
| 43 | +## Architecture |
| 44 | + |
| 45 | +**Dynamic routing** β each `.js` in `module/` becomes an API route: |
| 46 | +- `album_new.js` β `GET /album/new` |
| 47 | +- Underscores become slashes. Three overrides exist in `server.js`: |
| 48 | + - `daily_signin.js` β `/daily_signin` |
| 49 | + - `fm_trash.js` β `/fm_trash` |
| 50 | + - `personal_fm.js` β `/personal_fm` |
| 51 | + |
| 52 | +**Encryption** (see `util/crypto.js`): |
| 53 | +- `weapi` β AES-CBC + RSA (most endpoints) |
| 54 | +- `linuxapi` β AES-ECB (linux client endpoints) |
| 55 | +- `eapi` β custom (newer endpoints) |
| 56 | +- `api` β plaintext (rare) |
| 57 | + |
| 58 | +**API domains** β `music.163.com` (weapi/linuxapi), `interface.music.163.com` (eapi/api). |
| 59 | + |
| 60 | +**Cache** β 2-minute TTL via `util/apicache.js` on all responses. Bypass with `?cache=false`. |
| 61 | + |
| 62 | +**Anonymous token** β auto-generated at startup via `generateConfig.js` β `register_anonimous()`, cached at `os.tmpdir()/anonymous_token`. Deletion forces regeneration on next start. |
| 63 | + |
| 64 | +**Unblock feature** β set `ENABLE_GENERAL_UNBLOCK=true` in `.env` to activate `@neteasecloudmusicapienhanced/unblockmusic-utils` for `/song/url/v1`. |
| 65 | + |
| 66 | +## Config & style |
| 67 | + |
| 68 | +| Tool | Setting | |
| 69 | +|------|---------| |
| 70 | +| ESLint | **Flat config**`eslint.config.js` β extends prettier, 2-space indent, single quotes, no semicolons | |
| 71 | +| Prettier | `semi: false`, `singleQuote: true`, `trailingComma: "all"` | |
| 72 | +| EditorConfig | LF endings, 2-space indent for `*.{js,ts}` | |
| 73 | +| TypeScript | `tsconfig.json` β `strict: true`, `noEmit: true` (type-check only), path aliases `~/*` and `@/*` | |
| 74 | +| Husky v9 | Pre-commit: lint-staged (`*.js` β `eslint --fix`). Commit-msg & pre-push: placeholder shims. | |
| 75 | + |
| 76 | +## CI/CD workflows (`.github/workflows/`) |
| 77 | + |
| 78 | +| Workflow | Trigger | What it does | |
| 79 | +|----------|---------|-------------| |
| 80 | +| `npm.yml` | release published | Publishes to npm | |
| 81 | +| `release-on-version-change.yml` | push to main changing `package.json` | Builds binaries + creates GitHub Release | |
| 82 | +| `Build_Image.yml` | release published | Builds & pushes Docker images to Docker Hub + GHCR | |
| 83 | +| `build-and-pr.yml` | manual + push to main | Builds binaries (linux/win/macos) | |
| 84 | +| `sync.yml` | daily schedule | Syncs fork with upstream Binaryify repo | |
| 85 | +| `issue-manage.yml` | issue open/comment | Welcome / stale management | |
| 86 | + |
| 87 | +## Operational gotchas |
| 88 | + |
| 89 | +- **pnpm** lockfile (`pnpm-lock.yaml`). Never commit `package-lock.json`. |
| 90 | +- **Express v5** β verify v4βv5 migration quirks (route param handling, error middleware). |
| 91 | +- **No database** β this is a stateless API proxy. Persistent state is only `os.tmpdir()/anonymous_token`. |
| 92 | +- **`.env` is gitignored** β copy `.env.prod.example` for local config. |
| 93 | +- **`data/china_ip_ranges.txt`** β used for `realIP` spoofing to bypass Netease geo-restrictions. |
| 94 | +- **`data/deviceid.txt`** β pre-generated device IDs for API requests. |
| 95 | +- **Docker**: `node:lts-alpine`, runs via `tini`, only includes `module/plugins/public/util/app.js/server.js`. |
| 96 | +- **Vercel**: `@vercel/node` runtime with CORS headers in `vercel.json`. |
| 97 | +- **Precompiled binaries** via `pkg` β output to `precompiled/` (gitignored). Node 18 target pinned in scripts. |
| 98 | +- **Do not** modify files in `public/` β it's excluded from ESLint (`globalIgnores(['**/public/'])`). |
| 99 | + |
| 100 | +## Codebase structure (key dirs) |
| 101 | + |
| 102 | +``` |
| 103 | +module/ β 392 endpoint handlers (one .js per route) |
| 104 | +util/ β crypto, request (HTTP + encryption), cache, logger, config |
| 105 | +plugins/ β image & song upload handlers |
| 106 | +test/ β 5 integration test files (album, comment, lyric, music_url, search) |
| 107 | +data/ β china_ip_ranges.txt, deviceid.txt (static assets) |
| 108 | +public/ β docs site (Docsify), test pages (ESLint-ignored) |
| 109 | +examples/ β usage examples (moddef.json gitignored) |
| 110 | +.github/ β workflows, issue templates, dependabot, funding |
| 111 | +``` |
0 commit comments