From 886e022d231ad142ab74643221cdee492e381f54 Mon Sep 17 00:00:00 2001 From: Ludwig Lehnert Date: Mon, 21 Apr 2025 17:01:06 +0000 Subject: [PATCH] using webp for blogs now --- scripts/convert-blog | 125 ++++++++++ www/.htaccess | 2 +- www/blog.php | 106 +++++++-- www/blog/0.json | 11 - www/blog/0.svg | 2 - www/blog/1.json | 12 - www/blog/1.svg | 1 - www/blog/one/07a08c4.webp | Bin 0 -> 4998 bytes www/blog/one/09eef40.webp | Bin 0 -> 4660 bytes www/blog/one/0aea930.webp | Bin 0 -> 5690 bytes www/blog/one/15704c1.webp | Bin 0 -> 678 bytes www/blog/one/17e65d5.webp | Bin 0 -> 4860 bytes www/blog/one/1cc4eb8.webp | Bin 0 -> 4328 bytes www/blog/one/2618a28.webp | Bin 0 -> 7216 bytes www/blog/one/2f7fe30.webp | Bin 0 -> 608 bytes www/blog/one/30d5de3.webp | Bin 0 -> 2058 bytes www/blog/one/35ca008.webp | Bin 0 -> 3764 bytes www/blog/one/4d55914.webp | Bin 0 -> 11632 bytes www/blog/one/4e13630.webp | Bin 0 -> 598 bytes www/blog/one/53145df.webp | Bin 0 -> 6096 bytes www/blog/one/590f333.webp | Bin 0 -> 3110 bytes www/blog/one/5ad1430.webp | Bin 0 -> 1444 bytes www/blog/one/64a799d.webp | Bin 0 -> 606 bytes www/blog/one/717c078.webp | Bin 0 -> 8686 bytes www/blog/one/7e7a7e4.webp | Bin 0 -> 2884 bytes www/blog/one/908a399.webp | Bin 0 -> 1996 bytes www/blog/one/9c229c9.webp | Bin 0 -> 3844 bytes www/blog/one/_definition.json | 417 +++++++++++++++++++++++++++++++++ www/blog/one/a0be263.webp | Bin 0 -> 2358 bytes www/blog/one/b285770.webp | Bin 0 -> 2526 bytes www/blog/one/b55185f.webp | Bin 0 -> 1776 bytes www/blog/one/c1e1de3.webp | Bin 0 -> 696 bytes www/blog/one/c5aea0a.webp | Bin 0 -> 2008 bytes www/blog/one/ea08577.webp | Bin 0 -> 536 bytes www/blog/one/f072857.webp | Bin 0 -> 3580 bytes www/blog/one/f44e23c.webp | Bin 0 -> 638 bytes www/blog/one/f4b2484.webp | Bin 0 -> 912 bytes www/blog/one/f63dffe.webp | Bin 0 -> 7126 bytes www/blog/one/fe86e6f.webp | Bin 0 -> 2246 bytes www/blog/one/main_000.webp | Bin 0 -> 1236342 bytes www/blog/one/main_001.webp | Bin 0 -> 986388 bytes www/blog/zero/18bddb5.webp | Bin 0 -> 2740 bytes www/blog/zero/2db2951.webp | Bin 0 -> 5092 bytes www/blog/zero/60d1274.webp | Bin 0 -> 2632 bytes www/blog/zero/6a1748c.webp | Bin 0 -> 2946 bytes www/blog/zero/76c4bca.webp | Bin 0 -> 8640 bytes www/blog/zero/913fe45.webp | Bin 0 -> 11140 bytes www/blog/zero/_definition.json | 90 +++++++ www/blog/zero/main_000.webp | Bin 0 -> 352348 bytes www/error.php | 2 + www/index.php | 11 +- www/lib/blog.php | 79 ++++--- www/sitemap.php | 8 +- 53 files changed, 780 insertions(+), 86 deletions(-) create mode 100755 scripts/convert-blog delete mode 100644 www/blog/0.json delete mode 100644 www/blog/0.svg delete mode 100644 www/blog/1.json delete mode 100644 www/blog/1.svg create mode 100644 www/blog/one/07a08c4.webp create mode 100644 www/blog/one/09eef40.webp create mode 100644 www/blog/one/0aea930.webp create mode 100644 www/blog/one/15704c1.webp create mode 100644 www/blog/one/17e65d5.webp create mode 100644 www/blog/one/1cc4eb8.webp create mode 100644 www/blog/one/2618a28.webp create mode 100644 www/blog/one/2f7fe30.webp create mode 100644 www/blog/one/30d5de3.webp create mode 100644 www/blog/one/35ca008.webp create mode 100644 www/blog/one/4d55914.webp create mode 100644 www/blog/one/4e13630.webp create mode 100644 www/blog/one/53145df.webp create mode 100644 www/blog/one/590f333.webp create mode 100644 www/blog/one/5ad1430.webp create mode 100644 www/blog/one/64a799d.webp create mode 100644 www/blog/one/717c078.webp create mode 100644 www/blog/one/7e7a7e4.webp create mode 100644 www/blog/one/908a399.webp create mode 100644 www/blog/one/9c229c9.webp create mode 100644 www/blog/one/_definition.json create mode 100644 www/blog/one/a0be263.webp create mode 100644 www/blog/one/b285770.webp create mode 100644 www/blog/one/b55185f.webp create mode 100644 www/blog/one/c1e1de3.webp create mode 100644 www/blog/one/c5aea0a.webp create mode 100644 www/blog/one/ea08577.webp create mode 100644 www/blog/one/f072857.webp create mode 100644 www/blog/one/f44e23c.webp create mode 100644 www/blog/one/f4b2484.webp create mode 100644 www/blog/one/f63dffe.webp create mode 100644 www/blog/one/fe86e6f.webp create mode 100644 www/blog/one/main_000.webp create mode 100644 www/blog/one/main_001.webp create mode 100644 www/blog/zero/18bddb5.webp create mode 100644 www/blog/zero/2db2951.webp create mode 100644 www/blog/zero/60d1274.webp create mode 100644 www/blog/zero/6a1748c.webp create mode 100644 www/blog/zero/76c4bca.webp create mode 100644 www/blog/zero/913fe45.webp create mode 100644 www/blog/zero/_definition.json create mode 100644 www/blog/zero/main_000.webp diff --git a/scripts/convert-blog b/scripts/convert-blog new file mode 100755 index 0000000..4083bff --- /dev/null +++ b/scripts/convert-blog @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 + +import re +import os +import gzip +import json +import shutil +import argparse +import tempfile +import subprocess +from datetime import date +from lxml import etree as ET + +def open_blog(path: str) -> ET._Element: + with gzip.open(path, 'rt', encoding='utf-8') as f: + raw_svg = f.read() + + return ET.fromstring(raw_svg) + +def remove_by_xpath(el: ET._Element, xpath: str): + for node in el.xpath(xpath): + parent = node.getparent() + parent.remove(node) + +def tag_xpath(tag: str): + return f".//*[local-name()='{tag}']" + +def class_xpath(class_: str): + return f".//*[contains(concat(' ', normalize-space(@class), ' '), '{class_}')]" + +def save_blog(dir: str, root: ET._Element): + os.makedirs(dir, exist_ok=True) + + frame: ET._Element = root.xpath(tag_xpath('svg'))[0] + width = int(frame.attrib['width'][:-2]) + height = int(frame.attrib['height'][:-2]) + root.attrib['viewBox'] = f'0 0 {width} {height}' + + content: ET._Element = frame.getchildren()[0] + root.remove(frame) + root.append(content) + + remove_by_xpath(root, ".//*[@id='write-document']") + remove_by_xpath(root, ".//*[@id='write-defs']") + remove_by_xpath(root, ".//*[@id='write-doc-background']") + remove_by_xpath(root, class_xpath('ruleline')) + + bookmarks: list[tuple[str, float]] = [] + for node in root.xpath(class_xpath('bookmark')): + match = re.search(r"translate\([^\d\-]*([-+]?\d*\.?\d+),\s*([-+]?\d*\.?\d+)\)", node.attrib['transform']) + bookmarks.append((node.attrib['id'], float(match.group(2)))) + node.getparent().remove(node) + + hyperrefs: list[tuple[ET._Element, str, tuple[float, float], tuple[float, float]]] = [] + for node in root.xpath(class_xpath('hyperref')): + anchor = node.xpath(tag_xpath('a'))[0] + rect = anchor.xpath(tag_xpath('rect'))[0] + x, y = float(rect.attrib['x']), float(rect.attrib['y']) + w, h = float(rect.attrib['width']), float(rect.attrib['height']) + url = anchor.attrib['{http://www.w3.org/1999/xlink}href'] + hyperrefs.append((node, url, (x, y), (w, h))) + anchor.getparent().remove(anchor) + node.getparent().remove(node) + + tempdir = tempfile.mkdtemp() + + try: + with open(f'{tempdir}/main.svg', 'wb') as f: + f.write(ET.tostring(root, xml_declaration=True, encoding="utf-8")) + + subprocess.call(['magick', '-density', '300', '-background', 'none', f'{tempdir}/main.svg', f'{tempdir}/main.png']) + subprocess.call(['magick', f'{tempdir}/main.png', '-crop', 'x16383', '+repage', f'{tempdir}/main_%03d.webp']) + + main_files: list[str] = [] + for file in os.listdir(tempdir): + if file.endswith('webp'): main_files.append(file) + + url_defs: list[tuple[str, str, tuple[float, float], tuple[float, float]]] = [] + for node, url, (x, y), (w, h) in hyperrefs: + name = os.urandom(15).hex()[:7] + + svg = ET.Element('svg', attrib={'viewBox': f'{x} {y} {w} {h}'}, nsmap={None: 'http://www.w3.org/2000/svg'}) + svg.append(node) + + with open(f'{tempdir}/{name}.svg', 'wb') as f: + f.write(ET.tostring(svg, xml_declaration=True, encoding="utf-8")) + + subprocess.call(['magick', '-density', '300', '-background', 'none', f'{tempdir}/{name}.svg',f'{tempdir}/{name}.png']) + subprocess.call(['magick', f'{tempdir}/{name}.png', f'{tempdir}/{name}.webp']) + + url_defs.append((f'{name}.webp', url, (x, y), (w, h))) + + + for file in os.listdir(tempdir): + if file.endswith('webp'): + shutil.move(f'{tempdir}/{file}', f'{dir}/{file}') + + with open(f'{dir}/_definition.json', 'w') as f: + json.dump({ + 'date': date.today().strftime("%Y-%m-%d"), + 'title': 'My Cool Blog Entry', + 'keywords': ['Cool', 'Blog'], + 'bookmarks': list(map(lambda b: {'id': b[0], 'offset': b[1]}, bookmarks)), + 'urls': list(map(lambda d: {'src': d[0], 'href': d[1], 'offset': d[2], 'dimensions': d[3]}, url_defs)), + 'files': sorted(main_files), + 'dimensions': [width, height], + }, f, indent=4) + + finally: + shutil.rmtree(tempdir, ignore_errors=True) + +def parse_args(): + parser = argparse.ArgumentParser() + + parser.add_argument('--svgz', required=True, type=str) + parser.add_argument('--dir', required=True, type=str) + + return parser.parse_args() + +def main(): + args = parse_args() + save_blog(args.dir, open_blog(args.svgz)) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/www/.htaccess b/www/.htaccess index 5bc11e7..77cc464 100644 --- a/www/.htaccess +++ b/www/.htaccess @@ -31,7 +31,7 @@ RewriteRule ^(typo|admin|login|dashboard).*$ /dummy/kaffee.php [L] # Rewrite /lib/* or /blog/* to /error.php?code=404 # with 404 response code (internal rewriting) # ---------------------------------------------------- -RewriteCond %{REQUEST_URI} ^/(lib|blog)(/.*)?$ +RewriteCond %{REQUEST_URI} ^/(lib)(/.*)?$ RewriteRule ^ - [R=404,L] ErrorDocument 404 /error.php?code=404 diff --git a/www/blog.php b/www/blog.php index 072a275..d36ed78 100644 --- a/www/blog.php +++ b/www/blog.php @@ -2,22 +2,25 @@ require_once __DIR__ . '/lib/_index.php'; -$id = (int) $_GET['id']; +$id = $_GET['id']; $blog = Blog::get($id); if ($blog === null) { - http_response_code(404); - require __DIR__ . '/404.php'; + $_GET['code'] = 404; + require __DIR__ . '/error.php'; exit; } -$svgs = $blog->getSVGs(); - $rand_imprint = mt_rand() % 6; $rand_privacy = mt_rand() % 6; $rand_comments = mt_rand() % 6; $rand_send_comment = mt_rand() % 5; +function is_external_url(string $url): bool +{ + return !str_starts_with($url, '#'); +} + ?> @@ -27,11 +30,9 @@ $rand_send_comment = mt_rand() % 5; - + keywords()) ?>"> - keywords) ?>"> - - <?= $blog->title ?> + <?= $blog->title() ?>