Files
dl-organizer/docs/archive/2026-pre-baseline/CODE_IMPROVEMENTS.md
T
79797644e1 chore: trim dead code, modularize CLI, and archive stale docs
Extract review-plan, report, quarantine, state, and config handlers into
commands/ with shared cli_helpers; remove unused exceptions and duplicate
plan summary wrappers. Archive superseded review markdown, sync docs to
517-test baseline, and fix empty series titles when only a quality tag remains.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 10:36:03 +08:00

8.2 KiB
Raw Blame History

Note

Status: Historical snapshot. Current refactor results and validated baseline are tracked in CHANGELOG.md (updated 2026-04-07).

VLM 代码改进清单

本文档记录对 Video Library Manager (VLM) 项目的代码审查发现的问题及对应解决方案。排除 AI/OpenAPI 相关问题。


高优先级(确信度 ≥ 0.9

1. 时间戳未统一使用 UTC

问题描述

多处使用 datetime.now() 未指定 timezone,与项目约定「timestamps in UTC」不一致,可能导致:

  • 序列化为 ISO 时缺少 +00:00 后缀
  • 多环境部署时依赖本地时区,行为不一致

涉及文件

文件 行号
planner.py 51
executor.py 89, 119, 471
state.py 104, 139, 173
quarantine.py 61, 529

确信度: 0.95

解决方案

  1. vlm/utils.py 或现有模块中定义:
from datetime import datetime, timezone

def utc_now() -> datetime:
    """Return current UTC time (timezone-aware)."""
    return datetime.now(timezone.utc)
  1. 全局替换所有 datetime.now()utc_now()datetime.now(timezone.utc)
  2. load_planload_rollback_log 等反序列化时,对 naive datetime 做 replace(tzinfo=timezone.utc) 以保持向后兼容

2. 未使用的依赖 ffmpeg-python

问题描述

pyproject.toml 声明 ffmpeg-python>=0.2.0,但代码中未 import。scanner 使用 subprocess 直接调用 ffprobe。

确信度: 0.95

解决方案

pyproject.toml 的 dependencies 中移除 ffmpeg-python。若未来改用 ffmpeg-python 库再添加。


3. Parser 中 video extensions 硬编码

问题描述

parser.py 第 100、169 行使用固定扩展名列表 ['.mp4', '.mkv', ...],与 config.video_extensions 不一致。

  • 用户在 config 中新增扩展(如 .ts),scan 能发现,但 parse 去扩展名时不会匹配
  • Movie (2020).ts 可能得到错误的 title 解析

确信度: 0.9

解决方案

  1. parse_movie / parse_series 增加可选参数 extensions: list[str]
  2. CLI parse 命令调用时传入 config.video_extensions
  3. 默认值使用与 config 相同的列表以保持向后兼容

4. 抽出统一的 I/O 层

问题描述

数据读取和转换分散在各 CLI 命令中,同一份 identities JSON 在 analyze、plan 等处有重复且略有不同的转换逻辑。新增字段时需多处同步,易遗漏。

确信度: 0.9

解决方案

新增 vlm/io.py,集中:

  • load_inventory_csv(path) -> list[VideoFile]
  • save_inventory_csv(files, path, library_root)
  • load_identities_json(path) -> dict
  • save_identities_json(data, path)
  • identities_to_plan_input(data) -> list[(VideoFile, Identity | None)]
  • identities_to_analysis_input(data) -> (list[MovieIdentity], list[SeriesIdentity], list[VideoFile])

CLI 只调用这些函数,不再直接解析和构造 dataclass。


5. Analyze 阶段 VideoFile metadata 丢失

问题描述

identities.json 不含 size_bytesresolutioncodec 等,CLI 构造 VideoFile 时用 0 或 None,导致 compare_quality() 无法有效比较,duplicate 报告信息不足。

确信度: 0.9

解决方案

  1. 方案 Aanalyze 命令同时接受 --inventory,从 inventory.csv 加载 metadata 并与 identities 按 path 合并
  2. 方案 Bparse 输出时在 identities 中附带 size/resolution/codec(从 inventory 合并),避免 analyze 再读 inventory

中优先级(确信度 0.80.89

6. 拆分 CLI 为 commands 子模块

问题描述

cli.py 约 1700 行,混合参数定义、业务逻辑、I/O、输出展示,维护和单测困难。

确信度: 0.85

解决方案

src/vlm/
  cli.py              # main、参数、ctx 传递、调用 commands
  commands/
    __init__.py
    scan.py           # scan_cmd(ctx, ...)
    parse.py          # parse_cmd(ctx, ...)
    enrich.py
    analyze.py
    plan.py
    execute.py
    report.py         # 或按子命令拆分
    quarantine.py
    state.py
    config_cmd.py

每个 *_cmd 接收 ctx 和参数,CLI 只做装饰与调用。单测可直接测 *_cmd 函数。


7. Provider last_request_count 非正式接口

问题描述

enrichment.py 使用 getattr(provider, "last_request_count", 1) 统计 API 调用,依赖实现细节。

确信度: 0.85

解决方案

  1. providers/base.pyEnrichmentProvider 协议中显式声明 last_request_count: int 属性
  2. TMDBProvider 确保实现该属性
  3. enrichment 通过协议访问,去掉 getattr

8. 异常捕获过宽

问题描述

约 20+ 处 except Exception,容易吞掉逻辑错误,难以区分可恢复错误与编程错误。

涉及cli.pyenrichment.pyexecutor.pyquarantine.py 等。

确信度: 0.8

解决方案

  • 针对预期异常(FileNotFoundErrorjson.JSONDecodeErrorValueError)分别处理
  • 保留顶层 except Exception 作为兜底,记录完整 traceback 后 sys.exit(1)
  • 避免在业务逻辑深处宽泛捕获

9. Enrichment 主循环过长

问题描述

enrich_identities_data 主循环约 80 行,混合迭代、缓存、API 调用、统计、payload 合并,可读性和可测性差。

确信度: 0.8

解决方案

拆分为:

  • _process_single_record(record, media_type, ...) -> None
  • _fetch_from_providers(record, media_type, providers, ...) -> tuple[dict, int, list, str]
  • _update_stats(stats, ...) -> None
  • 主循环只负责迭代与调用上述函数

较低优先级(确信度 0.70.79

10. Duplicate 检测 file_map 使用 filename 作为 key

问题描述

analysis.py 第 87 行:

file_map = {file.filename: file for file in files}

同 filename 不同路径会互相覆盖(如 /a/Movie.mkv/b/Movie.mkv),导致 identity 映射到错误 VideoFile。

确信度: 0.75

解决方案

  • 使用 str(file.path) 作为 key
  • 确保 identity 与 VideoFile 的关联方式一致(如通过 path 或 (path, filename) 建立映射)

11. MovieIdentity / SeriesIdentity 字段重复

问题描述

两个 dataclass 有约 10 个共同 enrichment 字段,新增时需改两处,合并逻辑需分支处理。

确信度: 0.7

解决方案

  • 方案 A:抽取 EnrichmentMixin 基类,MovieIdentity / SeriesIdentity 继承
  • 方案 B(推荐):引入 EnrichmentPayload dataclass,两个 Identity 通过 enrichment: EnrichmentPayload 组合,侵入较小

12. Config 体积膨胀

问题描述

Config 约 50 个字段,enrichment/TMDB 相关占多数,职责混杂。

确信度: 0.7

解决方案

拆分 EnrichmentConfigTMDBConfig 等子配置,通过嵌套或组合放入主 Config。


13. review_status 与 needs_review 语义重叠

问题描述

review_statuspending/approved/rejected)与 needs_reviewbool)含义重叠,易混淆。

确信度: 0.75

解决方案

  • 在 docstring 或文档中明确定义:needs_review = (review_status == 'pending') and ...
  • 或在模型中合并为单一状态枚举,避免两个字段语义交叉

低优先级(确信度 < 0.7

14. config_init 与 ctx 一致性

问题描述

config init 未使用 @pass_context,与同组其他命令风格不一致,但当前不依赖 ctx,非功能性 bug。

确信度: 0.5

解决方案

若其他 config 子命令均用 @pass_context,可统一为 config_init 也接收 ctx 以保持风格一致;否则可保持现状。


15. CLI 延迟 import

问题描述

各命令在函数体内才 import,错误在首次执行该命令时才暴露,依赖关系不直观。

确信度: 0.6

解决方案

可接受;若希望启动时即发现依赖问题,可改为模块级 import,但会增加启动开销。


执行建议

阶段 项目 说明
第一批 1, 2, 3 改动小、风险低、收益明确
第二批 4, 5 需要一定重构,与 I/O 设计相关
第三批 6, 7, 8, 9 结构性改进,建议分步完成
第四批 1015 按需和档期安排

文档生成日期:2025-02-10