Compare commits
3 Commits
865a2f7ca9
...
555c2e767a
Author | SHA1 | Date | |
---|---|---|---|
555c2e767a | |||
e0382bfc81 | |||
00dae2c336 |
59
build/index.py
Normal file
59
build/index.py
Normal file
@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import re
|
||||
|
||||
# we expect the arguments to be filepaths to each blog post
|
||||
|
||||
def print_usage():
|
||||
print("\nusage: python mkblogindex.py POSTS\n")
|
||||
print("\n")
|
||||
print("\t\tPOSTS\tfilepaths of blog posts")
|
||||
|
||||
# check args for at least one file path
|
||||
if len(sys.argv) < 2:
|
||||
print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
# posts are arguments from index 1 onwards
|
||||
posts = sys.argv[1:]
|
||||
|
||||
dir_pattern = re.compile("(.+)/(blog\/.+\.html)")
|
||||
path_pattern = re.compile("(.+)\/(\d{4})\/(\d{1,2})\/(\d{1,2})\/(.+).html")
|
||||
title_pattern = re.compile("<h1>(.+)</h1>")
|
||||
|
||||
# filter posts to just those with a date in them
|
||||
posts = [p for p in posts if path_pattern.match(p)]
|
||||
posts.reverse()
|
||||
|
||||
links = []
|
||||
|
||||
# for each file we want to output an <a> tag with a relative href to the site root
|
||||
for path in posts:
|
||||
m = re.match(path_pattern, path)
|
||||
year = m.group(2)
|
||||
month = m.group(3).rjust(2, '0')
|
||||
day = m.group(4).rjust(2, '0')
|
||||
|
||||
date = f'<span class="post-date">{year}-{month}-{day}</span>'
|
||||
|
||||
title = ""
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
if title_pattern.match(line):
|
||||
title = re.sub(title_pattern, r'<span class="post-title">\1</span>', line).strip()
|
||||
break
|
||||
|
||||
# clean leading directories to get the relative path we'll use for the link
|
||||
url = re.sub(dir_pattern, r"\2", path)
|
||||
|
||||
item = (date, f'<li><a href="{url}">{date}{title}</a></li>')
|
||||
links.append(item)
|
||||
|
||||
# make sure we're properly ordered in reverse date order lol
|
||||
links = sorted(links, key=lambda x: x[0])
|
||||
links.reverse()
|
||||
|
||||
for l in links:
|
||||
print(l[1])
|
||||
|
88
build/page.py
Normal file
88
build/page.py
Normal file
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
import markdown
|
||||
import re
|
||||
|
||||
# SRC
|
||||
# +-2022/
|
||||
# | +-10/
|
||||
# | +-12/
|
||||
# | +-25/
|
||||
# +-2023/
|
||||
# | +-1/
|
||||
# | +-26/
|
||||
# | +-3/
|
||||
# ...
|
||||
|
||||
def print_usage():
|
||||
print("\nusage: python mkblog.py SRC DEST\n")
|
||||
print("\n")
|
||||
print("\t\tSRC\tinput markdown file")
|
||||
print("\t\tDEST\tdestination html file")
|
||||
|
||||
# check args
|
||||
if len(sys.argv) != 3:
|
||||
print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
src_file = sys.argv[1]
|
||||
dest_file = sys.argv[2]
|
||||
|
||||
# check blog root exists
|
||||
if not os.path.isfile(src_file):
|
||||
print("{blog_root} doesn't exist")
|
||||
sys.exit(1)
|
||||
|
||||
# make dest dir if it doesnt exist
|
||||
|
||||
dest_dir = os.path.dirname(dest_file)
|
||||
print(dest_dir)
|
||||
if not os.path.isdir(dest_dir):
|
||||
os.makedirs(dest_dir)
|
||||
|
||||
# write markdown into a dummy file first so that we can add lines before it in the final output
|
||||
dummy_file = f"{dest_file}.bak"
|
||||
open(dummy_file, 'w').close()
|
||||
|
||||
print(f"{src_file} -> {dummy_file}")
|
||||
markdown.markdownFromFile(input=src_file, output=dummy_file, extensions=["fenced_code"])
|
||||
|
||||
# TODO: a lot of this templating work is specific to the ktyl.dev blog - ideally, that stuff should
|
||||
# be in *that* repo, not this one
|
||||
print(f"{dummy_file} -> {dest_file}")
|
||||
with open(dummy_file, 'r') as read_file, open(dest_file, 'w') as write_file:
|
||||
write_file.write("#include blogstart.html\n")
|
||||
|
||||
# modify the basic html to make it nicer for styling later
|
||||
html = read_file.read()
|
||||
|
||||
# extract images from their enclosing <p> tags and put them in img panels
|
||||
html = re.sub('(<p>(<img(?:.+)/>)</p>)', r'<div class="img-panel">\2</div>', html)
|
||||
|
||||
# insert text-panel start between non-<p> and <p> elements
|
||||
html = re.sub('((?<!</p>)\n)(<p>)', r'\1<div class="text-panel">\n\2', html)
|
||||
# insert para-block end between <p> and non-<p> elements
|
||||
html = re.sub('(</p>\n)((?!<p>))', r'\1</div>\n\2', html)
|
||||
|
||||
# insert code-panel start before <pre> elements
|
||||
html = re.sub('(<pre>)', r'<div class="code-panel">\n\1', html)
|
||||
# insert code-panel end after </pre> elements
|
||||
html = re.sub('(</pre>)', r'\1\n</div>', html)
|
||||
|
||||
# replace horizontal rules with nice separator dot
|
||||
html = re.sub('<hr />', r'<div class="separator"></div>', html)
|
||||
|
||||
lines = html.split("\n")
|
||||
|
||||
# tack on a closing div because we will have opened one without closing it on the final <p>
|
||||
lines.append("</div>")
|
||||
|
||||
for line in lines:
|
||||
write_file.write(line + "\n")
|
||||
|
||||
write_file.write("\n#include blogend.html\n")
|
||||
|
||||
os.remove(dummy_file)
|
||||
|
76
build/rss.py
Normal file
76
build/rss.py
Normal file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import markdown
|
||||
import pathlib
|
||||
import sys
|
||||
import re
|
||||
|
||||
def print_usage():
|
||||
print("\nusage: python mkblogrss.py POSTS\n")
|
||||
print("\n")
|
||||
print("\t\tPOSTS\tfilepaths of blog posts")
|
||||
|
||||
# check args for at least one file path
|
||||
if len(sys.argv) < 2:
|
||||
print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
# posts are arguments from index 1 onwards
|
||||
posts = sys.argv[1:]
|
||||
|
||||
# header and footer to enclose feed items
|
||||
header = """<?xml version="1.0" encoding="utf-8" ?>
|
||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
|
||||
<channel>
|
||||
<title>ktyl.dev</title>
|
||||
<link>https://ktyl.dev/blog/index.html</link>
|
||||
<description>mostly computer stuff!</description>
|
||||
<atom:link href="https://ktyl.dev/blog/index.xml" rel="self" type="application/rss+xml"/>
|
||||
"""
|
||||
footer = "</channel></rss>"
|
||||
|
||||
# regex patterns
|
||||
title_pattern = re.compile("<h1>(.+)</h1>")
|
||||
path_pattern = re.compile("(.+)\/(\d{4})\/(\d{1,2})\/(\d{1,2})\/(.+).md")
|
||||
|
||||
def make_item(path):
|
||||
str = "<item>\n"
|
||||
|
||||
# get the HTML version of the file
|
||||
text = ""
|
||||
with open(path) as f:
|
||||
text = f.read()
|
||||
html = markdown.markdown(text, extensions=["fenced_code"])
|
||||
|
||||
# title
|
||||
title = ""
|
||||
m = title_pattern.match(html)
|
||||
title = m.group(1)
|
||||
str += f"<title>{title}</title>\n"
|
||||
|
||||
# link
|
||||
url = "/".join(pathlib.Path(path).parts[2:])
|
||||
url = url.replace(".md", ".html")
|
||||
link = f"https://ktyl.dev/blog/{url}"
|
||||
str += f"<link>{link}</link>\n"
|
||||
|
||||
# content
|
||||
description = html
|
||||
description = re.sub('<', '<', description)
|
||||
description = re.sub('>', '>', description)
|
||||
str += f"<description>{description}</description>\n"
|
||||
|
||||
# pub date
|
||||
date = re.sub(path_pattern, r'\2-\3-\4', path)
|
||||
str += f"<pubDate>{date}</pubDate>\n"
|
||||
|
||||
str += "</item>"
|
||||
|
||||
return str
|
||||
|
||||
# print everything!
|
||||
print(header)
|
||||
for p in posts:
|
||||
print(make_item(p))
|
||||
print(footer)
|
||||
|
33
makefile
33
makefile
@ -3,21 +3,44 @@ OUT_DIR = out/
|
||||
HTML_DIR = $(OUT_DIR)html
|
||||
GEMINI_DIR = $(OUT_DIR)gemini
|
||||
|
||||
MAKE_GEMINI = build/markdown2gemini.py
|
||||
MAKE_HTML = build/markdown2html.py
|
||||
MAKE_GEMINI = build/markdown2gemini.py
|
||||
MAKE_HTML = build/page.py
|
||||
MAKE_RSS = build/rss.py
|
||||
MAKE_HTML_INDEX = build/index.py
|
||||
|
||||
PAGES = $(shell find $(SRC_DIR) -wholename "$(BLOG_SRC_DIR)*.md")
|
||||
|
||||
HTML_TARGETS = $(PAGES:$(SRC_DIR)/%.md=$(HTML_DIR)/%.html)
|
||||
HTML_RSS = $(HTML_DIR)/index.xml
|
||||
HTML_INDEX = $(HTML_DIR)/index.html
|
||||
|
||||
GEMINI_TARGETS = $(PAGES:$(SRC_DIR)/%.md=$(GEMINI_DIR)/%.gmi)
|
||||
|
||||
IMAGES = $(shell find $(SRC_DIR) -wholename "$(SRC_DIR)*.png" -o -wholename "$(SRC_DIR)*.jpg")
|
||||
PNG_TARGETS = $(IMAGES:$(SRC_DIR)/%.png=$(HTML_DIR)/%.png)
|
||||
JPG_TARGETS = $(IMAGES:$(SRC_DIR)/%.jpg=$(HTML_DIR)/%.jpg)
|
||||
IMAGE_TARGETS = $(PNG_TARGETS) $(JPG_TARGETS)
|
||||
|
||||
_dummy := $(shell mkdir -p $(HTML_DIR) $(GEMINI_DIR))
|
||||
|
||||
$(HTML_DIR)/%.html: $(SRC_DIR)/%.md
|
||||
python $(MAKE_HTML) $< $@
|
||||
pipenv run python $(MAKE_HTML) $< $@
|
||||
|
||||
html: $(HTML_TARGETS)
|
||||
echo $(HTML_TARGETS)
|
||||
$(HTML_RSS): $(PAGES)
|
||||
pipenv run python $(MAKE_RSS) $(PAGES) > $@
|
||||
|
||||
$(HTML_INDEX): $(HTML_TARGETS)
|
||||
pipenv run python $(MAKE_HTML_INDEX) $(HTML_TARGETS) > $@
|
||||
|
||||
$(HTML_DIR)/%.png: $(SRC_DIR)/%.png
|
||||
mkdir -p $(shell dirname $@)
|
||||
cp $< $@
|
||||
|
||||
$(HTML_DIR)/%.jpg: $(SRC_DIR)/%.jpg
|
||||
mkdir -p $(shell dirname $@)
|
||||
cp $< $@
|
||||
|
||||
html: $(HTML_TARGETS) $(HTML_RSS) $(HTML_INDEX) $(IMAGE_TARGETS)
|
||||
|
||||
gemini:
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user