From f8df8b6b19e997ce1dd2490163d97fbf777a3820 Mon Sep 17 00:00:00 2001
From: Martin Weinelt <mweinelt@users.noreply.github.com>
Date: Sat, 26 Dec 2020 22:18:28 +0100
Subject: [PATCH] Add album art support in the mpd component (#44527)

* Add album art support in the mpd component

Uses `readpicture` to retrieve embedded artwork and `albumart` to
acquire cover art located in the media directory.

As the mpd component supports multiple different implementations (think
mopidy, PI MusicBox, etc.) we check for the availability of each command
before using them.

Tested against mpd 0.22.3, which includes support for both.

* fixup! Add album art support in the mpd component
---
 homeassistant/components/mpd/media_player.py | 53 ++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/homeassistant/components/mpd/media_player.py b/homeassistant/components/mpd/media_player.py
index 1e16675f7b6..1273b720dd8 100644
--- a/homeassistant/components/mpd/media_player.py
+++ b/homeassistant/components/mpd/media_player.py
@@ -1,5 +1,6 @@
 """Support to interact with a Music Player Daemon."""
 from datetime import timedelta
+import hashlib
 import logging
 import os
 
@@ -107,6 +108,7 @@ class MpdDevice(MediaPlayerEntity):
         self._muted_volume = 0
         self._media_position_updated_at = None
         self._media_position = None
+        self._commands = None
 
         # set up MPD client
         self._client = MPDClient()
@@ -163,6 +165,7 @@ class MpdDevice(MediaPlayerEntity):
         try:
             if not self._is_connected:
                 await self._connect()
+                self._commands = list(await self._client.commands())
 
             await self._fetch_status()
         except (mpd.ConnectionError, OSError, BrokenPipeError, ValueError) as error:
@@ -252,6 +255,56 @@ class MpdDevice(MediaPlayerEntity):
         """Return the album of current playing media (Music track only)."""
         return self._currentsong.get("album")
 
+    @property
+    def media_image_hash(self):
+        """Hash value for media image."""
+        file = self._currentsong.get("file")
+        if file:
+            return hashlib.sha256(file.encode("utf-8")).hexdigest()[:16]
+
+        return None
+
+    async def async_get_media_image(self):
+        """Fetch media image of current playing track."""
+        file = self._currentsong.get("file")
+        if not file:
+            return None, None
+
+        # not all MPD implementations and versions support the `albumart` and `fetchpicture` commands
+        can_albumart = "albumart" in self._commands
+        can_readpicture = "readpicture" in self._commands
+
+        response = None
+
+        # read artwork embedded into the media file
+        if can_readpicture:
+            try:
+                response = await self._client.readpicture(file)
+            except mpd.CommandError as error:
+                _LOGGER.warning(
+                    "Retrieving artwork through `readpicture` command failed: %s",
+                    error,
+                )
+
+        # read artwork contained in the media directory (cover.{jpg,png,tiff,bmp}) if none is embedded
+        if can_albumart and not response:
+            try:
+                response = await self._client.albumart(file)
+            except mpd.CommandError as error:
+                _LOGGER.warning(
+                    "Retrieving artwork through `albumart` command failed: %s",
+                    error,
+                )
+
+        if not response:
+            return None, None
+
+        image = bytes(response.get("binary"))
+        mime = response.get(
+            "type", "image/png"
+        )  # readpicture has type, albumart does not
+        return (image, mime)
+
     @property
     def volume_level(self):
         """Return the volume level."""
-- 
GitLab