@@ -166,6 +166,7 @@ async def wrapper(self: _AppleTvT, *args: _P.args, **kwargs: _P.kwargs) -> ucapi
166166
167167
168168ARTWORK_CACHE : dict [str , bytes ] = {}
169+ PLAYING_STATE_CACHE : dict [str , int ] = {}
169170
170171
171172class AppleTv (interface .AudioListener , interface .DeviceListener ):
@@ -564,8 +565,10 @@ async def _process_update(self, data: pyatv.interface.Playing) -> None: # pylin
564565 update ["media_type" ] = ""
565566 update ["repeat" ] = "OFF"
566567 update ["shuffle" ] = False
568+ # Send None for data so that artwork is cleared
569+ await self ._process_artwork (update , None )
567570 else :
568- await self ._process_artwork (update )
571+ await self ._process_artwork (update , data )
569572
570573 await self ._cleanup_data (data , update )
571574
@@ -714,9 +717,12 @@ async def _poll_worker(self) -> None:
714717 self ._state = data .device_state
715718 update ["state" ] = data .device_state
716719
717- await self ._process_artwork (update )
720+ await self ._process_artwork (update , data )
718721
719722 await self ._cleanup_data (data , update )
723+ else :
724+ # No playback data available, clear the artwork
725+ await self ._process_artwork (update , None )
720726
721727 if update :
722728 self .events .emit (EVENTS .UPDATE , self ._device .identifier , update )
@@ -734,20 +740,40 @@ async def _handle_power(self, update: dict[Any, Any]):
734740 else :
735741 update ["state" ] = self ._atv .power .power_state
736742
737- async def _process_artwork (self , update : dict [Any , Any ]):
743+ async def _process_artwork (self , update : dict [Any , Any ], data : pyatv . interface . Playing | None ):
738744 if self ._state not in [DeviceState .Idle , DeviceState .Stopped ]:
739745 try :
746+ if data :
747+ playback_hash = hash ((data .title , data .artist , data .album ))
748+ # Hash has changed, invalidate/update cache
749+ if PLAYING_STATE_CACHE .get (self ._device .identifier , None ) != playback_hash :
750+ ARTWORK_CACHE .pop (self ._device .identifier , None )
751+ PLAYING_STATE_CACHE [self ._device .identifier ] = playback_hash
752+ else :
753+ # No way of knowing if playback changed, clear cache so that the artwork is sent again
754+ ARTWORK_CACHE .pop (self ._device .identifier , None )
755+ PLAYING_STATE_CACHE .pop (self ._device .identifier , None )
756+ # Send empty artwork so that it's not stuck in the UI
757+ update ["artwork" ] = ""
758+ return
759+
740760 artwork = await self ._atv .metadata .artwork (width = ARTWORK_WIDTH , height = ARTWORK_HEIGHT )
741761 if artwork :
742- # Check hash of the artwork to avoid processing it again if it's unchanged
743762 artwork_hash = hashlib .md5 (artwork .bytes ).digest ()
744- if ARTWORK_CACHE .get (self ._device .identifier ) == artwork_hash :
763+ # Check hash of the artwork to avoid processing it again if it's unchanged
764+ if ARTWORK_CACHE .get (self ._device .identifier , None ) == artwork_hash :
745765 return
746766 artwork_encoded = "data:image/png;base64," + base64 .b64encode (artwork .bytes ).decode ("utf-8" )
747767 update ["artwork" ] = artwork_encoded
748768 ARTWORK_CACHE [self ._device .identifier ] = artwork_hash
749769 except Exception as err : # pylint: disable=broad-exception-caught
750770 _LOG .warning ("[%s] Error while updating the artwork: %s" , self .log_id , err )
771+ else :
772+ # Not playing - clear caches so that artwork is sent again when playback starts
773+ ARTWORK_CACHE .pop (self ._device .identifier , None )
774+ PLAYING_STATE_CACHE .pop (self ._device .identifier , None )
775+ # Send empty artwork so that it's not stuck in the UI
776+ update ["artwork" ] = ""
751777
752778 def _is_feature_available (self , feature : FeatureName ) -> bool :
753779 if self ._atv :
0 commit comments