Ctrl K
ComunidadGuías…

backend/sonarr_diagnostics.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Diagnostic/overview methods mixin for SonarrClient.

Extracted from sonarr_client.py. Groups two methods that don't touch
the core HTTP plumbing and are called from diagnostics/UI surfaces
rather than the search pipeline:

- ``extended_health_check`` — five-step diagnostic snapshot
  (connection, API version, library access, webhook status, health
  issues) used by the settings UI's per-instance health panel.
- ``get_library_info`` — flat series/episode count overview used by
  the dashboard and the integration export.

Both rely on ``self._get`` + ``self.url`` from the SonarrClient host
class; mixed in via multiple inheritance so the class location stays
at ``sonarr_client.SonarrClient`` for all test patches.
"""

import logging

logger = logging.getLogger(__name__)


class _SonarrDiagnosticsMixin:
    """Diagnostics + library-overview methods composed into SonarrClient."""

    def extended_health_check(self):
        """Extended diagnostic health check for Sonarr.

        Returns a structured dict with connection status, API version info,
        library access, webhook status, and health issues. Each sub-query
        is wrapped in try/except for graceful degradation.

        Returns:
            dict with keys: connection, api_version, library_access,
                  webhook_status, health_issues
        """
        report = {
            "connection": {"healthy": False, "message": ""},
            "api_version": {"version": "", "branch": "", "app_name": ""},
            "library_access": {"series_count": 0, "accessible": False},
            "webhook_status": {"configured": False, "sublarr_webhooks": []},
            "health_issues": [],
        }

        # 1. Connection + system status
        status = self._get("/system/status")
        if status is None:
            report["connection"]["message"] = f"Cannot connect to Sonarr at {self.url}"
            return report

        report["connection"]["healthy"] = True
        report["connection"]["message"] = "OK"

        # 2. API version info
        report["api_version"]["version"] = status.get("version", "")
        report["api_version"]["branch"] = status.get("branch", "")
        report["api_version"]["app_name"] = status.get("appName", "")

        # 3. Library access
        try:
            series = self._get("/series")
            if series is not None:
                report["library_access"]["accessible"] = True
                report["library_access"]["series_count"] = len(series)
        except Exception as exc:
            logger.debug("Extended health check: series query failed: %s", exc)

        # 4. Webhook status
        try:
            notifications = self._get("/notification")
            if notifications is not None:
                report["webhook_status"]["configured"] = True
                for notif in notifications:
                    name = str(notif.get("name", "")).lower()
                    implementation = str(notif.get("implementation", "")).lower()
                    if "sublarr" in name or "sublarr" in implementation:
                        report["webhook_status"]["sublarr_webhooks"].append(
                            {
                                "name": notif.get("name", ""),
                                "implementation": notif.get("implementation", ""),
                            }
                        )
        except Exception as exc:
            logger.debug("Extended health check: notification query failed: %s", exc)

        # 5. Health issues
        try:
            health = self._get("/health")
            if health is not None:
                for item in health:
                    report["health_issues"].append(
                        {
                            "type": item.get("type", ""),
                            "message": item.get("message", ""),
                        }
                    )
        except Exception as exc:
            logger.debug("Extended health check: health query failed: %s", exc)

        return report

    def get_library_info(self, anime_only=True):
        """Get library overview with subtitle status.

        Returns:
            list: Series with episode counts and file info
        """
        series_list = self.get_anime_series() if anime_only else self.get_series()
        result = []

        for series in series_list:
            # Sonarr v3 nests counts under "statistics"
            stats = series.get("statistics", {})
            result.append(
                {
                    "id": series.get("id"),
                    "title": series.get("title"),
                    "year": series.get("year"),
                    "seasons": stats.get("seasonCount", series.get("seasonCount", 0)),
                    "episodes": stats.get("episodeCount", series.get("episodeCount", 0)),
                    "episodes_with_files": stats.get(
                        "episodeFileCount", series.get("episodeFileCount", 0)
                    ),
                    "path": series.get("path"),
                    "poster": next(
                        (
                            img.get("remoteUrl", "")
                            for img in series.get("images", [])
                            if img.get("coverType") == "poster"
                        ),
                        "",
                    ),
                    "status": series.get("status"),
                }
            )

        return result