#!/usr/bin/env python3
"""Inject favicon and social meta tags into existing static HTML pages."""
from __future__ import annotations
import json
import os
import re
import sys
from pathlib import Path
from generate import build_archiv_entries, log, render_template, write_text_atomic
def extract_meta(html: str, prop: str) -> str | None:
match = re.search(rf'property="{re.escape(prop)}" content="([^"]*)"', html)
return match.group(1) if match else None
def extract_name_meta(html: str, name: str) -> str | None:
match = re.search(rf'name="{re.escape(name)}" content="([^"]*)"', html)
return match.group(1) if match else None
def extract_hero_image(html: str) -> str | None:
match = re.search(r'
str:
return render_template(
"_head_common.html.j2",
{
"site_url": site_url,
"canonical_path": canonical_path,
"og_title": og_title,
"og_description": og_description,
"og_image": og_image,
},
).rstrip()
def inject_head_block(html: str, block: str) -> str:
if 'rel="icon"' in html:
return html
marker = ' bool:
html = path.read_text(encoding="utf-8")
og_title = extract_meta(html, "og:title") or extract_name_meta(html, "twitter:title")
og_description = extract_meta(html, "og:description") or extract_name_meta(html, "description")
if not og_title or not og_description:
log(f"warning: skipping {path}, missing title/description")
return False
block = render_head_block(
site_url=site_url,
canonical_path=canonical_path,
og_title=og_title,
og_description=og_description,
og_image=extract_hero_image(html),
)
updated = inject_head_block(html, block)
if updated != html:
write_text_atomic(path, updated)
log(f"patched {path}")
return True
return False
def patch_archiv_index(path: Path, site_url: str, og_image: str) -> bool:
html = path.read_text(encoding="utf-8")
og_title = "MOBEA Archiv – Unsere bisherigen Pivots"
og_description = "Jeden Tag ein neues Startup. Hier ruhen die bisherigen."
if 'property="og:title"' not in html:
html = html.replace(
'',
'\n'
f' \n'
f' ',
1,
)
block = render_head_block(
site_url=site_url,
canonical_path="/archiv/",
og_title=og_title,
og_description=og_description,
og_image=og_image,
)
updated = inject_head_block(html, block)
if updated != html:
write_text_atomic(path, updated)
log(f"patched {path}")
return True
return False
def main() -> int:
repo_root = Path(__file__).resolve().parent.parent
site_dir = Path(os.environ.get("SITE_DIR", repo_root / "public"))
data_dir = Path(os.environ.get("DATA_DIR", repo_root / "data"))
site_url = os.environ.get("SITE_URL", "https://mobea.de")
archive = json.loads((data_dir / "archive.json").read_text(encoding="utf-8"))
latest_image = next(
(
f"/img/{entry['date']}.jpg"
for entry in sorted(archive, key=lambda e: e["date"], reverse=True)
if entry.get("has_image")
),
"/og-default.jpg",
)
patched = 0
index_path = site_dir / "index.html"
if index_path.exists():
patched += patch_startup_page(index_path, "/", site_url)
archiv_dir = site_dir / "archiv"
for path in sorted(archiv_dir.glob("2026-*.html")):
patched += patch_startup_page(path, f"/archiv/{path.name}", site_url)
archiv_index = archiv_dir / "index.html"
if archiv_index.exists():
patched += patch_archiv_index(archiv_index, site_url, latest_image)
log(f"done, patched {patched} file(s)")
return 0
if __name__ == "__main__":
sys.exit(main())