feat: add recruit sign-in automation
This commit is contained in:
1 parent
19c502f659
commit
8b7c5d45da
12 files changed
+288
No files matched your search
@@ -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):
|
||||
|
||||
Reference in new issue
Block a user