Files
core/homeassistant/components/media_source/helper.py
T

144 lines
4.5 KiB
Python

"""Helpers for media source."""
from collections.abc import Callable
from homeassistant.components.media_player import (
BrowseError,
BrowseMedia,
SearchMedia,
SearchMediaQuery,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.frame import report_usage
from homeassistant.helpers.typing import UNDEFINED, UndefinedType
from .const import DOMAIN
from .error import UnknownMediaSource, Unresolvable
from .models import (
BrowseMediaSource,
MediaSourceItem,
PlayMedia,
RootBrowseMediaSource,
_async_get_media_source,
_async_get_media_sources,
)
async def _get_media_item(
hass: HomeAssistant, media_content_id: str | None, target_media_player: str | None
) -> MediaSourceItem:
"""Return media item."""
if media_content_id:
item = MediaSourceItem.from_uri(hass, media_content_id, target_media_player)
else:
# We default to our own domain if its only one registered
sources = await _async_get_media_sources(hass)
domain = None if len(sources) > 1 else DOMAIN
return MediaSourceItem(hass, domain, "", target_media_player)
if (
item.domain is not None
and await _async_get_media_source(hass, item.domain) is None
):
raise UnknownMediaSource(
translation_domain=DOMAIN,
translation_key="unknown_media_source",
translation_placeholders={"domain": item.domain},
)
return item
async def async_browse_media(
hass: HomeAssistant,
media_content_id: str | None,
*,
content_filter: Callable[[BrowseMedia], bool] | None = None,
) -> BrowseMediaSource | RootBrowseMediaSource:
"""Return media player browse media results."""
if DOMAIN not in hass.config.top_level_components:
raise BrowseError("Media Source not loaded")
try:
media_item = await _get_media_item(hass, media_content_id, None)
item = await media_item.async_browse()
except ValueError as err:
raise BrowseError(
translation_domain=DOMAIN,
translation_key="browse_media_failed",
translation_placeholders={
"media_content_id": str(media_content_id),
"error": str(err),
},
) from err
if content_filter is None or item.children is None:
return item
old_count = len(item.children)
item.children = [
child for child in item.children if child.can_expand or content_filter(child)
]
item.not_shown += old_count - len(item.children)
return item
async def async_search_media(
hass: HomeAssistant,
media_content_id: str | None,
query: SearchMediaQuery,
) -> SearchMedia:
"""Return media searched in the media source."""
if DOMAIN not in hass.config.top_level_components:
raise BrowseError("Media Source not loaded")
try:
media_item = await _get_media_item(hass, media_content_id, None)
return await media_item.async_search(query)
except NotImplementedError as err:
raise BrowseError(
translation_domain=DOMAIN,
translation_key="search_not_supported",
translation_placeholders={"media_content_id": str(media_content_id)},
) from err
except ValueError as err:
raise BrowseError(
translation_domain=DOMAIN,
translation_key="search_media_failed",
translation_placeholders={
"media_content_id": str(media_content_id),
"error": str(err),
},
) from err
async def async_resolve_media(
hass: HomeAssistant,
media_content_id: str,
target_media_player: str | UndefinedType | None = UNDEFINED,
) -> PlayMedia:
"""Get info to play media."""
if DOMAIN not in hass.config.top_level_components:
raise Unresolvable("Media Source not loaded")
if target_media_player is UNDEFINED:
report_usage(
"calls media_source.async_resolve_media without passing an entity_id",
exclude_integrations={DOMAIN},
)
target_media_player = None
try:
item = await _get_media_item(hass, media_content_id, target_media_player)
except ValueError as err:
raise Unresolvable(
translation_domain=DOMAIN,
translation_key="resolve_media_failed",
translation_placeholders={
"media_content_id": str(media_content_id),
"error": str(err),
},
) from err
return await item.async_resolve()