Fix for Synology DSM shared images (#117695)

* Fix for shared images

* - FIX: Synology shared photos

* - changes after review

* Added test

* added test

* fix test
This commit is contained in:
Lode Smets 2024-06-16 00:48:08 +02:00 committed by GitHub
parent 59ade9cf93
commit c0a680a80a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 41 additions and 8 deletions

View File

@ -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"

View File

@ -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:

View File

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