mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 04:07:08 +00:00
Handle not found playlists in Spotify (#132033)
* Handle not found playlists * Handle not found playlists * Handle not found playlists * Handle not found playlists * Handle not found playlists * Update homeassistant/components/spotify/coordinator.py --------- Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
b6458ff9b8
commit
782fff198c
@ -11,6 +11,7 @@ from spotifyaio import (
|
|||||||
Playlist,
|
Playlist,
|
||||||
SpotifyClient,
|
SpotifyClient,
|
||||||
SpotifyConnectionError,
|
SpotifyConnectionError,
|
||||||
|
SpotifyNotFoundError,
|
||||||
UserProfile,
|
UserProfile,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -62,6 +63,7 @@ class SpotifyCoordinator(DataUpdateCoordinator[SpotifyCoordinatorData]):
|
|||||||
)
|
)
|
||||||
self.client = client
|
self.client = client
|
||||||
self._playlist: Playlist | None = None
|
self._playlist: Playlist | None = None
|
||||||
|
self._checked_playlist_id: str | None = None
|
||||||
|
|
||||||
async def _async_setup(self) -> None:
|
async def _async_setup(self) -> None:
|
||||||
"""Set up the coordinator."""
|
"""Set up the coordinator."""
|
||||||
@ -87,15 +89,29 @@ class SpotifyCoordinator(DataUpdateCoordinator[SpotifyCoordinatorData]):
|
|||||||
|
|
||||||
dj_playlist = False
|
dj_playlist = False
|
||||||
if (context := current.context) is not None:
|
if (context := current.context) is not None:
|
||||||
if self._playlist is None or self._playlist.uri != context.uri:
|
dj_playlist = context.uri == SPOTIFY_DJ_PLAYLIST_URI
|
||||||
|
if not (
|
||||||
|
context.uri
|
||||||
|
in (
|
||||||
|
self._checked_playlist_id,
|
||||||
|
SPOTIFY_DJ_PLAYLIST_URI,
|
||||||
|
)
|
||||||
|
or (self._playlist is None and context.uri == self._checked_playlist_id)
|
||||||
|
):
|
||||||
|
self._checked_playlist_id = context.uri
|
||||||
self._playlist = None
|
self._playlist = None
|
||||||
if context.uri == SPOTIFY_DJ_PLAYLIST_URI:
|
if context.context_type == ContextType.PLAYLIST:
|
||||||
dj_playlist = True
|
|
||||||
elif context.context_type == ContextType.PLAYLIST:
|
|
||||||
# Make sure any playlist lookups don't break the current
|
# Make sure any playlist lookups don't break the current
|
||||||
# playback state update
|
# playback state update
|
||||||
try:
|
try:
|
||||||
self._playlist = await self.client.get_playlist(context.uri)
|
self._playlist = await self.client.get_playlist(context.uri)
|
||||||
|
except SpotifyNotFoundError:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Spotify playlist '%s' not found. "
|
||||||
|
"Most likely a Spotify-created playlist",
|
||||||
|
context.uri,
|
||||||
|
)
|
||||||
|
self._playlist = None
|
||||||
except SpotifyConnectionError:
|
except SpotifyConnectionError:
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Unable to load spotify playlist '%s'. "
|
"Unable to load spotify playlist '%s'. "
|
||||||
@ -103,6 +119,7 @@ class SpotifyCoordinator(DataUpdateCoordinator[SpotifyCoordinatorData]):
|
|||||||
context.uri,
|
context.uri,
|
||||||
)
|
)
|
||||||
self._playlist = None
|
self._playlist = None
|
||||||
|
self._checked_playlist_id = None
|
||||||
return SpotifyCoordinatorData(
|
return SpotifyCoordinatorData(
|
||||||
current_playback=current,
|
current_playback=current,
|
||||||
position_updated_at=position_updated_at,
|
position_updated_at=position_updated_at,
|
||||||
|
@ -10,6 +10,7 @@ from spotifyaio import (
|
|||||||
ProductType,
|
ProductType,
|
||||||
RepeatMode as SpotifyRepeatMode,
|
RepeatMode as SpotifyRepeatMode,
|
||||||
SpotifyConnectionError,
|
SpotifyConnectionError,
|
||||||
|
SpotifyNotFoundError,
|
||||||
)
|
)
|
||||||
from syrupy import SnapshotAssertion
|
from syrupy import SnapshotAssertion
|
||||||
|
|
||||||
@ -142,6 +143,7 @@ async def test_spotify_dj_list(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_spotify: MagicMock,
|
mock_spotify: MagicMock,
|
||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the Spotify entities with a Spotify DJ playlist."""
|
"""Test the Spotify entities with a Spotify DJ playlist."""
|
||||||
mock_spotify.return_value.get_playback.return_value.context.uri = (
|
mock_spotify.return_value.get_playback.return_value.context.uri = (
|
||||||
@ -152,12 +154,67 @@ async def test_spotify_dj_list(
|
|||||||
assert state
|
assert state
|
||||||
assert state.attributes["media_playlist"] == "DJ"
|
assert state.attributes["media_playlist"] == "DJ"
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playlist.assert_not_called()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=30))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("media_player.spotify_spotify_1")
|
||||||
|
assert state
|
||||||
|
assert state.attributes["media_playlist"] == "DJ"
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playlist.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("setup_credentials")
|
||||||
|
async def test_normal_playlist(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_spotify: MagicMock,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test normal playlist switching."""
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
state = hass.states.get("media_player.spotify_spotify_1")
|
||||||
|
assert state
|
||||||
|
assert state.attributes["media_playlist"] == "Spotify Web API Testing playlist"
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playlist.assert_called_once_with(
|
||||||
|
"spotify:user:rushofficial:playlist:2r35vbe6hHl6yDSMfjKgmm"
|
||||||
|
)
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=30))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("media_player.spotify_spotify_1")
|
||||||
|
assert state
|
||||||
|
assert state.attributes["media_playlist"] == "Spotify Web API Testing playlist"
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playlist.assert_called_once_with(
|
||||||
|
"spotify:user:rushofficial:playlist:2r35vbe6hHl6yDSMfjKgmm"
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.return_value.context.uri = (
|
||||||
|
"spotify:playlist:123123123123123"
|
||||||
|
)
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=30))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playlist.assert_called_with(
|
||||||
|
"spotify:playlist:123123123123123"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("setup_credentials")
|
@pytest.mark.usefixtures("setup_credentials")
|
||||||
async def test_fetching_playlist_does_not_fail(
|
async def test_fetching_playlist_does_not_fail(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_spotify: MagicMock,
|
mock_spotify: MagicMock,
|
||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test failing fetching playlist does not fail update."""
|
"""Test failing fetching playlist does not fail update."""
|
||||||
mock_spotify.return_value.get_playlist.side_effect = SpotifyConnectionError
|
mock_spotify.return_value.get_playlist.side_effect = SpotifyConnectionError
|
||||||
@ -166,6 +223,42 @@ async def test_fetching_playlist_does_not_fail(
|
|||||||
assert state
|
assert state
|
||||||
assert "media_playlist" not in state.attributes
|
assert "media_playlist" not in state.attributes
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playlist.assert_called_once()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=30))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert mock_spotify.return_value.get_playlist.call_count == 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("setup_credentials")
|
||||||
|
async def test_fetching_playlist_once(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_spotify: MagicMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
) -> None:
|
||||||
|
"""Test that not being able to find a playlist doesn't retry."""
|
||||||
|
mock_spotify.return_value.get_playlist.side_effect = SpotifyNotFoundError
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
state = hass.states.get("media_player.spotify_spotify_1")
|
||||||
|
assert state
|
||||||
|
assert "media_playlist" not in state.attributes
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playlist.assert_called_once()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=30))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("media_player.spotify_spotify_1")
|
||||||
|
assert state
|
||||||
|
assert "media_playlist" not in state.attributes
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playlist.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("setup_credentials")
|
@pytest.mark.usefixtures("setup_credentials")
|
||||||
async def test_idle(
|
async def test_idle(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user