#include <libgen.h> #include <pthread.h> #include <signal.h> #include <stdio.h> #include <stdint.h> #include <unistd.h> // The one and only entrypoint to the libspotify API #include <spotify/api.h> /* --- Functions --- */ extern void metadata_updated(sp_session *session); extern void session_ready(sp_session *session); extern void session_terminated(void); /* --- Data --- */ extern const uint8_t g_appkey[]; extern const size_t g_appkey_size; int g_exit_code = -1; static pthread_t g_main_thread = -1; /* ------------------------ BEGIN SESSION CALLBACKS ---------------------- */ static void connection_error(sp_session *session, sp_error error) { fprintf(stderr, "connection to Spotify failed: %s\n", sp_error_message(error)); g_exit_code = 5; } static void logged_in(sp_session *session, sp_error error) { if (SP_ERROR_OK != error) { fprintf(stderr, "failed to log in to Spotify: %s\n", sp_error_message(error)); g_exit_code = 4; return; } // Let us print the nice message... sp_user *me = sp_session_user(session); const char *my_name = (sp_user_is_loaded(me) ? sp_user_display_name(me) : sp_user_canonical_name(me)); printf("Logged in to Spotify as user %s\n", my_name); session_ready(session); } static void logged_out(sp_session *session) { if (g_exit_code < 0) g_exit_code = 0; } static void notify_main_thread(sp_session *session) { pthread_kill(g_main_thread, SIGIO); } static void log_message(sp_session *session, const char *data) { fprintf(stderr, "log_message: %s\n", data); } static sp_session_callbacks g_callbacks = { &logged_in, &logged_out, &metadata_updated, &connection_error, NULL, ¬ify_main_thread, NULL, NULL, &log_message }; /* ------------------------- END SESSION CALLBACKS ----------------------- */ static void loop(sp_session *session) { sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGIO); while (g_exit_code < 0) { int timeout = -1; pthread_sigmask(SIG_BLOCK, &sigset, NULL); sp_session_process_events(session, &timeout); pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); usleep(timeout * 1000); } } static void sigIgn(int signo) { } int main(int argc, char **argv) { sp_session_config config; sp_error error; sp_session *session; // Sending passwords on the command line is bad in general. // We do it here for brevity. if (argc < 3 || argv[1][0] == '-') { fprintf(stderr, "usage: %s <username> <password>\n", basename(argv[0])); return 1; } // Setup for waking up the main thread in notify_main_thread() g_main_thread = pthread_self(); signal(SIGIO, &sigIgn); // Always do this. It allows libspotify to check for // header/library inconsistencies. config.api_version = SPOTIFY_API_VERSION; // The path of the directory to store the cache. This must be specified. // Please read the documentation on preferred values. config.cache_location = "tmp"; // The path of the directory to store the settings. This must be specified. // Please read the documentation on preferred values. config.settings_location = "tmp"; // The key of the application. They are generated by Spotify, // and are specific to each application using libspotify. config.application_key = g_appkey; config.application_key_size = g_appkey_size; // This identifies the application using some // free-text string [1, 255] characters. config.user_agent = "spotify-session-example"; // Register the callbacks. config.callbacks = &g_callbacks; error = sp_session_init(&config, &session); if (SP_ERROR_OK != error) { fprintf(stderr, "failed to create session: %s\n", sp_error_message(error)); return 2; } // Login using the credentials given on the command line. error = sp_session_login(session, argv[1], argv[2]); if (SP_ERROR_OK != error) { fprintf(stderr, "failed to login: %s\n", sp_error_message(error)); return 3; } loop(session); session_terminated(); return 0; }