diff --git a/article_server.py b/article_server.py
index 91b0fc9..7a6c0e8 100644
--- a/article_server.py
+++ b/article_server.py
@@ -181,13 +181,15 @@ def _get_unpublished_articles() -> list[dict]:
return articles[:50] # Max 50
SKIP_PATTERNS = [
- r'^ddg\d*\.html', r'^google', r'^bgg_(search|thread|game|price)',
+ r'^ddg\\d*\\.html', r'^google', r'^bgg_(search|thread|game|price)',
r'^bk_', r'^backerkit', r'^brave_search', r'^fb_post', r'^reddit',
r'^rp_mg', r'^rp_gladbach', r'^spiegel', r'^sportschau', r'^transfermarkt',
r'^tm_', r'^kicker', r'^brettspielbox', r'^bsg_', r'^bbb_',
r'^envyborn', r'^brettspiel_news_newsletter', r'^boardgamewire',
r'^ddg_', r'^blocked', r'^error', r'^just.a.moment',
r'^duckduckgo', r'^update.regarding',
+ r'deals', r'kennerspiele', r'kombi_deals', r'top_deals',
+ r'kinderspiele_deals', r'amazon_deals', r'amazon_primeday',
]
@@ -1435,8 +1437,11 @@ h1{color:#c0392b;}p{color:#888;}
article_body = re.sub(r'
]*>.*?
\s*', '', article_body, flags=re.DOTALL)
article_body = re.sub(r']*>.*?
\s*', '', article_body, flags=re.DOTALL)
article_body = re.sub(r']*>.*?
\s*', '', article_body, flags=re.DOTALL)
+ # ── Fallback: strip any remaining h1 or meta (edge cases) ──
+ article_body = re.sub(r']*>.*?
\s*', '', article_body, flags=re.DOTALL | re.IGNORECASE)
+ article_body = re.sub(r']*\bclass\s*=\s*"[^"]*\bmeta\b[^"]*"[^>]*>.*?
\s*', '', article_body, flags=re.DOTALL | re.IGNORECASE)
# ── Umbruch vor Überschriften (Daniel 19.06.: bessere Lesbarkeit) ──
- article_body = re.sub(r'((?:p|/div|/blockquote)>)\\s*(\\n\\3', article_body)
+ article_body = re.sub(r'((?:p|/div|/blockquote)>)\s*(\n\2', article_body)
# ── Remove
after read-more (muss NACH Umbruch-Insertion laufen!) ──
article_body = re.sub(
r'(
)\s*
\s*',
@@ -1528,9 +1533,34 @@ h1{color:#c0392b;}p{color:#888;}
fulltext = article_body.strip()
sr_match = re.search(r'
', article_body, re.IGNORECASE)
if sr_match:
- split_idx = sr_match.end()
+ split_idx = sr_match.start()
introtext = article_body[:split_idx].strip()
fulltext = article_body[split_idx:].strip()
+ # Remove the
from fulltext start
+ # (Joomla inserts its own read-more between introtext and fulltext)
+ fulltext = re.sub(r'^
\s*', '', fulltext)
+
+ # ── CSS aus in fulltext injizieren ──────────────────
+ # Problem: ', html_content, re.DOTALL)
+ if style_match:
+ style_css = style_match.group(1).strip()
+ fulltext = f'\n\n{fulltext}'
+
+ # ── target="_blank" für externe Links erzwingen ──────
+ # Daniel 24.06.: Alle externen Links müssen _blank sein,
+ # damit brettspiel-news.de nicht verlassen wird.
+ def add_target_blank(m):
+ href = m.group(1)
+ rest = m.group(2)
+ if 'brettspiel-news.de' in href:
+ return m.group(0) # interne Links unverändert
+ if 'target=' in rest:
+ return m.group(0) # hat bereits target
+ return f''
+ fulltext = re.sub(r']*)>', add_target_blank, fulltext)
+ introtext = re.sub(r']*)>', add_target_blank, introtext)
article_payload = {
"title": title,
@@ -1593,7 +1623,15 @@ h1{color:#c0392b;}p{color:#888;}
# Joomla requires relative + joomlaImage pseudo-protocol
# Format: images/Spiele/2026/file.jpg#joomlaImage://local-images/Spiele/2026/file.jpg
# image_intro braucht images/ prefix, joomlaImage NICHT
- image_intro_value = f"images/{j_img_path}#joomlaImage://local-images/{j_img_path}"
+ # ── Bild-Dimensionen erkennen (Joomla 6 braucht ?width=&height=) ──
+ try:
+ from PIL import Image
+ img_pil = Image.open(image_path)
+ iw, ih = img_pil.size
+ img_pil.close()
+ except:
+ iw, ih = 1920, 1080 # Fallback: Standard-BSN-Bildmaße
+ image_intro_value = f"images/{j_img_path}#joomlaImage://local-images/{j_img_path}?width={iw}&height={ih}"
article_payload["images"] = {
"image_intro": image_intro_value,
"image_intro_alt": title,
@@ -1679,6 +1717,7 @@ h1{color:#c0392b;}p{color:#888;}
self._json_reply(200 if published > 0 else 500, {
"ok": published > 0,
+ "error": None if published > 0 else (errors[0] if errors else "Unbekannter Fehler beim Veröffentlichen"),
"published": published,
"published_ids": published_ids,
"live_mode": allow_live,