Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
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