Various small bugfixes reported in the beta (#2475)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Fri, 3 Oct 2025 18:23:54 +0000 (20:23 +0200)
committerGitHub <noreply@github.com>
Fri, 3 Oct 2025 18:23:54 +0000 (20:23 +0200)
music_assistant/controllers/players/player_controller.py
music_assistant/controllers/players/sync_groups.py
music_assistant/controllers/streams.py
music_assistant/providers/squeezelite/player.py
music_assistant/providers/ytmusic/__init__.py

index ccef9d01ba2b162d3cc96899b9cf816cce1f0f99..8ce9851487088322f5be2fdba07a18f558fec158 100644 (file)
@@ -64,6 +64,7 @@ from music_assistant.constants import (
     CONF_PLAYER_DSP,
     CONF_PLAYERS,
     CONF_PRE_ANNOUNCE_CHIME_URL,
+    SYNCGROUP_PREFIX,
 )
 from music_assistant.helpers.api import api_command
 from music_assistant.helpers.tags import async_parse_tags
@@ -901,7 +902,9 @@ class PlayerController(CoreController):
                     pre_announce_url=pre_announce_url,
                 )
                 announcement = PlayerMedia(
-                    uri=self.mass.streams.get_announcement_url(player_id, url, announce_data),
+                    uri=self.mass.streams.get_announcement_url(
+                        player_id, announce_data=announce_data
+                    ),
                     media_type=MediaType.ANNOUNCEMENT,
                     title="Announcement",
                     custom_data=announce_data,
@@ -1420,8 +1423,12 @@ class PlayerController(CoreController):
             # we simply permanently delete the player config since it is not registered
             self.delete_player_config(player_id)
             return
+        if player.type == PlayerType.GROUP and player_id.startswith(SYNCGROUP_PREFIX):
+            await self._sync_groups.remove_group_player(player_id)
+            return
         if player.type == PlayerType.GROUP:
             # Handle group player removal
+            player.provider.check_feature(ProviderFeature.REMOVE_GROUP_PLAYER)
             await player.provider.remove_group_player(player_id)
             return
         player.provider.check_feature(ProviderFeature.REMOVE_PLAYER)
index de60ff5849490a8fe5d4297da3e5138f05dd169b..4ee5a183f77f524da4f53bf324ee2cc6f3719104 100644 (file)
@@ -284,7 +284,7 @@ class SyncGroupPlayer(GroupPlayer):
             ):
                 await self._handle_member_collisions(member)
                 if not member.powered and member.power_control != PLAYER_CONTROL_NONE:
-                    await member.power(True)
+                    await self.mass.players.cmd_power(member.player_id, True)
             # Set up the sync group with the new leader
             await self._handle_leader_transition(new_leader)
         elif prev_power and not powered:
@@ -295,7 +295,7 @@ class SyncGroupPlayer(GroupPlayer):
                 self, only_powered=True, active_only=True
             ):
                 if member.powered and member.power_control != PLAYER_CONTROL_NONE:
-                    await member.power(False)
+                    await self.mass.players.cmd_power(member.player_id, False)
 
         if not powered:
             # Reset to unfiltered static members list when powered off
index 55ec3da06d104ef1d8ae52ba3c28e595838f68a8..ec06a4caafeb36e68954a2ceab8958d150c0cf50 100644 (file)
@@ -823,10 +823,10 @@ class StreamsController(CoreController):
             queue.queue_id, CONF_CROSSFADE_DURATION, 10
         )
         self.logger.info(
-            "Start Queue Flow stream for Queue %s - %s: %s",
-            smart_fades_mode,
+            "Start Queue Flow stream for Queue %s - crossfade: %s %s",
             queue.display_name,
-            f"{standard_crossfade_duration}s"
+            smart_fades_mode,
+            f"({standard_crossfade_duration}s)"
             if smart_fades_mode == SmartFadesMode.STANDARD_CROSSFADE
             else "",
         )
index 50f6133c514c299daf398e709f2e2039b9166606..965d2af63041fa5f11e6c1df6797fd8036dda627 100644 (file)
@@ -35,6 +35,7 @@ from music_assistant.constants import (
     CONF_ENTRY_OUTPUT_CODEC,
     CONF_ENTRY_SYNC_ADJUST,
     DEFAULT_PCM_FORMAT,
+    VERBOSE_LOG_LEVEL,
     create_sample_rates_config_entry,
 )
 from music_assistant.helpers.ffmpeg import get_ffmpeg_stream
@@ -398,7 +399,7 @@ class SqueezelitePlayer(Player):
                 artist=metadata.get("artist"),
                 image_url=metadata.get("image_url"),
                 duration=metadata.get("duration"),
-                queue_id=metadata.get("queue_id"),
+                source_id=metadata.get("source_id"),
                 queue_item_id=metadata.get("queue_item_id"),
             )
         else:
@@ -421,7 +422,7 @@ class SqueezelitePlayer(Player):
             "artist": media.artist,
             "image_url": media.image_url,
             "duration": media.duration,
-            "queue_id": media.source_id,
+            "source_id": media.source_id,
             "queue_item_id": media.queue_item_id,
         }
         if queue := self.mass.player_queues.get(media.source_id):
@@ -541,7 +542,7 @@ class SqueezelitePlayer(Player):
             _, param = event_data.split(" ", 1)
             if param.isnumeric():
                 await self.mass.player_queues.seek(queue.queue_id, int(param))
-        self.logger.debug("CLI Event: %s", event_data)
+        self.logger.log(VERBOSE_LOG_LEVEL, "CLI Event: %s", event_data)
 
     def _handle_sync(self) -> None:
         """Synchronize audio of a sync slimplayer."""
index 1fafb4d6a065210afae3afca53861a2bea6a6c99..c9d2e42496a43c915f2bdac44baf46ee995fe183 100644 (file)
@@ -653,6 +653,8 @@ class YoutubeMusicProvider(MusicProvider):
                 icon=determine_recommendation_icon(section["title"]),
             )
             for recommended_item in section.get("contents", []):
+                if not recommended_item:
+                    continue  # yeah this seems to happen sometimes ?!
                 if recommended_item.get("videoId"):
                     # Probably a track
                     try: