Latest-Developments: Bullet-Format Name|URL statt nur Name

Problem: Pill-Link verwies auf falschen Post, weil sources_json fuer
Telegram-Kanaele viele Eintraege mit gleichem Namen aber unterschiedlichen
Post-URLs hat. Der Name-Match traf den ersten Eintrag (falschen Post).

Fix: Bullet-Format von {Name, Name} auf {Name|URL, Name|URL} erweitert.
Backend-Parser loest {M<ID>} nun zu Name|URL auf, URL kommt direkt vom
articles.source_url des belegenden Artikels. Kein sources_json-Lookup
noetig, keine Name-Kollision mehr moeglich.

Backend (analyzer.py):
- _parse_latest_developments: articles_by_id speichert (name, url) Tuple,
  Items werden als Name|URL gespeichert. Uebernommene Klammer-Items mit
  Pipe werden akzeptiert. Legacy-Items ohne Pipe bleiben als reiner Name.
- Prompt-Regel und Output-Beispiel auf {Name|URL, Name|URL} erweitert.

Frontend (components.js):
- buildPill-Aufruf vor Pipe-Split: Name und URL getrennt, wenn URL vorhanden
  wird Pseudo-src {name, url} uebergeben — eindeutiger Klicklink. Ohne URL
  Fallback auf lookupByName in sources_json (fuer Legacy-Bullets).
Dieser Commit ist enthalten in:
claude-dev
2026-04-18 23:19:02 +00:00
Ursprung 82e46792c7
Commit 34be98edaf
2 geänderte Dateien mit 64 neuen und 18 gelöschten Zeilen

Datei anzeigen

@@ -812,19 +812,29 @@ const UI = {
let pillsHtml = '';
// Primär: {Name1, Name2} am Bullet-Ende
// Primär: {Name1|URL1, Name2|URL2} oder {Name1, Name2} am Bullet-Ende
const trailing = trailingNamesRe.exec(rawBody);
if (trailing) {
rawBody = rawBody.replace(trailingNamesRe, '').trim();
const names = trailing[1].split(',').map(s => s.trim()).filter(Boolean);
const items = trailing[1].split(',').map(s => s.trim()).filter(Boolean);
const seen = new Set();
pillsHtml = names.map(name => {
const key = normalize(name);
pillsHtml = items.map(item => {
// Split am ersten Pipe: "Name|URL" → Name + URL; ohne Pipe nur Name
const pipeIdx = item.indexOf('|');
const itemName = pipeIdx >= 0 ? item.slice(0, pipeIdx).trim() : item.trim();
const itemUrl = pipeIdx >= 0 ? item.slice(pipeIdx + 1).trim() : '';
if (!itemName) return '';
const key = normalize(itemName);
if (seen.has(key)) return '';
seen.add(key);
if (/^(unbekannt|unknown|n\/a|keine)$/i.test(name)) return '';
const src = lookupByName(name);
return buildPill(src, name);
if (/^(unbekannt|unknown|n\/a|keine)$/i.test(itemName)) return '';
// Wenn URL direkt mitgeliefert wurde: eindeutiger Link, keine Kollision mit sources_json moeglich
if (itemUrl) {
return buildPill({ name: itemName, url: itemUrl }, itemName);
}
// Fallback (Legacy-Bullets ohne URL): Name-Lookup in sources_json
const src = lookupByName(itemName);
return buildPill(src, itemName);
}).filter(Boolean).join('');
}