diff --git a/homeassistant/components/mpd/media_player.py b/homeassistant/components/mpd/media_player.py index d2c6b7eeaf3..4d3df8f00ca 100644 --- a/homeassistant/components/mpd/media_player.py +++ b/homeassistant/components/mpd/media_player.py @@ -119,6 +119,9 @@ class MpdDevice(MediaPlayerEntity): self._muted_volume = None self._media_position_updated_at = None self._media_position = None + self._media_image_hash = None + # Track if the song changed so image doesn't have to be loaded every update. + self._media_image_file = None self._commands = None # set up MPD client @@ -149,6 +152,7 @@ class MpdDevice(MediaPlayerEntity): """Fetch status from MPD.""" self._status = await self._client.status() self._currentsong = await self._client.currentsong() + await self._async_update_media_image_hash() if (position := self._status.get("elapsed")) is None: position = self._status.get("time") @@ -265,16 +269,46 @@ class MpdDevice(MediaPlayerEntity): @property def media_image_hash(self): """Hash value for media image.""" - if file := self._currentsong.get("file"): - return hashlib.sha256(file.encode("utf-8")).hexdigest()[:16] - - return None + return self._media_image_hash async def async_get_media_image(self): """Fetch media image of current playing track.""" if not (file := self._currentsong.get("file")): return None, None + response = await self._async_get_file_image_response(file) + if response is None: + return None, None + image = bytes(response["binary"]) + mime = response.get( + "type", "image/png" + ) # readpicture has type, albumart does not + return (image, mime) + + async def _async_update_media_image_hash(self): + """Update the hash value for the media image.""" + file = self._currentsong.get("file") + + if file == self._media_image_file: + return + + if ( + file is not None + and (response := await self._async_get_file_image_response(file)) + is not None + ): + self._media_image_hash = hashlib.sha256( + bytes(response["binary"]) + ).hexdigest()[:16] + else: + # If there is no image, this hash has to be None, else the media player component + # assumes there is an image and returns an error trying to load it and the + # frontend media control card breaks. + self._media_image_hash = None + + self._media_image_file = file + + async def _async_get_file_image_response(self, file): # not all MPD implementations and versions support the `albumart` and `fetchpicture` commands can_albumart = "albumart" in self._commands can_readpicture = "readpicture" in self._commands @@ -303,14 +337,11 @@ class MpdDevice(MediaPlayerEntity): error, ) + # response can be an empty object if there is no image if not response: - return None, None + return None - image = bytes(response.get("binary")) - mime = response.get( - "type", "image/png" - ) # readpicture has type, albumart does not - return (image, mime) + return response @property def volume_level(self):