Beide Sites mit lokalem Font-Hosting, WebP, Build-Pipeline, SEO-Basis, HSTS, Performance-Tuning und aktualisierten Impressum/Datenschutz-Texten. Co-authored-by: Cursor <cursoragent@cursor.com>
100 lines
2.6 KiB
Python
Executable file
100 lines
2.6 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Synchronisiert head-common, Header und Footer in alle HTML-Seiten."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
VERSION = (ROOT / 'assets' / 'version.txt').read_text().strip()
|
|
HEAD_COMMON = ROOT / 'assets' / 'components' / 'head-common.html'
|
|
HEADER = ROOT / 'assets' / 'components' / 'header.html'
|
|
FOOTER = ROOT / 'assets' / 'components' / 'footer.html'
|
|
|
|
HEAD_BLOCK = re.compile(
|
|
r' <meta property="og:locale" content="de_DE" />.*?"inLanguage": "de-DE"\n \}\n </script>\n',
|
|
re.DOTALL,
|
|
)
|
|
|
|
HEADER_MOUNT = re.compile(
|
|
r' <div data-site-header></div>\n',
|
|
)
|
|
|
|
FOOTER_MOUNT = re.compile(
|
|
r' <div data-site-footer></div>\n',
|
|
)
|
|
|
|
APP_JS = re.compile(
|
|
r'<script src="\./assets/js/app\.js(?:\?v=[^"]*)?" defer></script>',
|
|
)
|
|
|
|
|
|
def indent_block(text: str, prefix: str = ' ') -> str:
|
|
lines = text.strip('\n').splitlines()
|
|
return '\n'.join(prefix + line if line.strip() else '' for line in lines) + '\n'
|
|
|
|
|
|
def build_head() -> str:
|
|
content = HEAD_COMMON.read_text()
|
|
content = content.replace('{{VERSION}}', VERSION)
|
|
return indent_block(content)
|
|
|
|
|
|
def process_html(path: Path) -> bool:
|
|
text = path.read_text()
|
|
if 'data-site-header' not in text and 'og:locale' not in text:
|
|
return False
|
|
|
|
original = text
|
|
|
|
if 'og:locale' in text:
|
|
text = HEAD_BLOCK.sub(build_head(), text, count=1)
|
|
|
|
if HEADER_MOUNT.search(text):
|
|
header = indent_block(HEADER.read_text())
|
|
text = HEADER_MOUNT.sub(header, text, count=1)
|
|
|
|
if FOOTER_MOUNT.search(text):
|
|
footer = indent_block(FOOTER.read_text())
|
|
text = FOOTER_MOUNT.sub(footer, text, count=1)
|
|
|
|
text = APP_JS.sub(
|
|
f'<script src="./assets/js/app.js?v={VERSION}" defer></script>',
|
|
text,
|
|
count=1,
|
|
)
|
|
|
|
# Alte statische Preloads + externes theme-init.js entfernen
|
|
text = re.sub(
|
|
r' <link rel="preload" as="image" href="\./assets/img/start-[^"]+\.webp"[^/]*/>\n',
|
|
'',
|
|
text,
|
|
)
|
|
text = re.sub(
|
|
r' <script src="\./assets/js/theme-init\.js"></script>\n',
|
|
'',
|
|
text,
|
|
)
|
|
|
|
if text != original:
|
|
path.write_text(text)
|
|
return True
|
|
return False
|
|
|
|
|
|
def main() -> None:
|
|
updated = []
|
|
for path in sorted(ROOT.glob('*.html')):
|
|
if process_html(path):
|
|
updated.append(path.name)
|
|
|
|
print(f'Version: {VERSION}')
|
|
for name in updated:
|
|
print(f' aktualisiert: {name}')
|
|
if not updated:
|
|
print(' keine Änderungen')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|