Add support for actions flow in Player config entries (#2572)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Wed, 29 Oct 2025 12:59:02 +0000 (13:59 +0100)
committerGitHub <noreply@github.com>
Wed, 29 Oct 2025 12:59:02 +0000 (13:59 +0100)
20 files changed:
music_assistant/controllers/config.py
music_assistant/controllers/players/sync_groups.py
music_assistant/models/player.py
music_assistant/providers/_demo_player_provider/player.py
music_assistant/providers/airplay/player.py
music_assistant/providers/alexa/__init__.py
music_assistant/providers/bluesound/player.py
music_assistant/providers/builtin_player/player.py
music_assistant/providers/chromecast/player.py
music_assistant/providers/dlna/player.py
music_assistant/providers/fully_kiosk/player.py
music_assistant/providers/hass_players/player.py
music_assistant/providers/musiccast/player.py
music_assistant/providers/resonate/player.py
music_assistant/providers/roku_media_assistant/player.py
music_assistant/providers/snapcast/player.py
music_assistant/providers/sonos/player.py
music_assistant/providers/sonos_s1/player.py
music_assistant/providers/squeezelite/player.py
music_assistant/providers/universal_group/player.py

index 88ee22ea3f99a2a1c68ba424ef78f010bd677ad8..9a91a6337811acddbed74ece9fd4929b9a0bfe52 100644 (file)
@@ -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,
index 4ee5a183f77f524da4f53bf324ee2cc6f3719104..9b186752556c9ae8878af172467f5bf8f1d1b929 100644 (file)
@@ -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,
index 92fc4d30ba1aebdc5d5293ba6100c2c282e687d8..b13679b92086b9e41c41069d793abb79019939c8 100644 (file)
@@ -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
index 72c5449259ea7e11caa87c1a67b30770d051616d..8f91ffd54d6262d4d847b4526d4d6f2d517fecaf 100644 (file)
@@ -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
index 8f73efde8b1cbc3af09b9810aaa30890ddaa47e9..c11b7a0764e431130df4a7f9be863110a09d9479 100644 (file)
@@ -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,
index 685a17cee82dd6e1b3fab0fc8d27ccc306dc5012..e98072e60a81ec4541153afe3bb670baf402ac5c 100644 (file)
@@ -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,
index 1329c2bf77a6e0d79df175e2f655e8cd7445727c..11d44b6e12440074e9e97ef0ed3663d12600641a 100644 (file)
@@ -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,
index 00130ccf6d56d7f09521188e1eec8ba1c1834d54..c481968b428ef8d572aa7e0ee200afb31051ec82 100644 (file)
@@ -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,
index 474bf5a4dfbb2b4730e6ab2ffcb311bfe8bb96c6..506da0709801c0d35913213e2e68cad2e632983e 100644 (file)
@@ -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,
index 3a9b24aa9fd05fa360c78cc989ecd4b15b7f21c2..1bfa31a4bc08bc1e8589aad809ac8be8781ba0b0 100644 (file)
@@ -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(
index 3e1d782b695edcc1715086d68ae1e463025b25f4..4efdb0263539835f7a079e5602c2d54123d155ef 100644 (file)
@@ -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,
index 4a218ee2e9387fa61e925b34e88257d631224401..948fa099984600dfd947efe515c83f086b235e4b 100644 (file)
@@ -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
index b88bbdbc07cd7b55e11b7cb329a80692cc1b3817..433ae2a2cb95587071ecbdbee72950cb44d345c9 100644 (file)
@@ -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:
index dd32093de43c3b393491e9b5ef30edab12af3882..8036ecae186bae9bdb3995143ded1f1a2ecc55a9 100644 (file)
@@ -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(
index fab76d71562b07b6e792df3577521cfe27b40aa5..b5f1ef56cddfa9006e84f6ec6495c1c3831ebfde 100644 (file)
@@ -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,
index eab60597f6a9197e05a7d48c0edd9ff62adb943d..5a76f5c061557f0c118f1584a5389a8505b692bd 100644 (file)
@@ -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,
index 9707b80d0794115576576e268c73fff9a6e771f7..a5bade0aaf462a7fe60217b596010e1dec27d637 100644 (file)
@@ -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(
index 2c1f5a512040c98390039225649d3334b9d4b2ba..a3fbbe8319d4b9aba36ea676bb33a123aff0746d 100644 (file)
@@ -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,
index 5bcd0b14c4b5a62f0d039b762cc3ace2236e1d27..12211c6242a5ac7c5d1cecaa85a933c096a26969 100644 (file)
@@ -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 = []
index 396cdf74796b9e217dd89fd885c36b66e4617382..5d1d729565715b978750ac8a8bfe136741cdcace 100644 (file)
@@ -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(