Skip to content

Instantly share code, notes, and snippets.

@hatkidchan
Created April 14, 2022 08:00
Show Gist options
  • Save hatkidchan/40eba2d340918c2a2b568d2f50fa8ba6 to your computer and use it in GitHub Desktop.
Save hatkidchan/40eba2d340918c2a2b568d2f50fa8ba6 to your computer and use it in GitHub Desktop.
Fedi.place timelapse renderer
#!/usr/bin/env python3
from csv import reader as CSVReader
from datetime import datetime
from subprocess import Popen, PIPE
from PIL import Image, ImageDraw, ImageFont
from PIL.ImageColor import getrgb
FFMPEG_ARGS = [
"ffmpeg", "-f", "image2pipe",
"-i", "-",
"-c:v", "libx264",
"-pix_fmt", "yuv420p",
"-vf", "scale=w=iw*2:h=ih*2:flags=neighbor",
"-y", "result.mkv"
]
font = ImageFont.truetype("./unifont.ttf", 16)
def get_color_for_place(i):
if i == 1:
return getrgb('#ff7f7f')
elif i <= 5:
return getrgb('#ffff7f')
elif i <= 10:
return getrgb('#7fff7f')
elif i <= 15:
return getrgb('#7fffff')
else:
return getrgb('#7f7fff')
with Image.new("RGB", (512 + 256, 512 + 32), (0xff, 0xff, 0xff)) as im:
draw = ImageDraw.Draw(im)
top = {}
with Popen(FFMPEG_ARGS, stdin=PIPE) as proc:
prev_minute = 0
changes = 0
changes_cum = 0
with open("./pixel_data.csv", "r") as fp:
reader = CSVReader(fp)
next(reader) # skip headers
for username, timestamp_string, x, y, color in reader:
top[username] = top.get(username, 0) + 1
timestamp = datetime.fromisoformat(timestamp_string)
curr_minute = int(timestamp.timestamp() // 60)
changes += 1
rgb = getrgb('#' + color)
im.putpixel((int(x), int(y)), rgb)
if prev_minute == 0:
prev_minute = curr_minute - 1
if prev_minute < curr_minute:
for minute in range(prev_minute, curr_minute):
timestamp = datetime.fromtimestamp(minute * 60)
print(timestamp, changes)
changes_cum += changes
txt = '{0} ({1:3d} changes/min, {2} total)'.format(
timestamp.isoformat(), changes, changes_cum)
draw.rectangle((0, 512, 512, 544), getrgb('#131313'))
draw.text((2, 513), txt, getrgb('#efefef'), font, 'la')
draw.rectangle((512, 0, 768, 544), getrgb('#262626'))
users_sorted = sorted(top.items(), key=lambda p: p[1],
reverse=True)
draw.text((512, 0), 'Top 32 users:', getrgb('#ef7fef'),
font, 'la')
for i, (name, count) in zip(range(1, 33), users_sorted):
clr = get_color_for_place(i)
txt = '% 2d. %s: %d' % (i, name, count)
draw.text((512, i * 16), txt, clr, font, 'la')
changes = 0
im.save(proc.stdin, 'PNG') # type: ignore
proc.stdin.flush() # type: ignore
prev_minute = curr_minute
txt = 'final: %d changes' % changes_cum
draw.rectangle((0, 512, 512, 544), getrgb('#131313'))
draw.text((2, 513), txt, getrgb('#efefef'), font, 'la')
for i in range(5 * 30):
im.save(proc.stdin, 'PNG') # type: ignore
proc.stdin.flush() # type: ignore
txt, final_text = '', 'Thanks to everyone!!!'
font_large = font.font_variant(size=32)
img_copy = im.copy()
draw_copy = ImageDraw.Draw(img_copy)
for i in range(len(final_text)):
txt += final_text[i]
img_copy.paste(im, (0, 0))
draw_copy.text((256, 256), txt, getrgb('#7f7fff'), font_large,
'ms', stroke_width=2, stroke_fill=getrgb('#262626'))
for i in range(5):
im_copy.save(proc.stdin, 'PNG') # type: ignore
proc.stdin.flush() # type: ignore
for i in range(5 * 30):
im_copy.save(proc.stdin, 'PNG') # type: ignore
proc.stdin.flush() # type: ignore
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment