Update Spotify state after mutation (#129607)

This commit is contained in:
Joost Lekkerkerker 2024-11-04 15:01:37 +01:00 committed by GitHub
parent 41a81cbf15
commit 02750452df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 34 additions and 2 deletions

View file

@ -2,10 +2,11 @@
from __future__ import annotations from __future__ import annotations
from collections.abc import Callable import asyncio
from collections.abc import Awaitable, Callable, Coroutine
import datetime as dt import datetime as dt
import logging import logging
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any, Concatenate
from spotifyaio import ( from spotifyaio import (
Device, Device,
@ -63,6 +64,7 @@ REPEAT_MODE_MAPPING_TO_HA = {
REPEAT_MODE_MAPPING_TO_SPOTIFY = { REPEAT_MODE_MAPPING_TO_SPOTIFY = {
value: key for key, value in REPEAT_MODE_MAPPING_TO_HA.items() value: key for key, value in REPEAT_MODE_MAPPING_TO_HA.items()
} }
AFTER_REQUEST_SLEEP = 1
async def async_setup_entry( async def async_setup_entry(
@ -93,6 +95,19 @@ def ensure_item[_R](
return wrapper return wrapper
def async_refresh_after[_T: SpotifyEntity, **_P](
func: Callable[Concatenate[_T, _P], Awaitable[None]],
) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]:
"""Define a wrapper to yield and refresh after."""
async def _async_wrap(self: _T, *args: _P.args, **kwargs: _P.kwargs) -> None:
await func(self, *args, **kwargs)
await asyncio.sleep(AFTER_REQUEST_SLEEP)
await self.coordinator.async_refresh()
return _async_wrap
class SpotifyMediaPlayer(SpotifyEntity, MediaPlayerEntity): class SpotifyMediaPlayer(SpotifyEntity, MediaPlayerEntity):
"""Representation of a Spotify controller.""" """Representation of a Spotify controller."""
@ -267,30 +282,37 @@ class SpotifyMediaPlayer(SpotifyEntity, MediaPlayerEntity):
return None return None
return REPEAT_MODE_MAPPING_TO_HA.get(self.currently_playing.repeat_mode) return REPEAT_MODE_MAPPING_TO_HA.get(self.currently_playing.repeat_mode)
@async_refresh_after
async def async_set_volume_level(self, volume: float) -> None: async def async_set_volume_level(self, volume: float) -> None:
"""Set the volume level.""" """Set the volume level."""
await self.coordinator.client.set_volume(int(volume * 100)) await self.coordinator.client.set_volume(int(volume * 100))
@async_refresh_after
async def async_media_play(self) -> None: async def async_media_play(self) -> None:
"""Start or resume playback.""" """Start or resume playback."""
await self.coordinator.client.start_playback() await self.coordinator.client.start_playback()
@async_refresh_after
async def async_media_pause(self) -> None: async def async_media_pause(self) -> None:
"""Pause playback.""" """Pause playback."""
await self.coordinator.client.pause_playback() await self.coordinator.client.pause_playback()
@async_refresh_after
async def async_media_previous_track(self) -> None: async def async_media_previous_track(self) -> None:
"""Skip to previous track.""" """Skip to previous track."""
await self.coordinator.client.previous_track() await self.coordinator.client.previous_track()
@async_refresh_after
async def async_media_next_track(self) -> None: async def async_media_next_track(self) -> None:
"""Skip to next track.""" """Skip to next track."""
await self.coordinator.client.next_track() await self.coordinator.client.next_track()
@async_refresh_after
async def async_media_seek(self, position: float) -> None: async def async_media_seek(self, position: float) -> None:
"""Send seek command.""" """Send seek command."""
await self.coordinator.client.seek_track(int(position * 1000)) await self.coordinator.client.seek_track(int(position * 1000))
@async_refresh_after
async def async_play_media( async def async_play_media(
self, media_type: MediaType | str, media_id: str, **kwargs: Any self, media_type: MediaType | str, media_id: str, **kwargs: Any
) -> None: ) -> None:
@ -334,6 +356,7 @@ class SpotifyMediaPlayer(SpotifyEntity, MediaPlayerEntity):
await self.coordinator.client.start_playback(**kwargs) await self.coordinator.client.start_playback(**kwargs)
@async_refresh_after
async def async_select_source(self, source: str) -> None: async def async_select_source(self, source: str) -> None:
"""Select playback device.""" """Select playback device."""
for device in self.devices.data: for device in self.devices.data:
@ -341,10 +364,12 @@ class SpotifyMediaPlayer(SpotifyEntity, MediaPlayerEntity):
await self.coordinator.client.transfer_playback(device.device_id) await self.coordinator.client.transfer_playback(device.device_id)
return return
@async_refresh_after
async def async_set_shuffle(self, shuffle: bool) -> None: async def async_set_shuffle(self, shuffle: bool) -> None:
"""Enable/Disable shuffle mode.""" """Enable/Disable shuffle mode."""
await self.coordinator.client.set_shuffle(state=shuffle) await self.coordinator.client.set_shuffle(state=shuffle)
@async_refresh_after
async def async_set_repeat(self, repeat: RepeatMode) -> None: async def async_set_repeat(self, repeat: RepeatMode) -> None:
"""Set repeat mode.""" """Set repeat mode."""
if repeat not in REPEAT_MODE_MAPPING_TO_SPOTIFY: if repeat not in REPEAT_MODE_MAPPING_TO_SPOTIFY:

View file

@ -84,6 +84,13 @@ async def setup_credentials(hass: HomeAssistant) -> None:
) )
@pytest.fixture(autouse=True)
async def patch_sleep() -> Generator[AsyncMock]:
"""Fixture to setup credentials."""
with patch("homeassistant.components.spotify.media_player.AFTER_REQUEST_SLEEP", 0):
yield
@pytest.fixture @pytest.fixture
def mock_spotify() -> Generator[AsyncMock]: def mock_spotify() -> Generator[AsyncMock]:
"""Mock the Spotify API.""" """Mock the Spotify API."""