Add ECW/HTTP planner scripts, browser crash recovery, and Planner error-overlay handling
- Add ecw_download.py and onedrive_planner_http.py for ECW and HTTP-based Planner access - Add build_exe.bat for packaging - Restart Chrome automatically on crash mid-run in planner_download.py - Detect and recover from Planner "something went wrong" error overlays - Improve board-load waiting, sort-descending menu matching, and screenshot timestamp rendering in chrome.py/onedrive_planner.py
This commit is contained in:
1 parent
c2dec96b1f
commit
291507c2f7
6 files changed
+2134
-49
No files matched your search
+48
-7
@@ -397,10 +397,33 @@ def _is_image_mostly_black(path: Path, *, threshold: int = 18) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _load_timestamp_font(size: int = 22):
|
||||
"""Return a PIL ImageFont at the requested size, falling back to the built-in bitmap font."""
|
||||
try:
|
||||
from PIL import ImageFont
|
||||
|
||||
candidates = [
|
||||
"C:/Windows/Fonts/segoeui.ttf",
|
||||
"C:/Windows/Fonts/arial.ttf",
|
||||
"C:/Windows/Fonts/calibri.ttf",
|
||||
"C:/Windows/Fonts/verdana.ttf",
|
||||
]
|
||||
for path in candidates:
|
||||
try:
|
||||
return ImageFont.truetype(path, size)
|
||||
except Exception:
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
from PIL import ImageFont
|
||||
return ImageFont.load_default()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _capture_browser_with_timestamp_bar(driver: webdriver.Chrome, path: Path) -> bool:
|
||||
"""
|
||||
Fallback when desktop capture is black: maximized browser PNG plus a taskbar-style clock strip.
|
||||
"""
|
||||
"""Browser viewport PNG with a timestamp bar showing machine time."""
|
||||
try:
|
||||
import io
|
||||
|
||||
@@ -409,18 +432,36 @@ def _capture_browser_with_timestamp_bar(driver: webdriver.Chrome, path: Path) ->
|
||||
prepare_browser_for_screenshot(driver)
|
||||
png = driver.get_screenshot_as_png()
|
||||
browser = Image.open(io.BytesIO(png)).convert("RGB")
|
||||
bar_h = 48
|
||||
canvas = Image.new("RGB", (browser.width, browser.height + bar_h), (30, 30, 30))
|
||||
bar_h = 36
|
||||
canvas = Image.new("RGB", (browser.width, browser.height + bar_h), (24, 24, 24))
|
||||
canvas.paste(browser, (0, 0))
|
||||
draw = ImageDraw.Draw(canvas)
|
||||
stamp = datetime.now().strftime("%I:%M %p %m/%d/%Y").lstrip("0")
|
||||
draw.text((max(browser.width - 260, 8), browser.height + 14), stamp, fill=(255, 255, 255))
|
||||
stamp = datetime.now().strftime("%I:%M:%S %p %m/%d/%Y").lstrip("0")
|
||||
font = _load_timestamp_font(22)
|
||||
y = browser.height + (bar_h - 22) // 2
|
||||
if font:
|
||||
draw.text((12, y), stamp, fill=(220, 220, 220), font=font)
|
||||
else:
|
||||
draw.text((12, y), stamp, fill=(220, 220, 220))
|
||||
canvas.save(str(path), "PNG")
|
||||
return path.is_file() and path.stat().st_size > 0
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def capture_browser_screenshot(driver: webdriver.Chrome, path: Path) -> bool:
|
||||
"""Capture only the Chromium browser viewport — no dependency on the host desktop."""
|
||||
path = Path(path)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
log_step("Browser screenshot", path=str(path))
|
||||
if _capture_browser_with_timestamp_bar(driver, path):
|
||||
log_step("Browser screenshot saved", path=str(path))
|
||||
return True
|
||||
driver.save_screenshot(str(path))
|
||||
log_step("Viewport screenshot saved", path=str(path))
|
||||
return path.is_file()
|
||||
|
||||
|
||||
def capture_fullscreen_screenshot(driver: webdriver.Chrome, path: Path) -> bool:
|
||||
"""
|
||||
Full-screen capture with system taskbar visible when an interactive desktop exists.
|
||||
|
||||
Reference in new issue
Block a user