diff options
| author | pablu <me@pablu.de> | 2026-09-19 14:57:17 +0200 |
|---|---|---|
| committer | pablu <me@pablu.de> | 2026-09-19 15:02:55 +0200 |
| commit | a0fc8e577e7414312ef66307497b36c393a1a582 (patch) | |
| tree | cb41b4cd7b209ba48f7d8f2f757b6debbd09bcc1 /about-filter.py | |
| parent | 1ff95d6dd3cbb9e75b0eb71a7341c278fda9f645 (diff) | |
Diffstat (limited to 'about-filter.py')
| -rw-r--r-- | about-filter.py | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/about-filter.py b/about-filter.py new file mode 100644 index 0000000..5e97bbe --- /dev/null +++ b/about-filter.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +"""Render cgit repository READMEs as safe HTML.""" + +import html +import os +import subprocess +import sys + + +MARKDOWN_EXTENSIONS = (".md", ".markdown") +CMARK_COMMAND = ( + "/usr/bin/cmark-gfm", + "--validate-utf8", + "--extension", + "table", + "--extension", + "autolink", + "--extension", + "strikethrough", + "--extension", + "tasklist", +) + +STYLE = """<style> +.markdown-body { line-height: 1.6; overflow-wrap: anywhere; } +.markdown-body img { max-width: 100%; } +.markdown-body pre { overflow-x: auto; padding: 1em; background: rgb(255 255 255 / 6%); } +.markdown-body code { padding: .15em .3em; background: rgb(255 255 255 / 8%); } +.markdown-body pre code { padding: 0; background: none; } +.markdown-body blockquote { margin-left: 0; padding-left: 1em; color: #aaa; border-left: .25em solid #555; } +.markdown-body table { display: block; max-width: 100%; overflow-x: auto; border-collapse: collapse; } +.markdown-body th, .markdown-body td { padding: .4em .8em; border: 1px solid #555; } +.markdown-body input[type="checkbox"] { margin-right: .4em; } +</style> +""" + + +def render_markdown(source: bytes) -> bytes: + """Render Markdown with cmark-gfm's safe defaults.""" + result = subprocess.run( + CMARK_COMMAND, + input=source, + stdout=subprocess.PIPE, + check=True, + ) + return result.stdout + + +def render_plain_text(source: bytes) -> bytes: + """Return arbitrary input as escaped, readable text.""" + text = source.decode("utf-8", errors="replace") + return f"<pre>{html.escape(text)}</pre>\n".encode() + + +def main() -> None: + filename = sys.argv[1] if len(sys.argv) > 1 else "" + source = sys.stdin.buffer.read() + + if os.path.splitext(filename)[1].lower() in MARKDOWN_EXTENSIONS: + rendered = render_markdown(source) + else: + rendered = render_plain_text(source) + + sys.stdout.buffer.write(STYLE.encode()) + sys.stdout.buffer.write(b'<div class="markdown-body">\n') + sys.stdout.buffer.write(rendered) + sys.stdout.buffer.write(b"</div>\n") + + +if __name__ == "__main__": + main() |
