1
Fork 0
mkdocs-site/hooks/kroki.py

94 lines
2.5 KiB
Python
Raw Normal View History

import base64
import zlib
from mkdocs.utils.cache import download_and_cache_url
from datetime import timedelta
from mkdocs.plugins import get_plugin_logger
2023-09-17 17:53:59 +01:00
from urllib.request import build_opener, install_opener, _opener
import hashlib
from functools import partial
from mkdocs.utils import write_file
import os
2023-09-15 17:41:31 +01:00
from py_svg_hush import filter_svg
from scour.scour import scourString
2023-09-15 21:41:46 +01:00
from slugify import slugify
import json
logger = get_plugin_logger("kroki")
DIAGRAM_CACHE_TIME = timedelta(days=7)
class ScourOptions:
"""
Scour takes its options as a class with attributes, because reasons
"""
remove_descriptions = True
remove_metadata = True
strip_comments = True
newlines = False
def get_kroki_diagram(source, language):
encoded_diagram = base64.urlsafe_b64encode(zlib.compress(source.encode(), 9)).decode()
2023-09-15 17:41:31 +01:00
svg = download_and_cache_url(f"https://kroki.io/{language}/svg/{encoded_diagram}", DIAGRAM_CACHE_TIME)
return scourString(filter_svg(svg), ScourOptions).encode()
def fence_div_format(site_dir, source, language, *args, attrs, **kwargs):
try:
2023-09-15 21:41:46 +01:00
title = attrs.get("title", "")
diagram = get_kroki_diagram(source, language)
2023-09-15 21:41:46 +01:00
filename = hashlib.md5(source.encode()).hexdigest()[:12] + ".svg"
2023-09-15 21:41:46 +01:00
if title:
filename = "-".join([slugify(title)[:32].rstrip("-"), filename])
image_url = f"/_gen/kroki/{filename}"
write_file(diagram, os.path.join(site_dir, image_url.removeprefix("/")))
except Exception:
logger.exception("Failed to generate diagram")
return
return f"<img src='{image_url}' alt='{title}' />"
def on_config(config):
kroki_langs = [
lang
for lang, version
in json.loads(download_and_cache_url("https://kroki.io/health", DIAGRAM_CACHE_TIME))["version"].items()
if isinstance(version, str)
]
format_kroki_diagram = partial(fence_div_format, config["site_dir"])
2023-09-15 18:05:28 +01:00
custom_fences = [
{
2023-09-15 21:14:06 +01:00
"name": diagram,
"class": diagram,
"format": format_kroki_diagram
2023-09-15 18:05:28 +01:00
}
for diagram in kroki_langs
2023-09-15 18:05:28 +01:00
]
config.mdx_configs["pymdownx.superfences"] = {
"custom_fences": custom_fences
}
return config
2023-09-17 17:53:59 +01:00
def on_startup(command, dirty):
# Override user-agent so kroki accepts it
if _opener is None:
opener = build_opener()
install_opener(opener)
else:
opener = _opener
opener.addheaders = [('User-Agent','mkdocs')]