Source code for spotify.config

from __future__ import unicode_literals

import spotify
from spotify import ffi, utils
from spotify.session import _SessionCallbacks

__all__ = ["Config"]


[docs]class Config(object): """The session config. Create an instance and assign to its attributes to configure. Then use the config object to create a session:: >>> config = spotify.Config() >>> config.user_agent = 'My awesome Spotify client' >>> # Etc ... >>> session = spotify.Session(config=config) """ 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 self.device_id = None self.proxy = None self.proxy_username = None self.proxy_password = None self.ca_certs_filename = None self.tracefile = None @property def api_version(self): """The API version of the libspotify we're using. You should not need to change this. It defaults to the value provided by libspotify through :func:`spotify.get_libspotify_api_version`. """ return self._sp_session_config.api_version @api_version.setter def api_version(self, value): self._sp_session_config.api_version = value @property def cache_location(self): """A location for libspotify to cache files. Defaults to ``tmp`` in the current working directory. Must be a bytestring. Cannot be shared with other Spotify apps. Can only be used by one session at the time. Optimally, you should use a lock file or similar to ensure this. """ return utils.to_bytes(self._sp_session_config.cache_location) @cache_location.setter def cache_location(self, value): # NOTE libspotify segfaults if cache_location is set to NULL, thus we # convert None to empty string. self._cache_location = utils.to_char("" if value is None else value) self._sp_session_config.cache_location = self._cache_location @property def settings_location(self): """A location for libspotify to save settings. Defaults to ``tmp`` in the current working directory. Must be a bytestring. Cannot be shared with other Spotify apps. Can only be used by one session at the time. Optimally, you should use a lock file or similar to ensure this. """ return utils.to_bytes(self._sp_session_config.settings_location) @settings_location.setter def settings_location(self, value): self._settings_location = utils.to_char("" if value is None else value) self._sp_session_config.settings_location = self._settings_location @property def application_key(self): """Your libspotify application key. Must be a bytestring. Alternatively, you can call :meth:`load_application_key_file`, and pyspotify will correctly read the file into :attr:`application_key`. """ return utils.to_bytes_or_none( ffi.cast("char *", self._sp_session_config.application_key) ) @application_key.setter def application_key(self, value): if value is None: size = 0 else: size = len(value) assert size in (0, 321), ( "Invalid application key; expected 321 bytes, got %d bytes" % size ) self._application_key = utils.to_char_or_null(value) self._sp_session_config.application_key = ffi.cast( "void *", self._application_key ) self._sp_session_config.application_key_size = size def load_application_key_file(self, filename=b"spotify_appkey.key"): """Load your libspotify application key file. If called without arguments, it tries to read ``spotify_appkey.key`` from the current working directory. This is an alternative to setting :attr:`application_key` yourself. The file must be a binary key file, not the C code key file that can be compiled into an application. """ with open(filename, "rb") as fh: self.application_key = fh.read() @property def user_agent(self): """A string with the name of your client. Defaults to ``pyspotify 2.x.y``. """ return utils.to_unicode(self._sp_session_config.user_agent) @user_agent.setter def user_agent(self, value): self._user_agent = utils.to_char("" if value is None else value) self._sp_session_config.user_agent = self._user_agent @property def compress_playlists(self): """Compress local copy of playlists, reduces disk space usage. Defaults to :class:`False`. """ return bool(self._sp_session_config.compress_playlists) @compress_playlists.setter def compress_playlists(self, value): self._sp_session_config.compress_playlists = bool(value) @property def dont_save_metadata_for_playlists(self): """Don't save metadata for local copies of playlists. Defaults to :class:`False`. Reduces disk space usage at the expense of needing to request metadata from Spotify backend when loading list. """ return bool(self._sp_session_config.dont_save_metadata_for_playlists) @dont_save_metadata_for_playlists.setter def dont_save_metadata_for_playlists(self, value): self._sp_session_config.dont_save_metadata_for_playlists = bool(value) @property def initially_unload_playlists(self): """Avoid loading playlists into RAM on startup. Defaults to :class:`False`. See :meth:`Playlist.in_ram` for more details. """ return bool(self._sp_session_config.initially_unload_playlists) @initially_unload_playlists.setter def initially_unload_playlists(self, value): self._sp_session_config.initially_unload_playlists = bool(value) @property def device_id(self): """Device ID for offline synchronization and logging purposes. Defaults to :class:`None`. The Device ID must be unique to the particular device instance, i.e. no two units must supply the same Device ID. The Device ID must not change between sessions or power cycles. Good examples is the device's MAC address or unique serial number. Setting the device ID to an empty string has the same effect as setting it to :class:`None`. """ return utils.to_unicode_or_none(self._sp_session_config.device_id) @device_id.setter def device_id(self, value): # NOTE libspotify segfaults if device_id is set to an empty string, # thus we convert empty strings to NULL. self._device_id = utils.to_char_or_null(value or None) self._sp_session_config.device_id = self._device_id @property def proxy(self): """URL to the proxy server that should be used. Defaults to :class:`None`. The format is protocol://host:port where protocol is http/https/socks4/socks5. """ return utils.to_unicode(self._sp_session_config.proxy) or None @proxy.setter def proxy(self, value): # NOTE libspotify reuses cached values from previous sessions if this # is set to NULL, thus we convert None to empty string. self._proxy = utils.to_char_or_null("" if value is None else value) self._sp_session_config.proxy = self._proxy @property def proxy_username(self): """Username to authenticate with proxy server. Defaults to :class:`None`. """ return utils.to_unicode(self._sp_session_config.proxy_username) or None @proxy_username.setter def proxy_username(self, value): # NOTE libspotify reuses cached values from previous sessions if this # is set to NULL, thus we convert None to empty string. self._proxy_username = utils.to_char("" if value is None else value) self._sp_session_config.proxy_username = self._proxy_username @property def proxy_password(self): """Password to authenticate with proxy server. Defaults to :class:`None`. """ return utils.to_unicode(self._sp_session_config.proxy_password) or None @proxy_password.setter def proxy_password(self, value): # NOTE libspotify reuses cached values from previous sessions if this # is set to NULL, thus we convert None to empty string. self._proxy_password = utils.to_char("" if value is None else value) self._sp_session_config.proxy_password = self._proxy_password @property def ca_certs_filename(self): """Path to a file containing the root CA certificates that HTTPS servers should be verified with. Defaults to :class:`None`. Must be a bytestring file path otherwise. This is not used for verifying Spotify's servers, but may be used for verifying third parties' HTTPS servers, like the Last.fm servers if you scrobbling the music you listen to through libspotify. libspotify for macOS use other means for communicating with HTTPS servers and ignores this configuration. The file must be a concatenation of all certificates in PEM format. Provided with libspotify is a sample PEM file in the ``examples/`` dir. It is recommended that the application export a similar file from the local certificate store. On Linux systems, the certificate store is often found at :file:`/etc/ssl/certs/ca-certificates.crt` or :file:`/etc/ssl/certs/ca-bundle.crt` """ ptr = self._get_ca_certs_filename_ptr() if ptr is not None: return utils.to_bytes_or_none(ptr[0]) else: return None @ca_certs_filename.setter def ca_certs_filename(self, value): ptr = self._get_ca_certs_filename_ptr() if ptr is not None: self._ca_certs_filename = utils.to_char_or_null(value) ptr[0] = self._ca_certs_filename def _get_ca_certs_filename_ptr(self): # XXX This function does pointer arithmetic based on the assumption # that if the ca_certs_filename field exists in sp_session_config on # the current platform, it will reside between the proxy_password and # tracefile fields. # # If CFFI supported #ifdef we could make this exact # science by including ca_certs_filename field in the sp_session_config # struct only if the SP_WITH_CURL macro is defined, ref. the # sp_session_create example in the libspotify docs. proxy_password_ptr = spotify.ffi.addressof( self._sp_session_config, "proxy_password" ) tracefile_ptr = spotify.ffi.addressof(self._sp_session_config, "tracefile") if tracefile_ptr - proxy_password_ptr != 2: return None return proxy_password_ptr + 1 @property def tracefile(self): """Path to API trace file. Defaults to :class:`None`. Must be a bytestring otherwise. """ return utils.to_bytes_or_none(self._sp_session_config.tracefile) @tracefile.setter def tracefile(self, value): # NOTE libspotify does not consider empty string as unset, and will try # to open the file "" and fail with a "LibError: Unable to open trace # file", thus we convert empty string to NULL. self._tracefile = utils.to_char_or_null(value or None) self._sp_session_config.tracefile = self._tracefile