From 80e0808b18d9317d6aab1584784b45cae67cdef6 Mon Sep 17 00:00:00 2001 From: chme Date: Sat, 16 Dec 2017 08:57:30 +0100 Subject: [PATCH 1/4] [mpd] command 'status': report current/next if player is stopped --- src/mpd.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/mpd.c b/src/mpd.c index dd22b1a1..af525fb1 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -732,8 +732,8 @@ mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, int queue_length; int queue_version; char *state; - int pos_pl; - struct db_queue_item *next_item; + uint32_t itemid = 0; + struct db_queue_item *queue_item; player_get_status(&status); @@ -775,39 +775,50 @@ mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, state); if (status.status != PLAY_STOPPED) - { - pos_pl = db_queue_get_pos(status.item_id, 0); + queue_item = db_queue_fetch_byitemid(status.item_id); + else + queue_item = db_queue_fetch_bypos(0, status.shuffle); + if (queue_item) + { evbuffer_add_printf(evbuf, "song: %d\n" - "songid: %d\n" + "songid: %d\n", + queue_item->pos, + queue_item->id); + + itemid = queue_item->id; + free_queue_item(queue_item, 0); + } + + if (status.status != PLAY_STOPPED) + { + evbuffer_add_printf(evbuf, "time: %d:%d\n" "elapsed: %#.3f\n" "bitrate: 128\n" "audio: 44100:16:2\n", - pos_pl, - status.item_id, (status.pos_ms / 1000), (status.len_ms / 1000), (status.pos_ms / 1000.0)); - } + } if (library_is_scanning()) { evbuffer_add(evbuf, "updating_db: 1\n", 15); } - if (status.status != PLAY_STOPPED) + if (itemid > 0) { - next_item = db_queue_fetch_next(status.item_id, status.shuffle); - if (next_item) + queue_item = db_queue_fetch_next(itemid, status.shuffle); + if (queue_item) { evbuffer_add_printf(evbuf, "nextsong: %d\n" "nextsongid: %d\n", - next_item->id, - next_item->pos); + queue_item->id, + queue_item->pos); - free_queue_item(next_item, 0); + free_queue_item(queue_item, 0); } } From 6f4f7c5b16c7b0cb243a41f804025bca54232903 Mon Sep 17 00:00:00 2001 From: chme Date: Sat, 16 Dec 2017 09:15:48 +0100 Subject: [PATCH 2/4] [mpd] command 'currentsong': report current item if player is stopped --- src/mpd.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/mpd.c b/src/mpd.c index af525fb1..7457743c 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -608,16 +608,13 @@ mpd_command_currentsong(struct evbuffer *evbuf, int argc, char **argv, char **er player_get_status(&status); if (status.status == PLAY_STOPPED) - { - // Return empty evbuffer if there is no current playing song - return 0; - } + queue_item = db_queue_fetch_bypos(0, status.shuffle); + else + queue_item = db_queue_fetch_byitemid(status.item_id); - queue_item = db_queue_fetch_byitemid(status.item_id); if (!queue_item) { - *errmsg = safe_asprintf("Error adding queue item info for file with id: %d", status.item_id); - return ACK_ERROR_UNKNOWN; + return 0; } ret = mpd_add_db_queue_item(evbuf, queue_item); From a1372c692e03379328e6be38adbe7b7452e92d0f Mon Sep 17 00:00:00 2001 From: chme Date: Fri, 15 Dec 2017 18:19:20 +0100 Subject: [PATCH 3/4] [mpd] Implement 'playlistfind' and 'playlistsearch' --- src/db.c | 2 +- src/mpd.c | 558 +++++++++++++++++++++++++++++++----------------------- 2 files changed, 322 insertions(+), 238 deletions(-) diff --git a/src/db.c b/src/db.c index 9f728687..753d44af 100644 --- a/src/db.c +++ b/src/db.c @@ -4450,7 +4450,7 @@ db_queue_add_item(struct db_queue_item *queue_item, char reshuffle, uint32_t ite static int queue_enum_start(struct query_params *qp) { -#define Q_TMPL "SELECT * FROM queue WHERE %s %s;" +#define Q_TMPL "SELECT * FROM queue f WHERE %s %s;" sqlite3_stmt *stmt; char *query; const char *orderby; diff --git a/src/mpd.c b/src/mpd.c index 7457743c..14a1534d 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -594,6 +594,239 @@ mpd_add_db_media_file_info(struct evbuffer *evbuf, struct db_media_file_info *db return ret; } +static int +mpd_get_query_params_find(int argc, char **argv, struct query_params *qp) +{ + char *c1; + char *c2; + int start_pos; + int end_pos; + int i; + uint32_t num; + int ret; + + c1 = NULL; + c2 = NULL; + + for (i = 0; i < argc; i += 2) + { + if (0 == strcasecmp(argv[i], "any")) + { + c1 = db_mprintf("(f.artist LIKE '%%%q%%' OR f.album LIKE '%%%q%%' OR f.title LIKE '%%%q%%')", argv[i + 1], argv[i + 1], argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "file")) + { + c1 = db_mprintf("(f.virtual_path = '/%q')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "base")) + { + c1 = db_mprintf("(f.virtual_path LIKE '/%q%%')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "modified-since")) + { + DPRINTF(E_WARN, L_MPD, "Special parameter 'modified-since' is not supported by forked-daapd and will be ignored\n"); + } + else if (0 == strcasecmp(argv[i], "window")) + { + ret = mpd_pars_range_arg(argv[i + 1], &start_pos, &end_pos); + if (ret == 0) + { + qp->idx_type = I_SUB; + qp->limit = end_pos - start_pos; + qp->offset = start_pos; + } + else + { + DPRINTF(E_LOG, L_MPD, "Window argument doesn't convert to integer or range: '%s'\n", argv[i + 1]); + } + } + else if (0 == strcasecmp(argv[i], "artist")) + { + c1 = db_mprintf("(f.artist = '%q')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "albumartist")) + { + c1 = db_mprintf("(f.album_artist = '%q')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "album")) + { + c1 = db_mprintf("(f.album = '%q')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "title")) + { + c1 = db_mprintf("(f.title = '%q')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "genre")) + { + c1 = db_mprintf("(f.genre = '%q')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "disc")) + { + ret = safe_atou32(argv[i + 1], &num); + if (ret < 0) + DPRINTF(E_WARN, L_MPD, "Disc parameter '%s' is not an integer and will be ignored\n", argv[i + 1]); + else + c1 = db_mprintf("(f.disc = %d)", num); + } + else if (0 == strcasecmp(argv[i], "track")) + { + ret = safe_atou32(argv[i + 1], &num); + if (ret < 0) + DPRINTF(E_WARN, L_MPD, "Track parameter '%s' is not an integer and will be ignored\n", argv[i + 1]); + else + c1 = db_mprintf("(f.track = %d)", num); + } + else if (0 == strcasecmp(argv[i], "date")) + { + ret = safe_atou32(argv[i + 1], &num); + if (ret < 0) + c1 = db_mprintf("(f.year = 0 OR f.year IS NULL)"); + else + c1 = db_mprintf("(f.year = %d)", num); + } + else if (i == 0 && argc == 1) + { + // Special case: a single token is allowed if listing albums for an artist + c1 = db_mprintf("(f.album_artist = '%q')", argv[i]); + } + else + { + DPRINTF(E_WARN, L_MPD, "Parameter '%s' is not supported by forked-daapd and will be ignored\n", argv[i]); + } + + if (c1) + { + if (qp->filter) + c2 = db_mprintf("%s AND %s", qp->filter, c1); + else + c2 = db_mprintf("%s", c1); + + free(qp->filter); + + qp->filter = c2; + c2 = NULL; + free(c1); + c1 = NULL; + } + } + + return 0; +} + +static int +mpd_get_query_params_search(int argc, char **argv, struct query_params *qp) +{ + char *c1; + char *c2; + int start_pos; + int end_pos; + int i; + uint32_t num; + int ret; + + c1 = NULL; + c2 = NULL; + + for (i = 0; i < argc; i += 2) + { + if (0 == strcasecmp(argv[i], "any")) + { + c1 = db_mprintf("(f.artist LIKE '%%%q%%' OR f.album LIKE '%%%q%%' OR f.title LIKE '%%%q%%')", argv[i + 1], argv[i + 1], argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "file")) + { + c1 = db_mprintf("(f.virtual_path LIKE '%%%q%%')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "base")) + { + c1 = db_mprintf("(f.virtual_path LIKE '/%q%%')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "modified-since")) + { + DPRINTF(E_WARN, L_MPD, "Special parameter 'modified-since' is not supported by forked-daapd and will be ignored\n"); + } + else if (0 == strcasecmp(argv[i], "window")) + { + ret = mpd_pars_range_arg(argv[i + 1], &start_pos, &end_pos); + if (ret == 0) + { + qp->idx_type = I_SUB; + qp->limit = end_pos - start_pos; + qp->offset = start_pos; + } + else + { + DPRINTF(E_LOG, L_MPD, "Window argument doesn't convert to integer or range: '%s'\n", argv[i + 1]); + } + } + else if (0 == strcasecmp(argv[i], "artist")) + { + c1 = db_mprintf("(f.artist LIKE '%%%q%%')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "albumartist")) + { + c1 = db_mprintf("(f.album_artist LIKE '%%%q%%')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "album")) + { + c1 = db_mprintf("(f.album LIKE '%%%q%%')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "title")) + { + c1 = db_mprintf("(f.title LIKE '%%%q%%')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "genre")) + { + c1 = db_mprintf("(f.genre LIKE '%%%q%%')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "disc")) + { + ret = safe_atou32(argv[i + 1], &num); + if (ret < 0) + DPRINTF(E_WARN, L_MPD, "Disc parameter '%s' is not an integer and will be ignored\n", argv[i + 1]); + else + c1 = db_mprintf("(f.disc = %d)", num); + } + else if (0 == strcasecmp(argv[i], "track")) + { + ret = safe_atou32(argv[i + 1], &num); + if (ret < 0) + DPRINTF(E_WARN, L_MPD, "Track parameter '%s' is not an integer and will be ignored\n", argv[i + 1]); + else + c1 = db_mprintf("(f.track = %d)", num); + } + else if (0 == strcasecmp(argv[i], "date")) + { + ret = safe_atou32(argv[i + 1], &num); + if (ret < 0) + c1 = db_mprintf("(f.year = 0 OR f.year IS NULL)"); + else + c1 = db_mprintf("(f.year = %d)", num); + } + else + { + DPRINTF(E_WARN, L_MPD, "Parameter '%s' is not supported by forked-daapd and will be ignored\n", argv[i]); + } + + if (c1) + { + if (qp->filter) + c2 = db_mprintf("%s AND %s", qp->filter, c1); + else + c2 = db_mprintf("%s", c1); + + free(qp->filter); + + qp->filter = c2; + c2 = NULL; + free(c1); + c1 = NULL; + } + } + + return 0; +} + /* * Command handler function for 'currentsong' */ @@ -1900,6 +2133,94 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e return 0; } +static int +mpd_command_playlistfind(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx) +{ + struct query_params query_params; + struct db_queue_item queue_item; + int ret; + + memset(&query_params, 0, sizeof(struct query_params)); + + if (argc < 3 || ((argc - 1) % 2) != 0) + { + *errmsg = safe_asprintf("Missing argument(s) for command 'playlistfind'"); + return ACK_ERROR_ARG; + } + + mpd_get_query_params_find(argc - 1, argv + 1, &query_params); + + ret = db_queue_enum_start(&query_params); + if (ret < 0) + { + free(query_params.filter); + *errmsg = safe_asprintf("Failed to start queue enum for command playlistinfo: '%s'", argv[1]); + return ACK_ERROR_ARG; + } + + while ((ret = db_queue_enum_fetch(&query_params, &queue_item)) == 0 && queue_item.id > 0) + { + ret = mpd_add_db_queue_item(evbuf, &queue_item); + if (ret < 0) + { + *errmsg = safe_asprintf("Error adding media info for file with id: %d", queue_item.file_id); + + db_queue_enum_end(&query_params); + free(query_params.filter); + return ACK_ERROR_UNKNOWN; + } + } + + db_queue_enum_end(&query_params); + free(query_params.filter); + + return 0; +} + +static int +mpd_command_playlistsearch(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx) +{ + struct query_params query_params; + struct db_queue_item queue_item; + int ret; + + memset(&query_params, 0, sizeof(struct query_params)); + + if (argc < 3 || ((argc - 1) % 2) != 0) + { + *errmsg = safe_asprintf("Missing argument(s) for command 'playlistfind'"); + return ACK_ERROR_ARG; + } + + mpd_get_query_params_search(argc - 1, argv + 1, &query_params); + + ret = db_queue_enum_start(&query_params); + if (ret < 0) + { + free(query_params.filter); + *errmsg = safe_asprintf("Failed to start queue enum for command playlistinfo: '%s'", argv[1]); + return ACK_ERROR_ARG; + } + + while ((ret = db_queue_enum_fetch(&query_params, &queue_item)) == 0 && queue_item.id > 0) + { + ret = mpd_add_db_queue_item(evbuf, &queue_item); + if (ret < 0) + { + *errmsg = safe_asprintf("Error adding media info for file with id: %d", queue_item.file_id); + + db_queue_enum_end(&query_params); + free(query_params.filter); + return ACK_ERROR_UNKNOWN; + } + } + + db_queue_enum_end(&query_params); + free(query_params.filter); + + return 0; +} + static int plchanges_build_queryparams(struct query_params *query_params, int argc, char **argv, char **errmsg) { @@ -2398,125 +2719,6 @@ mpd_command_save(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s return 0; } -static int -mpd_get_query_params_find(int argc, char **argv, struct query_params *qp) -{ - char *c1; - char *c2; - int start_pos; - int end_pos; - int i; - uint32_t num; - int ret; - - c1 = NULL; - c2 = NULL; - - for (i = 0; i < argc; i += 2) - { - if (0 == strcasecmp(argv[i], "any")) - { - c1 = db_mprintf("(f.artist LIKE '%%%q%%' OR f.album LIKE '%%%q%%' OR f.title LIKE '%%%q%%')", argv[i + 1], argv[i + 1], argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "file")) - { - c1 = db_mprintf("(f.virtual_path = '/%q')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "base")) - { - c1 = db_mprintf("(f.virtual_path LIKE '/%q%%')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "modified-since")) - { - DPRINTF(E_WARN, L_MPD, "Special parameter 'modified-since' is not supported by forked-daapd and will be ignored\n"); - } - else if (0 == strcasecmp(argv[i], "window")) - { - ret = mpd_pars_range_arg(argv[i + 1], &start_pos, &end_pos); - if (ret == 0) - { - qp->idx_type = I_SUB; - qp->limit = end_pos - start_pos; - qp->offset = start_pos; - } - else - { - DPRINTF(E_LOG, L_MPD, "Window argument doesn't convert to integer or range: '%s'\n", argv[i + 1]); - } - } - else if (0 == strcasecmp(argv[i], "artist")) - { - c1 = db_mprintf("(f.artist = '%q')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "albumartist")) - { - c1 = db_mprintf("(f.album_artist = '%q')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "album")) - { - c1 = db_mprintf("(f.album = '%q')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "title")) - { - c1 = db_mprintf("(f.title = '%q')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "genre")) - { - c1 = db_mprintf("(f.genre = '%q')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "disc")) - { - ret = safe_atou32(argv[i + 1], &num); - if (ret < 0) - DPRINTF(E_WARN, L_MPD, "Disc parameter '%s' is not an integer and will be ignored\n", argv[i + 1]); - else - c1 = db_mprintf("(f.disc = %d)", num); - } - else if (0 == strcasecmp(argv[i], "track")) - { - ret = safe_atou32(argv[i + 1], &num); - if (ret < 0) - DPRINTF(E_WARN, L_MPD, "Track parameter '%s' is not an integer and will be ignored\n", argv[i + 1]); - else - c1 = db_mprintf("(f.track = %d)", num); - } - else if (0 == strcasecmp(argv[i], "date")) - { - ret = safe_atou32(argv[i + 1], &num); - if (ret < 0) - c1 = db_mprintf("(f.year = 0 OR f.year IS NULL)"); - else - c1 = db_mprintf("(f.year = %d)", num); - } - else if (i == 0 && argc == 1) - { - // Special case: a single token is allowed if listing albums for an artist - c1 = db_mprintf("(f.album_artist = '%q')", argv[i]); - } - else - { - DPRINTF(E_WARN, L_MPD, "Parameter '%s' is not supported by forked-daapd and will be ignored\n", argv[i]); - } - - if (c1) - { - if (qp->filter) - c2 = db_mprintf("%s AND %s", qp->filter, c1); - else - c2 = db_mprintf("%s", c1); - - free(qp->filter); - - qp->filter = c2; - c2 = NULL; - free(c1); - c1 = NULL; - } - } - - return 0; -} - static int mpd_command_count(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx) { @@ -3034,120 +3236,6 @@ mpd_command_lsinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, return ret; } -static int -mpd_get_query_params_search(int argc, char **argv, struct query_params *qp) -{ - char *c1; - char *c2; - int start_pos; - int end_pos; - int i; - uint32_t num; - int ret; - - c1 = NULL; - c2 = NULL; - - for (i = 0; i < argc; i += 2) - { - if (0 == strcasecmp(argv[i], "any")) - { - c1 = db_mprintf("(f.artist LIKE '%%%q%%' OR f.album LIKE '%%%q%%' OR f.title LIKE '%%%q%%')", argv[i + 1], argv[i + 1], argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "file")) - { - c1 = db_mprintf("(f.virtual_path LIKE '%%%q%%')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "base")) - { - c1 = db_mprintf("(f.virtual_path LIKE '/%q%%')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "modified-since")) - { - DPRINTF(E_WARN, L_MPD, "Special parameter 'modified-since' is not supported by forked-daapd and will be ignored\n"); - } - else if (0 == strcasecmp(argv[i], "window")) - { - ret = mpd_pars_range_arg(argv[i + 1], &start_pos, &end_pos); - if (ret == 0) - { - qp->idx_type = I_SUB; - qp->limit = end_pos - start_pos; - qp->offset = start_pos; - } - else - { - DPRINTF(E_LOG, L_MPD, "Window argument doesn't convert to integer or range: '%s'\n", argv[i + 1]); - } - } - else if (0 == strcasecmp(argv[i], "artist")) - { - c1 = db_mprintf("(f.artist LIKE '%%%q%%')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "albumartist")) - { - c1 = db_mprintf("(f.album_artist LIKE '%%%q%%')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "album")) - { - c1 = db_mprintf("(f.album LIKE '%%%q%%')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "title")) - { - c1 = db_mprintf("(f.title LIKE '%%%q%%')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "genre")) - { - c1 = db_mprintf("(f.genre LIKE '%%%q%%')", argv[i + 1]); - } - else if (0 == strcasecmp(argv[i], "disc")) - { - ret = safe_atou32(argv[i + 1], &num); - if (ret < 0) - DPRINTF(E_WARN, L_MPD, "Disc parameter '%s' is not an integer and will be ignored\n", argv[i + 1]); - else - c1 = db_mprintf("(f.disc = %d)", num); - } - else if (0 == strcasecmp(argv[i], "track")) - { - ret = safe_atou32(argv[i + 1], &num); - if (ret < 0) - DPRINTF(E_WARN, L_MPD, "Track parameter '%s' is not an integer and will be ignored\n", argv[i + 1]); - else - c1 = db_mprintf("(f.track = %d)", num); - } - else if (0 == strcasecmp(argv[i], "date")) - { - ret = safe_atou32(argv[i + 1], &num); - if (ret < 0) - c1 = db_mprintf("(f.year = 0 OR f.year IS NULL)"); - else - c1 = db_mprintf("(f.year = %d)", num); - } - else - { - DPRINTF(E_WARN, L_MPD, "Parameter '%s' is not supported by forked-daapd and will be ignored\n", argv[i]); - } - - if (c1) - { - if (qp->filter) - c2 = db_mprintf("%s AND %s", qp->filter, c1); - else - c2 = db_mprintf("%s", c1); - - free(qp->filter); - - qp->filter = c2; - c2 = NULL; - free(c1); - c1 = NULL; - } - } - - return 0; -} - /* * Command handler function for 'search' * Lists any song that matches the given list of arguments. Arguments are pairs of TYPE and WHAT, where @@ -4394,12 +4482,10 @@ static struct mpd_command mpd_handlers[] = .mpdcommand = "playlist", .handler = mpd_command_playlistinfo }, - /* { .mpdcommand = "playlistfind", .handler = mpd_command_playlistfind }, - */ { .mpdcommand = "playlistid", .handler = mpd_command_playlistid @@ -4408,12 +4494,10 @@ static struct mpd_command mpd_handlers[] = .mpdcommand = "playlistinfo", .handler = mpd_command_playlistinfo }, - /* { .mpdcommand = "playlistsearch", .handler = mpd_command_playlistsearch }, - */ { .mpdcommand = "plchanges", .handler = mpd_command_plchanges From 434be2846074731af1e25715ecb817b3efa4068b Mon Sep 17 00:00:00 2001 From: chme Date: Sat, 16 Dec 2017 12:24:45 +0100 Subject: [PATCH 4/4] [mpd] Support position parameter in command 'addid' --- src/mpd.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/mpd.c b/src/mpd.c index 14a1534d..cb2d0355 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -1793,6 +1793,7 @@ static int mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx) { struct media_file_info mfi; + int to_pos = -1; int ret; if (argc < 2) @@ -1801,10 +1802,14 @@ mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, return ACK_ERROR_ARG; } - //TODO if argc > 2 add song at position argv[2] if (argc > 2) { - DPRINTF(E_LOG, L_MPD, "Adding at a specified position not supported for 'addid', adding songs at end of queue.\n"); + ret = safe_atoi32(argv[2], &to_pos); + if (ret < 0) + { + *errmsg = safe_asprintf("Argument doesn't convert to integer: '%s'", argv[2]); + return ACK_ERROR_ARG; + } } ret = mpd_queue_add(argv[1], true); @@ -1829,6 +1834,11 @@ mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, return ACK_ERROR_UNKNOWN; } + if (to_pos >= 0) + { + db_queue_move_byitemid(ret, to_pos, 0); + } + evbuffer_add_printf(evbuf, "Id: %d\n", ret); // mpd_queue_add returns the item_id of the last inserted queue item