mirror of
https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced.git
synced 2026-10-20 22:51:23 +08:00
6.0 KiB
6.0 KiB
NeteaseCloudMusicApiEnhanced Agent 说明
快速开始
- 包管理器:开发与 CI 使用
pnpm,Dockerfile也用 pnpm(pnpm@9 --frozen-lockfile,匹配pnpm-lock.yaml)。仓库没有yarn.lock,不要引入 yarn。 - Node 版本:README 推荐 Node 22+;
package.json的engines声明>=12;CI/打包在 Node 18–24 上运行。现代 Node 均可。 - 环境变量:
server.js调用了dotenv.config(),本地.env会被自动加载;所有支持的变量见.env.prod.example。
常用命令
- 安装依赖:
pnpm i - 启动服务:
pnpm start(等价node app.js);热重载开发:pnpm dev(nodemon) - 跑测试:
pnpm test(Mocha,超时 60s) - Lint:
pnpm lint;自动修复:pnpm lint-fix - 文档格式化检查/修复:
pnpm docs:check/pnpm docs:format - 打包独立二进制:
pnpm pkgwin/pkglinux/pkgmacos
架构
app.js(也是bin)——服务入口。执行generateConfig()预热运行时凭证(anonymous_token 与 xeapi 公钥,存于内存),再调用server.serveNcmApi()。不依赖/tmp等可写文件系统。server.js——Express 工厂。constructServer()自动扫描module/*.js,每个文件注册一条路由(文件名_转/,如album_new.js→/album/new;特例daily_signin/fm_trash/personal_fm硬编码在server.js的special对象里)。serveNcmApi()监听PORT(默认 3000)/HOST。main.js——作为依赖被引入时的入口(main字段)。把每个module/*导出为同名函数name(data),另导出server、serveNcmApi、getModulesDefinitions。module/*.js——每个接口一个文件,标准写法:module.exports = (query, request) => request(path, data, createOption(query))。createOption在util/option.js,负责 crypto、cookie(回退到NETEASE_COOKIE)、proxy、realIP/randomCNIP、headers、timeout。util/request.js——唯一的对外 HTTP 层(axios)。按crypto(api/eapi/weapi/linuxapi/xeapi)加密并设置 IP 头;运行时凭证一律从util/runtimeState.js读取,不再有任何 require 期文件 I/O。util/runtimeState.js——统一的进程内运行时状态(anonymous_token与xeapi_public_key)。默认纯内存、零文件 I/O;通过loadSeed()可选地从环境变量NETEASE_ANONYMOUS_TOKEN/NETEASE_XEAPI_PUBLIC_KEY或旧/tmp文件加载迁移种子。util/credentials.js是唯一的网络刷新层(含并发去重与防重入,适配 serverless 冷启动)。util/config.json——运行时配置:网易域名 +APP_CONF.encrypt: true(默认走 eapi 加密)。已被 git 跟踪,改动会改变全局默认行为。index.js/index.mjs——require('./app.js')的薄包装,供 Vercel(vercel.json)和 ESM 导入使用。server.js里有一段非显而易见的逻辑:环境变量ENABLE_GENERAL_UNBLOCK=true时,/song/url/v1的响应会被自动解灰(走@neteasecloudmusicapienhanced/unblockmusic-utils);另外query.noCookie为真时不向响应写Set-Cookie。
新增/修改接口
- 新建
module/xxx.js会自动挂载路由,无需注册;文件名即路由。 - 照抄同目录模块的写法(选对
crypto),用createOption(query)生成请求选项。 - 改文件名/路由会破坏已有客户端,尽量保持旧路径兼容。
测试
pnpm test跑server.test.js+main.test.js+util/runtimeState.test.js。server.test.js在before()里启动真实服务器,test/*.test.js全部请求真实网易云 API——必须联网,且可能因上游风控/限流偶发失败。main.test.js与util/runtimeState.test.js是纯单测,不需要网络。- CI 门禁只看稳定项:
ci-check.yml在 Node 18/22/24 上跑pnpm lint+main.test.js+pnpm docs:check;完整集成测试(server.test.js)是continue-on-error,不阻塞合并。本地跑全量测试失败先怀疑上游风控。 - 测试使用
power-assert(经intelli-espower-loader),普通assert写法也会输出详细 diff。 - 只跑单个用例:
pnpm exec mocha -r intelli-espower-loader -t 60000 --grep "<describe/it 名字>" server.test.js main.test.js --exit - 只跑离线单测:
pnpm exec mocha -r intelli-espower-loader -t 60000 main.test.js util/runtimeState.test.js --exit
坑与注意
- 改
package.json的version会触发自动发布:release-on-version-change.yml按 paths 过滤——只要 push 到main时package.json有改动且 version 变了,就自动打 tag + GitHub Release(pkg三平台二进制)、推送 Docker 镜像(Docker Hub + GHCR 多架构)、pnpm publish到 npm;tag 已存在则跳过。别顺手改版本号,也别往package.json里写无关改动凑提交。 - 没有实际 git hooks:
package.json里配了lint-staged和 husky,但.husky/下只有_脚手架目录、没有真正的 hook 文件,commit 时不会自动跑任何检查,自己记得pnpm lint-fix。 - 代理环境变量已失效:README 里关于
http_proxy/https_proxy的警告来自旧request库时代;现在util/request.js用 axios + 自定义 keep-alive agent,且显式proxy: false,环境变量代理不会生效。按请求走query.proxy参数(支持 PAC 和 http 隧道)。 - 运行时凭证在内存中:
anonymous_token、xeapi_public_key存于util/runtimeState.js(进程内),不再写/tmp,可在只读文件系统 / Android / iOS / serverless 上运行。缺失时由util/credentials.js按需刷新;旧/tmp文件仅作为可选迁移种子(loadSeed()),环境变量NETEASE_ANONYMOUS_TOKEN/NETEASE_XEAPI_PUBLIC_KEY优先。重启服务(或调用generateConfig())会重新刷新。 - ESLint 9 flat config:
eslint.config.js,风格由eslint-plugin-prettier强制(2 空格缩进、单引号、分号、endOfLine: auto)。