"""OS-level scrolling of the focused window via pyautogui. We drive real scroll input rather than the DOM, so it works over a plain screenshot pipeline on any OS. Needs Accessibility permission on macOS and an X11 session on Linux. """ from __future__ import annotations import time from config import SCROLL_AMOUNT, SCROLL_PAUSE class ScrollError(RuntimeError): pass def _pyautogui(): try: import pyautogui pyautogui.FAILSAFE = False return pyautogui except Exception as e: # pragma: no cover raise ScrollError( f"pyautogui not available ({e}). On macOS grant Accessibility; " f"on Linux use X11." ) def scroll_to_top() -> None: pg = _pyautogui() # A large upward scroll reliably returns most pages to the top. for _ in range(10): pg.scroll(SCROLL_AMOUNT) time.sleep(SCROLL_PAUSE) def scroll_down(amount: int = SCROLL_AMOUNT) -> None: pg = _pyautogui() pg.scroll(-abs(amount)) time.sleep(SCROLL_PAUSE) def click_at_fraction(x_frac: float, y_frac: float) -> None: """Click at a position given as fractions (0..1) of the logical screen. Fractions are resolution- and Retina-independent: pyautogui reports the logical screen size, and the capture covers the same primary display, so a fraction of the screenshot maps directly to a fraction of the screen. """ pg = _pyautogui() w, h = pg.size() x = int(max(0.0, min(1.0, x_frac)) * w) y = int(max(0.0, min(1.0, y_frac)) * h) pg.moveTo(x, y, duration=0.2) pg.click()