diff --git a/homeassistant/components/synology_dsm/const.py b/homeassistant/components/synology_dsm/const.py index 11839caf8be..e6367458578 100644 --- a/homeassistant/components/synology_dsm/const.py +++ b/homeassistant/components/synology_dsm/const.py @@ -46,6 +46,8 @@ DEFAULT_SNAPSHOT_QUALITY = SNAPSHOT_PROFILE_BALANCED ENTITY_UNIT_LOAD = "load" +SHARED_SUFFIX = "_shared" + # Signals SIGNAL_CAMERA_SOURCE_CHANGED = "synology_dsm.camera_stream_source_changed" diff --git a/homeassistant/components/synology_dsm/media_source.py b/homeassistant/components/synology_dsm/media_source.py index 4b0c19b2b55..ace5733c222 100644 --- a/homeassistant/components/synology_dsm/media_source.py +++ b/homeassistant/components/synology_dsm/media_source.py @@ -21,7 +21,7 @@ from homeassistant.components.media_source import ( from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from .const import DOMAIN +from .const import DOMAIN, SHARED_SUFFIX from .models import SynologyDSMData @@ -45,6 +45,7 @@ class SynologyPhotosMediaSourceIdentifier: self.album_id = None self.cache_key = None self.file_name = None + self.is_shared = False if parts: self.unique_id = parts[0] @@ -54,6 +55,9 @@ class SynologyPhotosMediaSourceIdentifier: self.cache_key = parts[2] if len(parts) > 3: self.file_name = parts[3] + if self.file_name.endswith(SHARED_SUFFIX): + self.is_shared = True + self.file_name = self.file_name.removesuffix(SHARED_SUFFIX) class SynologyPhotosMediaSource(MediaSource): @@ -160,10 +164,13 @@ class SynologyPhotosMediaSource(MediaSource): if isinstance(mime_type, str) and mime_type.startswith("image/"): # Force small small thumbnails album_item.thumbnail_size = "sm" + suffix = "" + if album_item.is_shared: + suffix = SHARED_SUFFIX ret.append( BrowseMediaSource( domain=DOMAIN, - identifier=f"{identifier.unique_id}/{identifier.album_id}/{album_item.thumbnail_cache_key}/{album_item.file_name}", + identifier=f"{identifier.unique_id}/{identifier.album_id}/{album_item.thumbnail_cache_key}/{album_item.file_name}{suffix}", media_class=MediaClass.IMAGE, media_content_type=mime_type, title=album_item.file_name, @@ -186,8 +193,11 @@ class SynologyPhotosMediaSource(MediaSource): mime_type, _ = mimetypes.guess_type(identifier.file_name) if not isinstance(mime_type, str): raise Unresolvable("No file extension") + suffix = "" + if identifier.is_shared: + suffix = SHARED_SUFFIX return PlayMedia( - f"/synology_dsm/{identifier.unique_id}/{identifier.cache_key}/{identifier.file_name}", + f"/synology_dsm/{identifier.unique_id}/{identifier.cache_key}/{identifier.file_name}{suffix}", mime_type, ) @@ -223,13 +233,14 @@ class SynologyDsmMediaView(http.HomeAssistantView): # location: {cache_key}/{filename} cache_key, file_name = location.split("/") image_id = int(cache_key.split("_")[0]) + if shared := file_name.endswith(SHARED_SUFFIX): + file_name = file_name.removesuffix(SHARED_SUFFIX) mime_type, _ = mimetypes.guess_type(file_name) if not isinstance(mime_type, str): raise web.HTTPNotFound diskstation: SynologyDSMData = self.hass.data[DOMAIN][source_dir_id] - assert diskstation.api.photos is not None - item = SynoPhotosItem(image_id, "", "", "", cache_key, "", False) + item = SynoPhotosItem(image_id, "", "", "", cache_key, "", shared) try: image = await diskstation.api.photos.download_item(item) except SynologyDSMException as exc: diff --git a/tests/components/synology_dsm/test_media_source.py b/tests/components/synology_dsm/test_media_source.py index 2a792d174f8..433a4b15c23 100644 --- a/tests/components/synology_dsm/test_media_source.py +++ b/tests/components/synology_dsm/test_media_source.py @@ -50,7 +50,8 @@ def dsm_with_photos() -> MagicMock: dsm.photos.get_albums = AsyncMock(return_value=[SynoPhotosAlbum(1, "Album 1", 10)]) dsm.photos.get_items_from_album = AsyncMock( return_value=[ - SynoPhotosItem(10, "", "filename.jpg", 12345, "10_1298753", "sm", False) + SynoPhotosItem(10, "", "filename.jpg", 12345, "10_1298753", "sm", False), + SynoPhotosItem(10, "", "filename.jpg", 12345, "10_1298753", "sm", True), ] ) dsm.photos.get_item_thumbnail_url = AsyncMock( @@ -102,6 +103,11 @@ async def test_resolve_media_bad_identifier( "/synology_dsm/ABC012345/12631_47189/filename.png", "image/png", ), + ( + "ABC012345/12/12631_47189/filename.png_shared", + "/synology_dsm/ABC012345/12631_47189/filename.png_shared", + "image/png", + ), ], ) async def test_resolve_media_success( @@ -333,7 +339,7 @@ async def test_browse_media_get_items_thumbnail_error( result = await source.async_browse_media(item) assert result - assert len(result.children) == 1 + assert len(result.children) == 2 item = result.children[0] assert isinstance(item, BrowseMedia) assert item.thumbnail is None @@ -372,7 +378,7 @@ async def test_browse_media_get_items( result = await source.async_browse_media(item) assert result - assert len(result.children) == 1 + assert len(result.children) == 2 item = result.children[0] assert isinstance(item, BrowseMedia) assert item.identifier == "mocked_syno_dsm_entry/1/10_1298753/filename.jpg" @@ -382,6 +388,15 @@ async def test_browse_media_get_items( assert item.can_play assert not item.can_expand assert item.thumbnail == "http://my.thumbnail.url" + item = result.children[1] + assert isinstance(item, BrowseMedia) + assert item.identifier == "mocked_syno_dsm_entry/1/10_1298753/filename.jpg_shared" + assert item.title == "filename.jpg" + assert item.media_class == MediaClass.IMAGE + assert item.media_content_type == "image/jpeg" + assert item.can_play + assert not item.can_expand + assert item.thumbnail == "http://my.thumbnail.url" @pytest.mark.usefixtures("setup_media_source") @@ -435,3 +450,8 @@ async def test_media_view( request, "mocked_syno_dsm_entry", "10_1298753/filename.jpg" ) assert isinstance(result, web.Response) + with patch.object(tempfile, "tempdir", tmp_path): + result = await view.get( + request, "mocked_syno_dsm_entry", "10_1298753/filename.jpg_shared" + ) + assert isinstance(result, web.Response)