feat: harden dedupe runtime and NAS deployment
This commit is contained in:
@@ -2,38 +2,94 @@
|
||||
|
||||
轻量级家庭 NAS 音乐库去重服务,面向 `AllMusic/{username}/` 场景。
|
||||
|
||||
## 设计目标
|
||||
## 处理模型
|
||||
|
||||
- 本地 SQLite 元数据库
|
||||
- L1 极速候选:文件大小 + 头/尾 64 KiB hash
|
||||
- Exact Duplicate 最终使用完整 SHA-256 确认
|
||||
- L2 使用 Chromaprint 做音频相似度候选
|
||||
- duration 预过滤,降低 CPU/I/O
|
||||
- 同一版本才允许自动择优
|
||||
- loser 进入 `.dedupe/trash/`,默认保留 30 天
|
||||
- 不使用软链接;物理去重使用 hard link
|
||||
- inotify 增量处理 + 低优先级全量 reconcile
|
||||
- 任何不确定或异常默认保留原文件
|
||||
```text
|
||||
AllMusic
|
||||
↓
|
||||
文件稳定检测
|
||||
↓
|
||||
L1:size + head/tail 64 KiB
|
||||
↓
|
||||
完整 SHA-256
|
||||
├─ 相同 → Exact Duplicate → hard link
|
||||
└─ 不同 → duration ±3s → Chromaprint
|
||||
├─ 高相似且版本一致 → hard link
|
||||
├─ 中等相似/版本冲突 → review
|
||||
└─ 低相似 → 保留
|
||||
```
|
||||
|
||||
## 当前阶段
|
||||
### 关键安全规则
|
||||
|
||||
第一阶段先完成安全的扫描、SQLite 索引、L1/Exact 去重、trash/quarantine 和测试。
|
||||
L2 Chromaprint 比对与生产 NAS 监听在后续阶段接入。
|
||||
- SHA-256 是 Exact Duplicate 的最终依据;L1 只负责缩小候选范围。
|
||||
- 不根据文件名、歌手、歌名、专辑或来源单独判重。
|
||||
- 确认相同版本后,优先使用 hard link 保留每个用户原来的逻辑路径。
|
||||
- 用户删除自己的路径不会影响其他 hard link;最后一个 link 删除后数据才释放。
|
||||
- 不跨文件系统创建 hard link。
|
||||
- 正在写入的文件必须先通过稳定性检查。
|
||||
- L2 对版本标记冲突的文件进入 review,不自动合并。
|
||||
- `--dry-run` 只报告/更新索引,不修改音乐文件。
|
||||
- SQLite 是加速索引,文件系统是最终事实;数据库丢失后可以重新扫描。
|
||||
|
||||
## 安全原则
|
||||
|
||||
1. 不修改正在写入的文件。
|
||||
2. L1 命中必须再做完整 SHA-256 才能判定 exact duplicate。
|
||||
3. 不根据歌名/歌手/专辑单独判重。
|
||||
4. 不同格式或音频规格不会因为 metadata 相似而直接合并。
|
||||
5. 自动处理前保留可恢复路径;失败不删除原文件。
|
||||
6. 数据库只是索引,文件系统才是最终事实。
|
||||
|
||||
## CLI 预期
|
||||
## CLI
|
||||
|
||||
```bash
|
||||
am-deduper scan /music/AllMusic
|
||||
am-deduper dedupe /music/AllMusic
|
||||
am-deduper reconcile /music/AllMusic
|
||||
am-deduper trash-prune /music/AllMusic --days 30
|
||||
# 建立/更新索引,不修改音乐文件
|
||||
am-deduper scan /music/AllMusic --db /data/dedupe.db
|
||||
|
||||
# Exact + L2;首次执行建议 dry-run
|
||||
am-deduper dedupe /music/AllMusic --db /data/dedupe.db --dry-run
|
||||
|
||||
# 确认后执行
|
||||
am-deduper dedupe /music/AllMusic --db /data/dedupe.db
|
||||
|
||||
# 长驻监听:默认只自动执行安全的 Exact hard-link
|
||||
am-deduper watch /music/AllMusic --db /data/dedupe.db
|
||||
|
||||
# 开启 L2 自动 acoustic 匹配(建议在 dry-run 验证阈值后再启用)
|
||||
am-deduper watch /music/AllMusic --db /data/dedupe.db --l2
|
||||
```
|
||||
|
||||
## Docker / Feiniu NAS 部署
|
||||
|
||||
wjyhk 负责构建镜像,推送到 Gitea Container Registry;NAS 只负责 pull + run,不在 NAS 上重新 build。
|
||||
|
||||
NAS 的 `AllMusic` 与 dedupe 数据建议分开:
|
||||
|
||||
```text
|
||||
NAS
|
||||
├── AllMusic/
|
||||
│ ├── admin/
|
||||
│ ├── alice/
|
||||
│ └── bob/
|
||||
└── AppData/
|
||||
└── am-deduper/
|
||||
└── dedupe.db
|
||||
```
|
||||
|
||||
注意:如果以后启用 trash,trash 目录必须位于 `AllMusic` 所在同一文件系统内,不能把需要原子 rename/hard-link 语义的文件直接移动到 `/data`。
|
||||
|
||||
### NAS `.env`
|
||||
|
||||
```dotenv
|
||||
AM_DEDUPER_IMAGE=<GITEA_REGISTRY>/<OWNER>/am-music-deduper:<TAG>
|
||||
ALLMUSIC_PATH=<NAS绝对路径>/AllMusic
|
||||
DEDUPE_DATA_PATH=<NAS绝对路径>/AppData/am-deduper
|
||||
```
|
||||
|
||||
### NAS 部署
|
||||
|
||||
```bash
|
||||
mkdir -p "$DEDUPE_DATA_PATH"
|
||||
docker login <GITEA_REGISTRY>
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
查看日志:
|
||||
|
||||
```bash
|
||||
docker logs -f am-deduper
|
||||
```
|
||||
|
||||
首次上线建议先暂停 `watch`,执行一次完整 `scan` + `dedupe --dry-run`,确认候选数量与 review 项,再启用正式 dedupe;L2 自动处理单独验证后再打开 `--l2`。
|
||||
|
||||
Reference in New Issue
Block a user