mirror of
https://github.com/home-assistant/core.git
synced 2025-07-26 06:37:52 +00:00
Add level of collections in Immich media source tree (#145734)
* add layer for collections in media source tree * re-arange tests, add test for collection layer * fix
This commit is contained in:
parent
2708c1c94c
commit
afa97f8ec1
@ -40,11 +40,12 @@ class ImmichMediaSourceIdentifier:
|
|||||||
def __init__(self, identifier: str) -> None:
|
def __init__(self, identifier: str) -> None:
|
||||||
"""Split identifier into parts."""
|
"""Split identifier into parts."""
|
||||||
parts = identifier.split("/")
|
parts = identifier.split("/")
|
||||||
# coonfig_entry.unique_id/album_id/asset_it/filename
|
# config_entry.unique_id/collection/collection_id/asset_id/file_name
|
||||||
self.unique_id = parts[0]
|
self.unique_id = parts[0]
|
||||||
self.album_id = parts[1] if len(parts) > 1 else None
|
self.collection = parts[1] if len(parts) > 1 else None
|
||||||
self.asset_id = parts[2] if len(parts) > 2 else None
|
self.collection_id = parts[2] if len(parts) > 2 else None
|
||||||
self.file_name = parts[3] if len(parts) > 2 else None
|
self.asset_id = parts[3] if len(parts) > 3 else None
|
||||||
|
self.file_name = parts[4] if len(parts) > 3 else None
|
||||||
|
|
||||||
|
|
||||||
class ImmichMediaSource(MediaSource):
|
class ImmichMediaSource(MediaSource):
|
||||||
@ -83,6 +84,7 @@ class ImmichMediaSource(MediaSource):
|
|||||||
) -> list[BrowseMediaSource]:
|
) -> list[BrowseMediaSource]:
|
||||||
"""Handle browsing different immich instances."""
|
"""Handle browsing different immich instances."""
|
||||||
if not item.identifier:
|
if not item.identifier:
|
||||||
|
LOGGER.debug("Render all Immich instances")
|
||||||
return [
|
return [
|
||||||
BrowseMediaSource(
|
BrowseMediaSource(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
@ -104,8 +106,22 @@ class ImmichMediaSource(MediaSource):
|
|||||||
assert entry
|
assert entry
|
||||||
immich_api = entry.runtime_data.api
|
immich_api = entry.runtime_data.api
|
||||||
|
|
||||||
if identifier.album_id is None:
|
if identifier.collection is None:
|
||||||
# Get Albums
|
LOGGER.debug("Render all collections for %s", entry.title)
|
||||||
|
return [
|
||||||
|
BrowseMediaSource(
|
||||||
|
domain=DOMAIN,
|
||||||
|
identifier=f"{identifier.unique_id}/albums",
|
||||||
|
media_class=MediaClass.DIRECTORY,
|
||||||
|
media_content_type=MediaClass.IMAGE,
|
||||||
|
title="albums",
|
||||||
|
can_play=False,
|
||||||
|
can_expand=True,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
if identifier.collection_id is None:
|
||||||
|
LOGGER.debug("Render all albums for %s", entry.title)
|
||||||
try:
|
try:
|
||||||
albums = await immich_api.albums.async_get_all_albums()
|
albums = await immich_api.albums.async_get_all_albums()
|
||||||
except ImmichError:
|
except ImmichError:
|
||||||
@ -114,7 +130,7 @@ class ImmichMediaSource(MediaSource):
|
|||||||
return [
|
return [
|
||||||
BrowseMediaSource(
|
BrowseMediaSource(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
identifier=f"{item.identifier}/{album.album_id}",
|
identifier=f"{identifier.unique_id}/albums/{album.album_id}",
|
||||||
media_class=MediaClass.DIRECTORY,
|
media_class=MediaClass.DIRECTORY,
|
||||||
media_content_type=MediaClass.IMAGE,
|
media_content_type=MediaClass.IMAGE,
|
||||||
title=album.name,
|
title=album.name,
|
||||||
@ -125,10 +141,14 @@ class ImmichMediaSource(MediaSource):
|
|||||||
for album in albums
|
for album in albums
|
||||||
]
|
]
|
||||||
|
|
||||||
# Request items of album
|
LOGGER.debug(
|
||||||
|
"Render all assets of album %s for %s",
|
||||||
|
identifier.collection_id,
|
||||||
|
entry.title,
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
album_info = await immich_api.albums.async_get_album_info(
|
album_info = await immich_api.albums.async_get_album_info(
|
||||||
identifier.album_id
|
identifier.collection_id
|
||||||
)
|
)
|
||||||
except ImmichError:
|
except ImmichError:
|
||||||
return []
|
return []
|
||||||
@ -137,8 +157,8 @@ class ImmichMediaSource(MediaSource):
|
|||||||
BrowseMediaSource(
|
BrowseMediaSource(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
identifier=(
|
identifier=(
|
||||||
f"{identifier.unique_id}/"
|
f"{identifier.unique_id}/albums/"
|
||||||
f"{identifier.album_id}/"
|
f"{identifier.collection_id}/"
|
||||||
f"{asset.asset_id}/"
|
f"{asset.asset_id}/"
|
||||||
f"{asset.file_name}"
|
f"{asset.file_name}"
|
||||||
),
|
),
|
||||||
@ -157,8 +177,8 @@ class ImmichMediaSource(MediaSource):
|
|||||||
BrowseMediaSource(
|
BrowseMediaSource(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
identifier=(
|
identifier=(
|
||||||
f"{identifier.unique_id}/"
|
f"{identifier.unique_id}/albums/"
|
||||||
f"{identifier.album_id}/"
|
f"{identifier.collection_id}/"
|
||||||
f"{asset.asset_id}/"
|
f"{asset.asset_id}/"
|
||||||
f"{asset.file_name}"
|
f"{asset.file_name}"
|
||||||
),
|
),
|
||||||
|
@ -44,8 +44,8 @@ async def test_get_media_source(hass: HomeAssistant) -> None:
|
|||||||
("identifier", "exception_msg"),
|
("identifier", "exception_msg"),
|
||||||
[
|
[
|
||||||
("unique_id", "No file name"),
|
("unique_id", "No file name"),
|
||||||
("unique_id/album_id", "No file name"),
|
("unique_id/albums/album_id", "No file name"),
|
||||||
("unique_id/album_id/asset_id/filename", "No file extension"),
|
("unique_id/albums/album_id/asset_id/filename", "No file extension"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_resolve_media_bad_identifier(
|
async def test_resolve_media_bad_identifier(
|
||||||
@ -64,12 +64,12 @@ async def test_resolve_media_bad_identifier(
|
|||||||
("identifier", "url", "mime_type"),
|
("identifier", "url", "mime_type"),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"unique_id/album_id/asset_id/filename.jpg",
|
"unique_id/albums/album_id/asset_id/filename.jpg",
|
||||||
"/immich/unique_id/asset_id/filename.jpg/fullsize",
|
"/immich/unique_id/asset_id/filename.jpg/fullsize",
|
||||||
"image/jpeg",
|
"image/jpeg",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"unique_id/album_id/asset_id/filename.png",
|
"unique_id/albums/album_id/asset_id/filename.png",
|
||||||
"/immich/unique_id/asset_id/filename.png/fullsize",
|
"/immich/unique_id/asset_id/filename.png/fullsize",
|
||||||
"image/png",
|
"image/png",
|
||||||
),
|
),
|
||||||
@ -95,13 +95,82 @@ async def test_browse_media_unconfigured(hass: HomeAssistant) -> None:
|
|||||||
|
|
||||||
source = await async_get_media_source(hass)
|
source = await async_get_media_source(hass)
|
||||||
item = MediaSourceItem(
|
item = MediaSourceItem(
|
||||||
hass, DOMAIN, "unique_id/album_id/asset_id/filename.png", None
|
hass, DOMAIN, "unique_id/albums/album_id/asset_id/filename.png", None
|
||||||
)
|
)
|
||||||
with pytest.raises(BrowseError, match="Immich is not configured"):
|
with pytest.raises(BrowseError, match="Immich is not configured"):
|
||||||
await source.async_browse_media(item)
|
await source.async_browse_media(item)
|
||||||
|
|
||||||
|
|
||||||
async def test_browse_media_album_error(
|
async def test_browse_media_get_root(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_immich: Mock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test browse_media returning root media sources."""
|
||||||
|
assert await async_setup_component(hass, "media_source", {})
|
||||||
|
|
||||||
|
with patch("homeassistant.components.immich.PLATFORMS", []):
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
source = await async_get_media_source(hass)
|
||||||
|
|
||||||
|
# get root
|
||||||
|
item = MediaSourceItem(hass, DOMAIN, "", None)
|
||||||
|
result = await source.async_browse_media(item)
|
||||||
|
|
||||||
|
assert result
|
||||||
|
assert len(result.children) == 1
|
||||||
|
media_file = result.children[0]
|
||||||
|
assert isinstance(media_file, BrowseMedia)
|
||||||
|
assert media_file.title == "Someone"
|
||||||
|
assert media_file.media_content_id == (
|
||||||
|
"media-source://immich/e7ef5713-9dab-4bd4-b899-715b0ca4379e"
|
||||||
|
)
|
||||||
|
|
||||||
|
# get collections
|
||||||
|
item = MediaSourceItem(hass, DOMAIN, "e7ef5713-9dab-4bd4-b899-715b0ca4379e", None)
|
||||||
|
result = await source.async_browse_media(item)
|
||||||
|
|
||||||
|
assert result
|
||||||
|
assert len(result.children) == 1
|
||||||
|
media_file = result.children[0]
|
||||||
|
assert isinstance(media_file, BrowseMedia)
|
||||||
|
assert media_file.title == "albums"
|
||||||
|
assert media_file.media_content_id == (
|
||||||
|
"media-source://immich/e7ef5713-9dab-4bd4-b899-715b0ca4379e/albums"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_browse_media_get_albums(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_immich: Mock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test browse_media returning albums."""
|
||||||
|
assert await async_setup_component(hass, "media_source", {})
|
||||||
|
|
||||||
|
with patch("homeassistant.components.immich.PLATFORMS", []):
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
source = await async_get_media_source(hass)
|
||||||
|
item = MediaSourceItem(
|
||||||
|
hass, DOMAIN, "e7ef5713-9dab-4bd4-b899-715b0ca4379e/albums", None
|
||||||
|
)
|
||||||
|
result = await source.async_browse_media(item)
|
||||||
|
|
||||||
|
assert result
|
||||||
|
assert len(result.children) == 1
|
||||||
|
media_file = result.children[0]
|
||||||
|
assert isinstance(media_file, BrowseMedia)
|
||||||
|
assert media_file.title == "My Album"
|
||||||
|
assert media_file.media_content_id == (
|
||||||
|
"media-source://immich/"
|
||||||
|
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/albums/"
|
||||||
|
"721e1a4b-aa12-441e-8d3b-5ac7ab283bb6"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_browse_media_get_albums_error(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_immich: Mock,
|
mock_immich: Mock,
|
||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
@ -124,7 +193,7 @@ async def test_browse_media_album_error(
|
|||||||
|
|
||||||
source = await async_get_media_source(hass)
|
source = await async_get_media_source(hass)
|
||||||
|
|
||||||
item = MediaSourceItem(hass, DOMAIN, mock_config_entry.unique_id, None)
|
item = MediaSourceItem(hass, DOMAIN, f"{mock_config_entry.unique_id}/albums", None)
|
||||||
result = await source.async_browse_media(item)
|
result = await source.async_browse_media(item)
|
||||||
|
|
||||||
assert result
|
assert result
|
||||||
@ -132,59 +201,7 @@ async def test_browse_media_album_error(
|
|||||||
assert len(result.children) == 0
|
assert len(result.children) == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_browse_media_get_root(
|
async def test_browse_media_get_album_items_error(
|
||||||
hass: HomeAssistant,
|
|
||||||
mock_immich: Mock,
|
|
||||||
mock_config_entry: MockConfigEntry,
|
|
||||||
) -> None:
|
|
||||||
"""Test browse_media returning root media sources."""
|
|
||||||
assert await async_setup_component(hass, "media_source", {})
|
|
||||||
|
|
||||||
with patch("homeassistant.components.immich.PLATFORMS", []):
|
|
||||||
await setup_integration(hass, mock_config_entry)
|
|
||||||
|
|
||||||
source = await async_get_media_source(hass)
|
|
||||||
item = MediaSourceItem(hass, DOMAIN, "", None)
|
|
||||||
result = await source.async_browse_media(item)
|
|
||||||
|
|
||||||
assert result
|
|
||||||
assert len(result.children) == 1
|
|
||||||
media_file = result.children[0]
|
|
||||||
assert isinstance(media_file, BrowseMedia)
|
|
||||||
assert media_file.title == "Someone"
|
|
||||||
assert media_file.media_content_id == (
|
|
||||||
"media-source://immich/e7ef5713-9dab-4bd4-b899-715b0ca4379e"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_browse_media_get_albums(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
mock_immich: Mock,
|
|
||||||
mock_config_entry: MockConfigEntry,
|
|
||||||
) -> None:
|
|
||||||
"""Test browse_media returning albums."""
|
|
||||||
assert await async_setup_component(hass, "media_source", {})
|
|
||||||
|
|
||||||
with patch("homeassistant.components.immich.PLATFORMS", []):
|
|
||||||
await setup_integration(hass, mock_config_entry)
|
|
||||||
|
|
||||||
source = await async_get_media_source(hass)
|
|
||||||
item = MediaSourceItem(hass, DOMAIN, "e7ef5713-9dab-4bd4-b899-715b0ca4379e", None)
|
|
||||||
result = await source.async_browse_media(item)
|
|
||||||
|
|
||||||
assert result
|
|
||||||
assert len(result.children) == 1
|
|
||||||
media_file = result.children[0]
|
|
||||||
assert isinstance(media_file, BrowseMedia)
|
|
||||||
assert media_file.title == "My Album"
|
|
||||||
assert media_file.media_content_id == (
|
|
||||||
"media-source://immich/"
|
|
||||||
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/"
|
|
||||||
"721e1a4b-aa12-441e-8d3b-5ac7ab283bb6"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_browse_media_get_items_error(
|
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_immich: Mock,
|
mock_immich: Mock,
|
||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
@ -202,7 +219,7 @@ async def test_browse_media_get_items_error(
|
|||||||
item = MediaSourceItem(
|
item = MediaSourceItem(
|
||||||
hass,
|
hass,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/721e1a4b-aa12-441e-8d3b-5ac7ab283bb6",
|
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/albums/721e1a4b-aa12-441e-8d3b-5ac7ab283bb6",
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
result = await source.async_browse_media(item)
|
result = await source.async_browse_media(item)
|
||||||
@ -223,7 +240,7 @@ async def test_browse_media_get_items_error(
|
|||||||
item = MediaSourceItem(
|
item = MediaSourceItem(
|
||||||
hass,
|
hass,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/721e1a4b-aa12-441e-8d3b-5ac7ab283bb6",
|
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/albums/721e1a4b-aa12-441e-8d3b-5ac7ab283bb6",
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
result = await source.async_browse_media(item)
|
result = await source.async_browse_media(item)
|
||||||
@ -233,7 +250,7 @@ async def test_browse_media_get_items_error(
|
|||||||
assert len(result.children) == 0
|
assert len(result.children) == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_browse_media_get_items(
|
async def test_browse_media_get_album_items(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_immich: Mock,
|
mock_immich: Mock,
|
||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
@ -249,7 +266,7 @@ async def test_browse_media_get_items(
|
|||||||
item = MediaSourceItem(
|
item = MediaSourceItem(
|
||||||
hass,
|
hass,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/721e1a4b-aa12-441e-8d3b-5ac7ab283bb6",
|
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/albums/721e1a4b-aa12-441e-8d3b-5ac7ab283bb6",
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
result = await source.async_browse_media(item)
|
result = await source.async_browse_media(item)
|
||||||
@ -259,7 +276,7 @@ async def test_browse_media_get_items(
|
|||||||
media_file = result.children[0]
|
media_file = result.children[0]
|
||||||
assert isinstance(media_file, BrowseMedia)
|
assert isinstance(media_file, BrowseMedia)
|
||||||
assert media_file.identifier == (
|
assert media_file.identifier == (
|
||||||
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/"
|
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/albums/"
|
||||||
"721e1a4b-aa12-441e-8d3b-5ac7ab283bb6/"
|
"721e1a4b-aa12-441e-8d3b-5ac7ab283bb6/"
|
||||||
"2e94c203-50aa-4ad2-8e29-56dd74e0eff4/filename.jpg"
|
"2e94c203-50aa-4ad2-8e29-56dd74e0eff4/filename.jpg"
|
||||||
)
|
)
|
||||||
@ -276,7 +293,7 @@ async def test_browse_media_get_items(
|
|||||||
media_file = result.children[1]
|
media_file = result.children[1]
|
||||||
assert isinstance(media_file, BrowseMedia)
|
assert isinstance(media_file, BrowseMedia)
|
||||||
assert media_file.identifier == (
|
assert media_file.identifier == (
|
||||||
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/"
|
"e7ef5713-9dab-4bd4-b899-715b0ca4379e/albums/"
|
||||||
"721e1a4b-aa12-441e-8d3b-5ac7ab283bb6/"
|
"721e1a4b-aa12-441e-8d3b-5ac7ab283bb6/"
|
||||||
"2e65a5f2-db83-44c4-81ab-f5ff20c9bd7b/filename.mp4"
|
"2e65a5f2-db83-44c4-81ab-f5ff20c9bd7b/filename.mp4"
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user