Moved stuff around, added time

Not a last commit, huh?
This commit is contained in:
Casey 2024-07-07 15:23:30 +03:00
parent 4a7f633a28
commit 319da9746f
Signed by: hkc
GPG Key ID: F0F6CFE11CDB0960
7 changed files with 80 additions and 26 deletions

View File

@ -1,5 +1,5 @@
import asyncio import asyncio
from typing import NewType, Optional from typing import Callable, NewType, Optional
from socketio import AsyncClient, AsyncSimpleClient from socketio import AsyncClient, AsyncSimpleClient
from aiohttp import ClientSession from aiohttp import ClientSession
from aiohttp_socks import ProxyConnector from aiohttp_socks import ProxyConnector
@ -8,6 +8,7 @@ from base64 import b64decode
from random import choice, randint from random import choice, randint
from json import load from json import load
from time import time as time_now from time import time as time_now
import datetime
PixelMap = NewType("PixelMap", dict[int, bool]) PixelMap = NewType("PixelMap", dict[int, bool])
@ -29,6 +30,8 @@ class AsyncBotManager:
self.avoid: set[int] = set() self.avoid: set[int] = set()
self.animations: list[Animation] = [] self.animations: list[Animation] = []
self.animation_functions: list[Callable[[], PixelMap]] = []
self._written_boxes = 0 self._written_boxes = 0
self._read_boxes = 0 self._read_boxes = 0
self._last_printout = time_now() self._last_printout = time_now()
@ -38,10 +41,11 @@ class AsyncBotManager:
@staticmethod @staticmethod
def get_text_image(text: str, font: ImageFont.ImageFont | ImageFont.FreeTypeFont) -> Image.Image: def get_text_image(text: str, font: ImageFont.ImageFont | ImageFont.FreeTypeFont) -> Image.Image:
left, top, right, bottom = font.getbbox(text) left, top, right, bottom = font.getbbox(text)
with Image.new("LA", (int(right - left) + 4, int(bottom - top) + 4), 0) as im: with Image.new("LA", (int(right - left) + 4, int(bottom - top) + 8), 0) as im:
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
draw.rectangle((0, 0, im.width, im.height), (0, 0)) draw.rectangle((0, 0, im.width, im.height), (0, 0))
draw.text((left + 2, top + 2), text, font=font, fill=(255, 0)) draw.text((left + 2, top + 2), text, font=font, fill=(255, 0),
anchor="lt")
alpha = im.convert("L").filter(ImageFilter.MaxFilter(5)) alpha = im.convert("L").filter(ImageFilter.MaxFilter(5))
im.putalpha(alpha) im.putalpha(alpha)
@ -60,6 +64,17 @@ class AsyncBotManager:
def put_text(self, x: int, y: int, text: str, font: str, size: int = 8): def put_text(self, x: int, y: int, text: str, font: str, size: int = 8):
self.put_image(x, y, self.get_text_image(text, self.get_font(font, size))) self.put_image(x, y, self.get_text_image(text, self.get_font(font, size)))
def get_image_diff(self, ox: int, oy: int, im: Image.Image) -> PixelMap:
pixmap = PixelMap({})
for y in range(im.height):
for x in range(im.width):
l, a = im.getpixel((x, y)) # type: ignore
index = x + ox + (y + oy) * 1000
if a and index not in self.avoid:
pixmap[index] = l > 0
return pixmap
def put_image(self, ox: int, oy: int, im: Image.Image): def put_image(self, ox: int, oy: int, im: Image.Image):
for y in range(im.height): for y in range(im.height):
for x in range(im.width): for x in range(im.width):
@ -174,6 +189,10 @@ class AsyncBotManager:
print(f"I/O: {incoming:7.2f}/s | {outgoing:7.2f}/s") print(f"I/O: {incoming:7.2f}/s | {outgoing:7.2f}/s")
print(f"Alive workers: {len(self._active)}") print(f"Alive workers: {len(self._active)}")
if len(self._active) < 5:
self._shutdown = True
return
n_correct, n_wrong = 0, 0 n_correct, n_wrong = 0, 0
for index, expected in self.difference.items(): for index, expected in self.difference.items():
y, x = divmod(index, 1000) y, x = divmod(index, 1000)
@ -193,6 +212,10 @@ class AsyncBotManager:
self.difference.update( self.difference.update(
pixmaps[frame_index % len(pixmaps)] pixmaps[frame_index % len(pixmaps)]
) )
for func in self.animation_functions:
self.difference.update(func())
except Exception as e: except Exception as e:
print(f"Listener died: {e!r}") print(f"Listener died: {e!r}")
self._shutdown = True self._shutdown = True
@ -208,22 +231,21 @@ class AsyncBotManager:
async with ClientSession(connector=proxy) as http: async with ClientSession(connector=proxy) as http:
async with AsyncSimpleClient(http_session=http) as sio: async with AsyncSimpleClient(http_session=http) as sio:
await sio.connect(f"{self.base}/socket.io") await sio.connect(f"{self.base}/socket.io")
offset = randint(0, 1000000) offset = 0
while not self._shutdown: while not self._shutdown:
diff = list(self.difference.items()) diff = list(self.difference.items())
diff = sorted(diff, key=lambda kv: kv[0])
for _ in range(100): for _ in range(100):
index, expected = diff[offset % len(diff)] index, expected = diff[offset % len(diff)]
offset += randint(0, 100) offset += randint(0, 1000)
y, x = divmod(index, 1000) y, x = divmod(index, 1000)
current = self.canvas.getpixel((x, y)) > 0 # type: ignore current = self.canvas.getpixel((x, y)) > 0 # type: ignore
if current != expected: if current != expected:
# print(f"[{bot_index:2d}] swap {x:3d} {y:3d}")
self._written_boxes += 1 self._written_boxes += 1
await sio.emit("toggle_bit", {"index": index}) await sio.emit("toggle_bit", {"index": index})
await asyncio.sleep(delay) await asyncio.sleep(delay)
break
self._active.add(bot_index) self._active.add(bot_index)
await asyncio.sleep(0.01) await sio.receive(0.1)
async def __aenter__(self): async def __aenter__(self):
self._listener_task = asyncio.create_task(self.listener()) self._listener_task = asyncio.create_task(self.listener())
@ -277,13 +299,27 @@ async def amain() -> None:
mgr.put_image(elem["x"], elem["y"], im) mgr.put_image(elem["x"], elem["y"], im)
print("ADD image", elem) print("ADD image", elem)
elif elem["type"] == "time":
time_format = elem["format"]
pos_x, pos_y = elem["x"], elem["y"]
font = mgr.get_font(elem.get("font", "default"), elem.get("size", 8))
def update() -> PixelMap:
now = datetime.datetime.now(datetime.timezone.utc)
txt = now.strftime(time_format)
img = mgr.get_text_image(txt, font)
pixmap = mgr.get_image_diff(pos_x, pos_y, img)
img.close()
return pixmap
mgr.animation_functions.append(update)
elif elem["type"] == "tile": elif elem["type"] == "tile":
with Image.open(elem["path"]).convert("LA") as im: with Image.open(elem["path"]).convert("LA") as im:
for i in range(elem.get("ry", 1)): for oy in range(elem.get("h", im.height)):
for j in range(elem.get("rx", 1)): for ox in range(elem.get("w", im.width)):
x = elem["x"] + im.width * j l, a = im.getpixel((ox % im.width, oy % im.height)) # type: ignore
y = elem["y"] + im.height * i if a:
mgr.put_image(x, y, im) x, y = elem["x"] + ox, elem["y"] + oy
index = x + y * 1000
mgr.put_bit(index, l > 0)
print("ADD tile", elem) print("ADD tile", elem)
elif elem["type"] == "animation": elif elem["type"] == "animation":
with Image.open(elem["path"]) as anim: with Image.open(elem["path"]) as anim:
@ -371,7 +407,9 @@ async def amain() -> None:
) )
for ret in res: for ret in res:
print(ret) print("RETURN", repr(ret))
mgr._shutdown = True
if __name__ == "__main__": if __name__ == "__main__":

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

BIN
pictures/hello.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

BIN
pictures/mogus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

BIN
pictures/niko_standing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 991 B

BIN
pictures/os_boat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -35,14 +35,6 @@
"stop": 1000000, "stop": 1000000,
"description": "catgirls.win text (both b64 and plain)" "description": "catgirls.win text (both b64 and plain)"
}, },
{
"type": "rect",
"x": 400,
"y": 750,
"w": 400,
"h": 128,
"description": "'be gay do crime' sign"
},
{ {
"type": "image", "type": "image",
"path": "./avoid_masks/noita.png", "path": "./avoid_masks/noita.png",
@ -50,16 +42,25 @@
} }
], ],
"elements": [ "elements": [
{
"type": "time",
"x": 75,
"y": 100,
"format": "And time is: %Y-%m-%d %H:%M:%S UTC",
"spf": 20,
"font": "/usr/share/fonts/TTF/TerminusTTF.ttf",
"size": 12
},
{ {
"type": "image", "type": "image",
"path": "./pictures/casey.png", "path": "./pictures/casey.png",
"x": 32, "x": 0,
"y": 420 "y": 128
}, },
{ {
"type": "rgb565", "type": "rgb565",
"path": "./pictures/niko_standing.png", "path": "./pictures/niko_standing.png",
"x": 106, "x": 116,
"y": 132 "y": 132
}, },
{ {
@ -67,6 +68,21 @@
"path": "./pictures/hello.png", "path": "./pictures/hello.png",
"x": 112, "x": 112,
"y": 203 "y": 203
},
{
"type": "text",
"font": "/usr/share/fonts/TTF/comic.ttf",
"size": 20,
"x": 250,
"y": 492,
"text": "You like kissing, don't you?"
},
{
"type": "animation",
"path": "./pictures/neko.gif",
"spf": 30,
"x": 625,
"y": 496
} }
] ]
} }