From 4f0c07211a12f35b1ef089a41c32c1978de4d5d0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 23 Apr 2019 20:41:27 -0700 Subject: [PATCH 1/6] Add media player external url --- .../components/media_player/__init__.py | 22 +++++- tests/components/media_player/test_init.py | 70 ++++++++++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 7dcfdac52179f..5d938c1be3505 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -64,6 +64,7 @@ CACHE_MAXSIZE: 16 } +TYPE_URL = 'text/url' SCAN_INTERVAL = timedelta(seconds=10) # Service call validation schemas @@ -324,6 +325,11 @@ def media_image_url(self): """Image url of current playing media.""" return None + @property + def media_image_remotely_accessible(self): + """If the image url is remotely accessible.""" + return None + @property def media_image_hash(self): """Hash value for media image.""" @@ -336,8 +342,11 @@ def media_image_hash(self): async def async_get_media_image(self): """Fetch media image of current playing image.""" url = self.media_image_url + if url is None: return None, None + elif self.media_image_remotely_accessible: + return url, TYPE_URL return await _async_fetch_image(self.hass, url) @@ -722,6 +731,9 @@ def entity_picture(self): if self.state == STATE_OFF: return None + if self.media_image_remotely_accessible: + return self.media_image_url + image_hash = self.media_image_hash if image_hash is None: @@ -813,6 +825,11 @@ async def get(self, request, entity_id): if data is None: return web.Response(status=500) + if content_type == TYPE_URL: + return web.Response(status=301, headers={ + 'location': data + }) + headers = {CACHE_CONTROL: 'max-age=3600'} return web.Response( body=data, content_type=content_type, headers=headers) @@ -840,8 +857,11 @@ async def websocket_handle_thumbnail(hass, connection, msg): 'Failed to fetch thumbnail')) return + if content_type != TYPE_URL: + data = base64.b64encode(data).decode('utf-8') + connection.send_message(websocket_api.result_message( msg['id'], { 'content_type': content_type, - 'content': base64.b64encode(data).decode('utf-8') + 'content': data })) diff --git a/tests/components/media_player/test_init.py b/tests/components/media_player/test_init.py index 808c6e4f50fa7..8148d6e5eb66b 100644 --- a/tests/components/media_player/test_init.py +++ b/tests/components/media_player/test_init.py @@ -4,12 +4,13 @@ from homeassistant.setup import async_setup_component from homeassistant.components.websocket_api.const import TYPE_RESULT +from homeassistant.components import media_player from tests.common import mock_coro -async def test_get_panels(hass, hass_ws_client): - """Test get_panels command.""" +async def test_get_image(hass, hass_ws_client): + """Test get image via WS command.""" await async_setup_component(hass, 'media_player', { 'media_player': { 'platform': 'demo' @@ -35,3 +36,68 @@ async def test_get_panels(hass, hass_ws_client): assert msg['result']['content_type'] == 'image/jpeg' assert msg['result']['content'] == \ base64.b64encode(b'image').decode('utf-8') + + +async def test_get_image_url(hass, hass_ws_client): + """Test get image url via WS command.""" + await async_setup_component(hass, 'media_player', { + 'media_player': { + 'platform': 'demo' + } + }) + + client = await hass_ws_client(hass) + + with patch('homeassistant.components.media_player.MediaPlayerDevice.' + 'async_get_media_image', return_value=mock_coro( + ('https://www.home-assistant.io', media_player.TYPE_URL))): + await client.send_json({ + 'id': 5, + 'type': 'media_player_thumbnail', + 'entity_id': 'media_player.bedroom', + }) + + msg = await client.receive_json() + + assert msg['id'] == 5 + assert msg['type'] == TYPE_RESULT + assert msg['success'] + assert msg['result']['content_type'] == 'text/url' + assert msg['result']['content'] == 'https://www.home-assistant.io' + + +async def test_get_image_http(hass, hass_client): + """Test get image via http command.""" + await async_setup_component(hass, 'media_player', { + 'media_player': { + 'platform': 'demo' + } + }) + + client = await hass_client() + + with patch('homeassistant.components.media_player.MediaPlayerDevice.' + 'async_get_media_image', return_value=mock_coro( + (b'image', 'image/jpeg'))): + resp = await client.get('/api/media_player_proxy/media_player.bedroom') + content = await resp.read() + + assert content == b'image' + + +async def test_get_image_http_url(hass, hass_client): + """Test get image url via http command.""" + await async_setup_component(hass, 'media_player', { + 'media_player': { + 'platform': 'demo' + } + }) + + client = await hass_client() + + with patch('homeassistant.components.media_player.MediaPlayerDevice.' + 'async_get_media_image', return_value=mock_coro( + ('https://www.home-assistant.io', media_player.TYPE_URL))): + resp = await client.get('/api/media_player_proxy/media_player.bedroom', + allow_redirects=False) + assert resp.headers['Location'] == 'https://www.home-assistant.io' From e601b583aab630392c1d2698bac096d1f07a5305 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 23 Apr 2019 23:52:46 -0700 Subject: [PATCH 2/6] Lint --- homeassistant/components/media_player/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 5d938c1be3505..cbe0ffafc2d92 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -345,7 +345,8 @@ async def async_get_media_image(self): if url is None: return None, None - elif self.media_image_remotely_accessible: + + if self.media_image_remotely_accessible: return url, TYPE_URL return await _async_fetch_image(self.hass, url) From 331422fe7eb51c9250eb9e6f8a2e54b9f6335dc5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 24 Apr 2019 13:15:32 -0700 Subject: [PATCH 3/6] Simplify --- homeassistant/components/cast/media_player.py | 5 +++ .../components/media_player/__init__.py | 20 +++++------ tests/components/media_player/test_init.py | 35 ++----------------- 3 files changed, 18 insertions(+), 42 deletions(-) diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index 4b2972b0c002e..0a1406adceec4 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -1046,6 +1046,11 @@ def media_image_url(self): return images[0].url if images and images[0].url else None + @property + def media_image_remotely_accessible(self) -> bool: + """If the image url is remotely accessible.""" + return True + @property def media_title(self): """Title of current playing media.""" diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index cbe0ffafc2d92..baabb49d43867 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -326,9 +326,9 @@ def media_image_url(self): return None @property - def media_image_remotely_accessible(self): + def media_image_remotely_accessible(self) -> bool: """If the image url is remotely accessible.""" - return None + return False @property def media_image_hash(self): @@ -346,9 +346,6 @@ async def async_get_media_image(self): if url is None: return None, None - if self.media_image_remotely_accessible: - return url, TYPE_URL - return await _async_fetch_image(self.hass, url) @property @@ -821,16 +818,19 @@ async def get(self, request, entity_id): if not authenticated: return web.Response(status=401) + if player.media_image_remotely_accessible: + url = player.media_image_url + if url is not None: + return web.Response(status=301, headers={ + 'location': url + }) + return web.Response(status=500) + data, content_type = await player.async_get_media_image() if data is None: return web.Response(status=500) - if content_type == TYPE_URL: - return web.Response(status=301, headers={ - 'location': data - }) - headers = {CACHE_CONTROL: 'max-age=3600'} return web.Response( body=data, content_type=content_type, headers=headers) diff --git a/tests/components/media_player/test_init.py b/tests/components/media_player/test_init.py index 8148d6e5eb66b..23deffa972a2e 100644 --- a/tests/components/media_player/test_init.py +++ b/tests/components/media_player/test_init.py @@ -4,7 +4,6 @@ from homeassistant.setup import async_setup_component from homeassistant.components.websocket_api.const import TYPE_RESULT -from homeassistant.components import media_player from tests.common import mock_coro @@ -38,34 +37,6 @@ async def test_get_image(hass, hass_ws_client): base64.b64encode(b'image').decode('utf-8') -async def test_get_image_url(hass, hass_ws_client): - """Test get image url via WS command.""" - await async_setup_component(hass, 'media_player', { - 'media_player': { - 'platform': 'demo' - } - }) - - client = await hass_ws_client(hass) - - with patch('homeassistant.components.media_player.MediaPlayerDevice.' - 'async_get_media_image', return_value=mock_coro( - ('https://www.home-assistant.io', media_player.TYPE_URL))): - await client.send_json({ - 'id': 5, - 'type': 'media_player_thumbnail', - 'entity_id': 'media_player.bedroom', - }) - - msg = await client.receive_json() - - assert msg['id'] == 5 - assert msg['type'] == TYPE_RESULT - assert msg['success'] - assert msg['result']['content_type'] == 'text/url' - assert msg['result']['content'] == 'https://www.home-assistant.io' - - async def test_get_image_http(hass, hass_client): """Test get image via http command.""" await async_setup_component(hass, 'media_player', { @@ -96,8 +67,8 @@ async def test_get_image_http_url(hass, hass_client): client = await hass_client() with patch('homeassistant.components.media_player.MediaPlayerDevice.' - 'async_get_media_image', return_value=mock_coro( - ('https://www.home-assistant.io', media_player.TYPE_URL))): + 'media_image_remotely_accessible', return_value=True): resp = await client.get('/api/media_player_proxy/media_player.bedroom', allow_redirects=False) - assert resp.headers['Location'] == 'https://www.home-assistant.io' + assert resp.headers['Location'] == \ + 'https://img.youtube.com/vi/kxopViU98Xo/hqdefault.jpg' From 3f8def94401f54d7620e040bcf1dd5fd2c70951c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 24 Apr 2019 13:44:02 -0700 Subject: [PATCH 4/6] Update __init__.py --- homeassistant/components/media_player/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index baabb49d43867..e6691b98dce62 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -64,7 +64,6 @@ CACHE_MAXSIZE: 16 } -TYPE_URL = 'text/url' SCAN_INTERVAL = timedelta(seconds=10) # Service call validation schemas From 07d7c65c88d6a5752cceb6d12def1bb0ff55618b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 24 Apr 2019 13:45:16 -0700 Subject: [PATCH 5/6] Update __init__.py --- homeassistant/components/media_player/__init__.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index e6691b98dce62..41b3f2010ea1d 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -341,7 +341,6 @@ def media_image_hash(self): async def async_get_media_image(self): """Fetch media image of current playing image.""" url = self.media_image_url - if url is None: return None, None @@ -857,11 +856,8 @@ async def websocket_handle_thumbnail(hass, connection, msg): 'Failed to fetch thumbnail')) return - if content_type != TYPE_URL: - data = base64.b64encode(data).decode('utf-8') - connection.send_message(websocket_api.result_message( msg['id'], { 'content_type': content_type, - 'content': data + 'content': base64.b64encode(data).decode('utf-8') })) From c1054aeb97f9f8fc3071341012f313e79f426e62 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 24 Apr 2019 20:18:26 -0700 Subject: [PATCH 6/6] Use 302 --- homeassistant/components/media_player/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 41b3f2010ea1d..478f59d2817ae 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -819,7 +819,7 @@ async def get(self, request, entity_id): if player.media_image_remotely_accessible: url = player.media_image_url if url is not None: - return web.Response(status=301, headers={ + return web.Response(status=302, headers={ 'location': url }) return web.Response(status=500)