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 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])
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
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, })
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
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, })
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)))
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, })
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')
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)
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)
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_)
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
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 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
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, })
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 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)
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_)
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, })
def to_char(value): """Converts bytes, unicode, and C char arrays to C char arrays. """ return ffi.new('char[]', to_bytes(value))
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])
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)))
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)))