blog/main.py

151 lines
3.8 KiB
Python

import os
import re
import glob
import html
import email
import logging
import datetime
from multiprocessing import Pool, TimeoutError
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)
md = markdown.Markdown(extensions=['extra', 'meta', TocExtension(anchorlink=True)])
cpu_count = os.cpu_count()
def convert(text):
md.reset()
return md.convert(text)
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 = convert(text)
title = md.Meta.get('title')[0]
date = md.Meta.get('date')[0]
draft = False
if md.Meta.get('draft'):
draft = True
out = convert('# ' + title) + 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())
out = tmpl.substitute(subs)
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():
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()