From 5ea49c94de59b8415b2c11b72f76ace7fcb549b2 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Sun, 3 Dec 2023 20:55:37 +0100 Subject: [PATCH] [library/db/jsonapi] Refactor adding items to queue via JSON API v2 --- src/db.c | 83 ++++++++------------------------------- src/db.h | 12 ------ src/httpd_dacp.c | 8 ++-- src/httpd_jsonapi.c | 64 +++++++++++++++++------------- src/library.c | 6 ++- src/library/filescanner.c | 21 ++++++++-- src/mpd.c | 7 +++- src/player.c | 8 +++- 8 files changed, 89 insertions(+), 120 deletions(-) diff --git a/src/db.c b/src/db.c index c86bb66f..1f33a842 100644 --- a/src/db.c +++ b/src/db.c @@ -1969,6 +1969,8 @@ db_free_query_clause(struct query_clause *qc) free(qc); } +// Builds the generic parts of the query. Parts that are specific to the query +// type are in db_build_query_* implementations. static struct query_clause * db_build_query_clause(struct query_params *qp) { @@ -2076,8 +2078,21 @@ db_build_query_items(struct query_params *qp, struct query_clause *qc) char *count; char *query; - count = sqlite3_mprintf("SELECT COUNT(*) FROM files f %s;", qc->where); - query = sqlite3_mprintf("SELECT f.* FROM files f %s %s %s %s;", qc->where, qc->group, qc->order, qc->index); + if (qp->id == 0) + { + count = sqlite3_mprintf("SELECT COUNT(*) FROM files f %s;", qc->where); + query = sqlite3_mprintf("SELECT f.* FROM files f %s %s %s %s;", qc->where, qc->group, qc->order, qc->index); + } + else if (qc->where[0] == '\0') + { + count = sqlite3_mprintf("SELECT COUNT(*) FROM files f WHERE f.id = %d;", qp->id); + query = sqlite3_mprintf("SELECT f.* FROM files f WHERE f.id = %d %s %s %s;", qp->id, qc->group, qc->order, qc->index); + } + else + { + count = sqlite3_mprintf("SELECT COUNT(*) FROM files f %s AND f.id = %d;", qc->where, qp->id); + query = sqlite3_mprintf("SELECT f.* FROM files f %s AND f.id = %d %s %s %s;", qc->where, qp->id, qc->group, qc->order, qc->index); + } return db_build_query_check(qp, count, query); } @@ -5274,70 +5289,6 @@ db_queue_add_by_query(struct query_params *qp, char reshuffle, uint32_t item_id, return ret; } -/* - * Adds the file with the given id to the queue - * - * @param id Id of the file - * @param reshuffle If 1 queue will be reshuffled after adding new items - * @param item_id The base item id, all items after this will be reshuffled - * @param position The position in the queue for the new queue item, -1 to add at end of queue - * @param count If not NULL returns the number of items added to the queue - * @param new_item_id If not NULL return the queue item id of the first new queue item - * @return 0 on success, -1 on failure - */ -int -db_queue_add_by_fileid(int id, char reshuffle, uint32_t item_id, int position, int *count, int *new_item_id) -{ - struct query_params qp = { .type = Q_ITEMS, .idx_type = I_NONE }; - char buf[124]; - - snprintf(buf, sizeof(buf), "f.id = %" PRIu32, id); - qp.filter = buf; - - return db_queue_add_by_query(&qp, reshuffle, item_id, position, count, new_item_id); -} - -/* - * Adds the artist with the given id to the queue, see db_queue_add_by_fileid() - */ -int -db_queue_add_by_artistid(int64_t id, char reshuffle, uint32_t item_id, int position, int *count, int *new_item_id) -{ - struct query_params qp = { .type = Q_ITEMS, .idx_type = I_NONE, .sort = S_ALBUM }; - char buf[124]; - - snprintf(buf, sizeof(buf), "f.songartistid = %" PRIi64, id); - qp.filter = buf; - - return db_queue_add_by_query(&qp, reshuffle, item_id, position, count, new_item_id); -} - -/* - * Adds the artist with the given id to the queue, see db_queue_add_by_fileid() - */ -int -db_queue_add_by_albumid(int64_t id, char reshuffle, uint32_t item_id, int position, int *count, int *new_item_id) -{ - struct query_params qp = { .type = Q_ITEMS, .idx_type = I_NONE, .sort = S_ALBUM }; - char buf[124]; - - snprintf(buf, sizeof(buf), "f.songalbumid = %" PRIi64, id); - qp.filter = buf; - - return db_queue_add_by_query(&qp, reshuffle, item_id, position, count, new_item_id); -} - -/* - * Adds the playlist with the given id to the queue, see db_queue_add_by_fileid() - */ -int -db_queue_add_by_playlistid(int plid, char reshuffle, uint32_t item_id, int position, int *count, int *new_item_id) -{ - struct query_params qp = { .type = Q_PLITEMS, .id = plid }; - - return db_queue_add_by_query(&qp, reshuffle, item_id, position, count, new_item_id); -} - static int queue_enum_start(struct query_params *qp) { diff --git a/src/db.h b/src/db.h index 7c8af5be..fc4d7e7a 100644 --- a/src/db.h +++ b/src/db.h @@ -901,18 +901,6 @@ db_queue_add_by_queryafteritemid(struct query_params *qp, uint32_t item_id); int db_queue_add_by_query(struct query_params *qp, char reshuffle, uint32_t item_id, int position, int *count, int *new_item_id); -int -db_queue_add_by_fileid(int id, char reshuffle, uint32_t item_id, int position, int *count, int *new_item_id); - -int -db_queue_add_by_artistid(int64_t songartistid, char reshuffle, uint32_t item_id, int position, int *count, int *new_item_id); - -int -db_queue_add_by_albumid(int64_t songalbumid, char reshuffle, uint32_t item_id, int position, int *count, int *new_item_id); - -int -db_queue_add_by_playlistid(int plid, char reshuffle, uint32_t item_id, int position, int *count, int *new_item_id); - int db_queue_add_start(struct db_queue_add_info *queue_add_info, int pos); diff --git a/src/httpd_dacp.c b/src/httpd_dacp.c index f8ec8c9d..c4d23146 100644 --- a/src/httpd_dacp.c +++ b/src/httpd_dacp.c @@ -1397,6 +1397,7 @@ dacp_reply_playspec(struct httpd_request *hreq) const char *shuffle; uint32_t plid; uint32_t id; + struct query_params qp = { 0 }; struct db_queue_item *queue_item = NULL; int ret; @@ -1482,11 +1483,10 @@ dacp_reply_playspec(struct httpd_request *hreq) db_queue_clear(0); - if (plid > 0) - ret = db_queue_add_by_playlistid(plid, status.shuffle, status.item_id, -1, NULL, NULL); - else if (id > 0) - ret = db_queue_add_by_fileid(id, status.shuffle, status.item_id, -1, NULL, NULL); + qp.type = (plid > 0) ? Q_PLITEMS : Q_ITEMS; + qp.id = (plid > 0) ? plid : id; + ret = db_queue_add_by_query(&qp, status.shuffle, status.item_id, -1, NULL, NULL); if (ret < 0) { DPRINTF(E_LOG, L_DACP, "Could not build song queue from playlist %d\n", plid); diff --git a/src/httpd_jsonapi.c b/src/httpd_jsonapi.c index 1074c803..1c496122 100644 --- a/src/httpd_jsonapi.c +++ b/src/httpd_jsonapi.c @@ -2228,9 +2228,8 @@ queue_item_to_json(struct db_queue_item *queue_item, char shuffle) } static int -queue_tracks_add_byuris(const char *param, int pos, int *total_count, int *new_item_id) +queue_tracks_add_byuris(const char *param, char shuffle, uint32_t item_id, int pos, int *total_count, int *new_item_id) { - struct player_status status; char *uris; const char *uri; char *ptr; @@ -2250,24 +2249,20 @@ queue_tracks_add_byuris(const char *param, int pos, int *total_count, int *new_i goto error; } - player_get_status(&status); - for (; uri; uri = strtok_r(NULL, ",", &ptr)) { - ret = library_queue_item_add(uri, pos, status.shuffle, status.item_id, &count, &new); + ret = library_queue_item_add(uri, pos, shuffle, item_id, &count, &new); if (ret != LIBRARY_OK) { DPRINTF(E_LOG, L_WEB, "Invalid uri '%s'\n", uri); goto error; } + *total_count += count; if (pos >= 0) pos += count; - - *new_item_id = (*new_item_id == -1) ? new : MIN(*new_item_id, new); - *total_count += count; - - DPRINTF(E_DBG, L_WEB, "pos %d, count %d, new %d, new_item_id %d\n", pos, count, new, *new_item_id); + if (*new_item_id == -1) + *new_item_id = new; } free(uris); @@ -2279,12 +2274,11 @@ queue_tracks_add_byuris(const char *param, int pos, int *total_count, int *new_i } static int -queue_tracks_add_byexpression(const char *param, int pos, int limit, int *total_count, int *new_item_id) +queue_tracks_add_byexpression(const char *param, char shuffle, uint32_t item_id, int pos, int limit, int *total_count, int *new_item_id) { struct query_params query_params = { .type = Q_ITEMS, .sort = S_NAME }; struct smartpl smartpl_expression = { 0 }; char *expression; - struct player_status status; int ret; expression = safe_asprintf("\"query\" { %s }", param); @@ -2300,14 +2294,32 @@ queue_tracks_add_byexpression(const char *param, int pos, int limit, int *total_ query_params.idx_type = query_params.limit > 0 ? I_FIRST : I_NONE; free_smartpl(&smartpl_expression, 1); - player_get_status(&status); - - ret = db_queue_add_by_query(&query_params, status.shuffle, status.item_id, pos, total_count, new_item_id); + ret = db_queue_add_by_query(&query_params, shuffle, item_id, pos, total_count, new_item_id); free_query_params(&query_params, 1); return ret; } +static int +create_reply_queue_tracks_add(struct evbuffer *evbuf, int count, int new_item_id, char shuffle) +{ + json_object *reply = json_object_new_object(); + int ret; + + json_object_object_add(reply, "count", json_object_new_int(count)); + + ret = evbuffer_add_printf(evbuf, "%s", json_object_to_json_string(reply)); + if (ret < 0) + goto error; + + jparse_free(reply); + return 0; + + error: + jparse_free(reply); + return -1; +} + static int jsonapi_reply_queue_tracks_add(struct httpd_request *hreq) { @@ -2315,12 +2327,12 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq) const char *param_uris; const char *param_expression; const char *param; + struct player_status status; int pos; int limit; bool shuffle; int total_count = 0; int new_item_id = 0; - json_object *reply; int ret = 0; @@ -2365,29 +2377,25 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq) player_shuffle_set(shuffle); } + player_get_status(&status); + if (param_uris) { - ret = queue_tracks_add_byuris(param_uris, pos, &total_count, &new_item_id); + ret = queue_tracks_add_byuris(param_uris, status.shuffle, status.item_id, pos, &total_count, &new_item_id); } else { // This overrides the value specified in query param = httpd_query_value_find(hreq->query, "limit"); if (param && safe_atoi32(param, &limit) == 0) - ret = queue_tracks_add_byexpression(param_expression, pos, limit, &total_count, &new_item_id); + ret = queue_tracks_add_byexpression(param_expression, status.shuffle, status.item_id, pos, limit, &total_count, &new_item_id); else - ret = queue_tracks_add_byexpression(param_expression, pos, -1, &total_count, &new_item_id); - } - - if (ret == 0) - { - reply = json_object_new_object(); - json_object_object_add(reply, "count", json_object_new_int(total_count)); - - ret = evbuffer_add_printf(hreq->out_body, "%s", json_object_to_json_string(reply)); - jparse_free(reply); + ret = queue_tracks_add_byexpression(param_expression, status.shuffle, status.item_id, pos, -1, &total_count, &new_item_id); } + if (ret < 0) + return HTTP_INTERNAL; + ret = create_reply_queue_tracks_add(hreq->out_body, total_count, new_item_id, status.shuffle); if (ret < 0) return HTTP_INTERNAL; diff --git a/src/library.c b/src/library.c index 9797da93..8ea5d681 100644 --- a/src/library.c +++ b/src/library.c @@ -842,6 +842,8 @@ int library_queue_item_add(const char *path, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id) { struct queue_item_add_param param; + int count_internal; + int new_item_id_internal; if (library_is_scanning()) return -1; @@ -850,8 +852,8 @@ library_queue_item_add(const char *path, int position, char reshuffle, uint32_t param.position = position; param.reshuffle = reshuffle; param.item_id = item_id; - param.count = count; - param.new_item_id = new_item_id; + param.count = count ? count : &count_internal; + param.new_item_id = new_item_id ? new_item_id : &new_item_id_internal; return commands_exec_sync(cmdbase, queue_item_add, NULL, ¶m); } diff --git a/src/library/filescanner.c b/src/library/filescanner.c index 379ac769..5b12bbbd 100644 --- a/src/library/filescanner.c +++ b/src/library/filescanner.c @@ -1722,36 +1722,49 @@ filescanner_fullrescan() static int queue_item_file_add(const char *sub_uri, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id) { + struct query_params query_params = { 0 }; int64_t id; if (strncmp(sub_uri, "artist:", strlen("artist:")) == 0) { if (safe_atoi64(sub_uri + (strlen("artist:")), &id) < 0) return -1; - return db_queue_add_by_artistid(id, reshuffle, item_id, position, count, new_item_id); + + query_params.type = Q_GROUP_ITEMS; + query_params.sort = S_ALBUM; + query_params.persistentid = id; } else if (strncmp(sub_uri, "album:", strlen("album:")) == 0) { if (safe_atoi64(sub_uri + (strlen("album:")), &id) < 0) return -1; - return db_queue_add_by_albumid(id, reshuffle, item_id, position, count, new_item_id); + + query_params.type = Q_GROUP_ITEMS; + query_params.sort = S_ALBUM; + query_params.persistentid = id; } else if (strncmp(sub_uri, "track:", strlen("track:")) == 0) { if (safe_atoi64(sub_uri + (strlen("track:")), &id) < 0) return -1; - return db_queue_add_by_fileid((int)id, reshuffle, item_id, position, count, new_item_id); + + query_params.type = Q_ITEMS; + query_params.id = id; } else if (strncmp(sub_uri, "playlist:", strlen("playlist:")) == 0) { if (safe_atoi64(sub_uri + (strlen("playlist:")), &id) < 0) return -1; - return db_queue_add_by_playlistid((int)id, reshuffle, item_id, position, count, new_item_id); + + query_params.type = Q_PLITEMS; + query_params.id = id; } else { return -1; } + + return db_queue_add_by_query(&query_params, reshuffle, item_id, position, count, new_item_id); } static int diff --git a/src/mpd.c b/src/mpd.c index 8c459269..fe0bb968 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -2461,6 +2461,7 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s char *path; struct playlist_info *pli; struct player_status status; + struct query_params qp = { .type = Q_PLITEMS }; int ret; if (!default_pl_dir || strstr(argv[1], ":/")) @@ -2484,10 +2485,12 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s //TODO If a second parameter is given only add the specified range of songs to the playqueue + qp.id = pli->id; + free_pli(pli, 0); + player_get_status(&status); - ret = db_queue_add_by_playlistid(pli->id, status.shuffle, status.item_id, -1, NULL, NULL); - free_pli(pli, 0); + ret = db_queue_add_by_query(&qp, status.shuffle, status.item_id, -1, NULL, NULL); if (ret < 0) { *errmsg = safe_asprintf("Failed to add song '%s' to playlist", argv[1]); diff --git a/src/player.c b/src/player.c index 5b7e3c6c..7147a0e9 100644 --- a/src/player.c +++ b/src/player.c @@ -2118,9 +2118,11 @@ playback_start_item(void *arg, int *retval) static enum command_state playback_start_id(void *arg, int *retval) { + struct query_params qp = { .type = Q_ITEMS }; struct db_queue_item *queue_item = NULL; union player_arg *cmdarg = arg; enum command_state cmd_state; + int new_item_id; int ret; *retval = -1; @@ -2129,11 +2131,13 @@ playback_start_id(void *arg, int *retval) { db_queue_clear(0); - ret = db_queue_add_by_fileid(cmdarg->id, 0, 0, -1, NULL, NULL); + qp.id = cmdarg->id; + + ret = db_queue_add_by_query(&qp, 0, 0, -1, NULL, &new_item_id); if (ret < 0) return COMMAND_END; - queue_item = db_queue_fetch_byfileid(cmdarg->id); + queue_item = db_queue_fetch_byitemid(new_item_id); if (!queue_item) return COMMAND_END; }