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)
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
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
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, )
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
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, ) )
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
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
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