summaryrefslogtreecommitdiff
path: root/about-filter.py
diff options
context:
space:
mode:
authorpablu <me@pablu.de>2026-09-19 14:57:17 +0200
committerpablu <me@pablu.de>2026-09-19 15:02:55 +0200
commita0fc8e577e7414312ef66307497b36c393a1a582 (patch)
treecb41b4cd7b209ba48f7d8f2f757b6debbd09bcc1 /about-filter.py
parent1ff95d6dd3cbb9e75b0eb71a7341c278fda9f645 (diff)
feat: markdown about renderHEADmain
Diffstat (limited to 'about-filter.py')
-rw-r--r--about-filter.py72
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()