From e025f32f610c235e5d1b5df299d8eb3e11b7c82b Mon Sep 17 00:00:00 2001 From: randogoth Date: Sat, 10 Oct 2026 15:39:26 +0300 Subject: [PATCH] Fix rewrite_html_links for sites whose URL isn't a bare {slug}.html It derived the slug to match against by stripping ".html" off a hardcoded link's basename, which only equals the real slug on a site whose ARTICLE_URL/PAGE_URL *is* "{slug}.html" -- true for randogoth.com, where this was first written and verified, false for sublunar.space's ARTICLE_URL ("{date:%Y}-{date:%m}-{slug}.html": "chaxiraxi"'s real link target is "2018-06-chaxiraxi.html", whose basename-minus-extension is "2018-06-chaxiraxi", never equal to the slug "chaxiraxi"). Every such article-to-article link passed smolnet's own "no match" branch and reached the capsule unrewritten, pointing at a path itsybitsy has no document for. Matches against each document's own rendered .url instead, which is correct for any ARTICLE_URL/PAGE_URL shape rather than one specific one. Verified against sublunar.space's full content: the reported broken link and 160+ others like it across the corpus now resolve; every remaining unrewritten .html link left in the capsule traces to a target genuinely absent from it (a tag-index page, a draft, a hidden page) or to a pre-existing dead link already broken on the live HTML site, unrelated to this fix. Co-Authored-By: Claude Sonnet 5 --- plugins/smolnet.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/plugins/smolnet.py b/plugins/smolnet.py index cc4460d..b9188f3 100644 --- a/plugins/smolnet.py +++ b/plugins/smolnet.py @@ -187,20 +187,30 @@ def rewrite_internal(text, by_source, warn): return INTERNAL.sub(sub, text) -def rewrite_html_links(text, slugs, warn): +def rewrite_html_links(text, urls, warn): """Point links written against the HTML build at the capsule instead. + Matched against each document's own rendered URL (Pelican's ARTICLE_URL / + PAGE_URL settings resolved per document), not by stripping ".html" off the + link's basename and hoping that equals the slug. That shortcut only holds + for a site whose URL *is* a bare "{slug}.html" -- true for randogoth.com, + where this was first written, false for a site like sublunar.space whose + ARTICLE_URL prefixes the date ("2018-06-chaxiraxi.html" for slug + "chaxiraxi"). There the stripped string never matched any slug, and every + article-to-article link passed through unrewritten, pointing the capsule + at a path itsybitsy has no document for. + `/pages/glossary.html` and `/go-west.html` both become `/`, since the - capsule is flat. A target whose slug is not among the documents built is + capsule is flat. A target whose rendered URL matches no document built is reported and left alone rather than silently rewritten into a second broken link. """ def sub(match): target, rest = match.group(1), match.group(2) - slug = os.path.basename(target)[: -len(".html")] - if slug in slugs: - return "](/%s%s)" % (slug, rest) + key = target.lstrip("/") + if key in urls: + return "](/%s%s)" % (urls[key], rest) warn("smolnet: link to %s matches no document", target) return match.group(0) @@ -391,10 +401,10 @@ class CapsuleGenerator(Generator): # Map source basename -> slug, so {filename} can be resolved. Built from # everything published, pages included, since an article may link one. by_source = {} - slugs = set() + urls = {} for doc in articles + pages: by_source[os.path.basename(doc.source_path)] = doc.slug - slugs.add(doc.slug) + urls[doc.url] = doc.slug os.makedirs(out, exist_ok=True) root_titles = {} @@ -403,7 +413,7 @@ class CapsuleGenerator(Generator): body = strip_metadata(self._read(doc)) body = body.replace(SUMMARY_MARKER, "") body = rewrite_internal(body, by_source, self._warn) - body = rewrite_html_links(body, slugs, self._warn) + body = rewrite_html_links(body, urls, self._warn) body = reveal_rot13(body, rot_attr) body = drop_dead_images(body, dead_hosts) if footnotes: