#!/opt/pw/bin/python """shot.py — open a page in real Chromium (Playwright) and screenshot it, phone and computer, HU and EN. Rehearsal 2026-10-20, A4. Runs in the throwaway LXC rehearsal1020-browser on demo-hp. Chromium is Debian's package (pinned by the image: `chromium --version` is in A4-browser/versions.txt); Playwright 1.52.0 from PyPI drives it via executable_path. usage: shot.py URL OUTPREFIX [--sizes phone,desktop] [--langs hu,en] [--state FILE] [--host-header H] [--url-env NAME] [--wait MS] [--full] --url-env NAME read the URL (or its secret tail) from env NAME and append it to URL — so a capability link never appears on a command line or in this script's output. --state FILE Playwright storage_state JSON (cookies) to load — a logged-in session. Writes OUTPREFIX--.png and prints one line per shot: status, final path (secret tails masked), title. """ import argparse, os, re, sys from playwright.sync_api import sync_playwright SIZES = {"phone": dict(width=390, height=844, is_mobile=True, device_scale_factor=2, has_touch=True), "desktop": dict(width=1366, height=768, is_mobile=False, device_scale_factor=1, has_touch=False)} LANGS = {"hu": "hu-HU", "en": "en-US"} UA_PHONE = ("Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/155.0.0.0 Mobile Safari/537.36") def mask(u: str) -> str: return re.sub(r"[0-9a-f]{32,}", "", u) def main(): ap = argparse.ArgumentParser() ap.add_argument("url"); ap.add_argument("out") ap.add_argument("--sizes", default="phone,desktop"); ap.add_argument("--langs", default="hu,en") ap.add_argument("--state"); ap.add_argument("--url-env"); ap.add_argument("--wait", type=int, default=1500) ap.add_argument("--full", action="store_true"); ap.add_argument("--ignore-https-errors", action="store_true") a = ap.parse_args() url = a.url + (os.environ[a.url_env] if a.url_env else "") with sync_playwright() as p: b = p.chromium.launch(executable_path="/usr/bin/chromium", args=["--no-sandbox"]) for s in a.sizes.split(","): for l in a.langs.split(","): kw = dict(viewport={"width": SIZES[s]["width"], "height": SIZES[s]["height"]}, device_scale_factor=SIZES[s]["device_scale_factor"], is_mobile=SIZES[s]["is_mobile"], has_touch=SIZES[s]["has_touch"], locale=LANGS[l], extra_http_headers={"Accept-Language": LANGS[l] + "," + l + ";q=0.9"}, ignore_https_errors=a.ignore_https_errors, timezone_id="Europe/Budapest") if s == "phone": kw["user_agent"] = UA_PHONE if a.state: kw["storage_state"] = a.state ctx = b.new_context(**kw) pg = ctx.new_page() try: r = pg.goto(url, wait_until="networkidle", timeout=45000) st = r.status if r else "-" except Exception as e: # noqa: BLE001 — a failed load is a result, recorded st = "ERR " + type(e).__name__ pg.wait_for_timeout(a.wait) out = f"{a.out}-{s}-{l}.png" pg.screenshot(path=out, full_page=a.full) hw = pg.evaluate("document.documentElement.scrollWidth > window.innerWidth") print(f"{st}\t{s}\t{l}\t{mask(pg.url)}\t{pg.title()!r}\thscroll={hw}\t{out}") ctx.close() b.close() if __name__ == "__main__": sys.exit(main())