Files
video-metadata-analyzer/docs/plans/2026-04-02-video-metadata-analyzer.md
T

235 lines
6.0 KiB
Markdown

# Video Metadata Analyzer Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 构建一个基于 Python + uv 的命令行视频元数据分析器,递归扫描一个或多个目录,调用 ffprobe/ffmpeg 汇总视频元数据,并输出 JSON、CSV 和静态 HTML 可视化报告。
**Architecture:** 项目采用 `src/` 布局的 CLI 应用。扫描层负责发现视频文件;探测层调用 ffprobe 获取结构化元数据,并调用 ffmpeg 记录运行环境能力;分析层负责做总量统计、分布分箱和类别汇总;报告层输出机器可读 JSON/CSV 以及带内嵌 SVG 图表的 HTML 报告,避免引入浏览器端框架依赖。
**Tech Stack:** Python 3.11+、uv、pytest、ffprobe、ffmpeg、标准库 `argparse/json/csv/pathlib/subprocess/statistics/html`
---
### Task 1: 建立 uv 项目基础
**Files:**
- Create: `pyproject.toml`
- Create: `src/video_metadata_analyzer/__init__.py`
- Create: `tests/__init__.py`
**Step 1: Write the failing test**
```python
def test_package_version_is_exposed():
from video_metadata_analyzer import __version__
assert __version__
```
**Step 2: Run test to verify it fails**
Run: `uv run pytest tests/test_package.py::test_package_version_is_exposed -v`
Expected: FAIL with `ModuleNotFoundError` or missing `__version__`
**Step 3: Write minimal implementation**
```python
__version__ = "0.1.0"
```
**Step 4: Run test to verify it passes**
Run: `uv run pytest tests/test_package.py::test_package_version_is_exposed -v`
Expected: PASS
**Step 5: Commit**
```bash
git add pyproject.toml src/video_metadata_analyzer/__init__.py tests/test_package.py
git commit -m "chore: initialize uv project skeleton"
```
### Task 2: 实现视频文件发现
**Files:**
- Create: `tests/test_discovery.py`
- Create: `src/video_metadata_analyzer/discovery.py`
**Step 1: Write the failing test**
```python
def test_discover_video_files_recursively_filters_supported_extensions(tmp_path):
...
```
**Step 2: Run test to verify it fails**
Run: `uv run pytest tests/test_discovery.py::test_discover_video_files_recursively_filters_supported_extensions -v`
Expected: FAIL with missing function
**Step 3: Write minimal implementation**
```python
def discover_video_files(inputs: list[Path]) -> list[Path]:
...
```
**Step 4: Run test to verify it passes**
Run: `uv run pytest tests/test_discovery.py::test_discover_video_files_recursively_filters_supported_extensions -v`
Expected: PASS
**Step 5: Commit**
```bash
git add tests/test_discovery.py src/video_metadata_analyzer/discovery.py
git commit -m "feat: add recursive video discovery"
```
### Task 3: 实现 ffprobe 元数据解析
**Files:**
- Create: `tests/test_probe.py`
- Create: `src/video_metadata_analyzer/models.py`
- Create: `src/video_metadata_analyzer/probe.py`
**Step 1: Write the failing test**
```python
def test_probe_video_metadata_parses_primary_streams():
...
```
**Step 2: Run test to verify it fails**
Run: `uv run pytest tests/test_probe.py::test_probe_video_metadata_parses_primary_streams -v`
Expected: FAIL with missing class or parser
**Step 3: Write minimal implementation**
```python
@dataclass
class VideoMetadata:
...
```
**Step 4: Run test to verify it passes**
Run: `uv run pytest tests/test_probe.py::test_probe_video_metadata_parses_primary_streams -v`
Expected: PASS
**Step 5: Commit**
```bash
git add tests/test_probe.py src/video_metadata_analyzer/models.py src/video_metadata_analyzer/probe.py
git commit -m "feat: parse metadata from ffprobe output"
```
### Task 4: 实现聚合分析与图表数据
**Files:**
- Create: `tests/test_analysis.py`
- Create: `src/video_metadata_analyzer/analysis.py`
**Step 1: Write the failing test**
```python
def test_build_summary_computes_totals_and_histograms():
...
```
**Step 2: Run test to verify it fails**
Run: `uv run pytest tests/test_analysis.py::test_build_summary_computes_totals_and_histograms -v`
Expected: FAIL with missing function
**Step 3: Write minimal implementation**
```python
def build_summary(records: list[VideoMetadata]) -> AnalysisSummary:
...
```
**Step 4: Run test to verify it passes**
Run: `uv run pytest tests/test_analysis.py::test_build_summary_computes_totals_and_histograms -v`
Expected: PASS
**Step 5: Commit**
```bash
git add tests/test_analysis.py src/video_metadata_analyzer/analysis.py
git commit -m "feat: add aggregate analysis summaries"
```
### Task 5: 实现报告输出与 CLI
**Files:**
- Create: `tests/test_report.py`
- Create: `tests/test_cli.py`
- Create: `src/video_metadata_analyzer/reporting.py`
- Create: `src/video_metadata_analyzer/cli.py`
**Step 1: Write the failing test**
```python
def test_write_reports_creates_json_csv_and_html(tmp_path):
...
```
**Step 2: Run test to verify it fails**
Run: `uv run pytest tests/test_report.py::test_write_reports_creates_json_csv_and_html -v`
Expected: FAIL with missing writer
**Step 3: Write minimal implementation**
```python
def write_report_bundle(output_dir: Path, ...):
...
```
**Step 4: Run test to verify it passes**
Run: `uv run pytest tests/test_report.py::test_write_reports_creates_json_csv_and_html -v`
Expected: PASS
**Step 5: Commit**
```bash
git add tests/test_report.py tests/test_cli.py src/video_metadata_analyzer/reporting.py src/video_metadata_analyzer/cli.py
git commit -m "feat: add report writers and CLI entrypoint"
```
### Task 6: 文档与验收
**Files:**
- Create: `README.md`
**Step 1: Write the failing test**
```python
def test_readme_mentions_uv_run_command():
...
```
**Step 2: Run test to verify it fails**
Run: `uv run pytest tests/test_cli.py::test_readme_mentions_uv_run_command -v`
Expected: FAIL because README or command example is absent
**Step 3: Write minimal implementation**
补充中文 README,写明依赖、安装、运行方式、输出文件说明和常见问题。
**Step 4: Run test to verify it passes**
Run: `uv run pytest -q`
Expected: PASS
**Step 5: Commit**
```bash
git add README.md
git commit -m "docs: add usage guide for video metadata analyzer"
```