async def test_process_play_media_url_for_addon(hass, mock_sign_path):
    """Test it uses the hostname for an addon if available."""
    await async_process_ha_core_config(
        hass,
        {
            "internal_url": "http://example.local:8123",
            "external_url": "https://example.com",
        },
    )

    # Not hassio or hassio not loaded yet, don't use supervisor network url
    hass.config.api = Mock(use_ssl=False,
                           port=8123,
                           local_ip="192.168.123.123")
    assert (async_process_play_media_url(
        hass, "/path", for_supervisor_network=True) !=
            "http://homeassistant:8123/path?authSig=bla")

    # Is hassio and not SSL, use an supervisor network url
    mock_component(hass, "hassio")
    assert (async_process_play_media_url(hass,
                                         "/path",
                                         for_supervisor_network=True) ==
            "http://homeassistant:8123/path?authSig=bla")

    # Hassio loaded but using SSL, don't use an supervisor network url
    hass.config.api = Mock(use_ssl=True, port=8123, local_ip="192.168.123.123")
    assert (async_process_play_media_url(
        hass, "/path", for_supervisor_network=True) !=
            "https://homeassistant:8123/path?authSig=bla")
    async def async_play_media(
        self,
        media_type: str,
        media_id: str,
        enqueue: MediaPlayerEnqueue | None = None,
        announce: bool | None = None,
        **kwargs: Any,
    ) -> None:
        """Send the play_media command to the media player."""
        # Handle media_source
        if media_source.is_media_source_id(media_id):
            sourced_media = await media_source.async_resolve_media(
                self.hass, media_id, self.entity_id)
            media_id = sourced_media.url

        media_id = async_process_play_media_url(self.hass, media_id)

        queue_opt = QUEUE_OPTION_MAP.get(enqueue, QueueOption.PLAY)
        if announce is None:
            announce = "/api/tts_proxy" in media_id

        if announce:
            announce_sound = "/api/tts_proxy" in media_id
            self.hass.create_task(
                self.player.active_queue.play_alert(media_id, announce_sound))
        else:
            await self.player.active_queue.play_media(media_id, queue_opt)
Exemple #3
0
    async def async_play_media(self, media_type: str, media_id: str, **kwargs) -> None:
        """Play media."""
        if media_source.is_media_source_id(media_id):
            play_item = await media_source.async_resolve_media(
                self.hass, media_id, self.entity_id
            )
            media_id = play_item.url

        if self.state == STATE_OFF:
            await self.async_turn_on()

        if media_id:
            parts = media_id.split(":")

            if parts[0] == "list":
                if (index := parts[3]) == "-1":
                    index = "0"

                await self.coordinator.musiccast.play_list_media(index, self._zone_id)
                return

            if parts[0] == "presets":
                index = parts[1]
                await self.coordinator.musiccast.recall_netusb_preset(
                    self._zone_id, index
                )
                return

            if parts[0] in ("http", "https") or media_id.startswith("/"):
                media_id = async_process_play_media_url(self.hass, media_id)

                await self.coordinator.musiccast.play_url_media(
                    self._zone_id, media_id, "HomeAssistant"
                )
                return
Exemple #4
0
    async def async_play_media(self, media_type: str, media_id: str,
                               **kwargs: Any) -> None:
        """Send the play_media command to the media player."""
        # If input (file) has a file format supported by pyatv, then stream it with
        # RAOP. Otherwise try to play it with regular AirPlay.
        if media_type == MEDIA_TYPE_APP:
            await self.atv.apps.launch_app(media_id)
            return

        if media_source.is_media_source_id(media_id):
            play_item = await media_source.async_resolve_media(
                self.hass, media_id, self.entity_id)
            media_id = async_process_play_media_url(self.hass, play_item.url)
            media_type = MEDIA_TYPE_MUSIC

        if self._is_feature_available(
                FeatureName.StreamFile) and (media_type == MEDIA_TYPE_MUSIC
                                             or await is_streamable(media_id)):
            _LOGGER.debug("Streaming %s via RAOP", media_id)
            await self.atv.stream.stream_file(media_id)
        elif self._is_feature_available(FeatureName.PlayUrl):
            _LOGGER.debug("Playing %s via AirPlay", media_id)
            await self.atv.stream.play_url(media_id)
        else:
            _LOGGER.error(
                "Media streaming is not possible with current configuration")
Exemple #5
0
    async def async_play_media(self, media_type: str, media_id: str,
                               **kwargs: Any) -> None:
        """Play a piece of media."""
        if media_source.is_media_source_id(media_id):
            media_type = MEDIA_TYPE_MUSIC
            play_item = await media_source.async_resolve_media(
                self.hass, media_id)
            media_id = async_process_play_media_url(self.hass, play_item.url)

        if media_type != MEDIA_TYPE_MUSIC:
            raise HomeAssistantError("Only music media type is supported")

        _LOGGER.debug("Playing Media %s for %s Speaker", media_id,
                      self.device.name)
        await self.async_media_stop()
        try:
            await self.device.play_audio(media_id, blocking=False)
        except StreamError as err:
            raise HomeAssistantError(err) from err
        else:
            # update state after starting player
            self._async_updated_event()
            # wait until player finishes to update state again
            await self.device.wait_until_audio_completes()

        self._async_updated_event()
Exemple #6
0
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Send the media player the command for playing a playlist."""
        if media_source.is_media_source_id(media_id):
            media_type = MEDIA_TYPE_MUSIC
            play_item = await media_source.async_resolve_media(
                self.hass, media_id)
            media_id = play_item.url

        if media_type == MEDIA_TYPE_PLAYLIST:
            _LOGGER.debug("Playing playlist: %s", media_id)
            if media_id in self._playlists:
                self._currentplaylist = media_id
            else:
                self._currentplaylist = None
                _LOGGER.warning("Unknown playlist name %s", media_id)
            await self._client.clear()
            await self._client.load(media_id)
            await self._client.play()
        else:
            media_id = async_process_play_media_url(self.hass, media_id)

            await self._client.clear()
            self._currentplaylist = None
            await self._client.add(media_id)
            await self._client.play()
Exemple #7
0
    async def async_play_media(self, media_type: str, media_id: str,
                               **kwargs: Any) -> None:
        """Play a piece of media."""
        if media_source.is_media_source_id(media_id):
            media_type = MEDIA_TYPE_URL
            play_item = await media_source.async_resolve_media(
                self.hass, media_id, self.entity_id)
            media_id = play_item.url

        if media_type in (MEDIA_TYPE_URL, MEDIA_TYPE_MUSIC):
            media_id = async_process_play_media_url(self.hass, media_id)

            await self._player.play_url(media_id)
            return

        if media_type == "quick_select":
            # media_id may be an int or a str
            selects = await self._player.get_quick_selects()
            try:
                index: int | None = int(media_id)
            except ValueError:
                # Try finding index by name
                index = next(
                    (index for index, select in selects.items()
                     if select == media_id),
                    None,
                )
            if index is None:
                raise ValueError(f"Invalid quick select '{media_id}'")
            await self._player.play_quick_select(index)
            return

        if media_type == MEDIA_TYPE_PLAYLIST:
            playlists = await self._player.heos.get_playlists()
            playlist = next((p for p in playlists if p.name == media_id), None)
            if not playlist:
                raise ValueError(f"Invalid playlist '{media_id}'")
            add_queue_option = HA_HEOS_ENQUEUE_MAP.get(
                kwargs.get(ATTR_MEDIA_ENQUEUE))

            await self._player.add_to_queue(playlist, add_queue_option)
            return

        if media_type == "favorite":
            # media_id may be an int or str
            try:
                index = int(media_id)
            except ValueError:
                # Try finding index by name
                index = next(
                    (index for index, favorite in self._source_manager.
                     favorites.items() if favorite.name == media_id),
                    None,
                )
            if index is None:
                raise ValueError(f"Invalid favorite '{media_id}'")
            await self._player.play_favorite(index)
            return

        raise ValueError(f"Unsupported media type '{media_type}'")
 async def async_play_media(self, media_type, media_id, **kwargs):
     if media_source.is_media_source_id(media_id):
         media_type = MEDIA_TYPE_URL
         play_item = await media_source.async_resolve_media(
             self.hass, media_id)
         media_id = play_item.url
     if media_type in (MEDIA_TYPE_URL, MEDIA_TYPE_MUSIC):
         media_id = async_process_play_media_url(self.hass, media_id)
     self.connection.send("play", media_content_id=media_id)
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Play a piece of media."""
        if media_source.is_media_source_id(media_id):
            play_item = await media_source.async_resolve_media(
                self.hass, media_id)
            media_id = async_process_play_media_url(self.hass, play_item.url)

        await self.hass.async_add_executor_job(
            partial(self.play_media, media_type, media_id, **kwargs))
Exemple #10
0
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Send the play_media command to the media player."""
        index = None

        enqueue: MediaPlayerEnqueue | None = kwargs.get(ATTR_MEDIA_ENQUEUE)

        if enqueue == MediaPlayerEnqueue.ADD:
            cmd = "add"
        elif enqueue == MediaPlayerEnqueue.NEXT:
            cmd = "insert"
        elif enqueue == MediaPlayerEnqueue.PLAY:
            cmd = "play_now"
        else:
            cmd = "play"

        if media_source.is_media_source_id(media_id):
            media_type = MEDIA_TYPE_MUSIC
            play_item = await media_source.async_resolve_media(
                self.hass, media_id, self.entity_id
            )
            media_id = play_item.url

        if media_type in MEDIA_TYPE_MUSIC:
            if not media_id.startswith(SQUEEZEBOX_SOURCE_STRINGS):
                # do not process special squeezebox "source" media ids
                media_id = async_process_play_media_url(self.hass, media_id)

            await self._player.async_load_url(media_id, cmd)
            return

        if media_type == MEDIA_TYPE_PLAYLIST:
            try:
                # a saved playlist by number
                payload = {
                    "search_id": int(media_id),
                    "search_type": MEDIA_TYPE_PLAYLIST,
                }
                playlist = await generate_playlist(self._player, payload)
            except ValueError:
                # a list of urls
                content = json.loads(media_id)
                playlist = content["urls"]
                index = content["index"]
        else:
            payload = {
                "search_id": media_id,
                "search_type": media_type,
            }
            playlist = await generate_playlist(self._player, payload)

            _LOGGER.debug("Generated playlist: %s", playlist)

        await self._player.async_load_playlist(playlist, cmd)
        if index is not None:
            await self._player.async_index(index)
Exemple #11
0
async def test_process_play_media_url(hass, mock_sign_path):
    """Test it prefixes and signs urls."""
    await async_process_ha_core_config(
        hass,
        {"internal_url": "http://example.local:8123"},
    )
    hass.config.api = Mock(use_ssl=False,
                           port=8123,
                           local_ip="192.168.123.123")

    # Not changing a url that is not a hass url
    assert (async_process_play_media_url(
        hass, "https://not-hass.com/path") == "https://not-hass.com/path")

    # Testing signing hass URLs
    assert (async_process_play_media_url(
        hass, "/path") == "http://example.local:8123/path?authSig=bla")
    assert (async_process_play_media_url(hass,
                                         "http://example.local:8123/path") ==
            "http://example.local:8123/path?authSig=bla")
    assert (async_process_play_media_url(hass,
                                         "http://192.168.123.123:8123/path") ==
            "http://192.168.123.123:8123/path?authSig=bla")

    # Test skip signing URLs that have a query param
    assert (async_process_play_media_url(
        hass,
        "/path?hello=world") == "http://example.local:8123/path?hello=world")
    assert (async_process_play_media_url(
        hass, "http://192.168.123.123:8123/path?hello=world") ==
            "http://192.168.123.123:8123/path?hello=world")
Exemple #12
0
async def test_process_play_media_url(hass, mock_sign_path):
    """Test it prefixes and signs urls."""
    await async_process_ha_core_config(
        hass,
        {"internal_url": "http://example.local:8123"},
    )
    hass.config.api = Mock(use_ssl=False,
                           port=8123,
                           local_ip="192.168.123.123")

    # Not changing a url that is not a hass url
    assert (async_process_play_media_url(
        hass, "https://not-hass.com/path") == "https://not-hass.com/path")

    # Testing signing hass URLs
    assert (async_process_play_media_url(
        hass, "/path") == "http://example.local:8123/path?authSig=bla")
    assert (async_process_play_media_url(hass,
                                         "http://example.local:8123/path") ==
            "http://example.local:8123/path?authSig=bla")
    assert (async_process_play_media_url(hass,
                                         "http://192.168.123.123:8123/path") ==
            "http://192.168.123.123:8123/path?authSig=bla")
    with pytest.raises(HomeAssistantError), patch(
            "homeassistant.components.media_player.browse_media.get_url",
            side_effect=NoURLAvailableError,
    ):
        async_process_play_media_url(hass, "/path")

    # Test skip signing URLs that have a query param
    assert (async_process_play_media_url(
        hass,
        "/path?hello=world") == "http://example.local:8123/path?hello=world")
    assert (async_process_play_media_url(
        hass, "http://192.168.123.123:8123/path?hello=world") ==
            "http://192.168.123.123:8123/path?hello=world")

    with pytest.raises(ValueError):
        async_process_play_media_url(hass, "hello")
Exemple #13
0
    async def async_play_media(
        self, media_type: str, media_id: str, **kwargs: Any
    ) -> None:
        """Play a piece of media."""
        if media_source.is_media_source_id(media_id):
            play_item = await media_source.async_resolve_media(
                self.hass, media_id, self.entity_id
            )
            media_id = async_process_play_media_url(self.hass, play_item.url)

        await self.coordinator.fully.playSound(media_id, AUDIOMANAGER_STREAM_MUSIC)
        self._attr_state = STATE_PLAYING
        self.async_write_ha_state()
Exemple #14
0
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Play media."""
        # Handle media_source
        if media_source.is_media_source_id(media_id):
            sourced_media = await media_source.async_resolve_media(self.hass, media_id)
            media_id = sourced_media.url

        elif media_type != MEDIA_TYPE_MUSIC:
            _LOGGER.error("Invalid media type")
            return

        media_id = async_process_play_media_url(self.hass, media_id)

        await self.hass.async_add_executor_job(self._player.queue, media_id)
Exemple #15
0
    async def async_play_media(
        self, media_type: str, media_id: str, **kwargs: Any
    ) -> None:
        """Send the play command with media url to the media player."""
        if media_source.is_media_source_id(media_id):
            sourced_media = await media_source.async_resolve_media(self.hass, media_id)
            media_id = sourced_media.url

        media_id = async_process_play_media_url(self.hass, media_id)

        await self._client.media_player_command(
            self._static_info.key,
            media_url=media_id,
        )
    async def async_play_media(self, media_type: str, media_id: str, **kwargs) -> None:
        """Send the play_media command to the media player."""
        to_send_media_type: str | None = media_type
        # Handle media_source
        if media_source.is_media_source_id(media_id):
            sourced_media = await media_source.async_resolve_media(self.hass, media_id)
            media_id = sourced_media.url
            to_send_media_type = sourced_media.mime_type

        if to_send_media_type and not to_send_media_type.startswith("audio/"):
            to_send_media_type = None
        media_id = async_process_play_media_url(self.hass, media_id)

        await self.player.play_url(media_id, mime_type=to_send_media_type)
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Play media."""
        if media_source.is_media_source_id(media_id):
            media_type = MEDIA_TYPE_URL
            play_item = await media_source.async_resolve_media(
                self.hass, media_id)
            media_id = play_item.url

        if media_type != MEDIA_TYPE_URL:
            _LOGGER.warning("Unsupported media_type: %s", media_type)
            return

        media_id = async_process_play_media_url(self.hass, media_id)
        await self._remote.async_play_media(media_type, media_id)
Exemple #18
0
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Send the play_media command to the media player."""
        if self.is_grouped and not self.is_master:
            return

        if media_source.is_media_source_id(media_id):
            play_item = await media_source.async_resolve_media(
                self.hass, media_id, self.entity_id)
            media_id = play_item.url

        media_id = async_process_play_media_url(self.hass, media_id)

        url = f"Play?url={media_id}"

        return await self.send_bluesound_command(url)
Exemple #19
0
    async def async_play_media(self, media_type, media_id, **kwargs):
        """
        Send the play_media command to the media player.

        If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the current playlist.
        """
        cmd = "play"
        index = None

        if kwargs.get(ATTR_MEDIA_ENQUEUE):
            cmd = "add"

        if media_source.is_media_source_id(media_id):
            media_type = MEDIA_TYPE_MUSIC
            play_item = await media_source.async_resolve_media(self.hass, media_id)
            media_id = play_item.url

        if media_type in MEDIA_TYPE_MUSIC:
            media_id = async_process_play_media_url(self.hass, media_id)

            await self._player.async_load_url(media_id, cmd)
            return

        if media_type == MEDIA_TYPE_PLAYLIST:
            try:
                # a saved playlist by number
                payload = {
                    "search_id": int(media_id),
                    "search_type": MEDIA_TYPE_PLAYLIST,
                }
                playlist = await generate_playlist(self._player, payload)
            except ValueError:
                # a list of urls
                content = json.loads(media_id)
                playlist = content["urls"]
                index = content["index"]
        else:
            payload = {
                "search_id": media_id,
                "search_type": media_type,
            }
            playlist = await generate_playlist(self._player, payload)

            _LOGGER.debug("Generated playlist: %s", playlist)

        await self._player.async_load_playlist(playlist, cmd)
        if index is not None:
            await self._player.async_index(index)
Exemple #20
0
async def websocket_resolve_media(
    hass: HomeAssistant, connection: ActiveConnection, msg: dict
) -> None:
    """Resolve media."""
    try:
        media = await async_resolve_media(hass, msg["media_content_id"])
    except Unresolvable as err:
        connection.send_error(msg["id"], "resolve_media_failed", str(err))
        return

    connection.send_result(
        msg["id"],
        {
            "url": async_process_play_media_url(
                hass, media.url, allow_relative_url=True
            ),
            "mime_type": media.mime_type,
        },
    )
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Send the play_media command to the media player."""
        if media_source.is_media_source_id(media_id):
            media_type = MEDIA_TYPE_MUSIC
            play_item = await media_source.async_resolve_media(
                self.hass, media_id)
            media_id = play_item.url

        if media_type != MEDIA_TYPE_MUSIC:
            _LOGGER.error(
                "Invalid media type %s. Only %s is supported",
                media_type,
                MEDIA_TYPE_MUSIC,
            )
            return

        media_id = async_process_play_media_url(self.hass, media_id)

        track_details = {"title": "Home Assistant", "uri": media_id}
        await self._device.play_media(track_details)
Exemple #22
0
    async def async_play_media(
        self, media_type: str, media_id: str, **kwargs: Any
    ) -> None:
        """Send the play_media command to the media player."""
        if media_source.is_media_source_id(media_id):
            media_type = MEDIA_TYPE_URL
            play_item = await media_source.async_resolve_media(self.hass, media_id)
            media_id = play_item.url

        media_type_lower = media_type.lower()

        if media_type_lower == MEDIA_TYPE_CHANNEL:
            await self._kodi.play_channel(int(media_id))
        elif media_type_lower == MEDIA_TYPE_PLAYLIST:
            await self._kodi.play_playlist(int(media_id))
        elif media_type_lower == "file":
            await self._kodi.play_file(media_id)
        elif media_type_lower == "directory":
            await self._kodi.play_directory(media_id)
        elif media_type_lower in [
            MEDIA_TYPE_ARTIST,
            MEDIA_TYPE_ALBUM,
            MEDIA_TYPE_TRACK,
        ]:
            await self.async_clear_playlist()
            await self.async_add_to_playlist(media_type_lower, media_id)
            await self._kodi.play_playlist(0)
        elif media_type_lower in [
            MEDIA_TYPE_MOVIE,
            MEDIA_TYPE_EPISODE,
            MEDIA_TYPE_SEASON,
            MEDIA_TYPE_TVSHOW,
        ]:
            await self._kodi.play_item(
                {MAP_KODI_MEDIA_TYPES[media_type_lower]: int(media_id)}
            )
        else:
            media_id = async_process_play_media_url(self.hass, media_id)

            await self._kodi.play_file(media_id)
    async def async_play_media(self, media_type, media_id, **kwargs):
        """
        Send the play_media command to the media player.

        If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the queue.
        """
        if self.is_grouped and not self.is_master:
            return

        if media_source.is_media_source_id(media_id):
            play_item = await media_source.async_resolve_media(
                self.hass, media_id)
            media_id = play_item.url

        media_id = async_process_play_media_url(self.hass, media_id)

        url = f"Play?url={media_id}"

        if kwargs.get(ATTR_MEDIA_ENQUEUE):
            return await self.send_bluesound_command(url)

        return await self.send_bluesound_command(url)
Exemple #24
0
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Play media from a URL or file."""
        # Handle media_source
        if media_source.is_media_source_id(media_id):
            sourced_media = await media_source.async_resolve_media(self.hass, media_id)
            media_id = sourced_media.url

        elif media_type != MEDIA_TYPE_MUSIC:
            _LOGGER.error(
                "Invalid media type %s. Only %s is supported",
                media_type,
                MEDIA_TYPE_MUSIC,
            )
            return

        media_id = async_process_play_media_url(self.hass, media_id)

        def play():
            self._vlc.set_media(self._instance.media_new(media_id))
            self._vlc.play()

        await self.hass.async_add_executor_job(play)
        self._state = STATE_PLAYING
Exemple #25
0
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Play a URI."""
        if media_source.is_media_source_id(media_id):
            media_type = MEDIA_TYPE_MUSIC
            play_item = await media_source.async_resolve_media(
                self.hass, media_id, self.entity_id)
            media_id = play_item.url

        if media_type == MEDIA_TYPE_MUSIC:
            media_id = async_process_play_media_url(self.hass, media_id)

            saved_state = self.state  # save play state
            saved_mute = self.is_volume_muted
            sleep_future = asyncio.create_task(
                asyncio.sleep(self._tts_pause_time)
            )  # start timing now, but not exact because of fd buffer + tts latency
            await self._pause_and_wait_for_callback()
            await self._save_and_set_tts_volumes()
            # save position
            saved_song_position = self._player["item_progress_ms"]
            saved_queue = (self._queue if self._queue["count"] > 0 else None
                           )  # stash queue
            if saved_queue:
                saved_queue_position = next(
                    i for i, item in enumerate(saved_queue["items"])
                    if item["id"] == self._player["item_id"])
            self._tts_requested = True
            await sleep_future
            await self._api.add_to_queue(uris=media_id,
                                         playback="start",
                                         clear=True)
            try:
                await asyncio.wait_for(self._tts_playing_event.wait(),
                                       timeout=TTS_TIMEOUT)
                # we have started TTS, now wait for completion
                await asyncio.sleep(
                    self._queue["items"][0]["length_ms"] /
                    1000  # player may not have updated yet so grab length from queue
                    + self._tts_pause_time)
            except asyncio.TimeoutError:
                self._tts_requested = False
                _LOGGER.warning("TTS request timed out")
            self._tts_playing_event.clear()
            # TTS done, return to normal
            await self.async_turn_on()  # restore outputs and volumes
            if saved_mute:  # mute if we were muted
                await self.async_mute_volume(True)
            if self._use_pipe_control():  # resume pipe
                await self._api.add_to_queue(
                    uris=self._sources_uris[self._source], clear=True)
                if saved_state == STATE_PLAYING:
                    await self.async_media_play()
            else:  # restore stashed queue
                if saved_queue:
                    uris = ""
                    for item in saved_queue["items"]:
                        uris += item["uri"] + ","
                    await self._api.add_to_queue(
                        uris=uris,
                        playback="start",
                        playback_from_position=saved_queue_position,
                        clear=True,
                    )
                    await self._api.seek(position_ms=saved_song_position)
                    if saved_state == STATE_PAUSED:
                        await self.async_media_pause()
                    elif saved_state != STATE_PLAYING:
                        await self.async_media_stop()
        else:
            _LOGGER.debug("Media type '%s' not supported", media_type)