Files
music-metadata-system/docs/P1-元数据解析与校验-开发落地说明.md

260 lines
11 KiB
Markdown
Raw Permalink 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.
# P1 元数据解析与校验开发落地说明
## 1. 阶段定位
P1 阶段聚焦“元数据解析与校验”核心能力落地,并同步补齐目录扫描、一级去重、二级疑似去重、断点续传、已归档跳过等与验收直接相关的基础处理流程。
该阶段的核心目标是:系统能够读取音频文件元数据、生成原始快照、执行一票否决制校验,并用测试证明关键规则与真实文件读取能力已经落地。
## 2. 阶段目标
- 集成 Jaudiotagger支持主流音频格式元数据读取
- 集成 juniversalchardet完成编码检测与乱码修复尝试
- 实现 `MetadataReaderService`,读取标签、封面、编码并生成原始快照
- 实现 `MetadataValidatorService`,执行核心字段一票否决校验与清洗规则
- 建立 `t_metadata_snapshot` 快照存储能力
- 为目录扫描、去重、断点续传提供落地实现与验收测试
- 使测试覆盖率达到 80% 以上
## 3. 技术落地概览
### 3.1 依赖集成
P1 阶段在 `music-metadata-system/pom.xml` 中新增:
- `net.jthink:jaudiotagger:2.2.5`
- `com.github.albfernandez:juniversalchardet:2.4.0`
- `org.jacoco:jacoco-maven-plugin:0.8.12`
说明:原始需求写的是 Jaudiotagger `2.2.7`,但实际 Maven 可解析并完成落地验证的版本为 `2.2.5`。当前功能已覆盖 MP3/FLAC/M4A/OGG/WAV 的读取需求,故以可稳定构建的版本为准。
### 3.2 领域模型与接口
新增元数据领域对象:
- `music-metadata-system/src/main/java/com/music/metadata/domain/metadata/AudioMetadata.java`
- `music-metadata-system/src/main/java/com/music/metadata/domain/metadata/CoverMetadata.java`
- `music-metadata-system/src/main/java/com/music/metadata/domain/metadata/MetadataValidationResult.java`
- `music-metadata-system/src/main/java/com/music/metadata/domain/metadata/ValidationFailure.java`
- `music-metadata-system/src/main/java/com/music/metadata/domain/metadata/ValidationFailureType.java`
新增核心服务接口:
- `music-metadata-system/src/main/java/com/music/metadata/service/MetadataReaderService.java`
- `music-metadata-system/src/main/java/com/music/metadata/service/MetadataValidatorService.java`
- `music-metadata-system/src/main/java/com/music/metadata/service/MetadataSnapshotService.java`
### 3.3 读取层实现
读取相关实现由两层组成:
1. `JaudiotaggerAudioTagExtractor`
- 负责调用 Jaudiotagger 读取底层标签与封面信息
- 读取核心字段:`title``artist``album_artist``album``track``year``genre``lyrics``disc``comment`
- 汇总全部可枚举标签字段到 `fields`
- 针对真实 FLAC 文件上 artwork/特殊字段抛异常的情况做了“尽力而为”兼容处理,避免整个读取流程失败
2. `MetadataReaderServiceImpl`
- 将提取结果组装成 `AudioMetadata`
- 自动识别文件格式
- 检测原始编码并尝试对 GBK/GB18030 类乱码做修复
- 解析封面格式、尺寸、二进制数据
- 生成原始元数据 JSON 快照
- 将快照持久化到 `t_metadata_snapshot`
关键文件:
- `music-metadata-system/src/main/java/com/music/metadata/infrastructure/audio/AudioTagExtractor.java`
- `music-metadata-system/src/main/java/com/music/metadata/infrastructure/audio/AudioTagExtractionResult.java`
- `music-metadata-system/src/main/java/com/music/metadata/infrastructure/audio/JaudiotaggerAudioTagExtractor.java`
- `music-metadata-system/src/main/java/com/music/metadata/service/impl/MetadataReaderServiceImpl.java`
### 3.4 一票否决校验实现
`MetadataValidatorServiceImpl` 实现了严格的一票否决制:
- 编码非 UTF-8 且修复失败,立即返回 `ENCODING_ERROR`
- 核心字段按顺序校验:
- `title`
- `artist`
- `album_artist`
- `album`
- `track`
- `cover`
- 任一字段缺失、乱码或不合规,立即返回失败,不继续后续字段校验
已落地规则包括:
- 强制 UTF-8 编码门禁
- `track` 必须为 `序号/总曲目数` 格式,例如 `01/12`
- 封面必须存在,且格式为 JPG/PNG分辨率不小于 `300x300`,比例必须 `1:1`
- 清洗规则涵盖:
- 首尾空白与不可见字符处理
- 非法文件名字符替换
- 多歌手分隔符统一
- 英文字段大小写规范化
- 版本信息从 `title``comment` 迁移
关键文件:
- `music-metadata-system/src/main/java/com/music/metadata/service/impl/MetadataValidatorServiceImpl.java`
### 3.5 元数据快照存储
新增快照实体与持久化层:
- `music-metadata-system/src/main/java/com/music/metadata/infrastructure/entity/MetadataSnapshotEntity.java`
- `music-metadata-system/src/main/java/com/music/metadata/infrastructure/mapper/MetadataSnapshotMapper.java`
- `music-metadata-system/src/main/java/com/music/metadata/service/impl/MetadataSnapshotServiceImpl.java`
数据库脚本新增:
- `t_metadata_snapshot`
对应位置:
- `music-metadata-system/src/main/resources/schema.sql`
## 4. 同阶段补充完成的扫描与去重能力
虽然本次文档主题是“元数据解析与校验”,但当前 P1 代码实际还同时落地了与目录扫描相关的验收能力:
- 目录递归扫描
- 一级哈希去重(`HASH_DUPLICATE`
- 二级特征疑似重复(`LEVEL2_SUSPECT`
- 扫描断点续传
- 已归档文件再次扫描时自动跳过
相关代码:
- `music-metadata-system/src/main/java/com/music/metadata/service/impl/DirectoryScanServiceImpl.java`
- `music-metadata-system/src/main/java/com/music/metadata/service/impl/ScanFileProcessorImpl.java`
- `music-metadata-system/src/main/java/com/music/metadata/service/impl/DeduplicationServiceImpl.java`
- `music-metadata-system/src/main/java/com/music/metadata/service/impl/Sha256FileHashServiceImpl.java`
- `music-metadata-system/src/main/java/com/music/metadata/service/impl/JaudiotaggerAudioDurationServiceImpl.java`
数据库脚本同步新增:
- `t_duplicate_file`
- `t_scan_item`
- `t_file_process.dedup_key`
## 5. 测试策略
P1 阶段测试分为三层:
### 5.1 纯单元测试
用于验证 reader、validator 的规则与边界行为:
- `music-metadata-system/src/test/java/com/music/metadata/service/impl/MetadataReaderServiceImplTest.java`
- `music-metadata-system/src/test/java/com/music/metadata/service/impl/MetadataValidatorServiceImplTest.java`
### 5.2 验收测试
用于直接对应本阶段验收标准:
- `music-metadata-system/src/test/java/com/music/metadata/service/impl/MetadataAcceptanceTest.java`
覆盖内容:
- 能正确读取测试音频文件元数据
- 缺失 `title` 返回 `MISSING_FIELD`
- GBK 中文标签修复成功或返回 `ENCODING_ERROR`
- 无封面返回 `COVER_INVALID`
### 5.3 真实音频集成测试
为满足“真实数据验证”口径,额外新增:
- `music-metadata-system/src/test/java/com/music/metadata/service/impl/RealAudioMetadataIntegrationTest.java`
该测试会:
- 从真实目录 `/home/liujingjing/下载/解压后2` 中选取 FLAC 文件
- 复制到临时目录,避免污染原始音乐库
- 直接使用 `JaudiotaggerAudioTagExtractor` 读取真实文件
- 校验 `fileFormat``title``artist``album``snapshotJson``tagFields`、封面二进制与尺寸
如果需要切换目录,也可通过环境变量 `REAL_AUDIO_DIR` 覆盖默认路径。
### 5.4 覆盖率补强测试
为满足覆盖率要求,补充了基础设施与低覆盖类测试:
- `music-metadata-system/src/test/java/com/music/metadata/service/impl/CoverageSupportTest.java`
- `music-metadata-system/src/test/java/com/music/metadata/service/impl/SimpleServiceImplCoverageTest.java`
- `music-metadata-system/src/test/java/com/music/metadata/service/impl/JaudiotaggerAudioDurationServiceImplTest.java`
### 5.5 测试资源说明
当前仓库未直接提交真实音频二进制测试资源,而是采用两种方式:
- 单元测试中使用 `byte[]` 与 mock extractor 快速构造边界场景
- 在文档中说明真实 fixtures 的构造方式
说明文件:
- `music-metadata-system/src/test/resources/audio-fixtures/README.md`
## 6. 验收结果
### 6.1 P1 核心验收项
| 验收项 | 结果 | 说明 |
|--------|------|------|
| 能正确读取测试音频文件的元数据 | 通过 | `RealAudioMetadataIntegrationTest` 直接读取真实 FLAC 文件通过 |
| 缺失 `title` 字段返回 `MISSING_FIELD` | 通过 | `MetadataAcceptanceTest` 已覆盖 |
| GBK 编码中文标签修复失败返回 `ENCODING_ERROR` | 通过 | `MetadataAcceptanceTest` 已覆盖“修复或失败”路径 |
| 无封面文件返回 `COVER_INVALID` | 通过 | `MetadataAcceptanceTest` 已覆盖 |
| 单元测试覆盖率 ≥ 80% | 通过 | 当前 JaCoCo 行覆盖率为 `88.60%` |
### 6.2 目录扫描附加验收项
| 验收项 | 结果 | 说明 |
|--------|------|------|
| 一级哈希去重 | 通过 | `DirectoryScanP1AcceptanceTest` 已覆盖 |
| 二级疑似重复识别 | 通过 | `DirectoryScanP1AcceptanceTest` 已覆盖 |
| 扫描中断后断点续传 | 通过 | `DirectoryScanP1AcceptanceTest` 已覆盖 1000 文件场景 |
| 已归档文件再次扫描时跳过 | 通过 | `DirectoryScanP1AcceptanceTest` 已覆盖 |
## 7. 验证命令
推荐使用以下命令复验:
```bash
cd music-metadata-system
mvn test
```
针对元数据与真实文件验证,也可执行:
```bash
mvn -q -Dtest=RealAudioMetadataIntegrationTest,MetadataAcceptanceTest,MetadataReaderServiceImplTest,MetadataValidatorServiceImplTest test
```
覆盖率报告输出位置:
- `music-metadata-system/target/site/jacoco/index.html`
- `music-metadata-system/target/site/jacoco/jacoco.csv`
## 8. 偏差与说明
### 8.1 Jaudiotagger 版本偏差
需求中写明 `2.2.7`,但实际可解析并完成稳定构建、测试通过的版本为 `2.2.5`。当前以 `2.2.5` 落地,后续如必须升级,可再做版本可用性验证。
### 8.2 编码修复策略说明
编码检测与乱码修复采用 `juniversalchardet + 启发式修复` 组合策略。对于疑似 GBK/GB18030 的中文乱码,会尝试修复;修复失败时,严格返回 `ENCODING_ERROR`
### 8.3 真实数据与严格校验的关系
真实音频集成测试当前验证的是“能读出来”,而不是“真实目录中的所有文件都能通过 validator”。这是因为真实库中的部分文件可能存在 `album_artist` 缺失、`track` 不为 `01/12` 等情况,属于数据质量问题,不代表读取能力失败。
## 9. 阶段结论
P1 阶段已经完成元数据读取、快照持久化、一票否决校验、编码检测与清洗规则的核心落地,并通过真实音频集成测试、验收测试和覆盖率报告证明当前能力可用。
在此基础上,项目已经具备继续进入后续归档、失败文件人工兜底、权威 API 补全等更高层业务能力开发的条件。