Files
music-hub/CLAUDE.md
T
2026-10-10 22:23:30 +08:00

3.8 KiB
Raw Blame History

CLAUDE.md

声匣:自托管音乐下载 Web 服务(网易云 + QQ 音乐),本机 npm start 或 NAS Docker 运行。UI、注释、日志均为中文。

命令

  • npm run dev — 后端 node --watch server/src/main.ts(:8066)+ Vite(:5173,代理 /api)
  • npm start — 生产模式(需先 npm run build)
  • npm run typecheck — tsc(server)+ vue-tsc(web)。改动后必须通过
  • npm run smoke -- <id|链接> [quality] [album|flat] — 端到端跑一次下载流水线(会导入 QQ Cookie)

没有测试框架;用 smoke、curl /api/*,以及无头浏览器截图验证。测试下载请用 MUSIC_DIR / DATA_DIR 指向临时目录,不要污染 ./music 与 ./data。

架构

单个 package.json:

  • server/src/ — Koa 3,Node 原生 TypeScript 类型剥离直接运行,无构建步骤
    • 只能用可擦除语法(erasableSyntaxOnly):不能用 enum / namespace / 参数属性
    • 相对导入必须写 .ts;类型导入用 import type(verbatimModuleSyntax)
    • core/ 与平台无关:pipeline.ts(下载流水线)、tagging.ts、lyrics.ts、layout.ts、quality.ts、net/http.ts
    • core/providers/{netease,qq}/ 实现 MusicProvider(core/types.ts),在 providers/index.ts 注册;resolveLink 处理分享短链
    • QQ:qq/client.ts 的 musicu() 在 comm 中带 uin + authst 并附 Cookie —— 缺这一步拿不到 VIP 音源
    • queue.ts — 任务存 SQLite tasks 表,进度只在内存,经 events.ts 的 bus 推送;routes/api.ts 的 /api/events 是 SSE
    • accounts.ts(Cookie 用 secret.ts AES-GCM 加密存储)、settings.ts(运行时设置)、auth.ts(可选访问密码)、library.ts(曲库工具)、stream.ts(试听代理)
    • db.ts — node:sqlite;history / tasks / settings 表
  • web/ — Vite 8 + Vue 3.5 + Vue Router 5,无 UI 库
    • lib/store.ts 全局状态 + SSE;lib/player.ts 试听;lib/api.ts 类型与请求
    • components/TrackList.vue 是所有曲目列表(搜索 / 专辑 / 歌单 / 歌手)的核心
    • 样式只用 styles/tokens.css 的 CSS 变量;base.css 有 .page .btn .seg .badge 等通用类

约定

  • 统一音质键 standard|high|lossless|hires|master|spatial|effect;provider 映射到平台参数,不可用时按 fallbackChain 降级。QQ 只声明到 hires
  • 目录:album 布局 = {第一位专辑艺人}/{专辑}/{NN}. {歌名}.ext(与 NAS 曲库一致);flat = {歌手} - {歌名}.ext
  • 下载先写 .part 再改名;已存在判定:≥ 音源 99% 且 ≤ 音源 + 8MB(内嵌封面会变大)
  • FatalError 表示重试无意义;队列间隔 gapMs(默认 400ms)防止打爆上游
  • 服务端永远不把 Cookie 原文返回前端;relFile 等路径一律用 /
  • 传给 TrackList 的数组必须稳定(用 computed),否则每次渲染都会清空选择
  • 前端 ref<null> 的接口要返回对象包一层(Koa 对 null body 返回 204)
  • QQ 登录在 qq/login.ts:扫码 = ptlogin2 → graph.qq.com OAuth → QQConnectLogin.QQLogin;续期 = music.login.LoginServer.Login(网页 Cookie 没有 refresh_key 也能续期,旧 key 不会失效)。accounts.ts 的 keeper 每 3 小时检查,过半寿命(key 有效 3 天)即续期。有效性必须用 GetLoginUserInfo 判断 —— vip_login_base 对失效 key 仍返回 code 0
  • NAS 部署:宿主机文件是 0700,镜像里必须 chmod -R a+rX /app;境外请求靠 NODE_USE_ENV_PROXY + HTTP(S)_PROXY,NO_PROXY 覆盖 QQ / 网易云域名
  • TypeScript 固定 6.x:TS 7 没有 JS API,vue-tsc 无法使用
  • 网易云红 / QQ 绿已用 dataviz 校验器验证(深色 QQ 绿 #42a07d);二者 CVD 区分度在 6–8,必须配合文字标签使用