async def test_is_internal_request(hass: HomeAssistant):
    """Test if accessing an instance on its internal URL."""
    # Test with internal URL: http://example.local:8123
    await async_process_ha_core_config(
        hass,
        {"internal_url": "http://example.local:8123"},
    )

    assert hass.config.internal_url == "http://example.local:8123"
    assert not is_internal_request(hass)

    with patch(
        "homeassistant.helpers.network._get_request_host", return_value="example.local"
    ):
        assert is_internal_request(hass)

    with patch(
        "homeassistant.helpers.network._get_request_host",
        return_value="no_match.example.local",
    ):
        assert not is_internal_request(hass)

    # Test with internal URL: http://192.168.0.1:8123
    await async_process_ha_core_config(
        hass,
        {"internal_url": "http://192.168.0.1:8123"},
    )

    assert hass.config.internal_url == "http://192.168.0.1:8123"
    assert not is_internal_request(hass)

    with patch(
        "homeassistant.helpers.network._get_request_host", return_value="192.168.0.1"
    ):
        assert is_internal_request(hass)
Beispiel #2
0
    async def async_browse_media(self,
                                 media_content_type=None,
                                 media_content_id=None):
        """Implement the websocket media browsing helper."""
        is_internal = is_internal_request(self.hass)

        async def _get_thumbnail_url(
            media_content_type,
            media_content_id,
            media_image_id=None,
            thumbnail_url=None,
        ):
            if is_internal:
                return self._kodi.thumbnail_url(thumbnail_url)

            return self.get_browse_image_url(
                media_content_type,
                urllib.parse.quote_plus(media_content_id),
                media_image_id,
            )

        if media_content_type in [None, "library"]:
            return await library_payload()

        payload = {
            "search_type": media_content_type,
            "search_id": media_content_id,
        }

        response = await build_item_response(self._kodi, payload,
                                             _get_thumbnail_url)
        if response is None:
            raise BrowseError(
                f"Media not found: {media_content_type} / {media_content_id}")
        return response
Beispiel #3
0
    async def async_browse_media(self,
                                 media_content_type=None,
                                 media_content_id=None):
        """Implement the websocket media browsing helper."""
        is_internal = is_internal_request(self.hass)

        def _get_thumbnail_url(media_content_type,
                               media_content_id,
                               media_image_id=None):
            if is_internal:
                if media_content_type == MEDIA_TYPE_APP and media_content_id:
                    return self.coordinator.roku.app_icon_url(media_content_id)
                return None

            return self.get_browse_image_url(media_content_type,
                                             media_content_id, media_image_id)

        if media_content_type in [None, "library"]:
            return library_payload(self.coordinator, _get_thumbnail_url)

        payload = {
            "search_type": media_content_type,
            "search_id": media_content_id,
        }
        response = build_item_response(self.coordinator, payload,
                                       _get_thumbnail_url)

        if response is None:
            raise BrowseError(
                f"Media not found: {media_content_type} / {media_content_id}")

        return response
Beispiel #4
0
 async def async_browse_media(self, media_content_type=None, media_content_id=None):
     """Implement the websocket media browsing helper."""
     is_internal = is_internal_request(self.hass)
     return await self.hass.async_add_executor_job(
         browse_media,
         self,
         is_internal,
         media_content_type,
         media_content_id,
     )
Beispiel #5
0
async def test_is_internal_request(hass: HomeAssistant, mock_current_request):
    """Test if accessing an instance on its internal URL."""
    # Test with internal URL: http://example.local:8123
    await async_process_ha_core_config(
        hass,
        {"internal_url": "http://example.local:8123"},
    )

    assert hass.config.internal_url == "http://example.local:8123"

    # No request active
    mock_current_request.return_value = None
    assert not is_internal_request(hass)

    mock_current_request.return_value = Mock(url="http://example.local:8123")
    assert is_internal_request(hass)

    mock_current_request.return_value = Mock(
        url="http://no_match.example.local:8123")
    assert not is_internal_request(hass)

    # Test with internal URL: http://192.168.0.1:8123
    await async_process_ha_core_config(
        hass,
        {"internal_url": "http://192.168.0.1:8123"},
    )

    assert hass.config.internal_url == "http://192.168.0.1:8123"
    assert not is_internal_request(hass)

    mock_current_request.return_value = Mock(url="http://192.168.0.1:8123")
    assert is_internal_request(hass)

    # Test for matching against local IP
    hass.config.api = Mock(use_ssl=False,
                           local_ip="192.168.123.123",
                           port=8123)
    for allowed in ("127.0.0.1", "192.168.123.123"):
        mock_current_request.return_value = Mock(url=f"http://{allowed}:8123")
        assert is_internal_request(hass), mock_current_request.return_value.url

    # Test for matching against HassOS hostname
    with patch.object(hass.components.hassio, "is_hassio",
                      return_value=True), patch.object(
                          hass.components.hassio,
                          "get_host_info",
                          return_value={"hostname": "hellohost"},
                      ):
        for allowed in ("hellohost", "hellohost.local"):
            mock_current_request.return_value = Mock(
                url=f"http://{allowed}:8123")
            assert is_internal_request(
                hass), mock_current_request.return_value.url
Beispiel #6
0
async def build_item_response(entity, player, payload):
    """Create response payload for search described by payload."""
    internal_request = is_internal_request(entity.hass)

    search_id = payload["search_id"]
    search_type = payload["search_type"]

    media_class = CONTENT_TYPE_MEDIA_CLASS[search_type]

    if search_id and search_id != search_type:
        browse_id = (SQUEEZEBOX_ID_BY_TYPE[search_type], search_id)
    else:
        browse_id = None

    result = await player.async_browse(
        MEDIA_TYPE_TO_SQUEEZEBOX[search_type],
        limit=BROWSE_LIMIT,
        browse_id=browse_id,
    )

    children = None

    if result is not None and result.get("items"):
        item_type = CONTENT_TYPE_TO_CHILD_TYPE[search_type]
        child_media_class = CONTENT_TYPE_MEDIA_CLASS[item_type]

        children = []
        for item in result["items"]:
            item_id = str(item["id"])
            item_thumbnail = None

            if artwork_track_id := item.get("artwork_track_id"):
                if internal_request:
                    item_thumbnail = player.generate_image_url_from_track_id(
                        artwork_track_id)
                else:
                    item_thumbnail = entity.get_browse_image_url(
                        item_type, item_id, artwork_track_id)

            children.append(
                BrowseMedia(
                    title=item["title"],
                    media_class=child_media_class["item"],
                    media_content_id=item_id,
                    media_content_type=item_type,
                    can_play=True,
                    can_expand=child_media_class["children"] is not None,
                    thumbnail=item_thumbnail,
                ))
async def async_browse_media(hass, media_content_type, media_content_id, platform=None):
    """Browse Plex media."""
    plex_server = next(iter(hass.data[PLEX_DOMAIN][SERVERS].values()), None)
    if not plex_server:
        raise BrowseError("No Plex servers available")
    is_internal = is_internal_request(hass)
    return await hass.async_add_executor_job(
        partial(
            browse_media,
            hass,
            is_internal,
            media_content_type,
            media_content_id,
            platform=platform,
        )
    )
Beispiel #8
0
    async def async_browse_media(
        self, media_content_type: str | None = None, media_content_id: str | None = None
    ) -> Any:
        """Implement the websocket media browsing helper."""
        is_internal = is_internal_request(self.hass)

        def _get_thumbnail_url(
            media_content_type: str,
            media_content_id: str,
            media_image_id: str | None = None,
        ) -> str | None:
            if is_internal:
                item = get_media(  # type: ignore[no-untyped-call]
                    self.media.library,
                    media_content_id,
                    media_content_type,
                )
                return getattr(item, "album_art_uri", None)  # type: ignore[no-any-return]

            return self.get_browse_image_url(
                media_content_type,
                urllib.parse.quote_plus(media_content_id),
                media_image_id,
            )

        if media_content_type in [None, "library"]:
            return await self.hass.async_add_executor_job(
                library_payload, self.media.library, _get_thumbnail_url
            )

        payload = {
            "search_type": media_content_type,
            "idstring": media_content_id,
        }
        response = await self.hass.async_add_executor_job(
            build_item_response, self.media.library, payload, _get_thumbnail_url
        )
        if response is None:
            raise BrowseError(
                f"Media not found: {media_content_type} / {media_content_id}"
            )
        return response
Beispiel #9
0
async def async_browse_media(
    hass: HomeAssistant,
    coordinator: RokuDataUpdateCoordinator,
    get_browse_image_url: GetBrowseImageUrlType,
    media_content_id: str | None,
    media_content_type: str | None,
) -> BrowseMedia:
    """Browse media."""
    if media_content_id is None:
        return await root_payload(
            hass,
            coordinator,
            get_browse_image_url,
        )

    if media_source.is_media_source_id(media_content_id):
        return await media_source.async_browse_media(hass, media_content_id)

    payload = {
        "search_type": media_content_type,
        "search_id": media_content_id,
    }

    response = await hass.async_add_executor_job(
        build_item_response,
        coordinator,
        payload,
        partial(
            get_thumbnail_url_full,
            coordinator,
            is_internal_request(hass),
            get_browse_image_url,
        ),
    )

    if response is None:
        raise BrowseError(f"Media not found: {media_content_type} / {media_content_id}")

    return response
Beispiel #10
0
async def async_browse_media(
    hass,
    speaker: SonosSpeaker,
    media: SonosMedia,
    get_browse_image_url: GetBrowseImageUrlType,
    media_content_id: str | None,
    media_content_type: str | None,
):
    """Browse media."""

    if media_content_id is None:
        return await root_payload(
            hass,
            speaker,
            media,
            get_browse_image_url,
        )

    if media_source.is_media_source_id(media_content_id):
        return await media_source.async_browse_media(
            hass, media_content_id, content_filter=media_source_filter
        )

    if plex.is_plex_media_id(media_content_id):
        return await plex.async_browse_media(
            hass, media_content_type, media_content_id, platform=DOMAIN
        )

    if media_content_type == "plex":
        return await plex.async_browse_media(hass, None, None, platform=DOMAIN)

    if spotify.is_spotify_media_type(media_content_type):
        return await spotify.async_browse_media(
            hass, media_content_type, media_content_id, can_play_artist=False
        )

    if media_content_type == "spotify":
        return await spotify.async_browse_media(hass, None, None, can_play_artist=False)

    if media_content_type == "library":
        return await hass.async_add_executor_job(
            library_payload,
            media.library,
            partial(
                get_thumbnail_url_full,
                media,
                is_internal_request(hass),
                get_browse_image_url,
            ),
        )

    if media_content_type == "favorites":
        return await hass.async_add_executor_job(
            favorites_payload,
            speaker.favorites,
        )

    if media_content_type == "favorites_folder":
        return await hass.async_add_executor_job(
            favorites_folder_payload,
            speaker.favorites,
            media_content_id,
        )

    payload = {
        "search_type": media_content_type,
        "idstring": media_content_id,
    }
    response = await hass.async_add_executor_job(
        build_item_response,
        media.library,
        payload,
        partial(
            get_thumbnail_url_full,
            media,
            is_internal_request(hass),
            get_browse_image_url,
        ),
    )
    if response is None:
        raise BrowseError(f"Media not found: {media_content_type} / {media_content_id}")
    return response