blog/main.py
Collin Lefeber 24b03c77c3
All checks were successful
/ build (push) Successful in 4s
add date to post page
2025-03-29 15:49:02 -04:00

180 lines
4.1 KiB
Python

import os
import re
import glob
import html
import logging
import datetime
import email.utils
from multiprocessing import Pool
from string import Template
import markdown
from markdown.extensions.toc import TocExtension
destpath_re = re.compile(r"\.md$")
logging.basicConfig(encoding="utf-8", level=logging.INFO)
cpu_count = os.cpu_count()
def convert(text):
md = markdown.Markdown(extensions=["extra", "meta", TocExtension(anchorlink=True)])
res = md.convert(text)
return res, md.Meta
def render_post(fpath):
destpath = destpath_re.sub(".html", fpath)
logging.info("opening %s for parsing, dest %s", fpath, destpath)
# from: https://python-markdown.github.io/reference/
with open(fpath, "r", encoding="utf-8") as input_file:
logging.info("reading %s", fpath)
text = input_file.read()
logging.info("parsing %s", fpath)
out, meta = convert(text)
title = meta.get("title")[0]
date = meta.get("date")[0]
draft = False
if meta.get("draft"):
draft = True
disp_date = datetime.datetime.fromisoformat(date).strftime(
"%Y-%m-%d"
)
title_out, _ = convert("# " + title + f'\n\n<time datetime="{disp_date}">{disp_date}</time>')
out = title_out + out
logging.info("writing to %s", destpath)
render_template(
"index.html.tmpl", destpath, {"content": out, "more_title": " - " + title}
)
return {
"title": title,
"date": date,
"fpath": fpath,
"destpath": destpath,
"draft": draft,
}
def render_posts():
files = glob.glob("posts/*.md")
logging.info("found post files %s", files)
posts = []
logging.info("starting render posts with cpu_count: %d", cpu_count)
with Pool(processes=cpu_count) as pool:
posts = pool.map(render_post, files)
logging.info("render_posts result: %s", posts)
return posts
def posts_list_html(posts):
post_tpl = """<li>
<a href="{href}">{title}</a>
<time datetime="{date}">{disp_date}</time>
</li>"""
out = '<ul class="blog-posts-list">'
for post in posts:
disp_date = datetime.datetime.fromisoformat(post.get("date")).strftime(
"%Y-%m-%d"
)
out += post_tpl.format(
href=post.get("destpath"),
title=post.get("title"),
date=post.get("date"),
disp_date=disp_date,
)
return out + "</ul>"
def render_template(tpl_fname, out_fname, subs):
with open(tpl_fname, "r", encoding="utf-8") as inf:
tmpl = Template(inf.read())
# include in every template
subs["_now"] = int(datetime.datetime.now().timestamp())
out = tmpl.substitute(subs)
out_fname = os.path.join("public/", out_fname)
with open(out_fname, "w", encoding="utf-8") as outf:
outf.write(out)
def render_index(posts):
content_html = posts_list_html(posts)
render_template(
"index.html.tmpl", "index.html", {"content": content_html, "more_title": ""}
)
def rss_post_xml(post):
tpl = """
<item>
<title>{title}</title>
<link>{link}</link>
<pubDate>{pubdate}</pubDate>
<guid>{link}</guid>
<description>{description}</description>
</item>
"""
link = "https://cfebs.com/" + post["destpath"]
with open(post["fpath"], "r", encoding="utf-8") as inf:
text = inf.read()
converted, _ = convert(text)
pubdate = email.utils.format_datetime(datetime.datetime.fromisoformat(post["date"]))
subs = {
"title": post["title"],
"link": link,
"pubdate": pubdate,
"description": converted,
}
for k, v in subs.items():
subs[k] = html.escape(v)
return tpl.format(**subs)
def render_rss_index(posts):
items = ""
for post in posts[:5]:
items += rss_post_xml(post)
subs = {
"site_title": "cfebs.com",
"site_link": "https://cfebs.com",
"self_full_link": "https://cfebs.com/index.xml",
"description": "Recent content from cfebs.com",
"last_build_date": email.utils.format_datetime(datetime.datetime.now()),
}
for k, v in subs.items():
subs[k] = html.escape(v)
subs["items"] = items
render_template("index.xml.tmpl", "index.xml", subs)
def main():
os.makedirs("public/posts/", exist_ok=True)
posts = render_posts()
logging.info("rendered posts: %s", posts)
posts = filter(lambda p: not p["draft"], posts)
sorted_posts = sorted(
posts, key=lambda p: datetime.datetime.fromisoformat(p["date"]), reverse=True
)
render_index(sorted_posts)
render_rss_index(sorted_posts)
if __name__ == "__main__":
main()