Пример #1
0
def create_image(uri):
    uri = Uri.from_uri(uri)

    if uri is None:
        return None

    return Image.from_id(uri.code)
Пример #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
    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
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
        })
Пример #5
0
def create_image(uri):
    uri = Uri.from_uri(uri)

    if uri is None:
        return None

    return Image.from_id(uri.code)
Пример #6
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()
Пример #7
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()
Пример #8
0
 def parse(cls, sp, data, parser):
     return Artist(
         sp, {
             'name': data.get('name'),
             'gid': Uri.from_uri(data.get('uri')).to_gid(),
             'portrait': [{
                 'imageUri': data.get('imageUri')
             }]
         }, parser.MercuryJSON, parser)
Пример #9
0
 def parse(cls, sp, data, parser):
     return Artist(sp, {
         'name': data.get('name'),
         'gid': Uri.from_uri(data.get('uri')).to_gid(),
         'portrait': [
             {
                 'imageUri': data.get('imageUri')
             }
         ]
     }, parser.MercuryJSON, parser)
Пример #10
0
    def parse(cls, sp, data, parser):
        if type(data) is not dict:
            data = etree_convert(data)

        return Image(sp, {
            'file_id': Uri.from_id('image', data.get('file_id')).to_gid(size=40),
            'size': convert(data.get('size'), long),

            'width': convert(data.get('width'), long),
            'height': convert(data.get('height'), long)
        }, parser.XML, parser)
Пример #11
0
    def parse(cls, sp, data, parser):
        if type(data) is not dict:
            data = etree_convert(data)

        return Playlist(sp, {
            'uri': Uri.from_uri(data.get('uri')),
            'attributes': {
                'name': data.get('name')
            },
            'image': data.get('image')
        }, parser.XML, parser)
Пример #12
0
    def reply_mercury_json(self, data):
        self.response_type = Parser.MercuryJSON

        if self.multi is None:
            self.multi = True

        data = json.loads(data)

        for item in data:
            uri = Uri.from_uri(item.get('uri'))
            yield uri.type, item
Пример #13
0
    def reply_mercury_json(self, data):
        self.response_type = Parser.MercuryJSON

        if self.multi is None:
            self.multi = True

        data = json.loads(data)

        for item in data:
            uri = Uri.from_uri(item.get('uri'))
            yield uri.type, item
Пример #14
0
    def parse(cls, sp, data, parser):
        image = data.get('image')

        if not image:
            return None

        image_id = image[image.rfind('/') + 1:]

        return Image(sp, {
            'file_id': Uri.from_id('image', image_id).to_gid(size=40),
            'size': 0
        }, parser.Tunigo, parser)
Пример #15
0
    def parse(cls, sp, data, parser):
        image_uri = data.get('imageUri')

        if not image_uri:
            return None

        image_id = image_uri[image_uri.rfind('/') + 1:]

        return Image(sp, {
            'file_id': Uri.from_id('image', image_id).to_gid(size=40),
            'size': 0
        }, parser.MercuryJSON, parser)
Пример #16
0
    def parse(cls, sp, data, parser):
        if type(data) is not dict:
            data = etree_convert(data)

        return Playlist(
            sp, {
                'uri': Uri.from_uri(data.get('uri')),
                'attributes': {
                    'name': data.get('name')
                },
                'image': data.get('image')
            }, parser.XML, parser)
Пример #17
0
    def playlists(self, username, start=0, count=100, callback=None):
        if count > 100:
            raise ValueError("You may only request up to 100 playlists at once")

        request = HermesRequest(self.sp, {
            'method': 'GET',
            'uri': 'hm://playlist/user/%s/rootlist?from=%s&length=%s' % (self.uri_quote(username), start, count)
        }, Playlist, defaults={
            'uri': Uri.from_uri('spotify:user:%s:rootlist' % username)
        })

        return self.request_wrapper(request, callback)
Пример #18
0
    def playlists(self, username, start=0, count=100, callback=None):
        if count > 100:
            raise ValueError("You may only request up to 100 playlists at once")

        request = HermesRequest(self.sp, {
            'method': 'GET',
            'uri': 'hm://playlist/user/%s/rootlist?from=%s&length=%s' % (self.uri_quote(username), start, count)
        }, Playlist, defaults={
            'uri': Uri.from_uri('spotify:user:%s:rootlist' % username)
        })

        return self.request_wrapper(request, callback)
Пример #19
0
    def parse(cls, sp, data, parser):
        image_uri = data.get('imageUri')

        if not image_uri:
            return None

        image_id = image_uri[image_uri.rfind('/') + 1:]

        return Image(sp, {
            'file_id': Uri.from_id('image', image_id).to_gid(size=40),
            'size': 0
        }, parser.MercuryJSON, parser)
Пример #20
0
    def parse(cls, sp, data, parser):
        image = data.get('image')

        if not image:
            return None

        image_id = image[image.rfind('/') + 1:]

        return Image(sp, {
            'file_id': Uri.from_id('image', image_id).to_gid(size=40),
            'size': 0
        }, parser.Tunigo, parser)
Пример #21
0
    def parse(cls, sp, data, parser):
        image_uri = None

        if data.get('image'):
            image_uri = 'spotify:image:' + data.get('image')

        return Playlist(sp, {
            'uri': Uri.from_uri(data.get('uri')),
            'attributes': {
                'name': data.get('title')
            },
            'image': image_uri
        }, parser.Tunigo, parser)
Пример #22
0
    def playlist(self, uri, start=0, count=100, callback=None):
        if type(uri) is Uri:
            uri = str(uri)

        parts = [self.uri_quote(p) for p in uri.split(':')]

        request = HermesRequest(self.sp, {
            'method': 'GET',
            'uri': 'hm://playlist/%s?from=%s&length=%s' % ('/'.join(parts[1:]), start, count)
        }, Playlist, defaults={
            'uri': Uri.from_uri(uri)
        })

        return self.request_wrapper(request, callback)
Пример #23
0
    def parse(cls, sp, data, parser):
        image_uri = None

        if data.get('image'):
            image_uri = 'spotify:image:' + data.get('image')

        return Playlist(
            sp, {
                'uri': Uri.from_uri(data.get('uri')),
                'attributes': {
                    'name': data.get('title')
                },
                'image': image_uri
            }, parser.Tunigo, parser)
Пример #24
0
    def playlist(self, uri, start=0, count=100, callback=None):
        if type(uri) is Uri:
            uri = str(uri)

        parts = [self.uri_quote(p) for p in uri.split(":")]

        request = HermesRequest(
            self.sp,
            {"method": "GET", "uri": "hm://playlist/%s?from=%s&length=%s" % ("/".join(parts[1:]), start, count)},
            Playlist,
            defaults={"uri": Uri.from_uri(uri)},
        )

        return self.request_wrapper(request, callback)
Пример #25
0
    def parse(cls, sp, data, parser):
        if type(data) is not dict:
            data = etree_convert(data)

        uri = Uri.from_id('artist', data.get('id'))

        return Artist(sp, {
            'gid': uri.to_gid(),
            'uri': uri,
            'name': data.get('name'),
            'portrait': cls.get_portraits(data),
            'popularity': float(data.get('popularity')) if data.get('popularity') else None,
            'restriction': data.get('restrictions')
        }, parser.XML, parser)
Пример #26
0
    def playlist(self, uri, start=0, count=100, callback=None):
        if type(uri) is Uri:
            uri = str(uri)

        parts = [self.uri_quote(p) for p in uri.split(':')]

        request = HermesRequest(self.sp, {
            'method': 'GET',
            'uri': 'hm://playlist/%s?from=%s&length=%s' % ('/'.join(parts[1:]), start, count)
        }, Playlist, defaults={
            'uri': Uri.from_uri(uri)
        })

        return self.request_wrapper(request, callback)
Пример #27
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
Пример #28
0
    def playlists(self, username, start=0, count=100, callback=None):
        if count > 100:
            raise ValueError("You may only request up to 100 playlists at once")

        request = HermesRequest(
            self.sp,
            {
                "method": "GET",
                "uri": "hm://playlist/user/%s/rootlist?from=%s&length=%s" % (self.uri_quote(username), start, count),
            },
            Playlist,
            defaults={"uri": Uri.from_uri("spotify:user:%s:rootlist" % username)},
        )

        return self.request_wrapper(request, callback)
Пример #29
0
    def parse(cls, sp, data, parser):
        if type(data) is not dict:
            data = etree_convert(data)

        return Image(
            sp, {
                'file_id':
                Uri.from_id('image', data.get('file_id')).to_gid(size=40),
                'size':
                convert(data.get('size'), long),
                'width':
                convert(data.get('width'), long),
                'height':
                convert(data.get('height'), long)
            }, parser.XML, parser)
Пример #30
0
 def parse(cls, sp, data, parser):
     return Album(sp, {
         'gid': Uri.from_uri(data.get('uri')).to_gid(),
         'name': data.get('albumName'),
         'artist': [
             {
                 'artistName': data.get('artistName')
             }
         ],
         'cover': [
             {
                 'image': data.get('image')
             }
         ],
     }, parser.Tunigo, parser)
Пример #31
0
 def parse(cls, sp, data, parser):
     return Album(sp, {
         'name': data.get('name'),
         'gid': Uri.from_uri(data.get('uri')).to_gid(),
         'artist': [
             {
                 'uri': data.get('artistUri'),
                 'name': data.get('artistName')
             }
         ],
         'cover': [
             {
                 'imageUri': data.get('imageUri'),
             }
         ]
     }, parser.MercuryJSON, parser)
Пример #32
0
    def parse(cls, sp, data, parser):
        if type(data) is not dict:
            data = etree_convert(data, {'artist-id': ('artist-id', 'artist')})

        uri = Uri.from_id('track', data.get('id'))

        return Track(
            sp,
            {
                'gid':
                uri.to_gid(),
                'uri':
                uri,
                'name':
                data.get('title'),
                'artist': [{
                    '$source': 'node',
                    'id': artist.get('artist-id'),
                    'name': artist.get('artist')
                } for artist in data.get('artist', [])],
                'album': {
                    '$source': 'node',
                    'id': data.get('album-id'),
                    'name': data.get('album'),
                    'artist-id': data.get('album-artist-id'),
                    'artist-name': data.get('album-artist'),
                    'cover': data.get('cover'),
                    'cover-small': data.get('cover-small'),
                    'cover-large': data.get('cover-large'),
                },

                # TODO year
                'number':
                int(data.get('track-number')),
                'duration':
                int(data.get('length')),
                'popularity':
                float(data.get('popularity')),
                'external_id':
                data.get('external-ids'),
                'restriction':
                data.get('restrictions'),
                'file':
                data.get('files')
            },
            parser.XML,
            parser)
Пример #33
0
    def parse(cls, sp, data, parser):
        if type(data) is not dict:
            data = etree_convert(data, {
                'artist-id': ('artist-id', 'artist')
            })

        uri = Uri.from_id('track', data.get('id'))

        return Track(sp, {
            'gid': uri.to_gid(),
            'uri': uri,
            'name': data.get('title'),

            'artist': [
                {
                    '$source': 'node',
                    'id': artist.get('artist-id'),
                    'name': artist.get('artist')
                }
                for artist in data.get('artist', [])
            ],

            'album': {
                '$source': 'node',
                'id': data.get('album-id'),
                'name': data.get('album'),

                'artist-id': data.get('album-artist-id'),
                'artist-name': data.get('album-artist'),

                'cover': data.get('cover'),
                'cover-small': data.get('cover-small'),
                'cover-large': data.get('cover-large'),
                },

            # TODO year
            'number': int(data.get('track-number')),
            'duration': int(data.get('length')),

            'popularity': float(data.get('popularity')),

            'external_id': data.get('external-ids'),
            'restriction': data.get('restrictions'),
            'file': data.get('files')
        }, parser.XML, parser)
Пример #34
0
    def list(self, group=None, flat=False):
        if group:
            # Pull the code from a group URI
            parts = group.split(':')
            group = parts[2] if len(parts) == 4 else group

        path = []

        for item in self.items:
            if item.uri.type == 'start-group':
                # Ignore groups if we are returning a flat list
                if flat:
                    continue

                # Only return placeholders on the root level
                if (not group and not path) or (path and path[-1] == group):
                    # Return group placeholder
                    yield PlaylistItem(self.sp).dict_update({
                        'uri':
                        Uri.from_uri('spotify:group:%s:%s' %
                                     (item.uri.code, item.uri.title)),
                        'name':
                        item.uri.title
                    })

                path.append(item.uri.code)
                continue
            elif item.uri.type == 'end-group':
                # Group close tag
                if path and path.pop() == group:
                    return

                continue

            if group is None:
                # Ignore if we are inside a group
                if path and not flat:
                    continue
            else:
                # Ignore if we aren't inside the specified group
                if not path or path[-1] != group:
                    continue

            # Return item
            yield item
Пример #35
0
    def list(self, group=None, flat=False):
        if group:
            # Pull the code from a group URI
            parts = group.split(':')
            group = parts[2] if len(parts) == 4 else group

        path = []

        for item in self.items:
            if item.uri.type == 'start-group':
                # Ignore groups if we are returning a flat list
                if flat:
                    continue

                # Only return placeholders on the root level
                if (not group and not path) or (path and path[-1] == group):
                    # Return group placeholder
                    yield PlaylistItem(self.sp).dict_update({
                        'uri': Uri.from_uri('spotify:group:%s:%s' % (item.uri.code, item.uri.title)),
                        'name': item.uri.title
                    })

                path.append(item.uri.code)
                continue
            elif item.uri.type == 'end-group':
                # Group close tag
                if path and path.pop() == group:
                    return

                continue

            if group is None:
                # Ignore if we are inside a group
                if path and not flat:
                    continue
            else:
                # Ignore if we aren't inside the specified group
                if not path or path[-1] != group:
                    continue

            # Return item
            yield item
Пример #36
0
    def parse(cls, sp, data, parser):
        if type(data) is not dict:
            data = etree_convert(data)

        return Album(sp, {
            'gid': Uri.from_id('album', data.get('id')).to_gid(),
            'name': data.get('name'),
            'artist': [
                {
                    '$source': 'node',
                    'id': data.get('artist-id'),
                    'name': data.get('artist-name')
                }
            ],
            'type': cls.get_type(data.get('album-type')),
            'cover': cls.get_covers(data),
            'popularity': convert(data.get('popularity'), float),
            'restriction': data.get('restrictions'),
            'external_id': data.get('external-ids')
        }, parser.XML, parser)
Пример #37
0
    def parse(cls, sp, data, parser):
        if type(data) is not dict:
            data = etree_convert(data)

        uri = Uri.from_id('artist', data.get('id'))

        return Artist(
            sp, {
                'gid':
                uri.to_gid(),
                'uri':
                uri,
                'name':
                data.get('name'),
                'portrait':
                cls.get_portraits(data),
                'popularity':
                float(data.get('popularity'))
                if data.get('popularity') else None,
                'restriction':
                data.get('restrictions')
            }, parser.XML, parser)
Пример #38
0
    def get(self, uris, callback=None):
        log.debug("metadata(%s)", uris)

        multi = type(uris) is list

        if type(uris) is not list:
            uris = [uris]

        # array of "request" Objects that will be protobuf'd
        requests = []
        h_type = ""

        for uri in uris:
            if type(uri) is not Uri:
                uri = Uri.from_uri(uri)

            if uri.type == "local":
                log.debug('ignoring "local" track URI: %s', uri)
                continue

            h_type = uri.type

            requests.append({"method": "GET", "uri": "hm://metadata/%s/%s" % (uri.type, uri.to_id())})

        # Build ProtoRequest
        request = HermesRequest(
            self.sp,
            requests,
            {
                "vnd.spotify/metadata-artist": Artist,
                "vnd.spotify/metadata-album": Album,
                "vnd.spotify/metadata-track": Track,
            },
            {"method": "GET", "uri": "hm://metadata/%ss" % h_type},
            container="objects",
            multi=multi,
        )

        return self.request_wrapper(request, callback)
Пример #39
0
    def get(self, uris, callback=None):
        log.debug('metadata(%s)', uris)

        multi = type(uris) is list

        if type(uris) is not list:
            uris = [uris]

        # array of "request" Objects that will be protobuf'd
        requests = []
        h_type = ''

        for uri in uris:
            if type(uri) is not Uri:
                uri = Uri.from_uri(uri)

            if uri.type == 'local':
                log.debug('ignoring "local" track URI: %s', uri)
                continue

            h_type = uri.type

            requests.append({
                'method': 'GET',
                'uri': 'hm://metadata/%s/%s' % (uri.type, uri.to_id())
            })

        # Build ProtoRequest
        request = HermesRequest(self.sp, requests, {
            'vnd.spotify/metadata-artist': Artist,
            'vnd.spotify/metadata-album': Album,
            'vnd.spotify/metadata-track': Track
        }, {
            'method': 'GET',
            'uri': 'hm://metadata/%ss' % h_type
        }, multi=multi)

        return self.request_wrapper(request, callback)
Пример #40
0
    def get(self, uris, callback=None):
        log.debug('metadata(%s)', uris)

        multi = type(uris) is list

        if type(uris) is not list:
            uris = [uris]

        # array of "request" Objects that will be protobuf'd
        requests = []
        h_type = ''

        for uri in uris:
            if type(uri) is not Uri:
                uri = Uri.from_uri(uri)

            if uri.type == 'local':
                log.debug('ignoring "local" track URI: %s', uri)
                continue

            h_type = uri.type

            requests.append({
                'method': 'GET',
                'uri': 'hm://metadata/%s/%s' % (uri.type, uri.to_id())
            })

        # Build ProtoRequest
        request = HermesRequest(self.sp, requests, {
            'vnd.spotify/metadata-artist': Artist,
            'vnd.spotify/metadata-album': Album,
            'vnd.spotify/metadata-track': Track
        }, {
            'method': 'GET',
            'uri': 'hm://metadata/%ss' % h_type
        }, container='objects', multi=multi)

        return self.request_wrapper(request, callback)
Пример #41
0
    def parse(cls, sp, data, parser):
        if type(data) is not dict:
            data = etree_convert(data, {"artist-id": ("artist-id", "artist")})

        uri = Uri.from_id("track", data.get("id"))

        return Track(
            sp,
            {
                "gid": uri.to_gid(),
                "uri": uri,
                "name": data.get("title"),
                "artist": [
                    {"$source": "node", "id": artist.get("artist-id"), "name": artist.get("artist")}
                    for artist in data.get("artist", [])
                ],
                "album": {
                    "$source": "node",
                    "id": data.get("album-id"),
                    "name": data.get("album"),
                    "artist-id": data.get("album-artist-id"),
                    "artist-name": data.get("album-artist"),
                    "cover": data.get("cover"),
                    "cover-small": data.get("cover-small"),
                    "cover-large": data.get("cover-large"),
                },
                # TODO year
                "number": int(data.get("track-number")),
                "duration": int(data.get("length")),
                "popularity": float(data.get("popularity")),
                "external_id": data.get("external-ids"),
                "restriction": data.get("restrictions"),
                "file": data.get("files"),
            },
            parser.XML,
            parser,
        )
Пример #42
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
        )
Пример #43
0
 def from_id(cls, id):
     return cls(None, {
         'file_id': Uri.from_id('image', id).to_gid(size=40),
         'size': 3
     })
Пример #44
0
 def from_id(cls, id):
     return cls(None, {
         'file_id': Uri.from_id('image', id).to_gid(size=40),
         'size': 3
     })