97 lines
3.6 KiB
Python
97 lines
3.6 KiB
Python
"""
|
|
automation/pitch_input.py — 투구 입력
|
|
|
|
개별 투구의 구종, 구속, 투구결과를 사이트에 입력합니다.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from playwright.sync_api import Page
|
|
|
|
from core.config_loader import pitch_type_map, pitch_result_map
|
|
from automation.page_helpers import set_radio_by_label
|
|
|
|
|
|
def get_pitch_runner_events(
|
|
pitch: dict[str, Any], event: dict[str, Any] | None = None,
|
|
) -> list[dict[str, Any]]:
|
|
"""투구에 연결된 주루 이벤트 반환"""
|
|
pitch_runner_events = list(pitch.get("runnerEvents") or [])
|
|
if pitch_runner_events:
|
|
return pitch_runner_events
|
|
if event and event.get("runnerEvents"):
|
|
return list(event.get("runnerEvents") or [])
|
|
return []
|
|
|
|
|
|
def set_pitch(page: Page, pitch: dict[str, Any], event: dict[str, Any] | None = None) -> None:
|
|
"""투구 하나를 사이트에 입력 (구종 + 결과 + 구속)"""
|
|
pt_map = pitch_type_map()
|
|
pr_map = pitch_result_map()
|
|
|
|
pitch_type = pt_map.get(pitch.get("pitchType") or "")
|
|
pitch_result_text = (pitch.get("pitchResultText") or "").strip()
|
|
normalized_text = pitch_result_text.replace(" ", "")
|
|
|
|
# 피치클락 투수위반 → 볼
|
|
if "피치클락" in pitch_result_text and "투수위반" in pitch_result_text:
|
|
pitch_result_text = "볼"
|
|
|
|
# 폭투/포일 체크
|
|
runner_events = get_pitch_runner_events(pitch, event)
|
|
is_wild_pitch = any(
|
|
re_.get("type") == "wild_pitch_advance" or "폭투" in (re_.get("text") or "")
|
|
for re_ in runner_events
|
|
)
|
|
is_passed_ball = any(
|
|
re_.get("type") == "passed_ball_advance" or "포일" in (re_.get("text") or "")
|
|
for re_ in runner_events
|
|
)
|
|
|
|
if is_wild_pitch:
|
|
pitch_result = "폭투-볼"
|
|
elif is_passed_ball:
|
|
pitch_result = "포일-볼"
|
|
else:
|
|
if "번트" in normalized_text and "헛스윙" in normalized_text:
|
|
pitch_result = "번트시도-스트라이크"
|
|
elif "번트" in normalized_text and "파울" in normalized_text:
|
|
pitch_result = "번트-파울"
|
|
else:
|
|
pitch_result = pr_map.get(pitch_result_text)
|
|
if not pitch_result and pitch.get("pitchResult") in {"BS", "V"}:
|
|
pitch_result = "번트시도-스트라이크"
|
|
if not pitch_result and pitch.get("pitchResult") == "BF":
|
|
pitch_result = "번트-파울"
|
|
if not pitch_result and "고의사구" in pitch_result_text:
|
|
pitch_result = "고의사구"
|
|
if not pitch_result and "파울플라이" in pitch_result_text and "실책" in pitch_result_text:
|
|
pitch_result = "파울플라이-실책"
|
|
|
|
# 구종 입력
|
|
if pitch_type:
|
|
set_radio_by_label(page, "evt_ballType", pitch_type)
|
|
|
|
# 투구 결과 입력
|
|
if pitch_result:
|
|
set_radio_by_label(page, "evt_batter", pitch_result)
|
|
|
|
# 구속 입력
|
|
speed_input = page.locator("#ballspeed")
|
|
speed_input.fill(str(pitch.get("speedKmh") or 0))
|
|
speed_input.evaluate("node => node.dispatchEvent(new Event('change', {bubbles:true}))")
|
|
page.wait_for_timeout(50)
|
|
|
|
|
|
def set_pitch_meta_only(page: Page, pitch: dict[str, Any]) -> None:
|
|
"""구종/구속만 세팅 (인플레이 마지막 구에서 사용)
|
|
|
|
evt_batter를 건드리지 않아 팝업이 미리 열리는 것을 방지.
|
|
"""
|
|
pt_map = pitch_type_map()
|
|
pitch_type = pt_map.get(pitch.get("pitchType") or "")
|
|
if pitch_type:
|
|
set_radio_by_label(page, "evt_ballType", pitch_type)
|
|
page.locator("#ballspeed").fill(str(pitch.get("speedKmh") or 0))
|