diff --git a/src/mpd.c b/src/mpd.c index 4e3438ea..db17d66e 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -1680,8 +1680,213 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) } static int -mpd_command_list() +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; + int ret; + + c1 = NULL; + c2 = NULL; + + for (i = 0; i < argc; i += 2) + { + if (0 == strcasecmp(argv[i], "any")) + { + c1 = sqlite3_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 = sqlite3_mprintf("(f.virtual_path = '/%q')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "base")) + { + c1 = sqlite3_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 = sqlite3_mprintf("(f.artist = '%q')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "albumartist")) + { + c1 = sqlite3_mprintf("(f.album_artist = '%q')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "album")) + { + c1 = sqlite3_mprintf("(f.album = '%q')", argv[i + 1]); + } + else if (0 == strcasecmp(argv[i], "title")) + { + c1 = sqlite3_mprintf("(f.title = '%q')", argv[i + 1]); + } + 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 = sqlite3_mprintf("%s AND %s", qp->filter, c1); + else + c2 = sqlite3_mprintf("%s", c1); + + if (qp->filter) + sqlite3_free(qp->filter); + + qp->filter = c2; + c2 = NULL; + sqlite3_free(c1); + c1 = NULL; + } + } + + return 0; +} + +static int +mpd_command_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) +{ + struct query_params qp; + struct db_media_file_info dbmfi; + int ret; + + if (argc < 3 || ((argc - 1) % 2) != 0) + { + DPRINTF(E_LOG, L_MPD, "Missing argument(s) for command 'find'\n"); + ret = asprintf(errmsg, "Missing argument(s) for command 'find'"); + if (ret < 0) + DPRINTF(E_LOG, L_MPD, "Out of memory\n"); + return ACK_ERROR_ARG; + } + + memset(&qp, 0, sizeof(struct query_params)); + + qp.type = Q_ITEMS; + qp.sort = S_NAME; + qp.idx_type = I_NONE; + + mpd_get_query_params_find(argc - 1, argv + 1, &qp); + + ret = db_query_start(&qp); + if (ret < 0) + { + db_query_end(&qp); + + DPRINTF(E_LOG, L_MPD, "Could not start query\n"); + ret = asprintf(errmsg, "Could not start query"); + if (ret < 0) + DPRINTF(E_LOG, L_MPD, "Out of memory\n"); + return ACK_ERROR_UNKNOWN; + } + + while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) + { + ret = mpd_add_db_media_file_info(evbuf, &dbmfi); + if (ret < 0) + { + DPRINTF(E_LOG, L_MPD, "Error adding song to the evbuffer, song id: %s\n", dbmfi.id); + } + } + + db_query_end(&qp); + + return 0; +} + +static int +mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) +{ + return 0; +} + +static int +mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) +{ + struct query_params qp; + struct db_group_info dbgri; + char *type; + int ret; + + if (argc < 2 || (argc % 2) != 0) + { + DPRINTF(E_LOG, L_MPD, "Missing argument(s) for command 'list'\n"); + ret = asprintf(errmsg, "Missing argument(s) for command 'list'"); + if (ret < 0) + DPRINTF(E_LOG, L_MPD, "Out of memory\n"); + return ACK_ERROR_ARG; + } + + memset(&qp, 0, sizeof(struct query_params)); + + if (0 == strcasecmp(argv[1], "artist") + || 0 == strcasecmp(argv[1], "albumartist")) + { + qp.type = Q_GROUP_ARTISTS; + qp.sort = S_ARTIST; + type = "Artist: "; + } + else if (0 == strcasecmp(argv[1], "album")) + { + qp.type = Q_GROUP_ALBUMS; + qp.sort = S_ALBUM; + type = "Album: "; + } + else + { + DPRINTF(E_WARN, L_MPD, "Unsupported type argument for command 'list': %s\n", argv[1]); + return 0; + } + + qp.idx_type = I_NONE; + + if (argc > 2) + { + mpd_get_query_params_find(argc - 2, argv + 2, &qp); + } + + ret = db_query_start(&qp); + if (ret < 0) + { + db_query_end(&qp); + + DPRINTF(E_LOG, L_MPD, "Could not start query\n"); + ret = asprintf(errmsg, "Could not start query"); + if (ret < 0) + DPRINTF(E_LOG, L_MPD, "Out of memory\n"); + return ACK_ERROR_UNKNOWN; + } + + while ((ret = db_query_fetch_group(&qp, &dbgri)) == 0) + { + evbuffer_add_printf(evbuf, + "%s%s\n", + type, + dbgri.itemname); + } + + db_query_end(&qp); return 0; } @@ -1781,7 +1986,7 @@ mpd_command_lsinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) } static int -mpd_get_query_params(int argc, char **argv, struct query_params *qp) +mpd_get_query_params_search(int argc, char **argv, struct query_params *qp) { char *c1; char *c2; @@ -1889,8 +2094,8 @@ mpd_command_search(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) if (argc < 3 || ((argc - 1) % 2) != 0) { - DPRINTF(E_LOG, L_MPD, "Missing argument(s) for command 'update'\n"); - ret = asprintf(errmsg, "Missing argument(s) for command 'update'"); + DPRINTF(E_LOG, L_MPD, "Missing argument(s) for command 'search'\n"); + ret = asprintf(errmsg, "Missing argument(s) for command 'search'"); if (ret < 0) DPRINTF(E_LOG, L_MPD, "Out of memory\n"); return ACK_ERROR_ARG; @@ -1902,7 +2107,7 @@ mpd_command_search(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) qp.sort = S_NAME; qp.idx_type = I_NONE; - mpd_get_query_params(argc - 1, argv + 1, &qp); + mpd_get_query_params_search(argc - 1, argv + 1, &qp); ret = db_query_start(&qp); if (ret < 0) @@ -2321,6 +2526,7 @@ static struct command mpd_handlers[] = .mpdcommand = "count", .handler = mpd_command_count }, + */ { .mpdcommand = "find", .handler = mpd_command_find @@ -2329,7 +2535,6 @@ static struct command mpd_handlers[] = .mpdcommand = "findadd", .handler = mpd_command_findadd }, - */ { .mpdcommand = "list", .handler = mpd_command_list