57 lines
1.9 KiB
Python
57 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)
|