Files

139 lines
5.1 KiB
Python

#!/usr/bin/env python3
"""Render the 'wikis that were not ours' markdown essay into a PDF.
Simple, dependency-light: parses the subset of markdown used in the essay
(headings, hr, bullet lists, bold/italic inline, paragraphs) and builds it
with reportlab. A4, bookish serif (Times), generous leading.
"""
import re
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import mm
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.lib.colors import black, HexColor
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, HRFlowable,
)
HERE = os.path.dirname(os.path.abspath(__file__))
INPUT = os.path.join(HERE, "README.md")
OUTPUT = os.path.join(HERE, "the-wikis-that-were-not-ours.pdf")
MARGIN = 22 * mm
WIDTH = A4[0] - 2 * MARGIN
INK = black
ACCENT = HexColor("#5b4636") # faded brown, like old book covers
STYLES = {
"title": ParagraphStyle(
"Title", fontName="Times-Bold", fontSize=22, leading=28,
alignment=TA_LEFT, spaceBefore=4 * mm, spaceAfter=2 * mm, textColor=INK),
"subtitle": ParagraphStyle(
"Subtitle", fontName="Times-Italic", fontSize=11, leading=16,
alignment=TA_LEFT, spaceAfter=6 * mm, textColor=HexColor("#444444")),
"h2": ParagraphStyle(
"H2", fontName="Times-Bold", fontSize=15, leading=20,
spaceBefore=9 * mm, spaceAfter=3 * mm, textColor=INK),
"h3": ParagraphStyle(
"H3", fontName="Times-Bold", fontSize=12.5, leading=17,
spaceBefore=6 * mm, spaceAfter=2 * mm, textColor=INK),
"body": ParagraphStyle(
"Body", fontName="Times-Roman", fontSize=11, leading=17,
alignment=TA_JUSTIFY, spaceAfter=3.2 * mm, textColor=INK),
"bullet": ParagraphStyle(
"Bullet", fontName="Times-Roman", fontSize=11, leading=16,
alignment=TA_LEFT, leftIndent=6 * mm, bulletIndent=1.5 * mm,
spaceAfter=1.6 * mm, textColor=INK),
"colophon": ParagraphStyle(
"Colophon", fontName="Times-Italic", fontSize=10.5, leading=15,
alignment=TA_LEFT, spaceAfter=2 * mm, textColor=HexColor("#444444")),
}
def inline(text: str) -> str:
"""Convert markdown inline markup to reportlab XML, escaping the rest."""
text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
text = re.sub(r"\[([^\]]+)\]\(([^)]+)\)", r'<link href="\2" color="#3a5a8c">\1</link>', text)
text = re.sub(r"\*\*([^*]+)\*\*", r"<b>\1</b>", text)
text = re.sub(r"\*([^*]+)\*", r"<i>\1</i>", text)
return text
def build():
with open(INPUT, "r", encoding="utf-8") as f:
lines = f.read().splitlines()
elements = []
i = 0
first_h1 = True
while i < len(lines):
raw = lines[i]
line = raw.strip()
i += 1
if not line:
continue
if line == "---":
elements.append(Spacer(1, 2 * mm))
elements.append(HRFlowable(width="100%", thickness=0.6,
color=ACCENT, spaceBefore=2 * mm,
spaceAfter=2 * mm))
continue
if line.startswith("# "):
style = STYLES["title"] if first_h1 else STYLES["h2"]
elements.append(Paragraph(inline(line[2:]), style))
first_h1 = False
continue
if line.startswith("## "):
elements.append(Paragraph(inline(line[3:]), STYLES["h2"]))
continue
if line.startswith("### "):
elements.append(Paragraph(inline(line[4:]), STYLES["h3"]))
continue
if re.match(r"^- ", line):
items = []
while i < len(lines) and lines[i].strip().startswith("- "):
items.append(lines[i].strip()[2:])
i += 1
for item in items:
elements.append(Paragraph(inline(item), STYLES["bullet"],
bulletText="\u2022"))
continue
# Collect a paragraph (until blank line or structural line)
para = [line]
while i < len(lines):
nxt = lines[i].strip()
if (not nxt or nxt == "---" or nxt.startswith("#")
or nxt.startswith("- ")):
break
para.append(nxt)
i += 1
text = " ".join(para)
# Italic-only lines (e.g. the source line, the closing — K.H.)
if re.fullmatch(r"\*[^*].*\*", text) and not text.startswith("*An"):
elements.append(Paragraph(inline(text), STYLES["colophon"]))
else:
elements.append(Paragraph(inline(text), STYLES["body"]))
# Drop the README H1 duplicate? No — the README's H1 is the essay title; keep it.
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=24 * mm, bottomMargin=24 * mm,
title="The Wikis That Were Not Ours",
author="Kevin Hermes",
subject="What the AI agents at collusion.wiki actually did",
)
doc.build(elements)
print(f"PDF written: {OUTPUT} ({os.path.getsize(OUTPUT)} bytes)")
if __name__ == "__main__":
build()