119 lines
3.7 KiB
Python
119 lines
3.7 KiB
Python
"""
|
|
automation/defense_popup.py — 수비 팝업 조작
|
|
|
|
수비 버튼 클릭, 수비 시퀀스 입력, 실책 수비 팝업 처리.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from playwright.sync_api import Page
|
|
|
|
from core.config_loader import defense_button_id_map, position_number_map
|
|
from core.field_calculator import (
|
|
extract_defense_sequence,
|
|
extract_error_position,
|
|
infer_error_position_fallback,
|
|
is_throwing_error,
|
|
)
|
|
from automation.page_helpers import get_last_visible_locator
|
|
|
|
|
|
def click_defense_button_robustly(page: Page, position: str, click_count: int = 1) -> bool:
|
|
"""수비 포지션 버튼을 안정적으로 클릭
|
|
|
|
ID 기반 → value 기반 → label 기반 순서로 시도
|
|
"""
|
|
btn_map = defense_button_id_map()
|
|
pos_num = position_number_map()
|
|
|
|
# 1) ID 기반
|
|
button_selector = btn_map.get(position)
|
|
if button_selector:
|
|
loc = page.locator(button_selector)
|
|
if loc.count() > 0:
|
|
for _ in range(click_count):
|
|
loc.click(force=True)
|
|
page.wait_for_timeout(60)
|
|
return True
|
|
|
|
# 2) value 기반
|
|
value = pos_num.get(position)
|
|
if value:
|
|
loc = page.locator(f"input[name='defenseNumberBtn'][value='{value}']")
|
|
if loc.count() > 0:
|
|
for _ in range(click_count):
|
|
loc.click(force=True)
|
|
page.wait_for_timeout(60)
|
|
return True
|
|
|
|
# 3) label 기반
|
|
all_buttons = page.locator("input[name='defenseNumberBtn']").all()
|
|
for btn in all_buttons:
|
|
label = (btn.get_attribute("id") or "").lower()
|
|
if position in label or label in position:
|
|
for _ in range(click_count):
|
|
btn.click(force=True)
|
|
page.wait_for_timeout(60)
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def clear_defense_selections(page: Page) -> None:
|
|
"""수비 선택 초기화"""
|
|
page.evaluate(
|
|
"""() => {
|
|
document.querySelectorAll("input[name='defenseNumberBtn']").forEach(btn => {
|
|
btn.checked = false;
|
|
});
|
|
}"""
|
|
)
|
|
|
|
|
|
def click_defense_sequence_in_popup(
|
|
page: Page,
|
|
sequence: list[str],
|
|
complete_button_selector: str | None = None,
|
|
) -> None:
|
|
"""수비 시퀀스 순서대로 클릭 후 완료 버튼 클릭"""
|
|
for position in sequence:
|
|
click_defense_button_robustly(page, position)
|
|
page.wait_for_timeout(80)
|
|
|
|
if complete_button_selector:
|
|
btn = get_last_visible_locator(page, complete_button_selector)
|
|
if btn:
|
|
btn.click()
|
|
page.wait_for_timeout(120)
|
|
|
|
|
|
def fill_runner_out_defense(
|
|
page: Page, text: str, sequence_override: list[str] | None = None,
|
|
) -> None:
|
|
"""주루 아웃 수비 팝업 처리"""
|
|
page.wait_for_timeout(300)
|
|
sequence = sequence_override or extract_defense_sequence(text)
|
|
if sequence:
|
|
click_defense_sequence_in_popup(page, sequence)
|
|
|
|
|
|
def fill_error_defense_popup(page: Page, text: str) -> None:
|
|
"""실책 수비 팝업 처리"""
|
|
defense_sequence = extract_defense_sequence(text)
|
|
if len(defense_sequence) >= 2:
|
|
click_defense_sequence_in_popup(page, defense_sequence)
|
|
else:
|
|
error_position = extract_error_position(text)
|
|
if not error_position:
|
|
error_position = infer_error_position_fallback(text)
|
|
click_count = 2 if is_throwing_error(text) else 1
|
|
click_defense_button_robustly(page, error_position, click_count)
|
|
|
|
complete_button = get_last_visible_locator(page, "#btnNext")
|
|
if complete_button is None:
|
|
complete_button = get_last_visible_locator(page, "#btnAdd")
|
|
if complete_button:
|
|
complete_button.click()
|
|
page.wait_for_timeout(120)
|