Use runtime_data instead of hass.data for Jellyfin (#122410)
* Use runtime_data instead of hass.data * Process reviewpull/122693/head
parent
6dd43be6ac
commit
99aa68c93f
|
@ -12,11 +12,11 @@ from .const import CONF_CLIENT_DEVICE_ID, DOMAIN, PLATFORMS
|
|||
from .coordinator import JellyfinDataUpdateCoordinator, SessionsDataUpdateCoordinator
|
||||
from .models import JellyfinData
|
||||
|
||||
type JellyfinConfigEntry = ConfigEntry[JellyfinData]
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: JellyfinConfigEntry) -> bool:
|
||||
"""Set up Jellyfin from a config entry."""
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
|
||||
if CONF_CLIENT_DEVICE_ID not in entry.data:
|
||||
entry_data = entry.data.copy()
|
||||
entry_data[CONF_CLIENT_DEVICE_ID] = entry.entry_id
|
||||
|
@ -45,7 +45,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
for coordinator in coordinators.values():
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
hass.data[DOMAIN][entry.entry_id] = JellyfinData(
|
||||
entry.runtime_data = JellyfinData(
|
||||
client_device_id=entry.data[CONF_CLIENT_DEVICE_ID],
|
||||
jellyfin_client=client,
|
||||
coordinators=coordinators,
|
||||
|
@ -56,21 +56,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: JellyfinConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
unloaded = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
if unloaded:
|
||||
data = hass.data[DOMAIN].pop(entry.entry_id)
|
||||
data.jellyfin_client.stop()
|
||||
entry.runtime_data.jellyfin_client.stop()
|
||||
|
||||
return unloaded
|
||||
|
||||
|
||||
async def async_remove_config_entry_device(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry, device_entry: dr.DeviceEntry
|
||||
hass: HomeAssistant, config_entry: JellyfinConfigEntry, device_entry: dr.DeviceEntry
|
||||
) -> bool:
|
||||
"""Remove device from a config entry."""
|
||||
data = hass.data[DOMAIN][config_entry.entry_id]
|
||||
data = config_entry.runtime_data
|
||||
coordinator = data.coordinators["sessions"]
|
||||
|
||||
return not device_entry.identifiers.intersection(
|
||||
|
|
|
@ -9,15 +9,15 @@ from typing import Any
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import (
|
||||
ConfigEntry,
|
||||
ConfigFlow,
|
||||
ConfigFlowResult,
|
||||
OptionsFlow,
|
||||
OptionsFlowWithConfigEntry,
|
||||
)
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_URL, CONF_USERNAME
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.util.uuid import random_uuid_hex
|
||||
|
||||
from . import JellyfinConfigEntry
|
||||
from .client_wrapper import CannotConnect, InvalidAuth, create_client, validate_input
|
||||
from .const import CONF_CLIENT_DEVICE_ID, DOMAIN, SUPPORTED_AUDIO_CODECS
|
||||
|
||||
|
@ -56,7 +56,7 @@ class JellyfinConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
def __init__(self) -> None:
|
||||
"""Initialize the Jellyfin config flow."""
|
||||
self.client_device_id: str | None = None
|
||||
self.entry: ConfigEntry | None = None
|
||||
self.entry: JellyfinConfigEntry | None = None
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
|
@ -146,18 +146,16 @@ class JellyfinConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow:
|
||||
def async_get_options_flow(
|
||||
config_entry: JellyfinConfigEntry,
|
||||
) -> OptionsFlowWithConfigEntry:
|
||||
"""Create the options flow."""
|
||||
return OptionsFlowHandler(config_entry)
|
||||
|
||||
|
||||
class OptionsFlowHandler(OptionsFlow):
|
||||
class OptionsFlowHandler(OptionsFlowWithConfigEntry):
|
||||
"""Handle an option flow for jellyfin."""
|
||||
|
||||
def __init__(self, config_entry: ConfigEntry) -> None:
|
||||
"""Initialize options flow."""
|
||||
self.config_entry = config_entry
|
||||
|
||||
async def async_step_init(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
|
|
|
@ -8,7 +8,6 @@ from typing import Any, TypeVar
|
|||
|
||||
from jellyfin_apiclient_python import JellyfinClient
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
|
@ -23,8 +22,6 @@ JellyfinDataT = TypeVar(
|
|||
class JellyfinDataUpdateCoordinator(DataUpdateCoordinator[JellyfinDataT], ABC):
|
||||
"""Data update coordinator for the Jellyfin integration."""
|
||||
|
||||
config_entry: ConfigEntry
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
|
|
|
@ -5,21 +5,19 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from homeassistant.components.diagnostics import async_redact_data
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_PASSWORD
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import DOMAIN
|
||||
from .models import JellyfinData
|
||||
from . import JellyfinConfigEntry
|
||||
|
||||
TO_REDACT = {CONF_PASSWORD}
|
||||
|
||||
|
||||
async def async_get_config_entry_diagnostics(
|
||||
hass: HomeAssistant, entry: ConfigEntry
|
||||
hass: HomeAssistant, entry: JellyfinConfigEntry
|
||||
) -> dict[str, Any]:
|
||||
"""Return diagnostics for a config entry."""
|
||||
data: JellyfinData = hass.data[DOMAIN][entry.entry_id]
|
||||
data = entry.runtime_data
|
||||
sessions = data.coordinators["sessions"]
|
||||
|
||||
return {
|
||||
|
|
|
@ -12,27 +12,26 @@ from homeassistant.components.media_player import (
|
|||
MediaType,
|
||||
)
|
||||
from homeassistant.components.media_player.browse_media import BrowseMedia
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util.dt import parse_datetime
|
||||
|
||||
from . import JellyfinConfigEntry
|
||||
from .browse_media import build_item_response, build_root_response
|
||||
from .client_wrapper import get_artwork_url
|
||||
from .const import CONTENT_TYPE_MAP, DOMAIN, LOGGER
|
||||
from .coordinator import JellyfinDataUpdateCoordinator
|
||||
from .entity import JellyfinEntity
|
||||
from .models import JellyfinData
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
entry: JellyfinConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Jellyfin media_player from a config entry."""
|
||||
jellyfin_data: JellyfinData = hass.data[DOMAIN][entry.entry_id]
|
||||
jellyfin_data = entry.runtime_data
|
||||
coordinator = jellyfin_data.coordinators["sessions"]
|
||||
|
||||
@callback
|
||||
|
|
|
@ -17,9 +17,9 @@ from homeassistant.components.media_source.models import (
|
|||
MediaSourceItem,
|
||||
PlayMedia,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import JellyfinConfigEntry
|
||||
from .const import (
|
||||
COLLECTION_TYPE_MOVIES,
|
||||
COLLECTION_TYPE_MUSIC,
|
||||
|
@ -48,7 +48,6 @@ from .const import (
|
|||
PLAYABLE_ITEM_TYPES,
|
||||
SUPPORTED_COLLECTION_TYPES,
|
||||
)
|
||||
from .models import JellyfinData
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -56,8 +55,8 @@ _LOGGER = logging.getLogger(__name__)
|
|||
async def async_get_media_source(hass: HomeAssistant) -> MediaSource:
|
||||
"""Set up Jellyfin media source."""
|
||||
# Currently only a single Jellyfin server is supported
|
||||
entry = hass.config_entries.async_entries(DOMAIN)[0]
|
||||
jellyfin_data: JellyfinData = hass.data[DOMAIN][entry.entry_id]
|
||||
entry: JellyfinConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
|
||||
jellyfin_data = entry.runtime_data
|
||||
|
||||
return JellyfinSource(hass, jellyfin_data.jellyfin_client, entry)
|
||||
|
||||
|
@ -68,7 +67,7 @@ class JellyfinSource(MediaSource):
|
|||
name: str = "Jellyfin"
|
||||
|
||||
def __init__(
|
||||
self, hass: HomeAssistant, client: JellyfinClient, entry: ConfigEntry
|
||||
self, hass: HomeAssistant, client: JellyfinClient, entry: JellyfinConfigEntry
|
||||
) -> None:
|
||||
"""Initialize the Jellyfin media source."""
|
||||
super().__init__(DOMAIN)
|
||||
|
|
|
@ -6,15 +6,13 @@ from collections.abc import Callable
|
|||
from dataclasses import dataclass
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from .const import DOMAIN
|
||||
from . import JellyfinConfigEntry
|
||||
from .coordinator import JellyfinDataT
|
||||
from .entity import JellyfinEntity
|
||||
from .models import JellyfinData
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
|
@ -46,14 +44,14 @@ SENSOR_TYPES: dict[str, JellyfinSensorEntityDescription] = {
|
|||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
entry: JellyfinConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Jellyfin sensor based on a config entry."""
|
||||
jellyfin_data: JellyfinData = hass.data[DOMAIN][entry.entry_id]
|
||||
data = entry.runtime_data
|
||||
|
||||
async_add_entities(
|
||||
JellyfinSensor(jellyfin_data.coordinators[coordinator_type], description)
|
||||
JellyfinSensor(data.coordinators[coordinator_type], description)
|
||||
for coordinator_type, description in SENSOR_TYPES.items()
|
||||
)
|
||||
|
||||
|
|
|
@ -68,12 +68,10 @@ async def test_load_unload_config_entry(
|
|||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert mock_config_entry.entry_id in hass.data[DOMAIN]
|
||||
assert mock_config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
await hass.config_entries.async_unload(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert mock_config_entry.entry_id not in hass.data[DOMAIN]
|
||||
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue