TG Video Check

针对 Telegram 导出场景的视频损坏检测 CLI,重点识别“下载被跳过或中断后留下的半截视频文件”,并支持后续统计、导出和批量删除。

项目目标

这个工具当前解决的是比较具体的一类问题,不是通用媒体法医工具:

  • Telegram 导出目录里存在大量视频文件
  • 一部分文件扩展名、文件名都正常,但内容其实已经不完整
  • 目标是尽快筛出高置信度坏文件,而不是对所有视频做最重的完整解码
  • 结果要能落盘、复跑、导出,并且最终支持批量删除

当前能力

  • 递归扫描一个或多个目录中的常见视频扩展名
  • 支持从 txt 文件批量导入目录列表
  • 使用 SQLite 落盘扫描状态,并基于 path + size + mtime 复用旧结果
  • stage1 使用 ffprobe 做容器级快速校验
  • stage2 只对可疑文件使用 ffmpeg 做定向采样或完整确认
  • 扫描过程中输出 discovery、stage1、stage2 的阶段进度
  • 输出 JSONL / CSV 报告
  • 支持按扫描结果做 confirmed_broken 文件删除预览和真实删除

目录结构

当前项目已经放在仓库根目录,核心内容如下:

在别的机器上使用

最稳的方式是把整个项目目录复制到目标机器,然后在目标机器本地重新创建虚拟环境并安装项目。不要直接把本机 .venv 原样复制过去继续用。

前置条件

目标机器至少需要:

  • Windows
  • Python 3.12+
  • ffprobe 可用
  • ffmpeg 可用

先验证:

python --version
ffprobe -version
ffmpeg -version

如果上面任一命令不可用,先把运行环境补齐。

方式 1:复制项目目录后本地安装

把项目目录复制到目标机器,例如:

D:\tools\clean-broken-tgvideos

然后进入项目根目录执行:

python -m venv .venv
.\.venv\Scripts\python.exe -m ensurepip
.\.venv\Scripts\python.exe -m pip install -e .

验证入口是否正常:

.\.venv\Scripts\tgvideo-check.exe --help
.\.venv\Scripts\tgvideo-check.exe scan --help

方式 2:如果目标机器也装了 uv

uv sync
uv run tgvideo-check --help

这种方式更省事,但前提是目标机器本身已经能使用 uv。

迁移后的最小验收

不要一开始就扫正式目录,先用一个小目录做最小验收:

.\.venv\Scripts\tgvideo-check.exe scan "D:\small-test" --db ".\small-test.db" --export-jsonl ".\small-test.jsonl" --export-csv ".\small-test.csv"

如果能正常看到 discovery/stage1/stage2 进度以及最终扫描摘要,并生成 db/jsonl/csv 三个文件,说明目标机器环境基本没问题。

基本扫描用法

直接传目录

tgvideo-check scan "D:\Exports\ChatA" "D:\Exports\ChatB" --profile tg-hdd

用 txt 批量导入目录

tgvideo-check scan --paths-file .\dirs.txt --db .\scan_state.db --export-jsonl .\results.jsonl --export-csv .\results.csv

混合使用

tgvideo-check scan "D:\extra-folder" --paths-file .\dirs.txt --db .\scan_state.db

常用参数

  • --db:指定 SQLite 状态库
  • --paths-file:从 txt 文件读取目录列表,一行一个目录
  • --export-jsonl / --export-csv:导出结果报告
  • --stage1-workers / --stage2-workers:覆盖 profile 默认 worker 数
  • --queue-limit:限制单阶段批次大小,避免把待处理文件一次性堆进内存
  • --full-decode-confirm:对 stage2 强制使用完整解码确认
  • --resume / --no-resume:控制是否复用旧结果

--paths-file 规则

  • 按 UTF-8 / UTF-8 BOM 读取
  • 一行一个目录
  • 空行自动跳过
  • 行内空格、中文、方括号、感叹号等字符按字面值保留
  • 如果整行外面包了一层单引号或双引号,会自动去掉外层引号

示例 dirs.txt:

D:\TG Export A
"D:\带空格 和 [特殊字符] 的目录"
D:\普通目录

小目录测试建议

如果要先验证工具效果,不要一上来扫正式目录。更稳的做法是先准备一个小样本目录,例如:

  • 3 到 5 个确认正常的视频
  • 2 到 3 个你故意截断的坏视频
  • 5 到 10 个真实导出样本

推荐测试命令:

tgvideo-check scan "D:\small-test" --db ".\small-test.db" --export-jsonl ".\small-test.jsonl" --export-csv ".\small-test.csv"

重点看:

  • confirmed_broken 是否命中了你故意造坏的样本
  • passed_stage2 里是否混进了你明知已坏的文件
  • 是否误伤了你确认正常的视频

状态说明

导出的 final_status / final_status_zh 含义如下:

状态码 中文说明 含义
confirmed_broken 明确损坏 高置信度确认文件损坏,适合进入删除候选
suspicious 可疑 有异常迹象,但证据还不足以直接当作明确损坏
passed_stage1 第一轮通过 容器级快速校验通过,未进入第二轮
passed_stage2 第二轮通过 进入第二轮后仍通过采样或确认校验
skipped 已跳过 预留状态
command_error 命令异常 ffprobe / ffmpeg 执行失败,不应直接视为媒体损坏

原因码说明

导出的 reason_code / reason_code_zh 含义如下:

原因码 中文说明 典型含义
ffprobe_exit_nonzero ffprobe 返回非零退出码,通常表示容器或头部校验失败 第一轮就明显坏了
ffmpeg_exit_nonzero ffmpeg 返回非零退出码,通常表示采样或解码失败 第二轮校验失败
invalid_nal_unit_size 视频流 NAL 单元尺寸异常,常见于截断文件 码流被截断或破损
truncating_packet 视频包被截断,常见于下载中断或文件不完整 明显的半截文件特征
decode_slice_header_error 视频切片头解析失败,通常表示码流损坏 解码阶段发现流损坏
corrupt_input_packet 输入数据包损坏,码流存在明显异常 包级别损坏
hard_error_keyword 命中高置信度损坏错误关键词 第一轮错误信息直接确认坏
soft_warning_keyword 命中软告警关键词,因此升级到第二轮验证 第一轮不够致命,但值得复核
missing_video_stream 没有检测到视频流 文件不是有效视频
missing_format_name 无法识别容器格式 容器头部或格式识别失败
invalid_duration 时长字段异常,因此升级到第二轮验证 容器信息不完整或异常
high_risk_extension 高风险扩展名,因此升级到第二轮验证 根据 profile 规则升级复核
passed_stage1 容器级快速校验通过 第一轮结束即可放行
passed_stage2 第二轮采样或确认校验通过 第二轮也没发现问题
command_error 外部命令执行异常 环境问题,不应直接删文件
missing_command 缺少 ffprobe 或 ffmpeg 外部命令 机器环境不完整
invalid_probe_output ffprobe 输出不是可解析的 JSON 外部命令输出异常
timeout 命令执行超时 文件过大、设备慢或进程卡住

CSV 与 Office

当前 CSV 导出采用 UTF-8 BOM,并附带中文说明列:

  • final_status_zh
  • reason_code_zh

这是为了尽量兼容 Windows 上的 Office / Excel 默认打开行为,减少中文乱码问题。

如果你已经打开过旧版 CSV,建议:

  1. 关闭旧文件
  2. 用当前版本重新导出 CSV
  3. 再重新用 Office 打开新文件

删除已确认损坏文件

先预览:

tgvideo-check prune --db .\scan_state.db

默认行为:

  • 默认 --dry-run
  • 默认只处理 confirmed_broken
  • 输出匹配数量、删除数量、总字节数、原因统计

确认后执行真实删除:

tgvideo-check prune --db .\scan_state.db --no-dry-run

如果后续你明确要扩大删除范围,可以传:

tgvideo-check prune --db .\scan_state.db --delete-status confirmed_broken,suspicious

但这不是默认推荐,因为 suspicious 仍然代表边界文件,不应默认直接删。

删除输出字段说明:

  • matched:命中删除条件的文件数
  • deleted:本次实际删除成功的文件数
  • missing:数据库里有记录,但磁盘上已经不存在的文件数
  • failed:尝试删除但失败的文件数
  • bytes:命中的文件总大小
  • Deleted bytes:本次实际删除成功的总大小

推荐删除流程:

  1. 先跑 prune --dry-run
  2. 看 matched 和 Reasons
  3. 必要时打开 CSV 抽查几条
  4. 确认没问题后再执行 --no-dry-run

性能 Smoke

仓库内提供了 tests/test_perf_smoke.py,默认跳过,不把环境波动硬编码成普通单测。

手动运行方式:

$env:TGVIDEO_RUN_PERF_SMOKE='1'
uv run pytest tests/test_perf_smoke.py -q

这个 smoke 目前只做两件事:

  • 生成一批最小测试视频
  • 分别跑 stage1_workers=1 和 stage1_workers=2,确认基线采集流程可执行

它不是严格 benchmark;真正的默认参数取舍,仍应基于真实 HDD 数据集人工复核。

S
Description
清理因点击跳过导致的tg视频损坏
Readme 266 KiB
Languages
Python 100%