88 lines
2.3 KiB
Python
88 lines
2.3 KiB
Python
|
import re
|
||
|
import sys
|
||
|
import os
|
||
|
|
||
|
def print_usage():
|
||
|
print(f"usage: python {sys.argv[0]} INPUT")
|
||
|
sys.exit(1)
|
||
|
|
||
|
argc = len(sys.argv)
|
||
|
if argc < 2:
|
||
|
print_usage()
|
||
|
|
||
|
|
||
|
def error(message):
|
||
|
print(f"error: {message}:", file=sys.stderr)
|
||
|
sys.exit(1)
|
||
|
|
||
|
|
||
|
path = sys.argv[1]
|
||
|
if not os.path.isfile(path):
|
||
|
error(f"{path} does not exist.")
|
||
|
|
||
|
|
||
|
def read_metadata(path):
|
||
|
pattern = re.compile(r"^\+{3}\n((?:.*|\n)*)\n\+{3}")
|
||
|
|
||
|
metadata = {}
|
||
|
|
||
|
with open(path) as f:
|
||
|
match = re.search(pattern, f.read())
|
||
|
if not match:
|
||
|
error(f"no metadata found at start of {path}")
|
||
|
|
||
|
lines = match.group(1).split('\n')
|
||
|
for l in lines:
|
||
|
pair = [s.strip() for s in l.split('=')]
|
||
|
metadata[pair[0]] = pair[1]
|
||
|
|
||
|
return metadata
|
||
|
|
||
|
|
||
|
def strip_metadata(path):
|
||
|
pattern = re.compile(r"(\+{3}\n(?:.*|\n)*\n\+{3})")
|
||
|
|
||
|
with open(path) as f:
|
||
|
return re.sub(pattern, "", f.read()).strip()
|
||
|
|
||
|
|
||
|
def generate_header(metadata):
|
||
|
|
||
|
if metadata is None:
|
||
|
error("no metadata, can't generate header")
|
||
|
|
||
|
# TODO: is the description meta tag length-restricted?
|
||
|
description = metadata["description"]
|
||
|
keywords = metadata["keywords"]
|
||
|
|
||
|
# if "description" or "keywords" don't exist we can't do anything: crash out
|
||
|
if description is None or keywords is None:
|
||
|
error("empty metadata parameters, can't generate header")
|
||
|
|
||
|
header = """<head>
|
||
|
<meta charset="UTF-8"/>
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0 minimum-scale=1" />
|
||
|
<meta name="description" content="{{DESCRIPTION}}" />
|
||
|
<meta name="keywords" content="{{KEYWORDS}}"/>
|
||
|
<link rel="canonical" href="https://ktyl.dev/">
|
||
|
<link rel="stylesheet" href="styles.css" />
|
||
|
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||
|
|
||
|
<script src="https://kit.fontawesome.com/ad50bb2e16.js" crossorigin="anonymous"></script>
|
||
|
</head>"""
|
||
|
header = header.replace("{{DESCRIPTION}}", description)
|
||
|
header = header.replace("{{KEYWORDS}}", keywords)
|
||
|
return header
|
||
|
|
||
|
html = strip_metadata(path)
|
||
|
metadata = read_metadata(path)
|
||
|
|
||
|
header = generate_header(metadata)
|
||
|
|
||
|
# Inject the generated <head> element between the opening <html> and <body> elements.
|
||
|
pattern = r"(<html>)(?:\n|.)*(<body>)"
|
||
|
replacement = f"\\1\\n{header}\\n\\2"
|
||
|
html = re.sub(pattern, replacement, html)
|
||
|
|
||
|
print(html)
|