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