Podcast-Feed-Typ im Verwaltungsportal

Passt Verwaltung an die Podcast-Integration im Monitor an (Commit 5127e0a):

Backend (src/routers/sources.py):
- Pydantic-Pattern von GlobalSourceCreate + GlobalSourceUpdate um
  podcast_feed erweitert
- Health-Check Feed-Validierung greift jetzt auch fuer podcast_feed
  (Podcast-Feeds sind technisch RSS/Atom)

Frontend:
- src/static/js/sources.js: TYPE_LABELS um podcast_feed ("Podcast-Feed")
  ergaenzt
- src/static/dashboard.html: Neue <option value=podcast_feed> in Filter-
  und Anlage-Dropdown

Ohne diese Anpassung waere das Anlegen von Podcast-Quellen ueber das
Verwaltungsportal nicht moeglich (422 Unprocessable Entity vom
Pydantic-Validator).
Dieser Commit ist enthalten in:
claude-dev
2026-04-18 12:22:12 +00:00
Ursprung 48c1892fea
Commit 0da66fb585
3 geänderte Dateien mit 7 neuen und 4 gelöschten Zeilen

Datei anzeigen

@@ -34,7 +34,7 @@ class GlobalSourceCreate(BaseModel):
name: str = Field(min_length=1, max_length=200) name: str = Field(min_length=1, max_length=200)
url: Optional[str] = None url: Optional[str] = None
domain: Optional[str] = None domain: Optional[str] = None
source_type: str = Field(default="rss_feed", pattern="^(rss_feed|web_source|excluded|telegram_channel)$") source_type: str = Field(default="rss_feed", pattern="^(rss_feed|web_source|excluded|telegram_channel|podcast_feed)$")
category: str = Field(default="sonstige") category: str = Field(default="sonstige")
status: str = Field(default="active", pattern="^(active|inactive)$") status: str = Field(default="active", pattern="^(active|inactive)$")
notes: Optional[str] = None notes: Optional[str] = None
@@ -44,7 +44,7 @@ class GlobalSourceUpdate(BaseModel):
name: Optional[str] = Field(default=None, max_length=200) name: Optional[str] = Field(default=None, max_length=200)
url: Optional[str] = None url: Optional[str] = None
domain: Optional[str] = None domain: Optional[str] = None
source_type: Optional[str] = Field(default=None, pattern="^(rss_feed|web_source|excluded|telegram_channel)$") source_type: Optional[str] = Field(default=None, pattern="^(rss_feed|web_source|excluded|telegram_channel|podcast_feed)$")
category: Optional[str] = None category: Optional[str] = None
status: Optional[str] = Field(default=None, pattern="^(active|inactive)$") status: Optional[str] = Field(default=None, pattern="^(active|inactive)$")
notes: Optional[str] = None notes: Optional[str] = None
@@ -597,7 +597,7 @@ async def run_health_check_stream(
"message": f"HTTP {resp.status_code} - nicht erreichbar"}) "message": f"HTTP {resp.status_code} - nicht erreichbar"})
else: else:
checks.append({"type": "reachability", "status": "ok", "message": "Erreichbar"}) checks.append({"type": "reachability", "status": "ok", "message": "Erreichbar"})
if source["source_type"] == "rss_feed": if source["source_type"] in ("rss_feed", "podcast_feed"):
text = resp.text[:20000] text = resp.text[:20000]
if "<rss" not in text and "<feed" not in text and "<channel" not in text: if "<rss" not in text and "<feed" not in text and "<channel" not in text:
checks.append({"type": "feed_validity", "status": "error", checks.append({"type": "feed_validity", "status": "error",

Datei anzeigen

@@ -299,6 +299,7 @@
<option value="rss_feed">RSS-Feed</option> <option value="rss_feed">RSS-Feed</option>
<option value="web_source">Webquelle</option> <option value="web_source">Webquelle</option>
<option value="telegram_channel">Telegram-Kanal</option> <option value="telegram_channel">Telegram-Kanal</option>
<option value="podcast_feed">Podcast-Feed</option>
</select> </select>
<select class="filter-select" id="globalFilterCategory" onchange="filterGlobalSources()"> <select class="filter-select" id="globalFilterCategory" onchange="filterGlobalSources()">
<option value="">Alle Kategorien</option> <option value="">Alle Kategorien</option>
@@ -528,6 +529,7 @@
<option value="rss_feed">RSS-Feed</option> <option value="rss_feed">RSS-Feed</option>
<option value="web_source">Webquelle</option> <option value="web_source">Webquelle</option>
<option value="telegram_channel">Telegram-Kanal</option> <option value="telegram_channel">Telegram-Kanal</option>
<option value="podcast_feed">Podcast-Feed</option>
<option value="excluded">Ausgeschlossen</option> <option value="excluded">Ausgeschlossen</option>
</select> </select>
</div> </div>

Datei anzeigen

@@ -33,6 +33,7 @@ const TYPE_LABELS = {
rss_feed: "RSS-Feed", rss_feed: "RSS-Feed",
web_source: "Webquelle", web_source: "Webquelle",
telegram_channel: "Telegram-Kanal", telegram_channel: "Telegram-Kanal",
podcast_feed: "Podcast-Feed",
excluded: "Ausgeschlossen", excluded: "Ausgeschlossen",
}; };