Exemple #1
0
 def is_scrobbling(self, social_provider):
     """Get the :class:`ScrobblingState` for the given
     ``social_provider``."""
     scrobbling_state = ffi.new('sp_scrobbling_state *')
     spotify.Error.maybe_raise(lib.sp_session_is_scrobbling(
         self._session._sp_session, social_provider, scrobbling_state))
     return spotify.ScrobblingState(scrobbling_state[0])
Exemple #2
0
 def is_scrobbling_possible(self, social_provider):
     """Check if the scrobbling settings should be shown to the user."""
     out = ffi.new('bool *')
     spotify.Error.maybe_raise(
         lib.sp_session_is_scrobbling_possible(self._session._sp_session,
                                               social_provider, out))
     return bool(out[0])
Exemple #3
0
    def __init__(self, config=None):
        super(Session, self).__init__()

        if spotify._session_instance is not None:
            raise RuntimeError('Session has already been initialized')

        if config is not None:
            self.config = config
        else:
            self.config = spotify.Config()

        if self.config.application_key is None:
            self.config.load_application_key_file()

        sp_session_ptr = ffi.new('sp_session **')

        spotify.Error.maybe_raise(lib.sp_session_create(
            self.config._sp_session_config, sp_session_ptr))

        self._sp_session = ffi.gc(sp_session_ptr[0], lib.sp_session_release)

        self._cache = weakref.WeakValueDictionary()
        self._emitters = []
        self._callback_handles = set()

        self.connection = spotify.connection.Connection(self)
        self.offline = spotify.offline.Offline(self)
        self.player = spotify.player.Player(self)
        self.social = spotify.social.Social(self)
        spotify._session_instance = self
Exemple #4
0
 def as_track_offset(self):
     """Get the track offset in milliseconds from the link."""
     offset = ffi.new('int *')
     sp_track = lib.sp_link_as_track_and_offset(self._sp_link, offset)
     if sp_track == ffi.NULL:
         return None
     return offset[0]
Exemple #5
0
 def as_track_offset(self):
     """Get the track offset in milliseconds from the link."""
     offset = ffi.new('int *')
     sp_track = lib.sp_link_as_track_and_offset(self._sp_link, offset)
     if sp_track == ffi.NULL:
         return None
     return offset[0]
 def get_struct(cls):
     return ffi.new('sp_playlistcontainer_callbacks *', {
         'playlist_added': cls.playlist_added,
         'playlist_removed': cls.playlist_removed,
         'playlist_moved': cls.playlist_moved,
         'container_loaded': cls.container_loaded,
     })
Exemple #7
0
    def __init__(self, config=None):
        super(Session, self).__init__()

        if spotify._session_instance is not None:
            raise RuntimeError('Session has already been initialized')

        if config is not None:
            self.config = config
        else:
            self.config = spotify.Config()

        if self.config.application_key is None:
            self.config.load_application_key_file()

        sp_session_ptr = ffi.new('sp_session **')

        spotify.Error.maybe_raise(
            lib.sp_session_create(self.config._sp_session_config,
                                  sp_session_ptr))

        self._sp_session = ffi.gc(sp_session_ptr[0], lib.sp_session_release)

        self._cache = weakref.WeakValueDictionary()
        self._emitters = []
        self._callback_handles = set()

        self.connection = spotify.connection.Connection(self)
        self.offline = spotify.offline.Offline(self)
        self.player = spotify.player.Player(self)
        self.social = spotify.social.Social(self)
        spotify._session_instance = self
Exemple #8
0
 def get_struct(cls):
     return ffi.new(
         'sp_session_callbacks *', {
             'logged_in': cls.logged_in,
             'logged_out': cls.logged_out,
             'metadata_updated': cls.metadata_updated,
             'connection_error': cls.connection_error,
             'message_to_user': cls.message_to_user,
             'notify_main_thread': cls.notify_main_thread,
             'music_delivery': cls.music_delivery,
             'play_token_lost': cls.play_token_lost,
             'log_message': cls.log_message,
             'end_of_track': cls.end_of_track,
             'streaming_error': cls.streaming_error,
             'userinfo_updated': cls.user_info_updated,
             'start_playback': cls.start_playback,
             'stop_playback': cls.stop_playback,
             'get_audio_buffer_stats': cls.get_audio_buffer_stats,
             'offline_status_updated': cls.offline_status_updated,
             'credentials_blob_updated': cls.credentials_blob_updated,
             'connectionstate_updated': cls.connection_state_updated,
             'scrobble_error': cls.scrobble_error,
             'private_session_mode_changed':
             cls.private_session_mode_changed,
         })
Exemple #9
0
 def starred(self, value):
     if spotify.session_instance is None:
         raise RuntimeError('Session must be initialized')
     tracks = ffi.new('sp_track *[]', 1)
     tracks[0] = self._sp_track
     spotify.Error.maybe_raise(
         lib.sp_track_set_starred(spotify.session_instance._sp_session,
                                  tracks, len(tracks), bool(value)))
Exemple #10
0
 def get_struct(cls):
     return ffi.new(
         'sp_playlistcontainer_callbacks *', {
             'playlist_added': cls.playlist_added,
             'playlist_removed': cls.playlist_removed,
             'playlist_moved': cls.playlist_moved,
             'container_loaded': cls.container_loaded,
         })
Exemple #11
0
 def is_scrobbling(self, social_provider):
     """Get the :class:`ScrobblingState` for the given
     ``social_provider``."""
     scrobbling_state = ffi.new('sp_scrobbling_state *')
     spotify.Error.maybe_raise(
         lib.sp_session_is_scrobbling(self._session._sp_session,
                                      social_provider, scrobbling_state))
     return spotify.ScrobblingState(scrobbling_state[0])
    def _get_more_tracks(self):
        self._sp_tracks_len = min(self._num_tracks, self._sp_tracks_len + self._BATCH_SIZE)
        self._sp_tracks = ffi.new("sp_track *[]", self._sp_tracks_len)
        self._num_tracks = lib.sp_playlistcontainer_get_unseen_tracks(
            self._sp_playlistcontainer, self._sp_playlist, self._sp_tracks, self._sp_tracks_len
        )

        if self._num_tracks < 0:
            raise spotify.Error("Failed to get unseen tracks for playlist")
    def _get_more_tracks(self):
        self._sp_tracks_len = min(self._num_tracks,
                                  self._sp_tracks_len + self._BATCH_SIZE)
        self._sp_tracks = ffi.new('sp_track *[]', self._sp_tracks_len)
        self._num_tracks = lib.sp_playlistcontainer_get_unseen_tracks(
            self._sp_playlistcontainer, self._sp_playlist, self._sp_tracks,
            self._sp_tracks_len)

        if self._num_tracks < 0:
            raise spotify.Error('Failed to get unseen tracks for playlist')
Exemple #14
0
    def sync_status(self):
        """The :class:`OfflineSyncStatus` or :class:`None` if not syncing.

        The :attr:`~SessionEvent.OFFLINE_STATUS_UPDATED` event is emitted on
        the session object when this is updated.
        """
        sp_offline_sync_status = ffi.new('sp_offline_sync_status *')
        syncing = lib.sp_offline_sync_get_status(
            self._session._sp_session, sp_offline_sync_status)
        if syncing:
            return spotify.OfflineSyncStatus(sp_offline_sync_status)
Exemple #15
0
    def sync_status(self):
        """The :class:`OfflineSyncStatus` or :class:`None` if not syncing.

        The :attr:`~SessionEvent.OFFLINE_STATUS_UPDATED` event is emitted on
        the session object when this is updated.
        """
        sp_offline_sync_status = ffi.new('sp_offline_sync_status *')
        syncing = lib.sp_offline_sync_get_status(self._session._sp_session,
                                                 sp_offline_sync_status)
        if syncing:
            return spotify.OfflineSyncStatus(sp_offline_sync_status)
Exemple #16
0
def get_with_fixed_buffer(buffer_length, func, *args):
    """Get a unicode string from a C function that takes a fixed-size buffer.

    The C function ``func`` is called with any arguments given in ``args``, a
    buffer of the given ``buffer_length``, and ``buffer_length``.

    Returns the buffer's value decoded from UTF-8 to a unicode string.
    """
    func = functools.partial(func, *args)
    buffer_ = ffi.new('char[]', buffer_length)
    func(buffer_, buffer_length)
    return to_unicode(buffer_)
Exemple #17
0
    def data(self):
        """The raw image data as a bytestring.

        Will always return :class:`None` if the image isn't loaded.
        """
        if not self.is_loaded:
            return None
        data_size_ptr = ffi.new("size_t *")
        data = lib.sp_image_data(self._sp_image, data_size_ptr)
        buffer_ = ffi.buffer(data, data_size_ptr[0])
        data_bytes = buffer_[:]
        assert len(data_bytes) == data_size_ptr[0], "%r == %r" % (len(data_bytes), data_size_ptr[0])
        return data_bytes
Exemple #18
0
    def __init__(self):
        self._sp_session_callbacks = _SessionCallbacks.get_struct()
        self._sp_session_config = ffi.new('sp_session_config *', {
            'callbacks': self._sp_session_callbacks,
        })

        # Defaults
        self.api_version = spotify.get_libspotify_api_version()
        self.cache_location = b'tmp'
        self.settings_location = b'tmp'
        self.user_agent = 'pyspotify %s' % spotify.__version__
        self.compress_playlists = False
        self.dont_save_metadata_for_playlists = False
        self.initially_unload_playlists = False
Exemple #19
0
    def data(self):
        """The raw image data as a bytestring.

        Will always return :class:`None` if the image isn't loaded.
        """
        if not self.is_loaded:
            return None
        data_size_ptr = ffi.new('size_t *')
        data = lib.sp_image_data(self._sp_image, data_size_ptr)
        buffer_ = ffi.buffer(data, data_size_ptr[0])
        data_bytes = buffer_[:]
        assert len(data_bytes) == data_size_ptr[0], '%r == %r' % (
            len(data_bytes), data_size_ptr[0])
        return data_bytes
Exemple #20
0
    def __init__(self):
        self._sp_session_callbacks = _SessionCallbacks.get_struct()
        self._sp_session_config = ffi.new(
            'sp_session_config *', {
                'callbacks': self._sp_session_callbacks,
            })

        # Defaults
        self.api_version = spotify.get_libspotify_api_version()
        self.cache_location = b'tmp'
        self.settings_location = b'tmp'
        self.user_agent = 'pyspotify %s' % spotify.__version__
        self.compress_playlists = False
        self.dont_save_metadata_for_playlists = False
        self.initially_unload_playlists = False
 def get_struct(cls):
     return ffi.new('sp_playlist_callbacks *', {
         'tracks_added': cls.tracks_added,
         'tracks_removed': cls.tracks_removed,
         'tracks_moved': cls.tracks_moved,
         'playlist_renamed': cls.playlist_renamed,
         'playlist_state_changed': cls.playlist_state_changed,
         'playlist_update_in_progress': cls.playlist_update_in_progress,
         'playlist_metadata_updated': cls.playlist_metadata_updated,
         'track_created_changed': cls.track_created_changed,
         'track_seen_changed': cls.track_seen_changed,
         'description_changed': cls.description_changed,
         'image_changed': cls.image_changed,
         'track_message_changed': cls.track_message_changed,
         'subscribers_changed': cls.subscribers_changed,
     })
Exemple #22
0
    def process_events(self):
        """Process pending events in libspotify.

        This method must be called for most callbacks to be called. Without
        calling this method, you'll only get the callbacks that are called from
        internal libspotify threads. When the
        :attr:`~SessionEvent.NOTIFY_MAIN_THREAD` event is emitted (from an
        internal libspotify thread), it's your job to make sure this method is
        called (from the thread you use for accessing Spotify), so that further
        callbacks can be triggered (from the same thread).

        pyspotify provides an :class:`~spotify.EventLoop` that you can use for
        processing events when needed.
        """
        next_timeout = ffi.new('int *')

        spotify.Error.maybe_raise(
            lib.sp_session_process_events(self._sp_session, next_timeout))

        return next_timeout[0]
Exemple #23
0
    def process_events(self):
        """Process pending events in libspotify.

        This method must be called for most callbacks to be called. Without
        calling this method, you'll only get the callbacks that are called from
        internal libspotify threads. When the
        :attr:`~SessionEvent.NOTIFY_MAIN_THREAD` event is emitted (from an
        internal libspotify thread), it's your job to make sure this method is
        called (from the thread you use for accessing Spotify), so that further
        callbacks can be triggered (from the same thread).

        pyspotify provides an :class:`~spotify.EventLoop` that you can use for
        processing events when needed.
        """
        next_timeout = ffi.new('int *')

        spotify.Error.maybe_raise(lib.sp_session_process_events(
            self._sp_session, next_timeout))

        return next_timeout[0]
    def image(self, callback=None):
        """The playlist's :class:`Image`.

        Due to limitations in libspotify's API you can't specify the
        :class:`ImageSize` of these images.

        If ``callback`` isn't :class:`None`, it is expected to be a callable
        that accepts a single argument, an :class:`Image` instance, when
        the image is done loading.

        Will always return :class:`None` if the playlist isn't loaded or the
        playlist has no image.
        """
        image_id = ffi.new('char[20]')
        has_image = bool(
            lib.sp_playlist_get_image(self._sp_playlist, image_id))
        if not has_image:
            return None
        sp_image = lib.sp_image_create(self._session._sp_session, image_id)
        return spotify.Image(
            self._session, sp_image=sp_image, add_ref=False, callback=callback)
Exemple #25
0
def get_with_growing_buffer(func, *args):
    """Get a unicode string from a C function that returns the buffer size
    needed to return the full string.

    The C function ``func`` is called with any arguments given in ``args``, a
    buffer of fixed size, and the buffer size. If the C function returns a
    size that is larger than the buffer already filled, the C function is
    called again with a buffer large enough to get the full string from the C
    function.

    Returns the buffer's value decoded from UTF-8 to a unicode string.
    """
    func = functools.partial(func, *args)
    actual_length = 10
    buffer_length = actual_length
    while actual_length >= buffer_length:
        buffer_length = actual_length + 1
        buffer_ = ffi.new('char[]', buffer_length)
        actual_length = func(buffer_, buffer_length)
    if actual_length == -1:
        return None
    return to_unicode(buffer_)
Exemple #26
0
 def get_struct(cls):
     return ffi.new('sp_session_callbacks *', {
         'logged_in': cls.logged_in,
         'logged_out': cls.logged_out,
         'metadata_updated': cls.metadata_updated,
         'connection_error': cls.connection_error,
         'message_to_user': cls.message_to_user,
         'notify_main_thread': cls.notify_main_thread,
         'music_delivery': cls.music_delivery,
         'play_token_lost': cls.play_token_lost,
         'log_message': cls.log_message,
         'end_of_track': cls.end_of_track,
         'streaming_error': cls.streaming_error,
         'userinfo_updated': cls.user_info_updated,
         'start_playback': cls.start_playback,
         'stop_playback': cls.stop_playback,
         'get_audio_buffer_stats': cls.get_audio_buffer_stats,
         'offline_status_updated': cls.offline_status_updated,
         'credentials_blob_updated': cls.credentials_blob_updated,
         'connectionstate_updated': cls.connection_state_updated,
         'scrobble_error': cls.scrobble_error,
         'private_session_mode_changed': cls.private_session_mode_changed,
     })
Exemple #27
0
def to_char(value):
    """Converts bytes, unicode, and C char arrays to C char arrays.  """
    return ffi.new('char[]', to_bytes(value))
Exemple #28
0
 def is_scrobbling_possible(self, social_provider):
     """Check if the scrobbling settings should be shown to the user."""
     out = ffi.new('bool *')
     spotify.Error.maybe_raise(lib.sp_session_is_scrobbling_possible(
         self._session._sp_session, social_provider, out))
     return bool(out[0])
Exemple #29
0
 def starred(self, value):
     tracks = ffi.new('sp_track *[]', 1)
     tracks[0] = self._sp_track
     spotify.Error.maybe_raise(lib.sp_track_set_starred(
         self._session._sp_session, tracks, len(tracks),
         bool(value)))
Exemple #30
0
 def starred(self, value):
     tracks = ffi.new('sp_track *[]', 1)
     tracks[0] = self._sp_track
     spotify.Error.maybe_raise(
         lib.sp_track_set_starred(self._session._sp_session, tracks,
                                  len(tracks), bool(value)))