if not protocol_provider:
continue
+ # Extract domain from provider instance_id (e.g., "airplay--uuid" -> "airplay")
+ protocol_domain = protocol_provider.split("--")[0]
+
# Get provider name for display
provider_name = "Protocol" # Default fallback
for provider in self.mass.get_providers(ProviderType.PLAYER):
- if provider.domain == protocol_provider:
+ if provider.domain == protocol_domain:
provider_name = provider.name
break
# Get priority for this protocol
- priority = PROTOCOL_PRIORITY.get(protocol_provider, 100)
+ priority = PROTOCOL_PRIORITY.get(protocol_domain, 100)
# Check if protocol player is available (registered)
protocol_player = self.get_player(protocol_id)
OutputProtocol(
output_protocol_id=protocol_id,
name=provider_name,
- protocol_domain=protocol_provider,
+ protocol_domain=protocol_domain,
priority=priority,
is_native=False,
available=is_available,
return list(self._provider_manifests.values())
@api_command("providers/manifests/get")
- def get_provider_manifest(self, domain: str) -> ProviderManifest:
+ def get_provider_manifest(self, instance_id_or_domain: str) -> ProviderManifest:
"""Return Provider manifests of single provider(domain)."""
- return self._provider_manifests[domain]
+ if instance_id_or_domain in self._provider_manifests:
+ return self._provider_manifests[instance_id_or_domain]
+ if provider := self.get_provider(instance_id_or_domain, return_unavailable=True):
+ return provider.manifest
+ raise KeyError(f"Provider manifest not found for {instance_id_or_domain}")
@api_command("providers")
def get_providers(
from collections.abc import Callable
from typing import TYPE_CHECKING, Any, cast
+from music_assistant_models.enums import ProviderFeature
+
from music_assistant.mass import MusicAssistant
from music_assistant.models.player_provider import PlayerProvider
hass_prov: HomeAssistantProvider,
) -> None:
"""Initialize MusicProvider."""
- super().__init__(mass, manifest, config)
+ supported_features = {ProviderFeature.REMOVE_PLAYER}
+ super().__init__(mass, manifest, config, supported_features=supported_features)
self.hass_prov = hass_prov
async def loaded_in_mass(self) -> None:
self.on_unload_callbacks = [
await self.hass_prov.hass.subscribe_entities(self._on_entity_state_update, player_ids)
]
+ # cleanup any players that are no longer in the config
+ for player_conf in await self.mass.config.get_player_configs(
+ provider=self.instance_id, include_unavailable=True, include_disabled=True
+ ):
+ if player_conf.player_id not in player_ids:
+ await self.mass.players.remove(player_conf.player_id)
async def unload(self, is_removed: bool = False) -> None:
"""
for callback in self.on_unload_callbacks:
callback()
+ async def remove_player(self, player_id: str) -> None:
+ """Remove a player."""
+ player_ids = cast("list[str]", self.config.get_value(CONF_PLAYERS))
+ if player_id in player_ids:
+ player_ids.remove(player_id)
+ self.mass.config.set_raw_provider_config_value(
+ self.instance_id, CONF_PLAYERS, player_ids
+ )
+ await self.mass.players.unregister(player_id, True)
+
async def _setup_player(
self,
state: HassState,