/
/
/
1"""Configuration entries for the AI Radio plugin."""
2
3from __future__ import annotations
4
5import asyncio
6from typing import TYPE_CHECKING
7
8from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType
9from music_assistant_models.enums import ConfigEntryType
10
11from music_assistant.constants import CONF_PROVIDERS
12from music_assistant.helpers.countries import get_country_codes
13from music_assistant.helpers.datetime import host_timezone_name
14
15from .constants import (
16 CONF_TIMEZONE,
17 CONF_TTS_LOUDNESS_BOOST,
18 CONF_WEATHER_CITY,
19 CONF_WEATHER_COUNTRY,
20 CONF_WEATHER_PROVIDER,
21 CONF_WEATHER_TIMEOUT,
22 DEFAULT_TTS_LOUDNESS_BOOST,
23 DEFAULT_WEATHER_PROVIDER,
24 DEFAULT_WEATHER_TIMEOUT_SECONDS,
25)
26
27if TYPE_CHECKING:
28 from music_assistant.mass import MusicAssistant
29
30
31async def get_config_entries(
32 mass: MusicAssistant,
33 instance_id: str | None = None,
34 action: str | None = None, # noqa: ARG001
35 values: dict[str, ConfigValueType] | None = None, # noqa: ARG001
36) -> tuple[ConfigEntry, ...]:
37 """Return Config entries to setup this provider."""
38 weather_city, weather_country = await get_weather_location_entries(mass, instance_id)
39 return (
40 ConfigEntry(
41 key=CONF_TIMEZONE,
42 type=ConfigEntryType.STRING,
43 default_value=host_timezone_name(),
44 advanced=True,
45 ),
46 weather_city,
47 weather_country,
48 ConfigEntry(
49 key=CONF_WEATHER_PROVIDER,
50 type=ConfigEntryType.STRING,
51 options=[
52 ConfigValueOption(value="open_meteo"),
53 ConfigValueOption(value="disabled"),
54 ],
55 default_value=DEFAULT_WEATHER_PROVIDER,
56 advanced=True,
57 ),
58 ConfigEntry(
59 key=CONF_WEATHER_TIMEOUT,
60 type=ConfigEntryType.INTEGER,
61 default_value=DEFAULT_WEATHER_TIMEOUT_SECONDS,
62 advanced=True,
63 ),
64 ConfigEntry(
65 key=CONF_TTS_LOUDNESS_BOOST,
66 type=ConfigEntryType.INTEGER,
67 default_value=DEFAULT_TTS_LOUDNESS_BOOST,
68 range=(0, 6),
69 advanced=True,
70 ),
71 )
72
73
74async def get_weather_location_entries(
75 mass: MusicAssistant, instance_id: str | None
76) -> tuple[ConfigEntry, ConfigEntry]:
77 """
78 Build the weather city/country config entries, shared by the setup flow and options page.
79
80 Defaults to the answer collected during setup when the instance already has one,
81 so the weather location works right after setup without a trip to the settings
82 screen, while still letting a later settings edit override it.
83
84 :param mass: The MusicAssistant instance.
85 :param instance_id: The provider instance id, or None during initial setup.
86 """
87 country_codes = await asyncio.to_thread(get_country_codes)
88 country_options = [
89 ConfigValueOption(title=name, value=code) for code, name in country_codes.items()
90 ]
91 # default the weather country to the region of the server's language, mirroring
92 # the itunes_podcasts locale precedent
93 region = mass.metadata.locale.split("_")[-1].upper()
94 setup_city, setup_country = _setup_weather_location(mass, instance_id)
95 return (
96 ConfigEntry(
97 key=CONF_WEATHER_CITY,
98 type=ConfigEntryType.STRING,
99 default_value=setup_city,
100 ),
101 ConfigEntry(
102 key=CONF_WEATHER_COUNTRY,
103 type=ConfigEntryType.STRING,
104 options=country_options,
105 default_value=setup_country or (region if region in country_codes else ""),
106 ),
107 )
108
109
110def _setup_weather_location(mass: MusicAssistant, instance_id: str | None) -> tuple[str, str]:
111 """Return the city/country collected by the setup flow, if any."""
112 if instance_id is None:
113 return "", ""
114 setup_data = mass.config.get(f"{CONF_PROVIDERS}/{instance_id}/setup_data") or {}
115 city = setup_data.get(CONF_WEATHER_CITY)
116 country = setup_data.get(CONF_WEATHER_COUNTRY)
117 if isinstance(city, str):
118 city = mass.config.decrypt_string(city)
119 if isinstance(country, str):
120 country = mass.config.decrypt_string(country)
121 return city or "", country or ""
122