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.
This commit is contained in:
Maddox 2026-05-03 14:47:24 -04:00
parent 5e3cd82145
commit 23e4fbd8d7
3 changed files with 27 additions and 24 deletions

View file

@ -1,6 +1,6 @@
maubot: 0.3.1 maubot: 0.3.1
id: com.3ddbrewery.media id: com.3ddbrewery.media
version: 0.5.3 version: 0.5.4
license: MIT license: MIT
modules: modules:
- media_bot - media_bot

View file

@ -778,59 +778,58 @@ class MediaBot(Plugin):
return_exceptions=True, return_exceptions=True,
) )
lines: list[str] = [] blocks: list[list[str]] = []
# /health-style: lists of {source, message} warnings. def arr_block(label: str, data) -> list[str]:
for label, data in (("Sonarr", sonarr_h), ("Radarr", radarr_h), ("Lidarr", lidarr_h)):
if isinstance(data, Exception): if isinstance(data, Exception):
lines.append(f"**{label}:** ❌ unreachable ({data})") return [f"**{label}:** ❌ unreachable ({data})"]
continue
if not data: if not data:
lines.append(f"**{label}:** ✅ healthy") return [f"**{label}:** ✅ healthy"]
continue out = [f"**{label}:** ⚠️ {len(data)} warning(s)"]
lines.append(f"**{label}:** ⚠️ {len(data)} warning(s)")
for h in data: for h in data:
src = h.get("source") or "?" src = h.get("source") or "?"
msg = h.get("message") 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): if isinstance(seerr_s, Exception):
lines.append(f"**Seerr:** ❌ unreachable ({seerr_s})") blocks.append([f"**Seerr:** ❌ unreachable ({seerr_s})"])
else: else:
ver = seerr_s.get("version") or "?" ver = seerr_s.get("version") or "?"
update = seerr_s.get("commitsBehind") update = seerr_s.get("commitsBehind")
tag = f" (update available, {update} behind)" if update else "" 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): if isinstance(emby_s, Exception):
lines.append(f"**Emby:** ❌ unreachable ({emby_s})") blocks.append([f"**Emby:** ❌ unreachable ({emby_s})"])
else: else:
ver = emby_s.get("Version") or "?" ver = emby_s.get("Version") or "?"
name = emby_s.get("ServerName") or "Emby" 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): if isinstance(nzb_s, Exception):
lines.append(f"**NZBGet:** ❌ unreachable ({nzb_s})") blocks.append([f"**NZBGet:** ❌ unreachable ({nzb_s})"])
else: else:
paused = nzb_s.get("DownloadPaused") or nzb_s.get("ServerStandBy") paused = nzb_s.get("DownloadPaused") or nzb_s.get("ServerStandBy")
ver = nzb_s.get("Version") or "?" ver = nzb_s.get("Version") or "?"
if paused: blocks.append([
lines.append(f"**NZBGet:** ⏸️ paused (v{ver})") f"**NZBGet:** ⏸️ paused (v{ver})" if paused else f"**NZBGet:** ✅ v{ver}"
else: ])
lines.append(f"**NZBGet:** ✅ v{ver}")
if isinstance(qbt_s, Exception): if isinstance(qbt_s, Exception):
lines.append(f"**qBittorrent:** ❌ unreachable ({qbt_s})") blocks.append([f"**qBittorrent:** ❌ unreachable ({qbt_s})"])
else: else:
conn = qbt_s.get("connection_status") or "?" conn = qbt_s.get("connection_status") or "?"
# 'connected' = healthy; 'firewalled' = reachable but inbound blocked; # 'connected' = healthy; 'firewalled' = reachable but inbound blocked;
# 'disconnected' = no peers reachable (often VPN issue). # 'disconnected' = no peers reachable (often VPN issue).
icon = {"connected": "", "firewalled": "⚠️"}.get(conn, "") 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: def _arr_pct(self, q: dict) -> str:
size = q.get("size") or 0 size = q.get("size") or 0

View file

@ -77,6 +77,10 @@ class RadarrClient(ArrClient):
class LidarrClient(ArrClient): class LidarrClient(ArrClient):
"""Lidarr API v1 — note the version difference from Sonarr/Radarr.""" """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]: async def lookup(self, term: str) -> list[dict]:
data = await self._get("/api/v1/artist/lookup", params={"term": term}) data = await self._get("/api/v1/artist/lookup", params={"term": term})
return data if isinstance(data, list) else (data or []) return data if isinstance(data, list) else (data or [])