Add categories to config entries (#1185)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 26 Mar 2024 23:01:29 +0000 (00:01 +0100)
committerGitHub <noreply@github.com>
Tue, 26 Mar 2024 23:01:29 +0000 (00:01 +0100)
add categories to config entries

20 files changed:
music_assistant/common/models/config_entries.py
music_assistant/common/models/enums.py
music_assistant/common/models/player.py
music_assistant/constants.py
music_assistant/server/controllers/players.py
music_assistant/server/controllers/streams.py
music_assistant/server/controllers/webserver.py
music_assistant/server/models/player_provider.py
music_assistant/server/providers/airplay/__init__.py
music_assistant/server/providers/chromecast/__init__.py
music_assistant/server/providers/dlna/__init__.py
music_assistant/server/providers/filesystem_local/base.py
music_assistant/server/providers/filesystem_smb/__init__.py
music_assistant/server/providers/fully_kiosk/__init__.py
music_assistant/server/providers/hass/__init__.py
music_assistant/server/providers/hass_players/__init__.py
music_assistant/server/providers/slimproto/__init__.py
music_assistant/server/providers/snapcast/__init__.py
music_assistant/server/providers/sonos/__init__.py
music_assistant/server/providers/ugp/__init__.py

index 0234fbbf051c9f61c9c1977cd3b2bf7c60698053..1d0ba7396db96112c5e348e639882a5a71bf2d0c 100644 (file)
@@ -25,6 +25,7 @@ from music_assistant.constants import (
     CONF_EQ_TREBLE,
     CONF_FLOW_MODE,
     CONF_HIDE_PLAYER,
+    CONF_ICON,
     CONF_LOG_LEVEL,
     CONF_OUTPUT_CHANNELS,
     CONF_SYNC_ADJUST,
@@ -52,9 +53,16 @@ ConfigEntryTypeMap = {
     ConfigEntryType.LABEL: str,
     ConfigEntryType.DIVIDER: str,
     ConfigEntryType.ACTION: str,
+    ConfigEntryType.ALERT: str,
+    ConfigEntryType.ICON: str,
 }
 
-UI_ONLY = (ConfigEntryType.LABEL, ConfigEntryType.DIVIDER, ConfigEntryType.ACTION)
+UI_ONLY = (
+    ConfigEntryType.LABEL,
+    ConfigEntryType.DIVIDER,
+    ConfigEntryType.ACTION,
+    ConfigEntryType.ALERT,
+)
 
 
 @dataclass
@@ -95,8 +103,8 @@ class ConfigEntry(DataClassDictMixin):
     depends_on: str | None = None
     # hidden: hide from UI
     hidden: bool = False
-    # advanced: this is an advanced setting (frontend hides it in some corner)
-    advanced: bool = False
+    # category: category to group this setting into in the frontend (e.g. advanced)
+    category: str = "generic"
     # action: (configentry)action that is needed to get the value for this entry
     action: str | None = None
     # action_label: default label for the action when no translation for the action is present
@@ -298,7 +306,7 @@ CONF_ENTRY_LOG_LEVEL = ConfigEntry(
         ConfigValueOption("verbose", "VERBOSE"),
     ),
     default_value="GLOBAL",
-    advanced=True,
+    category="advanced",
 )
 
 DEFAULT_PROVIDER_CONFIG_ENTRIES = (CONF_ENTRY_LOG_LEVEL,)
@@ -311,7 +319,6 @@ CONF_ENTRY_FLOW_MODE = ConfigEntry(
     type=ConfigEntryType.BOOLEAN,
     label="Enable queue flow mode",
     default_value=False,
-    advanced=False,
 )
 
 
@@ -335,7 +342,7 @@ CONF_ENTRY_OUTPUT_CHANNELS = ConfigEntry(
     ],
     default_value="stereo",
     label="Output Channel Mode",
-    advanced=True,
+    category="audio",
 )
 
 CONF_ENTRY_VOLUME_NORMALIZATION = ConfigEntry(
@@ -344,6 +351,7 @@ CONF_ENTRY_VOLUME_NORMALIZATION = ConfigEntry(
     label="Enable volume normalization",
     default_value=True,
     description="Enable volume normalization (EBU-R128 based)",
+    category="audio",
 )
 
 CONF_ENTRY_VOLUME_NORMALIZATION_TARGET = ConfigEntry(
@@ -354,7 +362,7 @@ CONF_ENTRY_VOLUME_NORMALIZATION_TARGET = ConfigEntry(
     label="Target level for volume normalization",
     description="Adjust average (perceived) loudness to this target level",
     depends_on=CONF_VOLUME_NORMALIZATION,
-    advanced=True,
+    category="audio",
 )
 
 CONF_ENTRY_EQ_BASS = ConfigEntry(
@@ -364,7 +372,7 @@ CONF_ENTRY_EQ_BASS = ConfigEntry(
     default_value=0,
     label="Equalizer: bass",
     description="Use the builtin basic equalizer to adjust the bass of audio.",
-    advanced=True,
+    category="audio",
 )
 
 CONF_ENTRY_EQ_MID = ConfigEntry(
@@ -374,7 +382,7 @@ CONF_ENTRY_EQ_MID = ConfigEntry(
     default_value=0,
     label="Equalizer: midrange",
     description="Use the builtin basic equalizer to adjust the midrange of audio.",
-    advanced=True,
+    category="audio",
 )
 
 CONF_ENTRY_EQ_TREBLE = ConfigEntry(
@@ -384,7 +392,7 @@ CONF_ENTRY_EQ_TREBLE = ConfigEntry(
     default_value=0,
     label="Equalizer: treble",
     description="Use the builtin basic equalizer to adjust the treble of audio.",
-    advanced=True,
+    category="audio",
 )
 
 
@@ -394,7 +402,7 @@ CONF_ENTRY_CROSSFADE = ConfigEntry(
     label="Enable crossfade",
     default_value=False,
     description="Enable a crossfade transition between (queue) tracks.",
-    advanced=False,
+    category="audio",
 )
 
 CONF_ENTRY_CROSSFADE_DURATION = ConfigEntry(
@@ -405,7 +413,7 @@ CONF_ENTRY_CROSSFADE_DURATION = ConfigEntry(
     label="Crossfade duration",
     description="Duration in seconds of the crossfade between tracks (if enabled)",
     depends_on=CONF_CROSSFADE,
-    advanced=True,
+    category="audio",
 )
 
 CONF_ENTRY_HIDE_PLAYER = ConfigEntry(
@@ -413,7 +421,6 @@ CONF_ENTRY_HIDE_PLAYER = ConfigEntry(
     type=ConfigEntryType.BOOLEAN,
     label="Hide this player in the user interface",
     default_value=False,
-    advanced=True,
 )
 
 CONF_ENTRY_ENFORCE_MP3 = ConfigEntry(
@@ -425,7 +432,7 @@ CONF_ENTRY_ENFORCE_MP3 = ConfigEntry(
     "to all players. Some players can not deal with that and require the stream to be packed "
     "into a lossy mp3 codec. \n\n "
     "Only enable when needed. Saves some bandwidth at the cost of audio quality.",
-    advanced=True,
+    category="audio",
 )
 
 CONF_ENTRY_SYNC_ADJUST = ConfigEntry(
@@ -437,7 +444,7 @@ CONF_ENTRY_SYNC_ADJUST = ConfigEntry(
     description="If this player is playing audio synced with other players "
     "and you always hear the audio too early or late on this player, "
     "you can shift the audio a bit.",
-    advanced=True,
+    category="advanced",
 )
 
 
@@ -446,8 +453,7 @@ CONF_ENTRY_TTS_PRE_ANNOUNCE = ConfigEntry(
     type=ConfigEntryType.BOOLEAN,
     default_value=True,
     label="Pre-announce TTS announcements",
-    description="When a TTS (text-to-speech) message is sent to the Announce feature, "
-    "prepend the announcement with a short pre-announcement sound (bell whistle).",
+    category="announcements",
 )
 
 
@@ -457,13 +463,12 @@ CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY = ConfigEntry(
     options=[
         ConfigValueOption("Absolute volume", "absolute"),
         ConfigValueOption("Relative volume increase", "relative"),
-        ConfigValueOption("Percentual volume increase", "percentual"),
+        ConfigValueOption("Volume increase by fixed percentage", "percentual"),
         ConfigValueOption("Do not adjust volume", "none"),
     ],
     default_value="percentual",
     label="Volume strategy for Announcements",
-    description="When an announcement is being broadcast to this player, "
-    "how should the volume be adjusted temporary (use in combination with the volume value below).",
+    category="announcements",
 )
 
 CONF_ENTRY_ANNOUNCE_VOLUME = ConfigEntry(
@@ -471,8 +476,7 @@ CONF_ENTRY_ANNOUNCE_VOLUME = ConfigEntry(
     type=ConfigEntryType.INTEGER,
     default_value=85,
     label="Volume for Announcements",
-    description="The percentual, relative or absolute volume level, "
-    "used with the strategy for announcements.",
+    category="announcements",
 )
 
 CONF_ENTRY_ANNOUNCE_VOLUME_MIN = ConfigEntry(
@@ -481,6 +485,7 @@ CONF_ENTRY_ANNOUNCE_VOLUME_MIN = ConfigEntry(
     default_value=15,
     label="Minimum Volume level for Announcements",
     description="The volume (adjustment) of announcements should no go below this level.",
+    category="announcements",
 )
 
 CONF_ENTRY_ANNOUNCE_VOLUME_MAX = ConfigEntry(
@@ -489,4 +494,19 @@ CONF_ENTRY_ANNOUNCE_VOLUME_MAX = ConfigEntry(
     default_value=75,
     label="Maximum Volume level for Announcements",
     description="The volume (adjustment) of announcements should no go above this level.",
+    category="announcements",
+)
+
+CONF_ENTRY_PLAYER_ICON = ConfigEntry(
+    key=CONF_ICON,
+    type=ConfigEntryType.ICON,
+    default_value="mdi-speaker",
+    label="Icon",
+    description="Material design icon for this player. "
+    "\n\nSee https://pictogrammers.com/library/mdi/",
+    category="generic",
+)
+
+CONF_ENTRY_PLAYER_ICON_GROUP = ConfigEntry.from_dict(
+    {**CONF_ENTRY_PLAYER_ICON.to_dict(), "default_value": "mdi-speaker-multiple"}
 )
index fae363c790919d0faf29008e399cba586f3ece50..755e839d283ce56b3036bd455afbed8b1e6c6a73 100644 (file)
@@ -388,6 +388,8 @@ class ConfigEntryType(StrEnum):
     LABEL = "label"
     DIVIDER = "divider"
     ACTION = "action"
+    ICON = "icon"
+    ALERT = "alert"
     UNKNOWN = "unknown"
 
     @classmethod
index 9ca4f1233b21550912a9a0f8a879f81737e92656..33bee344a19b2277fa40c35f4c1ab0182cdf1459 100644 (file)
@@ -91,6 +91,10 @@ class Player(DataClassDictMixin):
     # a hidden player is hidden in the UI only but can still be controlled
     hidden: bool = False
 
+    # icon: material design icon for this player
+    # will be set by the player manager based on config
+    icon: str = "mdi-speaker"
+
     # group_volume: if the player is a player group or syncgroup master,
     # this will return the average volume of all child players
     # if not a group player, this is just the player's volume
index 383952b59c765d230adbd3c755eb9037e406c0f7..bd6a965ec82bdae1f62b2ec998353a3933cfd32f 100644 (file)
@@ -60,7 +60,7 @@ CONF_ANNOUNCE_VOLUME_STRATEGY: Final[str] = "announce_volume_strategy"
 CONF_ANNOUNCE_VOLUME: Final[str] = "announce_volume"
 CONF_ANNOUNCE_VOLUME_MIN: Final[str] = "announce_volume_min"
 CONF_ANNOUNCE_VOLUME_MAX: Final[str] = "announce_volume_max"
-
+CONF_ICON: Final[str] = "icon"
 
 # config default values
 DEFAULT_HOST: Final[str] = "0.0.0.0"
index c44f2cbcd9bf5f2f342bc8ca6454f2bf84ace9a2..720a6aeb5179b59abfa8046c3df9f3b32876c34b 100644 (file)
@@ -15,6 +15,8 @@ from music_assistant.common.models.config_entries import (
     CONF_ENTRY_ANNOUNCE_VOLUME_MAX,
     CONF_ENTRY_ANNOUNCE_VOLUME_MIN,
     CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY,
+    CONF_ENTRY_PLAYER_ICON,
+    CONF_ENTRY_PLAYER_ICON_GROUP,
     CONF_ENTRY_TTS_PRE_ANNOUNCE,
 )
 from music_assistant.common.models.enums import (
@@ -273,6 +275,13 @@ class PlayerController(CoreController):
         player.hidden = self.mass.config.get_raw_player_config_value(
             player.player_id, CONF_HIDE_PLAYER, False
         )
+        player.icon = self.mass.config.get_raw_player_config_value(
+            player.player_id,
+            CONF_ENTRY_PLAYER_ICON.key,
+            CONF_ENTRY_PLAYER_ICON_GROUP.default_value
+            if player.type in (PlayerType.GROUP, PlayerType.SYNC_GROUP)
+            else CONF_ENTRY_PLAYER_ICON.default_value,
+        )
         # handle syncgroup - get attributes from first player that has this group as source
         if player.player_id.startswith(SYNCGROUP_PREFIX):
             if player.powered and (sync_leader := self.get_sync_leader(player)):
index b6b74fddf0f72d4318d6fa3a63071ff6fd93002c..42e32921de3ac03e6030a0e9426d141a3a1f0a4d 100644 (file)
@@ -330,7 +330,7 @@ class StreamsController(CoreController):
                 "on the given IP and TCP port by players on the local network. \n"
                 "This is an advanced setting that should normally "
                 "not be adjusted in regular setups.",
-                advanced=True,
+                category="advanced",
             ),
             ConfigEntry(
                 key=CONF_BIND_IP,
@@ -342,7 +342,7 @@ class StreamsController(CoreController):
                 "Use 0.0.0.0 to bind to all interfaces, which is the default. \n"
                 "This is an advanced setting that should normally "
                 "not be adjusted in regular setups.",
-                advanced=True,
+                category="advanced",
             ),
         )
 
index 12a0987c3ce32ebb0d79d640121a55bf11623536..7863aef64c49239a0650c08894ceb0a0bc120faa 100644 (file)
@@ -132,7 +132,7 @@ class WebserverController(CoreController):
                 "to enhance security and protect outside access to the webinterface and API. \n\n"
                 "This is an advanced setting that should normally "
                 "not be adjusted in regular setups.",
-                advanced=True,
+                category="advanced",
             ),
         )
 
index b869c042ff8ff5c8b080e56f3649bed520600f0f..2a4e46f991cf177a4ba1e39631fbe06ff98f002f 100644 (file)
@@ -12,6 +12,8 @@ from music_assistant.common.models.config_entries import (
     CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY,
     CONF_ENTRY_AUTO_PLAY,
     CONF_ENTRY_HIDE_PLAYER,
+    CONF_ENTRY_PLAYER_ICON,
+    CONF_ENTRY_PLAYER_ICON_GROUP,
     CONF_ENTRY_TTS_PRE_ANNOUNCE,
     CONF_ENTRY_VOLUME_NORMALIZATION,
     CONF_ENTRY_VOLUME_NORMALIZATION_TARGET,
@@ -41,6 +43,7 @@ class PlayerProvider(Provider):
     async def get_player_config_entries(self, player_id: str) -> tuple[ConfigEntry, ...]:
         """Return all (provider/player specific) Config Entries for the given player (if any)."""
         entries = (
+            CONF_ENTRY_PLAYER_ICON,
             CONF_ENTRY_VOLUME_NORMALIZATION,
             CONF_ENTRY_AUTO_PLAY,
             CONF_ENTRY_VOLUME_NORMALIZATION_TARGET,
@@ -69,6 +72,7 @@ class PlayerProvider(Provider):
                     multi_value=True,
                     required=True,
                 ),
+                CONF_ENTRY_PLAYER_ICON_GROUP,
             )
         return entries
 
index 3655bba22d67e299009e01d65ec4d8d75ef99d95..0bee81778c8b274ecc23e134599807ce953de612 100644 (file)
@@ -76,7 +76,7 @@ PLAYER_CONFIG_ENTRIES = (
         label="Enable encryption",
         description="Enable encrypted communication with the player, "
         "some (3rd party) players require this.",
-        advanced=True,
+        category="airplay",
     ),
     ConfigEntry(
         key=CONF_ALAC_ENCODE,
@@ -85,7 +85,7 @@ PLAYER_CONFIG_ENTRIES = (
         label="Enable compression",
         description="Save some network bandwidth by sending the audio as "
         "(lossless) ALAC at the cost of a bit CPU.",
-        advanced=True,
+        category="airplay",
     ),
     CONF_ENTRY_SYNC_ADJUST,
     ConfigEntry(
@@ -95,7 +95,7 @@ PLAYER_CONFIG_ENTRIES = (
         required=False,
         label="Device password",
         description="Some devices require a password to connect/play.",
-        advanced=True,
+        category="airplay",
     ),
 )
 BACKOFF_TIME_LOWER_LIMIT = 15  # seconds
@@ -561,7 +561,7 @@ class AirplayProvider(PlayerProvider):
         base_entries = await super().get_player_config_entries(player_id)
         if player_id not in self._players:
             # most probably a syncgroup
-            return base_entries
+            return (*base_entries, CONF_ENTRY_CROSSFADE, CONF_ENTRY_CROSSFADE_DURATION)
         return base_entries + PLAYER_CONFIG_ENTRIES
 
     async def cmd_stop(self, player_id: str) -> None:
index 5111b49d926483248b2c43645f0eb69a5166ebf2..361733a40702a145ba1e70b0825933164eacb52e 100644 (file)
@@ -66,7 +66,7 @@ PLAYER_CONFIG_ENTRIES = (
         description="Enable a crossfade transition between (queue) tracks. \n\n"
         "Note that Cast does not natively support crossfading so you need to enable "
         "the 'flow mode' workaround to use crossfading with Cast players.",
-        advanced=False,
+        category="audio",
         depends_on=CONF_FLOW_MODE,
     ),
     CONF_ENTRY_FLOW_MODE,
index 2181d78dbb8739fdd3d7808ac6c67bfb4426c772..96bdb8d928ef849f3cf73f1a7d614fcef4cd679e 100644 (file)
@@ -89,7 +89,7 @@ PLAYER_CONFIG_ENTRIES = (
         description="Enable a crossfade transition between (queue) tracks. \n\n"
         "Note that DLNA does not natively support crossfading so you need to enable "
         "the 'flow mode' workaround to use crossfading with DLNA players.",
-        advanced=False,
+        category="audio",
         depends_on=CONF_FLOW_MODE,
     ),
     CONF_ENTRY_FLOW_MODE,
index e29735f0b992d0d757134a3dd99611b4501a30ac..c8544c8163f3f8d4e750f1d0108741ff0db0874c 100644 (file)
@@ -68,7 +68,6 @@ CONF_ENTRY_MISSING_ALBUM_ARTIST = ConfigEntry(
     description="Music Assistant prefers information stored in ID3 tags and only uses"
     " online sources for additional metadata. This means that the ID3 tags need to be "
     "accurate, preferably tagged with MusicBrainz Picard.",
-    advanced=False,
     required=False,
     options=(
         ConfigValueOption("Skip track and log warning", "skip"),
index d61f35dbe4f640dc0c34c16fecbeb4c2b1d2e150..dbdb53d856f327c74cff07ee45022318d60f9c19 100644 (file)
@@ -112,7 +112,7 @@ async def get_config_entries(
             type=ConfigEntryType.STRING,
             label="Mount options",
             required=False,
-            advanced=True,
+            category="advanced",
             default_value="noserverino,file_mode=0775,dir_mode=0775,uid=0,gid=0",
             description="[optional] Any additional mount options you "
             "want to pass to the mount command if needed for your particular setup.",
index 2c296b2a418190aa0085ab2836e5121ad88dbd6e..54bffd9171caeba9e4c6e21be010e6a0e7aa781a 100644 (file)
@@ -79,7 +79,7 @@ async def get_config_entries(
             default_value="2323",
             label="Port to use to connect to the Fully Kiosk API (default is 2323).",
             required=True,
-            advanced=True,
+            category="advanced",
         ),
     )
 
@@ -160,7 +160,7 @@ class FullyKioskProvider(PlayerProvider):
                 description="By default, Music Assistant sends lossless, high quality audio "
                 "to all players. Some devices can not deal with that and require "
                 "the stream to be packed into a lossy mp3 codec. Only enable when needed.",
-                advanced=True,
+                category="advanced",
             ),
         )
 
index 60f527cbe1dfdab460c8bc634915756a9e6ef4ea..463b75d0993ac787feb5ce9919051f504df3f17d 100644 (file)
@@ -143,7 +143,7 @@ async def get_config_entries(
             "'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,
-            advanced=True,
+            category="advanced",
         ),
     )
 
index dd726857b538c0b94187ceba30e1669d6a053dea..f8ef8e21b3daa78b3eebca93fc92c542e9cd1805 100644 (file)
@@ -99,7 +99,7 @@ PLAYER_CONFIG_ENTRIES = (
         description="Enable a crossfade transition between (queue) tracks. \n\n"
         "Note that you need to enable the 'flow mode' workaround to use "
         "crossfading with Home Assistant players.",
-        advanced=False,
+        category="audio",
         depends_on=CONF_FLOW_MODE,
     ),
     CONF_ENTRY_FLOW_MODE,
@@ -113,7 +113,7 @@ PLAYER_CONFIG_ENTRIES = (
         "to all players. Some players can not deal with that and require the stream to be packed "
         "into a lossy mp3 codec. \n\n "
         "Only enable when needed. Saves some bandwidth at the cost of audio quality.",
-        advanced=True,
+        category="audio",
     ),
 )
 
index d89f76c34d42b8271968f4a7f60928bb79f7ed4a..3fbd2db27563565c6b91f02cfc1dbff731b8a44d 100644 (file)
@@ -112,7 +112,7 @@ CONF_ENTRY_DISPLAY = ConfigEntry(
     required=False,
     label="Enable display support",
     description="Enable/disable native display support on squeezebox or squeezelite32 hardware.",
-    advanced=True,
+    category="advanced",
 )
 CONF_ENTRY_VISUALIZATION = ConfigEntry(
     key=CONF_VISUALIZATION,
@@ -126,7 +126,7 @@ CONF_ENTRY_VISUALIZATION = ConfigEntry(
     label="Visualization type",
     description="The type of visualization to show on the display "
     "during playback if the device supports this.",
-    advanced=True,
+    category="advanced",
     depends_on=CONF_DISPLAY,
 )
 
@@ -168,7 +168,7 @@ async def get_config_entries(
             "player compatibility, so security risks are minimized to practically zero."
             "You may safely disable this option if you have no players that rely on this feature "
             "or you dont care about the additional metadata.",
-            advanced=True,
+            category="advanced",
         ),
         ConfigEntry(
             key=CONF_CLI_JSON_PORT,
@@ -184,7 +184,7 @@ async def get_config_entries(
             "it on a different port. Set to 0 to disable this functionality.\n\n"
             "You may safely disable this option if you have no players that rely on this feature "
             "or you dont care about the additional metadata.",
-            advanced=True,
+            category="advanced",
         ),
         ConfigEntry(
             key=CONF_DISCOVERY,
@@ -195,7 +195,7 @@ async def get_config_entries(
             "discover and connect to this server. \n\n"
             "You may want to disable this feature if you are running multiple slimproto servers "
             "on your network and/or you don't want clients to auto connect to this server.",
-            advanced=True,
+            category="advanced",
         ),
         ConfigEntry(
             key=CONF_PORT,
@@ -206,7 +206,7 @@ async def get_config_entries(
             "The default is 3483 and using a different port is not supported by "
             "hardware squeezebox players. Only adjust this port if you want to "
             "use other slimproto based servers side by side with (squeezelite) software players.",
-            advanced=True,
+            category="advanced",
         ),
     )
 
@@ -261,6 +261,9 @@ class SlimprotoProvider(PlayerProvider):
     async def get_player_config_entries(self, player_id: str) -> tuple[ConfigEntry]:
         """Return all (provider/player specific) Config Entries for the given player (if any)."""
         base_entries = await super().get_player_config_entries(player_id)
+        if not self.slimproto.get_player(player_id):
+            # most probably a syncgroup
+            return (*base_entries, CONF_ENTRY_CROSSFADE, CONF_ENTRY_CROSSFADE_DURATION)
 
         # create preset entries (for players that support it)
         preset_entries = ()
@@ -278,7 +281,7 @@ class SlimprotoProvider(PlayerProvider):
                 label=f"Preset {index}",
                 description="Assign a playable item to the player's preset. "
                 "Only supported on real squeezebox hardware or jive(lite) based emulators.",
-                advanced=False,
+                category="presets",
                 required=False,
             )
             for index in range(1, preset_count + 1)
index ac4daae12446bfb3954a6404f557bab36e69c9e1..0f0cb81fb80e9195f5f4e5d125ecaf2bfb04bfc0 100644 (file)
@@ -108,7 +108,7 @@ async def get_config_entries(
             description="Music Assistant by default already includes a Snapserver. \n\n"
             "Checking this option allows you to connect to your own/external existing Snapserver "
             "and not use the builtin one provided by Music Assistant.",
-            advanced=snapserver_present,
+            category="advanced" if snapserver_present else "generic",
         ),
         ConfigEntry(
             key=CONF_SERVER_HOST,
@@ -117,7 +117,7 @@ async def get_config_entries(
             label="Snapcast server ip",
             required=False,
             depends_on=CONF_USE_EXTERNAL_SERVER,
-            advanced=snapserver_present,
+            category="advanced" if snapserver_present else "generic",
         ),
         ConfigEntry(
             key=CONF_SERVER_CONTROL_PORT,
@@ -126,7 +126,7 @@ async def get_config_entries(
             label="Snapcast control port",
             required=False,
             depends_on=CONF_USE_EXTERNAL_SERVER,
-            advanced=snapserver_present,
+            category="advanced" if snapserver_present else "generic",
         ),
     )
 
index 6917734164da017738d927775685fbcc3a02fb62..e6312bd943ba7c031ed95f7edae7045a790c7cef 100644 (file)
@@ -184,7 +184,7 @@ class SonosPlayerProvider(PlayerProvider):
         base_entries = await super().get_player_config_entries(player_id)
         if not (sonos_player := self.sonosplayers.get(player_id)):
             # most probably a syncgroup
-            return base_entries
+            return (*base_entries, CONF_ENTRY_CROSSFADE)
         return (
             *base_entries,
             CONF_ENTRY_CROSSFADE,
@@ -196,7 +196,7 @@ class SonosPlayerProvider(PlayerProvider):
                 value=sonos_player.bass,
                 range=(-10, 10),
                 description="Set the Bass level for the Sonos player",
-                advanced=True,
+                category="advanced",
             ),
             ConfigEntry(
                 key="sonos_treble",
@@ -206,7 +206,7 @@ class SonosPlayerProvider(PlayerProvider):
                 value=sonos_player.treble,
                 range=(-10, 10),
                 description="Set the Treble level for the Sonos player",
-                advanced=True,
+                category="advanced",
             ),
             ConfigEntry(
                 key="sonos_loudness",
@@ -215,7 +215,7 @@ class SonosPlayerProvider(PlayerProvider):
                 default_value=sonos_player.loudness,
                 value=sonos_player.loudness,
                 description="Enable loudness compensation on the Sonos player",
-                advanced=True,
+                category="advanced",
             ),
         )
 
index 08d37700b08f0feb704334d6d8ebb73cddfc7222..5efa409c4d3f59d01071d5a5c2bb49e4b67af781 100644 (file)
@@ -113,7 +113,7 @@ class UniversalGroupProvider(PlayerProvider):
             ),
             ConfigEntry(
                 key="ugp_note",
-                type=ConfigEntryType.LABEL,
+                type=ConfigEntryType.ALERT,
                 label="Please note that although the universal group "
                 "allows you to group any player, it will not enable audio sync "
                 "between players of different ecosystems.",
@@ -126,7 +126,7 @@ class UniversalGroupProvider(PlayerProvider):
                 description="Enable a crossfade transition between (queue) tracks. \n\n"
                 "Note that DLNA does not natively support crossfading so you need to enable "
                 "the 'flow mode' workaround to use crossfading with DLNA players.",
-                advanced=False,
+                category="audio",
             ),
             CONF_ENTRY_CROSSFADE_DURATION,
         )