feat: 校验进度条+单文件日志 (on_file 回调)

This commit is contained in:
AskaEth committed 2026-08-22 15:02:12 +08:00
1 parent 0f9866a031
commit 0b28d26a18
3 files changed
+55 -4

No files matched your search

+26 -4
View File
@@ -97,11 +97,13 @@ def files_identical(path_a: str, path_b: str, chunk: int = 1 << 20) -> bool:
def verify_recent_files(src_dir: str, dst_dir: str, check_count: int = 5,
max_size: int = 100 * 1024 * 1024) -> list[str]:
max_size: int = 100 * 1024 * 1024,
on_file=None) -> list[str]:
"""智能续传: 校验目标最新 N 个文件与源一致性, 返回损坏/缺失列表并删除目标坏副本
- <=max_size 的文件: 大小 + 内容 hash 全校验
- >max_size 的文件: 只查大小 (内容由后续 rsync --append 兜底)
- on_file(i, total, rel, ok): 每文件进度回调 (i 从 1 开始)
- 返回需重传的相对路径列表 (目标坏副本已删除)
"""
bad: list[str] = []
@@ -113,19 +115,28 @@ def verify_recent_files(src_dir: str, dst_dir: str, check_count: int = 5,
full = os.path.join(root, name)
recent.append((os.path.getmtime(full), os.path.relpath(full, dst_dir)))
recent.sort(reverse=True)
for _mtime, rel in recent[:check_count]:
total = min(check_count, len(recent))
for idx, (_mtime, rel) in enumerate(recent[:check_count], 1):
sp = os.path.join(src_dir, rel)
tp = os.path.join(dst_dir, rel)
if not os.path.isfile(sp):
continue # 源无此文件(目标多余), 不处理
if on_file:
on_file(idx, total, rel, True) # 源无此文件, 跳过
continue
if not os.path.isfile(tp) or os.path.getsize(sp) != os.path.getsize(tp):
bad.append(rel)
if os.path.exists(tp):
os.remove(tp)
if on_file:
on_file(idx, total, rel, False)
continue
if os.path.getsize(tp) <= max_size and not files_identical(sp, tp):
bad.append(rel)
os.remove(tp)
if on_file:
on_file(idx, total, rel, False)
elif on_file:
on_file(idx, total, rel, True)
return bad
@@ -688,7 +699,18 @@ class TaskRunner:
self.lm.write(f"smart-resume: 校验目标最新 {self.cfg.smart_check} 个文件...")
if self.on_log:
self.on_log(f"[cyan]智能续传: 校验最近 {self.cfg.smart_check} 个文件...[/]")
bad = verify_recent_files(src_dir, dst_dir, self.cfg.smart_check)
def on_verify_file(idx: int, total: int, rel: str, ok: bool) -> None:
# 校验进度: 复用 stats 驱动进度条 + 日志栏每文件输出
self.stats.bytes_done = idx
self.stats.bytes_total = total
self.stats.pct = idx / max(1, total) * 100
self._emit_stats()
if self.on_log:
mark = "✓" if ok else "✘ 损坏"
self.on_log(f"校验 {idx}/{total}: {os.path.basename(rel)} {mark}")
bad = verify_recent_files(src_dir, dst_dir, self.cfg.smart_check,
on_file=on_verify_file)
if bad:
self.lm.write(f"smart-resume: 发现 {len(bad)} 个损坏/缺失, 将重传: {bad}")
if self.on_log: