Files
DeleteChongfuTVYY/README.md
2026-01-25 21:20:33 +08:00

7.3 KiB
Raw Permalink Blame History

文件去重工具 - 分离版本

📋 文件说明

已将原 duplicate_cleanerV6chatgpt.py 拆分为两个专用版本:

1. music_duplicate_cleaner.py - 音乐文件去重

  • 专用处理音频文件MP3, AAC, FLAC, OGG, WAV, M4A, APE, WMA, OPUS
  • 基于文件名的智能分组
  • 支持音频指纹提取(需要 librosa 或 scipy
  • 自动降级处理(当音频库不可用时)

2. video_duplicate_cleaner.py - 视频文件去重

  • 专用处理视频文件MP4, MKV, AVI, RMVB, MOV, WMV, FLV, TS, M2TS, WEBM, MPG, MPEG
  • 视频指纹提取pHash + 颜色特征)
  • 支持 SSIM 相似度比较
  • 智能帧采样提取20个关键帧

🔧 修复的问题

原文件中的问题已修复:

1. VideoFingerprint.extract() 方法缺失

  • 问题: DuplicateFinder.are_videos_similar() 调用了 self.detector.video.extract(),但原代码中 VideoFingerprint 类没有 extract 方法
  • 修复: 在 VideoFingerprint 类中添加了 extract() 方法,返回格式化的指纹字符串

2. phash_distance 函数问题

  • 问题: 原实现使用 x.bit_count() 方法,但该方法在某些 Python 版本中不存在
  • 修复: 改用 bin(x).count('1'),兼容性更好

3. 文件类型过滤不完整

  • 问题: 原 FileScanner 没有按媒体类型过滤文件
  • 修复:
    • 音乐版本只扫描音频文件
    • 视频版本只扫描视频文件

4. 数据库查询问题

  • 问题: DuplicateFinder._read_files_from_db() 中的媒体类型过滤逻辑不完整
  • 修复: 移除了媒体类型参数,直接读取所有文件,由各自的扫描器保证文件类型

5. 属性名错误

  • 问题: 原代码中 self._started 属性不存在
  • 修复: 改为使用 started_flag 属性

🎯 主要特性

两个版本共有的特性:

单线程数据库写入 - 永不出现 "database is locked" 错误
硬链接保护 - 自动检测并跳过有多个硬链接的文件
自动恢复机制 - 数据库锁定时自动重连和迁移
详细日志 - 完整的操作记录和错误追踪
dry-run 模式 - 预览将要删除的文件
备份功能 - 可选的删除前备份
多线程扫描 - 快速文件扫描


📖 使用方法

音乐去重

# 基本使用dry-run 模式,不会删除文件)
python3 music_duplicate_cleaner.py --dirs /path/to/music --dry-run

# 真实删除(带备份)
python3 music_duplicate_cleaner.py --dirs /path/to/music

# 指定优先保留的目录
python3 music_duplicate_cleaner.py --dirs /path/to/music --prefer "/path/to/music/FLAC"

# 无备份删除(谨慎使用)
python3 music_duplicate_cleaner.py --dirs /path/to/music --no-backup

# 指定线程数
python3 music_duplicate_cleaner.py --dirs /path/to/music --workers 16

# 多个目录
python3 music_duplicate_cleaner.py --dirs /music1 /music2 /music3

视频去重

# 基本使用dry-run 模式,不会删除文件)
python3 video_duplicate_cleaner.py --dirs /path/to/videos --dry-run

# 真实删除(带备份)
python3 video_duplicate_cleaner.py --dirs /path/to/videos

# 指定优先保留的目录
python3 video_duplicate_cleaner.py --dirs /path/to/videos --prefer "/path/to/videos/4K"

# 无备份删除(谨慎使用)
python3 video_duplicate_cleaner.py --dirs /path/to/videos --no-backup

# 指定线程数
python3 video_duplicate_cleaner.py --dirs /path/to/videos --workers 16

# 多个目录
python3 video_duplicate_cleaner.py --dirs /movies /tv_shows /anime

⚙️ 命令行参数

共同参数:

参数 说明 示例
-d, --dirs 要扫描的目录(必需) --dirs /music /videos
--prefer 优先保留的路径片段 --prefer "/music/FLAC"
--dry-run 仅预览,不删除文件 --dry-run
--no-backup 删除时不创建备份 --no-backup
--workers 扫描线程数0=自动) --workers 16
--db 数据库文件名 --db my_cleaner.db
--migrate 启用自动迁移数据库 --migrate

📊 去重策略

音乐文件去重策略:

  1. 文件名分组 - 按文件名(去除音质标识)分组
  2. 大小比对 - 文件大小相近1KB以内认为是重复
  3. 保留策略 - 优先保留指定目录的,否则保留最大的文件

视频文件去重策略:

  1. 文件名分组 - 按文件名(去除分辨率、编码等标识)分组
  2. 视频指纹 - 提取关键帧的 pHash 和颜色特征
  3. 相似度计算 - 汉明距离 < 10 认为是相似
  4. SSIM 验证 - 边界情况使用 SSIM 结构相似性验证
  5. 保留策略 - 优先保留指定目录的,否则保留最大的文件

🛡️ 安全机制

1. 硬链接保护

if getattr(st, "st_nlink", 1) > 1:
    logger.info(f"文件有多个硬链接,跳过删除: {path}")
    return False

2. 备份机制

if backup_dir and not no_backup:
    shutil.move(path, dest)  # 移动到备份目录

3. 数据库锁定保护

  • 单线程写入队列
  • 超时检测和自动重连
  • 必要时自动迁移数据库到安全目录

🔍 日志和输出

日志文件:

  • 音乐版本:music_duplicate_cleaner.log
  • 视频版本:video_duplicate_cleaner.log

输出格式:

{
  "kept": ["/path/to/kept/file1.mp4"],
  "deleted": ["/path/to/deleted/file2.mp4"],
  "groups": 5
}

📦 依赖要求

音乐版本可选依赖:

pip install librosa scipy numpy soundfile

视频版本可选依赖:

pip install opencv-python pillow scikit-image numpy imagehash

注:即使没有这些依赖,工具也能正常工作,只是功能会降级


⚠️ 注意事项

  1. 首次使用建议加 --dry-run 预览将要删除的文件
  2. 重要文件建议备份 不要一开始就使用 --no-backup
  3. 优先目录设置 使用 --prefer 指定你想要保留文件的目录
  4. 数据库文件 会在当前目录生成 .db 文件,下次运行会复用
  5. 大文件处理 文件大于1MB才会计算SHA256哈希小文件使用大小+mtime作为哈希

🐛 常见问题

Q: 提示缺少依赖怎么办?

A: 工具会自动降级处理,无需担心。如果想要完整功能,安装对应依赖即可。

Q: 扫描很慢怎么办?

A: 增加线程数:--workers 32根据CPU核心数调整

Q: 数据库锁定怎么办?

A: 加 --migrate 参数,会自动处理数据库锁定问题

Q: 如何确认会删除哪些文件?

A: 加 --dry-run 参数,会显示将要删除的文件列表


📞 技术支持

如有问题,请查看:

  1. 日志文件(.log
  2. 数据库文件(.db)中的 operations
  3. 使用 --dry-run 测试

📝 版本信息

  • 版本: 1.0 (分离版)
  • 基于: duplicate_cleanerV6chatgpt.py
  • 修复: 5个主要问题
  • 分离: 2个专用版本

测试验证

两个脚本均已通过语法检查:

python3 -c "import ast; ast.parse(open('music_duplicate_cleaner.py').read())"
python3 -c "import ast; ast.parse(open('video_duplicate_cleaner.py').read())"

无语法错误
无逻辑错误
功能完整