Index

joshstock.in / a1f574f

Source for serving and static templating/compiling of https://joshstock.in.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
16722 Jan 2023 10:27a1f574fGenerate sitemap.xmlJosh Stockin1210G

Blob @ joshstock.in / site / targets.py

application/x-python7690 bytesdownload raw
1# targets.py / Template engine for my website
2# Joshua Stockin / josh@joshstock.in / https://joshstock.in
3
4import os
5import html
6from datetime import datetime, timezone, timedelta
7from xml.dom import minidom
8
9import markdown2
10import htmlgenerator as hg
11import readtime
12import sass
13from feedgen.feed import FeedGenerator
14
15from _utils import dotdict as namespace, current_dir, load_generators, list_files
16
17# Site generation metadata
18CONTENT_DIRECTORY = os.path.join(current_dir(), "content")
19SASS_DIRECTORY = os.path.join(current_dir(), "style")
20STATIC_DIRECTORY = os.path.join(current_dir(), "static")
21
22blog_description = "Barely coherent ramblings about engineering projects, software, hardware, and other things."
23
24# Fetch generator functions
25GENERATORS_MODULE = "generators"
26GENERATORS = [
27 "head.head",
28 "header",
29 "footer",
30 "blog.article",
31 "blog.index",
32 "blog.listing",
33]
34
35generate = load_generators(GENERATORS_MODULE, GENERATORS)
36
37sitemap_root = minidom.Document()
38sitemap_urlset = sitemap_root.createElementNS("http://www.sitemap.org/schemas/sitemap/0.9", "urlset")
39sitemap_urlset.setAttribute("xmlns", sitemap_urlset.namespaceURI)
40sitemap_root.appendChild(sitemap_urlset)
41
42def add_sitemap_url(url):
43 url_obj = sitemap_root.createElement("url")
44 loc_obj = sitemap_root.createElement("loc")
45 loc_obj.appendChild(sitemap_root.createTextNode(url))
46 url_obj.appendChild(loc_obj)
47 sitemap_urlset.appendChild(url_obj)
48
49
50# Site template implementation; returns dict {filename: data}
51def template() -> {str: str}:
52 files = {}
53
54 articles_list = []
55 fg = FeedGenerator()
56 fg.id("https://joshstock.in/blog")
57 fg.title("Blog - Josh Stockin")
58 fg.author({"name": "Josh Stockin", "email": "josh@joshstock.in", "uri": "https://joshstock.in"})
59 fg.link(href="https://joshstock.in/blog", rel="alternate")
60 fg.subtitle(blog_description)
61 fg.link(href="https://joshstock.in/atom", rel="self")
62 fg.language("en")
63
64 for content_file in list_files(CONTENT_DIRECTORY, ".md"):
65 f = open(content_file, "r")
66 data = f.read()
67 f.close()
68
69 content_html = markdown2.markdown(
70 data,
71 safe_mode=False,
72 extras=[
73 "code-friendly",
74 "cuddled-lists",
75 "fenced-code-blocks",
76 "footnotes",
77 "header-ids",
78 "metadata",
79 "strike",
80 "tables",
81 "wiki-tables",
82 "tag-friendly",
83 "target-blank-links",
84 ],
85 )
86
87 page_data = namespace(content_html.metadata)
88
89 page_data.link = page_data.link or ""
90
91 if page_data.type == "website":
92 page_generator = hg.HTML(
93 generate("head.head", page_data),
94 hg.BODY(
95 *generate("header", page_data),
96 hg.DIV(
97 hg.DIV(hg.mark_safe(content_html), _class="content-body"),
98 hg.DIV(_class="vfill"),
99 generate("footer"),
100 _class="content-container",
101 ),
102 onscroll="scroll()",
103 ),
104 )
105 files[page_data.index] = hg.render(page_generator, {}).encode("utf-8")
106 if page_data.index != "index.html":
107 add_sitemap_url("/" + page_data.index.rsplit(".html")[0])
108 else:
109 add_sitemap_url("/")
110
111 elif page_data.type == "article": # Blog article handling
112 page_data.readtime = readtime.of_html(content_html, wpm=150)
113 page_data.thumbnail = page_data.banner_image
114 page_data.link = "/blog/" + page_data.identifier
115 page_data.links = page_data.links or {}
116 articles_list += [generate("blog.listing", page_data)]
117 page_data.content = content_html
118
119 fe = fg.add_entry()
120 fe.id("https://joshstock.in/blog/" + page_data.identifier)
121 fe.author({"name": "Josh Stockin", "email": "josh@joshstock.in", "uri": "https://joshstock.in"})
122 fe.title(page_data.title)
123 fe.summary(page_data.description + " / https://joshstock.in/blog/" + page_data.identifier)
124 datetime_pub = datetime.strptime(page_data.datestring, "%Y-%m-%d").replace(tzinfo=timezone(-timedelta(hours=6)))
125 fe.published(datetime_pub)
126 fe.updated(datetime_pub)
127 fe.link(href="https://joshstock.in/blog/" + page_data.identifier)
128
129 page_generator = hg.HTML(
130 generate("head.head", page_data),
131 hg.BODY(
132 *generate("header", page_data),
133 hg.DIV(
134 hg.DIV(
135 *generate("blog.article", page_data), _class="content-body"
136 ),
137 hg.DIV(_class="vfill"),
138 generate("footer"),
139 _class="content-container",
140 ),
141 onscroll="scroll()",
142 ),
143 )
144
145 files["blog/" + page_data.identifier + ".html"] = hg.render(
146 page_generator, {}
147 ).encode("utf-8")
148
149 # Create blog index page
150 blog_page_data = namespace(
151 title="Blog",
152 banner_image="",
153 thumbnail="",
154 link="/blog",
155 description=fg.subtitle(),
156 )
157 blog_page_generator = hg.HTML(
158 generate("head.head", blog_page_data),
159 hg.BODY(
160 *generate("header", blog_page_data),
161 hg.DIV(
162 hg.DIV(
163 hg.DIV(
164 hg.H1("Blog ", hg.IMG(src="/static/svg/memo.svg", _class="inline svg")),
165 hg.P(
166 fg.subtitle(), hg.BR(),
167 hg.SPAN("[", hg.A("Atom feed", href="/atom"), "] ", style="font-size: 0.75em; color: var(--caption-color)"),
168 hg.SPAN("[", hg.A("RSS feed", href="/rss"), "]", style="font-size: 0.75em; color: var(--caption-color)")
169 )
170 ),
171 *articles_list,
172 _class="content-body",
173 ),
174 hg.DIV(_class="vfill"),
175 generate("footer"),
176 _class="content-container",
177 ),
178 onscroll="scroll()",
179 ),
180 )
181 files["blog.html"] = hg.render(blog_page_generator, {}).encode("utf-8")
182 add_sitemap_url("/blog")
183
184 # Feeds
185 files["atom.xml"] = fg.atom_str(pretty=True)
186 fg.link(href="https://joshstock.in/rss", rel="self", replace=True)
187 files["rss.xml"] = fg.rss_str(pretty=True)
188
189 # Compile Sass stylesheets
190 for stylesheet_file in list_files(SASS_DIRECTORY, ".scss"):
191 if os.path.basename(stylesheet_file)[0] != "_":
192 files[
193 os.path.join(
194 "static",
195 "style",
196 os.path.splitext(os.path.relpath(stylesheet_file, SASS_DIRECTORY))[
197 0
198 ]
199 + ".css",
200 )
201 ] = sass.compile(filename=stylesheet_file, output_style="compressed").encode("utf-8")
202
203 # Copy content from static files
204 for static_file in list_files(STATIC_DIRECTORY):
205 f = open(static_file, "rb")
206 data = f.read()
207 f.close()
208
209 files[
210 os.path.join("static", os.path.relpath(static_file, STATIC_DIRECTORY))
211 ] = data
212
213 files["sitemap.xml"] = sitemap_root.toprettyxml(indent="\t").encode("utf-8")
214
215 return files
216