#!/bin/bash # verify_article.sh — Prüft Artikel-HTML auf Einhaltung aller redaktionellen Standards # Usage: ./verify_article.sh # Exit 0 = alle Checks bestanden, Exit 1 = Fehler gefunden # # Aufruf aus Cronjobs: bash /home/hermes/workspace/verify_article.sh /home/hermes/workspace/artikel_*.html set -euo pipefail FILE="${1:-}" ERRORS=0 WARNINGS=0 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color 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: Exactly one read-more ────────────────────────────────── # Nur echte HTML-Tags zählen, nicht <hr...> Referenzen in QC-Zeilen READMORE_COUNT=$(grep -c '
gefunden" else fail "Read-More: $READMORE_COUNT Stück (muss genau 1 sein)" fi # ── CHECK 2: No
immediately after read-more ──────────────────── if grep -A1 'system-readmore' "$FILE" | grep -q ' direkt nach Read-More (erzeugt doppelte Linie)" else ok "Kein
nach Read-More" fi # ── CHECK 3: p.meta not div.meta ──────────────────────────────────── if grep -q '
' "$FILE"; then fail "
statt

(article_server regex schlägt fehl)" else ok "

korrekt" fi # ── CHECK 4: No emojis in article body (QC line excluded) ────────── # Extract body between

and
, strip everything from QC line onward BODY=$(sed -n '/
/,/<\/article>/p' "$FILE" | sed '/

/,$d') if echo "$BODY" | python3 -c "import sys,re; t=sys.stdin.read(); sys.exit(0 if re.search(r'[\U0001F300-\U0001F9FF\U00002600-\U000027BF\U0001F600-\U0001F64F]',t) else 1)"; then fail "Emojis im Artikel-Body gefunden" else ok "Keine Emojis" fi # ── CHECK 5: File ends with ───────────────────────────────── LAST_LINE=$(tail -1 "$FILE") if echo "$LAST_LINE" | grep -q ''; then ok "Datei endet mit " else fail "Letzte Zeile ist nicht (Fremd-Content nach Artikel-Ende?)" fi # ── CHECK 6: No meta-line in body (title, date, reading time) ─────── if echo "$BODY" | grep -qP ']*>.*\d{1,2}\.\s+\w+\s+\d{4}.*·.*Lesezeit'; then fail "Meta-Zeile im Body (Datum · Lesezeit) — macht Article-Server selbst!" fi # ── CHECK 7: Sources heading uses span-strong, not h2 ─────────────── if echo "$BODY" | grep -q '

Quellen

'; then fail "

Quellen

statt Quellen" else ok "Quellen-Überschrift korrekt (kein

)" fi # ── CHECK 8: All links have target="_blank" ───────────────────────── LINKS_TOTAL=$(echo "$BODY" | grep -o ' ──────────────────── QC_COUNT=$(echo "$BODY" | grep -c 'class="qc"' || true) QC_RAW=$(echo "$BODY" | grep -cP 'QC:\s*[✓✔]' || true) if [ "$QC_RAW" -gt "$QC_COUNT" ]; then fail "QC-Hinweis nicht in

(wird nicht gestrippt)" else ok "QC-Zeile korrekt in

" fi # ── CHECK 11: Autoren gegen BGG verifizieren ───────────────────────── echo "" echo "--- BGG Autoren-Faktencheck ---" AUTHOR_CHECK=$(python3 /home/hermes/workspace/check_authors.py "$FILE" 2>&1) AUTHOR_EXIT=$? echo "$AUTHOR_CHECK" if [ $AUTHOR_EXIT -eq 1 ]; then ERRORS=$((ERRORS + 1)) elif [ $AUTHOR_EXIT -eq 2 ]; then WARNINGS=$((WARNINGS + 1)) fi # ── CHECK 12: Keine XML-API-Referenzen im Artikel ────────────────── if echo "$BODY" | grep -qiP 'xml\s*api|XMLAPI|xmlapi|betriebsgeheimnis'; then fail "XML-API-Referenz oder 'Betriebsgeheimnis' im Artikel (nicht leser-tauglich)" else ok "Keine XML-API-Referenzen" fi # ── CHECK 13: Quellen-Block muss klickbare Links enthalten ────────── # Sucht Quellen-Überschrift (h2, span, strong) und prüft ob danach Links kommen SOURCES_SECTION=$(echo "$BODY" | sed -n '/

Quellen<\/h2>/,$p; /.*Quellen.*<\/span>/,$p' || echo "") if [ -n "$SOURCES_SECTION" ]; then SOURCE_LINKS=$(echo "$SOURCES_SECTION" | grep -c '-Absatz (nach

) # MUSS VOR dem Read-More stehen. Read-More gehört ZWISCHEN Absatz 1 und Absatz 2. READMORE_LINE=$(grep -n '


(nicht meta, nicht qc) FIRST_P=$(grep -n '^

' "$FILE" | grep -v 'class="meta"' | grep -v 'class="qc"' | head -1 | cut -d: -f1 || echo "") if [ -z "$FIRST_P" ]; then warn "Kein

-Absatz gefunden — Read-More-Position nicht prüfbar" elif [ "$FIRST_P" -lt "$READMORE_LINE" ]; then ok "Read-More NACH Absatz 1 — korrekt (Absatz Zeile $FIRST_P, Read-More Zeile $READMORE_LINE)" else fail "Read-More VOR Absatz 1 (Zeile $READMORE_LINE < $FIRST_P). Intro fehlt — Joomla zeigt leere Vorschau!" fi # ── CHECK 17: JEDE Quelle im Quellen-Block hat ───────────── # Extrahiere Quellen-Block (nach "Quellen" bis ) SRC_START=$(grep -n 'Quellen' "$FILE" | tail -1 | cut -d: -f1 || echo "") if [ -n "$SRC_START" ]; then SRC_LI=$(sed -n "$SRC_START,\$p" "$FILE" | grep -c '

  • ' || true) SRC_LINKED=$(sed -n "$SRC_START,\$p" "$FILE" | grep -c '
  • .*