From a5de93576a79714c59de2616649d67f67bb66c9e Mon Sep 17 00:00:00 2001 From: omicron Date: Wed, 26 Aug 2026 04:11:56 +0200 Subject: [PATCH] Add sitemap generation --- omicron/ssg/output/__init__.py | 2 ++ omicron/ssg/output/content.py | 1 + omicron/ssg/output/index.py | 1 + omicron/ssg/output/output.py | 2 ++ omicron/ssg/output/sitemap.py | 38 ++++++++++++++++++++++++++++++++++ omicron/ssg/output/tags.py | 1 + omicron/ssg/site.py | 7 +++++++ 7 files changed, 52 insertions(+) create mode 100644 omicron/ssg/output/sitemap.py diff --git a/omicron/ssg/output/__init__.py b/omicron/ssg/output/__init__.py index f040a53..811de7b 100644 --- a/omicron/ssg/output/__init__.py +++ b/omicron/ssg/output/__init__.py @@ -7,6 +7,7 @@ from omicron.ssg.output.memory import Memory from omicron.ssg.output.directory import Directory from omicron.ssg.output.symlink import Symlink from omicron.ssg.output.tags import Tags, discover_tags +from omicron.ssg.output.sitemap import Sitemap __all__ = [ "Output", @@ -23,4 +24,5 @@ __all__ = [ "Symlink", "Tags", "discover_tags", + "Sitemap", ] diff --git a/omicron/ssg/output/content.py b/omicron/ssg/output/content.py index 55cfef2..9a9b752 100644 --- a/omicron/ssg/output/content.py +++ b/omicron/ssg/output/content.py @@ -44,6 +44,7 @@ class Content(Output): self.tags: set[str] = tags self.summary: str | None = summary self.draft: bool = draft + self.in_sitemap = True @staticmethod def build_path(section: str, slug: str) -> Path: diff --git a/omicron/ssg/output/index.py b/omicron/ssg/output/index.py index 6bff180..c831742 100644 --- a/omicron/ssg/output/index.py +++ b/omicron/ssg/output/index.py @@ -30,6 +30,7 @@ class Index(Output): self.page_num = page_num self.total_pages = total_pages self.label = label + self.in_sitemap = kind != "tag" and page_num == 1 def pagination_url(self, n: int) -> str: path = Index.build_path(self.kind, n, self.label) diff --git a/omicron/ssg/output/output.py b/omicron/ssg/output/output.py index e3e2c0f..1f3f38b 100644 --- a/omicron/ssg/output/output.py +++ b/omicron/ssg/output/output.py @@ -31,6 +31,8 @@ class Output(ABC): url = url.parent self.url = url.as_posix() + self.in_sitemap = False + @property def site(self) -> Site: obj = self._site_ref() diff --git a/omicron/ssg/output/sitemap.py b/omicron/ssg/output/sitemap.py new file mode 100644 index 0000000..78641fc --- /dev/null +++ b/omicron/ssg/output/sitemap.py @@ -0,0 +1,38 @@ +import logging +from pathlib import Path +from typing import TYPE_CHECKING +from xml.etree.ElementTree import Element, ElementTree, SubElement +from omicron.ssg.output.output import Output +from omicron.ssg.output.content import Content + +log = logging.getLogger(__name__) + +if TYPE_CHECKING: + from omicron.ssg.site import Site +else: + Site = "omicron.ssg.site.Site" + + +class Sitemap(Output): + PATH = Path("sitemap.xml") + NAMESPACE = "http://www.sitemaps.org/schemas/sitemap/0.9" + + def __init__(self, site: Site): + super().__init__(site, Sitemap.PATH) + + def write(self) -> None: + urlset = Element("urlset", xmlns=Sitemap.NAMESPACE) + for entry in self.site.by_path.values(): + if not entry.in_sitemap: + continue + + url = SubElement(urlset, "url") + SubElement(url, "loc").text = f"{self.site.origin}{entry.url}" + if isinstance(entry, Content): + lastmod = entry.updated or entry.created + SubElement(url, "lastmod").text = lastmod.isoformat() + + dest = self.site.output_path / self.destination + dest.parent.mkdir(parents=True, exist_ok=True) + ElementTree(urlset).write(dest, encoding="utf-8", xml_declaration=True) + log.debug("Wrote %s", dest) diff --git a/omicron/ssg/output/tags.py b/omicron/ssg/output/tags.py index b0a1b19..e95becb 100644 --- a/omicron/ssg/output/tags.py +++ b/omicron/ssg/output/tags.py @@ -17,6 +17,7 @@ class Tags(Output): def __init__(self, site: Site, tags: list[tuple[str, int]]): super().__init__(site, Tags.PATH) self.tags = tags + self.in_sitemap = True def write(self) -> None: template = self.site.jinja_env.get_template("tags.html") diff --git a/omicron/ssg/site.py b/omicron/ssg/site.py index de63e7e..d7d8da2 100644 --- a/omicron/ssg/site.py +++ b/omicron/ssg/site.py @@ -15,6 +15,7 @@ from omicron.ssg.output import ( Index, Tags, Memory, + Sitemap, discover_index, discover_tags, ) @@ -194,6 +195,12 @@ class Site: tags_page = discover_tags(self) self.add_by_path(tags_page) self.other_outputs.append(tags_page) + if self.origin: + sitemap = Sitemap(self) + self.add_by_path(sitemap) + self.other_outputs.append(sitemap) + else: + log.debug("Skipping sitemap, base_url has no domain name") log.info("Discovered %d content items", len(self.content)) def clean(self) -> None: