STAGEYE / HOST — Host Setup & Configuration
Capture setup for the front-of-house computer
Host disconnected
- Frame rate
- ~0.0 fps
- Last frame
- --:--:--
Connection details
Project URL
https://fxomeytrkhrzkpjkpfjt.supabase.coAnon key
••••••••••••••••••••••••••••••••••••••••••••••••Install dependencies
pip install mss pillow supabase pyautoguiRunning the host script
- Install Python 3.10 or newer on the FOH computer.
- Install the dependencies with the command above.
- Paste the script below, filling in the project URL and anon key above.
- Run it:
python stageye_host.py - It uploads
latest.jpgto thescreen-framesbucket, broadcasts{ timestamp }onframe-updates, and applies incoming events fromcontrol-events. - Autostart on Windows: press
Win + R, runshell:startup, and drop a shortcut tostageye_host.py(or a.batthat calls it) in that folder so the host script starts automatically on boot.
# stageye_host.py - run on the FOH computer
# pip install mss pillow supabase pyautogui
import io, time, asyncio
from datetime import datetime, timezone
from mss import mss
from PIL import Image
from supabase import create_client
import pyautogui
pyautogui.FAILSAFE = False
SUPABASE_URL = "<project url above>"
SUPABASE_KEY = "<anon key above>"
sb = create_client(SUPABASE_URL, SUPABASE_KEY)
BUTTONS = {0: "left", 1: "middle", 2: "right"}
async def main():
frames = sb.realtime.channel("frame-updates")
await frames.subscribe()
control = sb.realtime.channel("control-events")
def on_control(payload):
e = payload.get("payload", payload)
w, h = screen_size
if e["type"] in ("mousemove", "mouseclick"):
pyautogui.moveTo(int(e["x"] * w), int(e["y"] * h))
if e["type"] == "mouseclick":
pyautogui.click(button=BUTTONS.get(e.get("button", 0), "left"))
elif e["type"] == "keydown":
key = e["key"]
pyautogui.press({"Enter": "enter", "Escape": "esc", " ": "space"}.get(key, key.lower()))
control.on_broadcast("control", on_control)
await control.subscribe()
with mss() as sct:
mon = sct.monitors[1]
globals()["screen_size"] = (mon["width"], mon["height"])
last_beat = 0.0
try:
while True:
shot = sct.grab(mon)
img = Image.frombytes("RGB", shot.size, shot.bgra, "raw", "BGRX")
buf = io.BytesIO()
img.save(buf, format="JPEG", quality=55)
sb.storage.from_("screen-frames").upload(
"latest.jpg", buf.getvalue(),
{"content-type": "image/jpeg", "upsert": "true", "cache-control": "0"},
)
await frames.send_broadcast("frame", {"timestamp": int(time.time() * 1000)})
# Heartbeat every 5 seconds so viewers see "Host connected"
if time.time() - last_beat >= 5:
last_beat = time.time()
sb.table("host_status").update({
"is_connected": True,
"last_seen_at": datetime.now(timezone.utc).isoformat(),
}).eq("id", 1).execute()
await asyncio.sleep(1)
finally:
sb.table("host_status").update({"is_connected": False}).eq("id", 1).execute()
asyncio.run(main())