From a4c16741d9b88791025491fd8fa97f30a782cb94 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Thu, 21 Nov 2013 23:33:03 +0100 Subject: [PATCH] Better support for playqueue-edit (command add, mode 1) - reply message not fixed --- src/daap_query.gperf | 1 + src/httpd_dacp.c | 149 ++++++++++++++++++++++++++----------------- src/player.c | 149 ++++++++++++++++++++++++++++++++++++++++--- src/player.h | 5 +- 4 files changed, 232 insertions(+), 72 deletions(-) diff --git a/src/daap_query.gperf b/src/daap_query.gperf index fb61d635..89f4d6c3 100644 --- a/src/daap_query.gperf +++ b/src/daap_query.gperf @@ -12,6 +12,7 @@ struct dmap_query_field_map; %% "dmap.itemname", "f.title", 0 "dmap.itemid", "f.id", 1 +"dmap.containeritemid", "f.id", 1 "daap.songalbum", "f.album", 0 "daap.songalbumid", "f.songalbumid", 1 "daap.songartist", "f.album_artist", 0 diff --git a/src/httpd_dacp.c b/src/httpd_dacp.c index 43f81197..431ab13c 100644 --- a/src/httpd_dacp.c +++ b/src/httpd_dacp.c @@ -733,8 +733,8 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u { sort = evhttp_find_header(query, "sort"); - ps = player_queue_make_daap(cuequery, sort); - if (!ps) + ret = player_queue_make_daap(&ps, cuequery, NULL, sort); + if (ret < 0) { DPRINTF(E_LOG, L_DACP, "Could not build song queue\n"); @@ -1238,18 +1238,85 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf, httpd_send_reply(req, HTTP_OK, "OK", evbuf); } +static void +dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) +{ + struct player_source *ps; + const char *editquery; + const char *queuefilter; + const char *sort; + const char *param; + uint32_t idx; + int mode; + int ret; + + param = evhttp_find_header(query, "mode"); + if (param) + { + ret = safe_atoi32(param, &mode); + if (ret < 0) + { + DPRINTF(E_LOG, L_DACP, "Invalid mode value in playqueue-edit request\n"); + + dmap_send_error(req, "cmst", "Invalid mode value in playqueue-edit request"); + return; + } + } + + if (mode == 1) + { + player_playback_stop(); + player_queue_clear(); + } + + editquery = evhttp_find_header(query, "query"); + if (editquery) + { + queuefilter = evhttp_find_header(query, "queuefilter"); + sort = evhttp_find_header(query, "sort"); + + ret = player_queue_make_daap(&ps, editquery, queuefilter, sort); + if (ret < 0) + { + DPRINTF(E_LOG, L_DACP, "Could not build song queue\n"); + + dmap_send_error(req, "cmst", "Could not build song queue"); + return; + } + + idx = ret; + + player_queue_add(ps); + } + else + { + DPRINTF(E_LOG, L_DACP, "Could not add song queue, DACP query missing\n"); + + dmap_send_error(req, "cmst", "Could not add song queue, DACP query missing"); + return; + } + + /* + param = evhttp_find_header(query, "dacp.shufflestate"); + if (param) + dacp_propset_shufflestate(param, NULL);*/ + + DPRINTF(E_DBG, L_DACP, "Song queue built, playback starting at index %" PRIu32 "\n", idx); + ret = player_playback_start(&idx); + if (ret < 0) + { + DPRINTF(E_LOG, L_DACP, "Could not start playback\n"); + + dmap_send_error(req, "cmst", "Playback failed to start"); + return; + } +} + static void dacp_reply_playqueueedit(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) { struct daap_session *s; - struct player_status status; - struct player_source *ps; - const char *cuequery; - const char *sort; const char *param; - uint32_t id; - int mode; - int ret; /* Variations of /ctrl-int/1/playqueue-edit and expected behaviour User selected play (album or artist tab): @@ -1285,64 +1352,26 @@ dacp_reply_playqueueedit(struct evhttp_request *req, struct evbuffer *evbuf, cha if (!s) return; - param = evhttp_find_header(query, "mode"); - if (param) + param = evhttp_find_header(query, "command"); + if (!param) { - ret = safe_atoi32(param, &mode); - if (ret < 0) - DPRINTF(E_LOG, L_DACP, "Invalid mode value in playqueue-edit request\n"); - else if (mode == 1) - { - player_playback_stop(); + DPRINTF(E_LOG, L_DACP, "No command in playqueue-edit request\n"); - player_queue_clear(); - } + dmap_send_error(req, "cmst", "No command in cue request"); + return; } - cuequery = evhttp_find_header(query, "query"); - if (cuequery) - { - sort = evhttp_find_header(query, "sort"); - - ps = player_queue_make_daap(cuequery, sort); - if (!ps) - { - DPRINTF(E_LOG, L_DACP, "Could not build song queue\n"); - - dmap_send_error(req, "cmst", "Could not build song queue"); - return; - } - - player_queue_add(ps); - } + if (strcmp(param, "clear") == 0) + dacp_reply_cue_clear(req, evbuf, uri, query); // TODO this might give wrong reply container + else if (strcmp(param, "playnow") == 0) + dacp_reply_cue_play(req, evbuf, uri, query); // TODO this might give wrong reply container + else if (strcmp(param, "add") == 0) + dacp_reply_playqueueedit_add(req, evbuf, uri, query); else { - player_get_status(&status); + DPRINTF(E_LOG, L_DACP, "Unknown playqueue-edit command %s\n", param); - if (status.status != PLAY_STOPPED) - player_playback_stop(); - } - - /* - param = evhttp_find_header(query, "dacp.shufflestate"); - if (param) - dacp_propset_shufflestate(param, NULL);*/ - - id = 0; - param = evhttp_find_header(query, "index"); - if (param) - { - ret = safe_atou32(param, &id); - if (ret < 0) - DPRINTF(E_LOG, L_DACP, "Invalid index (%s) in playqueue-edit request\n", param); - } - - ret = player_playback_start(&id); - if (ret < 0) - { - DPRINTF(E_LOG, L_DACP, "Could not start playback\n"); - - dmap_send_error(req, "cmst", "Playback failed to start"); + dmap_send_error(req, "cmst", "Unknown command in cue request"); return; } } diff --git a/src/player.c b/src/player.c index b82fe86a..68483cff 100644 --- a/src/player.c +++ b/src/player.c @@ -635,32 +635,163 @@ player_queue_make(struct query_params *qp, const char *sort) return q_head; } -/* Thread: httpd (DACP) */ -struct player_source * -player_queue_make_daap(const char *query, const char *sort) +static int +fetch_first_query_match(const char *query, struct db_media_file_info *dbmfi) { struct query_params qp; - struct player_source *ps; + uint32_t id; + int ret; memset(&qp, 0, sizeof(struct query_params)); qp.type = Q_ITEMS; + qp.idx_type = I_FIRST; + qp.sort = S_NONE; qp.offset = 0; - qp.limit = 0; - + qp.limit = 1; qp.filter = daap_query_parse_sql(query); if (!qp.filter) { DPRINTF(E_LOG, L_PLAYER, "Improper DAAP query!\n"); - return NULL; + return -1; + } + + ret = db_query_start(&qp); + if (ret < 0) + { + DPRINTF(E_LOG, L_PLAYER, "Could not start query\n"); + + goto no_query_start; + } + + if (((ret = db_query_fetch_file(&qp, dbmfi)) == 0) && (dbmfi->id)) + { + ret = safe_atou32(dbmfi->id, &id); + if (ret < 0) + { + DPRINTF(E_LOG, L_PLAYER, "Invalid song id in query result!\n"); + + goto no_result; + } + + DPRINTF(E_DBG, L_PLAYER, "Found index song\n"); + ret = 1; + } + else + { + DPRINTF(E_LOG, L_PLAYER, "No song matches query (num %d): %s\n", qp.results, qp.filter); + + goto no_result; + } + + no_result: + db_query_end(&qp); + + no_query_start: + if (qp.filter) + free(qp.filter); + if (ret == 1) + return 0; + else + return -1; +} + + +/* Thread: httpd (DACP) */ +int +player_queue_make_daap(struct player_source **head, const char *query, const char *queuefilter, const char *sort) +{ + struct query_params qp; + struct player_source *ps; + struct db_media_file_info dbmfi; + uint32_t id; + int64_t albumid; + int plid; + int idx; + int ret; + char buf[200]; + + /* If query doesn't give even a single result give up */ + ret = fetch_first_query_match(query, &dbmfi); + if (ret < 0) + return -1; + + memset(&qp, 0, sizeof(struct query_params)); + + qp.offset = 0; + qp.limit = 0; + + id = 0; + + if (queuefilter) + { + safe_atou32(dbmfi.id, &id); + if ((strlen(queuefilter) > 6) && (strncmp(queuefilter, "album:", 6) == 0)) + { + qp.type = Q_ITEMS; + ret = safe_atoi64(strchr(queuefilter, ':') + 1, &albumid); + if (ret < 0) + { + DPRINTF(E_LOG, L_PLAYER, "Invalid album id in queuefilter: %s\n", queuefilter); + + return -1; + } + snprintf(buf, sizeof(buf), "f.songalbumid = %" PRIi64, albumid); + qp.filter = strdup(buf); + } + else if ((strlen(queuefilter) > 9) && (strncmp(queuefilter, "playlist:", 9) == 0)) + { + qp.type = Q_PLITEMS; + ret = safe_atoi32(strchr(queuefilter, ':') + 1, &plid); + if (ret < 0) + { + DPRINTF(E_LOG, L_PLAYER, "Invalid playlist id in queuefilter: %s\n", queuefilter); + + return -1; + } + qp.id = plid; + qp.filter = strdup("1 = 1"); + } + else + { + DPRINTF(E_LOG, L_PLAYER, "Unknown queuefilter: %s\n", queuefilter); + + return -1; + } + } + else if (strstr(query, "dmap.itemid:") && dbmfi.album_artist) + { + safe_atou32(dbmfi.id, &id); + qp.type = Q_ITEMS; + snprintf(buf, sizeof(buf), "f.album_artist = \"%s\"", dbmfi.album_artist); + qp.filter = strdup(buf); + } + else + { + id = 0; + qp.type = Q_ITEMS; + qp.filter = daap_query_parse_sql(query); } ps = player_queue_make(&qp, sort); - free(qp.filter); + if (qp.filter) + free(qp.filter); - return ps; + if (ps) + *head = ps; + else + return -1; + + idx = 0; + while (id && ps && ps->pl_next && (ps->id != id) && (ps->pl_next != *head)) + { + idx++; + ps = ps->pl_next; + } + + return idx; } struct player_source * diff --git a/src/player.h b/src/player.h index f477def0..bbdfa415 100644 --- a/src/player.h +++ b/src/player.h @@ -123,9 +123,8 @@ player_repeat_set(enum repeat_mode mode); int player_shuffle_set(int enable); - -struct player_source * -player_queue_make_daap(const char *query, const char *sort); +int +player_queue_make_daap(struct player_source **head, const char *query, const char *queuefilter, const char *sort); struct player_source * player_queue_make_pl(int plid, uint32_t *id);