From aa121ebf7332087ceea77ae2b04a73a123251859 Mon Sep 17 00:00:00 2001 From: OzGav Date: Sat, 8 Jun 2024 04:34:22 +1000 Subject: [PATCH] Add previous track intent (#113222) * add previous track intent * add stop and clear playlist * Remove clear_playlist and stop * Remove clear_playlist and stop * Use extra constraints --------- Co-authored-by: Michael Hansen --- .../components/media_player/intent.py | 15 ++++++ tests/components/media_player/test_intent.py | 54 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/homeassistant/components/media_player/intent.py b/homeassistant/components/media_player/intent.py index f8b00935358..77220a87622 100644 --- a/homeassistant/components/media_player/intent.py +++ b/homeassistant/components/media_player/intent.py @@ -10,6 +10,7 @@ from homeassistant.const import ( SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY, + SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_VOLUME_SET, ) from homeassistant.core import Context, HomeAssistant, State @@ -21,6 +22,7 @@ from .const import MediaPlayerEntityFeature, MediaPlayerState INTENT_MEDIA_PAUSE = "HassMediaPause" INTENT_MEDIA_UNPAUSE = "HassMediaUnpause" INTENT_MEDIA_NEXT = "HassMediaNext" +INTENT_MEDIA_PREVIOUS = "HassMediaPrevious" INTENT_SET_VOLUME = "HassSetVolume" @@ -69,6 +71,19 @@ async def async_setup_intents(hass: HomeAssistant) -> None: platforms={DOMAIN}, ), ) + intent.async_register( + hass, + intent.ServiceIntentHandler( + INTENT_MEDIA_PREVIOUS, + DOMAIN, + SERVICE_MEDIA_PREVIOUS_TRACK, + required_domains={DOMAIN}, + required_features=MediaPlayerEntityFeature.PREVIOUS_TRACK, + required_states={MediaPlayerState.PLAYING}, + description="Replays the previous item for a media player", + platforms={DOMAIN}, + ), + ) intent.async_register( hass, intent.ServiceIntentHandler( diff --git a/tests/components/media_player/test_intent.py b/tests/components/media_player/test_intent.py index e73104eeb39..df47296d90c 100644 --- a/tests/components/media_player/test_intent.py +++ b/tests/components/media_player/test_intent.py @@ -7,6 +7,7 @@ from homeassistant.components.media_player import ( SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY, + SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_VOLUME_SET, intent as media_player_intent, ) @@ -173,6 +174,59 @@ async def test_next_media_player_intent(hass: HomeAssistant) -> None: await hass.async_block_till_done() +async def test_previous_media_player_intent(hass: HomeAssistant) -> None: + """Test HassMediaPrevious intent for media players.""" + await media_player_intent.async_setup_intents(hass) + + entity_id = f"{DOMAIN}.test_media_player" + attributes = {ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature.PREVIOUS_TRACK} + + hass.states.async_set(entity_id, STATE_PLAYING, attributes=attributes) + + calls = async_mock_service(hass, DOMAIN, SERVICE_MEDIA_PREVIOUS_TRACK) + + response = await intent.async_handle( + hass, + "test", + media_player_intent.INTENT_MEDIA_PREVIOUS, + ) + await hass.async_block_till_done() + + assert response.response_type == intent.IntentResponseType.ACTION_DONE + assert len(calls) == 1 + call = calls[0] + assert call.domain == DOMAIN + assert call.service == SERVICE_MEDIA_PREVIOUS_TRACK + assert call.data == {"entity_id": entity_id} + + # Test if not playing + hass.states.async_set(entity_id, STATE_IDLE, attributes=attributes) + + with pytest.raises(intent.MatchFailedError): + response = await intent.async_handle( + hass, + "test", + media_player_intent.INTENT_MEDIA_PREVIOUS, + ) + await hass.async_block_till_done() + + # Test feature not supported + hass.states.async_set( + entity_id, + STATE_PLAYING, + attributes={ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature(0)}, + ) + + with pytest.raises(intent.MatchFailedError): + response = await intent.async_handle( + hass, + "test", + media_player_intent.INTENT_MEDIA_PREVIOUS, + {"name": {"value": "test media player"}}, + ) + await hass.async_block_till_done() + + async def test_volume_media_player_intent(hass: HomeAssistant) -> None: """Test HassSetVolume intent for media players.""" await media_player_intent.async_setup_intents(hass)