sites/randogoth.com/plugins/crtimages.py
randogoth 8505b7e9e0 Three sites, one directory each
flux.vision, tobias.raayoni-last.com and randogoth.com. They were one site until
October 2026, serving four audiences from a single dated list, which is the only
format that can hold unrelated things at once.

flux.vision is recovered from the Wayback Machine, where it had sat since being
deleted in 2021: 90 articles, closed and maintained rather than updated.
tobias.raayoni-last.com is the professional record, 97 articles back to 1999.
randogoth.com is the technical work, 41 articles across six areas, served as an
ANSI bulletin board.

History starts here deliberately. The development history, the 266-row inventory
that records why each article went where it did, the Wayback pipelines, the
pruned articles, the source archives and the full-size images are kept beside
the repo rather than in it, so a clone is the web presence and not the argument
that produced it. REFACTOR.md is gitignored for the same reason. See README.md
for where that material lives, and keep it: the sort is not reproducible from
these three directories alone.

Each site documents itself in its own README, including the traps that cost time
and look like nothing when you get them wrong.
2026-10-05 20:54:45 +03:00

56 lines
1.9 KiB
Python

"""Wrap every image in an article body so it can carry a CRT overlay.
The scanlines belong on the pictures, not on the whole screen. A board showing
a photograph was a monitor displaying it; the text around it is just text, and
a gradient over the entire page shimmers at non-integer zoom.
An <img> cannot host a ::after of its own, so each one gets a wrapper. Done here
rather than with CSS :has() because images are not reliably alone in their
paragraph, and :has() would miss the ones that are not.
"""
import re
from pelican import signals
IMG = re.compile(r'<img\b[^>]*>')
IFRAME = re.compile(r'<iframe\b[^>]*>')
DIM = re.compile(r'\b(width|height)="(\d+)"')
def _wrap(content):
body = getattr(content, "_content", None)
if not body or "<img" not in body:
return
# skip images already wrapped, e.g. if the signal fires twice
if 'class="crt"' in body:
return
content._content = IMG.sub(lambda m: f'<span class="crt">{m.group(0)}</span>', body)
def _ratio(content):
"""Give every embed its own aspect ratio so it can fill the column.
The embeds carry fixed pixel sizes from whenever they were pasted in, and
they are not all the same shape: four are 16:9 but one is 500x402. Forcing a
single ratio would letterbox or crop that one, so each gets the ratio its own
attributes describe, and anything without attributes falls back to 16:9.
"""
body = getattr(content, "_content", None)
if not body or "<iframe" not in body:
return
def sub(m):
tag = m.group(0)
if "aspect-ratio" in tag:
return tag
d = dict(DIM.findall(tag))
w, h = d.get("width"), d.get("height")
ratio = f"{w}/{h}" if w and h and int(h) else "16/9"
return tag[:-1].rstrip() + f' style="aspect-ratio:{ratio}">'
content._content = IFRAME.sub(sub, body)
def register():
signals.content_object_init.connect(_wrap)
signals.content_object_init.connect(_ratio)