diff --git a/src/artwork.c b/src/artwork.c index 03bf2dfe..7ae53ed4 100644 --- a/src/artwork.c +++ b/src/artwork.c @@ -42,7 +42,7 @@ #include "artwork.h" #ifdef HAVE_SPOTIFY_H -# include "spotify_webapi.h" +# include "spotify.h" #endif /* This artwork module will look for artwork by consulting a set of sources one @@ -218,57 +218,6 @@ static struct artwork_source artwork_item_source[] = /* -------------------------------- HELPERS -------------------------------- */ -/* Reads an artwork file from the given url straight into an evbuf - * - * @out evbuf Image data - * @in url URL for the image - * @return 0 on success, -1 on error - */ -static int -artwork_url_read(struct evbuffer *evbuf, const char *url) -{ - struct http_client_ctx client; - struct keyval *kv; - const char *content_type; - int len; - int ret; - - DPRINTF(E_SPAM, L_ART, "Trying internet artwork in %s\n", url); - - ret = ART_E_NONE; - - len = strlen(url); - if ((len < 14) || (len > PATH_MAX)) // Can't be shorter than http://a/1.jpg - goto out_url; - - kv = keyval_alloc(); - if (!kv) - goto out_url; - - memset(&client, 0, sizeof(struct http_client_ctx)); - client.url = url; - client.input_headers = kv; - client.input_body = evbuf; - - if (http_client_request(&client) < 0) - goto out_kv; - - content_type = keyval_get(kv, "Content-Type"); - if (content_type && (strcmp(content_type, "image/jpeg") == 0)) - ret = ART_FMT_JPEG; - else if (content_type && (strcmp(content_type, "image/png") == 0)) - ret = ART_FMT_PNG; - else - ret = ART_FMT_JPEG; - - out_kv: - keyval_clear(kv); - free(kv); - - out_url: - return ret; -} - /* Reads an artwork file from the filesystem straight into an evbuf * TODO Use evbuffer_add_file or evbuffer_read? * @@ -778,7 +727,10 @@ source_item_own_get(struct artwork_ctx *ctx) static int source_item_stream_get(struct artwork_ctx *ctx) { + struct http_client_ctx client; struct db_queue_item *queue_item; + struct keyval *kv; + const char *content_type; char *url; char *ext; int len; @@ -812,14 +764,34 @@ source_item_stream_get(struct artwork_ctx *ctx) if (ret > 0) goto out_url; - ret = artwork_url_read(ctx->evbuf, url); + kv = keyval_alloc(); + if (!kv) + goto out_url; + + memset(&client, 0, sizeof(struct http_client_ctx)); + client.url = url; + client.input_headers = kv; + client.input_body = ctx->evbuf; + + if (http_client_request(&client) < 0) + goto out_kv; + + content_type = keyval_get(kv, "Content-Type"); + if (content_type && (strcmp(content_type, "image/jpeg") == 0)) + ret = ART_FMT_JPEG; + else if (content_type && (strcmp(content_type, "image/png") == 0)) + ret = ART_FMT_PNG; if (ret > 0) { - DPRINTF(E_SPAM, L_ART, "Found internet stream artwork in %s (%d)\n", url, ret); + DPRINTF(E_SPAM, L_ART, "Found internet stream artwork in %s (%s)\n", url, content_type); cache_artwork_stash(ctx->evbuf, url, ret); } + out_kv: + keyval_clear(kv); + free(kv); + out_url: free(url); @@ -832,11 +804,8 @@ source_item_spotify_get(struct artwork_ctx *ctx) { struct evbuffer *raw; struct evbuffer *evbuf; - char *artwork_url; - int content_type; int ret; - artwork_url = NULL; raw = evbuffer_new(); evbuf = evbuffer_new(); if (!raw || !evbuf) @@ -845,19 +814,15 @@ source_item_spotify_get(struct artwork_ctx *ctx) return ART_E_ERROR; } - artwork_url = spotifywebapi_artwork_get(ctx->dbmfi->path, ctx->max_w, ctx->max_h); - if (!artwork_url) + ret = spotify_artwork_get(raw, ctx->dbmfi->path, ctx->max_w, ctx->max_h); + if (ret < 0) { DPRINTF(E_WARN, L_ART, "No artwork from Spotify for %s\n", ctx->dbmfi->path); + evbuffer_free(raw); + evbuffer_free(evbuf); return ART_E_NONE; } - ret = artwork_url_read(raw, artwork_url); - if (ret <= 0) - goto out_free_evbuf; - - content_type = ret; - // Make a refbuf of raw for ffmpeg image size probing and possibly rescaling. // We keep raw around in case rescaling is not necessary. #ifdef HAVE_LIBEVENT2_OLD @@ -893,14 +858,12 @@ source_item_spotify_get(struct artwork_ctx *ctx) evbuffer_free(evbuf); evbuffer_free(raw); - free(artwork_url); - return content_type; + return ART_FMT_JPEG; out_free_evbuf: evbuffer_free(evbuf); evbuffer_free(raw); - free(artwork_url); return ART_E_ERROR; } diff --git a/src/artwork_legacy.c b/src/artwork_legacy.c index 8790dddc..e25d502c 100644 --- a/src/artwork_legacy.c +++ b/src/artwork_legacy.c @@ -46,7 +46,7 @@ #include "artwork.h" #ifdef HAVE_SPOTIFY_H -# include "spotify_webapi.h" +# include "spotify.h" #endif #include "ffmpeg-compat.h" @@ -224,57 +224,6 @@ static struct artwork_source artwork_item_source[] = /* -------------------------------- HELPERS -------------------------------- */ -/* Reads an artwork file from the given url straight into an evbuf - * - * @out evbuf Image data - * @in url URL for the image - * @return 0 on success, -1 on error - */ -static int -artwork_url_read(struct evbuffer *evbuf, const char *url) -{ - struct http_client_ctx client; - struct keyval *kv; - const char *content_type; - int len; - int ret; - - DPRINTF(E_SPAM, L_ART, "Trying internet artwork in %s\n", url); - - ret = ART_E_NONE; - - len = strlen(url); - if ((len < 14) || (len > PATH_MAX)) // Can't be shorter than http://a/1.jpg - goto out_url; - - kv = keyval_alloc(); - if (!kv) - goto out_url; - - memset(&client, 0, sizeof(struct http_client_ctx)); - client.url = url; - client.input_headers = kv; - client.input_body = evbuf; - - if (http_client_request(&client) < 0) - goto out_kv; - - content_type = keyval_get(kv, "Content-Type"); - if (content_type && (strcmp(content_type, "image/jpeg") == 0)) - ret = ART_FMT_JPEG; - else if (content_type && (strcmp(content_type, "image/png") == 0)) - ret = ART_FMT_PNG; - else - ret = ART_FMT_JPEG; - - out_kv: - keyval_clear(kv); - free(kv); - - out_url: - return ret; -} - /* Reads an artwork file from the filesystem straight into an evbuf * TODO Use evbuffer_add_file or evbuffer_read? * @@ -1154,7 +1103,10 @@ source_item_own_get(struct artwork_ctx *ctx) static int source_item_stream_get(struct artwork_ctx *ctx) { + struct http_client_ctx client; struct db_queue_item *queue_item; + struct keyval *kv; + const char *content_type; char *url; char *ext; int len; @@ -1188,14 +1140,34 @@ source_item_stream_get(struct artwork_ctx *ctx) if (ret > 0) goto out_url; - ret = artwork_url_read(ctx->evbuf, url); + kv = keyval_alloc(); + if (!kv) + goto out_url; + + memset(&client, 0, sizeof(struct http_client_ctx)); + client.url = url; + client.input_headers = kv; + client.input_body = ctx->evbuf; + + if (http_client_request(&client) < 0) + goto out_kv; + + content_type = keyval_get(kv, "Content-Type"); + if (content_type && (strcmp(content_type, "image/jpeg") == 0)) + ret = ART_FMT_JPEG; + else if (content_type && (strcmp(content_type, "image/png") == 0)) + ret = ART_FMT_PNG; if (ret > 0) { - DPRINTF(E_SPAM, L_ART, "Found internet stream artwork in %s (%d)\n", url, ret); + DPRINTF(E_SPAM, L_ART, "Found internet stream artwork in %s (%s)\n", url, content_type); cache_artwork_stash(ctx->evbuf, url, ret); } + out_kv: + keyval_clear(kv); + free(kv); + out_url: free(url); @@ -1211,13 +1183,10 @@ source_item_spotify_get(struct artwork_ctx *ctx) AVInputFormat *ifmt; struct evbuffer *raw; struct evbuffer *evbuf; - char *artwork_url; - int content_type; int target_w; int target_h; int ret; - artwork_url = NULL; raw = evbuffer_new(); evbuf = evbuffer_new(); if (!raw || !evbuf) @@ -1226,19 +1195,15 @@ source_item_spotify_get(struct artwork_ctx *ctx) return ART_E_ERROR; } - artwork_url = spotifywebapi_artwork_get(ctx->dbmfi->path, ctx->max_w, ctx->max_h); - if (!artwork_url) + ret = spotify_artwork_get(raw, ctx->dbmfi->path, ctx->max_w, ctx->max_h); + if (ret < 0) { DPRINTF(E_WARN, L_ART, "No artwork from Spotify for %s\n", ctx->dbmfi->path); + evbuffer_free(raw); + evbuffer_free(evbuf); return ART_E_NONE; } - ret = artwork_url_read(raw, artwork_url); - if (ret <= 0) - goto out_free_evbuf; - - content_type = ret; - // Make a refbuf of raw for ffmpeg image size probing and possibly rescaling. // We keep raw around in case rescaling is not necessary. #ifdef HAVE_LIBEVENT2_OLD @@ -1313,7 +1278,7 @@ source_item_spotify_get(struct artwork_ctx *ctx) evbuffer_free(evbuf); evbuffer_free(raw); - return content_type; + return ART_FMT_JPEG; out_close_input: avformat_close_input(&src_ctx); diff --git a/src/spotify.c b/src/spotify.c index 637f325c..acda80e0 100644 --- a/src/spotify.c +++ b/src/spotify.c @@ -141,6 +141,9 @@ static bool scanning; static pthread_mutex_t status_lck; static struct spotify_status_info spotify_status_info; +// Timeout timespec +static struct timespec spotify_artwork_timeout = { SPOTIFY_ARTWORK_TIMEOUT, 0 }; + // Audio buffer static struct evbuffer *spotify_audio_buffer; @@ -888,6 +891,194 @@ playback_eot(void *arg, int *retval) return COMMAND_END; } +static void +artwork_loaded_cb(sp_image *image, void *userdata) +{ + struct artwork_get_param *artwork; + + artwork = userdata; + + CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&artwork->mutex)); + + artwork->is_loaded = 1; + + CHECK_ERR(L_SPOTIFY, pthread_cond_signal(&artwork->cond)); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&artwork->mutex)); +} + +static enum command_state +artwork_get_bh(void *arg, int *retval) +{ + struct artwork_get_param *artwork; + sp_imageformat imageformat; + sp_error err; + const void *data; + char *path; + size_t data_size; + int ret; + + artwork = arg; + sp_image *image = artwork->image; + path = artwork->path; + + fptr_sp_image_remove_load_callback(image, artwork_loaded_cb, artwork); + + err = fptr_sp_image_error(image); + if (err != SP_ERROR_OK) + { + DPRINTF(E_WARN, L_SPOTIFY, "Getting artwork (%s) failed, Spotify error: %s\n", path, fptr_sp_error_message(err)); + goto fail; + } + + if (!fptr_sp_image_is_loaded(image)) + { + DPRINTF(E_LOG, L_SPOTIFY, "Load callback returned, but no image? Possible bug: %s\n", path); + goto fail; + } + + imageformat = fptr_sp_image_format(image); + if (imageformat != SP_IMAGE_FORMAT_JPEG) + { + DPRINTF(E_WARN, L_SPOTIFY, "Getting artwork failed, invalid image format from Spotify: %s\n", path); + goto fail; + } + + data_size = 0; + data = fptr_sp_image_data(image, &data_size); + if (!data) + { + DPRINTF(E_LOG, L_SPOTIFY, "Getting artwork failed, no image data from Spotify: %s\n", path); + goto fail; + } + + if ((data_size < 200) || (data_size > 20000000)) + { + // Sometimes we get strange data size even though fptr_sp_image_data returns success + DPRINTF(E_LOG, L_SPOTIFY, "Skipping artwork, data size is weird (%zu)\n", data_size); + goto fail; + } + + ret = evbuffer_expand(artwork->evbuf, data_size); + if (ret < 0) + { + DPRINTF(E_LOG, L_SPOTIFY, "Out of memory for artwork (data size requested was %zu)\n", data_size); + goto fail; + } + + ret = evbuffer_add(artwork->evbuf, data, data_size); + if (ret < 0) + { + DPRINTF(E_LOG, L_SPOTIFY, "Could not add Spotify image to event buffer\n"); + goto fail; + } + + DPRINTF(E_DBG, L_SPOTIFY, "Spotify artwork loaded ok\n"); + + fptr_sp_image_release(image); + + *retval = 0; + return COMMAND_END; + + fail: + fptr_sp_image_release(image); + + *retval = -1; + return COMMAND_END; +} + +static enum command_state +artwork_get(void *arg, int *retval) +{ + struct artwork_get_param *artwork; + char *path; + sp_link *link; + sp_track *track; + sp_album *album; + const byte *image_id; + sp_image *image; + sp_image_size image_size; + sp_error err; + + artwork = arg; + path = artwork->path; + + // Now begins: path -> link -> track -> album -> image_id -> image -> format -> data + link = fptr_sp_link_create_from_string(path); + if (!link) + { + DPRINTF(E_WARN, L_SPOTIFY, "Getting artwork failed, invalid Spotify link: %s\n", path); + goto level1_exit; + } + + track = fptr_sp_link_as_track(link); + if (!track) + { + DPRINTF(E_WARN, L_SPOTIFY, "Getting artwork failed, invalid Spotify track: %s\n", path); + goto level2_exit; + } + + album = fptr_sp_track_album(track); + if (!album) + { + DPRINTF(E_WARN, L_SPOTIFY, "Getting artwork failed, invalid Spotify album: %s\n", path); + goto level2_exit; + } + + // Get an image at least the same size as requested + image_size = SP_IMAGE_SIZE_SMALL; // 64x64 + if ((artwork->max_w > 64) || (artwork->max_h > 64)) + image_size = SP_IMAGE_SIZE_NORMAL; // 300x300 + if ((artwork->max_w > 300) || (artwork->max_h > 300)) + image_size = SP_IMAGE_SIZE_LARGE; // 640x640 + + image_id = fptr_sp_album_cover(album, image_size); + if (!image_id) + { + DPRINTF(E_DBG, L_SPOTIFY, "Getting artwork failed, no Spotify image id: %s\n", path); + goto level2_exit; + } + + image = fptr_sp_image_create(g_sess, image_id); + if (!image) + { + DPRINTF(E_DBG, L_SPOTIFY, "Getting artwork failed, no Spotify image: %s\n", path); + goto level2_exit; + } + + fptr_sp_link_release(link); + + artwork->image = image; + artwork->is_loaded = fptr_sp_image_is_loaded(image); + + /* If the image is ready we can return it straight away, otherwise we will + * let the calling thread wait, since the Spotify thread should not wait + */ + if (artwork->is_loaded) + return artwork_get_bh(artwork, retval); + + DPRINTF(E_SPAM, L_SPOTIFY, "Will wait for Spotify to call artwork_loaded_cb\n"); + + /* Async - we will return to spotify_artwork_get which will wait for callback */ + err = fptr_sp_image_add_load_callback(image, artwork_loaded_cb, artwork); + if (err != SP_ERROR_OK) + { + DPRINTF(E_WARN, L_SPOTIFY, "Adding artwork cb failed, Spotify error: %s\n", fptr_sp_error_message(err)); + *retval = -1; + return COMMAND_END; + } + + *retval = 0; + return COMMAND_END; + + level2_exit: + fptr_sp_link_release(link); + + level1_exit: + *retval = -1; + return COMMAND_END; +} + + /* --------------------------- SESSION CALLBACKS ------------------------- */ /** * This callback is called when an attempt to login has succeeded or failed. @@ -1258,6 +1449,41 @@ spotify_playback_seek(int ms) return -1; } +/* Thread: httpd (artwork) and worker */ +int +spotify_artwork_get(struct evbuffer *evbuf, char *path, int max_w, int max_h) +{ + struct artwork_get_param artwork; + struct timespec ts; + int ret; + + artwork.evbuf = evbuf; + artwork.path = path; + artwork.max_w = max_w; + artwork.max_h = max_h; + + CHECK_ERR(L_SPOTIFY, mutex_init(&artwork.mutex)); + CHECK_ERR(L_SPOTIFY, pthread_cond_init(&artwork.cond, NULL)); + + ret = commands_exec_sync(cmdbase, artwork_get, NULL, &artwork); + + // Artwork was not ready, wait for callback from libspotify + if (ret == 0) + { + CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&artwork.mutex)); + ts = timespec_reltoabs(spotify_artwork_timeout); + while ((!artwork.is_loaded) && (ret != ETIMEDOUT)) + CHECK_ERR_EXCEPT(L_SPOTIFY, pthread_cond_timedwait(&artwork.cond, &artwork.mutex, &ts), ret, ETIMEDOUT); + if (ret == ETIMEDOUT) + DPRINTF(E_LOG, L_SPOTIFY, "Timeout waiting for artwork from Spotify\n"); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&artwork.mutex)); + + ret = commands_exec_sync(cmdbase, artwork_get_bh, NULL, &artwork); + } + + return ret; +} + /* Thread: httpd */ void spotify_oauth_interface(struct evbuffer *evbuf, const char *redirect_uri) @@ -1967,9 +2193,8 @@ spotify_init(void) CHECK_ERR(L_SPOTIFY, mutex_init(&login_lck)); CHECK_ERR(L_SPOTIFY, pthread_cond_init(&login_cond, NULL)); - CHECK_ERR(L_SPOTIFY, mutex_init(&status_lck)); - spotifywebapi_init(); + CHECK_ERR(L_SPOTIFY, mutex_init(&status_lck)); /* Spawn thread */ ret = pthread_create(&tid_spotify, NULL, spotify, NULL); @@ -1989,8 +2214,6 @@ spotify_init(void) return 0; thread_fail: - spotifywebapi_deinit(); - CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&status_lck)); CHECK_ERR(L_SPOTIFY, pthread_cond_destroy(&login_cond)); CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&login_lck)); @@ -2057,9 +2280,6 @@ spotify_deinit(void) CHECK_ERR(L_SPOTIFY, pthread_cond_destroy(&login_cond)); CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&login_lck)); - /* Deinit web api */ - spotifywebapi_deinit(); - /* Free audio buffer */ evbuffer_free(spotify_audio_buffer); diff --git a/src/spotify.h b/src/spotify.h index af21611f..8bbbf06b 100644 --- a/src/spotify.h +++ b/src/spotify.h @@ -39,6 +39,9 @@ spotify_playback_stop_nonblock(void); int spotify_playback_seek(int ms); +int +spotify_artwork_get(struct evbuffer *evbuf, char *path, int max_w, int max_h); + void spotify_oauth_interface(struct evbuffer *evbuf, const char *redirect_uri); diff --git a/src/spotify_webapi.c b/src/spotify_webapi.c index 30f03a11..3452d3bf 100644 --- a/src/spotify_webapi.c +++ b/src/spotify_webapi.c @@ -43,15 +43,12 @@ static char *spotify_user; static int32_t expires_in = 3600; static time_t token_requested = 0; -static pthread_mutex_t token_lck; - // Endpoints and credentials for the web api static const char *spotify_client_id = "0e684a5422384114a8ae7ac020f01789"; static const char *spotify_client_secret = "232af95f39014c9ba218285a5c11a239"; static const char *spotify_auth_uri = "https://accounts.spotify.com/authorize"; static const char *spotify_token_uri = "https://accounts.spotify.com/api/token"; static const char *spotify_playlist_uri = "https://api.spotify.com/v1/users/%s/playlists/%s"; -static const char *spotify_track_uri = "https://api.spotify.com/v1/tracks/%s"; static const char *spotify_me_uri = "https://api.spotify.com/v1/me"; @@ -75,14 +72,14 @@ free_http_client_ctx(struct http_client_ctx *ctx) } static int -request_uri(struct spotify_request *request, const char *uri, bool check_token) +request_uri(struct spotify_request *request, const char *uri) { char bearer_token[1024]; int ret; memset(request, 0, sizeof(struct spotify_request)); - if (check_token && (0 > spotifywebapi_token_refresh(NULL))) + if (0 > spotifywebapi_token_refresh(NULL)) { return -1; } @@ -168,7 +165,7 @@ spotifywebapi_request_next(struct spotify_request *request, const char *uri, boo spotifywebapi_request_end(request); } - ret = request_uri(request, next_uri, true); + ret = request_uri(request, next_uri); free(next_uri); if (ret < 0) @@ -424,28 +421,6 @@ get_owner_plid_from_uri(const char *uri, char **owner, char **plid) return 0; } -/* - * Extracts the id from a spotify album/artist/track uri - * - * E. g. album-uri has the following format: spotify:album:[id] - * The id must be freed by the caller. - */ -static int -get_id_from_uri(const char *uri, char **id) -{ - char *tmp; - tmp = strrchr(uri, ':'); - if (!tmp) - { - return -1; - } - tmp++; - - *id = strdup(tmp); - - return 0; -} - int spotifywebapi_playlisttracks_fetch(struct spotify_request *request, struct spotify_track *track) { @@ -500,7 +475,7 @@ spotifywebapi_playlist_start(struct spotify_request *request, const char *path, return -1; } - ret = request_uri(request, uri, true); + ret = request_uri(request, uri); if (ret < 0) { free(owner); @@ -516,120 +491,8 @@ spotifywebapi_playlist_start(struct spotify_request *request, const char *path, return 0; } - static int -spotifywebapi_track_start(struct spotify_request *request, const char *path, struct spotify_track *track, json_object **jsonimages, int *image_count) -{ - char uri[1024]; - char *id; - json_object *jsonalbum; - int ret; - - memset(track, 0, sizeof(struct spotify_track)); - - ret = get_id_from_uri(path, &id); - if (ret < 0) - { - DPRINTF(E_LOG, L_SPOTIFY, "Error extracting id from track uri '%s'\n", path); - return -1; - } - - ret = snprintf(uri, sizeof(uri), spotify_track_uri, id); - free(id); - if (ret < 0 || ret >= sizeof(uri)) - { - DPRINTF(E_LOG, L_SPOTIFY, "Error creating playlist endpoint uri for playlist '%s'\n", path); - return -1; - } - - ret = request_uri(request, uri, true); - if (ret < 0) - { - return -1; - } - - request->haystack = json_tokener_parse(request->response_body); - parse_metadata_track(request->haystack, track); - - if (jsonimages && image_count) - { - if (json_object_object_get_ex(request->haystack, "album", &jsonalbum)) - { - if (json_object_object_get_ex(jsonalbum, "images", jsonimages)) - { - *image_count = json_object_array_length(*jsonimages); - } - } - } - - return 0; -} - -static int -spotifywebapi_image_fetch(json_object *jsonimages, int index, struct spotify_image *image) -{ - json_object *jsonimage; - - memset(image, 0, sizeof(struct spotify_image)); - - jsonimage = json_object_array_get_idx(jsonimages, index); - - if (!jsonimage) - { - return -1; - } - - image->url = jparse_str_from_obj(jsonimage, "url"); - image->width = jparse_int_from_obj(jsonimage, "width"); - image->height = jparse_int_from_obj(jsonimage, "height"); - - return 0; -} - -char * -spotifywebapi_artwork_get(const char *path, int max_w, int max_h) -{ - struct spotify_request request; - struct spotify_track track; - json_object *jsonimages; - struct spotify_image image; - int image_count; - int i; - char *artwork_url; - int ret; - - artwork_url = NULL; - image_count = 0; - - memset(&request, 0, sizeof(struct spotify_request)); - ret = spotifywebapi_track_start(&request, path, &track, &jsonimages, &image_count); - if (ret == 0) - { - DPRINTF(E_DBG, L_SPOTIFY, "Got track: '%s' (%s) \n", track.name, track.uri); - - // Get an image at least the same size as requested, images are returned with decreasing size - for (i = (image_count - 1); i >= 0 && ret == 0; i--) - { - ret = spotifywebapi_image_fetch(jsonimages, i, &image); - if (ret < 0 || !image.url) - continue; - - free(artwork_url); - - DPRINTF(E_DBG, L_SPOTIFY, "Got image for album '%s' - '%s': '%s' (%dx%d)\n", track.album_artist, track.album, image.url, image.height, image.width); - artwork_url = strdup(image.url); - - if ((max_w < image.width) || (max_h < image.height)) - break; - } - } - spotifywebapi_request_end(&request); - - return artwork_url; -} - -static int -request_user_info(char **user) +request_user_info() { struct spotify_request request; int ret; @@ -639,7 +502,7 @@ request_user_info(char **user) free(spotify_user); spotify_user = NULL; - ret = request_uri(&request, spotify_me_uri, false); + ret = request_uri(&request, spotify_me_uri); if (ret < 0) { @@ -651,9 +514,6 @@ request_user_info(char **user) spotify_user_country = safe_strdup(jparse_str_from_obj(request.haystack, "country")); DPRINTF(E_DBG, L_SPOTIFY, "User '%s', country '%s'\n", spotify_user, spotify_user_country); - - if (user) - *user = safe_strdup(spotify_user); } spotifywebapi_request_end(&request); @@ -700,7 +560,7 @@ spotifywebapi_oauth_uri_get(const char *redirect_uri) } static int -tokens_get(struct keyval *kv, char **user, const char **err) +tokens_get(struct keyval *kv, const char **err) { struct http_client_ctx ctx; char *param; @@ -784,7 +644,7 @@ tokens_get(struct keyval *kv, char **user, const char **err) if (spotify_refresh_token) db_admin_set(DB_ADMIN_SPOTIFY_REFRESH_TOKEN, spotify_refresh_token); - request_user_info(user); + request_user_info(); ret = 0; @@ -802,8 +662,6 @@ spotifywebapi_token_get(const char *code, const char *redirect_uri, char **user, struct keyval kv; int ret; - CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&token_lck)); - *err = ""; memset(&kv, 0, sizeof(struct keyval)); ret = ( (keyval_add(&kv, "grant_type", "authorization_code") == 0) && @@ -818,12 +676,14 @@ spotifywebapi_token_get(const char *code, const char *redirect_uri, char **user, ret = -1; } else - ret = tokens_get(&kv, user, err); + ret = tokens_get(&kv, err); + if (user && ret == 0) + { + *user = safe_strdup(spotify_user); + } keyval_clear(&kv); - CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&token_lck)); - return ret; } @@ -831,19 +691,13 @@ int spotifywebapi_token_refresh(char **user) { struct keyval kv; - char *refresh_token = NULL; + char *refresh_token; const char *err; int ret; - memset(&kv, 0, sizeof(struct keyval)); - - CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&token_lck)); - if (token_requested && difftime(time(NULL), token_requested) < expires_in) { DPRINTF(E_DBG, L_SPOTIFY, "Spotify token still valid\n"); - - CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&token_lck)); return 0; } @@ -851,11 +705,12 @@ spotifywebapi_token_refresh(char **user) if (!refresh_token) { DPRINTF(E_LOG, L_SPOTIFY, "No spotify refresh token found\n"); - goto error; + return -1; } DPRINTF(E_DBG, L_SPOTIFY, "Spotify refresh-token: '%s'\n", refresh_token); + memset(&kv, 0, sizeof(struct keyval)); ret = ( (keyval_add(&kv, "grant_type", "refresh_token") == 0) && (keyval_add(&kv, "client_id", spotify_client_id) == 0) && (keyval_add(&kv, "client_secret", spotify_client_secret) == 0) && @@ -863,38 +718,18 @@ spotifywebapi_token_refresh(char **user) if (!ret) { DPRINTF(E_LOG, L_SPOTIFY, "Add parameters to keyval failed"); - goto error; + ret = -1; } + else + ret = tokens_get(&kv, &err); - ret = tokens_get(&kv, user, &err); - + if (user && ret == 0) + { + *user = safe_strdup(spotify_user); + } free(refresh_token); keyval_clear(&kv); - CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&token_lck)); - return ret; - - error: - free(refresh_token); - keyval_clear(&kv); - - CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&token_lck)); - - return -1; -} - -int -spotifywebapi_init() -{ - CHECK_ERR(L_SPOTIFY, mutex_init(&token_lck)); - return 0; -} - -int -spotifywebapi_deinit() -{ - CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&token_lck)); - return 0; } diff --git a/src/spotify_webapi.h b/src/spotify_webapi.h index f07d36f4..11af153c 100644 --- a/src/spotify_webapi.h +++ b/src/spotify_webapi.h @@ -82,13 +82,6 @@ struct spotify_playlist int tracks_count; }; -struct spotify_image -{ - const char *url; - int width; - int height; -}; - struct spotify_request { struct http_client_ctx *ctx; @@ -123,12 +116,5 @@ int spotifywebapi_playlisttracks_fetch(struct spotify_request *request, struct spotify_track *track); int spotifywebapi_playlist_start(struct spotify_request *request, const char *path, struct spotify_playlist *playlist); -char * -spotifywebapi_artwork_get(const char *path, int max_w, int max_h); - -int -spotifywebapi_init(void); -int -spotifywebapi_deinit(void); #endif /* SRC_SPOTIFY_WEBAPI_H_ */