mirror of
https://github.com/home-assistant/core.git
synced 2026-09-29 07:28:13 +01:00
Only import Plex and Spotify in Sonos when they are set up (#183285)
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -213,3 +213,6 @@ SCAN_INTERVAL = datetime.timedelta(seconds=10)
|
||||
DISCOVERY_INTERVAL = datetime.timedelta(seconds=60)
|
||||
SUBSCRIPTION_TIMEOUT = 1200
|
||||
LONG_SERVICE_TIMEOUT = 30.0
|
||||
|
||||
# Same as the Plex integration, which is only imported when used
|
||||
PLEX_URI_SCHEME = "plex://"
|
||||
|
||||
@@ -11,7 +11,7 @@ from soco.data_structures import DidlContainer, DidlObject
|
||||
from soco.ms_data_structures import MusicServiceItem
|
||||
from soco.music_library import MusicLibrary
|
||||
|
||||
from homeassistant.components import media_source, plex, spotify
|
||||
from homeassistant.components import media_source
|
||||
from homeassistant.components.media_player import (
|
||||
BrowseError,
|
||||
BrowseMedia,
|
||||
@@ -152,18 +152,25 @@ async def async_browse_media(
|
||||
hass, media_content_id, content_filter=media_source_filter
|
||||
)
|
||||
|
||||
if plex.is_plex_media_id(media_content_id):
|
||||
return await plex.async_browse_media(
|
||||
hass, media_content_type, media_content_id, platform=DOMAIN
|
||||
)
|
||||
# Plex and Spotify are only imported once set up, as they are heavy to load
|
||||
if "plex" in hass.config.components:
|
||||
from homeassistant.components import plex # noqa: PLC0415
|
||||
|
||||
if media_content_type == "plex":
|
||||
return await plex.async_browse_media(hass, None, None, platform=DOMAIN)
|
||||
if plex.is_plex_media_id(media_content_id):
|
||||
return await plex.async_browse_media(
|
||||
hass, media_content_type, media_content_id, platform=DOMAIN
|
||||
)
|
||||
|
||||
if spotify.is_spotify_media_type(media_content_type):
|
||||
return await spotify.async_browse_media(
|
||||
hass, media_content_type, media_content_id, can_play_artist=False
|
||||
)
|
||||
if media_content_type == "plex":
|
||||
return await plex.async_browse_media(hass, None, None, platform=DOMAIN)
|
||||
|
||||
if "spotify" in hass.config.components:
|
||||
from homeassistant.components import spotify # noqa: PLC0415
|
||||
|
||||
if spotify.is_spotify_media_type(media_content_type):
|
||||
return await spotify.async_browse_media(
|
||||
hass, media_content_type, media_content_id, can_play_artist=False
|
||||
)
|
||||
|
||||
if media_content_type == "library":
|
||||
return await hass.async_add_executor_job(
|
||||
@@ -420,6 +427,8 @@ async def root_payload(
|
||||
)
|
||||
|
||||
if "spotify" in hass.config.components:
|
||||
from homeassistant.components import spotify # noqa: PLC0415
|
||||
|
||||
result = await spotify.async_browse_media(hass, None, None)
|
||||
if result.children:
|
||||
children.extend(result.children)
|
||||
|
||||
@@ -20,7 +20,7 @@ from soco.ms_data_structures import MusicServiceItem
|
||||
from sonos_websocket import CLIP_ID_KEY
|
||||
from sonos_websocket.exception import SonosWebsocketError
|
||||
|
||||
from homeassistant.components import media_source, spotify
|
||||
from homeassistant.components import media_source
|
||||
from homeassistant.components.media_player import (
|
||||
ATTR_MEDIA_ALBUM_NAME,
|
||||
ATTR_MEDIA_ANNOUNCE,
|
||||
@@ -41,10 +41,6 @@ from homeassistant.components.media_player import (
|
||||
SearchMediaQuery,
|
||||
async_process_play_media_url,
|
||||
)
|
||||
from homeassistant.components.plex import PLEX_URI_SCHEME
|
||||
from homeassistant.components.plex.services import ( # pylint: disable=home-assistant-component-root-import
|
||||
process_plex_payload,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
@@ -63,6 +59,7 @@ from .const import (
|
||||
MODELS_LINEIN_ONLY,
|
||||
MODELS_TV_ONLY,
|
||||
PLAYABLE_MEDIA_TYPES,
|
||||
PLEX_URI_SCHEME,
|
||||
SONOS_CREATE_MEDIA_PLAYER,
|
||||
SONOS_FAVORITES_UPDATED,
|
||||
SONOS_MEDIA_UPDATED,
|
||||
@@ -561,9 +558,13 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
||||
},
|
||||
)
|
||||
|
||||
if spotify.is_spotify_media_type(media_type):
|
||||
media_type = spotify.resolve_spotify_media_type(media_type)
|
||||
media_id = spotify.spotify_uri_from_media_browser_url(media_id)
|
||||
# Spotify is only imported once set up, as it is heavy to load
|
||||
if "spotify" in self.hass.config.components:
|
||||
from homeassistant.components import spotify # noqa: PLC0415
|
||||
|
||||
if spotify.is_spotify_media_type(media_type):
|
||||
media_type = spotify.resolve_spotify_media_type(media_type)
|
||||
media_id = spotify.spotify_uri_from_media_browser_url(media_id)
|
||||
|
||||
await self.hass.async_add_executor_job(
|
||||
partial(self._play_media, media_type, media_id, is_radio, **kwargs)
|
||||
@@ -586,6 +587,11 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
||||
|
||||
soco = self.coordinator.soco
|
||||
if media_id and media_id.startswith(PLEX_URI_SCHEME):
|
||||
# Runs in the executor, only load Plex when playing Plex media
|
||||
from homeassistant.components.plex.services import ( # noqa: PLC0415 # pylint: disable=home-assistant-component-root-import
|
||||
process_plex_payload,
|
||||
)
|
||||
|
||||
plex_plugin = self.speaker.plex_plugin
|
||||
result = process_plex_payload(
|
||||
self.hass, media_type, media_id, supports_playqueues=False
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Tests for the Sonos Media Browser."""
|
||||
|
||||
from functools import partial
|
||||
from unittest.mock import MagicMock, Mock
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
@@ -269,6 +269,118 @@ async def test_browse_media_root(
|
||||
assert response["result"]["children"] == snapshot
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("media_content_type", "media_content_id", "target", "expected_args", "kwargs"),
|
||||
[
|
||||
pytest.param(
|
||||
"music",
|
||||
"plex://1/2",
|
||||
"homeassistant.components.plex.async_browse_media",
|
||||
("music", "plex://1/2"),
|
||||
{"platform": "sonos"},
|
||||
id="plex_item",
|
||||
),
|
||||
pytest.param(
|
||||
"plex",
|
||||
"",
|
||||
"homeassistant.components.plex.async_browse_media",
|
||||
(None, None),
|
||||
{"platform": "sonos"},
|
||||
id="plex_root",
|
||||
),
|
||||
pytest.param(
|
||||
"spotify://library",
|
||||
"spotify://entry_id",
|
||||
"homeassistant.components.spotify.async_browse_media",
|
||||
("spotify://library", "spotify://entry_id"),
|
||||
{"can_play_artist": False},
|
||||
id="spotify",
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("soco_factory", "async_autosetup_sonos", "soco")
|
||||
async def test_browse_media_plex_spotify(
|
||||
hass: HomeAssistant,
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
media_content_type: str,
|
||||
media_content_id: str,
|
||||
target: str,
|
||||
expected_args: tuple[str | None, str | None],
|
||||
kwargs: dict[str, str | bool],
|
||||
) -> None:
|
||||
"""Test browsing is passed to Plex and Spotify when they are set up."""
|
||||
hass.config.components.update({"plex", "spotify"})
|
||||
result = BrowseMedia(
|
||||
title="Result",
|
||||
media_class=MediaClass.DIRECTORY,
|
||||
media_content_id="result",
|
||||
media_content_type="result",
|
||||
can_play=False,
|
||||
can_expand=True,
|
||||
)
|
||||
|
||||
client = await hass_ws_client()
|
||||
with patch(target, return_value=result) as mock_browse:
|
||||
await client.send_json(
|
||||
{
|
||||
"id": 1,
|
||||
"type": "media_player/browse_media",
|
||||
"entity_id": "media_player.zone_a",
|
||||
"media_content_id": media_content_id,
|
||||
"media_content_type": media_content_type,
|
||||
}
|
||||
)
|
||||
response = await client.receive_json()
|
||||
|
||||
assert response["success"]
|
||||
assert response["result"]["title"] == "Result"
|
||||
mock_browse.assert_called_once_with(hass, *expected_args, **kwargs)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("soco_factory", "async_autosetup_sonos", "soco")
|
||||
async def test_browse_media_root_spotify(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
"""Test the root includes Spotify when it is set up."""
|
||||
hass.config.components.add("spotify")
|
||||
spotify_item = BrowseMedia(
|
||||
title="Spotify",
|
||||
media_class=MediaClass.APP,
|
||||
media_content_id="spotify://entry_id",
|
||||
media_content_type="spotify://library",
|
||||
can_play=False,
|
||||
can_expand=True,
|
||||
)
|
||||
spotify_root = BrowseMedia(
|
||||
title="Spotify",
|
||||
media_class=MediaClass.APP,
|
||||
media_content_id="spotify://",
|
||||
media_content_type="spotify",
|
||||
can_play=False,
|
||||
can_expand=True,
|
||||
children=[spotify_item],
|
||||
)
|
||||
|
||||
client = await hass_ws_client()
|
||||
with patch(
|
||||
"homeassistant.components.spotify.async_browse_media",
|
||||
return_value=spotify_root,
|
||||
):
|
||||
await client.send_json(
|
||||
{
|
||||
"id": 1,
|
||||
"type": "media_player/browse_media",
|
||||
"entity_id": "media_player.zone_a",
|
||||
}
|
||||
)
|
||||
response = await client.receive_json()
|
||||
|
||||
assert response["success"]
|
||||
assert "spotify://entry_id" in [
|
||||
child["media_content_id"] for child in response["result"]["children"]
|
||||
]
|
||||
|
||||
|
||||
async def test_browse_media_library(
|
||||
hass: HomeAssistant,
|
||||
soco_factory: SoCoMockFactory,
|
||||
|
||||
@@ -537,6 +537,28 @@ async def test_play_media_share_link_add(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("soco_factory", "async_autosetup_sonos")
|
||||
async def test_play_media_spotify_media_browser_url(
|
||||
hass: HomeAssistant, soco_sharelink: MagicMock
|
||||
) -> None:
|
||||
"""Tests playing a Spotify media browser URL when Spotify is set up."""
|
||||
hass.config.components.add("spotify")
|
||||
await hass.services.async_call(
|
||||
MP_DOMAIN,
|
||||
SERVICE_PLAY_MEDIA,
|
||||
{
|
||||
ATTR_ENTITY_ID: "media_player.zone_a",
|
||||
ATTR_MEDIA_CONTENT_TYPE: "spotify://playlist",
|
||||
ATTR_MEDIA_CONTENT_ID: f"spotify://01J5TX5A0FF6G5V0QJX6HBC94T/{_share_link}",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
assert soco_sharelink.add_share_link_to_queue.call_count == 1
|
||||
assert (
|
||||
soco_sharelink.add_share_link_to_queue.call_args_list[0].args[0] == _share_link
|
||||
)
|
||||
|
||||
|
||||
async def test_play_media_share_link_next(
|
||||
hass: HomeAssistant,
|
||||
soco_factory: SoCoMockFactory,
|
||||
|
||||
Reference in New Issue
Block a user