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 <noreply@anthropic.com>
This commit is contained in:
randogoth 2026-10-10 15:39:26 +03:00
parent bfb54d3ffa
commit e025f32f61

View file

@ -187,20 +187,30 @@ def rewrite_internal(text, by_source, warn):
return INTERNAL.sub(sub, text) 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. """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 `/<slug>`, since the `/pages/glossary.html` and `/go-west.html` both become `/<slug>`, 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 reported and left alone rather than silently rewritten into a second broken
link. link.
""" """
def sub(match): def sub(match):
target, rest = match.group(1), match.group(2) target, rest = match.group(1), match.group(2)
slug = os.path.basename(target)[: -len(".html")] key = target.lstrip("/")
if slug in slugs: if key in urls:
return "](/%s%s)" % (slug, rest) return "](/%s%s)" % (urls[key], rest)
warn("smolnet: link to %s matches no document", target) warn("smolnet: link to %s matches no document", target)
return match.group(0) return match.group(0)
@ -391,10 +401,10 @@ class CapsuleGenerator(Generator):
# Map source basename -> slug, so {filename} can be resolved. Built from # Map source basename -> slug, so {filename} can be resolved. Built from
# everything published, pages included, since an article may link one. # everything published, pages included, since an article may link one.
by_source = {} by_source = {}
slugs = set() urls = {}
for doc in articles + pages: for doc in articles + pages:
by_source[os.path.basename(doc.source_path)] = doc.slug 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) os.makedirs(out, exist_ok=True)
root_titles = {} root_titles = {}
@ -403,7 +413,7 @@ class CapsuleGenerator(Generator):
body = strip_metadata(self._read(doc)) body = strip_metadata(self._read(doc))
body = body.replace(SUMMARY_MARKER, "") body = body.replace(SUMMARY_MARKER, "")
body = rewrite_internal(body, by_source, self._warn) 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 = reveal_rot13(body, rot_attr)
body = drop_dead_images(body, dead_hosts) body = drop_dead_images(body, dead_hosts)
if footnotes: if footnotes: