Fix: Don't use look_up key in player providers
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 25 Feb 2025 10:32:13 +0000 (11:32 +0100)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 25 Feb 2025 10:32:13 +0000 (11:32 +0100)
It casuses some side effects

13 files changed:
music_assistant/controllers/config.py
music_assistant/controllers/players.py
music_assistant/providers/airplay/provider.py
music_assistant/providers/bluesound/__init__.py
music_assistant/providers/chromecast/__init__.py
music_assistant/providers/dlna/__init__.py
music_assistant/providers/hass_players/__init__.py
music_assistant/providers/player_group/__init__.py
music_assistant/providers/slimproto/__init__.py
music_assistant/providers/snapcast/__init__.py
music_assistant/providers/sonos/player.py
music_assistant/providers/sonos_s1/__init__.py
music_assistant/providers/spotify_connect/__init__.py

index 288814129a27c140e3a84b35ba3662eebb0ef846..2e9ca08784f54ae9b08939b2c6d486e5ad1ca7cc 100644 (file)
@@ -570,7 +570,10 @@ class ConfigController:
             msg = f"Unknown provider domain: {provider_domain}"
             raise KeyError(msg)
         config_entries = await self.get_provider_config_entries(provider_domain)
-        instance_id = f"{manifest.domain}--{shortuuid.random(8)}"
+        if manifest.multi_instance:
+            instance_id = f"{manifest.domain}--{shortuuid.random(8)}"
+        else:
+            instance_id = manifest.domain
         default_config: ProviderConfig = ProviderConfig.parse(
             config_entries,
             {
@@ -911,7 +914,10 @@ class ConfigController:
         if existing and not manifest.multi_instance:
             msg = f"Provider {manifest.name} does not support multiple instances"
             raise ValueError(msg)
-        instance_id = f"{manifest.domain}--{shortuuid.random(8)}"
+        if manifest.multi_instance:
+            instance_id = f"{manifest.domain}--{shortuuid.random(8)}"
+        else:
+            instance_id = manifest.domain
         # all checks passed, create config object
         config_entries = await self.get_provider_config_entries(
             provider_domain=provider_domain, instance_id=instance_id, values=values
index 88d8af65a0e8d61b1f1411d41dcc9978bd3604c3..d03016ab2a4b9d37aeb5676d582f6f9fd3fa6770 100644 (file)
@@ -933,9 +933,9 @@ class PlayerController(CoreController):
             msg = f"Player {player_id} is already registered"
             raise AlreadyRegisteredError(msg)
 
-        # make sure that the player's provider is set to the lookup key (=instance id)
+        # make sure that the player's provider is set to the instance_id
         prov = self.mass.get_provider(player.provider)
-        if not prov or prov.lookup_key != player.provider:
+        if not prov or prov.instance_id != player.provider:
             raise RuntimeError(f"Invalid provider ID given: {player.provider}")
 
         # make sure a default config exists
index 29e3ac98ca59208a3b9891057a662a3c87a7a36d..0d405953ea59b80a64a76fef823755322d7a7e76 100644 (file)
@@ -522,7 +522,7 @@ class AirplayProvider(PlayerProvider):
             volume = FALLBACK_VOLUME
         mass_player = Player(
             player_id=player_id,
-            provider=self.lookup_key,
+            provider=self.instance_id,
             type=PlayerType.PLAYER,
             name=display_name,
             available=True,
@@ -538,7 +538,7 @@ class AirplayProvider(PlayerProvider):
                 PlayerFeature.VOLUME_SET,
             },
             volume_level=volume,
-            can_group_with={self.lookup_key},
+            can_group_with={self.instance_id},
             enabled_by_default=not is_broken_raop_model(manufacturer, model),
         )
         await self.mass.players.register_or_update(mass_player)
index 534f728bc4ea498958806c7a10912c4523cb54a1..ebaa8d42d001e38d4dad4f72a9026b05991042fa 100644 (file)
@@ -277,7 +277,7 @@ class BluesoundPlayerProvider(PlayerProvider):
 
         bluos_player.mass_player = mass_player = Player(
             player_id=self.player_id,
-            provider=self.lookup_key,
+            provider=self.instance_id,
             type=PlayerType.PLAYER,
             name=name,
             available=True,
@@ -294,7 +294,7 @@ class BluesoundPlayerProvider(PlayerProvider):
             },
             needs_poll=True,
             poll_interval=30,
-            can_group_with={self.lookup_key},
+            can_group_with={self.instance_id},
         )
         await self.mass.players.register(mass_player)
 
index 32f12f79b00f441f7be27ef0948a17c5554ce1e6..c472e7a4d14d20b0dce0fe351a18afa8e07da2bc 100644 (file)
@@ -413,7 +413,7 @@ class ChromecastProvider(PlayerProvider):
                 ),
                 player=Player(
                     player_id=player_id,
-                    provider=self.lookup_key,
+                    provider=self.instance_id,
                     type=player_type,
                     name=cast_info.friendly_name,
                     available=False,
index eb07e45fde283532433f576ae7bf8eb763585f88..c1d623b9341e3f5b27454738492af87cd035158b 100644 (file)
@@ -480,7 +480,7 @@ class DLNAPlayerProvider(PlayerProvider):
                     udn=udn,
                     player=Player(
                         player_id=udn,
-                        provider=self.lookup_key,
+                        provider=self.instance_id,
                         type=PlayerType.PLAYER,
                         name=udn,
                         available=False,
index e9ab4da38c7ca46c440f282698b6c3a2675511d5..20cdeaa575040b0273fd7f0715704b536850f6f3 100644 (file)
@@ -476,7 +476,7 @@ class HomeAssistantPlayers(PlayerProvider):
 
         player = Player(
             player_id=state["entity_id"],
-            provider=self.lookup_key,
+            provider=self.instance_id,
             type=PlayerType.PLAYER,
             name=state["attributes"]["friendly_name"],
             available=state["state"] not in UNAVAILABLE_STATES,
index bc2ecb52406e4cce4fe311188517df011406cdbe..5238897728ebe40a51dff212486fe451e8a4bb26 100644 (file)
@@ -291,7 +291,7 @@ class PlayerGroupProvider(PlayerProvider):
             return base_entries  # guard
         if TYPE_CHECKING:
             player_provider = cast(PlayerProvider, player_provider)
-        assert player_provider.lookup_key != self.lookup_key
+        assert player_provider.instance_id != self.instance_id
         if not (child_player := next((x for x in player_provider.players), None)):
             return base_entries  # guard
 
@@ -584,7 +584,7 @@ class PlayerGroupProvider(PlayerProvider):
             if ProviderFeature.SYNC_PLAYERS not in player_prov.supported_features:
                 msg = f"Provider {player_prov.name} does not support creating groups"
                 raise UnsupportedFeaturedException(msg)
-            group_type = player_prov.lookup_key  # just in case only domain was sent
+            group_type = player_prov.instance_id  # just in case only domain was sent
 
         new_group_id = f"{prefix}{shortuuid.random(8).lower()}"
         # cleanup list, just in case the frontend sends some garbage
@@ -730,7 +730,7 @@ class PlayerGroupProvider(PlayerProvider):
     async def _register_all_players(self) -> None:
         """Register all (virtual/fake) group players in the Player controller."""
         player_configs = await self.mass.config.get_player_configs(
-            self.lookup_key, include_values=True
+            self.instance_id, include_values=True
         )
         for player_config in player_configs:
             if self.mass.players.get(player_config.player_id):
@@ -773,9 +773,9 @@ class PlayerGroupProvider(PlayerProvider):
             )
             can_group_with = {
                 # allow grouping with all providers, except the playergroup provider itself
-                x.lookup_key
+                x.instance_id
                 for x in self.mass.players.providers
-                if x.lookup_key != self.lookup_key
+                if x.instance_id != self.instance_id
             }
             player_features.add(PlayerFeature.MULTI_DEVICE_DSP)
         elif player_provider := self.mass.get_provider(group_type):
@@ -784,7 +784,7 @@ class PlayerGroupProvider(PlayerProvider):
                 player_provider = cast(PlayerProvider, player_provider)
             model_name = "Sync Group"
             manufacturer = self.mass.get_provider(group_type).name
-            can_group_with = {player_provider.lookup_key}
+            can_group_with = {player_provider.instance_id}
             for feature in (PlayerFeature.PAUSE, PlayerFeature.VOLUME_MUTE, PlayerFeature.ENQUEUE):
                 if all(feature in x.supported_features for x in player_provider.players):
                     player_features.add(feature)
@@ -800,7 +800,7 @@ class PlayerGroupProvider(PlayerProvider):
 
         player = Player(
             player_id=group_player_id,
-            provider=self.lookup_key,
+            provider=self.instance_id,
             type=PlayerType.GROUP,
             name=name,
             available=True,
@@ -904,12 +904,12 @@ class PlayerGroupProvider(PlayerProvider):
         if group_type == GROUP_TYPE_UNIVERSAL:
             can_group_with = {
                 # allow grouping with all providers, except the playergroup provider itself
-                x.lookup_key
+                x.instance_id
                 for x in self.mass.players.providers
-                if x.lookup_key != self.lookup_key
+                if x.instance_id != self.instance_id
             }
         elif sync_player_provider := self.mass.get_provider(group_type):
-            can_group_with = {sync_player_provider.lookup_key}
+            can_group_with = {sync_player_provider.instance_id}
         else:
             can_group_with = {}
         player.can_group_with = can_group_with
@@ -1028,7 +1028,7 @@ class PlayerGroupProvider(PlayerProvider):
                 x
                 for x in members
                 if (player := self.mass.players.get(x))
-                and player.provider == player_provider.lookup_key
+                and player.provider == player_provider.instance_id
             ]
         # cleanup members - filter out impossible choices
         syncgroup_childs: list[str] = []
index b44a5bfebad4a0bb744d092352cf4e9f1cca3520..c98f5e1739b91a8a7c0876ea7757566742e1da77 100644 (file)
@@ -647,7 +647,7 @@ class SlimprotoProvider(PlayerProvider):
             # player does not yet exist, create it
             player = Player(
                 player_id=player_id,
-                provider=self.lookup_key,
+                provider=self.instance_id,
                 type=PlayerType.PLAYER,
                 name=slimplayer.name,
                 available=True,
@@ -666,7 +666,7 @@ class SlimprotoProvider(PlayerProvider):
                     PlayerFeature.VOLUME_MUTE,
                     PlayerFeature.ENQUEUE,
                 },
-                can_group_with={self.lookup_key},
+                can_group_with={self.instance_id},
             )
             await self.mass.players.register_or_update(player)
 
index e6e92ad299de2a40d2fa6c5df0989887cdf349b4..ea24ddfe3cfbc7e562beab96a92d180cb799429a 100644 (file)
@@ -370,7 +370,7 @@ class SnapCastProvider(PlayerProvider):
             )
             player = Player(
                 player_id=player_id,
-                provider=self.lookup_key,
+                provider=self.instance_id,
                 type=PlayerType.PLAYER,
                 name=snap_client.friendly_name,
                 available=snap_client.connected,
@@ -385,7 +385,7 @@ class SnapCastProvider(PlayerProvider):
                     PlayerFeature.VOLUME_MUTE,
                 },
                 synced_to=self._synced_to(player_id),
-                can_group_with={self.lookup_key},
+                can_group_with={self.instance_id},
             )
         asyncio.run_coroutine_threadsafe(
             self.mass.players.register_or_update(player), loop=self.mass.loop
index 3aa32b0242fedca30b1fa455e2ddb88fb1f2f3fc..97ae9005902fbffb1113694abccd14c66cb4d266 100644 (file)
@@ -127,7 +127,7 @@ class SonosPlayer:
         # instantiate the MA player
         self.mass_player = mass_player = Player(
             player_id=self.player_id,
-            provider=self.prov.lookup_key,
+            provider=self.prov.instance_id,
             type=PlayerType.PLAYER,
             name=self.discovery_info["device"]["name"]
             or self.discovery_info["device"]["modelDisplayName"],
@@ -140,7 +140,7 @@ class SonosPlayer:
             supported_features=supported_features,
             # NOTE: strictly taken we can have multiple sonos households
             # but for now we assume we only have one
-            can_group_with={self.prov.lookup_key},
+            can_group_with={self.prov.instance_id},
         )
         if SonosCapability.LINE_IN in self.discovery_info["device"]["capabilities"]:
             mass_player.source_list.append(PLAYER_SOURCE_MAP[SOURCE_LINE_IN])
@@ -308,7 +308,7 @@ class SonosPlayer:
                     if x.player_id != airplay_player.player_id
                 )
             else:
-                self.mass_player.can_group_with = {self.prov.lookup_key}
+                self.mass_player.can_group_with = {self.prov.instance_id}
             self.mass_player.synced_to = None
         else:
             # player is group child (synced to another player)
index c06056e3724a7a0d7e9a893a59927c4b97ffb7c4..ebb2e5aa80b49a96fa96fdf79f8ff4baf89615d3 100644 (file)
@@ -429,7 +429,7 @@ class SonosPlayerProvider(PlayerProvider):
         if not (mass_player := self.mass.players.get(soco.uid)):
             mass_player = Player(
                 player_id=soco.uid,
-                provider=self.lookup_key,
+                provider=self.instance_id,
                 type=PlayerType.PLAYER,
                 name=soco.player_name,
                 available=True,
@@ -441,7 +441,7 @@ class SonosPlayerProvider(PlayerProvider):
                 ),
                 needs_poll=True,
                 poll_interval=30,
-                can_group_with={self.lookup_key},
+                can_group_with={self.instance_id},
             )
         self.sonosplayers[player_id] = sonos_player = SonosPlayer(
             self,
index eadbfc3859d25f9fcced1b4402edad286dc85855..3c4104aab5bd80049f1735cd099c16f58295bfc1 100644 (file)
@@ -122,7 +122,7 @@ class SpotifyConnectProvider(PluginProvider):
         self._librespot_started = asyncio.Event()
         self.named_pipe = f"/tmp/{self.instance_id}"  # noqa: S108
         self._source_details = PluginSource(
-            id=self.lookup_key,
+            id=self.instance_id,
             name=self.manifest.name,
             # we set passive to true because we
             # dont allow this source to be selected directly
@@ -276,7 +276,7 @@ class SpotifyConnectProvider(PluginProvider):
             # initiate playback by selecting this source on the default player
             self.logger.error("Initiating playback on %s", self.mass_player_id)
             self.mass.create_task(
-                self.mass.players.select_source(self.mass_player_id, self.lookup_key)
+                self.mass.players.select_source(self.mass_player_id, self.instance_id)
             )
             self._source_details.in_use_by = self.mass_player_id