From 40a4dccc2759a48cbae51d8a9a570e033c826919 Mon Sep 17 00:00:00 2001 From: Maddox Date: Sun, 3 May 2026 14:47:24 -0400 Subject: [PATCH] v0.5.4: fix Lidarr health (v1 not v3), blank line between services - LidarrClient.health() override: hits /api/v1/health. Base ArrClient uses /api/v3/health which 404s on Lidarr. - !media health output now joins service blocks with a blank line for readability. --- maubot.yaml | 2 +- media_bot/bot.py | 45 ++++++++++++++++++++-------------------- media_bot/clients/arr.py | 4 ++++ 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/maubot.yaml b/maubot.yaml index 426aa60..f016b7a 100644 --- a/maubot.yaml +++ b/maubot.yaml @@ -1,6 +1,6 @@ maubot: 0.3.1 id: com.3ddbrewery.media -version: 0.5.3 +version: 0.5.4 license: MIT modules: - media_bot diff --git a/media_bot/bot.py b/media_bot/bot.py index 0ffbdc5..ea2f1f8 100644 --- a/media_bot/bot.py +++ b/media_bot/bot.py @@ -778,59 +778,58 @@ class MediaBot(Plugin): return_exceptions=True, ) - lines: list[str] = [] + blocks: list[list[str]] = [] - # /health-style: lists of {source, message} warnings. - for label, data in (("Sonarr", sonarr_h), ("Radarr", radarr_h), ("Lidarr", lidarr_h)): + def arr_block(label: str, data) -> list[str]: if isinstance(data, Exception): - lines.append(f"**{label}:** ❌ unreachable ({data})") - continue + return [f"**{label}:** ❌ unreachable ({data})"] if not data: - lines.append(f"**{label}:** ✅ healthy") - continue - lines.append(f"**{label}:** ⚠️ {len(data)} warning(s)") + return [f"**{label}:** ✅ healthy"] + out = [f"**{label}:** ⚠️ {len(data)} warning(s)"] for h in data: src = h.get("source") or "?" msg = h.get("message") or "?" - lines.append(f" - [{src}] {msg}") + out.append(f" - [{src}] {msg}") + return out + + blocks.append(arr_block("Sonarr", sonarr_h)) + blocks.append(arr_block("Radarr", radarr_h)) + blocks.append(arr_block("Lidarr", lidarr_h)) - # Reachability + version probes. if isinstance(seerr_s, Exception): - lines.append(f"**Seerr:** ❌ unreachable ({seerr_s})") + blocks.append([f"**Seerr:** ❌ unreachable ({seerr_s})"]) else: ver = seerr_s.get("version") or "?" update = seerr_s.get("commitsBehind") tag = f" (update available, {update} behind)" if update else "" - lines.append(f"**Seerr:** ✅ v{ver}{tag}") + blocks.append([f"**Seerr:** ✅ v{ver}{tag}"]) if isinstance(emby_s, Exception): - lines.append(f"**Emby:** ❌ unreachable ({emby_s})") + blocks.append([f"**Emby:** ❌ unreachable ({emby_s})"]) else: ver = emby_s.get("Version") or "?" name = emby_s.get("ServerName") or "Emby" - lines.append(f"**Emby:** ✅ {name} v{ver}") + blocks.append([f"**Emby:** ✅ {name} v{ver}"]) - # Download clients — also surface paused state as a warning. if isinstance(nzb_s, Exception): - lines.append(f"**NZBGet:** ❌ unreachable ({nzb_s})") + blocks.append([f"**NZBGet:** ❌ unreachable ({nzb_s})"]) else: paused = nzb_s.get("DownloadPaused") or nzb_s.get("ServerStandBy") ver = nzb_s.get("Version") or "?" - if paused: - lines.append(f"**NZBGet:** ⏸️ paused (v{ver})") - else: - lines.append(f"**NZBGet:** ✅ v{ver}") + blocks.append([ + f"**NZBGet:** ⏸️ paused (v{ver})" if paused else f"**NZBGet:** ✅ v{ver}" + ]) if isinstance(qbt_s, Exception): - lines.append(f"**qBittorrent:** ❌ unreachable ({qbt_s})") + blocks.append([f"**qBittorrent:** ❌ unreachable ({qbt_s})"]) else: conn = qbt_s.get("connection_status") or "?" # 'connected' = healthy; 'firewalled' = reachable but inbound blocked; # 'disconnected' = no peers reachable (often VPN issue). icon = {"connected": "✅", "firewalled": "⚠️"}.get(conn, "❌") - lines.append(f"**qBittorrent:** {icon} {conn}") + blocks.append([f"**qBittorrent:** {icon} {conn}"]) - await self._say(evt, "\n".join(lines)) + await self._say(evt, "\n\n".join("\n".join(b) for b in blocks)) def _arr_pct(self, q: dict) -> str: size = q.get("size") or 0 diff --git a/media_bot/clients/arr.py b/media_bot/clients/arr.py index 6e3c384..58b7182 100644 --- a/media_bot/clients/arr.py +++ b/media_bot/clients/arr.py @@ -77,6 +77,10 @@ class RadarrClient(ArrClient): class LidarrClient(ArrClient): """Lidarr API v1 — note the version difference from Sonarr/Radarr.""" + async def health(self) -> list[dict]: + data = await self._get("/api/v1/health") + return data if isinstance(data, list) else (data or []) + async def lookup(self, term: str) -> list[dict]: data = await self._get("/api/v1/artist/lookup", params={"term": term}) return data if isinstance(data, list) else (data or [])