Some more fixes for the Airplay provider (#1088)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Sun, 18 Feb 2024 20:30:45 +0000 (21:30 +0100)
committerGitHub <noreply@github.com>
Sun, 18 Feb 2024 20:30:45 +0000 (21:30 +0100)
music_assistant/server/providers/airplay/__init__.py

index 98042efd2388e9016a77b3b7e926ef8e7094008c..643f8bd53138ec0367b0eea9e941112d64a64f1c 100644 (file)
@@ -10,6 +10,8 @@ from random import randint, randrange
 from typing import TYPE_CHECKING, cast
 
 import aiofiles
+import shortuuid
+from aiofiles.os import wrap
 from pyatv import connect, exceptions, interface, scan
 from pyatv.conf import AppleTV as ATVConf
 from pyatv.const import DeviceModel, DeviceState, PowerState, Protocol
@@ -38,7 +40,6 @@ from music_assistant.common.models.enums import (
 from music_assistant.common.models.media_items import AudioFormat
 from music_assistant.common.models.player import DeviceInfo, Player
 from music_assistant.server.helpers.process import AsyncProcess, check_output
-from music_assistant.server.helpers.util import create_tempfile
 from music_assistant.server.models.player_provider import PlayerProvider
 
 if TYPE_CHECKING:
@@ -49,6 +50,8 @@ if TYPE_CHECKING:
     from music_assistant.server.controllers.streams import MultiClientStreamJob
     from music_assistant.server.models import ProviderInstanceType
 
+DOMAIN = "airplay"
+
 CONF_LATENCY = "latency"
 CONF_ENCRYPTION = "encryption"
 CONF_ALAC_ENCODE = "alac_encode"
@@ -374,7 +377,7 @@ class AirPlayPlayer(DeviceListener):
         if not (mass_player := self.mass.players.get(self.player_id)):
             mass_player = Player(
                 player_id=self.player_id,
-                provider="airplay",
+                provider=DOMAIN,
                 type=PlayerType.PLAYER,
                 name=self.discovery_info.name,
                 available=True,
@@ -871,7 +874,12 @@ class AirplayProvider(PlayerProvider):
             if discovery_info.address != atv_player.discovery_info.address:
                 atv_player.address_updated(discovery_info.address)
             return
-        self.logger.info(f"Connecting to {discovery_info.address}")
+        if "_raop._tcp.local" not in discovery_info.properties:
+            # skip players without raop
+            return
+        self.logger.debug(
+            "Discovered Airplay device %s on %s", discovery_info.name, discovery_info.address
+        )
         self._atv_players[player_id] = atv_player = AirPlayPlayer(
             self.mass, player_id, discovery_info
         )
@@ -1050,25 +1058,29 @@ class AirplayProvider(PlayerProvider):
         cmd = f"TITLE={title or 'Music Assistant'}\nARTIST={artist}\nALBUM={album}\n"
         cmd += f"DURATION={duration}\nACTION=SENDMETA\n"
 
-        async with asyncio.TaskGroup() as tg:
-            for atv_player in self._get_sync_clients(player_id):
-                tg.create_task(atv_player.send_cli_command(cmd))
+        for atv_player in self._get_sync_clients(player_id):
+            await atv_player.send_cli_command(cmd)
+
+        # temp test for not sending artwork
+        exists_func = wrap(os.path.exists)
+        if await exists_func("/tmp/do_not_send_artwork"):  # noqa: S108
+            return
 
         # get image
         if not queue.current_item.image:
             return
-        image_path = create_tempfile()
+        image_path = f"/tmp/{shortuuid.random(12)}"  # noqa: S108
         image_data = await self.mass.metadata.get_thumbnail(
             queue.current_item.image.path,
             512,
             queue.current_item.image.provider,
         )
-        async with aiofiles.open(image_path.name, "wb") as outfile:
+        async with aiofiles.open(image_path, "wb") as outfile:
             await outfile.write(image_data)
-            async with asyncio.TaskGroup() as tg:
-                for atv_player in self._get_sync_clients(player_id):
-                    if image_path:
-                        tg.create_task(atv_player.send_cli_command(f"ARTWORK={image_path.name}\n"))
+        for atv_player in self._get_sync_clients(player_id):
+            if image_path:
+                await atv_player.send_cli_command(f"ARTWORK={image_path}\n")
         # make sure the temp file gets deleted again
-        await asyncio.sleep(5)
-        image_path.close()
+        await asyncio.sleep(10)
+        rm_func = wrap(os.remove)
+        await rm_func(image_path)