mirror of
https://github.com/home-assistant/core.git
synced 2025-07-09 06:17:07 +00:00
Make uploaded images browsable in media (#131468)
* Make uploaded images browsable in media * tests * Update homeassistant/components/image_upload/media_source.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * use executor * more executor * use thumbnail --------- Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
e8ced4fa12
commit
2c1a754e5d
76
homeassistant/components/image_upload/media_source.py
Normal file
76
homeassistant/components/image_upload/media_source.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
"""Expose image_upload as media sources."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from homeassistant.components.media_player import BrowseError, MediaClass
|
||||||
|
from homeassistant.components.media_source import (
|
||||||
|
BrowseMediaSource,
|
||||||
|
MediaSource,
|
||||||
|
MediaSourceItem,
|
||||||
|
PlayMedia,
|
||||||
|
Unresolvable,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
|
||||||
|
async def async_get_media_source(hass: HomeAssistant) -> ImageUploadMediaSource:
|
||||||
|
"""Set up image media source."""
|
||||||
|
return ImageUploadMediaSource(hass)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageUploadMediaSource(MediaSource):
|
||||||
|
"""Provide images as media sources."""
|
||||||
|
|
||||||
|
name: str = "Image Upload"
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant) -> None:
|
||||||
|
"""Initialize ImageMediaSource."""
|
||||||
|
super().__init__(DOMAIN)
|
||||||
|
self.hass = hass
|
||||||
|
|
||||||
|
async def async_resolve_media(self, item: MediaSourceItem) -> PlayMedia:
|
||||||
|
"""Resolve media to a url."""
|
||||||
|
image = self.hass.data[DOMAIN].data.get(item.identifier)
|
||||||
|
|
||||||
|
if not image:
|
||||||
|
raise Unresolvable(f"Could not resolve media item: {item.identifier}")
|
||||||
|
|
||||||
|
return PlayMedia(
|
||||||
|
f"/api/image/serve/{image['id']}/original", image["content_type"]
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_browse_media(
|
||||||
|
self,
|
||||||
|
item: MediaSourceItem,
|
||||||
|
) -> BrowseMediaSource:
|
||||||
|
"""Return media."""
|
||||||
|
if item.identifier:
|
||||||
|
raise BrowseError("Unknown item")
|
||||||
|
|
||||||
|
children = [
|
||||||
|
BrowseMediaSource(
|
||||||
|
domain=DOMAIN,
|
||||||
|
identifier=image["id"],
|
||||||
|
media_class=MediaClass.IMAGE,
|
||||||
|
media_content_type=image["content_type"],
|
||||||
|
title=image["name"],
|
||||||
|
thumbnail=f"/api/image/serve/{image['id']}/256x256",
|
||||||
|
can_play=True,
|
||||||
|
can_expand=False,
|
||||||
|
)
|
||||||
|
for image in self.hass.data[DOMAIN].data.values()
|
||||||
|
]
|
||||||
|
|
||||||
|
return BrowseMediaSource(
|
||||||
|
domain=DOMAIN,
|
||||||
|
identifier=None,
|
||||||
|
media_class=MediaClass.APP,
|
||||||
|
media_content_type="",
|
||||||
|
title="Image Upload",
|
||||||
|
can_play=False,
|
||||||
|
can_expand=True,
|
||||||
|
children_media_class=MediaClass.IMAGE,
|
||||||
|
children=children,
|
||||||
|
)
|
90
tests/components/image_upload/test_media_source.py
Normal file
90
tests/components/image_upload/test_media_source.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
"""Test image_upload media source."""
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from aiohttp import ClientSession
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components import media_source
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from . import TEST_IMAGE
|
||||||
|
|
||||||
|
from tests.typing import ClientSessionGenerator
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
async def setup_media_source(hass: HomeAssistant) -> None:
|
||||||
|
"""Set up media source."""
|
||||||
|
assert await async_setup_component(hass, "media_source", {})
|
||||||
|
|
||||||
|
|
||||||
|
async def __upload_test_image(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
hass_client: ClientSessionGenerator,
|
||||||
|
) -> str:
|
||||||
|
with (
|
||||||
|
tempfile.TemporaryDirectory() as tempdir,
|
||||||
|
patch.object(hass.config, "path", return_value=tempdir),
|
||||||
|
):
|
||||||
|
assert await async_setup_component(hass, "image_upload", {})
|
||||||
|
client: ClientSession = await hass_client()
|
||||||
|
|
||||||
|
file = await hass.async_add_executor_job(TEST_IMAGE.open, "rb")
|
||||||
|
res = await client.post("/api/image/upload", data={"file": file})
|
||||||
|
hass.async_add_executor_job(file.close)
|
||||||
|
|
||||||
|
assert res.status == 200
|
||||||
|
item = await res.json()
|
||||||
|
assert item["content_type"] == "image/png"
|
||||||
|
assert item["filesize"] == 38847
|
||||||
|
return item["id"]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_browsing(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
hass_client: ClientSessionGenerator,
|
||||||
|
) -> None:
|
||||||
|
"""Test browsing image media source."""
|
||||||
|
image_id = await __upload_test_image(hass, hass_client)
|
||||||
|
|
||||||
|
item = await media_source.async_browse_media(hass, "media-source://image_upload")
|
||||||
|
|
||||||
|
assert item is not None
|
||||||
|
assert item.title == "Image Upload"
|
||||||
|
assert len(item.children) == 1
|
||||||
|
assert item.children[0].media_content_type == "image/png"
|
||||||
|
assert item.children[0].identifier == image_id
|
||||||
|
assert item.children[0].thumbnail == f"/api/image/serve/{image_id}/256x256"
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
media_source.BrowseError,
|
||||||
|
match="Unknown item",
|
||||||
|
):
|
||||||
|
await media_source.async_browse_media(
|
||||||
|
hass, "media-source://image_upload/invalid_path"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_resolving(
|
||||||
|
hass: HomeAssistant, hass_client: ClientSessionGenerator
|
||||||
|
) -> None:
|
||||||
|
"""Test resolving."""
|
||||||
|
image_id = await __upload_test_image(hass, hass_client)
|
||||||
|
item = await media_source.async_resolve_media(
|
||||||
|
hass, f"media-source://image_upload/{image_id}", None
|
||||||
|
)
|
||||||
|
assert item is not None
|
||||||
|
assert item.url == f"/api/image/serve/{image_id}/original"
|
||||||
|
assert item.mime_type == "image/png"
|
||||||
|
|
||||||
|
invalid_id = "aabbccddeeff"
|
||||||
|
with pytest.raises(
|
||||||
|
media_source.Unresolvable,
|
||||||
|
match=f"Could not resolve media item: {invalid_id}",
|
||||||
|
):
|
||||||
|
await media_source.async_resolve_media(
|
||||||
|
hass, f"media-source://image_upload/{invalid_id}", None
|
||||||
|
)
|
Loading…
x
Reference in New Issue
Block a user