From: Marcel van der Veldt Date: Wed, 29 Oct 2025 12:59:02 +0000 (+0100) Subject: Add support for actions flow in Player config entries (#2572) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=0876fcfa21816f3be8f6275d4fe96e73ee8da5d1;p=music-assistant-server.git Add support for actions flow in Player config entries (#2572) --- diff --git a/music_assistant/controllers/config.py b/music_assistant/controllers/config.py index 88ee22ea..9a91a633 100644 --- a/music_assistant/controllers/config.py +++ b/music_assistant/controllers/config.py @@ -68,6 +68,7 @@ from music_assistant.constants import ( from music_assistant.helpers.api import api_command from music_assistant.helpers.json import JSON_DECODE_EXCEPTIONS, async_json_dumps, async_json_loads from music_assistant.helpers.util import load_provider_module +from music_assistant.models import ProviderModuleType if TYPE_CHECKING: import asyncio @@ -244,7 +245,7 @@ class ConfigController: return val @api_command("config/providers/get_entries") - async def get_provider_config_entries( + async def get_provider_config_entries( # noqa: PLR0915 self, provider_domain: str, instance_id: str | None = None, @@ -260,13 +261,21 @@ class ConfigController: values: the (intermediate) raw values for config entries sent with the action. """ # lookup provider manifest and module + prov_mod: ProviderModuleType | None for manifest in self.mass.get_provider_manifests(): if manifest.domain == provider_domain: - prov_mod = await load_provider_module(provider_domain, manifest.requirements) + try: + prov_mod = await load_provider_module(provider_domain, manifest.requirements) + except Exception as e: + msg = f"Failed to load provider module for {provider_domain}: {e}" + LOGGER.exception(msg) + return [] break else: msg = f"Unknown provider domain: {provider_domain}" - raise KeyError(msg) + LOGGER.exception(msg) + return [] + if values is None: values = self.get(f"{CONF_PROVIDERS}/{instance_id}/values", {}) if instance_id else {} @@ -416,14 +425,22 @@ class ConfigController: ] @api_command("config/players/get") - async def get_player_config(self, player_id: str) -> PlayerConfig: + async def get_player_config( + self, + player_id: str, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> PlayerConfig: """Return (full) configuration for a single player.""" raw_conf: dict[str, Any] if raw_conf := self.get(f"{CONF_PLAYERS}/{player_id}"): if player := self.mass.players.get(player_id, False): raw_conf["default_name"] = player.display_name raw_conf["provider"] = player.provider.lookup_key - conf_entries = await player.get_config_entries() + # pass action and values to get_config_entries + if values is None: + values = raw_conf.get("values", {}) + conf_entries = await player.get_config_entries(action=action, values=values) else: # handle unavailable player and/or provider conf_entries = [] @@ -434,6 +451,29 @@ class ConfigController: msg = f"No config found for player id {player_id}" raise KeyError(msg) + @api_command("config/players/get_entries") + async def get_player_config_entries( + self, + player_id: str, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: + """ + Return Config entries to configure a player. + + player_id: id of an existing player instance. + action: [optional] action key called from config entries UI. + values: the (intermediate) raw values for config entries sent with the action. + """ + if not (player := self.mass.players.get(player_id, False)): + msg = f"Player {player_id} not found" + raise KeyError(msg) + + if values is None: + values = self.get(f"{CONF_PLAYERS}/{player_id}/values", {}) + + return await player.get_config_entries(action=action, values=values) + @api_command("config/players/get_value") async def get_player_config_value( self, diff --git a/music_assistant/controllers/players/sync_groups.py b/music_assistant/controllers/players/sync_groups.py index 4ee5a183..9b186752 100644 --- a/music_assistant/controllers/players/sync_groups.py +++ b/music_assistant/controllers/players/sync_groups.py @@ -13,7 +13,7 @@ from copy import deepcopy from typing import TYPE_CHECKING, cast import shortuuid -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption +from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType from music_assistant_models.constants import PLAYER_CONTROL_NONE from music_assistant_models.enums import ( ConfigEntryType, @@ -184,11 +184,15 @@ class SyncGroupPlayer(GroupPlayer): else: return set() - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the given player (if any).""" entries: list[ConfigEntry] = [ # default entries for player groups - *await super().get_config_entries(), + *await super().get_config_entries(action=action, values=values), # add syncgroup specific entries ConfigEntry( key=CONF_GROUP_MEMBERS, diff --git a/music_assistant/models/player.py b/music_assistant/models/player.py index 92fc4d30..b13679b9 100644 --- a/music_assistant/models/player.py +++ b/music_assistant/models/player.py @@ -15,7 +15,12 @@ from collections.abc import Callable from copy import deepcopy from typing import TYPE_CHECKING, Any, cast, final -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, PlayerConfig +from music_assistant_models.config_entries import ( + ConfigEntry, + ConfigValueOption, + ConfigValueType, + PlayerConfig, +) from music_assistant_models.constants import ( PLAYER_CONTROL_FAKE, PLAYER_CONTROL_NATIVE, @@ -581,8 +586,14 @@ class Player(ABC): async def get_config_entries( self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, ) -> list[ConfigEntry]: - """Return all (provider/player specific) Config Entries for the player.""" + """Return all (provider/player specific) Config Entries for the player. + + action: [optional] action key called from config entries UI. + values: the (intermediate) raw values for config entries sent with the action. + """ # Return all base config entries for a player. # Feel free to override but ensure to include the base entries by calling super() first. # To override the default config entries, simply define an entry with the same key @@ -1426,8 +1437,16 @@ class GroupPlayer(Player): # default implementation: groups can't be synced return None - async def get_config_entries(self) -> list[ConfigEntry]: - """Return all (provider/player specific) Config Entries for the player.""" + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: + """Return all (provider/player specific) Config Entries for the player. + + action: [optional] action key called from config entries UI. + values: the (intermediate) raw values for config entries sent with the action. + """ # Return all base config entries for a group player. # Feel free to override but ensure to include the base entries by calling super() first. # To override the default config entries, simply define an entry with the same key diff --git a/music_assistant/providers/_demo_player_provider/player.py b/music_assistant/providers/_demo_player_provider/player.py index 72c54492..8f91ffd5 100644 --- a/music_assistant/providers/_demo_player_provider/player.py +++ b/music_assistant/providers/_demo_player_provider/player.py @@ -4,7 +4,7 @@ from __future__ import annotations from typing import TYPE_CHECKING -from music_assistant_models.config_entries import ConfigEntry +from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from music_assistant_models.enums import ConfigEntryType, PlaybackState, PlayerFeature, PlayerType from music_assistant_models.player import PlayerSource @@ -84,14 +84,18 @@ class DemoPlayer(Player): ), ] - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the player.""" # OPTIONAL # this method is optional and should be implemented if you need player specific # configuration entries. If you do not need player specific configuration entries, # you can leave this method out completely to accept the default implementation. # Please note that you need to call the super() method to get the default entries. - default_entries = await super().get_config_entries() + default_entries = await super().get_config_entries(action=action, values=values) return [ *default_entries, # example of a player specific config entry diff --git a/music_assistant/providers/airplay/player.py b/music_assistant/providers/airplay/player.py index 8f73efde..c11b7a07 100644 --- a/music_assistant/providers/airplay/player.py +++ b/music_assistant/providers/airplay/player.py @@ -6,7 +6,7 @@ import asyncio import time from typing import TYPE_CHECKING, cast -from music_assistant_models.config_entries import ConfigEntry +from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from music_assistant_models.enums import ( ConfigEntryType, ContentType, @@ -104,10 +104,14 @@ class AirPlayPlayer(Player): self._attr_can_group_with = {provider.lookup_key} self._attr_enabled_by_default = not is_broken_raop_model(manufacturer, model) - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the given player (if any).""" - base_entries = [ - *await super().get_config_entries(), + base_entries = await super().get_config_entries(action=action, values=values) + base_entries += [ CONF_ENTRY_FLOW_MODE_ENFORCED, CONF_ENTRY_DEPRECATED_EQ_BASS, CONF_ENTRY_DEPRECATED_EQ_MID, diff --git a/music_assistant/providers/alexa/__init__.py b/music_assistant/providers/alexa/__init__.py index 685a17ce..e98072e6 100644 --- a/music_assistant/providers/alexa/__init__.py +++ b/music_assistant/providers/alexa/__init__.py @@ -368,9 +368,13 @@ class AlexaPlayer(Player): self._attr_playback_state = PlaybackState.PLAYING self.update_state() - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the given player (if any).""" - base_entries = await super().get_config_entries() + base_entries = await super().get_config_entries(action=action, values=values) return [ *base_entries, CONF_ENTRY_FLOW_MODE_ENFORCED, diff --git a/music_assistant/providers/bluesound/player.py b/music_assistant/providers/bluesound/player.py index 1329c2bf..11d44b6e 100644 --- a/music_assistant/providers/bluesound/player.py +++ b/music_assistant/providers/bluesound/player.py @@ -6,7 +6,7 @@ import asyncio import time from typing import TYPE_CHECKING -from music_assistant_models.config_entries import ConfigEntry +from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from music_assistant_models.enums import PlaybackState, PlayerFeature, PlayerType from music_assistant_models.errors import PlayerCommandFailed from pyblu import Player as BluosPlayer @@ -84,10 +84,14 @@ class BluesoundPlayer(Player): self._attr_supported_features.add(PlayerFeature.VOLUME_SET) await self.mass.players.register_or_update(self) - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the player.""" return [ - *await super().get_config_entries(), + *await super().get_config_entries(action=action, values=values), CONF_ENTRY_HTTP_PROFILE_DEFAULT_3, create_sample_rates_config_entry( max_sample_rate=192000, diff --git a/music_assistant/providers/builtin_player/player.py b/music_assistant/providers/builtin_player/player.py index 00130ccf..c481968b 100644 --- a/music_assistant/providers/builtin_player/player.py +++ b/music_assistant/providers/builtin_player/player.py @@ -7,7 +7,7 @@ from time import time from aiohttp import web from music_assistant_models.builtin_player import BuiltinPlayerEvent, BuiltinPlayerState -from music_assistant_models.config_entries import ConfigEntry +from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from music_assistant_models.constants import PLAYER_CONTROL_NATIVE from music_assistant_models.enums import ( BuiltinPlayerEventType, @@ -95,9 +95,13 @@ class BuiltinPlayer(Player): if update_state: self.update_state() - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the player.""" - base_entries = await super().get_config_entries() + base_entries = await super().get_config_entries(action=action, values=values) return [ *base_entries, CONF_ENTRY_FLOW_MODE_ENFORCED, diff --git a/music_assistant/providers/chromecast/player.py b/music_assistant/providers/chromecast/player.py index 474bf5a4..506da070 100644 --- a/music_assistant/providers/chromecast/player.py +++ b/music_assistant/providers/chromecast/player.py @@ -7,6 +7,10 @@ import time from typing import TYPE_CHECKING, Any, cast from uuid import UUID +from music_assistant_models.config_entries import ConfigEntry + +if TYPE_CHECKING: + from music_assistant_models.config_entries import ConfigValueType from music_assistant_models.enums import MediaType, PlaybackState, PlayerFeature, PlayerType from music_assistant_models.errors import PlayerUnavailableError from music_assistant_models.player import PlayerSource @@ -104,9 +108,13 @@ class ChromecastPlayer(Player): self.mz_controller = mz_controller self.cc.start() - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the given player (if any).""" - base_entries = await super().get_config_entries() + base_entries = await super().get_config_entries(action=action, values=values) if self.type == PlayerType.GROUP: return [ *base_entries, diff --git a/music_assistant/providers/dlna/player.py b/music_assistant/providers/dlna/player.py index 3a9b24aa..1bfa31a4 100644 --- a/music_assistant/providers/dlna/player.py +++ b/music_assistant/providers/dlna/player.py @@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, Any, Concatenate from async_upnp_client.client import UpnpService, UpnpStateVariable from async_upnp_client.exceptions import UpnpError, UpnpResponseError from async_upnp_client.profiles.dlna import DmrDevice, TransportState -from music_assistant_models.config_entries import ConfigEntry +from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from music_assistant_models.enums import PlaybackState, PlayerFeature from music_assistant_models.errors import PlayerUnavailableError from music_assistant_models.player import DeviceInfo, PlayerMedia @@ -260,9 +260,11 @@ class DLNAPlayer(Player): async def get_config_entries( self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the given player (if any).""" - base_entries = await super().get_config_entries() + base_entries = await super().get_config_entries(action=action, values=values) return base_entries + PLAYER_CONFIG_ENTRIES # async def on_player_config_change( diff --git a/music_assistant/providers/fully_kiosk/player.py b/music_assistant/providers/fully_kiosk/player.py index 3e1d782b..4efdb026 100644 --- a/music_assistant/providers/fully_kiosk/player.py +++ b/music_assistant/providers/fully_kiosk/player.py @@ -18,7 +18,7 @@ from music_assistant.models.player import DeviceInfo, Player, PlayerMedia if TYPE_CHECKING: from fullykiosk import FullyKiosk - from music_assistant_models.config_entries import ConfigEntry + from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from .provider import FullyKioskProvider @@ -51,9 +51,13 @@ class FullyKioskPlayer(Player): self._attr_needs_poll = True self._attr_poll_interval = 10 - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the given player (if any).""" - base_entries = await super().get_config_entries() + base_entries = await super().get_config_entries(action=action, values=values) return [ *base_entries, CONF_ENTRY_FLOW_MODE_ENFORCED, diff --git a/music_assistant/providers/hass_players/player.py b/music_assistant/providers/hass_players/player.py index 4a218ee2..948fa099 100644 --- a/music_assistant/providers/hass_players/player.py +++ b/music_assistant/providers/hass_players/player.py @@ -40,7 +40,7 @@ if TYPE_CHECKING: from hass_client.models import CompressedState from hass_client.models import Entity as HassEntity from hass_client.models import State as HassState - from music_assistant_models.config_entries import ConfigEntry + from music_assistant_models.config_entries import ConfigEntry, ConfigValueType DEFAULT_PLAYER_CONFIG_ENTRIES = ( @@ -106,9 +106,13 @@ class HomeAssistantPlayer(Player): self.extra_data["hass_supported_features"] = hass_supported_features self._update_attributes(hass_state["attributes"]) - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the player.""" - base_entries = await super().get_config_entries() + base_entries = await super().get_config_entries(action=action, values=values) base_entries = [*base_entries, *DEFAULT_PLAYER_CONFIG_ENTRIES] if self.extra_data.get("esphome_supported_audio_formats"): # optimized config for new ESPHome mediaplayer diff --git a/music_assistant/providers/musiccast/player.py b/music_assistant/providers/musiccast/player.py index b88bbdbc..433ae2a2 100644 --- a/music_assistant/providers/musiccast/player.py +++ b/music_assistant/providers/musiccast/player.py @@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, Any, cast from aiohttp import ServerDisconnectedError from aiomusiccast.exceptions import MusicCastGroupException from aiomusiccast.pyamaha import MusicCastConnectionException -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption +from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType from music_assistant_models.enums import ConfigEntryType, PlaybackState, PlayerFeature from music_assistant_models.player import DeviceInfo, PlayerMedia, PlayerSource from propcache import under_cached_property as cached_property @@ -580,9 +580,13 @@ class MusicCastPlayer(Player): await self._cmd_run(self.zone_device.join_players, child_player_zone_devices) - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Get player config entries.""" - base_entries = await super().get_config_entries() + base_entries = await super().get_config_entries(action=action, values=values) zone_entries: list[ConfigEntry] = [] if len(self.physical_device.zone_devices) > 1: diff --git a/music_assistant/providers/resonate/player.py b/music_assistant/providers/resonate/player.py index dd32093d..8036ecae 100644 --- a/music_assistant/providers/resonate/player.py +++ b/music_assistant/providers/resonate/player.py @@ -11,9 +11,7 @@ from typing import TYPE_CHECKING, cast from aioresonate.models import MediaCommand from aioresonate.models.types import PlaybackStateType from aioresonate.models.types import RepeatMode as ResonateRepeatMode -from aioresonate.server import ( - AudioFormat as ResonateAudioFormat, -) +from aioresonate.server import AudioFormat as ResonateAudioFormat from aioresonate.server import ( ClientEvent, GroupCommandEvent, @@ -21,10 +19,7 @@ from aioresonate.server import ( GroupStateChangedEvent, VolumeChangedEvent, ) -from aioresonate.server.client import ( - ClientGroupChangedEvent, - DisconnectBehaviour, -) +from aioresonate.server.client import ClientGroupChangedEvent, DisconnectBehaviour from aioresonate.server.group import ( AudioCodec, GroupDeletedEvent, @@ -32,7 +27,7 @@ from aioresonate.server.group import ( GroupMemberRemovedEvent, Metadata, ) -from music_assistant_models.config_entries import ConfigEntry +from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from music_assistant_models.constants import PLAYER_CONTROL_NONE from music_assistant_models.enums import ( ContentType, @@ -354,9 +349,13 @@ class ResonatePlayer(Player): # Send metadata to the group self.api.group.set_metadata(metadata) - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the player.""" - default_entries = await super().get_config_entries() + default_entries = await super().get_config_entries(action=action, values=values) return [ *default_entries, ConfigEntry.from_dict( diff --git a/music_assistant/providers/roku_media_assistant/player.py b/music_assistant/providers/roku_media_assistant/player.py index fab76d71..b5f1ef56 100644 --- a/music_assistant/providers/roku_media_assistant/player.py +++ b/music_assistant/providers/roku_media_assistant/player.py @@ -15,7 +15,7 @@ from music_assistant.models.player import Player, PlayerMedia from .constants import CONF_ROKU_APP_ID if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigEntry + from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from rokuecp import Roku from .provider import MediaAssistantprovider @@ -65,9 +65,13 @@ class MediaAssistantPlayer(Player): """Return the interval in seconds to poll the player for state updates.""" return 5 if self.powered else 30 - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the player.""" - default_entries = await super().get_config_entries() + default_entries = await super().get_config_entries(action=action, values=values) return [ *default_entries, CONF_ENTRY_HTTP_PROFILE, diff --git a/music_assistant/providers/snapcast/player.py b/music_assistant/providers/snapcast/player.py index eab60597..5a76f5c0 100644 --- a/music_assistant/providers/snapcast/player.py +++ b/music_assistant/providers/snapcast/player.py @@ -7,7 +7,7 @@ import urllib.parse from contextlib import suppress from typing import TYPE_CHECKING, cast -from music_assistant_models.config_entries import ConfigEntry +from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from music_assistant_models.enums import ContentType, MediaType, PlaybackState, PlayerFeature from music_assistant_models.media_items.audio_format import AudioFormat from music_assistant_models.player import DeviceInfo, PlayerMedia @@ -333,9 +333,13 @@ class SnapCastPlayer(Player): assert group is not None # for type checking await group.set_stream(new_stream_name) - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Player config.""" - base_entries = await super().get_config_entries() + base_entries = await super().get_config_entries(action=action, values=values) return [ *base_entries, CONF_ENTRY_FLOW_MODE_ENFORCED, diff --git a/music_assistant/providers/sonos/player.py b/music_assistant/providers/sonos/player.py index 9707b80d..a5bade0a 100644 --- a/music_assistant/providers/sonos/player.py +++ b/music_assistant/providers/sonos/player.py @@ -21,7 +21,7 @@ from aiosonos.client import SonosLocalApiClient from aiosonos.const import EventType as SonosEventType from aiosonos.const import SonosEvent from aiosonos.exceptions import ConnectionFailed, FailedCommand -from music_assistant_models.config_entries import ConfigEntry +from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from music_assistant_models.enums import ( ConfigEntryType, EventType, @@ -228,10 +228,12 @@ class SonosPlayer(Player): async def get_config_entries( self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the player.""" base_entries = [ - *await super().get_config_entries(), + *await super().get_config_entries(action=action, values=values), CONF_ENTRY_OUTPUT_CODEC, CONF_ENTRY_HTTP_PROFILE_DEFAULT_1, create_sample_rates_config_entry( diff --git a/music_assistant/providers/sonos_s1/player.py b/music_assistant/providers/sonos_s1/player.py index 2c1f5a51..a3fbbe83 100644 --- a/music_assistant/providers/sonos_s1/player.py +++ b/music_assistant/providers/sonos_s1/player.py @@ -45,7 +45,7 @@ from .constants import ( from .helpers import SonosUpdateError, soco_error if TYPE_CHECKING: - from music_assistant_models.config_entries import ConfigEntry + from music_assistant_models.config_entries import ConfigEntry, ConfigValueType from soco.events_base import Event as SonosEvent from soco.events_base import SubscriptionBase @@ -124,10 +124,14 @@ class SonosPlayer(Player): self.update_state() await self.unsubscribe() - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the player.""" return [ - *await super().get_config_entries(), + *await super().get_config_entries(action=action, values=values), CONF_ENTRY_FLOW_MODE_HIDDEN_DISABLED, CONF_ENTRY_HTTP_PROFILE_DEFAULT_1, CONF_ENTRY_OUTPUT_CODEC, diff --git a/music_assistant/providers/squeezelite/player.py b/music_assistant/providers/squeezelite/player.py index 5bcd0b14..12211c62 100644 --- a/music_assistant/providers/squeezelite/player.py +++ b/music_assistant/providers/squeezelite/player.py @@ -15,7 +15,7 @@ from aioslimproto.models import PlayerState as SlimPlayerState from aioslimproto.models import Preset as SlimPreset from aioslimproto.models import SlimEvent from aioslimproto.models import VisualisationType as SlimVisualisationType -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption +from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType from music_assistant_models.enums import ( ConfigEntryType, ContentType, @@ -130,9 +130,13 @@ class SqueezelitePlayer(Player): await self.client.volume_set(init_volume) await self.mass.players.register_or_update(self) - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the player.""" - base_entries = await super().get_config_entries() + base_entries = await super().get_config_entries(action=action, values=values) max_sample_rate = int(self.client.max_sample_rate) # create preset entries (for players that support it) presets = [] diff --git a/music_assistant/providers/universal_group/player.py b/music_assistant/providers/universal_group/player.py index 396cdf74..5d1d7295 100644 --- a/music_assistant/providers/universal_group/player.py +++ b/music_assistant/providers/universal_group/player.py @@ -8,7 +8,7 @@ from time import time from typing import TYPE_CHECKING, cast from aiohttp import web -from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption +from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption, ConfigValueType from music_assistant_models.constants import PLAYER_CONTROL_NONE from music_assistant_models.enums import ( ConfigEntryType, @@ -98,11 +98,15 @@ class UniversalGroupPlayer(GroupPlayer): """Return if the player is a dynamic group player.""" return bool(self.config.get_value(CONF_DYNAMIC_GROUP_MEMBERS, False)) - async def get_config_entries(self) -> list[ConfigEntry]: + async def get_config_entries( + self, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, + ) -> list[ConfigEntry]: """Return all (provider/player specific) Config Entries for the given player (if any).""" return [ # default entries for player groups - *await super().get_config_entries(), + *await super().get_config_entries(action=action, values=values), # add universal group specific entries CONFIG_ENTRY_UGP_NOTE, ConfigEntry(