Feat: Add removal flag to unload callback
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 7 Jan 2025 23:58:26 +0000 (00:58 +0100)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 7 Jan 2025 23:58:26 +0000 (00:58 +0100)
17 files changed:
music_assistant/controllers/config.py
music_assistant/mass.py
music_assistant/models/provider.py
music_assistant/providers/_template_music_provider/__init__.py
music_assistant/providers/_template_player_provider/__init__.py
music_assistant/providers/airplay/provider.py
music_assistant/providers/chromecast/__init__.py
music_assistant/providers/dlna/__init__.py
music_assistant/providers/filesystem_smb/__init__.py
music_assistant/providers/hass/__init__.py
music_assistant/providers/player_group/__init__.py
music_assistant/providers/siriusxm/__init__.py
music_assistant/providers/slimproto/__init__.py
music_assistant/providers/snapcast/__init__.py
music_assistant/providers/sonos/player.py
music_assistant/providers/sonos/provider.py
music_assistant/providers/sonos_s1/__init__.py

index 6cefe509efdd64024f5ae82a147318290b83d02a..6beae0dce773749cb30263d9a9f4cd63a8954267 100644 (file)
@@ -291,7 +291,7 @@ class ConfigController:
             msg = f"Builtin provider {prov_manifest.name} can not be removed."
             raise RuntimeError(msg)
         self.remove(conf_key)
-        await self.mass.unload_provider(instance_id)
+        await self.mass.unload_provider(instance_id, True)
         if existing["type"] == "music":
             # cleanup entries in library
             await self.mass.music.cleanup_provider(instance_id)
index 5f2174d52fac807e5c0317ece5491b344b79d098..4b9c8298dfa255e032b3388ed6ec8a77a01f8404 100644 (file)
@@ -504,7 +504,7 @@ class MusicAssistant:
             if dep_prov.manifest.depends_on == prov_conf.domain:
                 await self.unload_provider(dep_prov.instance_id)
 
-    async def unload_provider(self, instance_id: str) -> None:
+    async def unload_provider(self, instance_id: str, is_removed: bool = False) -> None:
         """Unload a provider."""
         if provider := self._providers.get(instance_id):
             # remove mdns discovery if needed
@@ -525,7 +525,7 @@ class MusicAssistant:
                     player.available = False
                     self.players.update(player.player_id)
             try:
-                await provider.unload()
+                await provider.unload(is_removed)
             except Exception as err:
                 LOGGER.warning("Error while unload provider %s: %s", provider.name, str(err))
             finally:
index 7b406df670e0b5213242b67c0088696c170bb19b..81d951db6c3da546cc8f6f99ac25e7365c0def91 100644 (file)
@@ -58,11 +58,12 @@ class Provider:
     async def loaded_in_mass(self) -> None:
         """Call after the provider has been loaded."""
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """
         Handle unload/close of the provider.
 
         Called when provider is deregistered (e.g. MA exiting or config reloading).
+        is_removed will be set to True when the provider is removed from the configuration.
         """
 
     async def on_mdns_service_state_change(
index 5dc0adf698e74aa002d4a38b4505463ad7bebe5f..7eaba12ac3e42b2de929eb8bc732614b13bc239e 100644 (file)
@@ -167,11 +167,12 @@ class MyDemoMusicprovider(MusicProvider):
         # relevant or leave out completely if not needed.
         # In most cases this can be omitted for music providers.
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """
         Handle unload/close of the provider.
 
         Called when provider is deregistered (e.g. MA exiting or config reloading).
+        is_removed will be set to True when the provider is removed from the configuration.
         """
         # OPTIONAL
         # This is an optional method that you can implement if
index 104fa89fa07e357595c22050fd2a3a24a2c1d329..7a6467a4176e914648d4bff58145142973ff2fca 100644 (file)
@@ -122,11 +122,12 @@ class MyDemoPlayerprovider(PlayerProvider):
         # you can use this for instance to trigger custom (non-mdns) discovery of players
         # or any other logic that needs to run after the provider is fully loaded.
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """
         Handle unload/close of the provider.
 
         Called when provider is deregistered (e.g. MA exiting or config reloading).
+        is_removed will be set to True when the provider is removed from the configuration.
         """
         # OPTIONAL
         # this is an optional method that you can implement if
index 9fcfefd26ab8985e75ef2a0d3cadf6b7eaafab8b..d44963031c78ae254c460db502c914aa0601ce9e 100644 (file)
@@ -221,8 +221,8 @@ class AirplayProvider(PlayerProvider):
         # handle new player
         await self._setup_player(player_id, display_name, info)
 
-    async def unload(self) -> None:
-        """Handle close/cleanup of the provider."""
+    async def unload(self, is_removed: bool = False) -> None:
+        """Handle unload/close of the provider."""
         # power off all players (will disconnect and close cliraop)
         for player_id in self._players:
             await self.cmd_power(player_id, False)
index b206bde923f50aea41772c1fa2b3a0772948ef79..dd8c334b07b9bacfc5f228ec2752e1d890b515a6 100644 (file)
@@ -153,7 +153,7 @@ class ChromecastProvider(PlayerProvider):
         # start discovery in executor
         await self.mass.loop.run_in_executor(None, self.browser.start_discovery)
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """Handle close/cleanup of the provider."""
         if not self.browser:
             return
index ce0d966cde584fc178189d61a8d9dd058b87f225..028ab3265f91d5e882993880f54362c758b03e1b 100644 (file)
@@ -250,7 +250,7 @@ class DLNAPlayerProvider(PlayerProvider):
         self.upnp_factory = UpnpFactory(self.requester, non_strict=True)
         self.notify_server = DLNANotifyServer(self.requester, self.mass)
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """
         Handle unload/close of the provider.
 
index b43245dd761c373bfaef5538c5da37a75ea33d22..a510876d4b008a570188c57abdc768f32fd9621d 100644 (file)
@@ -149,7 +149,7 @@ class SMBFileSystemProvider(LocalFileSystemProvider):
 
         await self.check_write_access()
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """
         Handle unload/close of the provider.
 
index dc243eb43980aa0e4cfc2a247b2d8c4cf606f1b1..0d6203652a85d04554e3c8a906fed7ab8c9a80b0 100644 (file)
@@ -185,7 +185,7 @@ class HomeAssistant(PluginProvider):
             raise SetupFailedError(err_msg) from err
         self._listen_task = self.mass.create_task(self._hass_listener())
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """
         Handle unload/close of the provider.
 
index 11adea4d7387a1826514b117076f0eb47d58836d..bea0788bb091db642a1fd0ab88614bda93656933 100644 (file)
@@ -202,7 +202,7 @@ class PlayerGroupProvider(PlayerProvider):
             self.mass.subscribe(self._on_mass_player_added_event, EventType.PLAYER_ADDED)
         )
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """
         Handle unload/close of the provider.
 
index 36724642569a2dcc908dba880238ca3474c3236f..d5ed26f2589759fe2d2fa4d17788fdf6663ea33a 100644 (file)
@@ -175,7 +175,7 @@ class SiriusXMProvider(MusicProvider):
 
         self.logger.debug(f"SXM Proxy server running at {bind_ip}:{bind_port}")
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """
         Handle unload/close of the provider.
 
index 234578e770aa6432b4fb631d82e762a4b9d0f981..ab50aa94244f3a878db1b9733115472bc7a8d3b0 100644 (file)
@@ -266,7 +266,7 @@ class SlimprotoProvider(PlayerProvider):
             "/slimproto/multi", self._serve_multi_client_stream
         )
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """Handle close/cleanup of the provider."""
         self.mass.streams.unregister_dynamic_route("/slimproto/multi")
         await self.slimproto.stop()
index 4991436d20933ffc516de3886adcb15ac4726953..11bb1a56045606fe4abb1f99725b9ff0d2780f06 100644 (file)
@@ -332,7 +332,7 @@ class SnapCastProvider(PlayerProvider):
         # initial load of players
         self._handle_update()
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """Handle close/cleanup of the provider."""
         self._stop_called = True
         for snap_client_id in self._snapserver.clients:
index 7b7290685c813fa7ec5c05b01455011a9c91c0d1..78794a5cf440256ece4522a08715e5eb120c1315 100644 (file)
@@ -165,7 +165,7 @@ class SonosPlayer:
             )
         )
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """Unload the player (disconnect + cleanup)."""
         await self._disconnect()
         self.mass.players.remove(self.player_id, False)
index f7c060cec71c16291e0f787a3157f60265b9f732..5b59b16a98bb18717828efa74e8e0e83da173bba 100644 (file)
@@ -67,7 +67,7 @@ class SonosPlayerProvider(PlayerProvider):
             "/sonos_queue/v2.3/timePlayed", self._handle_sonos_queue_time_played
         )
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """Handle close/cleanup of the provider."""
         # disconnect all players
         await asyncio.gather(*(player.unload() for player in self.sonos_players.values()))
index a35d395271f2225a1852d675efc9fc9b9df2b6ab..ed62855af18caa230744022dd77ec13d18c0795a 100644 (file)
@@ -155,7 +155,7 @@ class SonosPlayerProvider(PlayerProvider):
         self.creation_lock = asyncio.Lock()
         self._known_invisible: set[SoCo] = set()
 
-    async def unload(self) -> None:
+    async def unload(self, is_removed: bool = False) -> None:
         """Handle close/cleanup of the provider."""
         if self._discovery_reschedule_timer:
             self._discovery_reschedule_timer.cancel()