From 4efe97559998e6664335d0ea92ea37bcf8349ca6 Mon Sep 17 00:00:00 2001 From: randogoth Date: Tue, 6 Oct 2026 11:04:28 +0300 Subject: [PATCH] fix: recover one hotlinked image, retire the other eleven Twelve images across seven articles were hotlinked from servers that no longer exist, so they were broken on the live sites. Checked every one against the Wayback Machine, patiently enough to trust the answer: an earlier pass appeared to find seven, but that was a test treating an empty response as a hit. One survives. visualberlin.org's p1010789, a 2011 capture of the projector set up against Mannheim city hall during the Flimmerkiste wildscreening, is now a local asset in flux.vision/content/library/ and the reference points at it. The other eleven were never captured. Both dead domains are archived, so this is not a gap in coverage: of 8,438 visualberlin.org URLs and 204 for mutanten.org, only that one image is there. mutanten.org's archive does not reach back to its fp-content era at all, which is where the Logan's Run stills lived. So lostimages.py learns about dead hosts, which it matches rather than fetching, because a build must not depend on the network and a dead host is a fact about the world rather than about the document. The references stay in the Markdown, as the existing ones do: the reference records what was there. It matters more on the capsule than on the web. A browser shows a broken image as a silent gap, but gemtext has no inline images, so every one becomes a visible => link line and the page would advertise a dead host as somewhere worth going. smolnet.py therefore strips them too, reading the same host list, since it works on the Markdown source and never sees Pelican's output. lostimages.py moves to the repo-level plugins/ directory beside smolnet. It was shared already, with flux.vision reaching into tobias.raayoni-last.com for it, and randogoth.com now needs it too; a shared plugin living inside one site was the wrong shape for three consumers. Left alone deliberately: the two mutanten.org links in mutantenkino-website.md. That entry is about having built the site, so the link is its subject rather than decoration, and a dead link does not make the record wrong. Co-Authored-By: Claude Opus 5 --- .../content/flimmerkiste-2-wildscreening.md | 2 +- .../content/library/p1010789-492x276.jpg | Bin 0 -> 32096 bytes flux.vision/pelicanconf.py | 11 ++- plugins/lostimages.py | 84 ++++++++++++++++++ plugins/smolnet.py | 35 ++++++++ randogoth.com/pelicanconf.py | 11 ++- tobias.raayoni-last.com/pelicanconf.py | 2 +- tobias.raayoni-last.com/plugins/lostimages.py | 55 ------------ 8 files changed, 141 insertions(+), 59 deletions(-) create mode 100644 flux.vision/content/library/p1010789-492x276.jpg create mode 100644 plugins/lostimages.py delete mode 100644 tobias.raayoni-last.com/plugins/lostimages.py diff --git a/flux.vision/content/flimmerkiste-2-wildscreening.md b/flux.vision/content/flimmerkiste-2-wildscreening.md index 5402a4c..81597fd 100755 --- a/flux.vision/content/flimmerkiste-2-wildscreening.md +++ b/flux.vision/content/flimmerkiste-2-wildscreening.md @@ -33,7 +33,7 @@ generator, a nice 5000 ANSI projector, manfrotto tripod, V4 and laptops we walked through the Kreuzberg'ish 'Jungbusch' area towards the center marketplace where the huge city hall is located. -![p1010789](http://visualberlin.org/wp-content/uploads/2009/05/p1010789-492x276.jpg "p1010789") +![p1010789](/library/p1010789-492x276.jpg "p1010789") Equipment was set up quickly and we had a lot of fun, doing spontaneous mapping masks, jamming along, spreading Flimmerkiste flyers to curious diff --git a/flux.vision/content/library/p1010789-492x276.jpg b/flux.vision/content/library/p1010789-492x276.jpg new file mode 100644 index 0000000000000000000000000000000000000000..624c0dec7787ffefb38a4a2cb45d1f30ac26a6ee GIT binary patch literal 32096 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 literal 0 HcmV?d00001 diff --git a/flux.vision/pelicanconf.py b/flux.vision/pelicanconf.py index c3f37ee..16c316d 100644 --- a/flux.vision/pelicanconf.py +++ b/flux.vision/pelicanconf.py @@ -7,9 +7,18 @@ TIMEZONE = 'Europe/Berlin' DEFAULT_LANG = 'en' THEME = 'flux' -PLUGIN_PATHS = ['plugins', '../tobias.raayoni-last.com/plugins'] +PLUGIN_PATHS = ['plugins', '../plugins'] PLUGINS = ['assetcheck', 'tileweight', 'lostimages'] +# Hosts that no longer exist, so their hotlinked images can never resolve. +# Checked against Wayback: of twelve such images only one was ever captured, +# and it now lives in content/library/. See lostimages.py. +LOSTIMAGES_DEAD_HOSTS = [ + 'visualberlin.org', 'mutanten.org', 'web.mac.com', + 'kino.web.de', 'lh4.google.it', 'l.yimg.com', +] + + ARTICLE_PATHS = [''] ARTICLE_EXCLUDES = ['pages', 'library', 'images', 'recover'] PAGE_PATHS = ['pages'] diff --git a/plugins/lostimages.py b/plugins/lostimages.py new file mode 100644 index 0000000..e5ab17f --- /dev/null +++ b/plugins/lostimages.py @@ -0,0 +1,84 @@ +"""Drop tags in article bodies whose image is gone for good. + +Two kinds of gone, same symptom: + +**Local.** The same situation as assetcheck.py, one level down: the recovered +bodies kept their original /library/ references, and 22 of 200 point at files no +archive holds (checked against Wayback; the CDX API returns no captures). + +**Remote.** Older posts hotlink images from other people's servers, and some of +those servers no longer exist: visualberlin.org, mutanten.org, web.mac.com, +kino.web.de, lh4.google.it, l.yimg.com. Name them in LOSTIMAGES_DEAD_HOSTS and +their images are treated exactly like a lost local file. The host is matched +rather than the URL fetched, because a build must not depend on the network and +a dead host is a fact about the world, not about this document. + +Left alone either kind renders as a broken-image box, which on a phone reads as +an unexplained 40px hole between paragraphs. On a gemtext capsule it is worse: +an image becomes a visible link line, so the page advertises a dead host. + +The reference is still worth keeping in the Markdown source, so this strips it +only from the generated output and leaves a comment naming the file, which keeps +the output self-documenting for anyone who later finds the originals. +""" +import os +import re + +from pelican import signals + +IMG = re.compile(r']*\bsrc="([^"]+)"[^>]*>') +REMOTE = re.compile(r'^https?://([^/]+)/', re.IGNORECASE) +ANCHOR = re.compile(r']*\bhref="(/library/[^"]+)"[^>]*>(.*?)', re.S) + + +def _strip(content): + body = getattr(content, "_content", None) + if not body or "" % name_of(src) + + body = IMG.sub(sub, body) + # a thumbnail that linked to the full-size file leaves the behind, and + # its href 404s just as the did + body = ANCHOR.sub(anchor, body) + if not lost: + return + # a paragraph that held nothing but the lost image would still occupy space + body = re.sub(r"

\s*((?:\s*)+)

", r"\1", body) + content._content = body + content.lost_images = lost + + +def register(): + signals.content_object_init.connect(_strip) diff --git a/plugins/smolnet.py b/plugins/smolnet.py index a34c6e4..b757234 100644 --- a/plugins/smolnet.py +++ b/plugins/smolnet.py @@ -69,6 +69,12 @@ INTERNAL = re.compile(r"\{(filename|static|attach)\}([^)\s]+)") SUMMARY_MARKER = "" +# Markdown image syntax, for dropping the ones whose host is gone. Matched on +# the source rather than the rendered HTML because this plugin reads the +# Markdown directly, so lostimages.py, which works on Pelican's output, never +# sees the capsule. +MD_IMAGE = re.compile(r'!\[[^\]]*\]\(\s*(https?://[^\s)]+)[^)]*\)') + def rot13(text): """The obfuscation used on addresses in the HTML templates.""" @@ -156,6 +162,32 @@ def reveal_rot13(text, attr): return "".join(out) +def drop_dead_images(text, dead): + """Remove images hotlinked from hosts that no longer exist. + + It matters more here than on the web. A browser shows a broken image as a + silent gap, but gemtext has no inline images: every one becomes a visible + `=>` link line, so the page would advertise a dead host as though it were + somewhere worth going. + + Shares LOSTIMAGES_DEAD_HOSTS with lostimages.py so there is one list, and + matches on the host rather than fetching, because a build must not depend on + the network. + """ + if not dead: + return text + + def sub(match): + host = match.group(1).split("//", 1)[1].split("/")[0].lower().split(":")[0] + if any(host == d or host.endswith("." + d) for d in dead): + return "" + return match.group(0) + + text = MD_IMAGE.sub(sub, text) + # a line that held nothing but the dropped image would leave a blank + return re.sub(r"\n[ \t]*\n[ \t]*\n+", "\n\n", text) + + def toml_escape(value): return str(value).replace("\\", "\\\\").replace('"', '\\"') @@ -193,6 +225,8 @@ class CapsuleGenerator(Generator): order = s.get("SMOLNET_SECTION_ORDER", {}) or {} latest_n = s.get("SMOLNET_LATEST", 15) rot_attr = s.get("SMOLNET_ROT13_ATTR") + dead_hosts = {h.lower().lstrip(".") for h in + s.get("LOSTIMAGES_DEAD_HOSTS", [])} sidecar_name = s.get("SMOLNET_SIDECAR", ".itsybitsy.toml") articles = [a for a in self.context.get("articles", [])] @@ -214,6 +248,7 @@ class CapsuleGenerator(Generator): body = body.replace(SUMMARY_MARKER, "") body = rewrite_internal(body, by_source, self._warn) body = reveal_rot13(body, rot_attr) + body = drop_dead_images(body, dead_hosts) # Blank lines, not newlines: a heading and the line under it are # separate blocks only if a blank line divides them, otherwise the # date runs into the first sentence as one paragraph. diff --git a/randogoth.com/pelicanconf.py b/randogoth.com/pelicanconf.py index 5d7914f..b7f1455 100644 --- a/randogoth.com/pelicanconf.py +++ b/randogoth.com/pelicanconf.py @@ -10,7 +10,16 @@ DEFAULT_LANG = 'en' # and the one actually wanted here. mc-pelican stays in the tree as the fallback. THEME = 'bbs' PLUGIN_PATHS = ['plugins', '../plugins'] -PLUGINS = ['crtimages', 'smolnet'] +PLUGINS = ['crtimages', 'smolnet', 'lostimages'] + +# Hosts that no longer exist, so their hotlinked images can never resolve. +# Checked against Wayback: of twelve such images only one was ever captured, +# and it now lives in content/library/. See lostimages.py. +LOSTIMAGES_DEAD_HOSTS = [ + 'visualberlin.org', 'mutanten.org', 'web.mac.com', + 'kino.web.de', 'lh4.google.it', 'l.yimg.com', +] + # The sections are message areas, numbered so they can be dialled by key the way # a board's main menu works. No descriptions: the names are the whole listing, diff --git a/tobias.raayoni-last.com/pelicanconf.py b/tobias.raayoni-last.com/pelicanconf.py index b07879f..a45c59d 100644 --- a/tobias.raayoni-last.com/pelicanconf.py +++ b/tobias.raayoni-last.com/pelicanconf.py @@ -6,7 +6,7 @@ TIMEZONE = 'Asia/Jerusalem' DEFAULT_LANG = 'en' THEME = 'raayoni' -PLUGIN_PATHS = ['plugins'] +PLUGIN_PATHS = ['plugins', '../plugins'] PLUGINS = ['assetcheck', 'lostimages'] # Dark is the register this work belongs to, so it is the default rather than # following the system. An explicit toggle (persisted in localStorage) wins. diff --git a/tobias.raayoni-last.com/plugins/lostimages.py b/tobias.raayoni-last.com/plugins/lostimages.py deleted file mode 100644 index c7b36ef..0000000 --- a/tobias.raayoni-last.com/plugins/lostimages.py +++ /dev/null @@ -1,55 +0,0 @@ -"""Drop tags in article bodies whose file did not survive the recovery. - -The same situation as assetcheck.py, one level down: the recovered bodies kept -their original /library/ references, and 22 of 200 point at files no archive -holds (checked against Wayback; the CDX API returns no captures for them). - -Left alone they render as a broken-image box, which on a phone reads as an -unexplained 40px hole between paragraphs. The reference is still worth keeping -in the Markdown source, so this strips it only from the generated HTML and -leaves a comment naming the file, which keeps the output self-documenting for -anyone who later finds the originals on the offline drive. -""" -import os -import re - -from pelican import signals - -IMG = re.compile(r']*\bsrc="(/[^"]+)"[^>]*>') -ANCHOR = re.compile(r']*\bhref="(/library/[^"]+)"[^>]*>(.*?)
', re.S) - - -def _strip(content): - body = getattr(content, "_content", None) - if not body or "" % os.path.basename(rel) - - body = IMG.sub(sub, body) - # a thumbnail that linked to the full-size file leaves the behind, and - # its href 404s just as the did - body = ANCHOR.sub(anchor, body) - if not lost: - return - # a paragraph that held nothing but the lost image would still occupy space - body = re.sub(r"

\s*((?:\s*)+)

", r"\1", body) - content._content = body - content.lost_images = lost - - -def register(): - signals.content_object_init.connect(_strip)