From a289135325bd11cb30f5df588ec4f75059d23f24 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Tue, 18 Feb 2020 22:12:54 +0100 Subject: [PATCH] [artwork] Construct online src querys based on data_kind For http streams we don't have an album name to search for. Plus we don't want to cache those images. --- src/artwork.c | 224 +++++++++++++++++++++++++++++++------------------- 1 file changed, 140 insertions(+), 84 deletions(-) diff --git a/src/artwork.c b/src/artwork.c index 77b79204..892937fa 100644 --- a/src/artwork.c +++ b/src/artwork.c @@ -97,6 +97,7 @@ struct artwork_ctx { // Input data for item handlers struct db_media_file_info *dbmfi; int id; + uint32_t data_kind; // Input data for group handlers int64_t persistentid; @@ -171,12 +172,12 @@ static int source_item_embedded_get(struct artwork_ctx *ctx); static int source_item_own_get(struct artwork_ctx *ctx); static int source_item_stream_get(struct artwork_ctx *ctx); static int source_item_pipe_get(struct artwork_ctx *ctx); +static int source_item_libspotify_get(struct artwork_ctx *ctx); +static int source_item_spotifywebapi_track_get(struct artwork_ctx *ctx); +static int source_item_ownpl_get(struct artwork_ctx *ctx); +static int source_item_spotifywebapi_search_get(struct artwork_ctx *ctx); static int source_item_discogs_get(struct artwork_ctx *ctx); static int source_item_coverartarchive_get(struct artwork_ctx *ctx); -static int source_item_spotify2_get(struct artwork_ctx *ctx); -static int source_item_spotify_get(struct artwork_ctx *ctx); -static int source_item_spotifywebapi_get(struct artwork_ctx *ctx); -static int source_item_ownpl_get(struct artwork_ctx *ctx); /* List of sources that can provide artwork for a group (i.e. usually an album * identified by a persistentid). The source handlers will be called in the @@ -214,26 +215,6 @@ static struct artwork_source artwork_item_source[] = .data_kinds = (1 << DATA_KIND_FILE) | (1 << DATA_KIND_SPOTIFY), .cache = ON_FAILURE, }, - { - // TODO merge with spotifywebapi_get - .name = "Spotify2", - .handler = source_item_spotify2_get, - .data_kinds = (1 << DATA_KIND_FILE), - .cache = NEVER, - }, - { - .name = "Discogs", - .handler = source_item_discogs_get, - .data_kinds = (1 << DATA_KIND_FILE), - .cache = NEVER, - }, - { - // The Cover Art Archive seems rather slow, so low priority - .name = "Cover Art Archive", - .handler = source_item_coverartarchive_get, - .data_kinds = (1 << DATA_KIND_FILE), - .cache = NEVER, - }, { .name = "embedded", .handler = source_item_embedded_get, @@ -259,14 +240,14 @@ static struct artwork_source artwork_item_source[] = .cache = NEVER, }, { - .name = "Spotify", - .handler = source_item_spotify_get, + .name = "libspotify", + .handler = source_item_libspotify_get, .data_kinds = (1 << DATA_KIND_SPOTIFY), .cache = ON_SUCCESS, }, { - .name = "Spotify web api", - .handler = source_item_spotifywebapi_get, + .name = "Spotify track web api", + .handler = source_item_spotifywebapi_track_get, .data_kinds = (1 << DATA_KIND_SPOTIFY), .cache = ON_SUCCESS | ON_FAILURE, }, @@ -276,6 +257,44 @@ static struct artwork_source artwork_item_source[] = .data_kinds = (1 << DATA_KIND_HTTP), .cache = ON_SUCCESS | ON_FAILURE, }, + { + .name = "Spotify search web api (files)", + .handler = source_item_spotifywebapi_search_get, + .data_kinds = (1 << DATA_KIND_FILE), + .cache = ON_SUCCESS | ON_FAILURE, + }, + { + .name = "Spotify search web api (streams)", + .handler = source_item_spotifywebapi_search_get, + .data_kinds = (1 << DATA_KIND_HTTP) | (1 << DATA_KIND_PIPE), + .cache = NEVER, + }, + { + .name = "Discogs (files)", + .handler = source_item_discogs_get, + .data_kinds = (1 << DATA_KIND_FILE), + .cache = ON_SUCCESS | ON_FAILURE, + }, + { + .name = "Discogs (streams)", + .handler = source_item_discogs_get, + .data_kinds = (1 << DATA_KIND_HTTP) | (1 << DATA_KIND_PIPE), + .cache = NEVER, + }, + { + // The Cover Art Archive seems rather slow, so low priority + .name = "Cover Art Archive (files)", + .handler = source_item_coverartarchive_get, + .data_kinds = (1 << DATA_KIND_FILE), + .cache = ON_SUCCESS | ON_FAILURE, + }, + { + // The Cover Art Archive seems rather slow, so low priority + .name = "Cover Art Archive (streams)", + .handler = source_item_coverartarchive_get, + .data_kinds = (1 << DATA_KIND_HTTP) | (1 << DATA_KIND_PIPE), + .cache = NEVER, + }, { .name = NULL, .handler = NULL, @@ -299,6 +318,7 @@ static struct online_source spotify_source = .query_parts = { { "q", "artist:$ARTIST$ album:$ALBUM$" }, + { "q", "artist:$ARTIST$ track:$TITLE$" }, { NULL, NULL }, }, .response_jparse = response_jparse_spotify, @@ -330,6 +350,7 @@ static struct online_source musicbrainz_source = .query_parts = { { "query", "artist:$ARTIST$ AND release:$ALBUM$ AND status:Official" }, + { "query", "artist:$ARTIST$ AND title:$TITLE$ AND status:Official" }, { NULL, NULL }, }, .response_jparse = response_jparse_musicbrainz, @@ -952,16 +973,56 @@ online_source_response_parse(char **artwork_url, struct online_source *src, stru } static int -online_source_request_url_make(char *url, size_t url_size, struct online_source *src, const char *artist, const char *album, const char *title) +online_source_request_url_make(char *url, size_t url_size, struct online_source *src, struct artwork_ctx *ctx) { + struct db_queue_item *queue_item; struct keyval query = { 0 }; + const char *artist = NULL; + const char *album = NULL; + const char *title = NULL; char param[512]; - char *encoded_query; + char *encoded_query = NULL; int ret; int i; + // First check if the item is in the queue. When searching for artwork, it is + // better to use queue_item metadata. For stream items the queue metadata will + // for instance be updated with icy metadata. It is also possible we are asked + // for artwork for a non-library item. + queue_item = db_queue_fetch_byfileid(ctx->id); + if (queue_item && ctx->data_kind == DATA_KIND_HTTP) + { + // Normally we prefer searching by artist and album, but for streams we + // take the below approach, since they have no album information, and the + // title is in the album field + artist = queue_item->artist; + title = queue_item->album; + } + else if (queue_item) + { + artist = queue_item->artist; + album = queue_item->album; + } + else + { + // We will just search for artist and album + artist = ctx->dbmfi->artist; + album = ctx->dbmfi->album; + } + + if (!artist || (!album && !title)) + { + DPRINTF(E_DBG, L_ART, "Cannot construct query to %s, missing input data (artist=%s, album=%s, title=%s)\n", src->name, artist, album, title); + goto error; + } + for (i = 0; src->query_parts[i].key; i++) { + if (!album && strstr(src->query_parts[i].template, "$ALBUM$")) + continue; + if (!title && strstr(src->query_parts[i].template, "$TITLE$")) + continue; + snprintf(param, sizeof(param), "%s", src->query_parts[i].template); if ((safe_snreplace(param, sizeof(param), "$ARTIST$", artist) < 0) || (safe_snreplace(param, sizeof(param), "$ALBUM$", album) < 0) || @@ -992,11 +1053,14 @@ online_source_request_url_make(char *url, size_t url_size, struct online_source free(encoded_query); keyval_clear(&query); + free_queue_item(queue_item, 0); return 0; error: + free(encoded_query); keyval_clear(&query); + free_queue_item(queue_item, 0); return -1; } @@ -1010,14 +1074,7 @@ online_source_search(struct online_source *src, struct artwork_ctx *ctx) char auth_header[256]; int ret; - if (!ctx->dbmfi->artist || !ctx->dbmfi->album || !ctx->dbmfi->title) - { - DPRINTF(E_DBG, L_ART, "Skipping artwork source %s, missing input data (artist=%s, album=%s, title=%s)\n", - src->name, ctx->dbmfi->artist, ctx->dbmfi->album, ctx->dbmfi->title); - return NULL; - } - - ret = online_source_request_url_make(url, sizeof(url), src, ctx->dbmfi->artist, ctx->dbmfi->album, ctx->dbmfi->title); + ret = online_source_request_url_make(url, sizeof(url), src, ctx); if (ret < 0) { DPRINTF(E_WARN, L_ART, "Skipping artwork source %s, could not construct a request URL\n", src->name); @@ -1382,34 +1439,7 @@ source_item_coverartarchive_get(struct artwork_ctx *ctx) #ifdef HAVE_SPOTIFY_H static int -source_item_spotify2_get(struct artwork_ctx *ctx) -{ - struct spotifywebapi_access_token info; - char *url; - int ret; - - if (!online_source_is_enabled("enable_spotify")) - return ART_E_NONE; - - spotifywebapi_access_token_get(&info); - if (!info.token) - return ART_E_ERROR; - - spotify_source.auth_secret = info.token; - - url = online_source_search(&spotify_source, ctx); - free(info.token); - if (!url) - return ART_E_NONE; - - ret = artwork_get_byurl(ctx->evbuf, url, ctx->max_w, ctx->max_h); - - free(url); - return ret; -} - -static int -source_item_spotify_get(struct artwork_ctx *ctx) +source_item_libspotify_get(struct artwork_ctx *ctx) { struct evbuffer *raw; int ret; @@ -1437,7 +1467,7 @@ source_item_spotify_get(struct artwork_ctx *ctx) } static int -source_item_spotifywebapi_get(struct artwork_ctx *ctx) +source_item_spotifywebapi_track_get(struct artwork_ctx *ctx) { char *artwork_url; int ret; @@ -1454,27 +1484,54 @@ source_item_spotifywebapi_get(struct artwork_ctx *ctx) free(artwork_url); return ret; } + +static int +source_item_spotifywebapi_search_get(struct artwork_ctx *ctx) +{ + struct spotifywebapi_access_token info; + char *url; + int ret; + + if (!online_source_is_enabled("enable_spotify")) + return ART_E_NONE; + + spotifywebapi_access_token_get(&info); + if (!info.token) + return ART_E_ERROR; + + spotify_source.auth_secret = info.token; + + url = online_source_search(&spotify_source, ctx); + free(info.token); + if (!url) + return ART_E_NONE; + + ret = artwork_get_byurl(ctx->evbuf, url, ctx->max_w, ctx->max_h); + + free(url); + return ret; +} #else static int -source_item_spotify2_get(struct artwork_ctx *ctx) +source_item_libspotify_get(struct artwork_ctx *ctx) +{ + return ART_E_ERROR; +} + +static int +source_item_spotifywebapi_track_get(struct artwork_ctx *ctx) +{ + return ART_E_ERROR; +} + +static int +source_item_spotifywebapi_search_get(struct artwork_ctx *ctx) { // Silence compiler warning about spotify_source being unused (void)spotify_source; return ART_E_NONE; } - -static int -source_item_spotify_get(struct artwork_ctx *ctx) -{ - return ART_E_ERROR; -} - -static int -source_item_spotifywebapi_get(struct artwork_ctx *ctx) -{ - return ART_E_ERROR; -} #endif /* First looks of the mfi->path is in any playlist, and if so looks in the dir @@ -1538,7 +1595,6 @@ static int process_items(struct artwork_ctx *ctx, int item_mode) { struct db_media_file_info dbmfi; - uint32_t data_kind; int i; int ret; @@ -1560,8 +1616,8 @@ process_items(struct artwork_ctx *ctx, int item_mode) goto no_artwork; ret = (safe_atoi32(dbmfi.id, &ctx->id) < 0) || - (safe_atou32(dbmfi.data_kind, &data_kind) < 0) || - (data_kind > 30); + (safe_atou32(dbmfi.data_kind, &ctx->data_kind) < 0) || + (ctx->data_kind > 30); if (ret) { DPRINTF(E_LOG, L_ART, "Error converting dbmfi id or data_kind to number\n"); @@ -1570,7 +1626,7 @@ process_items(struct artwork_ctx *ctx, int item_mode) for (i = 0; artwork_item_source[i].handler; i++) { - if ((artwork_item_source[i].data_kinds & (1 << data_kind)) == 0) + if ((artwork_item_source[i].data_kinds & (1 << ctx->data_kind)) == 0) continue; // If just one handler says we should not cache a negative result then we obey that