1 """Text-to-speech media source."""
3 from __future__
import annotations
7 from typing
import TypedDict
18 generate_media_source_id
as ms_generate_media_source_id,
23 from .const
import DATA_COMPONENT, DATA_TTS_MANAGER, DOMAIN
24 from .helper
import get_engine_instance
26 URL_QUERY_TTS_OPTIONS =
"tts_options"
30 """Set up tts media source."""
38 engine: str |
None =
None,
39 language: str |
None =
None,
40 options: dict |
None =
None,
41 cache: bool |
None =
None,
43 """Generate a media source ID for text-to-speech."""
44 from .
import async_resolve_engine
51 assert engine_instance
is not None
53 hass.data[DATA_TTS_MANAGER].process_options(engine_instance, language, options)
58 params[
"cache"] =
"true" if cache
else "false"
59 if language
is not None:
60 params[
"language"] = language
61 params[URL_QUERY_TTS_OPTIONS] = json.dumps(options, separators=(
",",
":"))
63 return ms_generate_media_source_id(
65 str(URL.build(path=engine, query=params)),
70 """Media source options."""
81 """Turn a media source ID into options."""
82 parsed =
URL(media_source_id)
83 if URL_QUERY_TTS_OPTIONS
in parsed.query:
85 options = json.loads(parsed.query[URL_QUERY_TTS_OPTIONS])
86 except json.JSONDecodeError
as err:
87 raise Unresolvable(f
"Invalid TTS options: {err.msg}")
from err
91 for k, v
in parsed.query.items()
92 if k
not in (
"message",
"language",
"cache")
94 if "message" not in parsed.query:
96 kwargs: MediaSourceOptions = {
97 "engine": parsed.name,
98 "message": parsed.query[
"message"],
99 "language": parsed.query.get(
"language"),
103 if "cache" in parsed.query:
104 kwargs[
"cache"] = parsed.query[
"cache"] ==
"true"
110 """Provide text-to-speech providers as media sources."""
112 name: str =
"Text-to-speech"
115 """Initialize TTSMediaSource."""
120 """Resolve media to a url."""
122 url = await self.
hasshass.data[DATA_TTS_MANAGER].async_get_url_path(
127 except HomeAssistantError
as err:
130 mime_type = mimetypes.guess_type(url)[0]
or "audio/mpeg"
136 item: MediaSourceItem,
137 ) -> BrowseMediaSource:
140 engine, _, params = item.identifier.partition(
"?")
146 for engine
in self.
hasshass.data[DATA_TTS_MANAGER].providers
149 for entity
in self.
hasshass.data[DATA_COMPONENT].entities
154 media_class=MediaClass.APP,
155 media_content_type=
"",
159 children_media_class=MediaClass.APP,
164 def _engine_item(self, engine: str, params: str |
None =
None) -> BrowseMediaSource:
165 """Return provider item."""
166 from .
import TextToSpeechEntity
171 if isinstance(engine_instance, TextToSpeechEntity):
172 engine_domain = engine_instance.platform.domain
174 engine_domain = engine
177 params = f
"?{params}"
183 identifier=f
"{engine}{params}",
184 media_class=MediaClass.APP,
185 media_content_type=
"provider",
186 title=engine_instance.name,
187 thumbnail=f
"https://brands.home-assistant.io/_/{engine_domain}/logo.png",
TextToSpeechEntity|Provider|None get_engine_instance(HomeAssistant hass, str engine)
str|None async_resolve_engine(HomeAssistant hass, str|None engine)