50 lines
1.5 KiB
Python
50 lines
1.5 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Grab the full screen to a PNG. Used by the arena verification flow to
|
||
|
|
prove the quad grid actually tiles on screen — without this we only have
|
||
|
|
DisplayServer's inside-Godot view of its own window state, which is the
|
||
|
|
kind of circumstantial evidence that burned us earlier.
|
||
|
|
|
||
|
|
Uses ffmpeg's x11grab (via XWayland on Wayland sessions). `mss` fails on
|
||
|
|
pure Wayland because its Linux backend is Xlib-only.
|
||
|
|
|
||
|
|
Usage: tools/grab-screen.py <output.png> [WIDTH] [HEIGHT]
|
||
|
|
"""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import os
|
||
|
|
import subprocess
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
if len(sys.argv) < 2 or len(sys.argv) > 4:
|
||
|
|
print("usage: grab-screen.py <output.png> [WIDTH] [HEIGHT]", file=sys.stderr)
|
||
|
|
sys.exit(2)
|
||
|
|
|
||
|
|
out = Path(sys.argv[1])
|
||
|
|
width = int(sys.argv[2]) if len(sys.argv) >= 3 else 3440
|
||
|
|
height = int(sys.argv[3]) if len(sys.argv) >= 4 else 1440
|
||
|
|
display = os.environ.get("DISPLAY", ":0")
|
||
|
|
|
||
|
|
out.parent.mkdir(parents=True, exist_ok=True)
|
||
|
|
|
||
|
|
cmd = [
|
||
|
|
"ffmpeg",
|
||
|
|
"-hide_banner",
|
||
|
|
"-loglevel", "error",
|
||
|
|
"-f", "x11grab",
|
||
|
|
"-video_size", f"{width}x{height}",
|
||
|
|
"-i", display,
|
||
|
|
"-frames:v", "1",
|
||
|
|
"-update", "1",
|
||
|
|
"-y",
|
||
|
|
str(out),
|
||
|
|
]
|
||
|
|
result = subprocess.run(cmd, check=False, capture_output=True, text=True)
|
||
|
|
if result.returncode != 0:
|
||
|
|
print(f"ffmpeg failed (exit {result.returncode}):", file=sys.stderr)
|
||
|
|
print(result.stderr, file=sys.stderr)
|
||
|
|
sys.exit(result.returncode)
|
||
|
|
|
||
|
|
size = out.stat().st_size
|
||
|
|
print(f"saved {out} ({width}x{height}, {size} bytes)")
|