diff --git a/homeassistant/components/directv/media_player.py b/homeassistant/components/directv/media_player.py index b93577a03d6..ec39734573b 100644 --- a/homeassistant/components/directv/media_player.py +++ b/homeassistant/components/directv/media_player.py @@ -8,6 +8,7 @@ from homeassistant.components.media_player import MediaPlayerDevice from homeassistant.components.media_player.const import ( MEDIA_TYPE_CHANNEL, MEDIA_TYPE_MOVIE, + MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, @@ -34,6 +35,8 @@ from .const import ( _LOGGER = logging.getLogger(__name__) +KNOWN_MEDIA_TYPES = [MEDIA_TYPE_MOVIE, MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW] + SUPPORT_DTV = ( SUPPORT_PAUSE | SUPPORT_TURN_ON @@ -177,8 +180,7 @@ class DIRECTVMediaPlayer(DIRECTVEntity, MediaPlayerDevice): if self._is_standby or self._program is None: return None - known_types = [MEDIA_TYPE_MOVIE, MEDIA_TYPE_TVSHOW] - if self._program.program_type in known_types: + if self._program.program_type in KNOWN_MEDIA_TYPES: return self._program.program_type return MEDIA_TYPE_MOVIE @@ -213,8 +215,27 @@ class DIRECTVMediaPlayer(DIRECTVEntity, MediaPlayerDevice): if self._is_standby or self._program is None: return None + if self.media_content_type == MEDIA_TYPE_MUSIC: + return self._program.music_title + return self._program.title + @property + def media_artist(self): + """Artist of current playing media, music track only.""" + if self._is_standby or self._program is None: + return None + + return self._program.music_artist + + @property + def media_album_name(self): + """Album name of current playing media, music track only.""" + if self._is_standby or self._program is None: + return None + + return self._program.music_album + @property def media_series_title(self): """Return the title of current episode of TV show.""" diff --git a/tests/components/directv/__init__.py b/tests/components/directv/__init__.py index d34ab0266af..6b71b1e8cfe 100644 --- a/tests/components/directv/__init__.py +++ b/tests/components/directv/__init__.py @@ -1,7 +1,7 @@ """Tests for the DirecTV component.""" from homeassistant.components.directv.const import CONF_RECEIVER_ID, DOMAIN from homeassistant.components.ssdp import ATTR_SSDP_LOCATION -from homeassistant.const import CONF_HOST, HTTP_INTERNAL_SERVER_ERROR +from homeassistant.const import CONF_HOST, HTTP_FORBIDDEN, HTTP_INTERNAL_SERVER_ERROR from homeassistant.helpers.typing import HomeAssistantType from tests.common import MockConfigEntry, load_fixture @@ -31,6 +31,13 @@ def mock_connection(aioclient_mock: AiohttpClientMocker) -> None: headers={"Content-Type": "application/json"}, ) + aioclient_mock.get( + f"http://{HOST}:8080/info/mode", + params={"clientAddr": "B01234567890"}, + text=load_fixture("directv/info-mode-standby.json"), + headers={"Content-Type": "application/json"}, + ) + aioclient_mock.get( f"http://{HOST}:8080/info/mode", params={"clientAddr": "9XXXXXXXXXX9"}, @@ -64,6 +71,21 @@ def mock_connection(aioclient_mock: AiohttpClientMocker) -> None: headers={"Content-Type": "application/json"}, ) + aioclient_mock.get( + f"http://{HOST}:8080/tv/getTuned", + params={"clientAddr": "A01234567890"}, + text=load_fixture("directv/tv-get-tuned-music.json"), + headers={"Content-Type": "application/json"}, + ) + + aioclient_mock.get( + f"http://{HOST}:8080/tv/getTuned", + params={"clientAddr": "C01234567890"}, + status=HTTP_FORBIDDEN, + text=load_fixture("directv/tv-get-tuned-restricted.json"), + headers={"Content-Type": "application/json"}, + ) + aioclient_mock.get( f"http://{HOST}:8080/tv/getTuned", text=load_fixture("directv/tv-get-tuned-movie.json"), diff --git a/tests/components/directv/test_media_player.py b/tests/components/directv/test_media_player.py index 698e6ddac31..8b428c1b708 100644 --- a/tests/components/directv/test_media_player.py +++ b/tests/components/directv/test_media_player.py @@ -13,6 +13,8 @@ from homeassistant.components.directv.media_player import ( ) from homeassistant.components.media_player.const import ( ATTR_INPUT_SOURCE, + ATTR_MEDIA_ALBUM_NAME, + ATTR_MEDIA_ARTIST, ATTR_MEDIA_CHANNEL, ATTR_MEDIA_CONTENT_ID, ATTR_MEDIA_CONTENT_TYPE, @@ -24,6 +26,7 @@ from homeassistant.components.media_player.const import ( ATTR_MEDIA_TITLE, DOMAIN as MP_DOMAIN, MEDIA_TYPE_MOVIE, + MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, SERVICE_PLAY_MEDIA, SUPPORT_NEXT_TRACK, @@ -44,6 +47,7 @@ from homeassistant.const import ( SERVICE_MEDIA_STOP, SERVICE_TURN_OFF, SERVICE_TURN_ON, + STATE_OFF, STATE_PAUSED, STATE_PLAYING, STATE_UNAVAILABLE, @@ -57,6 +61,9 @@ from tests.test_util.aiohttp import AiohttpClientMocker ATTR_UNIQUE_ID = "unique_id" CLIENT_ENTITY_ID = f"{MP_DOMAIN}.client" MAIN_ENTITY_ID = f"{MP_DOMAIN}.host" +MUSIC_ENTITY_ID = f"{MP_DOMAIN}.music_client" +RESTRICTED_ENTITY_ID = f"{MP_DOMAIN}.restricted_client" +STANDBY_ENTITY_ID = f"{MP_DOMAIN}.standby_client" UNAVAILABLE_ENTITY_ID = f"{MP_DOMAIN}.unavailable_client" # pylint: disable=redefined-outer-name @@ -250,6 +257,63 @@ async def test_check_attributes( 2010, 7, 5, 15, 0, 8, tzinfo=dt_util.UTC ) + state = hass.states.get(MUSIC_ENTITY_ID) + assert state.state == STATE_PLAYING + + assert state.attributes.get(ATTR_MEDIA_CONTENT_ID) == "76917562" + assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_MUSIC + assert state.attributes.get(ATTR_MEDIA_DURATION) == 86400 + assert state.attributes.get(ATTR_MEDIA_POSITION) == 15050 + assert state.attributes.get(ATTR_MEDIA_POSITION_UPDATED_AT) + assert state.attributes.get(ATTR_MEDIA_TITLE) == "Sparkle In Your Eyes" + assert state.attributes.get(ATTR_MEDIA_ARTIST) == "Gerald Albright" + assert state.attributes.get(ATTR_MEDIA_ALBUM_NAME) == "Slam Dunk (2014)" + assert state.attributes.get(ATTR_MEDIA_SERIES_TITLE) is None + assert state.attributes.get(ATTR_MEDIA_CHANNEL) == "{} ({})".format("MCSJ", "851") + assert state.attributes.get(ATTR_INPUT_SOURCE) == "851" + assert not state.attributes.get(ATTR_MEDIA_CURRENTLY_RECORDING) + assert state.attributes.get(ATTR_MEDIA_RATING) == "TV-PG" + assert not state.attributes.get(ATTR_MEDIA_RECORDED) + assert state.attributes.get(ATTR_MEDIA_START_TIME) == datetime( + 2020, 3, 21, 10, 0, 0, tzinfo=dt_util.UTC + ) + + state = hass.states.get(STANDBY_ENTITY_ID) + assert state.state == STATE_OFF + + assert state.attributes.get(ATTR_MEDIA_CONTENT_ID) is None + assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) is None + assert state.attributes.get(ATTR_MEDIA_DURATION) is None + assert state.attributes.get(ATTR_MEDIA_POSITION) is None + assert state.attributes.get(ATTR_MEDIA_POSITION_UPDATED_AT) is None + assert state.attributes.get(ATTR_MEDIA_TITLE) is None + assert state.attributes.get(ATTR_MEDIA_ARTIST) is None + assert state.attributes.get(ATTR_MEDIA_ALBUM_NAME) is None + assert state.attributes.get(ATTR_MEDIA_SERIES_TITLE) is None + assert state.attributes.get(ATTR_MEDIA_CHANNEL) is None + assert state.attributes.get(ATTR_INPUT_SOURCE) is None + assert not state.attributes.get(ATTR_MEDIA_CURRENTLY_RECORDING) + assert state.attributes.get(ATTR_MEDIA_RATING) is None + assert not state.attributes.get(ATTR_MEDIA_RECORDED) + + state = hass.states.get(RESTRICTED_ENTITY_ID) + assert state.state == STATE_PLAYING + + assert state.attributes.get(ATTR_MEDIA_CONTENT_ID) is None + assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) is None + assert state.attributes.get(ATTR_MEDIA_DURATION) is None + assert state.attributes.get(ATTR_MEDIA_POSITION) is None + assert state.attributes.get(ATTR_MEDIA_POSITION_UPDATED_AT) is None + assert state.attributes.get(ATTR_MEDIA_TITLE) is None + assert state.attributes.get(ATTR_MEDIA_ARTIST) is None + assert state.attributes.get(ATTR_MEDIA_ALBUM_NAME) is None + assert state.attributes.get(ATTR_MEDIA_SERIES_TITLE) is None + assert state.attributes.get(ATTR_MEDIA_CHANNEL) is None + assert state.attributes.get(ATTR_INPUT_SOURCE) is None + assert not state.attributes.get(ATTR_MEDIA_CURRENTLY_RECORDING) + assert state.attributes.get(ATTR_MEDIA_RATING) is None + assert not state.attributes.get(ATTR_MEDIA_RECORDED) + state = hass.states.get(UNAVAILABLE_ENTITY_ID) assert state.state == STATE_UNAVAILABLE diff --git a/tests/fixtures/directv/info-get-locations.json b/tests/fixtures/directv/info-get-locations.json index 5279bcebefc..d8b14124c13 100644 --- a/tests/fixtures/directv/info-get-locations.json +++ b/tests/fixtures/directv/info-get-locations.json @@ -8,6 +8,18 @@ "clientAddr": "2CA17D1CD30X", "locationName": "Client" }, + { + "clientAddr": "A01234567890", + "locationName": "Music Client" + }, + { + "clientAddr": "B01234567890", + "locationName": "Standby Client" + }, + { + "clientAddr": "C01234567890", + "locationName": "Restricted Client" + }, { "clientAddr": "9XXXXXXXXXX9", "locationName": "Unavailable Client" diff --git a/tests/fixtures/directv/info-mode-standby.json b/tests/fixtures/directv/info-mode-standby.json new file mode 100644 index 00000000000..4c40c305723 --- /dev/null +++ b/tests/fixtures/directv/info-mode-standby.json @@ -0,0 +1,9 @@ +{ + "mode": 1, + "status": { + "code": 200, + "commandResult": 0, + "msg": "OK", + "query": "/info/mode" + } +} diff --git a/tests/fixtures/directv/tv-get-tuned-music.json b/tests/fixtures/directv/tv-get-tuned-music.json new file mode 100644 index 00000000000..d7e51e5dfe7 --- /dev/null +++ b/tests/fixtures/directv/tv-get-tuned-music.json @@ -0,0 +1,28 @@ +{ + "callsign": "MCSJ", + "duration": 86400, + "isOffAir": false, + "isPclocked": 3, + "isPpv": false, + "isRecording": false, + "isVod": false, + "major": 851, + "minor": 65535, + "music": { + "by": "Gerald Albright", + "cd": "Slam Dunk (2014)", + "title": "Sparkle In Your Eyes" + }, + "offset": 15050, + "programId": "76917562", + "rating": "TV-PG", + "startTime": 1584784800, + "stationId": 2872196, + "status": { + "code": 200, + "commandResult": 0, + "msg": "OK.", + "query": "/tv/getTuned" + }, + "title": "Smooth Jazz" +} diff --git a/tests/fixtures/directv/tv-get-tuned-restricted.json b/tests/fixtures/directv/tv-get-tuned-restricted.json new file mode 100644 index 00000000000..1e705b37d64 --- /dev/null +++ b/tests/fixtures/directv/tv-get-tuned-restricted.json @@ -0,0 +1,8 @@ +{ + "status": { + "code": 403, + "commandResult": 1, + "msg": "Forbidden.", + "query": "/tv/getTuned" + } +}