diff --git a/homeassistant/components/roku/media_player.py b/homeassistant/components/roku/media_player.py index d4a5f656c82..96d23872dfa 100644 --- a/homeassistant/components/roku/media_player.py +++ b/homeassistant/components/roku/media_player.py @@ -22,6 +22,7 @@ from homeassistant.components.media_player.const import ( from homeassistant.const import ( STATE_HOME, STATE_IDLE, + STATE_ON, STATE_PAUSED, STATE_PLAYING, STATE_STANDBY, @@ -77,6 +78,13 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity): self._unique_id = unique_id + def _media_playback_trackable(self) -> bool: + """Detect if we have enough media data to track playback.""" + if self.coordinator.data.media is None or self.coordinator.data.media.live: + return False + + return self.coordinator.data.media.duration > 0 + @property def unique_id(self) -> str: """Return the unique ID for this entity.""" @@ -100,11 +108,13 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity): if self.coordinator.data.app.name == "Roku": return STATE_HOME - if self.coordinator.data.media and self.coordinator.data.media.paused: - return STATE_PAUSED + if self.coordinator.data.media: + if self.coordinator.data.media.paused: + return STATE_PAUSED + return STATE_PLAYING if self.coordinator.data.app.name: - return STATE_PLAYING + return STATE_ON return None @@ -170,6 +180,30 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity): return None + @property + def media_duration(self): + """Duration of current playing media in seconds.""" + if self._media_playback_trackable(): + return self.coordinator.data.media.duration + + return None + + @property + def media_position(self): + """Position of current playing media in seconds.""" + if self._media_playback_trackable(): + return self.coordinator.data.media.position + + return None + + @property + def media_position_updated_at(self): + """When was the position of the current playing media valid.""" + if self._media_playback_trackable(): + return self.coordinator.data.media.at + + return None + @property def source(self) -> str: """Return the current input source.""" diff --git a/tests/components/roku/test_media_player.py b/tests/components/roku/test_media_player.py index a05cde5a596..4df0c95ad07 100644 --- a/tests/components/roku/test_media_player.py +++ b/tests/components/roku/test_media_player.py @@ -10,6 +10,8 @@ from homeassistant.components.media_player.const import ( ATTR_MEDIA_CHANNEL, ATTR_MEDIA_CONTENT_ID, ATTR_MEDIA_CONTENT_TYPE, + ATTR_MEDIA_DURATION, + ATTR_MEDIA_POSITION, ATTR_MEDIA_TITLE, ATTR_MEDIA_VOLUME_MUTED, DOMAIN as MP_DOMAIN, @@ -43,6 +45,7 @@ from homeassistant.const import ( SERVICE_VOLUME_UP, STATE_HOME, STATE_IDLE, + STATE_ON, STATE_PAUSED, STATE_PLAYING, STATE_STANDBY, @@ -207,7 +210,7 @@ async def test_attributes_app( await setup_integration(hass, aioclient_mock, app="netflix") state = hass.states.get(MAIN_ENTITY_ID) - assert state.state == STATE_PLAYING + assert state.state == STATE_ON assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_APP assert state.attributes.get(ATTR_APP_ID) == "12" @@ -215,6 +218,23 @@ async def test_attributes_app( assert state.attributes.get(ATTR_INPUT_SOURCE) == "Netflix" +async def test_attributes_app_media_playing( + hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker +) -> None: + """Test attributes for app with playing media.""" + await setup_integration(hass, aioclient_mock, app="pluto", media_state="play") + + state = hass.states.get(MAIN_ENTITY_ID) + assert state.state == STATE_PLAYING + + assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_APP + assert state.attributes.get(ATTR_MEDIA_DURATION) == 6496 + assert state.attributes.get(ATTR_MEDIA_POSITION) == 38 + assert state.attributes.get(ATTR_APP_ID) == "74519" + assert state.attributes.get(ATTR_APP_NAME) == "Pluto TV - It's Free TV" + assert state.attributes.get(ATTR_INPUT_SOURCE) == "Pluto TV - It's Free TV" + + async def test_attributes_app_media_paused( hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker ) -> None: @@ -225,6 +245,8 @@ async def test_attributes_app_media_paused( assert state.state == STATE_PAUSED assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_APP + assert state.attributes.get(ATTR_MEDIA_DURATION) == 6496 + assert state.attributes.get(ATTR_MEDIA_POSITION) == 313 assert state.attributes.get(ATTR_APP_ID) == "74519" assert state.attributes.get(ATTR_APP_NAME) == "Pluto TV - It's Free TV" assert state.attributes.get(ATTR_INPUT_SOURCE) == "Pluto TV - It's Free TV" @@ -259,7 +281,7 @@ async def test_tv_attributes( ) state = hass.states.get(TV_ENTITY_ID) - assert state.state == STATE_PLAYING + assert state.state == STATE_ON assert state.attributes.get(ATTR_APP_ID) == "tvinput.dtv" assert state.attributes.get(ATTR_APP_NAME) == "Antenna TV"