Remove base_url configuration option from tts (#94905)

This commit is contained in:
Erik Montnemery 2023-06-21 11:20:33 +02:00 committed by GitHub
parent 83c478105b
commit b254218dd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 5 additions and 151 deletions

View File

@ -362,15 +362,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
): ):
external_url = None external_url = None
internal_url = None internal_url = None
tts_base_url = None
url_description = "" url_description = ""
if "tts" in self.hass.config.components:
# pylint: disable-next=[import-outside-toplevel]
from homeassistant.components import tts
with suppress(KeyError): # base_url not configured
tts_base_url = tts.get_base_url(self.hass)
with suppress(NoURLAvailableError): # external_url not configured with suppress(NoURLAvailableError): # external_url not configured
external_url = get_url(self.hass, allow_internal=False) external_url = get_url(self.hass, allow_internal=False)
@ -378,8 +370,6 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity):
internal_url = get_url(self.hass, allow_external=False) internal_url = get_url(self.hass, allow_external=False)
if media_status.content_id: if media_status.content_id:
if tts_base_url and media_status.content_id.startswith(tts_base_url):
url_description = f" from tts.base_url ({tts_base_url})"
if external_url and media_status.content_id.startswith(external_url): if external_url and media_status.content_id.startswith(external_url):
url_description = f" from external_url ({external_url})" url_description = f" from external_url ({external_url})"
if internal_url and media_status.content_id.startswith(internal_url): if internal_url and media_status.content_id.startswith(internal_url):

View File

@ -52,7 +52,6 @@ from .const import (
ATTR_LANGUAGE, ATTR_LANGUAGE,
ATTR_MESSAGE, ATTR_MESSAGE,
ATTR_OPTIONS, ATTR_OPTIONS,
CONF_BASE_URL,
CONF_CACHE, CONF_CACHE,
CONF_CACHE_DIR, CONF_CACHE_DIR,
CONF_TIME_MEMORY, CONF_TIME_MEMORY,
@ -76,7 +75,6 @@ __all__ = [
"CONF_LANG", "CONF_LANG",
"DEFAULT_CACHE_DIR", "DEFAULT_CACHE_DIR",
"generate_media_source_id", "generate_media_source_id",
"get_base_url",
"PLATFORM_SCHEMA_BASE", "PLATFORM_SCHEMA_BASE",
"PLATFORM_SCHEMA", "PLATFORM_SCHEMA",
"Provider", "Provider",
@ -93,8 +91,6 @@ ATTR_VOICE = "voice"
CONF_LANG = "language" CONF_LANG = "language"
BASE_URL_KEY = "tts_base_url"
SERVICE_CLEAR_CACHE = "clear_cache" SERVICE_CLEAR_CACHE = "clear_cache"
_RE_LEGACY_VOICE_FILE = re.compile( _RE_LEGACY_VOICE_FILE = re.compile(
@ -214,15 +210,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
use_cache: bool = conf.get(CONF_CACHE, DEFAULT_CACHE) use_cache: bool = conf.get(CONF_CACHE, DEFAULT_CACHE)
cache_dir: str = conf.get(CONF_CACHE_DIR, DEFAULT_CACHE_DIR) cache_dir: str = conf.get(CONF_CACHE_DIR, DEFAULT_CACHE_DIR)
time_memory: int = conf.get(CONF_TIME_MEMORY, DEFAULT_TIME_MEMORY) time_memory: int = conf.get(CONF_TIME_MEMORY, DEFAULT_TIME_MEMORY)
base_url: str | None = conf.get(CONF_BASE_URL)
if base_url is not None:
_LOGGER.warning(
"TTS base_url option is deprecated. Configure internal/external URL"
" instead"
)
hass.data[BASE_URL_KEY] = base_url
tts = SpeechManager(hass, use_cache, cache_dir, time_memory, base_url) tts = SpeechManager(hass, use_cache, cache_dir, time_memory)
try: try:
await tts.async_init_cache() await tts.async_init_cache()
@ -413,7 +402,6 @@ class SpeechManager:
use_cache: bool, use_cache: bool,
cache_dir: str, cache_dir: str,
time_memory: int, time_memory: int,
base_url: str | None,
) -> None: ) -> None:
"""Initialize a speech store.""" """Initialize a speech store."""
self.hass = hass self.hass = hass
@ -422,7 +410,6 @@ class SpeechManager:
self.use_cache = use_cache self.use_cache = use_cache
self.cache_dir = cache_dir self.cache_dir = cache_dir
self.time_memory = time_memory self.time_memory = time_memory
self.base_url = base_url
self.file_cache: dict[str, str] = {} self.file_cache: dict[str, str] = {}
self.mem_cache: dict[str, TTSCache] = {} self.mem_cache: dict[str, TTSCache] = {}
@ -886,7 +873,7 @@ class TextToSpeechUrlView(HomeAssistantView):
_LOGGER.error("Error on init tts: %s", err) _LOGGER.error("Error on init tts: %s", err)
return self.json({"error": err}, HTTPStatus.BAD_REQUEST) return self.json({"error": err}, HTTPStatus.BAD_REQUEST)
base = self.tts.base_url or get_url(self.tts.hass) base = get_url(self.tts.hass)
url = base + path url = base + path
return self.json({"url": url, "path": path}) return self.json({"url": url, "path": path})
@ -914,11 +901,6 @@ class TextToSpeechView(HomeAssistantView):
return web.Response(body=data, content_type=content) return web.Response(body=data, content_type=content)
def get_base_url(hass: HomeAssistant) -> str:
"""Get base URL."""
return hass.data[BASE_URL_KEY] or get_url(hass)
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
"type": "tts/engine/list", "type": "tts/engine/list",

View File

@ -4,7 +4,6 @@ ATTR_LANGUAGE = "language"
ATTR_MESSAGE = "message" ATTR_MESSAGE = "message"
ATTR_OPTIONS = "options" ATTR_OPTIONS = "options"
CONF_BASE_URL = "base_url"
CONF_CACHE = "cache" CONF_CACHE = "cache"
CONF_CACHE_DIR = "cache_dir" CONF_CACHE_DIR = "cache_dir"
CONF_FIELDS = "fields" CONF_FIELDS = "fields"

View File

@ -9,7 +9,6 @@ from pathlib import Path
from typing import TYPE_CHECKING, Any, cast from typing import TYPE_CHECKING, Any, cast
import voluptuous as vol import voluptuous as vol
import yarl
from homeassistant.components.media_player import ( from homeassistant.components.media_player import (
ATTR_MEDIA_ANNOUNCE, ATTR_MEDIA_ANNOUNCE,
@ -31,7 +30,6 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.service import async_set_service_schema from homeassistant.helpers.service import async_set_service_schema
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.setup import async_prepare_setup_platform from homeassistant.setup import async_prepare_setup_platform
from homeassistant.util.network import normalize_url
from homeassistant.util.yaml import load_yaml from homeassistant.util.yaml import load_yaml
from .const import ( from .const import (
@ -39,7 +37,6 @@ from .const import (
ATTR_LANGUAGE, ATTR_LANGUAGE,
ATTR_MESSAGE, ATTR_MESSAGE,
ATTR_OPTIONS, ATTR_OPTIONS,
CONF_BASE_URL,
CONF_CACHE, CONF_CACHE,
CONF_CACHE_DIR, CONF_CACHE_DIR,
CONF_FIELDS, CONF_FIELDS,
@ -72,16 +69,6 @@ def _deprecated_platform(value: str) -> str:
return value return value
def _valid_base_url(value: str) -> str:
"""Validate base url, return value."""
url = yarl.URL(cv.url(value))
if url.path != "/":
raise vol.Invalid("Path should be empty")
return normalize_url(value)
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend( PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(
{ {
vol.Required(CONF_PLATFORM): vol.All(cv.string, _deprecated_platform), vol.Required(CONF_PLATFORM): vol.All(cv.string, _deprecated_platform),
@ -90,7 +77,6 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(
vol.Optional(CONF_TIME_MEMORY, default=DEFAULT_TIME_MEMORY): vol.All( vol.Optional(CONF_TIME_MEMORY, default=DEFAULT_TIME_MEMORY): vol.All(
vol.Coerce(int), vol.Range(min=60, max=57600) vol.Coerce(int), vol.Range(min=60, max=57600)
), ),
vol.Optional(CONF_BASE_URL): _valid_base_url,
vol.Optional(CONF_SERVICE_NAME): cv.string, vol.Optional(CONF_SERVICE_NAME): cv.string,
} }
) )

View File

@ -18,7 +18,6 @@ from homeassistant.components.media_source import (
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.network import get_url
from .const import DATA_TTS_MANAGER, DOMAIN from .const import DATA_TTS_MANAGER, DOMAIN
from .helper import get_engine_instance from .helper import get_engine_instance
@ -124,9 +123,6 @@ class TTSMediaSource(MediaSource):
mime_type = mimetypes.guess_type(url)[0] or "audio/mpeg" mime_type = mimetypes.guess_type(url)[0] or "audio/mpeg"
if manager.base_url and manager.base_url != get_url(self.hass):
url = f"{manager.base_url}{url}"
return PlayMedia(url, mime_type) return PlayMedia(url, mime_type)
async def async_browse_media( async def async_browse_media(

View File

@ -1894,7 +1894,7 @@ async def test_failed_cast_other_url(
assert await async_setup_component( assert await async_setup_component(
hass, hass,
tts.DOMAIN, tts.DOMAIN,
{tts.DOMAIN: {"platform": "demo", "base_url": "http://example.local:8123"}}, {tts.DOMAIN: {"platform": "demo"}},
) )
info = get_fake_chromecast_info() info = get_fake_chromecast_info()
@ -1951,7 +1951,7 @@ async def test_failed_cast_external_url(
assert await async_setup_component( assert await async_setup_component(
hass, hass,
tts.DOMAIN, tts.DOMAIN,
{tts.DOMAIN: {"platform": "demo", "base_url": "http://example.com:8123"}}, {tts.DOMAIN: {"platform": "demo"}},
) )
info = get_fake_chromecast_info() info = get_fake_chromecast_info()
@ -1969,33 +1969,6 @@ async def test_failed_cast_external_url(
) )
async def test_failed_cast_tts_base_url(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test warning when casting from tts.base_url fails."""
await async_setup_component(hass, "homeassistant", {})
with assert_setup_component(1, tts.DOMAIN):
assert await async_setup_component(
hass,
tts.DOMAIN,
{tts.DOMAIN: {"platform": "demo", "base_url": "http://example.local:8123"}},
)
info = get_fake_chromecast_info()
chromecast, _ = await async_setup_media_player_cast(hass, info)
_, _, media_status_cb = get_status_callbacks(chromecast)
media_status = MagicMock(images=None)
media_status.player_is_idle = True
media_status.idle_reason = "ERROR"
media_status.content_id = "http://example.local:8123/tts.mp3"
media_status_cb(media_status)
assert (
"Failed to cast media http://example.local:8123/tts.mp3 from tts.base_url"
in caplog.text
)
async def test_disconnect_on_stop(hass: HomeAssistant) -> None: async def test_disconnect_on_stop(hass: HomeAssistant) -> None:
"""Test cast device disconnects socket on stop.""" """Test cast device disconnects socket on stop."""
info = get_fake_chromecast_info() info = get_fake_chromecast_info()

View File

@ -5,7 +5,6 @@ from typing import Any
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
import pytest import pytest
import voluptuous as vol
from homeassistant.components import tts from homeassistant.components import tts
from homeassistant.components.media_player import ( from homeassistant.components.media_player import (
@ -17,7 +16,6 @@ from homeassistant.components.media_player import (
MediaType, MediaType,
) )
from homeassistant.components.media_source import Unresolvable from homeassistant.components.media_source import Unresolvable
from homeassistant.components.tts.legacy import _valid_base_url
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN
from homeassistant.core import HomeAssistant, State from homeassistant.core import HomeAssistant, State
@ -25,7 +23,6 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.typing import UNDEFINED from homeassistant.helpers.typing import UNDEFINED
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from homeassistant.util.network import normalize_url
from .common import ( from .common import (
DEFAULT_LANG, DEFAULT_LANG,
@ -1315,44 +1312,6 @@ async def test_tags_with_wave() -> None:
assert tagged_data != tts_data assert tagged_data != tts_data
@pytest.mark.parametrize(
"value",
(
"http://example.local:8123",
"http://example.local",
"http://example.local:80",
"https://example.com",
"https://example.com:443",
"https://example.com:8123",
),
)
def test_valid_base_url(value) -> None:
"""Test we validate base urls."""
assert _valid_base_url(value) == normalize_url(value)
# Test we strip trailing `/`
assert _valid_base_url(value + "/") == normalize_url(value)
@pytest.mark.parametrize(
"value",
(
"http://example.local:8123/sub-path",
"http://example.local/sub-path",
"https://example.com/sub-path",
"https://example.com:8123/sub-path",
"mailto:some@email",
"http:example.com",
"http:/example.com",
"http//example.com",
"example.com",
),
)
def test_invalid_base_url(value) -> None:
"""Test we catch bad base urls."""
with pytest.raises(vol.Invalid):
_valid_base_url(value)
@pytest.mark.parametrize( @pytest.mark.parametrize(
("setup", "result_engine"), ("setup", "result_engine"),
[ [

View File

@ -4,11 +4,8 @@ from __future__ import annotations
import pytest import pytest
from homeassistant.components.media_player import ( from homeassistant.components.media_player import (
ATTR_MEDIA_CONTENT_ID,
ATTR_MEDIA_CONTENT_TYPE,
DOMAIN as DOMAIN_MP, DOMAIN as DOMAIN_MP,
SERVICE_PLAY_MEDIA, SERVICE_PLAY_MEDIA,
MediaType,
) )
from homeassistant.components.tts import ATTR_MESSAGE, DOMAIN, Provider from homeassistant.components.tts import ATTR_MESSAGE, DOMAIN, Provider
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
@ -17,7 +14,7 @@ from homeassistant.helpers.discovery import async_load_platform
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from .common import SUPPORT_LANGUAGES, MockProvider, MockTTS, get_media_source_url from .common import SUPPORT_LANGUAGES, MockProvider, MockTTS
from tests.common import ( from tests.common import (
MockModule, MockModule,
@ -140,34 +137,6 @@ async def test_platform_setup_with_error(
assert "Error setting up platform: bad_tts" in caplog.text assert "Error setting up platform: bad_tts" in caplog.text
async def test_service_base_url_set(hass: HomeAssistant, mock_tts) -> None:
"""Set up a TTS platform with ``base_url`` set and call service."""
calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
config = {DOMAIN: {"platform": "test", "base_url": "http://fnord"}}
with assert_setup_component(1, DOMAIN):
assert await async_setup_component(hass, DOMAIN, config)
await hass.services.async_call(
DOMAIN,
"test_say",
{
ATTR_ENTITY_ID: "media_player.something",
ATTR_MESSAGE: "There is someone at the door.",
},
blocking=True,
)
assert len(calls) == 1
assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC
assert (
await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID])
== "http://fnord"
"/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491"
"_en-us_-_test.mp3"
)
async def test_service_without_cache_config( async def test_service_without_cache_config(
hass: HomeAssistant, mock_tts_cache_dir, mock_tts hass: HomeAssistant, mock_tts_cache_dir, mock_tts
) -> None: ) -> None: