mirror of
https://github.com/home-assistant/core.git
synced 2025-07-04 20:07:10 +00:00
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:
parent
59ade9cf93
commit
c0a680a80a
@ -46,6 +46,8 @@ DEFAULT_SNAPSHOT_QUALITY = SNAPSHOT_PROFILE_BALANCED
|
|||||||
|
|
||||||
ENTITY_UNIT_LOAD = "load"
|
ENTITY_UNIT_LOAD = "load"
|
||||||
|
|
||||||
|
SHARED_SUFFIX = "_shared"
|
||||||
|
|
||||||
# Signals
|
# Signals
|
||||||
SIGNAL_CAMERA_SOURCE_CHANGED = "synology_dsm.camera_stream_source_changed"
|
SIGNAL_CAMERA_SOURCE_CHANGED = "synology_dsm.camera_stream_source_changed"
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ from homeassistant.components.media_source import (
|
|||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN, SHARED_SUFFIX
|
||||||
from .models import SynologyDSMData
|
from .models import SynologyDSMData
|
||||||
|
|
||||||
|
|
||||||
@ -45,6 +45,7 @@ class SynologyPhotosMediaSourceIdentifier:
|
|||||||
self.album_id = None
|
self.album_id = None
|
||||||
self.cache_key = None
|
self.cache_key = None
|
||||||
self.file_name = None
|
self.file_name = None
|
||||||
|
self.is_shared = False
|
||||||
|
|
||||||
if parts:
|
if parts:
|
||||||
self.unique_id = parts[0]
|
self.unique_id = parts[0]
|
||||||
@ -54,6 +55,9 @@ class SynologyPhotosMediaSourceIdentifier:
|
|||||||
self.cache_key = parts[2]
|
self.cache_key = parts[2]
|
||||||
if len(parts) > 3:
|
if len(parts) > 3:
|
||||||
self.file_name = 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):
|
class SynologyPhotosMediaSource(MediaSource):
|
||||||
@ -160,10 +164,13 @@ class SynologyPhotosMediaSource(MediaSource):
|
|||||||
if isinstance(mime_type, str) and mime_type.startswith("image/"):
|
if isinstance(mime_type, str) and mime_type.startswith("image/"):
|
||||||
# Force small small thumbnails
|
# Force small small thumbnails
|
||||||
album_item.thumbnail_size = "sm"
|
album_item.thumbnail_size = "sm"
|
||||||
|
suffix = ""
|
||||||
|
if album_item.is_shared:
|
||||||
|
suffix = SHARED_SUFFIX
|
||||||
ret.append(
|
ret.append(
|
||||||
BrowseMediaSource(
|
BrowseMediaSource(
|
||||||
domain=DOMAIN,
|
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_class=MediaClass.IMAGE,
|
||||||
media_content_type=mime_type,
|
media_content_type=mime_type,
|
||||||
title=album_item.file_name,
|
title=album_item.file_name,
|
||||||
@ -186,8 +193,11 @@ class SynologyPhotosMediaSource(MediaSource):
|
|||||||
mime_type, _ = mimetypes.guess_type(identifier.file_name)
|
mime_type, _ = mimetypes.guess_type(identifier.file_name)
|
||||||
if not isinstance(mime_type, str):
|
if not isinstance(mime_type, str):
|
||||||
raise Unresolvable("No file extension")
|
raise Unresolvable("No file extension")
|
||||||
|
suffix = ""
|
||||||
|
if identifier.is_shared:
|
||||||
|
suffix = SHARED_SUFFIX
|
||||||
return PlayMedia(
|
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,
|
mime_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -223,13 +233,14 @@ class SynologyDsmMediaView(http.HomeAssistantView):
|
|||||||
# location: {cache_key}/{filename}
|
# location: {cache_key}/{filename}
|
||||||
cache_key, file_name = location.split("/")
|
cache_key, file_name = location.split("/")
|
||||||
image_id = int(cache_key.split("_")[0])
|
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)
|
mime_type, _ = mimetypes.guess_type(file_name)
|
||||||
if not isinstance(mime_type, str):
|
if not isinstance(mime_type, str):
|
||||||
raise web.HTTPNotFound
|
raise web.HTTPNotFound
|
||||||
diskstation: SynologyDSMData = self.hass.data[DOMAIN][source_dir_id]
|
diskstation: SynologyDSMData = self.hass.data[DOMAIN][source_dir_id]
|
||||||
|
|
||||||
assert diskstation.api.photos is not None
|
assert diskstation.api.photos is not None
|
||||||
item = SynoPhotosItem(image_id, "", "", "", cache_key, "", False)
|
item = SynoPhotosItem(image_id, "", "", "", cache_key, "", shared)
|
||||||
try:
|
try:
|
||||||
image = await diskstation.api.photos.download_item(item)
|
image = await diskstation.api.photos.download_item(item)
|
||||||
except SynologyDSMException as exc:
|
except SynologyDSMException as exc:
|
||||||
|
@ -50,7 +50,8 @@ def dsm_with_photos() -> MagicMock:
|
|||||||
dsm.photos.get_albums = AsyncMock(return_value=[SynoPhotosAlbum(1, "Album 1", 10)])
|
dsm.photos.get_albums = AsyncMock(return_value=[SynoPhotosAlbum(1, "Album 1", 10)])
|
||||||
dsm.photos.get_items_from_album = AsyncMock(
|
dsm.photos.get_items_from_album = AsyncMock(
|
||||||
return_value=[
|
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(
|
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",
|
"/synology_dsm/ABC012345/12631_47189/filename.png",
|
||||||
"image/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(
|
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)
|
result = await source.async_browse_media(item)
|
||||||
|
|
||||||
assert result
|
assert result
|
||||||
assert len(result.children) == 1
|
assert len(result.children) == 2
|
||||||
item = result.children[0]
|
item = result.children[0]
|
||||||
assert isinstance(item, BrowseMedia)
|
assert isinstance(item, BrowseMedia)
|
||||||
assert item.thumbnail is None
|
assert item.thumbnail is None
|
||||||
@ -372,7 +378,7 @@ async def test_browse_media_get_items(
|
|||||||
result = await source.async_browse_media(item)
|
result = await source.async_browse_media(item)
|
||||||
|
|
||||||
assert result
|
assert result
|
||||||
assert len(result.children) == 1
|
assert len(result.children) == 2
|
||||||
item = result.children[0]
|
item = result.children[0]
|
||||||
assert isinstance(item, BrowseMedia)
|
assert isinstance(item, BrowseMedia)
|
||||||
assert item.identifier == "mocked_syno_dsm_entry/1/10_1298753/filename.jpg"
|
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 item.can_play
|
||||||
assert not item.can_expand
|
assert not item.can_expand
|
||||||
assert item.thumbnail == "http://my.thumbnail.url"
|
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")
|
@pytest.mark.usefixtures("setup_media_source")
|
||||||
@ -435,3 +450,8 @@ async def test_media_view(
|
|||||||
request, "mocked_syno_dsm_entry", "10_1298753/filename.jpg"
|
request, "mocked_syno_dsm_entry", "10_1298753/filename.jpg"
|
||||||
)
|
)
|
||||||
assert isinstance(result, web.Response)
|
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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user