def play_media(self, media_type, media_id, **kwargs): """ Send the play_media command to the media player. If media_id is a Plex payload, attempt Plex->Sonos playback. If media_type is "playlist", media_id should be a Sonos Playlist name. Otherwise, media_id should be a URI. If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the queue. """ if media_id and media_id.startswith(PLEX_URI_SCHEME): media_id = media_id[len(PLEX_URI_SCHEME):] play_on_sonos(self.hass, media_type, media_id, self.name) elif media_type in (MEDIA_TYPE_MUSIC, MEDIA_TYPE_TRACK): if kwargs.get(ATTR_MEDIA_ENQUEUE): try: if self.soco.is_service_uri(media_id): self.soco.add_service_uri_to_queue(media_id) else: self.soco.add_uri_to_queue(media_id) except SoCoUPnPException: _LOGGER.error( 'Error parsing media uri "%s", ' "please check it's a valid media resource " "supported by Sonos", media_id, ) else: if self.soco.is_service_uri(media_id): self.soco.clear_queue() self.soco.add_service_uri_to_queue(media_id) self.soco.play_from_queue(0) else: self.soco.play_uri(media_id) elif media_type == MEDIA_TYPE_PLAYLIST: if media_id.startswith("S:"): item = get_media(self._media_library, media_id, media_type) self.soco.play_uri(item.get_uri()) return try: playlists = self.soco.get_sonos_playlists() playlist = next(p for p in playlists if p.title == media_id) self.soco.clear_queue() self.soco.add_to_queue(playlist) self.soco.play_from_queue(0) except StopIteration: _LOGGER.error('Could not find a Sonos playlist named "%s"', media_id) elif media_type in PLAYABLE_MEDIA_TYPES: item = get_media(self._media_library, media_id, media_type) if not item: _LOGGER.error('Could not find "%s" in the library', media_id) return self.soco.play_uri(item.get_uri()) else: _LOGGER.error('Sonos does not support a media type of "%s"', media_type)
def play_media(self, media_type: str, media_id: str, **kwargs: Any) -> None: """ Send the play_media command to the media player. If media_id is a Plex payload, attempt Plex->Sonos playback. If media_id is a Sonos or Tidal share link, attempt playback using the respective service. If media_type is "playlist", media_id should be a Sonos Playlist name. Otherwise, media_id should be a URI. If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the queue. """ soco = self.coordinator.soco if media_id and media_id.startswith(PLEX_URI_SCHEME): media_id = media_id[len(PLEX_URI_SCHEME) :] play_on_sonos(self.hass, media_type, media_id, self.name) # type: ignore[no-untyped-call] return share_link = self.speaker.share_link if share_link.is_share_link(media_id): if kwargs.get(ATTR_MEDIA_ENQUEUE): share_link.add_share_link_to_queue(media_id) else: soco.clear_queue() share_link.add_share_link_to_queue(media_id) soco.play_from_queue(0) elif media_type in (MEDIA_TYPE_MUSIC, MEDIA_TYPE_TRACK): if kwargs.get(ATTR_MEDIA_ENQUEUE): soco.add_uri_to_queue(media_id) else: soco.play_uri(media_id) elif media_type == MEDIA_TYPE_PLAYLIST: if media_id.startswith("S:"): item = get_media(self.media.library, media_id, media_type) # type: ignore[no-untyped-call] soco.play_uri(item.get_uri()) return try: playlists = soco.get_sonos_playlists() playlist = next(p for p in playlists if p.title == media_id) except StopIteration: _LOGGER.error('Could not find a Sonos playlist named "%s"', media_id) else: soco.clear_queue() soco.add_to_queue(playlist) soco.play_from_queue(0) elif media_type in PLAYABLE_MEDIA_TYPES: item = get_media(self.media.library, media_id, media_type) # type: ignore[no-untyped-call] if not item: _LOGGER.error('Could not find "%s" in the library', media_id) return soco.play_uri(item.get_uri()) else: _LOGGER.error('Sonos does not support a media type of "%s"', media_type)
async def test_sonos_play_media( hass, entry, setup_plex_server, requests_mock, empty_payload, playqueue_1234, playqueue_created, plextv_account, sonos_resources, ): """Test playback from a Sonos media_player.play_media call.""" media_content_id = ( '{"library_name": "Music", "artist_name": "Artist", "album_name": "Album"}' ) sonos_speaker_name = "Zone A" requests_mock.get("https://plex.tv/users/account", text=plextv_account) requests_mock.post("/playqueues", text=playqueue_created) playback_mock = requests_mock.get("/player/playback/playMedia", status_code=200) # Test with no Plex integration available with pytest.raises(HomeAssistantError) as excinfo: play_on_sonos(hass, MEDIA_TYPE_MUSIC, media_content_id, sonos_speaker_name) assert "Plex integration not configured" in str(excinfo.value) with patch("homeassistant.components.plex.PlexServer.connect", side_effect=NotFound): # Initialize Plex integration without setting up a server with pytest.raises(AssertionError): await setup_plex_server() # Test with no Plex servers available with pytest.raises(HomeAssistantError) as excinfo: play_on_sonos(hass, MEDIA_TYPE_MUSIC, media_content_id, sonos_speaker_name) assert "No Plex servers available" in str(excinfo.value) # Complete setup of a Plex server await hass.config_entries.async_unload(entry.entry_id) mock_plex_server = await setup_plex_server() # Test with no speakers available requests_mock.get("https://sonos.plex.tv/resources", text=empty_payload) with pytest.raises(HomeAssistantError) as excinfo: play_on_sonos(hass, MEDIA_TYPE_MUSIC, media_content_id, sonos_speaker_name) assert f"Sonos speaker '{sonos_speaker_name}' is not associated with" in str( excinfo.value) assert playback_mock.call_count == 0 # Test with speakers available requests_mock.get("https://sonos.plex.tv/resources", text=sonos_resources) with patch.object(mock_plex_server.account, "_sonos_cache_timestamp", 0): play_on_sonos(hass, MEDIA_TYPE_MUSIC, media_content_id, sonos_speaker_name) assert playback_mock.call_count == 1 # Test with speakers available and media key payload play_on_sonos(hass, MEDIA_TYPE_MUSIC, "100", sonos_speaker_name) assert playback_mock.call_count == 2 # Test with speakers available and Plex server specified content_id_with_server = '{"plex_server": "Plex Server 1", "library_name": "Music", "artist_name": "Artist", "album_name": "Album"}' play_on_sonos(hass, MEDIA_TYPE_MUSIC, content_id_with_server, sonos_speaker_name) assert playback_mock.call_count == 3 # Test with speakers available but media not found content_id_bad_media = '{"library_name": "Music", "artist_name": "Not an Artist"}' with pytest.raises(HomeAssistantError) as excinfo: play_on_sonos(hass, MEDIA_TYPE_MUSIC, content_id_bad_media, sonos_speaker_name) assert "Plex media not found" in str(excinfo.value) assert playback_mock.call_count == 3 # Test with speakers available and playqueue requests_mock.get("https://1.2.3.4:32400/playQueues/1234", text=playqueue_1234) content_id_with_playqueue = '{"playqueue_id": 1234}' play_on_sonos(hass, MEDIA_TYPE_MUSIC, content_id_with_playqueue, sonos_speaker_name) assert playback_mock.call_count == 4 # Test with speakers available and invalid playqueue requests_mock.get("https://1.2.3.4:32400/playQueues/1235", status_code=404) content_id_with_playqueue = '{"playqueue_id": 1235}' with pytest.raises(HomeAssistantError) as excinfo: play_on_sonos(hass, MEDIA_TYPE_MUSIC, content_id_with_playqueue, sonos_speaker_name) assert "PlayQueue '1235' could not be found" in str(excinfo.value) assert playback_mock.call_count == 4