Prefer internal docker URL for VLC telnet when possible (#67090)
parent
65eefcacfc
commit
4ea6ca7f91
|
@ -10,14 +10,22 @@ import yarl
|
|||
|
||||
from homeassistant.components.http.auth import async_sign_path
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.network import get_url, is_hass_url
|
||||
from homeassistant.helpers.network import (
|
||||
get_supervisor_network_url,
|
||||
get_url,
|
||||
is_hass_url,
|
||||
)
|
||||
|
||||
from .const import CONTENT_AUTH_EXPIRY_TIME, MEDIA_CLASS_DIRECTORY
|
||||
|
||||
|
||||
@callback
|
||||
def async_process_play_media_url(
|
||||
hass: HomeAssistant, media_content_id: str, *, allow_relative_url: bool = False
|
||||
hass: HomeAssistant,
|
||||
media_content_id: str,
|
||||
*,
|
||||
allow_relative_url: bool = False,
|
||||
for_supervisor_network: bool = False,
|
||||
) -> str:
|
||||
"""Update a media URL with authentication if it points at Home Assistant."""
|
||||
if media_content_id[0] != "/" and not is_hass_url(hass, media_content_id):
|
||||
|
@ -39,7 +47,14 @@ def async_process_play_media_url(
|
|||
|
||||
# convert relative URL to absolute URL
|
||||
if media_content_id[0] == "/" and not allow_relative_url:
|
||||
media_content_id = f"{get_url(hass)}{media_content_id}"
|
||||
base_url = None
|
||||
if for_supervisor_network:
|
||||
base_url = get_supervisor_network_url(hass)
|
||||
|
||||
if not base_url:
|
||||
base_url = get_url(hass)
|
||||
|
||||
media_content_id = f"{base_url}{media_content_id}"
|
||||
|
||||
return media_content_id
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ from homeassistant.components.media_player.const import (
|
|||
SUPPORT_VOLUME_MUTE,
|
||||
SUPPORT_VOLUME_SET,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.config_entries import SOURCE_HASSIO, ConfigEntry
|
||||
from homeassistant.const import CONF_NAME, STATE_IDLE, STATE_PAUSED, STATE_PLAYING
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
@ -125,6 +125,7 @@ class VlcDevice(MediaPlayerEntity):
|
|||
manufacturer="VideoLAN",
|
||||
name=name,
|
||||
)
|
||||
self._using_addon = config_entry.source == SOURCE_HASSIO
|
||||
|
||||
@catch_vlc_errors
|
||||
async def async_update(self) -> None:
|
||||
|
@ -316,7 +317,9 @@ class VlcDevice(MediaPlayerEntity):
|
|||
)
|
||||
|
||||
# If media ID is a relative URL, we serve it from HA.
|
||||
media_id = async_process_play_media_url(self.hass, media_id)
|
||||
media_id = async_process_play_media_url(
|
||||
self.hass, media_id, for_supervisor_network=self._using_addon
|
||||
)
|
||||
|
||||
await self._vlc.add(media_id)
|
||||
self._state = STATE_PLAYING
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""Network helpers."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from contextlib import suppress
|
||||
from ipaddress import ip_address
|
||||
from typing import cast
|
||||
|
@ -15,6 +16,7 @@ from homeassistant.util.network import is_ip_address, is_loopback, normalize_url
|
|||
|
||||
TYPE_URL_INTERNAL = "internal_url"
|
||||
TYPE_URL_EXTERNAL = "external_url"
|
||||
SUPERVISOR_NETWORK_HOST = "homeassistant"
|
||||
|
||||
|
||||
class NoURLAvailableError(HomeAssistantError):
|
||||
|
@ -33,6 +35,31 @@ def is_internal_request(hass: HomeAssistant) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
@bind_hass
|
||||
def get_supervisor_network_url(
|
||||
hass: HomeAssistant, *, allow_ssl: bool = False
|
||||
) -> str | None:
|
||||
"""Get URL for home assistant within supervisor network."""
|
||||
if hass.config.api is None or not hass.components.hassio.is_hassio():
|
||||
return None
|
||||
|
||||
scheme = "http"
|
||||
if hass.config.api.use_ssl:
|
||||
# Certificate won't be valid for hostname so this URL usually won't work
|
||||
if not allow_ssl:
|
||||
return None
|
||||
|
||||
scheme = "https"
|
||||
|
||||
return str(
|
||||
yarl.URL.build(
|
||||
scheme=scheme,
|
||||
host=SUPERVISOR_NETWORK_HOST,
|
||||
port=hass.config.api.port,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def is_hass_url(hass: HomeAssistant, url: str) -> bool:
|
||||
"""Return if the URL points at this Home Assistant instance."""
|
||||
parsed = yarl.URL(normalize_url(url))
|
||||
|
@ -53,11 +80,13 @@ def is_hass_url(hass: HomeAssistant, url: str) -> bool:
|
|||
except NoURLAvailableError:
|
||||
return None
|
||||
|
||||
potential_base_factory: Callable[[], str | None]
|
||||
for potential_base_factory in (
|
||||
lambda: hass.config.internal_url,
|
||||
lambda: hass.config.external_url,
|
||||
cloud_url,
|
||||
host_ip,
|
||||
lambda: get_supervisor_network_url(hass, allow_ssl=True),
|
||||
):
|
||||
potential_base = potential_base_factory()
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@ from homeassistant.components.media_player.browse_media import (
|
|||
)
|
||||
from homeassistant.config import async_process_ha_core_config
|
||||
|
||||
from tests.common import mock_component
|
||||
|
||||
@pytest.fixture
|
||||
def mock_sign_path():
|
||||
|
||||
@pytest.fixture(name="mock_sign_path")
|
||||
def fixture_mock_sign_path():
|
||||
"""Mock sign path."""
|
||||
with patch(
|
||||
"homeassistant.components.media_player.browse_media.async_sign_path",
|
||||
|
@ -58,3 +60,35 @@ async def test_process_play_media_url(hass, mock_sign_path):
|
|||
)
|
||||
== "http://192.168.123.123:8123/path?hello=world"
|
||||
)
|
||||
|
||||
|
||||
async def test_process_play_media_url_for_addon(hass, mock_sign_path):
|
||||
"""Test it uses the hostname for an addon if available."""
|
||||
await async_process_ha_core_config(
|
||||
hass,
|
||||
{
|
||||
"internal_url": "http://example.local:8123",
|
||||
"external_url": "https://example.com",
|
||||
},
|
||||
)
|
||||
|
||||
# Not hassio or hassio not loaded yet, don't use supervisor network url
|
||||
hass.config.api = Mock(use_ssl=False, port=8123, local_ip="192.168.123.123")
|
||||
assert (
|
||||
async_process_play_media_url(hass, "/path", for_supervisor_network=True)
|
||||
!= "http://homeassistant:8123/path?authSig=bla"
|
||||
)
|
||||
|
||||
# Is hassio and not SSL, use an supervisor network url
|
||||
mock_component(hass, "hassio")
|
||||
assert (
|
||||
async_process_play_media_url(hass, "/path", for_supervisor_network=True)
|
||||
== "http://homeassistant:8123/path?authSig=bla"
|
||||
)
|
||||
|
||||
# Hassio loaded but using SSL, don't use an supervisor network url
|
||||
hass.config.api = Mock(use_ssl=True, port=8123, local_ip="192.168.123.123")
|
||||
assert (
|
||||
async_process_play_media_url(hass, "/path", for_supervisor_network=True)
|
||||
!= "https://homeassistant:8123/path?authSig=bla"
|
||||
)
|
||||
|
|
|
@ -12,6 +12,7 @@ from homeassistant.helpers.network import (
|
|||
_get_external_url,
|
||||
_get_internal_url,
|
||||
_get_request_host,
|
||||
get_supervisor_network_url,
|
||||
get_url,
|
||||
is_hass_url,
|
||||
is_internal_request,
|
||||
|
@ -715,3 +716,41 @@ async def test_is_hass_url(hass):
|
|||
assert is_hass_url(hass, "https://example.nabu.casa") is True
|
||||
assert is_hass_url(hass, "http://example.nabu.casa:443") is False
|
||||
assert is_hass_url(hass, "http://example.nabu.casa") is False
|
||||
|
||||
|
||||
async def test_is_hass_url_addon_url(hass):
|
||||
"""Test is_hass_url with a supervisor network URL."""
|
||||
assert is_hass_url(hass, "http://homeassistant:8123") is False
|
||||
|
||||
hass.config.api = Mock(use_ssl=False, port=8123, local_ip="192.168.123.123")
|
||||
await async_process_ha_core_config(
|
||||
hass,
|
||||
{"internal_url": "http://example.local:8123"},
|
||||
)
|
||||
assert is_hass_url(hass, "http://homeassistant:8123") is False
|
||||
|
||||
mock_component(hass, "hassio")
|
||||
assert is_hass_url(hass, "http://homeassistant:8123")
|
||||
assert not is_hass_url(hass, "https://homeassistant:8123")
|
||||
|
||||
hass.config.api = Mock(use_ssl=True, port=8123, local_ip="192.168.123.123")
|
||||
assert not is_hass_url(hass, "http://homeassistant:8123")
|
||||
assert is_hass_url(hass, "https://homeassistant:8123")
|
||||
|
||||
|
||||
async def test_get_supervisor_network_url(hass):
|
||||
"""Test get_supervisor_network_url."""
|
||||
assert get_supervisor_network_url(hass) is None
|
||||
|
||||
hass.config.api = Mock(use_ssl=False, port=8123, local_ip="192.168.123.123")
|
||||
await async_process_ha_core_config(hass, {})
|
||||
assert get_supervisor_network_url(hass) is None
|
||||
|
||||
mock_component(hass, "hassio")
|
||||
assert get_supervisor_network_url(hass) == "http://homeassistant:8123"
|
||||
|
||||
hass.config.api = Mock(use_ssl=True, port=8123, local_ip="192.168.123.123")
|
||||
assert get_supervisor_network_url(hass) is None
|
||||
assert (
|
||||
get_supervisor_network_url(hass, allow_ssl=True) == "https://homeassistant:8123"
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue