class MrpMetadata(Metadata): """Implementation of API for retrieving metadata.""" def __init__(self, protocol, psm, identifier): """Initialize a new MrpPlaying.""" super().__init__(identifier) self.protocol = protocol self.psm = psm self.artwork_cache = Cache(limit=4) async def artwork(self): """Return artwork for what is currently playing (or None).""" identifier = self.artwork_id if not identifier: _LOGGER.debug('No artwork available') return None if identifier in self.artwork_cache: _LOGGER.debug('Retrieved artwork %s from cache', identifier) return self.artwork_cache.get(identifier) artwork = await self._fetch_artwork() if artwork: self.artwork_cache.put(identifier, artwork) return artwork return None async def _fetch_artwork(self): playing = self.psm.playing resp = await self.psm.protocol.send_and_receive( messages.playback_queue_request(playing.location)) if not resp.HasField('type'): return None item = resp.inner().playbackQueue.contentItems[playing.location] return ArtworkInfo(item.artworkData, playing.metadata.artworkMIMEType) @property def artwork_id(self): """Return a unique identifier for current artwork.""" metadata = self.psm.playing.metadata if metadata and metadata.artworkAvailable: if metadata.HasField('artworkIdentifier'): return metadata.artworkIdentifier if metadata.HasField('contentIdentifier'): return metadata.contentIdentifier return None async def playing(self): """Return what is currently playing.""" return MrpPlaying(self.psm.playing)
class DmapMetadata(Metadata): """Implementation of API for retrieving metadata from an Apple TV.""" def __init__(self, identifier, apple_tv): """Initialize metadata instance.""" super().__init__(identifier) self.apple_tv = apple_tv self.artwork_cache = Cache(limit=4) async def artwork(self): """Return artwork for what is currently playing (or None).""" # Having to fetch "playing" here is not ideal, but an identifier is # needed and we cannot trust any previous identifiers. So we have to do # this until a better solution comes along. playing = await self.playing() identifier = playing.hash if identifier in self.artwork_cache: _LOGGER.debug('Retrieved artwork %s from cache', identifier) return self.artwork_cache.get(identifier) artwork = await self._fetch_artwork() if artwork: self.artwork_cache.put(identifier, artwork) return artwork return None async def _fetch_artwork(self): _LOGGER.debug('Fetching artwork') data = await self.apple_tv.artwork() if data: return ArtworkInfo(data, 'image/png') return None @property def artwork_id(self): """Return a unique identifier for current artwork.""" return self.apple_tv.latest_hash async def playing(self): """Return current device state.""" return await self.apple_tv.playstatus()
def __init__(self, identifier, apple_tv): """Initialize metadata instance.""" super().__init__(identifier) self.apple_tv = apple_tv self.artwork_cache = Cache(limit=4)
def __init__(self, protocol, psm, identifier): """Initialize a new MrpPlaying.""" super().__init__(identifier) self.protocol = protocol self.psm = psm self.artwork_cache = Cache(limit=4)
def setUp(self): self.cache = Cache(limit=2)
class CacheTest(unittest.TestCase): def setUp(self): self.cache = Cache(limit=2) def test_cache_is_empty(self): self.assertTrue(self.cache.empty()) def test_put_get_item(self): self.cache.put(ID1, DATA1) self.assertEqual(self.cache.get(ID1), DATA1) def test_put_get_multiple(self): self.cache.put(ID1, DATA1) self.cache.put(ID2, DATA2) self.assertEqual(self.cache.get(ID1), DATA1) self.assertEqual(self.cache.get(ID2), DATA2) def test_cache_not_empty(self): self.cache.put(ID1, DATA1) self.assertFalse(self.cache.empty()) def test_cache_has_item(self): self.cache.put(ID1, DATA1) self.assertTrue(ID1 in self.cache) self.assertFalse(ID2 in self.cache) def test_cache_size(self): self.assertEqual(len(self.cache), 0) self.cache.put(ID1, DATA1) self.assertEqual(len(self.cache), 1) def test_put_same_identifier_replaces_data(self): self.cache.put(ID1, DATA1) self.cache.put(ID1, DATA2) self.assertEqual(self.cache.get(ID1), DATA2) self.assertEqual(len(self.cache), 1) def test_put_removes_oldest(self): self.cache.put(ID1, DATA1) self.cache.put(ID2, DATA2) self.cache.put(ID3, DATA3) self.assertEqual(len(self.cache), 2) self.assertNotIn(ID1, self.cache) self.assertIn(ID2, self.cache) self.assertIn(ID3, self.cache) def test_get_makes_data_newer(self): self.cache.put(ID1, DATA1) self.cache.put(ID2, DATA2) self.cache.get(ID1) self.cache.put(ID3, DATA3) self.assertEqual(len(self.cache), 2) self.assertIn(ID1, self.cache) self.assertNotIn(ID2, self.cache) self.assertIn(ID3, self.cache) def test_get_latest_identifier(self): self.assertEqual(self.cache.latest(), None) self.cache.put(ID1, DATA1) self.assertEqual(self.cache.latest(), ID1) self.cache.put(ID2, DATA2) self.assertEqual(self.cache.latest(), ID2) self.cache.get(ID1) self.assertEqual(self.cache.latest(), ID1)