From: Marcel van der Veldt Date: Tue, 18 Feb 2025 12:18:50 +0000 (+0100) Subject: Fix issues with ConfigEntry model (de)serializing X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=8169f6016865b177f824d3f747edb67eb8f6b455;p=music-assistant-server.git Fix issues with ConfigEntry model (de)serializing --- diff --git a/music_assistant/constants.py b/music_assistant/constants.py index 8c4bee3b..1132e07f 100644 --- a/music_assistant/constants.py +++ b/music_assistant/constants.py @@ -3,7 +3,11 @@ import pathlib from typing import Final -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption +from music_assistant_models.config_entries import ( + ConfigEntry, + ConfigValueOption, + MultiValueConfigEntry, +) from music_assistant_models.enums import ConfigEntryType, ContentType from music_assistant_models.media_items import AudioFormat @@ -126,14 +130,14 @@ CONF_ENTRY_LOG_LEVEL = ConfigEntry( key=CONF_LOG_LEVEL, type=ConfigEntryType.STRING, label="Log level", - options=( + options=[ ConfigValueOption("global", "GLOBAL"), ConfigValueOption("info", "INFO"), ConfigValueOption("warning", "WARNING"), ConfigValueOption("error", "ERROR"), ConfigValueOption("debug", "DEBUG"), ConfigValueOption("verbose", "VERBOSE"), - ), + ], default_value="GLOBAL", category="advanced", ) @@ -185,12 +189,12 @@ CONF_ENTRY_AUTO_PLAY = ConfigEntry( CONF_ENTRY_OUTPUT_CHANNELS = ConfigEntry( key=CONF_OUTPUT_CHANNELS, type=ConfigEntryType.STRING, - options=( + options=[ ConfigValueOption("Stereo (both channels)", "stereo"), ConfigValueOption("Left channel", "left"), ConfigValueOption("Right channel", "right"), ConfigValueOption("Mono (both channels)", "mono"), - ), + ], default_value="stereo", label="Output Channel Mode", category="audio", @@ -334,12 +338,12 @@ CONF_ENTRY_TTS_PRE_ANNOUNCE = ConfigEntry( CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY = ConfigEntry( key=CONF_ANNOUNCE_VOLUME_STRATEGY, type=ConfigEntryType.STRING, - options=( + options=[ ConfigValueOption("Absolute volume", "absolute"), ConfigValueOption("Relative volume increase", "relative"), ConfigValueOption("Volume increase by fixed percentage", "percentual"), ConfigValueOption("Do not adjust volume", "none"), - ), + ], default_value="percentual", label="Volume strategy for Announcements", category="announcements", @@ -404,10 +408,10 @@ CONF_ENTRY_PLAYER_ICON_GROUP = ConfigEntry.from_dict( {**CONF_ENTRY_PLAYER_ICON.to_dict(), "default_value": "mdi-speaker-multiple"} ) -CONF_ENTRY_SAMPLE_RATES = ConfigEntry( +CONF_ENTRY_SAMPLE_RATES = MultiValueConfigEntry( key=CONF_SAMPLE_RATES, type=ConfigEntryType.INTEGER_TUPLE, - options=( + options=[ ConfigValueOption("44.1kHz / 16 bits", (44100, 16)), ConfigValueOption("44.1kHz / 24 bits", (44100, 24)), ConfigValueOption("48kHz / 16 bits", (48000, 16)), @@ -424,10 +428,9 @@ CONF_ENTRY_SAMPLE_RATES = ConfigEntry( ConfigValueOption("352.8kHz / 24 bits", (352800, 24)), ConfigValueOption("384kHz / 16 bits", (384000, 16)), ConfigValueOption("384kHz / 24 bits", (384000, 24)), - ), + ], default_value=[(44100, 16), (48000, 16)], required=True, - multi_value=True, label="Sample rates supported by this player", category="advanced", description="The sample rates (and bit depths) supported by this player.\n" @@ -438,11 +441,11 @@ CONF_ENTRY_SAMPLE_RATES = ConfigEntry( CONF_ENTRY_HTTP_PROFILE = ConfigEntry( key=CONF_HTTP_PROFILE, type=ConfigEntryType.STRING, - options=( + options=[ ConfigValueOption("Profile 1 - chunked", "chunked"), ConfigValueOption("Profile 2 - no content length", "no_content_length"), ConfigValueOption("Profile 3 - forced content length", "forced_content_length"), - ), + ], default_value="no_content_length", label="HTTP Profile used for sending audio", category="advanced", @@ -465,11 +468,11 @@ CONF_ENTRY_HTTP_PROFILE_FORCED_2 = ConfigEntry.from_dict( CONF_ENTRY_ENABLE_ICY_METADATA = ConfigEntry( key=CONF_ENABLE_ICY_METADATA, type=ConfigEntryType.STRING, - options=( + options=[ ConfigValueOption("Disabled - do not send ICY metadata", "disabled"), ConfigValueOption("Profile 1 - basic info", "basic"), ConfigValueOption("Profile 2 - full info (including image)", "full"), - ), + ], depends_on=CONF_FLOW_MODE, default_value="disabled", label="Try to ingest metadata into stream (ICY)", @@ -496,10 +499,10 @@ def create_sample_rates_config_entry( safe_max_bit_depth: int = 16, hidden: bool = False, supported_sample_rates: list[int] | None = None, -) -> ConfigEntry: +) -> MultiValueConfigEntry: """Create sample rates config entry based on player specific helpers.""" assert CONF_ENTRY_SAMPLE_RATES.options - conf_entry = ConfigEntry.from_dict(CONF_ENTRY_SAMPLE_RATES.to_dict()) + conf_entry = MultiValueConfigEntry.from_dict(CONF_ENTRY_SAMPLE_RATES.to_dict()) conf_entry.hidden = hidden options: list[ConfigValueOption] = [] default_value: list[tuple[int, int]] = [] @@ -513,7 +516,7 @@ def create_sample_rates_config_entry( options.append(option) if sample_rate <= safe_max_sample_rate and bit_depth <= safe_max_bit_depth: default_value.append(option.value) - conf_entry.options = tuple(options) + conf_entry.options = options conf_entry.default_value = default_value return conf_entry diff --git a/music_assistant/controllers/cache.py b/music_assistant/controllers/cache.py index 5103e6c6..59aeccba 100644 --- a/music_assistant/controllers/cache.py +++ b/music_assistant/controllers/cache.py @@ -11,7 +11,7 @@ from collections import OrderedDict from collections.abc import Callable, Iterator, MutableMapping from typing import TYPE_CHECKING, Any, ParamSpec, TypeVar -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ConfigEntryType from music_assistant.constants import DB_TABLE_CACHE, DB_TABLE_SETTINGS, MASS_LOGGER_NAME @@ -46,7 +46,7 @@ class CacheController(CoreController): async def get_config_entries( self, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """Return all Config Entries for this core module (if any).""" if action == CONF_CLEAR_CACHE: @@ -75,7 +75,8 @@ class CacheController(CoreController): async def close(self) -> None: """Cleanup on exit.""" - await self.database.close() + if self.database: + await self.database.close() async def get( self, diff --git a/music_assistant/controllers/config.py b/music_assistant/controllers/config.py index 62df0b10..88927b28 100644 --- a/music_assistant/controllers/config.py +++ b/music_assistant/controllers/config.py @@ -16,7 +16,7 @@ from cryptography.fernet import Fernet, InvalidToken from music_assistant_models import config_entries from music_assistant_models.config_entries import ( ConfigEntry, - ConfigValueType, + ConfigValueTypes, CoreConfig, PlayerConfig, ProviderConfig, @@ -77,7 +77,7 @@ class ConfigController: self._data: dict[str, Any] = {} self.filename = os.path.join(self.mass.storage_path, "settings.json") self._timer_handle: asyncio.TimerHandle | None = None - self._value_cache: dict[str, ConfigValueType] = {} + self._value_cache: dict[str, ConfigValueTypes] = {} async def setup(self) -> None: """Async initialize of controller.""" @@ -208,7 +208,7 @@ class ConfigController: raise KeyError(msg) @api_command("config/providers/get_value") - async def get_provider_config_value(self, instance_id: str, key: str) -> ConfigValueType: + async def get_provider_config_value(self, instance_id: str, key: str) -> ConfigValueTypes: """Return single configentry value for a provider.""" cache_key = f"prov_conf_value_{instance_id}.{key}" if (cached_value := self._value_cache.get(cache_key)) is not None: @@ -229,7 +229,7 @@ class ConfigController: provider_domain: str, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup/configure a provider. @@ -261,7 +261,7 @@ class ConfigController: async def save_provider_config( self, provider_domain: str, - values: dict[str, ConfigValueType], + values: dict[str, ConfigValueTypes], instance_id: str | None = None, ) -> ProviderConfig: """ @@ -356,7 +356,7 @@ class ConfigController: self, player_id: str, key: str, - ) -> ConfigValueType: + ) -> ConfigValueTypes: """Return single configentry value for a player.""" conf = await self.get_player_config(player_id) return ( @@ -366,8 +366,8 @@ class ConfigController: ) def get_raw_player_config_value( - self, player_id: str, key: str, default: ConfigValueType = None - ) -> ConfigValueType: + self, player_id: str, key: str, default: ConfigValueTypes = None + ) -> ConfigValueTypes: """ Return (raw) single configentry value for a player. @@ -380,7 +380,7 @@ class ConfigController: @api_command("config/players/save") async def save_player_config( - self, player_id: str, values: dict[str, ConfigValueType] + self, player_id: str, values: dict[str, ConfigValueTypes] ) -> PlayerConfig: """Save/update PlayerConfig.""" config = await self.get_player_config(player_id) @@ -513,7 +513,7 @@ class ConfigController: provider: str, name: str, enabled: bool, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> None: """ Create default/empty PlayerConfig. @@ -600,7 +600,7 @@ class ConfigController: return CoreConfig.parse(config_entries, raw_conf) @api_command("config/core/get_value") - async def get_core_config_value(self, domain: str, key: str) -> ConfigValueType: + async def get_core_config_value(self, domain: str, key: str) -> ConfigValueTypes: """Return single configentry value for a core controller.""" conf = await self.get_core_config(domain) return ( @@ -614,7 +614,7 @@ class ConfigController: self, domain: str, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to configure a core controller. @@ -635,7 +635,7 @@ class ConfigController: async def save_core_config( self, domain: str, - values: dict[str, ConfigValueType], + values: dict[str, ConfigValueTypes], ) -> CoreConfig: """Save CoreController Config values.""" config = await self.get_core_config(domain) @@ -656,8 +656,8 @@ class ConfigController: return await self.get_core_config(domain) def get_raw_core_config_value( - self, core_module: str, key: str, default: ConfigValueType = None - ) -> ConfigValueType: + self, core_module: str, key: str, default: ConfigValueTypes = None + ) -> ConfigValueTypes: """ Return (raw) single configentry value for a core controller. @@ -669,8 +669,8 @@ class ConfigController: ) def get_raw_provider_config_value( - self, provider_instance: str, key: str, default: ConfigValueType = None - ) -> ConfigValueType: + self, provider_instance: str, key: str, default: ConfigValueTypes = None + ) -> ConfigValueTypes: """ Return (raw) single config(entry) value for a provider. @@ -685,7 +685,7 @@ class ConfigController: self, provider_instance: str, key: str, - value: ConfigValueType, + value: ConfigValueTypes, encrypted: bool = False, ) -> None: """ @@ -707,7 +707,9 @@ class ConfigController: if prov := self.mass.get_provider(provider_instance, return_unavailable=True): prov.config.values[key].value = value - def set_raw_core_config_value(self, core_module: str, key: str, value: ConfigValueType) -> None: + def set_raw_core_config_value( + self, core_module: str, key: str, value: ConfigValueTypes + ) -> None: """ Set (raw) single config(entry) value for a core controller. @@ -718,7 +720,9 @@ class ConfigController: self.set(f"{CONF_CORE}/{core_module}", CoreConfig({}, core_module).to_raw()) self.set(f"{CONF_CORE}/{core_module}/values/{key}", value) - def set_raw_player_config_value(self, player_id: str, key: str, value: ConfigValueType) -> None: + def set_raw_player_config_value( + self, player_id: str, key: str, value: ConfigValueTypes + ) -> None: """ Set (raw) single config(entry) value for a player. @@ -821,7 +825,7 @@ class ConfigController: await self.mass.load_provider_config(config) async def _update_provider_config( - self, instance_id: str, values: dict[str, ConfigValueType] + self, instance_id: str, values: dict[str, ConfigValueTypes] ) -> ProviderConfig: """Update ProviderConfig.""" config = await self.get_provider_config(instance_id) @@ -861,7 +865,7 @@ class ConfigController: async def _add_provider_config( self, provider_domain: str, - values: dict[str, ConfigValueType], + values: dict[str, ConfigValueTypes], ) -> list[ConfigEntry] | ProviderConfig: """ Add new Provider (instance). diff --git a/music_assistant/controllers/metadata.py b/music_assistant/controllers/metadata.py index 1d3efb88..cd0a20a0 100644 --- a/music_assistant/controllers/metadata.py +++ b/music_assistant/controllers/metadata.py @@ -16,7 +16,7 @@ from uuid import uuid4 import aiofiles from aiohttp import web -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueTypes from music_assistant_models.enums import ( AlbumType, ConfigEntryType, @@ -131,7 +131,7 @@ class MetaDataController(CoreController): async def get_config_entries( self, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """Return all Config Entries for this core module (if any).""" return ( @@ -144,7 +144,7 @@ class MetaDataController(CoreController): description="Preferred language for metadata.\n\n" "Note that English will always be used as fallback when content " "in your preferred language is not available.", - options=tuple(ConfigValueOption(value, key) for key, value in LOCALES.items()), + options=[ConfigValueOption(value, key) for key, value in LOCALES.items()], ), ConfigEntry( key=CONF_ENABLE_ONLINE_METADATA, diff --git a/music_assistant/controllers/music.py b/music_assistant/controllers/music.py index aa779b06..edc8d9c7 100644 --- a/music_assistant/controllers/music.py +++ b/music_assistant/controllers/music.py @@ -11,7 +11,7 @@ from itertools import zip_longest from math import inf from typing import TYPE_CHECKING, Final, cast -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ( CacheCategory, ConfigEntryType, @@ -113,7 +113,7 @@ class MusicController(CoreController): async def get_config_entries( self, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """Return all Config Entries for this core module (if any).""" entries = ( diff --git a/music_assistant/controllers/player_queues.py b/music_assistant/controllers/player_queues.py index 002b9f18..8a2fcc73 100644 --- a/music_assistant/controllers/player_queues.py +++ b/music_assistant/controllers/player_queues.py @@ -19,7 +19,7 @@ import time from types import NoneType from typing import TYPE_CHECKING, Any, TypedDict, cast -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueTypes from music_assistant_models.enums import ( CacheCategory, ConfigEntryType, @@ -139,17 +139,17 @@ class PlayerQueuesController(CoreController): async def get_config_entries( self, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """Return all Config Entries for this core module (if any).""" - enqueue_options = tuple(ConfigValueOption(x.name, x.value) for x in QueueOption) + enqueue_options = [ConfigValueOption(x.name, x.value) for x in QueueOption] return ( ConfigEntry( key=CONF_DEFAULT_ENQUEUE_SELECT_ARTIST, type=ConfigEntryType.STRING, default_value=ENQUEUE_SELECT_ARTIST_DEFAULT_VALUE, label="Items to select when you play a (in-library) artist.", - options=( + options=[ ConfigValueOption( title="Only in-library tracks", value="library_tracks", @@ -166,14 +166,14 @@ class PlayerQueuesController(CoreController): title="All tracks from all albums from (all) streaming provider(s)", value="all_album_tracks", ), - ), + ], ), ConfigEntry( key=CONF_DEFAULT_ENQUEUE_SELECT_ALBUM, type=ConfigEntryType.STRING, default_value=ENQUEUE_SELECT_ALBUM_DEFAULT_VALUE, label="Items to select when you play a (in-library) album.", - options=( + options=[ ConfigValueOption( title="Only in-library tracks", value="library_tracks", @@ -182,7 +182,7 @@ class PlayerQueuesController(CoreController): title="All tracks for album on (streaming) provider", value="all_tracks", ), - ), + ], ), ConfigEntry( key=CONF_DEFAULT_ENQUEUE_OPTION_ARTIST, diff --git a/music_assistant/controllers/streams.py b/music_assistant/controllers/streams.py index b2213731..2efb1d16 100644 --- a/music_assistant/controllers/streams.py +++ b/music_assistant/controllers/streams.py @@ -16,7 +16,7 @@ from typing import TYPE_CHECKING from aiofiles.os import wrap from aiohttp import web -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueTypes from music_assistant_models.enums import ( ConfigEntryType, ContentType, @@ -115,7 +115,7 @@ class StreamsController(CoreController): async def get_config_entries( self, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """Return all Config Entries for this core module (if any).""" default_ip = await get_ip() @@ -136,10 +136,10 @@ class StreamsController(CoreController): type=ConfigEntryType.STRING, default_value=VolumeNormalizationMode.FALLBACK_DYNAMIC, label="Volume normalization method for radio streams", - options=( + options=[ ConfigValueOption(x.value.replace("_", " ").title(), x.value) for x in VolumeNormalizationMode - ), + ], category="audio", ), ConfigEntry( @@ -147,10 +147,10 @@ class StreamsController(CoreController): type=ConfigEntryType.STRING, default_value=VolumeNormalizationMode.FALLBACK_DYNAMIC, label="Volume normalization method for tracks", - options=( + options=[ ConfigValueOption(x.value.replace("_", " ").title(), x.value) for x in VolumeNormalizationMode - ), + ], category="audio", ), ConfigEntry( @@ -187,7 +187,7 @@ class StreamsController(CoreController): key=CONF_BIND_IP, type=ConfigEntryType.STRING, default_value="0.0.0.0", - options=(ConfigValueOption(x, x) for x in {"0.0.0.0", *all_ips}), + options=[ConfigValueOption(x, x) for x in {"0.0.0.0", *all_ips}], label="Bind to IP/interface", description="Start the stream server on this specific interface. \n" "Use 0.0.0.0 to bind to all interfaces, which is the default. \n" diff --git a/music_assistant/controllers/webserver.py b/music_assistant/controllers/webserver.py index 8ab15fbb..44c32a12 100644 --- a/music_assistant/controllers/webserver.py +++ b/music_assistant/controllers/webserver.py @@ -39,7 +39,7 @@ from music_assistant.models.core_controller import CoreController if TYPE_CHECKING: from collections.abc import Awaitable - from music_assistant_models.config_entries import ConfigValueType, CoreConfig + from music_assistant_models.config_entries import ConfigValueTypes, CoreConfig from music_assistant_models.event import MassEvent DEFAULT_SERVER_PORT = 8095 @@ -73,7 +73,7 @@ class WebserverController(CoreController): async def get_config_entries( self, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """Return all Config Entries for this core module (if any).""" default_publish_ip = await get_ip() @@ -122,7 +122,7 @@ class WebserverController(CoreController): key=CONF_BIND_IP, type=ConfigEntryType.STRING, default_value="0.0.0.0", - options=(ConfigValueOption(x, x) for x in {"0.0.0.0", *all_ips}), + options=[ConfigValueOption(x, x) for x in {"0.0.0.0", *all_ips}], label="Bind to IP/interface", description="Start the (web)server on this specific interface. \n" "Use 0.0.0.0 to bind to all interfaces. \n" diff --git a/music_assistant/models/__init__.py b/music_assistant/models/__init__.py index ce2bab18..d9e88472 100644 --- a/music_assistant/models/__init__.py +++ b/music_assistant/models/__init__.py @@ -10,7 +10,7 @@ from .player_provider import PlayerProvider from .plugin import PluginProvider if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.provider import ProviderManifest from music_assistant import MusicAssistant @@ -33,7 +33,7 @@ class ProviderModuleType(Protocol): mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/models/core_controller.py b/music_assistant/models/core_controller.py index 7f2532c3..f73ed6a5 100644 --- a/music_assistant/models/core_controller.py +++ b/music_assistant/models/core_controller.py @@ -11,7 +11,7 @@ from music_assistant_models.provider import ProviderManifest from music_assistant.constants import CONF_LOG_LEVEL, MASS_LOGGER_NAME if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, CoreConfig + from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, CoreConfig from music_assistant import MusicAssistant @@ -38,7 +38,7 @@ class CoreController: async def get_config_entries( self, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """Return all Config Entries for this core module (if any).""" return () diff --git a/music_assistant/models/player_provider.py b/music_assistant/models/player_provider.py index 08d0b611..ae050dc6 100644 --- a/music_assistant/models/player_provider.py +++ b/music_assistant/models/player_provider.py @@ -315,10 +315,10 @@ class PlayerProvider(Provider): label="Power Control", default_value=PLAYER_CONTROL_NATIVE if supports_power else PLAYER_CONTROL_NONE, required=True, - options=( + options=[ *base_power_options, *(ConfigValueOption(x.name, x.id) for x in power_controls), - ), + ], category="player_controls", ), # Volume control config entry @@ -328,10 +328,10 @@ class PlayerProvider(Provider): label="Volume Control", default_value=PLAYER_CONTROL_NATIVE if supports_volume else PLAYER_CONTROL_NONE, required=True, - options=( + options=[ *base_volume_options, *(ConfigValueOption(x.name, x.id) for x in volume_controls), - ), + ], category="player_controls", ), # Mute control config entry @@ -341,10 +341,10 @@ class PlayerProvider(Provider): label="Mute Control", default_value=PLAYER_CONTROL_NATIVE if supports_mute else PLAYER_CONTROL_NONE, required=True, - options=( + options=[ *base_mute_options, - *(ConfigValueOption(x.name, x.id) for x in mute_controls), - ), + *[ConfigValueOption(x.name, x.id) for x in mute_controls], + ], category="player_controls", ), ) diff --git a/music_assistant/providers/_template_music_provider/__init__.py b/music_assistant/providers/_template_music_provider/__init__.py index b9600575..3ecf27c1 100644 --- a/music_assistant/providers/_template_music_provider/__init__.py +++ b/music_assistant/providers/_template_music_provider/__init__.py @@ -58,7 +58,7 @@ from music_assistant_models.streamdetails import StreamDetails from music_assistant.models.music_provider import MusicProvider if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.provider import ProviderManifest from music_assistant.mass import MusicAssistant @@ -79,7 +79,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -90,9 +90,9 @@ async def get_config_entries( """ # ruff: noqa: ARG001 # Config Entries are used to configure the Music Provider if needed. - # See the models of ConfigEntry and ConfigValueType for more information what is supported. + # See the models of ConfigEntry and ConfigValueTypes for more information what is supported. # The ConfigEntry is a dataclass that represents a single configuration entry. - # The ConfigValueType is an Enum that represents the type of value that + # The ConfigValueTypes is an Enum that represents the type of value that # can be stored in a ConfigEntry. # If your provider does not need any configuration, you can return an empty tuple. diff --git a/music_assistant/providers/_template_player_provider/__init__.py b/music_assistant/providers/_template_player_provider/__init__.py index 33ff6dea..8bb1350c 100644 --- a/music_assistant/providers/_template_player_provider/__init__.py +++ b/music_assistant/providers/_template_player_provider/__init__.py @@ -43,7 +43,7 @@ from music_assistant.models.player_provider import PlayerProvider if TYPE_CHECKING: from music_assistant_models.config_entries import ( ConfigEntry, - ConfigValueType, + ConfigValueTypes, PlayerConfig, ProviderConfig, ) @@ -68,7 +68,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -79,9 +79,9 @@ async def get_config_entries( """ # ruff: noqa: ARG001 # Config Entries are used to configure the Player Provider if needed. - # See the models of ConfigEntry and ConfigValueType for more information what is supported. + # See the models of ConfigEntry and ConfigValueTypes for more information what is supported. # The ConfigEntry is a dataclass that represents a single configuration entry. - # The ConfigValueType is an Enum that represents the type of value that + # The ConfigValueTypes is an Enum that represents the type of value that # can be stored in a ConfigEntry. # If your provider does not need any configuration, you can return an empty tuple. return () diff --git a/music_assistant/providers/_template_plugin_provider/__init__.py b/music_assistant/providers/_template_plugin_provider/__init__.py index fbed2400..0ca1a613 100644 --- a/music_assistant/providers/_template_plugin_provider/__init__.py +++ b/music_assistant/providers/_template_plugin_provider/__init__.py @@ -43,7 +43,7 @@ from music_assistant_models.media_items.audio_format import AudioFormat from music_assistant.models.plugin import PluginProvider, PluginSource if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.event import MassEvent from music_assistant_models.provider import ProviderManifest @@ -65,7 +65,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -76,9 +76,9 @@ async def get_config_entries( """ # ruff: noqa: ARG001 # Config Entries are used to configure the Provider if needed. - # See the models of ConfigEntry and ConfigValueType for more information what is supported. + # See the models of ConfigEntry and ConfigValueTypes for more information what is supported. # The ConfigEntry is a dataclass that represents a single configuration entry. - # The ConfigValueType is an Enum that represents the type of value that + # The ConfigValueTypes is an Enum that represents the type of value that # can be stored in a ConfigEntry. # If your provider does not need any configuration, you can return an empty tuple. return () diff --git a/music_assistant/providers/airplay/__init__.py b/music_assistant/providers/airplay/__init__.py index ee3282cb..67c2a009 100644 --- a/music_assistant/providers/airplay/__init__.py +++ b/music_assistant/providers/airplay/__init__.py @@ -2,9 +2,9 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.enums import ConfigEntryType from music_assistant_models.provider import ProviderManifest @@ -24,7 +24,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -38,7 +38,7 @@ async def get_config_entries( ConfigEntry( key=CONF_BIND_INTERFACE, type=ConfigEntryType.STRING, - default_value=mass.streams.publish_ip, + default_value=cast(str, mass.streams.publish_ip), label="Bind interface", description="Interface to bind to for Airplay streaming.", category="advanced", diff --git a/music_assistant/providers/apple_music/__init__.py b/music_assistant/providers/apple_music/__init__.py index bfee2038..60d175e2 100644 --- a/music_assistant/providers/apple_music/__init__.py +++ b/music_assistant/providers/apple_music/__init__.py @@ -8,7 +8,7 @@ import os from typing import TYPE_CHECKING, Any import aiofiles -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ( AlbumType, ConfigEntryType, @@ -82,7 +82,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/audible/__init__.py b/music_assistant/providers/audible/__init__.py index 79da00ac..167f2050 100644 --- a/music_assistant/providers/audible/__init__.py +++ b/music_assistant/providers/audible/__init__.py @@ -13,7 +13,7 @@ import audible from music_assistant_models.config_entries import ( ConfigEntry, ConfigValueOption, - ConfigValueType, + ConfigValueTypes, ProviderConfig, ) from music_assistant_models.enums import ConfigEntryType, EventType, MediaType, ProviderFeature @@ -60,7 +60,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, # noqa: ARG001 action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -139,7 +139,7 @@ async def get_config_entries( hidden=not auth_required, required=True, value=locale, - options=( + options=[ ConfigValueOption("US and all other countries not listed", "us"), ConfigValueOption("Canada", "ca"), ConfigValueOption("UK and Ireland", "uk"), @@ -151,7 +151,7 @@ async def get_config_entries( ConfigValueOption("India", "in"), ConfigValueOption("Spain", "es"), ConfigValueOption("Brazil", "br"), - ), + ], default_value="us", ), ConfigEntry( @@ -166,7 +166,7 @@ async def get_config_entries( type=ConfigEntryType.STRING, label="Post Login Url", required=False, - value=values.get(CONF_POST_LOGIN_URL), + value=cast(str | None, values.get(CONF_POST_LOGIN_URL)), hidden=not auth_required, ), ConfigEntry( @@ -183,7 +183,7 @@ async def get_config_entries( label="Code Verifier", hidden=True, required=False, - value=values.get(CONF_CODE_VERIFIER), + value=cast(str | None, values.get(CONF_CODE_VERIFIER)), ), ConfigEntry( key=CONF_SERIAL, @@ -191,7 +191,7 @@ async def get_config_entries( label="Serial", hidden=True, required=False, - value=values.get(CONF_SERIAL), + value=cast(str | None, values.get(CONF_SERIAL)), ), ConfigEntry( key=CONF_LOGIN_URL, @@ -199,7 +199,7 @@ async def get_config_entries( label="Login Url", hidden=True, required=False, - value=values.get(CONF_LOGIN_URL), + value=cast(str | None, values.get(CONF_LOGIN_URL)), ), ConfigEntry( key=CONF_AUTH_FILE, @@ -207,7 +207,7 @@ async def get_config_entries( label="Authentication File", hidden=True, required=True, - value=values.get(CONF_AUTH_FILE), + value=cast(str | None, values.get(CONF_AUTH_FILE)), ), ) diff --git a/music_assistant/providers/audiobookshelf/__init__.py b/music_assistant/providers/audiobookshelf/__init__.py index 8131bedc..f47afa54 100644 --- a/music_assistant/providers/audiobookshelf/__init__.py +++ b/music_assistant/providers/audiobookshelf/__init__.py @@ -24,7 +24,7 @@ from aioaudiobookshelf.schema.library import ( ) from aioaudiobookshelf.schema.library import LibraryMediaType as AbsLibraryMediaType from mashumaro.mixins.dict import DataClassDictMixin -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.enums import ( ConfigEntryType, ContentType, @@ -136,7 +136,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/bluesound/__init__.py b/music_assistant/providers/bluesound/__init__.py index 08f03eb1..32c488ed 100644 --- a/music_assistant/providers/bluesound/__init__.py +++ b/music_assistant/providers/bluesound/__init__.py @@ -28,7 +28,7 @@ from music_assistant.helpers.util import ( from music_assistant.models.player_provider import PlayerProvider if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.provider import ProviderManifest from zeroconf.asyncio import AsyncServiceInfo @@ -78,7 +78,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """Set up legacy BluOS devices.""" # ruff: noqa: ARG001 diff --git a/music_assistant/providers/builtin/__init__.py b/music_assistant/providers/builtin/__init__.py index 9dacc398..047b4258 100644 --- a/music_assistant/providers/builtin/__init__.py +++ b/music_assistant/providers/builtin/__init__.py @@ -45,7 +45,7 @@ from music_assistant.helpers.uri import parse_uri from music_assistant.models.music_provider import MusicProvider if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigValueTypes, ProviderConfig from music_assistant_models.provider import ProviderManifest from music_assistant.mass import MusicAssistant @@ -108,7 +108,7 @@ async def get_config_entries( mass: MusicAssistant, # noqa: ARG001 instance_id: str | None = None, # noqa: ARG001 action: str | None = None, # noqa: ARG001 - values: dict[str, ConfigValueType] | None = None, # noqa: ARG001 + values: dict[str, ConfigValueTypes] | None = None, # noqa: ARG001 ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/chromecast/__init__.py b/music_assistant/providers/chromecast/__init__.py index f6957c29..586b2856 100644 --- a/music_assistant/providers/chromecast/__init__.py +++ b/music_assistant/providers/chromecast/__init__.py @@ -47,7 +47,7 @@ from music_assistant.models.player_provider import PlayerProvider from .helpers import CastStatusListener, ChromecastInfo if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigValueTypes, ProviderConfig from music_assistant_models.provider import ProviderManifest from pychromecast.controllers.media import MediaStatus from pychromecast.controllers.receiver import CastStatus @@ -101,7 +101,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/deezer/__init__.py b/music_assistant/providers/deezer/__init__.py index a7a5ae3e..81c9c852 100644 --- a/music_assistant/providers/deezer/__init__.py +++ b/music_assistant/providers/deezer/__init__.py @@ -11,7 +11,7 @@ import deezer from aiohttp import ClientSession, ClientTimeout from Crypto.Cipher import Blowfish from deezer import exceptions as deezer_exceptions -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.enums import ( AlbumType, ConfigEntryType, @@ -122,7 +122,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, # noqa: ARG001 action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """Return Config entries to setup this provider.""" # Action is to launch oauth flow diff --git a/music_assistant/providers/dlna/__init__.py b/music_assistant/providers/dlna/__init__.py index 22836391..d8b6322c 100644 --- a/music_assistant/providers/dlna/__init__.py +++ b/music_assistant/providers/dlna/__init__.py @@ -22,7 +22,7 @@ from async_upnp_client.client_factory import UpnpFactory from async_upnp_client.exceptions import UpnpError, UpnpResponseError from async_upnp_client.profiles.dlna import DmrDevice, TransportState from async_upnp_client.search import async_search -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ConfigEntryType, PlayerFeature, PlayerState, PlayerType from music_assistant_models.errors import PlayerUnavailableError from music_assistant_models.player import DeviceInfo, Player, PlayerMedia @@ -88,7 +88,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/fanarttv/__init__.py b/music_assistant/providers/fanarttv/__init__.py index 89a94c5b..f641cc50 100644 --- a/music_assistant/providers/fanarttv/__init__.py +++ b/music_assistant/providers/fanarttv/__init__.py @@ -16,7 +16,7 @@ from music_assistant.helpers.throttle_retry import Throttler from music_assistant.models.metadata_provider import MetadataProvider if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigValueTypes, ProviderConfig from music_assistant_models.media_items import Album, Artist from music_assistant_models.provider import ProviderManifest @@ -51,7 +51,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/filesystem_local/__init__.py b/music_assistant/providers/filesystem_local/__init__.py index fcfc0054..affbdf1a 100644 --- a/music_assistant/providers/filesystem_local/__init__.py +++ b/music_assistant/providers/filesystem_local/__init__.py @@ -90,7 +90,7 @@ from .helpers import ( ) if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.provider import ProviderManifest from music_assistant.mass import MusicAssistant @@ -116,7 +116,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/filesystem_local/constants.py b/music_assistant/providers/filesystem_local/constants.py index 81ba3304..cb536700 100644 --- a/music_assistant/providers/filesystem_local/constants.py +++ b/music_assistant/providers/filesystem_local/constants.py @@ -15,11 +15,11 @@ CONF_ENTRY_MISSING_ALBUM_ARTIST = ConfigEntry( default_value="various_artists", help_link="https://music-assistant.io/music-providers/filesystem/#tagging-files", required=False, - options=( + options=[ ConfigValueOption("Use Track artist(s)", "track_artist"), ConfigValueOption("Use Various Artists", "various_artists"), ConfigValueOption("Use Folder name (if possible)", "folder_name"), - ), + ], depends_on=CONF_CONTENT_TYPE, depends_on_value="music", ) @@ -39,11 +39,11 @@ CONF_ENTRY_CONTENT_TYPE = ConfigEntry( default_value="music", description="The type of content to expect in the media folder(s)", required=False, - options=( + options=[ ConfigValueOption("Music", "music"), ConfigValueOption("Audiobooks", "audiobooks"), ConfigValueOption("Podcasts", "podcasts"), - ), + ], ) CONF_ENTRY_CONTENT_TYPE_READ_ONLY = ConfigEntry.from_dict( { diff --git a/music_assistant/providers/filesystem_smb/__init__.py b/music_assistant/providers/filesystem_smb/__init__.py index 72b2213e..de4ee236 100644 --- a/music_assistant/providers/filesystem_smb/__init__.py +++ b/music_assistant/providers/filesystem_smb/__init__.py @@ -6,7 +6,7 @@ import os import platform from typing import TYPE_CHECKING -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ConfigEntryType from music_assistant_models.errors import LoginFailed @@ -56,7 +56,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/fully_kiosk/__init__.py b/music_assistant/providers/fully_kiosk/__init__.py index b096db65..630a8455 100644 --- a/music_assistant/providers/fully_kiosk/__init__.py +++ b/music_assistant/providers/fully_kiosk/__init__.py @@ -8,7 +8,7 @@ import time from typing import TYPE_CHECKING from fullykiosk import FullyKiosk -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ConfigEntryType, PlayerFeature, PlayerState, PlayerType from music_assistant_models.errors import PlayerUnavailableError, SetupFailedError from music_assistant_models.player import DeviceInfo, Player, PlayerMedia @@ -47,7 +47,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/hass/__init__.py b/music_assistant/providers/hass/__init__.py index c3c0a266..ace6ee7f 100644 --- a/music_assistant/providers/hass/__init__.py +++ b/music_assistant/providers/hass/__init__.py @@ -24,7 +24,12 @@ from hass_client.utils import ( get_token, get_websocket_url, ) -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType +from music_assistant_models.config_entries import ( + ConfigEntry, + ConfigValueOption, + ConfigValueTypes, + MultiValueConfigEntry, +) from music_assistant_models.enums import ConfigEntryType from music_assistant_models.errors import LoginFailed, SetupFailedError from music_assistant_models.player_control import PlayerControl @@ -65,7 +70,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -143,7 +148,7 @@ async def get_config_entries( label="URL", required=True, description="URL to your Home Assistant instance (e.g. http://192.168.1.1:8123)", - value=values.get(CONF_URL) if values else None, + value=cast(str, values.get(CONF_URL)) if values else None, ), ConfigEntry( key=CONF_ACTION_AUTH, @@ -162,7 +167,7 @@ async def get_config_entries( description="You can either paste a Long Lived Token here manually or use the " "'authenticate' button to generate a token for you with logging in.", depends_on=CONF_URL, - value=values.get(CONF_AUTH_TOKEN) if values else None, + value=cast(str, values.get(CONF_AUTH_TOKEN)) if values else None, category="advanced", ), ConfigEntry( @@ -183,26 +188,23 @@ async def get_config_entries( return ( *base_entries, - ConfigEntry( + MultiValueConfigEntry( key=CONF_POWER_CONTROLS, type=ConfigEntryType.STRING, label=CONF_POWER_CONTROLS, default_value=[], - multi_value=True, ), - ConfigEntry( + MultiValueConfigEntry( key=CONF_VOLUME_CONTROLS, type=ConfigEntryType.STRING, label=CONF_VOLUME_CONTROLS, default_value=[], - multi_value=True, ), - ConfigEntry( + MultiValueConfigEntry( key=CONF_MUTE_CONTROLS, type=ConfigEntryType.STRING, label=CONF_MUTE_CONTROLS, default_value=[], - multi_value=True, ), ) @@ -252,37 +254,34 @@ async def _get_player_control_config_entries(hass: HomeAssistantClient) -> tuple all_mute_entities.sort(key=lambda x: x.title) all_volume_entities.sort(key=lambda x: x.title) return ( - ConfigEntry( + MultiValueConfigEntry( key=CONF_POWER_CONTROLS, type=ConfigEntryType.STRING, label="Player Power Control entities", required=True, - options=tuple(all_power_entities), - multi_value=True, + options=all_power_entities, default_value=[], description="Specify which Home Assistant entities you " "like to import as player Power controls in Music Assistant.", category="player_controls", ), - ConfigEntry( + MultiValueConfigEntry( key=CONF_VOLUME_CONTROLS, type=ConfigEntryType.STRING, label="Player Volume Control entities", required=True, - options=tuple(all_volume_entities), - multi_value=True, + options=all_volume_entities, default_value=[], description="Specify which Home Assistant entities you " "like to import as player Volume controls in Music Assistant.", category="player_controls", ), - ConfigEntry( + MultiValueConfigEntry( key=CONF_MUTE_CONTROLS, type=ConfigEntryType.STRING, label="Player Mute Control entities", required=True, - options=tuple(all_mute_entities), - multi_value=True, + options=all_mute_entities, default_value=[], description="Specify which Home Assistant entities you " "like to import as player Mute controls in Music Assistant.", diff --git a/music_assistant/providers/hass_players/__init__.py b/music_assistant/providers/hass_players/__init__.py index 63f253ef..93a24a02 100644 --- a/music_assistant/providers/hass_players/__init__.py +++ b/music_assistant/providers/hass_players/__init__.py @@ -12,7 +12,12 @@ import time from typing import TYPE_CHECKING, Any from hass_client.exceptions import FailedCommand -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType +from music_assistant_models.config_entries import ( + ConfigEntry, + ConfigValueOption, + ConfigValueTypes, + MultiValueConfigEntry, +) from music_assistant_models.enums import ConfigEntryType, PlayerFeature, PlayerState, PlayerType from music_assistant_models.errors import SetupFailedError from music_assistant_models.player import DeviceInfo, Player, PlayerMedia @@ -124,7 +129,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, # noqa: ARG001 action: str | None = None, # noqa: ARG001 - values: dict[str, ConfigValueType] | None = None, # noqa: ARG001 + values: dict[str, ConfigValueTypes] | None = None, # noqa: ARG001 ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -140,13 +145,12 @@ async def get_config_entries( name = f"{state['attributes']['friendly_name']} ({state['entity_id']})" player_entities.append(ConfigValueOption(name, state["entity_id"])) return ( - ConfigEntry( + MultiValueConfigEntry( key=CONF_PLAYERS, type=ConfigEntryType.STRING, label="Player entities", required=True, - options=tuple(player_entities), - multi_value=True, + options=player_entities, description="Specify which HA media_player entity id's you " "like to import as players in Music Assistant.", ), diff --git a/music_assistant/providers/ibroadcast/__init__.py b/music_assistant/providers/ibroadcast/__init__.py index 2a3a11bc..39770488 100644 --- a/music_assistant/providers/ibroadcast/__init__.py +++ b/music_assistant/providers/ibroadcast/__init__.py @@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Any from aiohttp import ClientSession from ibroadcastaio import IBroadcastClient -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ( AlbumType, ConfigEntryType, @@ -74,7 +74,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/jellyfin/__init__.py b/music_assistant/providers/jellyfin/__init__.py index 9e698dcf..7480a7b2 100644 --- a/music_assistant/providers/jellyfin/__init__.py +++ b/music_assistant/providers/jellyfin/__init__.py @@ -11,7 +11,7 @@ from typing import TYPE_CHECKING from aiojellyfin import MediaLibrary as JellyMediaLibrary from aiojellyfin import NotFound, authenticate_by_name from aiojellyfin.session import SessionConfiguration -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.enums import ConfigEntryType, MediaType, ProviderFeature, StreamType from music_assistant_models.errors import LoginFailed, MediaNotFoundError from music_assistant_models.media_items import ( @@ -71,7 +71,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/musicbrainz/__init__.py b/music_assistant/providers/musicbrainz/__init__.py index a7522994..61daeee9 100644 --- a/music_assistant/providers/musicbrainz/__init__.py +++ b/music_assistant/providers/musicbrainz/__init__.py @@ -23,7 +23,7 @@ from music_assistant.helpers.util import parse_title_and_version from music_assistant.models.metadata_provider import MetadataProvider if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.media_items import Album, Track from music_assistant_models.provider import ProviderManifest @@ -47,7 +47,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/opensubsonic/__init__.py b/music_assistant/providers/opensubsonic/__init__.py index 2505c386..eb070f41 100644 --- a/music_assistant/providers/opensubsonic/__init__.py +++ b/music_assistant/providers/opensubsonic/__init__.py @@ -4,7 +4,7 @@ from __future__ import annotations from typing import TYPE_CHECKING -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType, ProviderConfig +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes, ProviderConfig from music_assistant_models.enums import ConfigEntryType from music_assistant.constants import CONF_PASSWORD, CONF_PATH, CONF_PORT, CONF_USERNAME @@ -35,7 +35,7 @@ async def get_config_entries( mass: MusicAssistant, # noqa: ARG001 instance_id: str | None = None, # noqa: ARG001 action: str | None = None, # noqa: ARG001 - values: dict[str, ConfigValueType] | None = None, # noqa: ARG001 + values: dict[str, ConfigValueTypes] | None = None, # noqa: ARG001 ) -> tuple[ConfigEntry, ...]: """Return Config entries to setup this provider.""" return ( diff --git a/music_assistant/providers/player_group/__init__.py b/music_assistant/providers/player_group/__init__.py index c1b89b90..259b193d 100644 --- a/music_assistant/providers/player_group/__init__.py +++ b/music_assistant/providers/player_group/__init__.py @@ -18,7 +18,8 @@ from aiohttp import web from music_assistant_models.config_entries import ( ConfigEntry, ConfigValueOption, - ConfigValueType, + ConfigValueTypes, + MultiValueConfigEntry, PlayerConfig, ) from music_assistant_models.constants import PLAYER_CONTROL_NATIVE, PLAYER_CONTROL_NONE @@ -100,13 +101,12 @@ CONF_ENTRY_GROUP_TYPE = ConfigEntry( hidden=True, required=True, ) -CONF_ENTRY_GROUP_MEMBERS = ConfigEntry( +CONF_ENTRY_GROUP_MEMBERS = MultiValueConfigEntry( key=CONF_GROUP_MEMBERS, type=ConfigEntryType.STRING, label="Group members", default_value=[], description="Select all players you want to be part of this group", - multi_value=True, required=False, # otherwise dynamic members won't work (which allows empty members list) ) CONF_ENTRY_SAMPLE_RATES_UGP = create_sample_rates_config_entry(44100, 16, 44100, 16, True) @@ -143,7 +143,7 @@ async def get_config_entries( mass: MusicAssistant, # noqa: ARG001 instance_id: str | None = None, # noqa: ARG001 action: str | None = None, # noqa: ARG001 - values: dict[str, ConfigValueType] | None = None, # noqa: ARG001 + values: dict[str, ConfigValueTypes] | None = None, # noqa: ARG001 ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/plex/__init__.py b/music_assistant/providers/plex/__init__.py index d4aa15a0..62a52146 100644 --- a/music_assistant/providers/plex/__init__.py +++ b/music_assistant/providers/plex/__init__.py @@ -14,7 +14,7 @@ import requests from music_assistant_models.config_entries import ( ConfigEntry, ConfigValueOption, - ConfigValueType, + ConfigValueTypes, ProviderConfig, ) from music_assistant_models.enums import ( @@ -105,7 +105,7 @@ async def get_config_entries( # noqa: PLR0915 mass: MusicAssistant, instance_id: str | None = None, # noqa: ARG001 action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -182,7 +182,7 @@ async def get_config_entries( # noqa: PLR0915 label="Local server IP", description="The local server IP (e.g. 192.168.1.77)", required=True, - value=values.get(CONF_LOCAL_SERVER_IP) if values else None, + value=cast(str, values.get(CONF_LOCAL_SERVER_IP)) if values else None, ), ConfigEntry( key=CONF_LOCAL_SERVER_PORT, @@ -191,7 +191,7 @@ async def get_config_entries( # noqa: PLR0915 description="The local server port (e.g. 32400)", required=True, default_value=32400, - value=values.get(CONF_LOCAL_SERVER_PORT) if values else None, + value=cast(int, values.get(CONF_LOCAL_SERVER_PORT)) if values else None, ), ConfigEntry( key=CONF_LOCAL_SERVER_SSL, @@ -216,7 +216,7 @@ async def get_config_entries( # noqa: PLR0915 type=ConfigEntryType.SECURE_STRING, label=CONF_AUTH_TOKEN, action=CONF_AUTH_TOKEN, - value=values.get(CONF_AUTH_TOKEN) if values else None, + value=cast(str | None, values.get(CONF_AUTH_TOKEN)) if values else None, hidden=True, ), ] @@ -257,7 +257,7 @@ async def get_config_entries( # noqa: PLR0915 ): msg = "Unable to retrieve Servers and/or Music Libraries" raise LoginFailed(msg) - conf_libraries.options = tuple( + conf_libraries.options = [ # use the same value for both the value and the title # until we find out what plex uses as stable identifiers ConfigValueOption( @@ -265,7 +265,7 @@ async def get_config_entries( # noqa: PLR0915 value=x, ) for x in libraries - ) + ] # select first library as (default) value conf_libraries.default_value = libraries[0] conf_libraries.value = libraries[0] diff --git a/music_assistant/providers/podcastfeed/__init__.py b/music_assistant/providers/podcastfeed/__init__.py index 0e18cc7f..bc69bfa7 100644 --- a/music_assistant/providers/podcastfeed/__init__.py +++ b/music_assistant/providers/podcastfeed/__init__.py @@ -14,7 +14,7 @@ from io import BytesIO from typing import TYPE_CHECKING import podcastparser -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ( ConfigEntryType, ContentType, @@ -63,7 +63,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -76,7 +76,6 @@ async def get_config_entries( ConfigEntry( key=CONF_FEED_URL, type=ConfigEntryType.STRING, - default_value=[], label="RSS Feed URL", required=True, ), diff --git a/music_assistant/providers/qobuz/__init__.py b/music_assistant/providers/qobuz/__init__.py index 0549e454..5b7f774f 100644 --- a/music_assistant/providers/qobuz/__init__.py +++ b/music_assistant/providers/qobuz/__init__.py @@ -9,7 +9,7 @@ from contextlib import suppress from typing import TYPE_CHECKING from aiohttp import client_exceptions -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ( AlbumType, ConfigEntryType, @@ -91,7 +91,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/radiobrowser/__init__.py b/music_assistant/providers/radiobrowser/__init__.py index 1b85736b..3f617813 100644 --- a/music_assistant/providers/radiobrowser/__init__.py +++ b/music_assistant/providers/radiobrowser/__init__.py @@ -5,7 +5,7 @@ from __future__ import annotations from collections.abc import AsyncGenerator, Sequence from typing import TYPE_CHECKING, cast -from music_assistant_models.config_entries import ConfigEntry +from music_assistant_models.config_entries import ConfigEntry, MultiValueConfigEntry from music_assistant_models.enums import ( ConfigEntryType, ContentType, @@ -44,7 +44,7 @@ SUPPORTED_FEATURES = { } if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigValueTypes, ProviderConfig from music_assistant_models.provider import ProviderManifest from music_assistant.mass import MusicAssistant @@ -64,7 +64,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -74,7 +74,7 @@ async def get_config_entries( """ # ruff: noqa: ARG001 D205 return ( - ConfigEntry( + MultiValueConfigEntry( # RadioBrowser doesn't support a library feature at all # but MA users like to favorite their radio stations and # have that included in backups so we store it in the config. @@ -83,7 +83,6 @@ async def get_config_entries( label=CONF_STORED_RADIOS, default_value=[], required=False, - multi_value=True, hidden=True, ), ) diff --git a/music_assistant/providers/siriusxm/__init__.py b/music_assistant/providers/siriusxm/__init__.py index 45ddc7ae..cef97208 100644 --- a/music_assistant/providers/siriusxm/__init__.py +++ b/music_assistant/providers/siriusxm/__init__.py @@ -5,7 +5,7 @@ from __future__ import annotations from collections.abc import AsyncGenerator, Awaitable, Sequence from typing import TYPE_CHECKING, Any, cast -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueTypes from music_assistant_models.enums import ( ConfigEntryType, ContentType, @@ -58,7 +58,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -85,10 +85,10 @@ async def get_config_entries( key=CONF_SXM_REGION, type=ConfigEntryType.STRING, default_value="US", - options=( + options=[ ConfigValueOption(title="United States", value="US"), ConfigValueOption(title="Canada", value="CA"), - ), + ], label="Region", required=True, ), diff --git a/music_assistant/providers/slimproto/__init__.py b/music_assistant/providers/slimproto/__init__.py index d8a75624..153503e0 100644 --- a/music_assistant/providers/slimproto/__init__.py +++ b/music_assistant/providers/slimproto/__init__.py @@ -22,7 +22,7 @@ from aioslimproto.server import SlimServer from music_assistant_models.config_entries import ( ConfigEntry, ConfigValueOption, - ConfigValueType, + ConfigValueTypes, PlayerConfig, ) from music_assistant_models.enums import ( @@ -126,10 +126,10 @@ CONF_ENTRY_VISUALIZATION = ConfigEntry( key=CONF_VISUALIZATION, type=ConfigEntryType.STRING, default_value=DEFAULT_VISUALIZATION, - options=tuple( + options=[ ConfigValueOption(title=x.name.replace("_", " ").title(), value=x.value) for x in SlimVisualisationType - ), + ], required=False, label="Visualization type", description="The type of visualization to show on the display " @@ -150,7 +150,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/snapcast/__init__.py b/music_assistant/providers/snapcast/__init__.py index 1cae193f..f2d8d5b6 100644 --- a/music_assistant/providers/snapcast/__init__.py +++ b/music_assistant/providers/snapcast/__init__.py @@ -13,7 +13,7 @@ from contextlib import suppress from typing import TYPE_CHECKING, Final, cast from bidict import bidict -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueTypes from music_assistant_models.enums import ( ConfigEntryType, ContentType, @@ -114,7 +114,7 @@ async def get_config_entries( mass: MusicAssistant, # noqa: ARG001 instance_id: str | None = None, # noqa: ARG001 action: str | None = None, # noqa: ARG001 - values: dict[str, ConfigValueType] | None = None, # noqa: ARG001 + values: dict[str, ConfigValueTypes] | None = None, # noqa: ARG001 ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -176,7 +176,7 @@ async def get_config_entries( ConfigEntry( key=CONF_SERVER_TRANSPORT_CODEC, type=ConfigEntryType.STRING, - options=( + options=[ ConfigValueOption( title="FLAC", value="flac", @@ -193,7 +193,7 @@ async def get_config_entries( title="PCM", value="pcm", ), - ), + ], default_value="flac", label="Snapserver default transport codec", required=False, diff --git a/music_assistant/providers/sonos/__init__.py b/music_assistant/providers/sonos/__init__.py index 0ccfa50c..95c95a1d 100644 --- a/music_assistant/providers/sonos/__init__.py +++ b/music_assistant/providers/sonos/__init__.py @@ -17,7 +17,7 @@ from music_assistant.constants import VERBOSE_LOG_LEVEL from .provider import CONF_IPS, SonosPlayerProvider if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigValueTypes, ProviderConfig from music_assistant_models.provider import ProviderManifest from music_assistant import MusicAssistant @@ -41,7 +41,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/sonos_s1/__init__.py b/music_assistant/providers/sonos_s1/__init__.py index 23c0474b..e5068323 100644 --- a/music_assistant/providers/sonos_s1/__init__.py +++ b/music_assistant/providers/sonos_s1/__init__.py @@ -15,7 +15,7 @@ from collections import OrderedDict from dataclasses import dataclass, field from typing import TYPE_CHECKING, cast -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ( ConfigEntryType, PlayerFeature, @@ -89,7 +89,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/soundcloud/__init__.py b/music_assistant/providers/soundcloud/__init__.py index e0363ed9..88c43496 100644 --- a/music_assistant/providers/soundcloud/__init__.py +++ b/music_assistant/providers/soundcloud/__init__.py @@ -5,7 +5,7 @@ from __future__ import annotations import time from typing import TYPE_CHECKING, Any -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ( ConfigEntryType, ContentType, @@ -69,7 +69,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/spotify/__init__.py b/music_assistant/providers/spotify/__init__.py index 804ac419..c3112413 100644 --- a/music_assistant/providers/spotify/__init__.py +++ b/music_assistant/providers/spotify/__init__.py @@ -10,7 +10,7 @@ import time from typing import TYPE_CHECKING, Any, cast from urllib.parse import urlencode -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ( AlbumType, ConfigEntryType, @@ -125,7 +125,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/spotify_connect/__init__.py b/music_assistant/providers/spotify_connect/__init__.py index 7c96224d..4b404a96 100644 --- a/music_assistant/providers/spotify_connect/__init__.py +++ b/music_assistant/providers/spotify_connect/__init__.py @@ -35,7 +35,7 @@ from music_assistant.providers.spotify.helpers import get_librespot_binary if TYPE_CHECKING: from aiohttp.web import Request - from music_assistant_models.config_entries import ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigValueTypes, ProviderConfig from music_assistant_models.event import MassEvent from music_assistant_models.provider import ProviderManifest @@ -60,7 +60,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, # noqa: ARG001 action: str | None = None, # noqa: ARG001 - values: dict[str, ConfigValueType] | None = None, # noqa: ARG001 + values: dict[str, ConfigValueTypes] | None = None, # noqa: ARG001 ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -77,10 +77,10 @@ async def get_config_entries( label="Connected Music Assistant Player", description="Select the player for which you want to enable Spotify Connect.", multi_value=False, - options=tuple( + options=[ ConfigValueOption(x.display_name, x.player_id) for x in mass.players.all(False, False) - ), + ], required=True, ), # ConfigEntry( diff --git a/music_assistant/providers/test/__init__.py b/music_assistant/providers/test/__init__.py index d645ad52..e3d3d2bf 100644 --- a/music_assistant/providers/test/__init__.py +++ b/music_assistant/providers/test/__init__.py @@ -35,7 +35,7 @@ from music_assistant.constants import MASS_LOGO, SILENCE_FILE_LONG, VARIOUS_ARTI from music_assistant.models.music_provider import MusicProvider if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigValueTypes, ProviderConfig from music_assistant_models.provider import ProviderManifest from music_assistant.mass import MusicAssistant @@ -74,7 +74,7 @@ async def get_config_entries( mass: MusicAssistant, # noqa: ARG001 instance_id: str | None = None, # noqa: ARG001 action: str | None = None, # noqa: ARG001 - values: dict[str, ConfigValueType] | None = None, # noqa: ARG001 + values: dict[str, ConfigValueTypes] | None = None, # noqa: ARG001 ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/theaudiodb/__init__.py b/music_assistant/providers/theaudiodb/__init__.py index ded4f559..c732284d 100644 --- a/music_assistant/providers/theaudiodb/__init__.py +++ b/music_assistant/providers/theaudiodb/__init__.py @@ -32,7 +32,7 @@ from music_assistant.helpers.throttle_retry import Throttler from music_assistant.models.metadata_provider import MetadataProvider if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigValueType, ProviderConfig + from music_assistant_models.config_entries import ConfigValueTypes, ProviderConfig from music_assistant_models.provider import ProviderManifest from music_assistant.mass import MusicAssistant @@ -94,7 +94,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/tidal/__init__.py b/music_assistant/providers/tidal/__init__.py index b9c3026f..14664551 100644 --- a/music_assistant/providers/tidal/__init__.py +++ b/music_assistant/providers/tidal/__init__.py @@ -11,7 +11,7 @@ from datetime import datetime, timedelta from enum import StrEnum from typing import TYPE_CHECKING, ParamSpec, TypeVar, cast -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueTypes from music_assistant_models.enums import ( AlbumType, CacheCategory, @@ -165,7 +165,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, # noqa: ARG001 action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. @@ -226,8 +226,8 @@ async def get_config_entries( label=CONF_QUALITY, required=True, hidden=True, - default_value=values.get(CONF_QUALITY, TidalQualityEnum.HI_RES.value), - value=values.get(CONF_QUALITY), + value=cast(str, values.get(CONF_QUALITY) or TidalQualityEnum.HI_RES.value), + default_value=cast(str, values.get(CONF_QUALITY) or TidalQualityEnum.HI_RES.value), ), ) else: @@ -238,9 +238,9 @@ async def get_config_entries( label="Quality setting for Tidal:", required=True, description="HIGH_LOSSLESS = 16bit 44.1kHz, HI_RES = Up to 24bit 192kHz", - options=tuple(ConfigValueOption(x.value, x.name) for x in TidalQualityEnum), + options=[ConfigValueOption(x.value, x.name) for x in TidalQualityEnum], default_value=TidalQualityEnum.HI_RES.value, - value=values.get(CONF_QUALITY) if values else None, + value=cast(str, values.get(CONF_QUALITY)) if values else None, ), ConfigEntry( key=LABEL_START_PKCE_LOGIN, @@ -261,7 +261,7 @@ async def get_config_entries( action=CONF_ACTION_START_PKCE_LOGIN, depends_on=CONF_QUALITY, action_label="Starts the auth process via PKCE on Tidal.com", - value=values.get(CONF_TEMP_SESSION) if values else None, + value=cast(str, values.get(CONF_TEMP_SESSION)) if values else None, hidden=action == CONF_ACTION_START_PKCE_LOGIN, ), ConfigEntry( @@ -270,7 +270,7 @@ async def get_config_entries( label="Temporary session for Tidal", hidden=True, required=False, - value=values.get(CONF_TEMP_SESSION) if values else None, + value=cast(str, values.get(CONF_TEMP_SESSION)) if values else None, ), ConfigEntry( key=LABEL_OOPS_URL, @@ -287,7 +287,7 @@ async def get_config_entries( " Tidal.com and being redirected to a page that prominently displays" " 'Oops' at the top.", depends_on=CONF_ACTION_START_PKCE_LOGIN, - value=values.get(CONF_OOPS_URL) if values else None, + value=cast(str, values.get(CONF_OOPS_URL)) if values else None, hidden=action != CONF_ACTION_START_PKCE_LOGIN, ), ConfigEntry( @@ -320,7 +320,7 @@ async def get_config_entries( label="Authentication token for Tidal", description="You need to link Music Assistant to your Tidal account.", hidden=True, - value=values.get(CONF_AUTH_TOKEN) if values else None, + value=cast(str, values.get(CONF_AUTH_TOKEN)) if values else None, ), ConfigEntry( key=CONF_REFRESH_TOKEN, @@ -328,14 +328,14 @@ async def get_config_entries( label="Refresh token for Tidal", description="You need to link Music Assistant to your Tidal account.", hidden=True, - value=values.get(CONF_REFRESH_TOKEN) if values else None, + value=cast(str, values.get(CONF_REFRESH_TOKEN)) if values else None, ), ConfigEntry( key=CONF_EXPIRY_TIME, type=ConfigEntryType.STRING, label="Expiry time of auth token for Tidal", hidden=True, - value=values.get(CONF_EXPIRY_TIME) if values else None, + value=cast(str, values.get(CONF_EXPIRY_TIME)) if values else None, ), ConfigEntry( key=CONF_USER_ID, @@ -343,7 +343,7 @@ async def get_config_entries( label="Your Tidal User ID", description="This is your unique Tidal user ID.", hidden=True, - value=values.get(CONF_USER_ID) if values else None, + value=cast(str, values.get(CONF_USER_ID)) if values else None, ), ) diff --git a/music_assistant/providers/tunein/__init__.py b/music_assistant/providers/tunein/__init__.py index c03a2ddf..b4595155 100644 --- a/music_assistant/providers/tunein/__init__.py +++ b/music_assistant/providers/tunein/__init__.py @@ -4,7 +4,7 @@ from __future__ import annotations from typing import TYPE_CHECKING -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ( ConfigEntryType, ContentType, @@ -56,7 +56,7 @@ async def get_config_entries( mass: MusicAssistant, instance_id: str | None = None, action: str | None = None, - values: dict[str, ConfigValueType] | None = None, + values: dict[str, ConfigValueTypes] | None = None, ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/music_assistant/providers/ytmusic/__init__.py b/music_assistant/providers/ytmusic/__init__.py index 4e39a0cf..101b3d32 100644 --- a/music_assistant/providers/ytmusic/__init__.py +++ b/music_assistant/providers/ytmusic/__init__.py @@ -11,7 +11,7 @@ from urllib.parse import unquote import yt_dlp from duration_parser import parse as parse_str_duration -from music_assistant_models.config_entries import ConfigEntry, ConfigValueType +from music_assistant_models.config_entries import ConfigEntry, ConfigValueTypes from music_assistant_models.enums import ( AlbumType, ConfigEntryType, @@ -136,7 +136,7 @@ async def get_config_entries( mass: MusicAssistant, # noqa: ARG001 instance_id: str | None = None, # noqa: ARG001 action: str | None = None, # noqa: ARG001 - values: dict[str, ConfigValueType] | None = None, # noqa: ARG001 + values: dict[str, ConfigValueTypes] | None = None, # noqa: ARG001 ) -> tuple[ConfigEntry, ...]: """ Return Config entries to setup this provider. diff --git a/pyproject.toml b/pyproject.toml index 4dc657ad..a5cb57d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ dependencies = [ "mashumaro==3.15", "memory-tempfile==2.2.3", "music-assistant-frontend==2.11.5", - "music-assistant-models==1.1.27", + "music-assistant-models==1.1.28", "mutagen==1.47.0", "orjson==3.10.12", "pillow==11.1.0", diff --git a/requirements_all.txt b/requirements_all.txt index d85cd324..642e0aef 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -26,7 +26,7 @@ ifaddr==0.2.0 mashumaro==3.15 memory-tempfile==2.2.3 music-assistant-frontend==2.11.5 -music-assistant-models==1.1.27 +music-assistant-models==1.1.28 mutagen==1.47.0 orjson==3.10.12 pillow==11.1.0