Esempio n. 1
0
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)
Esempio n. 2
0
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()
Esempio n. 3
0
 def __init__(self, identifier, apple_tv):
     """Initialize metadata instance."""
     super().__init__(identifier)
     self.apple_tv = apple_tv
     self.artwork_cache = Cache(limit=4)
Esempio n. 4
0
 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)
Esempio n. 5
0
 def setUp(self):
     self.cache = Cache(limit=2)
Esempio n. 6
0
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)