#!/usr/bin/env python3
"""make_content.py OUTDIR — the bench's test content. Generated, or public domain. No personal data.
photos/ 140 generated 4000x3000 JPEGs (gradients + noise, phone-photo sized)
+ up to 60 CC0 portrait PAINTINGS from The Met's Open Access API (isPublicDomain=true),
resized to 4000 px — faces for Immich's face detection, of people long dead.
pdfs/ 20 image-only A4 "scans" at 300 dpi (rendered text, slight skew + noise) — OCR has work
video/ 3 generated 1080p H.264 clips (testsrc2 + tone), 3 min each
upload/ 50 x 10 MiB random files = 500 MiB
books/ 20 minimal EPUB 3 books (generated text)
roms/ a few generated dummy files in platform folders (RomM's scan only; no real ROMs)
Run with `python3 -I`. Needs Pillow and ffmpeg (both present on DooPlex).
"""
import io, json, os, random, subprocess, sys, urllib.request, zipfile
from PIL import Image, ImageDraw, ImageFilter, ImageFont
OUT = sys.argv[1]
rnd = random.Random(20261013)
def mk(p):
os.makedirs(os.path.join(OUT, p), exist_ok=True)
return os.path.join(OUT, p)
def photos():
d = mk("photos")
for i in range(140):
w, h = 4000, 3000
c1 = tuple(rnd.randrange(256) for _ in range(3)); c2 = tuple(rnd.randrange(256) for _ in range(3))
g = Image.linear_gradient("L").resize((w, h))
im = Image.composite(Image.new("RGB", (w, h), c1), Image.new("RGB", (w, h), c2), g)
dr = ImageDraw.Draw(im)
for _ in range(40):
x, y = rnd.randrange(w), rnd.randrange(h); r = rnd.randrange(50, 600)
dr.ellipse([x - r, y - r, x + r, y + r], fill=tuple(rnd.randrange(256) for _ in range(3)))
noise = Image.effect_noise((w, h), 40).convert("RGB")
im = Image.blend(im, noise, 0.25)
im.save(os.path.join(d, f"gen-{i:03d}.jpg"), quality=92)
# CC0 portrait paintings (The Met, European Paintings, public domain)
try:
q = "https://collectionapi.metmuseum.org/public/collection/v1.1/search?departmentId=11&hasImages=true&q=portrait&limit=150&offset=0"
ids = json.load(urllib.request.urlopen(q, timeout=60))["objectIDs"]
except Exception as e:
print("met search failed:", e); ids = []
got, credits = 0, []
for oid in ids:
if got >= 60:
break
try:
o = json.load(urllib.request.urlopen(f"https://collectionapi.metmuseum.org/public/collection/v1/objects/{oid}", timeout=60))
if not o.get("isPublicDomain") or not o.get("primaryImage"):
continue
raw = urllib.request.urlopen(o["primaryImage"], timeout=120).read()
im = Image.open(io.BytesIO(raw)).convert("RGB")
im.thumbnail((4000, 4000))
im.save(os.path.join(d, f"met-{oid}.jpg"), quality=92)
credits.append(f"{oid}\t{o.get('title','')[:80]}\t{o.get('objectURL','')}\tCC0")
got += 1
except Exception as e:
print("skip", oid, e)
open(os.path.join(OUT, "photos-credits.tsv"), "w").write("\n".join(credits) + "\n")
print("photos:", 140 + got, "of which paintings:", got)
WORDS = ("alma korte szilva haz kert konyv level szamla ugyfel datum osszeg fizetes hatarido "
"szerzodes biztositas orvos recept iskola munka berlet viz gaz aram adoszam").split()
def text(n):
return " ".join(rnd.choice(WORDS) for _ in range(n))
def pdfs():
d = mk("pdfs")
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf", 38)
except OSError:
font = ImageFont.load_default()
for i in range(20):
im = Image.new("L", (2480, 3508), 245)
dr = ImageDraw.Draw(im)
y = 200
dr.text((200, y), f"Bench document {i + 1:02d} - 2026-10-13", font=font, fill=20); y += 120
while y < 3300:
dr.text((200, y), text(9), font=font, fill=30); y += 62
im = im.rotate(rnd.uniform(-1.2, 1.2), fillcolor=235).filter(ImageFilter.GaussianBlur(0.6))
im = Image.blend(im, Image.effect_noise(im.size, 25).convert("L"), 0.08)
im.save(os.path.join(d, f"scan-{i + 1:02d}.pdf"), resolution=300)
print("pdfs: 20")
def video():
d = mk("video/Bench Films")
for i in range(3):
sub = os.path.join(d, f"Bench Film {i + 1} (2026)")
os.makedirs(sub, exist_ok=True)
subprocess.run(["ffmpeg", "-loglevel", "error", "-y", "-f", "lavfi", "-i", f"testsrc2=size=1920x1080:rate=30",
"-f", "lavfi", "-i", f"sine=frequency={440 + 110 * i}:sample_rate=48000",
"-t", "180", "-c:v", "libx264", "-preset", "veryfast", "-b:v", "8M", "-pix_fmt", "yuv420p",
"-c:a", "aac", "-b:a", "192k", os.path.join(sub, f"Bench Film {i + 1} (2026).mkv")], check=True)
print("video: 3 x 180 s 1080p")
def upload():
d = mk("upload")
for i in range(50):
with open(os.path.join(d, f"blob-{i:02d}.bin"), "wb") as f:
f.write(os.urandom(10 * 1024 * 1024))
print("upload: 500 MiB")
def books():
d = mk("books")
for i in range(20):
p = os.path.join(d, f"bench-book-{i + 1:02d}.epub")
with zipfile.ZipFile(p, "w") as z:
z.writestr(zipfile.ZipInfo("mimetype"), "application/epub+zip", compress_type=zipfile.ZIP_STORED)
z.writestr("META-INF/container.xml",
'
{text(80)}
" for _ in range(200)) + "") print("books: 20") def roms(): for plat, ext in (("nes", "nes"), ("snes", "sfc"), ("gb", "gb")): d = mk(f"roms/{plat}") for i in range(5): with open(os.path.join(d, f"Bench Game {i + 1}.{ext}"), "wb") as f: f.write(os.urandom(256 * 1024)) print("roms: 15 dummy files") if __name__ == "__main__": for fn in (pdfs, books, roms, upload, video, photos): fn()