From d7086cab000bc5ac1389554eed7e99a84218ea1a Mon Sep 17 00:00:00 2001 From: chme Date: Fri, 24 Dec 2021 14:02:37 +0100 Subject: [PATCH 1/4] [db,jsonapi] Additional meta data for browse queries --- src/db.c | 79 ++++++++++++++++++++++++++++++++++++++++++++- src/db.h | 21 ++++++++++++ src/httpd_jsonapi.c | 38 ++++++++++++++++++---- 3 files changed, 130 insertions(+), 8 deletions(-) diff --git a/src/db.c b/src/db.c index 41596213..2cadf011 100644 --- a/src/db.c +++ b/src/db.c @@ -420,6 +420,27 @@ static const ssize_t dbgri_cols_map[] = dbgri_offsetof(seek), }; +/* This list must be kept in sync with + * - the order of fields in the Q_BROWSE_INFO query + * - the name of the fields in struct db_browse_info + */ +static const ssize_t dbbi_cols_map[] = + { + dbbi_offsetof(itemname), + dbbi_offsetof(itemname_sort), + dbbi_offsetof(track_count), + dbbi_offsetof(album_count), + dbbi_offsetof(artist_count), + dbbi_offsetof(song_length), + dbbi_offsetof(data_kind), + dbbi_offsetof(media_kind), + dbbi_offsetof(year), + dbbi_offsetof(date_released), + dbbi_offsetof(time_added), + dbbi_offsetof(time_played), + dbbi_offsetof(seek), + }; + /* This list must be kept in sync with * - qi_cols_map */ @@ -2188,7 +2209,10 @@ db_build_query_browse(struct query_params *qp, struct query_clause *qc) where = browse_clause[qp->type & ~Q_F_BROWSE].where; count = sqlite3_mprintf("SELECT COUNT(*) FROM (SELECT %s FROM files f %s AND %s != '' %s);", select, qc->where, where, qc->group); - query = sqlite3_mprintf("SELECT %s FROM files f %s AND %s != '' %s %s %s;", select, qc->where, where, qc->group, qc->order, qc->index); + query = sqlite3_mprintf("SELECT %s, COUNT(f.id) as track_count, COUNT(DISTINCT f.songalbumid) as album_count, COUNT(DISTINCT f.songartistid) as artist_count, " + " SUM(f.song_length), MIN(f.data_kind), MIN(f.media_kind), MAX(f.year), MAX(f.date_released), " + " MAX(f.time_added), MAX(f.time_played), MAX(f.seek) FROM files f %s AND %s != '' %s %s %s;", + select, qc->where, where, qc->group, qc->order, qc->index); return db_build_query_check(qp, count, query); } @@ -2522,6 +2546,59 @@ db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri) return 0; } +int +db_query_fetch_browse(struct query_params *qp, struct db_browse_info *dbbi) +{ + int ncols; + char **strcol; + int i; + int ret; + + memset(dbbi, 0, sizeof(struct db_browse_info)); + + if (!qp->stmt) + { + DPRINTF(E_LOG, L_DB, "Query not started!\n"); + return -1; + } + + if (!(qp->type & Q_F_BROWSE)) + { + DPRINTF(E_LOG, L_DB, "Not a browse query!\n"); + return -1; + } + + ret = db_blocking_step(qp->stmt); + if (ret == SQLITE_DONE) + { + DPRINTF(E_DBG, L_DB, "End of query results\n"); + return 1; + } + else if (ret != SQLITE_ROW) + { + DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl)); + return -1; + } + + ncols = sqlite3_column_count(qp->stmt); + + // We allow more cols in db than in map because the db may be a future schema + if (ncols < ARRAY_SIZE(dbbi_cols_map)) + { + DPRINTF(E_LOG, L_DB, "BUG: database has fewer columns (%d) than dbbi column map (%u)\n", ncols, ARRAY_SIZE(dbbi_cols_map)); + return -1; + } + + for (i = 0; i < ARRAY_SIZE(dbbi_cols_map); i++) + { + strcol = (char **) ((char *)dbbi + dbbi_cols_map[i]); + + *strcol = (char *)sqlite3_column_text(qp->stmt, i); + } + + return 0; +} + int db_query_fetch_count(struct query_params *qp, struct filecount_info *fci) { diff --git a/src/db.h b/src/db.h index dda94c1e..eceb9db6 100644 --- a/src/db.h +++ b/src/db.h @@ -409,6 +409,24 @@ struct db_media_file_info { #define dbmfi_offsetof(field) offsetof(struct db_media_file_info, field) +struct db_browse_info { + char *itemname; + char *itemname_sort; + char *track_count; + char *album_count; + char *artist_count; + char *song_length; + char *data_kind; + char *media_kind; + char *year; + char *date_released; + char *time_added; + char *time_played; + char *seek; +}; + +#define dbbi_offsetof(field) offsetof(struct db_browse_info, field) + enum strip_type { STRIP_NONE, STRIP_PATH, @@ -593,6 +611,9 @@ db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli); int db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri); +int +db_query_fetch_browse(struct query_params *qp, struct db_browse_info *dbbi); + int db_query_fetch_count(struct query_params *qp, struct filecount_info *fci); diff --git a/src/httpd_jsonapi.c b/src/httpd_jsonapi.c index ea00e4f3..9e4f99b4 100644 --- a/src/httpd_jsonapi.c +++ b/src/httpd_jsonapi.c @@ -388,17 +388,42 @@ playlist_to_json(struct db_playlist_info *dbpli) } static json_object * -genre_to_json(const char *genre) +browse_info_to_json(struct db_browse_info *dbbi) { json_object *item; + int intval; + int ret; - if (genre == NULL) + if (dbbi == NULL) { return NULL; } item = json_object_new_object(); - safe_json_add_string(item, "name", genre); + safe_json_add_string(item, "name", dbbi->itemname); + safe_json_add_string(item, "name_sort", dbbi->itemname_sort); + safe_json_add_int_from_string(item, "track_count", dbbi->track_count); + safe_json_add_int_from_string(item, "album_count", dbbi->album_count); + safe_json_add_int_from_string(item, "artist_count", dbbi->artist_count); + safe_json_add_int_from_string(item, "length_ms", dbbi->song_length); + + safe_json_add_time_from_string(item, "time_played", dbbi->time_played); + safe_json_add_time_from_string(item, "time_added", dbbi->time_added); + + ret = safe_atoi32(dbbi->seek, &intval); + if (ret == 0) + json_object_object_add(item, "in_progress", json_object_new_boolean(intval > 0)); + + ret = safe_atoi32(dbbi->media_kind, &intval); + if (ret == 0) + safe_json_add_string(item, "media_kind", db_media_kind_label(intval)); + + ret = safe_atoi32(dbbi->data_kind, &intval); + if (ret == 0) + safe_json_add_string(item, "data_kind", db_data_kind_label(intval)); + + safe_json_add_date_from_string(item, "date_released", dbbi->date_released); + safe_json_add_int_from_string(item, "year", dbbi->year); return item; } @@ -662,18 +687,17 @@ fetch_playlist(bool *notfound, uint32_t playlist_id) static int fetch_genres(struct query_params *query_params, json_object *items, int *total) { + struct db_browse_info dbbi; json_object *item; int ret; - char *genre; - char *sort_item; ret = db_query_start(query_params); if (ret < 0) goto error; - while (((ret = db_query_fetch_string_sort(query_params, &genre, &sort_item)) == 0) && (genre)) + while (((ret = db_query_fetch_browse(query_params, &dbbi)) == 0) && (dbbi.track_count)) { - item = genre_to_json(genre); + item = browse_info_to_json(&dbbi); if (!item) { ret = -1; From a65ee4462eacf549fd6bf828d0686645365a084f Mon Sep 17 00:00:00 2001 From: chme Date: Tue, 28 Dec 2021 06:55:35 +0100 Subject: [PATCH 2/4] [db] Refactor fetching query result into generic function Additionally changes the return value in case the end of the result set is reached. --- src/artwork.c | 4 +- src/db.c | 136 ++++++++++++-------------------------- src/httpd_daap.c | 2 +- src/httpd_dacp.c | 5 +- src/httpd_jsonapi.c | 5 +- src/httpd_rsp.c | 2 +- src/inputs/pipe.c | 2 +- src/library/filescanner.c | 2 +- src/mpd.c | 14 ++-- 9 files changed, 59 insertions(+), 113 deletions(-) diff --git a/src/artwork.c b/src/artwork.c index 403f3e35..4665a886 100644 --- a/src/artwork.c +++ b/src/artwork.c @@ -1766,7 +1766,7 @@ process_items(struct artwork_ctx *ctx, int item_mode) return -1; } - while (((ret = db_query_fetch_file(&ctx->qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&ctx->qp, &dbmfi)) == 0) { // Save the first songalbumid, might need it for process_group() if this search doesn't give anything if (!ctx->persistentid) @@ -1859,7 +1859,7 @@ process_group(struct artwork_ctx *ctx) goto invalid_group; } - is_valid = (db_query_fetch_file(&ctx->qp, &dbmfi) == 0 && dbmfi.id && strcmp(dbmfi.album, CFG_NAME_UNKNOWN_ALBUM) != 0 && strcmp(dbmfi.album_artist, CFG_NAME_UNKNOWN_ARTIST) != 0); + is_valid = (db_query_fetch_file(&ctx->qp, &dbmfi) == 0 && strcmp(dbmfi.album, CFG_NAME_UNKNOWN_ALBUM) != 0 && strcmp(dbmfi.album_artist, CFG_NAME_UNKNOWN_ARTIST) != 0); db_query_end(&ctx->qp); if (!is_valid) { diff --git a/src/db.c b/src/db.c index 2cadf011..abd5f410 100644 --- a/src/db.c +++ b/src/db.c @@ -2372,53 +2372,44 @@ db_query_run(char *query, int free, short update_events) return ((ret != SQLITE_OK) ? -1 : 0); } -int -db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi) +static int +db_query_fetch(void *item, struct query_params *qp, const ssize_t cols_map[], int size) { int ncols; char **strcol; int i; int ret; - memset(dbmfi, 0, sizeof(struct db_media_file_info)); - if (!qp->stmt) { DPRINTF(E_LOG, L_DB, "Query not started!\n"); return -1; } - if ((qp->type != Q_ITEMS) && (qp->type != Q_PLITEMS) && (qp->type != Q_GROUP_ITEMS)) - { - DPRINTF(E_LOG, L_DB, "Not an items, playlist or group items query!\n"); - return -1; - } - ret = db_blocking_step(qp->stmt); if (ret == SQLITE_DONE) { DPRINTF(E_DBG, L_DB, "End of query results\n"); - dbmfi->id = NULL; - return 0; + return 1; } else if (ret != SQLITE_ROW) { - DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl)); + DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl)); return -1; } ncols = sqlite3_column_count(qp->stmt); // We allow more cols in db than in map because the db may be a future schema - if (ncols < ARRAY_SIZE(dbmfi_cols_map)) + if (ncols < size) { - DPRINTF(E_LOG, L_DB, "BUG: database has fewer columns (%d) than dbmfi column map (%u)\n", ncols, ARRAY_SIZE(dbmfi_cols_map)); + DPRINTF(E_LOG, L_DB, "BUG: database has fewer columns (%d) than column map (%u)\n", ncols, size); return -1; } - for (i = 0; i < ARRAY_SIZE(dbmfi_cols_map); i++) + for (i = 0; i < size; i++) { - strcol = (char **) ((char *)dbmfi + dbmfi_cols_map[i]); + strcol = (char **) ((char *)item + cols_map[i]); *strcol = (char *)sqlite3_column_text(qp->stmt, i); } @@ -2426,6 +2417,26 @@ db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi) return 0; } +int +db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi) +{ + int ret; + + memset(dbmfi, 0, sizeof(struct db_media_file_info)); + + if ((qp->type != Q_ITEMS) && (qp->type != Q_PLITEMS) && (qp->type != Q_GROUP_ITEMS)) + { + DPRINTF(E_LOG, L_DB, "Not an items, playlist or group items query!\n"); + return -1; + } + + ret = db_query_fetch(dbmfi, qp, dbmfi_cols_map, ARRAY_SIZE(dbmfi_cols_map)); + if (ret < 0) { + DPRINTF(E_LOG, L_DB, "Failed to fetch db_media_file_info\n"); + } + return ret; +} + int db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli) { @@ -2496,107 +2507,41 @@ db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli) int db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri) { - int ncols; - char **strcol; - int i; int ret; memset(dbgri, 0, sizeof(struct db_group_info)); - if (!qp->stmt) - { - DPRINTF(E_LOG, L_DB, "Query not started!\n"); - return -1; - } - if ((qp->type != Q_GROUP_ALBUMS) && (qp->type != Q_GROUP_ARTISTS)) { DPRINTF(E_LOG, L_DB, "Not a groups query!\n"); return -1; } - ret = db_blocking_step(qp->stmt); - if (ret == SQLITE_DONE) - { - DPRINTF(E_DBG, L_DB, "End of query results\n"); - return 1; - } - else if (ret != SQLITE_ROW) - { - DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl)); - return -1; - } - - ncols = sqlite3_column_count(qp->stmt); - - // We allow more cols in db than in map because the db may be a future schema - if (ncols < ARRAY_SIZE(dbgri_cols_map)) - { - DPRINTF(E_LOG, L_DB, "BUG: database has fewer columns (%d) than dbgri column map (%u)\n", ncols, ARRAY_SIZE(dbgri_cols_map)); - return -1; - } - - for (i = 0; i < ARRAY_SIZE(dbgri_cols_map); i++) - { - strcol = (char **) ((char *)dbgri + dbgri_cols_map[i]); - - *strcol = (char *)sqlite3_column_text(qp->stmt, i); - } - - return 0; + ret = db_query_fetch(dbgri, qp, dbgri_cols_map, ARRAY_SIZE(dbgri_cols_map)); + if (ret < 0) { + DPRINTF(E_LOG, L_DB, "Failed to fetch db_group_info\n"); + } + return ret; } int db_query_fetch_browse(struct query_params *qp, struct db_browse_info *dbbi) { - int ncols; - char **strcol; - int i; int ret; memset(dbbi, 0, sizeof(struct db_browse_info)); - if (!qp->stmt) - { - DPRINTF(E_LOG, L_DB, "Query not started!\n"); - return -1; - } - if (!(qp->type & Q_F_BROWSE)) { DPRINTF(E_LOG, L_DB, "Not a browse query!\n"); return -1; } - ret = db_blocking_step(qp->stmt); - if (ret == SQLITE_DONE) - { - DPRINTF(E_DBG, L_DB, "End of query results\n"); - return 1; - } - else if (ret != SQLITE_ROW) - { - DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl)); - return -1; - } - - ncols = sqlite3_column_count(qp->stmt); - - // We allow more cols in db than in map because the db may be a future schema - if (ncols < ARRAY_SIZE(dbbi_cols_map)) - { - DPRINTF(E_LOG, L_DB, "BUG: database has fewer columns (%d) than dbbi column map (%u)\n", ncols, ARRAY_SIZE(dbbi_cols_map)); - return -1; - } - - for (i = 0; i < ARRAY_SIZE(dbbi_cols_map); i++) - { - strcol = (char **) ((char *)dbbi + dbbi_cols_map[i]); - - *strcol = (char *)sqlite3_column_text(qp->stmt, i); - } - - return 0; + ret = db_query_fetch(dbbi, qp, dbbi_cols_map, ARRAY_SIZE(dbbi_cols_map)); + if (ret < 0) { + DPRINTF(E_LOG, L_DB, "Failed to fetch db_browse_info\n"); + } + return ret; } int @@ -5174,7 +5119,7 @@ db_queue_add_by_query(struct query_params *qp, char reshuffle, uint32_t item_id, goto end_transaction; } - while (((ret = db_query_fetch_file(qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(qp, &dbmfi)) == 0) { ret = queue_item_add_from_file(&dbmfi, pos, queue_count, queue_version); @@ -5195,6 +5140,9 @@ db_queue_add_by_query(struct query_params *qp, char reshuffle, uint32_t item_id, queue_count++; } + if (ret > 0) + ret = 0; + db_query_end(qp); if (ret < 0) diff --git a/src/httpd_daap.c b/src/httpd_daap.c index 9bc2eaee..f807aaea 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -1271,7 +1271,7 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist) nsongs = 0; last_codectype = NULL; - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { nsongs++; diff --git a/src/httpd_dacp.c b/src/httpd_dacp.c index 07c61ba4..cb6980fe 100644 --- a/src/httpd_dacp.c +++ b/src/httpd_dacp.c @@ -253,7 +253,7 @@ find_first_song_id(const char *query) goto no_query_start; } - if (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + if ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { ret = safe_atoi32(dbmfi.id, &id); if (ret < 0) @@ -264,7 +264,6 @@ find_first_song_id(const char *query) } DPRINTF(E_DBG, L_DACP, "Found index song (id %d)\n", id); - ret = 1; } else { @@ -280,7 +279,7 @@ find_first_song_id(const char *query) if (qp.filter) free(qp.filter); - if (ret == 1) + if (id > 0) return id; else return -1; diff --git a/src/httpd_jsonapi.c b/src/httpd_jsonapi.c index 9e4f99b4..36ac659a 100644 --- a/src/httpd_jsonapi.c +++ b/src/httpd_jsonapi.c @@ -458,7 +458,7 @@ fetch_tracks(struct query_params *query_params, json_object *items, int *total) if (ret < 0) goto error; - while (((ret = db_query_fetch_file(query_params, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(query_params, &dbmfi)) == 0) { item = track_to_json(&dbmfi); if (!item) @@ -3322,8 +3322,7 @@ jsonapi_reply_library_tracks_get_byid(struct httpd_request *hreq) ret = db_query_fetch_file(&query_params, &dbmfi); if (ret < 0) goto error; - - if (dbmfi.id == 0) + else if (ret == 1) { DPRINTF(E_LOG, L_WEB, "Track with id '%s' not found.\n", track_id); ret = -1; diff --git a/src/httpd_rsp.c b/src/httpd_rsp.c index ac126835..53bd95a4 100644 --- a/src/httpd_rsp.c +++ b/src/httpd_rsp.c @@ -588,7 +588,7 @@ rsp_reply_playlist(struct httpd_request *hreq) mxmlNewTextf(node, 0, "%d", qp.results); /* Items block (all items) */ - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { headers = evhttp_request_get_input_headers(hreq->req); diff --git a/src/inputs/pipe.c b/src/inputs/pipe.c index fbdd8c94..056ee550 100644 --- a/src/inputs/pipe.c +++ b/src/inputs/pipe.c @@ -982,7 +982,7 @@ pipelist_create(void) return NULL; head = NULL; - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { ret = safe_atoi32(dbmfi.id, &id); if (ret < 0) diff --git a/src/library/filescanner.c b/src/library/filescanner.c index 3dfe672d..556f1463 100644 --- a/src/library/filescanner.c +++ b/src/library/filescanner.c @@ -1909,7 +1909,7 @@ playlist_add_files(FILE *fp, int pl_id, const char *virtual_path) if (qp.results > 0) { - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { if ((safe_atou32(dbmfi.data_kind, &data_kind) < 0) || (data_kind == DATA_KIND_PIPE)) diff --git a/src/mpd.c b/src/mpd.c index d93f23f9..7faf92f9 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -2317,7 +2317,7 @@ mpd_command_listplaylist(struct evbuffer *evbuf, int argc, char **argv, char **e return ACK_ERROR_UNKNOWN; } - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { evbuffer_add_printf(evbuf, "file: %s\n", @@ -2380,7 +2380,7 @@ mpd_command_listplaylistinfo(struct evbuffer *evbuf, int argc, char **argv, char return ACK_ERROR_UNKNOWN; } - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { ret = mpd_add_db_media_file_info(evbuf, &dbmfi); if (ret < 0) @@ -2672,7 +2672,7 @@ mpd_command_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s return ACK_ERROR_UNKNOWN; } - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { ret = mpd_add_db_media_file_info(evbuf, &dbmfi); if (ret < 0) @@ -2777,7 +2777,7 @@ mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s return ACK_ERROR_UNKNOWN; } - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { strval = (char **) ((char *)&dbmfi + tagtype->mfi_offset); @@ -2917,7 +2917,7 @@ mpd_add_directory(struct evbuffer *evbuf, int directory_id, int listall, int lis *errmsg = safe_asprintf("Could not start query"); return ACK_ERROR_UNKNOWN; } - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { if (listinfo) { @@ -3140,7 +3140,7 @@ mpd_command_search(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, return ACK_ERROR_UNKNOWN; } - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { ret = mpd_add_db_media_file_info(evbuf, &dbmfi); if (ret < 0) @@ -3392,7 +3392,7 @@ mpd_sticker_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, c return ret; } - while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) { ret = safe_atou32(dbmfi.rating, &rating); if (ret < 0) From 8becdee8f15c30ce5354cd653e6b273adf45f01a Mon Sep 17 00:00:00 2001 From: chme Date: Tue, 28 Dec 2021 07:23:56 +0100 Subject: [PATCH 3/4] [db] Refactor db_query_fetch_* functions to take the output parameter first and the input parameter as last parameter --- src/artwork.c | 8 ++++---- src/db.c | 20 ++++++++++---------- src/db.h | 14 +++++++------- src/httpd_daap.c | 8 ++++---- src/httpd_dacp.c | 2 +- src/httpd_jsonapi.c | 18 +++++++++--------- src/httpd_rsp.c | 6 +++--- src/inputs/pipe.c | 2 +- src/library/filescanner.c | 2 +- src/library/filescanner_itunes.c | 2 +- src/library/filescanner_playlist.c | 2 +- src/library/rssscanner.c | 2 +- src/library/spotify_webapi.c | 2 +- src/mpd.c | 18 +++++++++--------- 14 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/artwork.c b/src/artwork.c index 4665a886..d72b7d46 100644 --- a/src/artwork.c +++ b/src/artwork.c @@ -1377,7 +1377,7 @@ source_group_dir_get(struct artwork_ctx *ctx) return ART_E_ERROR; } - while (((ret = db_query_fetch_string(&qp, &dir)) == 0) && (dir)) + while (((ret = db_query_fetch_string(&dir, &qp)) == 0) && (dir)) { /* The db query may return non-directories (eg if item is an internet stream or Spotify) */ if (access(dir, F_OK) < 0) @@ -1718,7 +1718,7 @@ source_item_ownpl_get(struct artwork_ctx *ctx) mfi_path = ctx->dbmfi->path; format = ART_E_NONE; - while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.id) && (format == ART_E_NONE)) + while (((ret = db_query_fetch_pl(&dbpli, &qp)) == 0) && (dbpli.id) && (format == ART_E_NONE)) { if (!dbpli.path) continue; @@ -1766,7 +1766,7 @@ process_items(struct artwork_ctx *ctx, int item_mode) return -1; } - while ((ret = db_query_fetch_file(&ctx->qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &ctx->qp)) == 0) { // Save the first songalbumid, might need it for process_group() if this search doesn't give anything if (!ctx->persistentid) @@ -1859,7 +1859,7 @@ process_group(struct artwork_ctx *ctx) goto invalid_group; } - is_valid = (db_query_fetch_file(&ctx->qp, &dbmfi) == 0 && strcmp(dbmfi.album, CFG_NAME_UNKNOWN_ALBUM) != 0 && strcmp(dbmfi.album_artist, CFG_NAME_UNKNOWN_ARTIST) != 0); + is_valid = (db_query_fetch_file(&dbmfi, &ctx->qp) == 0 && strcmp(dbmfi.album, CFG_NAME_UNKNOWN_ALBUM) != 0 && strcmp(dbmfi.album_artist, CFG_NAME_UNKNOWN_ARTIST) != 0); db_query_end(&ctx->qp); if (!is_valid) { diff --git a/src/db.c b/src/db.c index abd5f410..451a36f8 100644 --- a/src/db.c +++ b/src/db.c @@ -2418,7 +2418,7 @@ db_query_fetch(void *item, struct query_params *qp, const ssize_t cols_map[], in } int -db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi) +db_query_fetch_file(struct db_media_file_info *dbmfi, struct query_params *qp) { int ret; @@ -2438,7 +2438,7 @@ db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi) } int -db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli) +db_query_fetch_pl(struct db_playlist_info *dbpli, struct query_params *qp) { int ncols; char **strcol; @@ -2505,7 +2505,7 @@ db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli) } int -db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri) +db_query_fetch_group(struct db_group_info *dbgri, struct query_params *qp) { int ret; @@ -2525,7 +2525,7 @@ db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri) } int -db_query_fetch_browse(struct query_params *qp, struct db_browse_info *dbbi) +db_query_fetch_browse(struct db_browse_info *dbbi, struct query_params *qp) { int ret; @@ -2545,7 +2545,7 @@ db_query_fetch_browse(struct query_params *qp, struct db_browse_info *dbbi) } int -db_query_fetch_count(struct query_params *qp, struct filecount_info *fci) +db_query_fetch_count(struct filecount_info *fci, struct query_params *qp) { int ret; @@ -2596,7 +2596,7 @@ db_filecount_get(struct filecount_info *fci, struct query_params *qp) return -1; } - ret = db_query_fetch_count(qp, fci); + ret = db_query_fetch_count(fci, qp); if (ret < 0) { db_query_end(qp); @@ -2609,7 +2609,7 @@ db_filecount_get(struct filecount_info *fci, struct query_params *qp) } int -db_query_fetch_string(struct query_params *qp, char **string) +db_query_fetch_string(char **string, struct query_params *qp) { int ret; @@ -2640,7 +2640,7 @@ db_query_fetch_string(struct query_params *qp, char **string) } int -db_query_fetch_string_sort(struct query_params *qp, char **string, char **sortstring) +db_query_fetch_string_sort(char **string, char **sortstring, struct query_params *qp) { int ret; @@ -3863,7 +3863,7 @@ db_pl_delete_bypath(const char *path) return; } - while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.id)) + while (((ret = db_query_fetch_pl(&dbpli, &qp)) == 0) && (dbpli.id)) { if (safe_atoi32(dbpli.id, &id) != 0) continue; @@ -5119,7 +5119,7 @@ db_queue_add_by_query(struct query_params *qp, char reshuffle, uint32_t item_id, goto end_transaction; } - while ((ret = db_query_fetch_file(qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, qp)) == 0) { ret = queue_item_add_from_file(&dbmfi, pos, queue_count, queue_version); diff --git a/src/db.h b/src/db.h index eceb9db6..d3af83a4 100644 --- a/src/db.h +++ b/src/db.h @@ -603,25 +603,25 @@ void db_query_end(struct query_params *qp); int -db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi); +db_query_fetch_file(struct db_media_file_info *dbmfi, struct query_params *qp); int -db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli); +db_query_fetch_pl(struct db_playlist_info *dbpli, struct query_params *qp); int -db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri); +db_query_fetch_group(struct db_group_info *dbgri, struct query_params *qp); int -db_query_fetch_browse(struct query_params *qp, struct db_browse_info *dbbi); +db_query_fetch_browse(struct db_browse_info *dbbi, struct query_params *qp); int -db_query_fetch_count(struct query_params *qp, struct filecount_info *fci); +db_query_fetch_count(struct filecount_info *fci, struct query_params *qp); int -db_query_fetch_string(struct query_params *qp, char **string); +db_query_fetch_string(char **string, struct query_params *qp); int -db_query_fetch_string_sort(struct query_params *qp, char **string, char **sortstring); +db_query_fetch_string_sort(char **string, char **sortstring, struct query_params *qp); /* Files */ int diff --git a/src/httpd_daap.c b/src/httpd_daap.c index f807aaea..efea92d3 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -1271,7 +1271,7 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist) nsongs = 0; last_codectype = NULL; - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { nsongs++; @@ -1479,7 +1479,7 @@ daap_reply_playlists(struct httpd_request *hreq) } npls = 0; - while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.id)) + while (((ret = db_query_fetch_pl(&dbpli, &qp)) == 0) && (dbpli.id)) { plid = 1; if (safe_atoi32(dbpli.id, &plid) != 0) @@ -1705,7 +1705,7 @@ daap_reply_groups(struct httpd_request *hreq) } ngrp = 0; - while ((ret = db_query_fetch_group(&qp, &dbgri)) == 0) + while ((ret = db_query_fetch_group(&dbgri, &qp)) == 0) { /* Don't add item if no name (eg blank album name) */ if (strlen(dbgri.itemname) == 0) @@ -1901,7 +1901,7 @@ daap_reply_browse(struct httpd_request *hreq) } nitems = 0; - while (((ret = db_query_fetch_string_sort(&qp, &browse_item, &sort_item)) == 0) && (browse_item)) + while (((ret = db_query_fetch_string_sort(&browse_item, &sort_item, &qp)) == 0) && (browse_item)) { nitems++; diff --git a/src/httpd_dacp.c b/src/httpd_dacp.c index cb6980fe..e4a7e467 100644 --- a/src/httpd_dacp.c +++ b/src/httpd_dacp.c @@ -253,7 +253,7 @@ find_first_song_id(const char *query) goto no_query_start; } - if ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + if ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { ret = safe_atoi32(dbmfi.id, &id); if (ret < 0) diff --git a/src/httpd_jsonapi.c b/src/httpd_jsonapi.c index 36ac659a..ea9dab78 100644 --- a/src/httpd_jsonapi.c +++ b/src/httpd_jsonapi.c @@ -458,7 +458,7 @@ fetch_tracks(struct query_params *query_params, json_object *items, int *total) if (ret < 0) goto error; - while ((ret = db_query_fetch_file(query_params, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, query_params)) == 0) { item = track_to_json(&dbmfi); if (!item) @@ -490,7 +490,7 @@ fetch_artists(struct query_params *query_params, json_object *items, int *total) if (ret < 0) goto error; - while ((ret = db_query_fetch_group(query_params, &dbgri)) == 0) + while ((ret = db_query_fetch_group(&dbgri, query_params)) == 0) { /* Don't add item if no name (eg blank album name) */ if (strlen(dbgri.itemname) == 0) @@ -535,7 +535,7 @@ fetch_artist(bool *notfound, const char *artist_id) if (ret < 0) goto error; - if ((ret = db_query_fetch_group(&query_params, &dbgri)) == 0) + if ((ret = db_query_fetch_group(&dbgri, &query_params)) == 0) { artist = artist_to_json(&dbgri); notfound = false; @@ -559,7 +559,7 @@ fetch_albums(struct query_params *query_params, json_object *items, int *total) if (ret < 0) goto error; - while ((ret = db_query_fetch_group(query_params, &dbgri)) == 0) + while ((ret = db_query_fetch_group(&dbgri, query_params)) == 0) { /* Don't add item if no name (eg blank album name) */ if (strlen(dbgri.itemname) == 0) @@ -605,7 +605,7 @@ fetch_album(bool *notfound, const char *album_id) if (ret < 0) goto error; - if ((ret = db_query_fetch_group(&query_params, &dbgri)) == 0) + if ((ret = db_query_fetch_group(&dbgri, &query_params)) == 0) { album = album_to_json(&dbgri); *notfound = false; @@ -629,7 +629,7 @@ fetch_playlists(struct query_params *query_params, json_object *items, int *tota if (ret < 0) goto error; - while (((ret = db_query_fetch_pl(query_params, &dbpli)) == 0) && (dbpli.id)) + while (((ret = db_query_fetch_pl(&dbpli, query_params)) == 0) && (dbpli.id)) { item = playlist_to_json(&dbpli); if (!item) @@ -671,7 +671,7 @@ fetch_playlist(bool *notfound, uint32_t playlist_id) if (ret < 0) goto error; - if (((ret = db_query_fetch_pl(&query_params, &dbpli)) == 0) && (dbpli.id)) + if (((ret = db_query_fetch_pl(&dbpli, &query_params)) == 0) && (dbpli.id)) { playlist = playlist_to_json(&dbpli); *notfound = false; @@ -695,7 +695,7 @@ fetch_genres(struct query_params *query_params, json_object *items, int *total) if (ret < 0) goto error; - while (((ret = db_query_fetch_browse(query_params, &dbbi)) == 0) && (dbbi.track_count)) + while ((ret = db_query_fetch_browse(&dbbi, query_params)) == 0) { item = browse_info_to_json(&dbbi); if (!item) @@ -3319,7 +3319,7 @@ jsonapi_reply_library_tracks_get_byid(struct httpd_request *hreq) if (ret < 0) goto error; - ret = db_query_fetch_file(&query_params, &dbmfi); + ret = db_query_fetch_file(&dbmfi, &query_params); if (ret < 0) goto error; else if (ret == 1) diff --git a/src/httpd_rsp.c b/src/httpd_rsp.c index 53bd95a4..f0bcb961 100644 --- a/src/httpd_rsp.c +++ b/src/httpd_rsp.c @@ -441,7 +441,7 @@ rsp_reply_db(struct httpd_request *hreq) mxmlNewTextf(node, 0, "%d", qp.results); /* Playlists block (all playlists) */ - while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.id)) + while (((ret = db_query_fetch_pl(&dbpli, &qp)) == 0) && (dbpli.id)) { // Skip non-local playlists, can't be streamed to the device if (!dbpli.path || dbpli.path[0] != '/') @@ -588,7 +588,7 @@ rsp_reply_playlist(struct httpd_request *hreq) mxmlNewTextf(node, 0, "%d", qp.results); /* Items block (all items) */ - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { headers = evhttp_request_get_input_headers(hreq->req); @@ -772,7 +772,7 @@ rsp_reply_browse(struct httpd_request *hreq) mxmlNewTextf(node, 0, "%d", qp.results); /* Items block (all items) */ - while (((ret = db_query_fetch_string(&qp, &browse_item)) == 0) && (browse_item)) + while (((ret = db_query_fetch_string(&browse_item, &qp)) == 0) && (browse_item)) { node = mxmlNewElement(items, "item"); mxmlNewText(node, 0, browse_item); diff --git a/src/inputs/pipe.c b/src/inputs/pipe.c index 056ee550..c7d925f9 100644 --- a/src/inputs/pipe.c +++ b/src/inputs/pipe.c @@ -982,7 +982,7 @@ pipelist_create(void) return NULL; head = NULL; - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { ret = safe_atoi32(dbmfi.id, &id); if (ret < 0) diff --git a/src/library/filescanner.c b/src/library/filescanner.c index 556f1463..78714c40 100644 --- a/src/library/filescanner.c +++ b/src/library/filescanner.c @@ -1909,7 +1909,7 @@ playlist_add_files(FILE *fp, int pl_id, const char *virtual_path) if (qp.results > 0) { - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { if ((safe_atou32(dbmfi.data_kind, &data_kind) < 0) || (data_kind == DATA_KIND_PIPE)) diff --git a/src/library/filescanner_itunes.c b/src/library/filescanner_itunes.c index f955ce06..9fab84eb 100644 --- a/src/library/filescanner_itunes.c +++ b/src/library/filescanner_itunes.c @@ -390,7 +390,7 @@ mfi_id_find(const char *path) winner = NULL; score = 0; - while ((db_query_fetch_string(&qp, &dbpath) == 0) && dbpath) + while ((db_query_fetch_string(&dbpath, &qp) == 0) && dbpath) { if (qp.results == 1) { diff --git a/src/library/filescanner_playlist.c b/src/library/filescanner_playlist.c index ae040409..ca4cd7cb 100644 --- a/src/library/filescanner_playlist.c +++ b/src/library/filescanner_playlist.c @@ -317,7 +317,7 @@ process_regular_file(int pl_id, char *path) winner = NULL; score = 0; - while ((db_query_fetch_string(&qp, &dbpath) == 0) && dbpath) + while ((db_query_fetch_string(&dbpath, &qp) == 0) && dbpath) { if (qp.results == 1) { diff --git a/src/library/rssscanner.c b/src/library/rssscanner.c index 88b63dbb..0345c7a2 100644 --- a/src/library/rssscanner.c +++ b/src/library/rssscanner.c @@ -568,7 +568,7 @@ rss_scan_all(enum rss_scan_type scan_type) } count = 0; - while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.path)) + while (((ret = db_query_fetch_pl(&dbpli, &qp)) == 0) && (dbpli.path)) { ret = rss_scan(dbpli.path, scan_type); if (ret == 0) diff --git a/src/library/spotify_webapi.c b/src/library/spotify_webapi.c index 0b9d645a..2df6db1f 100644 --- a/src/library/spotify_webapi.c +++ b/src/library/spotify_webapi.c @@ -1508,7 +1508,7 @@ cleanup_spotify_files(void) return -1; } - while (((ret = db_query_fetch_string(&qp, &path)) == 0) && (path)) + while (((ret = db_query_fetch_string(&path, &qp)) == 0) && (path)) { cache_artwork_delete_by_path(path); } diff --git a/src/mpd.c b/src/mpd.c index 7faf92f9..add34da8 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -2317,7 +2317,7 @@ mpd_command_listplaylist(struct evbuffer *evbuf, int argc, char **argv, char **e return ACK_ERROR_UNKNOWN; } - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { evbuffer_add_printf(evbuf, "file: %s\n", @@ -2380,7 +2380,7 @@ mpd_command_listplaylistinfo(struct evbuffer *evbuf, int argc, char **argv, char return ACK_ERROR_UNKNOWN; } - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { ret = mpd_add_db_media_file_info(evbuf, &dbmfi); if (ret < 0) @@ -2426,7 +2426,7 @@ mpd_command_listplaylists(struct evbuffer *evbuf, int argc, char **argv, char ** return ACK_ERROR_UNKNOWN; } - while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.id)) + while (((ret = db_query_fetch_pl(&dbpli, &qp)) == 0) && (dbpli.id)) { if (safe_atou32(dbpli.db_timestamp, &time_modified) != 0) { @@ -2672,7 +2672,7 @@ mpd_command_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s return ACK_ERROR_UNKNOWN; } - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { ret = mpd_add_db_media_file_info(evbuf, &dbmfi); if (ret < 0) @@ -2777,7 +2777,7 @@ mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s return ACK_ERROR_UNKNOWN; } - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { strval = (char **) ((char *)&dbmfi + tagtype->mfi_offset); @@ -2843,7 +2843,7 @@ mpd_add_directory(struct evbuffer *evbuf, int directory_id, int listall, int lis *errmsg = safe_asprintf("Could not start query"); return ACK_ERROR_UNKNOWN; } - while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.id)) + while (((ret = db_query_fetch_pl(&dbpli, &qp)) == 0) && (dbpli.id)) { if (safe_atou32(dbpli.db_timestamp, &time_modified) != 0) { @@ -2917,7 +2917,7 @@ mpd_add_directory(struct evbuffer *evbuf, int directory_id, int listall, int lis *errmsg = safe_asprintf("Could not start query"); return ACK_ERROR_UNKNOWN; } - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { if (listinfo) { @@ -3140,7 +3140,7 @@ mpd_command_search(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, return ACK_ERROR_UNKNOWN; } - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { ret = mpd_add_db_media_file_info(evbuf, &dbmfi); if (ret < 0) @@ -3392,7 +3392,7 @@ mpd_sticker_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, c return ret; } - while ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) + while ((ret = db_query_fetch_file(&dbmfi, &qp)) == 0) { ret = safe_atou32(dbmfi.rating, &rating); if (ret < 0) From 8dfbb460c279cb69168b9daa543a9f24b159be16 Mon Sep 17 00:00:00 2001 From: chme Date: Wed, 29 Dec 2021 12:01:42 +0100 Subject: [PATCH 4/4] [db/readme] Add comment to browse_info object; update docs for genre endpoint --- README_JSON_API.md | 12 +++++++++--- src/db.h | 4 ++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README_JSON_API.md b/README_JSON_API.md index 43cb3ed4..f3d1d164 100644 --- a/README_JSON_API.md +++ b/README_JSON_API.md @@ -1677,7 +1677,7 @@ GET /api/library/genres | Key | Type | Value | | --------------- | -------- | ----------------------------------------- | -| items | array | Array of [`genre`](#genre-object) objects | +| items | array | Array of [`browse-info`](#browse-info-object) objects | | total | integer | Total number of genres in the library | | offset | integer | Requested offset of the first genre | | limit | integer | Requested maximum number of genres | @@ -2604,11 +2604,17 @@ curl --include \ | limit | integer | Requested maximum number of items | -### `genre` object +### `browse-info` object | Key | Type | Value | | --------------- | -------- | ----------------------------------------- | -| name | string | Name of genre | +| name | string | Name (depends on the type of the query) | +| name_sort | string | Sort name | +| artist_count | integer | Number of artists | +| album_count | integer | Number of albums | +| track_count | integer | Number of tracks | +| time_played | string | Timestamp in `ISO 8601` format | +| time_added | string | Timestamp in `ISO 8601` format | ### `directory` object diff --git a/src/db.h b/src/db.h index d3af83a4..5d272c65 100644 --- a/src/db.h +++ b/src/db.h @@ -409,6 +409,10 @@ struct db_media_file_info { #define dbmfi_offsetof(field) offsetof(struct db_media_file_info, field) +/* Info object for generic browse queries that want more info than just + * the item string and sort string (e. g. for genre or compose queries + * that want to display the total track / album count). + */ struct db_browse_info { char *itemname; char *itemname_sort;