2023-03-31 00:10:32 +08:00
|
|
|
IN='http://us2.g-load.eu:9090/stream'
|
|
|
|
OUT='fdcf:8538:9ad5:3333'
|
|
|
|
IN='http://[fd51:9b17:dc40::2]:9090/stream'
|
|
|
|
OUT='fd51:9b17:dc40:a55'
|
2023-03-10 23:14:42 +08:00
|
|
|
#gen3
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument('--skip', type=int, default=0, help="skip x lines (unused)")
|
|
|
|
parser.add_argument('--drawfirst', action='store_true', help="draw image first (unused)")
|
|
|
|
parser.add_argument('--keepdrawing', action='store_true', help="keepdrawing, sleep for slp1")
|
|
|
|
parser.add_argument('--slp', type=float, default=0.0001, help="sleep x seconds after each ping")
|
|
|
|
parser.add_argument('--slp1', type=float, default=0.5, help="sleep x seconds after each frame")
|
|
|
|
parser.add_argument('--rotate', type=int, default=0, help="rotate image for x deg")
|
|
|
|
parser.add_argument('-i', '--image', type=str, default='1.png', help="input image")
|
|
|
|
args = parser.parse_args()
|
|
|
|
skip, slp, slp1, draw_img = args.skip, args.slp, args.slp1, args.drawfirst
|
|
|
|
|
|
|
|
import struct
|
|
|
|
class ICMP6:
|
|
|
|
_ICMP_ECHO_REQUEST = 128
|
|
|
|
def __init__(self, destination, id, sequence, payload=None,
|
|
|
|
payload_size=56, ttl=64, traffic_class=0):
|
|
|
|
|
|
|
|
if payload is not None:
|
|
|
|
payload_size = len(payload)
|
|
|
|
else:
|
|
|
|
payload = b'\x00'*payload_size
|
|
|
|
|
|
|
|
self._destination = destination
|
|
|
|
self._id = id & 0xffff
|
|
|
|
self._sequence = sequence & 0xffff
|
|
|
|
self._payload = payload
|
|
|
|
self._payload_size = payload_size
|
|
|
|
self._ttl = ttl
|
|
|
|
self._traffic_class = traffic_class
|
|
|
|
self._time = 0
|
|
|
|
def _checksum(self, data):
|
|
|
|
'''
|
|
|
|
Compute the checksum of an ICMP packet. Checksums are used to
|
|
|
|
verify the integrity of packets.
|
|
|
|
'''
|
|
|
|
sum = 0
|
|
|
|
data += b'\x00'
|
|
|
|
|
|
|
|
for i in range(0, len(data) - 1, 2):
|
|
|
|
sum += (data[i] << 8) + data[i + 1]
|
|
|
|
sum = (sum & 0xffff) + (sum >> 16)
|
|
|
|
|
|
|
|
sum = ~sum & 0xffff
|
|
|
|
|
|
|
|
return sum
|
|
|
|
def _create_packet(self):
|
|
|
|
'''
|
|
|
|
Build an ICMP packet from an identifier, a sequence number and
|
|
|
|
a payload.
|
|
|
|
This method returns the newly created ICMP header concatenated
|
|
|
|
to the payload passed in parameters.
|
|
|
|
'''
|
|
|
|
id, sequence, payload = self._id, self._sequence, self._payload
|
|
|
|
checksum = 0
|
|
|
|
|
|
|
|
# Temporary ICMP header to compute the checksum
|
|
|
|
header = struct.pack('!2B3H', self._ICMP_ECHO_REQUEST, 0, checksum,
|
|
|
|
id, sequence)
|
|
|
|
|
|
|
|
checksum = self._checksum(header + payload)
|
|
|
|
|
|
|
|
# Definitive ICMP header
|
|
|
|
header = struct.pack('!2B3H', self._ICMP_ECHO_REQUEST, 0, checksum,
|
|
|
|
id, sequence)
|
|
|
|
|
|
|
|
return header + payload
|
|
|
|
|
|
|
|
|
|
|
|
#X=512
|
|
|
|
#Y=512
|
|
|
|
X=77
|
|
|
|
Y=58
|
|
|
|
X_OFFSET=512-X
|
|
|
|
Y_OFFSET=512-Y
|
|
|
|
Y_OFFSET=80
|
|
|
|
import socket, traceback, time
|
|
|
|
|
|
|
|
from PIL import Image
|
|
|
|
|
|
|
|
icmp6pkt = ICMP6(None, 0xad, 0, b'')._create_packet()
|
|
|
|
import concurrent.futures
|
|
|
|
def send_icmp_mt(addrs, workers=10):
|
|
|
|
def sendto(addr):
|
|
|
|
with socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_ICMPV6) as s:
|
|
|
|
s.sendto(icmp6pkt, (addr, 0))
|
|
|
|
time.sleep(slp)
|
|
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
|
|
|
|
for addr in addrs:
|
|
|
|
executor.submit(sendto, addr)
|
|
|
|
executor.shutdown(wait=True, cancel_futures=False)
|
|
|
|
def send_icmp_st(addrs):
|
|
|
|
try:
|
|
|
|
for addr in addrs:
|
|
|
|
with socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_ICMPV6) as s:
|
|
|
|
s.sendto(icmp6pkt, (addr, 0))
|
|
|
|
time.sleep(slp)
|
|
|
|
except Exception:
|
|
|
|
traceback.print_exc()
|
|
|
|
send_icmp = send_icmp_st
|
|
|
|
|
|
|
|
headers = {'User-Agent': 'curl/7.88.1)'}
|
|
|
|
mkreq = lambda u: urllib.request.Request(u, data=None, headers=headers)
|
|
|
|
timeout = 60
|
|
|
|
|
|
|
|
import urllib.request
|
|
|
|
import contextlib
|
|
|
|
import base64
|
|
|
|
import io
|
|
|
|
import threading
|
|
|
|
img = None
|
|
|
|
imglock = threading.Lock()
|
|
|
|
def get_bg():
|
|
|
|
global img
|
|
|
|
while True:
|
|
|
|
try:
|
2023-03-31 00:10:32 +08:00
|
|
|
with contextlib.closing(urllib.request.urlopen(mkreq(IN), timeout=timeout)) as resp:
|
2023-03-10 23:14:42 +08:00
|
|
|
for line in resp:
|
|
|
|
if line.startswith(b'data:'):
|
|
|
|
with imglock:
|
|
|
|
imgn = Image.open(io.BytesIO(base64.b64decode(line[5:-1])))
|
|
|
|
assert imgn.size == (X, Y)
|
|
|
|
#print(imgn.mode)
|
|
|
|
if imgn.mode == 'RGB':
|
|
|
|
img = imgn.convert(mode='RGBA')
|
|
|
|
else:
|
|
|
|
assert imgn.mode == 'RGBA'
|
|
|
|
img.paste(imgn, (0, 0), imgn)
|
|
|
|
except Exception:
|
|
|
|
traceback.print_exc()
|
|
|
|
print('get_bg exit')
|
|
|
|
time.sleep(3)
|
|
|
|
|
|
|
|
def start_bg_task():
|
|
|
|
threading.Thread(target=get_bg, daemon=True).start()
|
|
|
|
while img is None:
|
|
|
|
time.sleep(1)
|
|
|
|
print('connection established')
|
|
|
|
|
|
|
|
import random
|
|
|
|
|
|
|
|
draw_seq = [(x, y) for x in range(X) for y in range(Y)]
|
|
|
|
random.shuffle(draw_seq)
|
|
|
|
#start_bg_task()
|
|
|
|
ldraw = Image.new(mode="RGBA", size=(X, Y))
|
|
|
|
def draw(img):
|
|
|
|
global ldraw
|
|
|
|
send_icmp_q = []
|
|
|
|
#start = time.time()
|
|
|
|
#print('draw 1 frame in ', end='')
|
|
|
|
for x, y in draw_seq:
|
|
|
|
newpix = img.getpixel((x, y))
|
|
|
|
r, g, b, a = newpix
|
|
|
|
if a and newpix != ldraw.getpixel((x, y)):
|
|
|
|
x += X_OFFSET
|
|
|
|
y += Y_OFFSET
|
2023-03-31 00:10:32 +08:00
|
|
|
send_icmp_q.append(f"{OUT}:{x:x}:{y:x}:11{r:02x}:{g:02x}{b:02x}")
|
2023-03-10 23:14:42 +08:00
|
|
|
#startsend = time.time()
|
|
|
|
send_icmp(send_icmp_q)
|
|
|
|
ldraw = img.copy()
|
|
|
|
#end = time.time()
|
|
|
|
#print(f"{1000*(end-start):.1f}ms {1000*(end-startsend):.1f}ms")
|
|
|
|
|
|
|
|
LANCZOS = Image.Resampling.LANCZOS if getattr(Image, 'Resampling', None) else Image.LANCZOS
|
|
|
|
#to_draw = Image.open(args.image).convert('RGBA').rotate(args.rotate).resize((X, Y), LANCZOS)
|
|
|
|
import pathlib
|
|
|
|
print('loading...')
|
|
|
|
bad_apple_frames = [
|
|
|
|
Image.open(_f).convert('RGBA').resize((X, Y)) for _f in
|
|
|
|
sorted([f for f in pathlib.Path(f'ba_{X}x{Y}').iterdir()], key=lambda x: int(x.name.removesuffix('.png')))
|
|
|
|
]
|
|
|
|
print('loaded')
|
|
|
|
|
|
|
|
while True:
|
|
|
|
ldraw = Image.new(mode="RGBA", size=(X, Y))
|
|
|
|
start = time.time()
|
|
|
|
frameskip = 12
|
|
|
|
rfc = random.randint(0, frameskip)
|
|
|
|
fc = 0
|
|
|
|
fps = 24
|
|
|
|
spf = 1/fps
|
|
|
|
for frame in bad_apple_frames:
|
|
|
|
if not rfc % frameskip == 0:
|
|
|
|
fc += 1
|
|
|
|
rfc += 1
|
|
|
|
continue
|
|
|
|
draw(frame)
|
|
|
|
fc += 1
|
|
|
|
rfc += 1
|
|
|
|
now = time.time()
|
|
|
|
should_sleep = fc * spf - now + start
|
|
|
|
if should_sleep <= 0:
|
|
|
|
start = now
|
|
|
|
fc = 0
|
|
|
|
print(f'cant keep up, running {-should_sleep*1000:.1f} ms behind')
|
|
|
|
should_sleep = 0.1
|
|
|
|
time.sleep(should_sleep)
|
|
|
|
print(f'played one round, sleeping for {slp1=}')
|
|
|
|
time.sleep(slp1)
|