fix: 打勾检测改用全局蓝色角标计数,不受列表滚动漂移影响

根因:等待期间列表轻微滚动(约50px),用点击时的旧行坐标检测打勾
位置偏移,导致明明已打勾却检测不到0/6,误判为下载失败。

修复:
- 新增 count_checked_badges():扫描整屏蓝色角标总数,不依赖行坐标
- 等待逻辑改为:点击前记基线→等待期间统计当前总数→
  增量>=点击数即完成
- 重试逻辑同步改用全局计数
This commit is contained in:
yuming
2026-09-18 21:44:17 +08:00
parent 317bd3020d
commit 011eb51cfb
+45 -24
View File
@@ -346,6 +346,26 @@ def get_checked_cells_dynamic(png_path, row_centers):
return checked return checked
def count_checked_badges(png_path):
"""统计整屏已打勾(蓝色角标)的卡片数量,不依赖行坐标。
等待期间列表可能轻微滚动,用绝对坐标检测打勾会偏移,
改为直接扫描整屏蓝色角标总数,不受行位置漂移影响。"""
try:
with Image.open(png_path) as img:
img = img.convert("RGB")
w, h = img.size
cnt = 0
# 扫描卡片区域内所有可能的角标位置(3列 × 多行)
for gx in THUMB_X:
for cy in range(ROW_Y0 + 100, ROW_Y1, ROW_PITCH):
bx, by = gx + BADGE_OFFSET[0], cy + BADGE_OFFSET[1]
if count_blue_pixels(png_path, bx, by) >= BLUE_THRESHOLD:
cnt += 1
return cnt
except Exception:
return 0
def launch_app(): def launch_app():
"""从头启动 App,等待 618 开屏广告自动关闭后回到首页。 """从头启动 App,等待 618 开屏广告自动关闭后回到首页。
用 am start -S 强制重启主 Activity(比 monkey 更可靠:避免之前残留的 用 am start -S 强制重启主 Activity(比 monkey 更可靠:避免之前残留的
@@ -731,40 +751,40 @@ def tap_all_thumbnails(baseline, max_rounds=300, poll_interval=4, max_wait_per_r
# 关键:等这一轮点击的卡片全部显示打勾(下载完成)再滚动。这样滚动 # 关键:等这一轮点击的卡片全部显示打勾(下载完成)再滚动。这样滚动
# 留下的重叠行必然是打勾状态,下一轮开头 get_checked_cells 会跳过它们, # 留下的重叠行必然是打勾状态,下一轮开头 get_checked_cells 会跳过它们,
# 从根上消除"重叠行还没下完就被重复点击"这个唯一的重复来源。 # 从根上消除"重叠行还没下完就被重复点击"这个唯一的重复来源。
print(f" 轮 {r+1}: 等待刚点击的 {len(tapped_cells)} 个卡片全部打勾(最多 {max_wait_per_round}s)...") baseline_checked = count_checked_badges(grid_shot)
target_checked = baseline_checked + len(tapped_cells)
print(f" 轮 {r+1}: 等待刚点击的 {len(tapped_cells)} 个卡片全部打勾(基线 {baseline_checked},目标 {target_checked})...")
waited = 0 waited = 0
pending = list(tapped_cells) done = 0
while waited < max_wait_per_round: while waited < max_wait_per_round:
time.sleep(poll_interval) time.sleep(poll_interval)
waited += poll_interval waited += poll_interval
ensure_not_anr() # 等待期间 App 也可能卡死,同样要检测 ensure_not_anr()
wait_shot = screenshot("/tmp/_waitchk.png") wait_shot = screenshot("/tmp/_waitchk.png")
# 等待期间未滚动,行位置不变,复用本轮 row_centers 复检这些格子 current_checked = count_checked_badges(wait_shot)
chk = get_checked_cells_dynamic(wait_shot, row_centers) done = current_checked - baseline_checked
pending = [c for c in tapped_cells if not chk.get(c)] if done >= len(tapped_cells):
if not pending:
break break
done = len(tapped_cells) - len(pending) pending = len(tapped_cells) - done
total = get_remote_new_file_count(baseline) total = get_remote_new_file_count(baseline)
if pending: if pending:
# 超时未打勾:先不重试点击(队列满时重试无效),再等一轮让正在下载的完成 # 第二轮等待:不重试点击,让正在下载的完成
print(f" 轮 {r+1}: 等待 {waited}s 后 {done}/{len(tapped_cells)} 个已打勾," print(f" 轮 {r+1}: 等待 {waited}s 后 {done}/{len(tapped_cells)} 个已打勾,继续等待...")
f"仍有 {len(pending)} 个未完成,继续等待一轮...")
wait2_waited = 0 wait2_waited = 0
while wait2_waited < max_wait_per_round: while wait2_waited < max_wait_per_round:
time.sleep(poll_interval) time.sleep(poll_interval)
wait2_waited += poll_interval wait2_waited += poll_interval
ensure_not_anr() ensure_not_anr()
w2_shot = screenshot("/tmp/_wait2.png") w2_shot = screenshot("/tmp/_wait2.png")
w2_chk = get_checked_cells_dynamic(w2_shot, row_centers) current2 = count_checked_badges(w2_shot)
still_pending = [c for c in pending if not w2_chk.get(c)] done = current2 - baseline_checked
if not still_pending: if done >= len(tapped_cells):
break break
if still_pending: pending = len(tapped_cells) - done
# 两轮等待后仍未打勾,可能是点击没生效(落在间隙上)或队列满被拒绝 if pending:
# 再重试点击一次,然后等最后一轮 # 两轮等待后仍未完成,重试点击所有未完成的卡片
print(f" 轮 {r+1}: 再等 {wait2_waited}s 后仍有 {len(still_pending)} 个未完成,重试点击...") print(f" 轮 {r+1}: 再等 {wait2_waited}s 后仍有 {pending} 个未完成,重试点击...")
for (gx, cy) in still_pending: for (gx, cy) in tapped_cells:
adb("shell", "input", "tap", str(gx), str(cy)) adb("shell", "input", "tap", str(gx), str(cy))
time.sleep(0.5) time.sleep(0.5)
retry_waited = 0 retry_waited = 0
@@ -773,12 +793,13 @@ def tap_all_thumbnails(baseline, max_rounds=300, poll_interval=4, max_wait_per_r
retry_waited += poll_interval retry_waited += poll_interval
ensure_not_anr() ensure_not_anr()
retry_shot = screenshot("/tmp/_retrywait.png") retry_shot = screenshot("/tmp/_retrywait.png")
retry_chk = get_checked_cells_dynamic(retry_shot, row_centers) current3 = count_checked_badges(retry_shot)
still_pending = [c for c in still_pending if not retry_chk.get(c)] done = current3 - baseline_checked
if not still_pending: if done >= len(tapped_cells):
break break
if still_pending: pending = len(tapped_cells) - done
print(f" 轮 {r+1}: 三轮等待后仍有 {len(still_pending)} 个未完成,照常滚动(靠下游去重兜底)") if pending:
print(f" 轮 {r+1}: 三轮等待后仍有 {pending} 个未完成,照常滚动(靠下游去重兜底)")
else: else:
print(f" 轮 {r+1}: 全部打勾完成") print(f" 轮 {r+1}: 全部打勾完成")
else: else: