feat: add recruit sign-in automation

This commit is contained in:
admin committed 2026-10-05 04:18:02 +08:00
1 parent 19c502f659
commit 8b7c5d45da
12 files changed
+288

No files matched your search

+52
View File
@@ -78,6 +78,37 @@ class Matcher:
return 0.0, None
return float(score), (x1 + x, y1 + y, w, h)
def locate_all(self, frame, spec, limit=20):
"""Return non-overlapping template matches, ordered from top to bottom."""
name = spec['template']
if name not in self.cache:
p = self.assets / name
if not p.is_file():
raise WorkflowError('缺少识别模板:' + name)
self.cache[name] = np.asarray(Image.open(p).convert('RGB'))
template = self.cache[name]
x1, y1, x2, y2 = spec['search']
area = frame[y1:y2, x1:x2]
h, w = template.shape[:2]
if area.shape[0] < h or area.shape[1] < w:
raise WorkflowError('模板尺寸超出识别区域。')
scores = cv2.matchTemplate(area, template, cv2.TM_CCOEFF_NORMED)
threshold = spec.get('threshold', 0.86)
matches = []
while len(matches) < limit:
_, score, _, (x, y) = cv2.minMaxLoc(scores)
if not math.isfinite(score) or score < threshold:
break
candidate = area[y:y + h, x:x + w]
difference = float(np.abs(candidate.astype(float) - template.astype(float)).mean())
# Suppress this neighbourhood regardless of the colour check so
# a rejected partial overlap cannot repeat forever.
scores[max(0, y - h // 2):min(scores.shape[0], y + h // 2 + 1),
max(0, x - w // 2):min(scores.shape[1], x + w // 2 + 1)] = -1
if difference <= spec.get('max_color_difference', 28):
matches.append((float(score), (x1 + x, y1 + y, w, h)))
return sorted(matches, key=lambda item: (item[1][1], item[1][0]))
def matches(self, frame, specs):
return all(self.score(frame, s) >= s.get('threshold', 0.86) for s in specs)
@@ -116,6 +147,27 @@ class Desktop:
finally:
self.api.FAILSAFE = saved_failsafe
def drag(self, start, end, region, screenshot_size, hold=0.2, duration=0.7):
"""Perform a deliberate touch-like list swipe inside the game region."""
from .permissions import mouse_permission_granted
if not mouse_permission_granted():
raise WorkflowError('macOS 辅助功能权限未授予,无法发送有效鼠标拖拽。')
start_point = region.mouse_point(start, screenshot_size, tuple(self.api.size()))
end_point = region.mouse_point(end, screenshot_size, tuple(self.api.size()))
self.api.moveTo(*start_point, duration=0.2)
self.api.mouseDown()
try:
time.sleep(hold)
self.api.moveTo(*end_point, duration=duration)
time.sleep(hold)
finally:
saved = self.api.FAILSAFE
self.api.FAILSAFE = False
try:
self.api.mouseUp()
finally:
self.api.FAILSAFE = saved
class Runner:
def __init__(self, desktop, matcher, region, log=print, stop=None):