'commit'
This commit is contained in:
@@ -73,8 +73,24 @@ async def get_station_list(d, service, max_scrolls=MAX_SCROLLS):
|
|||||||
logger.info("检查是否存在广告弹窗...")
|
logger.info("检查是否存在广告弹窗...")
|
||||||
ad_res = await ReadImageKit.detect_ad_popup(screenshot_path, device_info=device_info)
|
ad_res = await ReadImageKit.detect_ad_popup(screenshot_path, device_info=device_info)
|
||||||
if ad_res:
|
if ad_res:
|
||||||
logger.info(f"检测到广告弹窗,准备关闭: {ad_res}")
|
ad_type = ad_res.get("ad_type")
|
||||||
d.click(ad_res['x'], ad_res['y'])
|
logger.info(f"检测到广告弹窗,准备关闭: {ad_res} [Type: {ad_type}]")
|
||||||
|
|
||||||
|
x, y = ad_res['x'], ad_res['y']
|
||||||
|
|
||||||
|
if ad_type == "rabbit":
|
||||||
|
logger.info(">>> 检测到顽固的兔子广告,执行强力双击策略...")
|
||||||
|
# 使用 u2 的 double_click,它比两次 click + sleep 更快
|
||||||
|
d.double_click(x, y, duration=0.05)
|
||||||
|
|
||||||
|
# 处理“误触背景卡片”的逻辑
|
||||||
|
logger.info(">>> 考虑到可能误触背景卡片,等待 2s 后执行返回操作...")
|
||||||
|
await asyncio.sleep(2.0)
|
||||||
|
d.press("back")
|
||||||
|
await asyncio.sleep(1.0)
|
||||||
|
logger.info(">>> 已尝试从误触页面返回。")
|
||||||
|
else:
|
||||||
|
d.click(x, y)
|
||||||
await asyncio.sleep(1.5)
|
await asyncio.sleep(1.5)
|
||||||
# 重新截图
|
# 重新截图
|
||||||
if os.path.exists(screenshot_path): os.remove(screenshot_path)
|
if os.path.exists(screenshot_path): os.remove(screenshot_path)
|
||||||
|
|||||||
@@ -133,9 +133,14 @@ class ReadImageKit:
|
|||||||
if result.get("has_ad") and result.get("close_point"):
|
if result.get("has_ad") and result.get("close_point"):
|
||||||
if result.get("ad_type") == "rabbit":
|
if result.get("ad_type") == "rabbit":
|
||||||
logger.info("大模型找到了兔子广告!")
|
logger.info("大模型找到了兔子广告!")
|
||||||
|
# 强制使用固定坐标 (94, 830) - 归一化 0-1000
|
||||||
|
# 根据多次 CV 测试结果 (94, 828) 和 (93, 830) 的综合评估
|
||||||
|
logger.info(">>> 采用强制固定坐标策略 (94, 830) 以确保点击准确性")
|
||||||
|
norm_point = [94, 830]
|
||||||
|
else:
|
||||||
|
norm_point = result["close_point"]
|
||||||
|
|
||||||
# 转换坐标
|
# 转换坐标
|
||||||
norm_point = result["close_point"]
|
|
||||||
if len(norm_point) == 2:
|
if len(norm_point) == 2:
|
||||||
if not device_info:
|
if not device_info:
|
||||||
device_info = cls._FALLBACK_DEVICE_INFO
|
device_info = cls._FALLBACK_DEVICE_INFO
|
||||||
@@ -147,7 +152,11 @@ class ReadImageKit:
|
|||||||
x = int(norm_point[0] / 1000 * w)
|
x = int(norm_point[0] / 1000 * w)
|
||||||
y = int(norm_point[1] / 1000 * h)
|
y = int(norm_point[1] / 1000 * h)
|
||||||
|
|
||||||
return {"x": x, "y": y}
|
return {
|
||||||
|
"x": x,
|
||||||
|
"y": y,
|
||||||
|
"ad_type": result.get("ad_type", "unknown")
|
||||||
|
}
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -168,8 +168,24 @@ async def get_station_list(d, service, uploader, max_scrolls=MAX_SCROLLS):
|
|||||||
logger.info("检查是否存在广告弹窗...")
|
logger.info("检查是否存在广告弹窗...")
|
||||||
ad_res = await ReadImageKit.detect_ad_popup(screenshot_path, device_info=device_info)
|
ad_res = await ReadImageKit.detect_ad_popup(screenshot_path, device_info=device_info)
|
||||||
if ad_res:
|
if ad_res:
|
||||||
logger.info(f"检测到广告弹窗,准备关闭: {ad_res}")
|
ad_type = ad_res.get("ad_type")
|
||||||
d.click(ad_res['x'], ad_res['y'])
|
logger.info(f"检测到广告弹窗,准备关闭: {ad_res} [Type: {ad_type}]")
|
||||||
|
|
||||||
|
x, y = ad_res['x'], ad_res['y']
|
||||||
|
|
||||||
|
if ad_type == "rabbit":
|
||||||
|
logger.info(">>> 检测到顽固的兔子广告,执行强力双击策略...")
|
||||||
|
# 使用 u2 的 double_click,它比两次 click + sleep 更快
|
||||||
|
d.double_click(x, y, duration=0.05)
|
||||||
|
|
||||||
|
# 处理“误触背景卡片”的逻辑:既然可能进去了,就等一会儿再退出来
|
||||||
|
logger.info(">>> 考虑到可能误触背景卡片,等待 2s 后执行返回操作...")
|
||||||
|
await asyncio.sleep(2.0)
|
||||||
|
d.press("back")
|
||||||
|
await asyncio.sleep(1.0)
|
||||||
|
logger.info(">>> 已尝试从误触页面返回。")
|
||||||
|
else:
|
||||||
|
d.click(x, y)
|
||||||
await asyncio.sleep(1.5)
|
await asyncio.sleep(1.5)
|
||||||
# 重新截图
|
# 重新截图
|
||||||
if os.path.exists(screenshot_path): os.remove(screenshot_path)
|
if os.path.exists(screenshot_path): os.remove(screenshot_path)
|
||||||
|
|||||||
@@ -61,8 +61,25 @@ async def check_and_close_ad(d):
|
|||||||
ad_result = await ReadImageKit.detect_ad_popup(screenshot_path, device_info=device_info)
|
ad_result = await ReadImageKit.detect_ad_popup(screenshot_path, device_info=device_info)
|
||||||
if ad_result:
|
if ad_result:
|
||||||
x, y = ad_result["x"], ad_result["y"]
|
x, y = ad_result["x"], ad_result["y"]
|
||||||
logger.info(f"通过视觉大模型检测到广告关闭按钮: ({x}, {y})")
|
ad_type = ad_result.get("ad_type")
|
||||||
|
|
||||||
|
logger.info(f"通过视觉大模型检测到广告关闭按钮: ({x}, {y}) [Type: {ad_type}]")
|
||||||
|
|
||||||
|
# 针对“新电兔AI”兔子广告的强力关闭策略
|
||||||
|
if ad_type == "rabbit":
|
||||||
|
logger.info(">>> 检测到顽固的兔子广告,执行强力双击策略...")
|
||||||
|
# 使用 u2 的 double_click,它比两次 click + sleep 更快
|
||||||
|
d.double_click(x, y, duration=0.05)
|
||||||
|
|
||||||
|
# 处理“误触背景卡片”的逻辑
|
||||||
|
logger.info(">>> 考虑到可能误触背景卡片,等待 2s 后执行返回操作...")
|
||||||
|
await asyncio.sleep(2.0)
|
||||||
|
d.press("back")
|
||||||
|
await asyncio.sleep(1.0)
|
||||||
|
logger.info(">>> 已尝试从误触页面返回。")
|
||||||
|
else:
|
||||||
d.click(x, y)
|
d.click(x, y)
|
||||||
|
|
||||||
if os.path.exists(screenshot_path):
|
if os.path.exists(screenshot_path):
|
||||||
os.remove(screenshot_path)
|
os.remove(screenshot_path)
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -129,9 +129,14 @@ class ReadImageKit:
|
|||||||
if result.get("has_ad") and result.get("close_point"):
|
if result.get("has_ad") and result.get("close_point"):
|
||||||
if result.get("ad_type") == "rabbit":
|
if result.get("ad_type") == "rabbit":
|
||||||
logger.info("大模型找到了兔子广告!")
|
logger.info("大模型找到了兔子广告!")
|
||||||
|
# 强制使用固定坐标 (94, 830) - 归一化 0-1000
|
||||||
|
# 根据多次 CV 测试结果 (94, 828) 和 (93, 830) 的综合评估
|
||||||
|
logger.info(">>> 采用强制固定坐标策略 (94, 830) 以确保点击准确性")
|
||||||
|
norm_point = [94, 830]
|
||||||
|
else:
|
||||||
|
norm_point = result["close_point"]
|
||||||
|
|
||||||
# 转换坐标
|
# 转换坐标
|
||||||
norm_point = result["close_point"]
|
|
||||||
if len(norm_point) == 2:
|
if len(norm_point) == 2:
|
||||||
if not device_info:
|
if not device_info:
|
||||||
device_info = cls._FALLBACK_DEVICE_INFO
|
device_info = cls._FALLBACK_DEVICE_INFO
|
||||||
@@ -143,7 +148,11 @@ class ReadImageKit:
|
|||||||
x = int(norm_point[0] / 1000 * w)
|
x = int(norm_point[0] / 1000 * w)
|
||||||
y = int(norm_point[1] / 1000 * h)
|
y = int(norm_point[1] / 1000 * h)
|
||||||
|
|
||||||
return {"x": x, "y": y}
|
return {
|
||||||
|
"x": x,
|
||||||
|
"y": y,
|
||||||
|
"ad_type": result.get("ad_type", "unknown")
|
||||||
|
}
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
147
Tools/TestAdClick.py
Normal file
147
Tools/TestAdClick.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import uiautomator2 as u2
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
def test_click():
|
||||||
|
d = u2.connect()
|
||||||
|
w, h = d.window_size()
|
||||||
|
print(f"Device size: {w}x{h}")
|
||||||
|
|
||||||
|
# 1. Take screenshot
|
||||||
|
print("Taking screenshot...")
|
||||||
|
screenshot_path = r"d:\dsWork\aiData\Output\debug_ad_before.jpg"
|
||||||
|
d.screenshot(screenshot_path)
|
||||||
|
|
||||||
|
# 2. Check hierarchy
|
||||||
|
print("Dumping hierarchy...")
|
||||||
|
try:
|
||||||
|
xml = d.dump_hierarchy()
|
||||||
|
with open(r"d:\dsWork\aiData\Output\hierarchy.xml", "w", encoding="utf-8") as f:
|
||||||
|
f.write(xml)
|
||||||
|
print(r"Hierarchy saved to d:\dsWork\aiData\Output\hierarchy.xml")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to dump hierarchy: {e}")
|
||||||
|
|
||||||
|
# 3. Visualize the current fixed point (80/1000, 835/1000)
|
||||||
|
# Norm: 0.08, 0.835
|
||||||
|
# Previous attempt was: (86, 2004) for 1080x2400
|
||||||
|
|
||||||
|
# Let's try to detect the black circle using HSV or thresholding
|
||||||
|
img = cv2.imread(screenshot_path)
|
||||||
|
if img is None:
|
||||||
|
print("Failed to load screenshot")
|
||||||
|
return
|
||||||
|
|
||||||
|
# ROI: Left side, bottom half
|
||||||
|
# x: 0 - 200, y: 1500 - 2200 (approx for 1080x2400)
|
||||||
|
roi_x1, roi_x2 = 0, int(w * 0.25)
|
||||||
|
roi_y1, roi_y2 = int(h * 0.6), int(h * 0.9)
|
||||||
|
|
||||||
|
roi = img[roi_y1:roi_y2, roi_x1:roi_x2]
|
||||||
|
|
||||||
|
# Convert to grayscale
|
||||||
|
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
# The close button is a black circle. So it should be very dark.
|
||||||
|
# Try multiple thresholds to find the best candidates
|
||||||
|
candidates = []
|
||||||
|
for threshold_val in [50, 70, 90, 110]:
|
||||||
|
_, thresh = cv2.threshold(gray, threshold_val, 255, cv2.THRESH_BINARY_INV)
|
||||||
|
|
||||||
|
# Find contours
|
||||||
|
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||||
|
|
||||||
|
for cnt in contours:
|
||||||
|
area = cv2.contourArea(cnt)
|
||||||
|
# Approximate circle check
|
||||||
|
perimeter = cv2.arcLength(cnt, True)
|
||||||
|
if perimeter == 0: continue
|
||||||
|
circularity = 4 * np.pi * (area / (perimeter * perimeter))
|
||||||
|
|
||||||
|
# Filter by size and circularity
|
||||||
|
# Size: it's a small button
|
||||||
|
if 50 < area < 6000 and circularity > 0.35:
|
||||||
|
M = cv2.moments(cnt)
|
||||||
|
if M["m00"] != 0:
|
||||||
|
cX = int(M["m10"] / M["m00"]) + roi_x1
|
||||||
|
cY = int(M["m01"] / M["m00"]) + roi_y1
|
||||||
|
|
||||||
|
# Calculate normalized coordinates
|
||||||
|
norm_x = int(cX / w * 1000)
|
||||||
|
norm_y = int(cY / h * 1000)
|
||||||
|
|
||||||
|
# Avoid duplicates
|
||||||
|
if not any(abs(cX - c[0]) < 10 and abs(cY - c[1]) < 10 for c in candidates):
|
||||||
|
candidates.append((cX, cY, area, norm_x, norm_y))
|
||||||
|
|
||||||
|
# Save thresh image for debugging
|
||||||
|
_, debug_thresh = cv2.threshold(gray, 70, 255, cv2.THRESH_BINARY_INV)
|
||||||
|
cv2.imwrite(r"d:\dsWork\aiData\Output\debug_thresh.jpg", debug_thresh)
|
||||||
|
|
||||||
|
# Sort by proximity to expected location (Left side, Middle-Bottom)
|
||||||
|
# Expected norm: (93, 830)
|
||||||
|
def score_candidate(c):
|
||||||
|
# Weighting: X proximity is important, Y proximity is also important, Area around 400-500 is ideal
|
||||||
|
dist_x = abs(c[3] - 93)
|
||||||
|
dist_y = abs(c[4] - 830)
|
||||||
|
area_diff = abs(c[2] - 450) / 450.0
|
||||||
|
return dist_x * 2 + dist_y + area_diff * 100
|
||||||
|
|
||||||
|
candidates.sort(key=score_candidate)
|
||||||
|
|
||||||
|
target_x, target_y = int(w * 0.08), int(h * 0.835) # Default fallback
|
||||||
|
norm_target_x, norm_target_y = 80, 835
|
||||||
|
|
||||||
|
if candidates:
|
||||||
|
print(f"Found {len(candidates)} candidate close buttons via CV:")
|
||||||
|
for i, (cx, cy, area, nx, ny) in enumerate(candidates):
|
||||||
|
score = score_candidate((cx, cy, area, nx, ny))
|
||||||
|
print(f" Candidate {i}: ({cx}, {cy}), Area: {area}, Norm: ({nx}, {ny}), Score: {score:.2f}")
|
||||||
|
|
||||||
|
# Pick the best one
|
||||||
|
best_c = candidates[0]
|
||||||
|
target_x, target_y = best_c[0], best_c[1]
|
||||||
|
norm_target_x, norm_target_y = best_c[3], best_c[4]
|
||||||
|
print(f"Selected CV target: ({target_x}, {target_y}), Norm: ({norm_target_x}, {norm_target_y})")
|
||||||
|
else:
|
||||||
|
print("No CV candidates found. Using fixed coordinates.")
|
||||||
|
|
||||||
|
# Visualize
|
||||||
|
cv2.circle(img, (target_x, target_y), 20, (0, 255, 0), -1)
|
||||||
|
cv2.putText(img, f"Click ({target_x}, {target_y})", (target_x + 30, target_y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
|
||||||
|
|
||||||
|
# Also draw the fixed point for comparison (Blue)
|
||||||
|
fixed_x = int(w * 0.08)
|
||||||
|
fixed_y = int(h * 0.835)
|
||||||
|
cv2.circle(img, (fixed_x, fixed_y), 15, (255, 0, 0), -1)
|
||||||
|
|
||||||
|
debug_path = r"d:\dsWork\aiData\Output\debug_ad_point.jpg"
|
||||||
|
cv2.imwrite(debug_path, img)
|
||||||
|
print(f"Debug image saved to {debug_path}")
|
||||||
|
|
||||||
|
# 4. Perform click
|
||||||
|
print(f"Clicking ({target_x}, {target_y}) using double_click...")
|
||||||
|
# Use d.double_click for a faster interaction
|
||||||
|
d.double_click(target_x, target_y, duration=0.05)
|
||||||
|
|
||||||
|
# NEW: Handle potential background click as per user's latest request
|
||||||
|
print("Waiting 2s for potential background card to load...")
|
||||||
|
time.sleep(2)
|
||||||
|
print("Pressing BACK to return to main page...")
|
||||||
|
d.press("back")
|
||||||
|
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
# 5. Take after screenshot
|
||||||
|
after_path = r"d:\dsWork\aiData\Output\debug_ad_after.jpg"
|
||||||
|
d.screenshot(after_path)
|
||||||
|
print(f"After screenshot saved to {after_path}")
|
||||||
|
|
||||||
|
# Check if successful (compare image hash or just file size, though file size varies with compression)
|
||||||
|
# Simple check: If the black button is gone, the area should be brighter?
|
||||||
|
# Or just let user check.
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_click()
|
||||||
Reference in New Issue
Block a user