#!/usr/bin/env python3 """ Parser fuer das "build broken" Blog-Archiv (Wayback-Downloads) -> Hugo-Content. Ziel: - Liest die heruntergeladenen web.archive.org HTML-Dateien aus einem Quellordner - Entfernt Wayback-Toolbar/Wrapper-Markup - Extrahiert Titel, Datum, Autor, Kategorie, Tags, Content-HTML und optional Kommentare - Laedt referenzierte Bilder herunter (falls online erreichbar) bzw. kopiert sie aus einem lokalen Assets-Ordner und schreibt sie nach static/images// - Konvertiert den Content nach Markdown - Schreibt content/posts/.md mit YAML-Frontmatter fuer Hugo Voraussetzungen: pip install beautifulsoup4 markdownify requests python-slugify lxml Nutzung: python parse_buildbroken_archive.py \ --source ../archive/wayback-html \ --output .. \ --download-images """ import argparse import json import re import sys import shutil from pathlib import Path from urllib.parse import urljoin, urlparse from bs4 import BeautifulSoup from markdownify import MarkdownConverter from slugify import slugify try: import requests except ImportError: requests = None class HugoConverter(MarkdownConverter): """Markdownify-Konverter, der -Tags als HTML erhaelt (statt sie zu ![](...) zu konvertieren), damit width/height und align-Klassen aus dem Original-Design nicht verloren gehen.""" def convert_img(self, el, text, parent_tags): alt = el.attrs.get("alt", "") or "" src = el.attrs.get("src", "") or "" title = el.attrs.get("title", "") or "" w = el.attrs.get("width") h = el.attrs.get("height") cls = " ".join(el.attrs.get("class") or []) attrs = [] if alt: attrs.append(f'alt="{alt}"') if title: attrs.append(f'title="{title}"') if w: attrs.append(f'width="{w}"') if h: attrs.append(f'height="{h}"') if cls: attrs.append(f'class="{cls}"') attr_str = " " + " ".join(attrs) if attrs else "" return f'' def to_md(html): return HugoConverter(heading_style="ATX").convert(html) WAYBACK_WRAPPER_IDS = ["wm-ipp-base", "wm-ipp", "donato"] WAYBACK_WRAPPER_CLASSES = ["wb-autocomplete-suggestions"] CONTENT_SELECTORS = [ ("div", {"class": "entry"}), ("div", {"class": "post"}), ("div", {"class": "entry-content"}), ("article", {}), ("div", {"id": "content"}), ] TITLE_SELECTORS = [ ("h2", {"class": "posttitle"}), ("h2", {"class": "entry-title"}), ("h1", {"class": "entry-title"}), ("h2", {}), ("title", {}), ] DATE_BADGE_SELECTORS = [ ("div", {"class": "datestamp"}), ("div", {"class": "date"}), ("span", {"class": "date"}), ] META_LINE_PATTERN = re.compile( r"(?:Geschrieben von|Posted by)\s+(?P.+?)\s+in\s+" r"(?P.*?)(?:,\s*tags:\s*(?P.*))?$", re.IGNORECASE, ) FOOTER_LINE_PATTERN = re.compile( r"Geschrieben am\s+(?P.+?)\s+um\s+(?P