sites/randogoth.com/pelicanconf.py

122 lines
4.8 KiB
Python
Raw Normal View History

AUTHOR = 'randogoth'
SITENAME = 'RANDOGOTH'
SITEURL = ''
PATH = 'content'
TIMEZONE = 'Asia/Jerusalem'
DEFAULT_LANG = 'en'
# An ANSI bulletin board. The TuiCSS theme that came over from TRL was a DOS
# *application*: grey chrome, dialogs, a menu bar. A board is a different thing,
# and the one actually wanted here. mc-pelican stays in the tree as the fallback.
THEME = 'bbs'
feat: render randogoth.com as a small-net capsule A Pelican generator that writes a capsule beside the HTML build: plain Markdown plus per-directory .itsybitsy.toml sidecars, which a protocol daemon converts per request to gemtext, XHTML-MP, WML or plain text. The obstacle was recorded in the README as "smolweb reads YAML frontmatter while Pelican uses bare Title: lines". Both halves turned out to be wrong: itsybitsy parses no frontmatter at all, by design, and metadata lives outside the document. So the transform is not a translation between dialects, it is a removal, and a protocol daemon stays ignorant of one static generator. Nothing in plugins/smolnet.py is specific to this site. Every difference is a setting and every setting has a default, so another site enables it with PLUGINS = ['smolnet']. It sits at the repo root for the same reason flux.vision reaches into tobias.raayoni-last.com for lostimages. Index entries are emitted as link-only paragraphs rather than Markdown lists, which is not a style choice: the gemtext renderer prints a bare => line for a paragraph holding nothing but links, and a bullet *and* a => line for a list item, so a list would publish every entry twice. Gemini clients number link lines themselves, so the board's dial-an-area-by-number idiom survives into the capsule without emitting a single bracket. The trade-off is in the docstring: the text renderer reflows such a run into prose, which costs nothing here because randogoth.com is not getting Nex or Gopher. Also drops a Zemanta tracking pixel that came in with a 2012 blog import and is live on the site today, firing a third-party request on every view of that article. It would have been worse in the capsule, where an image becomes a visible link line advertising a dead tracker. It was the only one across all three sites. Verified by serving the output with the real daemon: 41 articles, 2 pages, 6 area indexes and an archive, no metadata surviving, no {filename} left, trl@posteo.net revealed on Connect where the renderer would otherwise have dropped it with its enclosing HTML, images served as image/png, and the index rendering as a clean run of => lines in gemtext and as XHTML Mobile over HTTP. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 08:24:18 +03:00
PLUGIN_PATHS = ['plugins', '../plugins']
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 <noreply@anthropic.com>
2026-10-06 11:04:28 +03:00
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,
# as they were on a real board, and working out what an area holds is the point.
BBS_AREAS = {
'RANDOM': 1, 'PLACE': 2, 'MINIMAL': 3,
'MACHINES': 4, 'GONZO': 5, 'ENDTIMES': 6,
}
feat: render randogoth.com as a small-net capsule A Pelican generator that writes a capsule beside the HTML build: plain Markdown plus per-directory .itsybitsy.toml sidecars, which a protocol daemon converts per request to gemtext, XHTML-MP, WML or plain text. The obstacle was recorded in the README as "smolweb reads YAML frontmatter while Pelican uses bare Title: lines". Both halves turned out to be wrong: itsybitsy parses no frontmatter at all, by design, and metadata lives outside the document. So the transform is not a translation between dialects, it is a removal, and a protocol daemon stays ignorant of one static generator. Nothing in plugins/smolnet.py is specific to this site. Every difference is a setting and every setting has a default, so another site enables it with PLUGINS = ['smolnet']. It sits at the repo root for the same reason flux.vision reaches into tobias.raayoni-last.com for lostimages. Index entries are emitted as link-only paragraphs rather than Markdown lists, which is not a style choice: the gemtext renderer prints a bare => line for a paragraph holding nothing but links, and a bullet *and* a => line for a list item, so a list would publish every entry twice. Gemini clients number link lines themselves, so the board's dial-an-area-by-number idiom survives into the capsule without emitting a single bracket. The trade-off is in the docstring: the text renderer reflows such a run into prose, which costs nothing here because randogoth.com is not getting Nex or Gopher. Also drops a Zemanta tracking pixel that came in with a 2012 blog import and is live on the site today, firing a third-party request on every view of that article. It would have been worse in the capsule, where an image becomes a visible link line advertising a dead tracker. It was the only one across all three sites. Verified by serving the output with the real daemon: 41 articles, 2 pages, 6 area indexes and an archive, no metadata surviving, no {filename} left, trl@posteo.net revealed on Connect where the renderer would otherwise have dropped it with its enclosing HTML, images served as image/png, and the index rendering as a clean run of => lines in gemtext and as XHTML Mobile over HTTP. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 08:24:18 +03:00
# The capsule mirrors the board: same areas, same order, same words. Gemini
# clients number link lines themselves, so an area is still dialled by number
# over there without the plugin writing a single bracket.
SMOLNET_SECTION_DIR = 'area'
SMOLNET_SECTION_ORDER = BBS_AREAS
SMOLNET_LABELS = {
'sections': 'Message areas', 'latest': 'Latest messages',
'archive': 'All messages', 'back': 'Main menu', 'pages': 'System',
'comments': 'Replies',
feat: render randogoth.com as a small-net capsule A Pelican generator that writes a capsule beside the HTML build: plain Markdown plus per-directory .itsybitsy.toml sidecars, which a protocol daemon converts per request to gemtext, XHTML-MP, WML or plain text. The obstacle was recorded in the README as "smolweb reads YAML frontmatter while Pelican uses bare Title: lines". Both halves turned out to be wrong: itsybitsy parses no frontmatter at all, by design, and metadata lives outside the document. So the transform is not a translation between dialects, it is a removal, and a protocol daemon stays ignorant of one static generator. Nothing in plugins/smolnet.py is specific to this site. Every difference is a setting and every setting has a default, so another site enables it with PLUGINS = ['smolnet']. It sits at the repo root for the same reason flux.vision reaches into tobias.raayoni-last.com for lostimages. Index entries are emitted as link-only paragraphs rather than Markdown lists, which is not a style choice: the gemtext renderer prints a bare => line for a paragraph holding nothing but links, and a bullet *and* a => line for a list item, so a list would publish every entry twice. Gemini clients number link lines themselves, so the board's dial-an-area-by-number idiom survives into the capsule without emitting a single bracket. The trade-off is in the docstring: the text renderer reflows such a run into prose, which costs nothing here because randogoth.com is not getting Nex or Gopher. Also drops a Zemanta tracking pixel that came in with a 2012 blog import and is live on the site today, firing a third-party request on every view of that article. It would have been worse in the capsule, where an image becomes a visible link line advertising a dead tracker. It was the only one across all three sites. Verified by serving the output with the real daemon: 41 articles, 2 pages, 6 area indexes and an archive, no metadata surviving, no {filename} left, trl@posteo.net revealed on Connect where the renderer would otherwise have dropped it with its enclosing HTML, images served as image/png, and the index rendering as a clean run of => lines in gemtext and as XHTML Mobile over HTTP. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 08:24:18 +03:00
}
# The address is rot13 in the HTML because of web crawlers. That defence needs
# JavaScript, which Gemini does not have, and the renderer drops raw HTML, so
# without this the one thing the Connect page exists to carry would vanish.
SMOLNET_ROT13_ATTR = 'data-r'
# The capsule's half of the replies box, off until kapara is deployed. Setting
# it puts a Replies link under every article in the capsule, so it must not be
# switched on before something answers Gemini on the other end.
#
# When it lands: kapara gateways this same remark42 instance, and remark42 keys
# a thread by the article's canonical web URL, which bbs.js builds as origin +
# pathname. So kapara has to run with `-page-url 'https://randogoth.com/%s.html'`
# and `-site randogoth`, or the capsule opens a second, empty thread under every
# article instead of joining the one that is there. Port 1966, not the default:
# stunnel owns 1965 in front of itsybitsy, and kapara has to terminate its own
# TLS because Gemini client certificates are its identity mechanism.
#
# SMOLNET_COMMENTS = 'gemini://comments.randogoth.com:1966/c/{slug}'
# Articles live flat in content/; assets are carved out of that.
ARTICLE_PATHS = ['']
ARTICLE_EXCLUDES = ['pages', 'library', 'images', 'files']
PAGE_PATHS = ['pages']
STATIC_PATHS = ['library', 'images', 'files']
# Flat slugs, for the reason TRL learned the hard way: sections get reworked and
# every reassignment moves a URL. The section lives in the listing, not the path.
ARTICLE_URL = '{slug}.html'
ARTICLE_SAVE_AS = '{slug}.html'
PAGE_URL = '{slug}.html'
PAGE_SAVE_AS = '{slug}.html'
CATEGORY_URL = 'section/{slug}.html'
CATEGORY_SAVE_AS = 'section/{slug}.html'
CATEGORIES_SAVE_AS = 'sections.html'
TAG_URL = 'tag/{slug}.html'
TAG_SAVE_AS = 'tag/{slug}.html'
TAGS_SAVE_AS = 'tags.html'
ARCHIVES_SAVE_AS = 'archives.html'
AUTHOR_SAVE_AS = ''
AUTHORS_SAVE_AS = ''
# Unlike the other two sites, this one is a blog, so it is paginated and it has
# feeds. People should be able to subscribe to a devlog without visiting it.
DEFAULT_PAGINATION = 15
FEED_ALL_ATOM = 'feeds/all.atom.xml'
FEED_ALL_RSS = 'feeds/all.rss.xml'
CATEGORY_FEED_ATOM = 'feeds/{slug}.atom.xml'
CATEGORY_FEED_RSS = 'feeds/{slug}.rss.xml'
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None
# The eight sections are the navigation, the way a file manager shows directories.
DISPLAY_CATEGORIES_ON_MENU = True
DISPLAY_PAGES_ON_MENU = False
MENUITEMS = [
('ARCHIVES', '/archives.html'),
('TAGS', '/tags.html'),
]
# No nl2br. The recovered bodies are hard wrapped at roughly 70 characters, so it
# turns every source line into a forced break and the prose stops reflowing.
MARKDOWN = {
'extension_configs': {
'markdown.extensions.tables': {},
'markdown.extensions.footnotes': {},
'markdown.extensions.codehilite': {'css_class': 'highlight'},
'markdown.extensions.extra': {},
},
'output_format': 'html5',
}
DELETE_OUTPUT_DIRECTORY = True
CACHE_CONTENT = False
feat: replies on every article, in the board's own chrome A message base is a thing people answer, and until now this one could only be read. The site already calls its articles messages in areas, so replies are the feature the metaphor was asking for rather than a comment box bolted onto it. Talks to the comment server's API directly instead of loading its widget. The widget is a React app in an iframe and would arrive with its own fonts, spacing and avatars; an iframe cannot inherit the page's font in any case. Rules are drawn the way the guestbook draws them, padded to exactly 80 cells, so a reply is indistinguishable from any other row on the board. All five pre elements in the section measure 80 in a real browser. Two things this surfaced, both verified by driving a browser rather than curl: The command handler took every letter key as a command, which was harmless when there was nothing on the board to type into. With a message box, typing `i` navigated to the index mid-sentence. It now ignores keys aimed at an input or textarea. bbs.js already says the bracket chrome is a promise rather than decoration, and [P]ost was drawn without wiring P to anything. P now focuses the message box. Handles are checked here as well as at the server, since remark42 wants three or more characters and only letters, numbers, underscores and spaces; failing in the page is better than a refusal with no explanation. Without JS the section is simply absent, which is honest, and the capsule never sees it since Gemini has no way to render it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 18:10:23 +03:00
# The comment server. One instance serves three sites, keyed on COMMENTS_SITE,
# so this is the id rather than the hostname. Unset it and the replies section
# disappears from every article, which is the off switch.
COMMENTS_HOST = 'https://comments.randogoth.com'
COMMENTS_SITE = 'randogoth'