diff --git a/automate.py b/automate.py index 28178d8..3ddc4d6 100644 --- a/automate.py +++ b/automate.py @@ -346,6 +346,26 @@ def get_checked_cells_dynamic(png_path, row_centers): 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(): """从头启动 App,等待 618 开屏广告自动关闭后回到首页。 用 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 会跳过它们, # 从根上消除"重叠行还没下完就被重复点击"这个唯一的重复来源。 - 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 - pending = list(tapped_cells) + done = 0 while waited < max_wait_per_round: time.sleep(poll_interval) waited += poll_interval - ensure_not_anr() # 等待期间 App 也可能卡死,同样要检测 + ensure_not_anr() wait_shot = screenshot("/tmp/_waitchk.png") - # 等待期间未滚动,行位置不变,复用本轮 row_centers 复检这些格子 - chk = get_checked_cells_dynamic(wait_shot, row_centers) - pending = [c for c in tapped_cells if not chk.get(c)] - if not pending: + current_checked = count_checked_badges(wait_shot) + done = current_checked - baseline_checked + if done >= len(tapped_cells): break - done = len(tapped_cells) - len(pending) + pending = len(tapped_cells) - done total = get_remote_new_file_count(baseline) if pending: - # 超时未打勾:先不重试点击(队列满时重试无效),再等一轮让正在下载的完成 - print(f" 轮 {r+1}: 等待 {waited}s 后 {done}/{len(tapped_cells)} 个已打勾," - f"仍有 {len(pending)} 个未完成,继续等待一轮...") + # 第二轮等待:不重试点击,让正在下载的完成 + print(f" 轮 {r+1}: 等待 {waited}s 后 {done}/{len(tapped_cells)} 个已打勾,继续等待...") wait2_waited = 0 while wait2_waited < max_wait_per_round: time.sleep(poll_interval) wait2_waited += poll_interval ensure_not_anr() w2_shot = screenshot("/tmp/_wait2.png") - w2_chk = get_checked_cells_dynamic(w2_shot, row_centers) - still_pending = [c for c in pending if not w2_chk.get(c)] - if not still_pending: + current2 = count_checked_badges(w2_shot) + done = current2 - baseline_checked + if done >= len(tapped_cells): break - if still_pending: - # 两轮等待后仍未打勾,可能是点击没生效(落在间隙上)或队列满被拒绝 - # 再重试点击一次,然后等最后一轮 - print(f" 轮 {r+1}: 再等 {wait2_waited}s 后仍有 {len(still_pending)} 个未完成,重试点击...") - for (gx, cy) in still_pending: + pending = len(tapped_cells) - done + if pending: + # 两轮等待后仍未完成,重试点击所有未完成的卡片 + print(f" 轮 {r+1}: 再等 {wait2_waited}s 后仍有 {pending} 个未完成,重试点击...") + for (gx, cy) in tapped_cells: adb("shell", "input", "tap", str(gx), str(cy)) time.sleep(0.5) 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 ensure_not_anr() retry_shot = screenshot("/tmp/_retrywait.png") - retry_chk = get_checked_cells_dynamic(retry_shot, row_centers) - still_pending = [c for c in still_pending if not retry_chk.get(c)] - if not still_pending: + current3 = count_checked_badges(retry_shot) + done = current3 - baseline_checked + if done >= len(tapped_cells): break - if still_pending: - print(f" 轮 {r+1}: 三轮等待后仍有 {len(still_pending)} 个未完成,照常滚动(靠下游去重兜底)") + pending = len(tapped_cells) - done + if pending: + print(f" 轮 {r+1}: 三轮等待后仍有 {pending} 个未完成,照常滚动(靠下游去重兜底)") else: print(f" 轮 {r+1}: 全部打勾完成") else: