Files
omni-parse/tools/shots_ui.py
reform 3b237af1f0
Some checks failed
ci / test (3.10) (push) Has been cancelled
ci / test (3.11) (push) Has been cancelled
ci / test (3.12) (push) Has been cancelled
docs: скриншоты панели (9 разделов) + tools/shots_ui.py для пересъёмки; README — раздел «Скриншоты»
2026-10-27 13:21:06 +03:00

78 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Пересъёмка скриншотов панели в docs/screenshots (нужен playwright + chromium).
python -m omni serve --port 8077 # в одном окне
python tools/shots_ui.py # в другом
Каждый маршрут снимается только после того, как пропали скелетоны,
иначе в кадр попадает «Загрузка находок...». Ресайз до 1600px по ширине —
картинки для README, а не для печати.
"""
from __future__ import annotations
import argparse
import asyncio
import pathlib
from playwright.async_api import async_playwright
ROUTES = ["feed", "abuse", "sources", "tg", "watch", "digest", "overview", "runs", "keys"]
SKELETONS = (
"() => document.querySelectorAll("
"'[class*=skeleton],[class*=placeholder],[class*=spinner]').length"
)
def resize(path: pathlib.Path, width: int = 1600) -> tuple[int, int]:
from PIL import Image
im = Image.open(path)
if im.width > width:
im = im.resize((width, round(im.height * width / im.width)), Image.LANCZOS)
im.save(path, "PNG", optimize=True)
return im.size
async def shoot(base: str, out: pathlib.Path, only: list[str], scale: int) -> None:
out.mkdir(parents=True, exist_ok=True)
async with async_playwright() as p:
browser = await p.chromium.launch(
headless=True,
args=["--no-sandbox", "--disable-gpu", "--hide-scrollbars",
"--force-color-profile=srgb"],
)
ctx = await browser.new_context(
viewport={"width": 1600, "height": 1000},
device_scale_factor=scale,
locale="ru-RU",
)
page = await ctx.new_page()
for route in only:
await page.goto(f"{base}/#/{route}", wait_until="networkidle", timeout=90000)
clean = False
for _ in range(30):
await page.wait_for_timeout(1000)
if await page.evaluate(SKELETONS) == 0:
await page.wait_for_timeout(1500)
if await page.evaluate(SKELETONS) == 0:
clean = True
break
target = out / f"{route}.png"
await page.screenshot(path=str(target))
size = resize(target)
print(f"{route:9s} clean={clean} -> {size} {target.stat().st_size} B")
await browser.close()
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--base", default="http://127.0.0.1:8077")
ap.add_argument("--out", default="docs/screenshots")
ap.add_argument("--only", default="", help="через запятую: feed,abuse")
ap.add_argument("--scale", type=int, default=2, help="device scale factor")
a = ap.parse_args()
only = [r.strip() for r in a.only.split(",") if r.strip()] or ROUTES
asyncio.run(shoot(a.base, pathlib.Path(a.out), only, a.scale))
if __name__ == "__main__":
main()