示例#1
0
class Image(Descriptor):
    __protobuf__ = metadata_pb2.Image

    file_uri = PropertyProxy(
        'file_id', func=lambda file_id: Uri.from_gid('image', file_id))

    size = PropertyProxy()

    width = PropertyProxy
    height = PropertyProxy

    @staticmethod
    def __parsers__():
        return [MercuryJSON, XML, Tunigo]

    @property
    def file_url(self):
        if not self.file_uri or type(self.file_uri) is not Uri:
            return None

        return 'https://%s/%s/%s' % (RESOURCE_HOST,
                                     SIZES.get(self.size, self.width),
                                     self.file_uri.to_id(size=40))

    @classmethod
    def from_id(cls, id):
        return cls(None, {
            'file_id': Uri.from_id('image', id).to_gid(size=40),
            'size': 3
        })
示例#2
0
class Artist(Descriptor):
    __protobuf__ = metadata_pb2.Artist

    gid = PropertyProxy
    uri = PropertyProxy('gid', func=lambda gid: Uri.from_gid('artist', gid))
    name = PropertyProxy

    popularity = PropertyProxy
    top_tracks = PropertyProxy('top_track', 'TopTracks')

    albums = PropertyProxy('album_group', 'AlbumGroup')
    singles = PropertyProxy('single_group', 'AlbumGroup')
    compilations = PropertyProxy('compilation_group', 'AlbumGroup')
    appears_on = PropertyProxy('appears_on_group', 'AlbumGroup')

    genres = PropertyProxy('genre')
    external_ids = PropertyProxy('external_id', 'ExternalId')

    portraits = PropertyProxy('portrait', 'Image')
    biographies = PropertyProxy('biography')

    activity_periods = PropertyProxy('activity_period')
    restrictions = PropertyProxy('restriction')
    related = PropertyProxy('related')

    is_portrait_album_cover = PropertyProxy('is_portrait_album_cover')
    portrait_group = PropertyProxy('portrait_group')

    @staticmethod
    def __parsers__():
        return [MercuryJSON, XML, Tunigo]
示例#3
0
文件: track.py 项目: novag/spotify.py
    def track_uri(self, callback=None):
        """Requests the track stream URI.

        :param callback: Callback to trigger on a successful response
        :type callback: function

        :return: decorate wrapper if no callback is provided, otherwise
                 returns the `Request` object.
        :rtype: function or `spotify.core.request.Request`
        """

        def on_track_uri(response):
            def on_track_key(key):
                if callback:
                    callback(response, EncryptedStream(self.sp, key))

            self.sp.trackKeyQueue.put(on_track_key)

        files = {}
        for file in self.files:
            files[file.format] = file
            log.debug("[%s] File format found: %s", self.uri, file.format)

        request = self.build("sp/track_uri2", self.uri.to_id(), Uri.from_gid(None, files.get(7).file_id))

        return self.request_wrapper(request, on_track_uri)
示例#4
0
文件: cache.py 项目: novag/spotify.py
    def get_object_key(self, content_type, internal):
        group, type = self.get_schema_key(content_type)

        if group is None or type is None:
            return None, None

        uri = Uri.from_gid(type, internal.gid)

        return "hm://%s/%s" % (group, uri.type), uri.to_id()
示例#5
0
    def get_object_key(self, content_type, internal):
        group, type = self.get_schema_key(content_type)

        if group is None or type is None:
            return None, None

        uri = Uri.from_gid(type, internal.gid)

        return 'hm://%s/%s' % (group, uri.type), uri.to_id()
示例#6
0
class Album(Descriptor):
    __protobuf__ = metadata_pb2.Album

    gid = PropertyProxy
    uri = PropertyProxy('gid', func=lambda gid: Uri.from_gid('album', gid))
    name = PropertyProxy

    artists = PropertyProxy('artist', 'Artist')
    type = PropertyProxy

    label = PropertyProxy
    date = PropertyProxy(func=PropertyProxy.parse_date)
    popularity = PropertyProxy

    genres = PropertyProxy('genre')
    covers = PropertyProxy('cover', 'Image')
    external_ids = PropertyProxy('external_id', 'ExternalId')

    discs = PropertyProxy('disc', 'Disc')
    # review - []
    copyrights = PropertyProxy('copyright', 'Copyright')
    restrictions = PropertyProxy('restriction', 'Restriction')
    # related - []
    # sale_period - []
    cover_group = PropertyProxy('cover_group', 'ImageGroup')

    @staticmethod
    def __parsers__():
        return [MercuryJSON, XML, Tunigo]

    def is_available(self):
        message = ''

        for restriction in self.restrictions:
            success, message = restriction.check()

            if success:
                return True

        log.debug('Album "%s" not available (%s)', self.uri, message)
        return False

    @property
    def tracks(self):
        # Iterate through each disc and return a flat track list
        for disc in self.discs:

            for track in disc.tracks:
                yield track
示例#7
0
class Track(Descriptor):
    __protobuf__ = metadata_pb2.Track

    gid = PropertyProxy
    uri = PropertyProxy('gid', func=lambda gid: Uri.from_gid('track', gid))
    name = PropertyProxy

    album = PropertyProxy('album', 'Album')
    artists = PropertyProxy('artist', 'Artist')

    number = PropertyProxy
    disc_number = PropertyProxy
    duration = PropertyProxy

    popularity = PropertyProxy
    explicit = PropertyProxy

    external_ids = PropertyProxy('external_id', 'ExternalId')
    restrictions = PropertyProxy('restriction', 'Restriction')
    files = PropertyProxy('file', 'AudioFile')
    alternatives = PropertyProxy('alternative', 'Track')
    # sale_period - []
    preview = PropertyProxy

    @staticmethod
    def __parsers__():
        return [XML]

    def is_available(self):
        catalogues = {}
        available = False

        for restriction in self.restrictions:
            re_available, re_allowed = restriction.check()

            if re_allowed and restriction.catalogues:
                for catalogue in restriction.catalogues:
                    catalogues[catalogue] = True

            if restriction.type is None or restriction.type == 'streaming':
                available |= re_available

        if catalogues.get(self.sp.catalogue):
            return True

        return False

    def find_alternative(self):
        if not self.alternatives:
            log.debug('No alternatives available for "%s"', self.uri)
            return False

        alternative = None

        # Try find an available alternative
        for alternative in self.alternatives:
            if alternative.is_available():
                break
            else:
                alternative = None

        if alternative is None:
            log.debug('Unable to find alternative for "%s"', self.uri)
            return False

        # Update our object with new attributes
        self.protobuf_update(alternative, 'uri', 'gid', 'restrictions',
                             'files')
        return True

    def track_uri(self, callback=None):
        """Requests the track stream URI.

        :param callback: Callback to trigger on a successful response
        :type callback: function

        :return: decorate wrapper if no callback is provided, otherwise
                 returns the `Request` object.
        :rtype: function or `spotify.core.request.Request`
        """
        request = self.build('sp/track_uri', 'mp3160', self.uri.to_id())

        return self.request_wrapper(request, callback)

    def track_event(self, lid, event, time):
        """Send the "sp/track_event" event.

        :param lid: Stream lid (from "sp/track_uri")
        :param event: Event
        :param time: Current track playing position (in milliseconds)
        """
        return self.send('sp/track_event', lid, event, time)

    def track_progress(self,
                       lid,
                       position,
                       source='unknown',
                       reason='unknown',
                       latency=150,
                       context='unknown',
                       referrer=None):
        """
        :type lid: str
        :type position: int
        :type source: str
        :type reason: str
        :type latency: int
        :type context: str
        :type referrer: dict {'referrer', 'version', 'vendor'}
        :return:
        """

        referrer = set_defaults(referrer, {
            'referrer': 'unknown',
            'version': '0.1.0',
            'vendor': 'com.spotify'
        })

        return self.send(
            'sp/track_progress',
            lid,

            # Start
            source,
            reason,

            # Timings
            position,
            latency,

            # Context
            context,
            str(self.uri),

            # Referrer
            referrer['referrer'],
            referrer['version'],
            referrer['vendor'],
        )

    def track_end(self,
                  lid,
                  position,
                  seeks=None,
                  latency=150,
                  context='unknown',
                  source=None,
                  reason=None,
                  referrer=None):
        """
        :type lid: str
        :type position: int
        :type seeks: dict {'num_forward', 'num_backward', 'ms_forward', 'ms_backward'}
        :type latency: int
        :type context: str
        :type source: dict {'start', 'end'}
        :type reason: dict {'start', 'end'}
        :type referrer: dict {'referrer', 'version', 'vendor'}
        :return:
        """

        seeks = set_defaults(seeks, {
            'num_forward': 0,
            'num_backward': 0,
            'ms_forward': 0,
            'ms_backward': 0
        })

        source = set_defaults(source, {'start': 'unknown', 'end': 'unknown'})

        reason = set_defaults(reason, {'start': 'unknown', 'end': 'unknown'})

        referrer = set_defaults(referrer, {
            'referrer': 'unknown',
            'version': '0.1.0',
            'vendor': 'com.spotify'
        })

        return self.send(
            'sp/track_end',
            lid,

            # Timings
            position,  # ms_played
            position,  # ms_played_union

            # Seek count
            seeks['num_forward'],
            seeks['num_backward'],
            seeks['ms_forward'],
            seeks['ms_backward'],
            latency,

            # Context
            str(self.uri),
            context,

            # Source
            source['start'],
            source['end'],

            # Reason
            reason['start'],
            reason['end'],

            # Referrer
            referrer['referrer'],
            referrer['version'],
            referrer['vendor'],
            position  # max_continuous
        )