#!/usr/bin/env python3 """Run the TUI as a kitty terminal and report what the cover grid emitted. Usage: scripts/grid-probe.py [--root DIR] [--width N] [--height N] """ import argparse, fcntl, os, pty, re, select, struct, sys, termios, time APC = b"\x1b_G" class Session: def __init__(self, args): self.raw = b"" env = dict(os.environ) env["TERM"] = "xterm-kitty" env["COLORTERM"] = "truecolor" env["LINES"] = str(args.height) env["COLUMNS"] = str(args.width) pid, fd = pty.fork() if pid == 0: os.environ.update(env) os.execv(args.binary, [args.binary, "tui", "--root", args.root]) self.fd = fd fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack("HHHH", args.height, args.width, 0, 0)) self.pid = pid def drain(self, seconds): end = time.time() + seconds out = b"" while time.time() < end: r, _, _ = select.select([self.fd], [], [], 0.1) if not r: continue try: chunk = os.read(self.fd, 1 << 20) except OSError: break if not chunk: break out += chunk self.raw += out return out def send(self, keys): os.write(self.fd, keys) return self.drain(0.8) def close(self): try: os.close(self.fd) except OSError: pass try: os.kill(self.pid, 9) except ProcessLookupError: pass os.waitpid(self.pid, 0) def main(): ap = argparse.ArgumentParser() ap.add_argument("--root", default="/tmp/intake-tour") ap.add_argument("--binary", default="./out/intake") ap.add_argument("--width", type=int, default=104) ap.add_argument("--height", type=int, default=34) ap.add_argument("--save", default="", help="write the raw output here") args = ap.parse_args() s = Session(args) try: s.drain(3.0) # browse -> metadata -> track names -> cover art -> search for candidates for _ in range(4): os.write(s.fd, b"\r") s.drain(2.0) s.drain(3.0) finally: s.close() data = s.raw if args.save: with open(args.save, "wb") as f: f.write(data) print(f"raw output saved to {args.save}") print(f"captured {len(data)} bytes") print(f"graphics commands: {data.count(APC)}") cells = data.count("\U0010EEEE".encode()) print(f"placeholder cells: {cells}") for label, pat in [ ("38:2:...m (colon truecolor)", rb"\x1b\[38:2:[0-9]+:[0-9]+:[0-9]+m"), ("38;2;...m (semicolon truecolor)", rb"\x1b\[38;2;[0-9]+;[0-9]+;[0-9]+m"), ("38;5;...m (256 colour)", rb"\x1b\[38;5;[0-9]+m"), ("38:5:...m", rb"\x1b\[38:5:[0-9]+m"), ]: found = set(re.findall(pat, data)) print(f"{label}: {len(found)} distinct") for c in list(found)[:6]: print(f" {c.decode()}") # A grid row is a run of cells; report how wide the widest run is. widest = 0 for line in data.split(b"\n"): n = line.count("\U0010EEEE".encode()) widest = max(widest, n) print(f"widest grid row: {widest} cells") if cells == 0: print("\nNO PLACEHOLDER CELLS REACHED THE TERMINAL") return 1 print("\nthe grid reached the terminal") return 0 if __name__ == "__main__": sys.exit(main())