#!/bin/bash # verify_article.sh — Prüft Artikel-HTML auf Einhaltung aller redaktionellen Standards # Usage: bash verify_article.sh # Exit 0 = alle Checks bestanden, Exit 1 = Fehler gefunden set -euo pipefail FILE="${1:-}" ERRORS=0 WARNINGS=0 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' ok() { echo -e "${GREEN}✅ $1${NC}"; } fail() { echo -e "${RED}❌ $1${NC}"; ERRORS=$((ERRORS+1)); } warn() { echo -e "${YELLOW}⚠️ $1${NC}"; WARNINGS=$((WARNINGS+1)); } if [ -z "$FILE" ] || [ ! -f "$FILE" ]; then echo "Usage: $0 " exit 1 fi echo "=== Verifiziere: $FILE ===" echo "" # CHECK 1: Genau 1 Read-More READMORE_COUNT=$(grep -c 'system-readmore' "$FILE" || true) if [ "$READMORE_COUNT" = "1" ]; then ok "Read-More: genau 1" elif [ "$READMORE_COUNT" = "0" ]; then fail "Read-More: KEIN
gefunden" else fail "Read-More: $READMORE_COUNT Stück (muss genau 1 sein)"; fi # CHECK 2: Kein
nach Read-More if grep -A1 'system-readmore' "$FILE" | grep -q ' direkt nach Read-More"; else ok "Kein
nach Read-More"; fi # CHECK 3: p.meta nicht div.meta if grep -q '
' "$FILE"; then fail "
statt

"; else ok "

korrekt"; fi # CHECK 4: Keine Emojis BODY=$(sed -n '/

/,/<\/article>/p' "$FILE") if echo "$BODY" | grep -qP '[\x{1F300}-\x{1F9FF}\x{2600}-\x{27BF}\x{1F600}-\x{1F64F}]'; then fail "Emojis im Artikel-Body gefunden"; else ok "Keine Emojis"; fi # CHECK 5: Endet mit LAST_LINE=$(tail -1 "$FILE") if echo "$LAST_LINE" | grep -q ''; then ok "Datei endet mit " else fail "Letzte Zeile ist nicht "; fi # CHECK 6: Meta-Zeile im Body (Warnung) if echo "$BODY" | grep -qP ']*>.*\d{1,2}\.\s+\w+\s+\d{4}.*·.*Lesezeit'; then warn "Meta-Zeile möglicherweise im Body"; fi # CHECK 7: Quellen als span-strong, nicht h2 if echo "$BODY" | grep -q '

Quellen

'; then fail "

Quellen

statt span-strong"; else ok "Quellen-Überschrift korrekt"; fi # CHECK 8: Alle Links target="_blank" LINKS_TOTAL=$(echo "$BODY" | grep -o '" else ok "QC-Zeile korrekt in

"; fi # CHECK 11: Umlaute (fix_umlauts.py) — 29.06.2026 UMLAUT_SCRIPT="$(dirname "$0")/fix_umlauts.py" if [ -f "$UMLAUT_SCRIPT" ]; then UMLAUT_OUTPUT=$(python3 "$UMLAUT_SCRIPT" "$FILE" 2>&1) if echo "$UMLAUT_OUTPUT" | grep -q "⚠"; then fail "Umlaut-Fehler gefunden. fix_umlauts.py angewandt — bitte erneut prüfen" echo "$UMLAUT_OUTPUT" | grep "⚠" | head -3 else ok "Umlaute: sauber" fi else warn "fix_umlauts.py nicht gefunden, Umlaut-Check übersprungen" fi # CHECK 12: vorbestell-box ohne Inline-Styles (10.07.2026) if echo "$BODY" | grep -qP ']*class="[^"]*vorbestell-box[^"]*"[^>]*style='; then fail "vorbestell-box hat Inline-Styles — muss clean sein (nur class=)" else ok "vorbestell-box: keine Inline-Styles"; fi # CHECK 13: bsn-facts ohne Inline-Styles (10.07.2026) if echo "$BODY" | grep -qP ']*class="[^"]*bsn-facts[^"]*"[^>]*style='; then fail "bsn-facts hat Inline-Styles — muss clean sein (nur class=)" else ok "bsn-facts: keine Inline-Styles"; fi # CHECK 14: Keine veralteten affiliate-box / dotted / cream (10.07.2026) if echo "$BODY" | grep -qP 'affiliate-box|border:[^;]*dotted|background:#f5f0eb'; then fail "Veraltete Box-Formate (affiliate-box/dotted/cream) — vorbestell-box verwenden!" else ok "Keine veralteten Box-Formate"; fi # CHECK 15: Keine strukturellen Inline-Styles im Body (10.07.2026) INLINE_DIV_COUNT=$(echo "$BODY" | grep -oP ']*style="[^"]*(?:background|border)[^"]*"' | wc -l || true) if [ "$INLINE_DIV_COUNT" -gt 0 ]; then fail "$INLINE_DIV_COUNT div(s) mit Inline-background/border — BSN-Klassen verwenden!" else ok "Keine strukturellen Inline-Styles im Body"; fi echo "" echo "═══════════════════════════════════════" if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then echo -e "${GREEN}✅ ALLE CHECKS BESTANDEN${NC}" exit 0 elif [ $ERRORS -eq 0 ]; then echo -e "${YELLOW}⚠️ $WARNINGS Warnung(en) — KEINE Fehler${NC}" exit 0 else echo -e "${RED}❌ $ERRORS Fehler, $WARNINGS Warnungen${NC}" exit 1 fi