diff --git a/custom_components/my_music_library/__init__.py b/custom_components/my_music_library/__init__.py index 686e8611..6b922ddd 100644 --- a/custom_components/my_music_library/__init__.py +++ b/custom_components/my_music_library/__init__.py @@ -18,6 +18,7 @@ from homeassistant.config_entries import ConfigEntryState from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.core import Event, HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.helpers import device_registry as dr from homeassistant.helpers import issue_registry as ir from homeassistant.loader import async_get_integration @@ -25,6 +26,7 @@ from .api import ImageProxyView, MAThumbnailView, MAQueueView, MusicAssistantBro from .const import CARD_JS_FILENAME, CARD_URL, CONF_DEBUG_MODE, CONF_DEFAULT_PLAYER, CONF_DEFAULT_TAB, CONF_EXCLUDED_PLAYERS, CONF_MA_URL, CONFIG_ENTRY_VERSION, DEFAULT_TAB, DOMAIN, ICON_URL, WS_CONFIG_COMMAND, WS_SUBSCRIBE_QUEUE_COMMAND from .duplicates import ISSUE_DUPLICATE_ENTITIES, async_track_duplicates, async_update_issue from .mass_connection import MyMusicLibraryConfigEntry, async_connect, async_disconnect +from .missing_players import async_track_missing from .queue_push import async_relay_queue_events, ws_subscribe_queue from .queue_watchdog import QueueWatchdog @@ -187,6 +189,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: MyMusicLibraryConfigEntr # every media_player registry change. async_update_issue(hass) entry.async_on_unload(async_track_duplicates(hass)) + # Our media_players whose MA player is gone (missing_players.py). + entry.async_on_unload(async_track_missing(hass, entry)) return True @@ -237,6 +241,25 @@ async def async_unload_entry(hass: HomeAssistant, entry: MyMusicLibraryConfigEnt return unload_ok +async def async_remove_config_entry_device( + hass: HomeAssistant, entry: MyMusicLibraryConfigEntry, device_entry: dr.DeviceEntry +) -> bool: + """Allow deleting a device from the UI once its Music Assistant player is gone. + + A player MA still knows would come straight back: it has to be removed in + Music Assistant first. + """ + if entry.state is not ConfigEntryState.LOADED: + return False + mass = entry.runtime_data.mass + if not mass.connection.connected: + return False + return not any( + domain == DOMAIN and mass.players.get(player_id) is not None + for domain, player_id in device_entry.identifiers + ) + + def _register_websocket_commands(hass: HomeAssistant) -> None: """Register WebSocket commands exposed to the frontend card.""" diff --git a/custom_components/my_music_library/manifest.json b/custom_components/my_music_library/manifest.json index 81892e28..f726cc63 100644 --- a/custom_components/my_music_library/manifest.json +++ b/custom_components/my_music_library/manifest.json @@ -8,5 +8,5 @@ "iot_class": "local_push", "issue_tracker": "https://github.com/Patafoin/ha-my-music-library/issues", "requirements": ["music-assistant-client>=1.3.3,<2"], - "version": "4.8.4" + "version": "4.8.5" } diff --git a/custom_components/my_music_library/strings.json b/custom_components/my_music_library/strings.json index 99da3a8c..87b6fbd2 100644 --- a/custom_components/my_music_library/strings.json +++ b/custom_components/my_music_library/strings.json @@ -65,6 +65,24 @@ "no_duplicates": "No duplicate left: nothing to rename." } } + }, + "missing_players": { + "title": "Music Assistant players that no longer exist", + "fix_flow": { + "step": { + "confirm": { + "title": "Delete the media players of vanished players", + "description": "Music Assistant no longer knows these players, but their media players are still in Home Assistant (unavailable):\n\n{players}\n\nThis usually happens when a device comes back under another identifier: Music Assistant then sees a new player (for Squeezelite, a different MAC address — set a fixed MAC address in the player's settings to avoid it), or for browser web players.\n\nTick the media players to delete. Untick a speaker that is only switched off: it will come back by itself when it reconnects.", + "data": { + "players": "Media players to delete" + } + } + }, + "abort": { + "no_missing_players": "Every player is back: nothing to delete.", + "not_connected": "My Music Library is not connected to Music Assistant." + } + } } }, "services": { diff --git a/custom_components/my_music_library/translations/de.json b/custom_components/my_music_library/translations/de.json index bc8d1e70..d80bc21b 100644 --- a/custom_components/my_music_library/translations/de.json +++ b/custom_components/my_music_library/translations/de.json @@ -65,6 +65,24 @@ "no_duplicates": "Keine Duplikate mehr: nichts umzubenennen." } } + }, + "missing_players": { + "title": "Music-Assistant-Player, die nicht mehr existieren", + "fix_flow": { + "step": { + "confirm": { + "title": "Media Player verschwundener Player löschen", + "description": "Music Assistant kennt diese Player nicht mehr, ihre Media Player sind aber noch in Home Assistant (nicht verfügbar):\n\n{players}\n\nDas passiert meist, wenn ein Gerät unter einer anderen Kennung zurückkommt: Music Assistant sieht dann einen neuen Player (bei Squeezelite eine andere MAC-Adresse — eine feste MAC-Adresse in den Player-Einstellungen verhindert das) oder bei Webplayern von Browsern.\n\nWähle die zu löschenden Media Player aus. Einen nur ausgeschalteten Lautsprecher abwählen: Er kommt beim erneuten Verbinden von selbst zurück.", + "data": { + "players": "Zu löschende Media Player" + } + } + }, + "abort": { + "no_missing_players": "Alle Player sind zurück: nichts zu löschen.", + "not_connected": "My Music Library ist nicht mit Music Assistant verbunden." + } + } } }, "services": { diff --git a/custom_components/my_music_library/translations/en.json b/custom_components/my_music_library/translations/en.json index 99da3a8c..87b6fbd2 100644 --- a/custom_components/my_music_library/translations/en.json +++ b/custom_components/my_music_library/translations/en.json @@ -65,6 +65,24 @@ "no_duplicates": "No duplicate left: nothing to rename." } } + }, + "missing_players": { + "title": "Music Assistant players that no longer exist", + "fix_flow": { + "step": { + "confirm": { + "title": "Delete the media players of vanished players", + "description": "Music Assistant no longer knows these players, but their media players are still in Home Assistant (unavailable):\n\n{players}\n\nThis usually happens when a device comes back under another identifier: Music Assistant then sees a new player (for Squeezelite, a different MAC address — set a fixed MAC address in the player's settings to avoid it), or for browser web players.\n\nTick the media players to delete. Untick a speaker that is only switched off: it will come back by itself when it reconnects.", + "data": { + "players": "Media players to delete" + } + } + }, + "abort": { + "no_missing_players": "Every player is back: nothing to delete.", + "not_connected": "My Music Library is not connected to Music Assistant." + } + } } }, "services": { diff --git a/custom_components/my_music_library/translations/fr.json b/custom_components/my_music_library/translations/fr.json index 819f4c66..09163fe2 100644 --- a/custom_components/my_music_library/translations/fr.json +++ b/custom_components/my_music_library/translations/fr.json @@ -65,6 +65,24 @@ "no_duplicates": "Plus aucun doublon : rien à renommer." } } + }, + "missing_players": { + "title": "Lecteurs Music Assistant qui n'existent plus", + "fix_flow": { + "step": { + "confirm": { + "title": "Supprimer les media players des lecteurs disparus", + "description": "Music Assistant ne connaît plus ces lecteurs, mais leurs media players sont restés dans Home Assistant (indisponibles) :\n\n{players}\n\nCela arrive le plus souvent quand un appareil revient sous un autre identifiant : Music Assistant y voit alors un nouveau lecteur (pour Squeezelite, une autre adresse MAC — fixez l'adresse MAC dans les réglages du lecteur pour l'éviter), ou avec les lecteurs web des navigateurs.\n\nCochez les media players à supprimer. Décochez une enceinte simplement éteinte : elle reviendra d'elle-même à sa reconnexion.", + "data": { + "players": "Media players à supprimer" + } + } + }, + "abort": { + "no_missing_players": "Tous les lecteurs sont revenus : rien à supprimer.", + "not_connected": "My Music Library n'est pas connectée à Music Assistant." + } + } } }, "services": { diff --git a/custom_components/my_music_library/www/my-music-library-card.js b/custom_components/my_music_library/www/my-music-library-card.js index 8de70a19..e84a431e 100644 --- a/custom_components/my_music_library/www/my-music-library-card.js +++ b/custom_components/my_music_library/www/my-music-library-card.js @@ -5,7 +5,7 @@ * @version 1.0.0 */ -const CARD_VERSION = "4.8.4"; +const CARD_VERSION = "4.8.5"; /* ─── Icons (inline SVG strings) ─────────────────────────── */ const ICONS = {