1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-21 18:38:17 +00:00
Files
core/homeassistant/components/radarr/services.py
2026-02-04 10:16:47 +01:00

146 lines
4.4 KiB
Python

"""Define services for the Radarr integration."""
from collections.abc import Awaitable, Callable
from typing import Any, Final, cast
from aiopyarr import exceptions
import voluptuous as vol
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_URL
from homeassistant.core import HomeAssistant, ServiceCall, SupportsResponse, callback
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import selector
from .const import DOMAIN
from .coordinator import RadarrConfigEntry
from .helpers import format_movies, format_queue
# Service names
SERVICE_GET_MOVIES: Final = "get_movies"
SERVICE_GET_QUEUE: Final = "get_queue"
# Service attributes
ATTR_MOVIES: Final = "movies"
ATTR_ENTRY_ID: Final = "entry_id"
# Service parameter constants
CONF_MAX_ITEMS = "max_items"
# Default values - 0 means no limit
DEFAULT_MAX_ITEMS = 0
SERVICE_BASE_SCHEMA = vol.Schema(
{
vol.Required(ATTR_ENTRY_ID): selector.ConfigEntrySelector(
{"integration": DOMAIN}
),
}
)
SERVICE_GET_MOVIES_SCHEMA = SERVICE_BASE_SCHEMA
SERVICE_GET_QUEUE_SCHEMA = SERVICE_BASE_SCHEMA.extend(
{
vol.Optional(CONF_MAX_ITEMS, default=DEFAULT_MAX_ITEMS): vol.All(
vol.Coerce(int), vol.Range(min=0, max=500)
),
}
)
def _get_config_entry_from_service_data(call: ServiceCall) -> RadarrConfigEntry:
"""Return config entry for entry id."""
config_entry_id: str = call.data[ATTR_ENTRY_ID]
if not (entry := call.hass.config_entries.async_get_entry(config_entry_id)):
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="integration_not_found",
translation_placeholders={"target": DOMAIN},
)
if entry.state is not ConfigEntryState.LOADED:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="not_loaded",
translation_placeholders={"target": entry.title},
)
return cast(RadarrConfigEntry, entry)
async def _handle_api_errors[_T](func: Callable[[], Awaitable[_T]]) -> _T:
"""Handle API errors and raise HomeAssistantError with user-friendly messages."""
try:
return await func()
except exceptions.ArrAuthenticationException as ex:
raise HomeAssistantError("Authentication failed for Radarr") from ex
except exceptions.ArrConnectionException as ex:
raise HomeAssistantError("Failed to connect to Radarr") from ex
except exceptions.ArrException as ex:
raise HomeAssistantError(f"Radarr API error: {ex}") from ex
async def _async_get_movies(service: ServiceCall) -> dict[str, Any]:
"""Get all Radarr movies."""
entry = _get_config_entry_from_service_data(service)
api_client = entry.runtime_data.status.api_client
movies_list = await _handle_api_errors(api_client.async_get_movies)
# Get base URL from config entry for image URLs
base_url = entry.data[CONF_URL]
movies = format_movies(cast(list, movies_list), base_url)
return {
ATTR_MOVIES: movies,
}
async def _async_get_queue(service: ServiceCall) -> dict[str, Any]:
"""Get Radarr queue."""
entry = _get_config_entry_from_service_data(service)
max_items: int = service.data[CONF_MAX_ITEMS]
api_client = entry.runtime_data.status.api_client
if max_items > 0:
page_size = max_items
else:
# Get total count first, then fetch all items
queue_preview = await _handle_api_errors(
lambda: api_client.async_get_queue(page_size=1)
)
total = queue_preview.totalRecords
page_size = total if total > 0 else 1
queue = await _handle_api_errors(
lambda: api_client.async_get_queue(page_size=page_size, include_movie=True)
)
# Get base URL from config entry for image URLs
base_url = entry.data[CONF_URL]
movies = format_queue(queue, base_url)
return {ATTR_MOVIES: movies}
@callback
def async_setup_services(hass: HomeAssistant) -> None:
"""Register services for the Radarr integration."""
hass.services.async_register(
DOMAIN,
SERVICE_GET_MOVIES,
_async_get_movies,
schema=SERVICE_GET_MOVIES_SCHEMA,
supports_response=SupportsResponse.ONLY,
)
hass.services.async_register(
DOMAIN,
SERVICE_GET_QUEUE,
_async_get_queue,
schema=SERVICE_GET_QUEUE_SCHEMA,
supports_response=SupportsResponse.ONLY,
)