[library/db/jsonapi] Refactor adding items to queue via JSON API v2

This commit is contained in:
ejurgensen 2023-12-03 20:55:37 +01:00
parent 1ea90b9445
commit 5ea49c94de
8 changed files with 89 additions and 120 deletions

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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, &param);
}

View File

@ -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

View File

@ -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]);

View File

@ -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;
}