From 6eb4c5e9153bb4486ceabccea1d4d465b4a315a9 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 3 Oct 2025 00:39:44 +0200 Subject: [PATCH] Fix playergroup migration (#2469) --- music_assistant/controllers/config.py | 26 ++++++++++++++++--- .../controllers/players/sync_groups.py | 2 +- music_assistant/models/player.py | 3 +++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/music_assistant/controllers/config.py b/music_assistant/controllers/config.py index 494d7298..09ba41eb 100644 --- a/music_assistant/controllers/config.py +++ b/music_assistant/controllers/config.py @@ -528,6 +528,11 @@ class ConfigController: # Also remove the DSP config if it exists self.remove(dsp_conf_key) + def set_player_default_name(self, player_id: str, default_name: str) -> None: + """Set (or update) the default name for a player.""" + conf_key = f"{CONF_PLAYERS}/{player_id}/default_name" + self.set(conf_key, default_name) + @api_command("config/players/dsp/get") def get_player_dsp_config(self, player_id: str) -> DSPConfig: """ @@ -1005,15 +1010,28 @@ class ConfigController: # Migrate the crossfade setting into Smart Fade Mode = 'crossfade' for player_config in self._data.get(CONF_PLAYERS, {}).values(): + if (crossfade := player_config.pop(CONF_DEPRECATED_CROSSFADE, None)) is None: + continue # Check if player has old crossfade enabled but no smart fades mode set - if ( - player_config.get(CONF_DEPRECATED_CROSSFADE) is True - and CONF_SMART_FADES_MODE not in player_config - ): + if crossfade is True and CONF_SMART_FADES_MODE not in player_config: # Set smart fades mode to standard_crossfade player_config[CONF_SMART_FADES_MODE] = "standard_crossfade" changed = True + # migrate player configs: always use lookup key for provider + prov_configs = self._data.get(CONF_PROVIDERS, {}) + for player_config in self._data.get(CONF_PLAYERS, {}).values(): + player_provider = player_config["provider"] + if prov_conf := prov_configs.get(player_provider): + if not (prov_manifest := self.mass.get_provider_manifest(prov_conf["domain"])): + continue + if prov_manifest.multi_instance: + # multi instance providers use instance_id as lookup key + continue + # single instance providers use domain as lookup key + player_config["provider"] = prov_conf["domain"] + changed = True + if changed: await self._async_save() diff --git a/music_assistant/controllers/players/sync_groups.py b/music_assistant/controllers/players/sync_groups.py index 4aad160e..de60ff58 100644 --- a/music_assistant/controllers/players/sync_groups.py +++ b/music_assistant/controllers/players/sync_groups.py @@ -88,7 +88,7 @@ class SyncGroupPlayer(GroupPlayer): ) -> None: """Initialize GroupPlayer instance.""" super().__init__(provider, player_id) - self._attr_name = self.config.name or f"SyncGroup {player_id}" + self._attr_name = self.config.name or self.config.default_name or f"SyncGroup {player_id}" self._attr_available = True self._attr_powered = False # group players are always powered off by default self._attr_active_source = None diff --git a/music_assistant/models/player.py b/music_assistant/models/player.py index d4863934..ad59cf1c 100644 --- a/music_assistant/models/player.py +++ b/music_assistant/models/player.py @@ -1058,6 +1058,9 @@ class Player(ABC): changed_values.pop("elapsed_time_last_updated", None) changed_values.pop("extra_attributes.seq_no", None) changed_values.pop("extra_attributes.last_poll", None) + # persist the default name if it changed + if self.name and self.config.default_name != self.name: + self.mass.config.set_player_default_name(self.player_id, self.name) # return early if nothing changed (unless force_update is True) if len(changed_values) == 0 and not force_update: return -- 2.34.1