diff options
Diffstat (limited to 'cgit/filters')
| -rwxr-xr-x | cgit/filters/about.sh | 5 | ||||
| -rwxr-xr-x | cgit/filters/html-transform.py | 83 |
2 files changed, 88 insertions, 0 deletions
diff --git a/cgit/filters/about.sh b/cgit/filters/about.sh new file mode 100755 index 0000000..e8554b0 --- /dev/null +++ b/cgit/filters/about.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +# About content filter + +/usr/lib/cgit/filters/about-formatting.sh "$@" | /usr/lib/cgit/filters/ediblemonad/html-transform.py + diff --git a/cgit/filters/html-transform.py b/cgit/filters/html-transform.py new file mode 100755 index 0000000..9fc7aec --- /dev/null +++ b/cgit/filters/html-transform.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# Rewrite image urls in about section + +import sys +from html.parser import HTMLParser +import html +from urllib.parse import urljoin, urlparse +import re + +def is_absolute_url(url): + if not url: return False + parsed = urlparse(url) + return bool(parsed.netloc or parsed.scheme) + +def is_relative_path(url): + if not url: return False + return not url.startswith("/") and not is_absolute_url(url) + +def linkify(text, make_link): + url_pattern = r'(?<!\S)(https?://\S+?)([.,!?;:]?(?=\s|$))' + def replace(m): + url, trail = m.group(1), m.group(2) + return make_link(url) + trail + return re.sub(url_pattern, replace, text) + +class LinkRewriter(HTMLParser): + def __init__(self): + super().__init__(convert_charrefs=False) + self.output = [] + + def get_html(self): + return "".join(self.output) + + def _build_tag(self, tag, attrs, self_closing = False): + new_tag = tag + attr_map = {} + for name, value in attrs: + if name in ("href", "src") and is_relative_path(value) and not value.startswith('#'): + if tag == 'a': + value = "../" + urljoin("tree/", value) + else: + value = "../" + urljoin("plain/", value) + attr_map[name] = value + # Open in new tab + if tag == "a" and name == "href" and is_absolute_url(value): + if not 'target' in attr_map: attr_map['target'] = '_blank _parent' + if not 'rel' in attr_map: attr_map['rel'] = 'noopener' + + attr_str = "".join( + f' {name}="{html.escape(value, quote=True)}"' if value is not None else f" {name}" + for name, value in attr_map.items() + ) + return f"<{new_tag}{attr_str}{' /' if self_closing else ''}>" + + def handle_starttag(self, tag, attrs): + self.output.append(self._build_tag(tag, attrs)) + + def handle_startendtag(self, tag, attrs): + self.output.append(self._build_tag(tag, attrs, self_closing=True)) + + def handle_endtag(self, tag): + self.output.append(f"</{tag}>") + + def handle_data(self, data): + data_with_links = linkify(data, + lambda url: self._build_tag("a", [('href', url)]) + html.escape(url) + "</a>") + self.output.append(data_with_links) + + def handle_entityref(self, name): + self.output.append(f"&{name};") + + def handle_charref(self, name): + self.output.append(f"&#{name};") + + def handle_comment(self, data): + self.output.append(f"<!--{data}-->") + +html_in = sys.stdin.read() + +parser = LinkRewriter() +parser.feed(html_in) + +print(parser.get_html()) |
