Files
music-hub/CLAUDE.md
T
Jocay 21945cc54f feat: 声匣 —— 网易云 / QQ 音乐自托管下载服务
由 163-music-dl CLI 重构为 Web 服务:
- 下载流水线、歌词与标签逻辑沿用旧版(node-id3 / ffmpeg)
- 网易云(chksz 接口 + music.163.com 元数据)与 QQ 音乐(VIP Cookie)provider
- QQ 扫码登录与 musickey 自动续期
- SQLite 持久化的下载队列,SSE 实时进度
- 曲库工具(M3U / ZIP / 回收站 / 补全标签)、历史统计与导出、访问密码
- Vite 8 + Vue 3 前端,浅色 / 深色
- Docker 部署配置(飞牛 NAS)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 22:05:30 +08:00

43 lines
3.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)
- TypeScript 固定 6.x:TS 7 没有 JS API,vue-tsc 无法使用
- 网易云红 / QQ 绿已用 dataviz 校验器验证(深色 QQ 绿 `#42a07d`);二者 CVD 区分度在 6–8,必须配合文字标签使用