Live viewer now takes a screenshot once as second

This commit is contained in:
Casey 2024-07-04 15:14:24 +03:00
parent f378f15c6c
commit ebe6fab9c6
Signed by: hkc
GPG Key ID: F0F6CFE11CDB0960
4 changed files with 26 additions and 3 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ logs.txt
rgb111-full.png rgb111-full.png
state-new.json state-new.json
settings.json settings.json
screenshots/

BIN
astley.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -59,6 +59,7 @@ class AsyncBotManager:
bits_on, bits_off, timestamp = data bits_on, bits_off, timestamp = data
if timestamp < self._last_update: if timestamp < self._last_update:
print("SKIPPING UPDATES: TOO OLD") print("SKIPPING UPDATES: TOO OLD")
self._last_update: int = data["timestamp"]
for ndx in bits_on: for ndx in bits_on:
y, x = divmod(ndx, 1000) y, x = divmod(ndx, 1000)
self.canvas.putpixel((x, y), 255) self.canvas.putpixel((x, y), 255)
@ -107,7 +108,7 @@ async def amain():
mgr.font = ImageFont.truetype(settings["font"], 8) mgr.font = ImageFont.truetype(settings["font"], 8)
for elem in settings["elements"]: for elem in settings["elements"]:
if elem["type"] == "text": if elem["type"] == "text":
mgr.put_text(elem["text"], elem["x"], elem["y"]) mgr.put_text(elem["x"], elem["y"], elem["text"])
elif elem["type"] == "image": elif elem["type"] == "image":
with Image.open(elem["path"]).convert("LA") as im: with Image.open(elem["path"]).convert("LA") as im:
mgr.put_image(elem["x"], elem["y"], im) mgr.put_image(elem["x"], elem["y"], im)

View File

@ -4,10 +4,12 @@ from PIL import Image, ImageTk
from socketio import SimpleClient, exceptions from socketio import SimpleClient, exceptions
from threading import Thread from threading import Thread
from requests import get from requests import get
from datetime import datetime
COLORS = [(0x33, 0x33, 0x66), (0x96, 0x96, 0xe0)] COLORS = [(0x33, 0x33, 0x66), (0x96, 0x96, 0xe0)]
COLORS_UNPACKED = COLORS[0] + ((0, 0, 0) * 254) + COLORS[1] COLORS_UNPACKED = COLORS[0] + ((0, 0, 0) * 254) + COLORS[1]
SCREENSHOTS_TMPL = "./screenshots/%Y%m%d_%H%M%S.png"
class App(tk.Tk): class App(tk.Tk):
def __init__(self, url: str = "https://onemillioncheckboxes.com") -> None: def __init__(self, url: str = "https://onemillioncheckboxes.com") -> None:
@ -22,6 +24,8 @@ class App(tk.Tk):
self._canvas.pack() self._canvas.pack()
self.config(width=1000, height=1000, borderwidth=0, highlightthickness=0) self.config(width=1000, height=1000, borderwidth=0, highlightthickness=0)
self._last_update = 0
self._running = False self._running = False
self._image = Image.new("RGB", (1000, 1000), COLORS[0]) self._image = Image.new("RGB", (1000, 1000), COLORS[0])
@ -38,15 +42,25 @@ class App(tk.Tk):
x, y = event.x, event.y x, y = event.x, event.y
self.sio.emit("toggle_bit", { "index": x + y * 1000 }) self.sio.emit("toggle_bit", { "index": x + y * 1000 })
def _save_image(self):
ts = datetime.fromtimestamp(self._last_update / 1000)
path = ts.strftime(SCREENSHOTS_TMPL)
print("SAVED", path)
self._image.save(path)
self.after(1000, self._save_image)
def _on_key_down(self, event: tk.Event): def _on_key_down(self, event: tk.Event):
# <KeyPress event state=Control keysym=r keycode=27 char='\x12' x=538 y=556> # <KeyPress event state=Control keysym=r keycode=27 char='\x12' x=538 y=556>
if event.keysym == "r": if event.keysym == "r":
print("FULL REFRESH") print("FULL REFRESH")
with get(f"{self.url}/api/initial-state") as req: with get(f"{self.url}/api/initial-state") as req:
buffer = b64decode(req.json()["full_state"].encode() + b"=") data = req.json()
buffer = b64decode(data["full_state"].encode() + b"=")
img = Image.frombytes("1", (1000, 1000), buffer).convert("P") img = Image.frombytes("1", (1000, 1000), buffer).convert("P")
img.putpalette(COLORS_UNPACKED) img.putpalette(COLORS_UNPACKED)
self._image.paste(img.convert("RGB")) self._image.paste(img.convert("RGB"))
self._last_update = data["timestamp"]
print("FULL REFRESH DONE") print("FULL REFRESH DONE")
def _reader(self): def _reader(self):
@ -59,6 +73,10 @@ class App(tk.Tk):
if name == "batched_bit_toggles": if name == "batched_bit_toggles":
bits_on, bits_off, timestamp = data bits_on, bits_off, timestamp = data
if timestamp < self._last_update:
print("SKIP partial updates: too old")
continue
self._last_update = timestamp
for ndx in bits_on: for ndx in bits_on:
y, x = divmod(ndx, 1000) y, x = divmod(ndx, 1000)
self._image.putpixel((x, y), COLORS[1]) self._image.putpixel((x, y), COLORS[1])
@ -92,7 +110,9 @@ class App(tk.Tk):
self.sio.connect(f"{self.url}/socket.io") self.sio.connect(f"{self.url}/socket.io")
with get(f"{self.url}/api/initial-state") as req: with get(f"{self.url}/api/initial-state") as req:
buffer = b64decode(req.json()["full_state"].encode() + b"=") data = req.json()
buffer = b64decode(data["full_state"].encode() + b"=")
self._last_update = data["timestamp"]
img = Image.frombytes("1", (1000, 1000), buffer).convert("P") img = Image.frombytes("1", (1000, 1000), buffer).convert("P")
img.putpalette(COLORS_UNPACKED) img.putpalette(COLORS_UNPACKED)
self._image.paste(img.convert("RGB")) self._image.paste(img.convert("RGB"))
@ -104,6 +124,7 @@ class App(tk.Tk):
self._reader_thr.start() self._reader_thr.start()
self.protocol("WM_DELETE_WINDOW", self._close) self.protocol("WM_DELETE_WINDOW", self._close)
self.after(1000, self._save_image)
self.mainloop() self.mainloop()
if __name__ == "__main__": if __name__ == "__main__":