mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-11 23:13:24 -05:00
[mpd] Refactor parsing filter/window arguments and add support for
"group" argument in "list" command
This commit is contained in:
parent
e015032292
commit
f77c216650
492
src/mpd.c
492
src/mpd.c
@ -59,6 +59,13 @@
|
||||
#include "remote_pairing.h"
|
||||
|
||||
|
||||
enum mpd_type {
|
||||
MPD_TYPE_INT,
|
||||
MPD_TYPE_STRING,
|
||||
MPD_TYPE_SPECIAL,
|
||||
};
|
||||
|
||||
|
||||
#define MPD_ALL_IDLE_LISTENER_EVENTS (LISTENER_PLAYER | LISTENER_QUEUE | LISTENER_VOLUME | LISTENER_SPEAKER | LISTENER_OPTIONS | LISTENER_DATABASE | LISTENER_UPDATE | LISTENER_STORED_PLAYLIST | LISTENER_RATING)
|
||||
#define MPD_RATING_FACTOR 10.0
|
||||
|
||||
@ -145,6 +152,65 @@ static const char * const ffmpeg_mime_types[] = { "application/flv", "applicatio
|
||||
NULL
|
||||
};
|
||||
|
||||
struct mpd_tagtype
|
||||
{
|
||||
char *tag;
|
||||
char *field;
|
||||
char *sort_field;
|
||||
char *group_field;
|
||||
enum mpd_type type;
|
||||
ssize_t mfi_offset;
|
||||
|
||||
/*
|
||||
* This allows omitting the "group" fields in the created group by clause to improve
|
||||
* performance in the "list" command. For example listing albums and artists already
|
||||
* groups by their persistent id, an additional group clause by artist/album will
|
||||
* decrease performance of the select query and will in general not change the result
|
||||
* (e. g. album persistent id is generated by artist and album and listing albums
|
||||
* grouped by artist is therefor not necessary).
|
||||
*/
|
||||
bool group_in_listcommand;
|
||||
};
|
||||
|
||||
static struct mpd_tagtype tagtypes[] =
|
||||
{
|
||||
/* tag | db field | db sort field | db group field | type | media_file offset | group_in_listcommand */
|
||||
|
||||
// We treat the artist tag as album artist, this allows grouping over the artist-persistent-id index and increases performance
|
||||
// { "Artist", "f.artist", "f.artist", "f.artist", MPD_TYPE_STRING, dbmfi_offsetof(artist), },
|
||||
{ "Artist", "f.album_artist", "f.album_artist_sort, f.album_artist", "f.songartistid", MPD_TYPE_STRING, dbmfi_offsetof(album_artist), false, },
|
||||
{ "ArtistSort", "f.album_artist_sort", "f.album_artist_sort, f.album_artist", "f.songartistid", MPD_TYPE_STRING, dbmfi_offsetof(album_artist_sort), false, },
|
||||
{ "AlbumArtist", "f.album_artist", "f.album_artist_sort, f.album_artist", "f.songartistid", MPD_TYPE_STRING, dbmfi_offsetof(album_artist), false, },
|
||||
{ "AlbumArtistSort", "f.album_artist_sort", "f.album_artist_sort, f.album_artist", "f.songartistid", MPD_TYPE_STRING, dbmfi_offsetof(album_artist_sort), false, },
|
||||
{ "Album", "f.album", "f.album_sort, f.album", "f.songalbumid", MPD_TYPE_STRING, dbmfi_offsetof(album), false, },
|
||||
{ "Title", "f.title", "f.title", "f.title", MPD_TYPE_STRING, dbmfi_offsetof(title), true, },
|
||||
{ "Track", "f.track", "f.track", "f.track", MPD_TYPE_INT, dbmfi_offsetof(track), true, },
|
||||
{ "Genre", "f.genre", "f.genre", "f.genre", MPD_TYPE_STRING, dbmfi_offsetof(genre), true, },
|
||||
{ "Disc", "f.disc", "f.disc", "f.disc", MPD_TYPE_INT, dbmfi_offsetof(disc), true, },
|
||||
{ "Date", "f.year", "f.year", "f.year", MPD_TYPE_INT, dbmfi_offsetof(year), true, },
|
||||
{ "file", NULL, NULL, NULL, MPD_TYPE_SPECIAL, -1, true, },
|
||||
{ "base", NULL, NULL, NULL, MPD_TYPE_SPECIAL, -1, true, },
|
||||
{ "any", NULL, NULL, NULL, MPD_TYPE_SPECIAL, -1, true, },
|
||||
|
||||
};
|
||||
|
||||
static struct mpd_tagtype *
|
||||
find_tagtype(const char *tag)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!tag)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tagtypes); i++)
|
||||
{
|
||||
if (strcasecmp(tag, tagtypes[i].tag) == 0)
|
||||
return &tagtypes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* MPD client connection data
|
||||
*/
|
||||
@ -586,11 +652,34 @@ 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)
|
||||
static void
|
||||
append_string(char **a, const char *b, const char *separator)
|
||||
{
|
||||
char *temp;
|
||||
|
||||
if (*a)
|
||||
temp = db_mprintf("%s%s%s", *a, (separator ? separator : ""), b);
|
||||
else
|
||||
temp = db_mprintf("%s", b);
|
||||
|
||||
free(*a);
|
||||
*a = temp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the filter (where clause) and the window (limit clause) in the given query_params
|
||||
* based on the given arguments
|
||||
*
|
||||
* @param argc Number of arguments in argv
|
||||
* @param argv Pointer to the first filter parameter
|
||||
* @param exact_match If true, creates filter for exact matches (e. g. find command) otherwise matches substrings (e. g. search command)
|
||||
* @param qp Query parameters
|
||||
*/
|
||||
static int
|
||||
parse_filter_window_params(int argc, char **argv, bool exact_match, struct query_params *qp)
|
||||
{
|
||||
struct mpd_tagtype *tagtype;
|
||||
char *c1;
|
||||
char *c2;
|
||||
int start_pos;
|
||||
int end_pos;
|
||||
int i;
|
||||
@ -598,83 +687,61 @@ mpd_get_query_params_find(int argc, char **argv, struct query_params *qp)
|
||||
int ret;
|
||||
|
||||
c1 = NULL;
|
||||
c2 = NULL;
|
||||
|
||||
for (i = 0; i < argc; i += 2)
|
||||
{
|
||||
if (0 == strcasecmp(argv[i], "any"))
|
||||
// End of filter key/value pairs reached, if keywords "window" or "group" found
|
||||
if (0 == strcasecmp(argv[i], "window") || 0 == strcasecmp(argv[i], "group"))
|
||||
break;
|
||||
|
||||
// Process filter key/value pair
|
||||
if ((i + 1) < argc)
|
||||
{
|
||||
tagtype = find_tagtype(argv[i]);
|
||||
|
||||
if (!tagtype)
|
||||
{
|
||||
DPRINTF(E_WARN, L_MPD, "Parameter '%s' is not supported by forked-daapd and will be ignored\n", argv[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tagtype->type == MPD_TYPE_STRING)
|
||||
{
|
||||
if (exact_match)
|
||||
c1 = db_mprintf("(%s = '%q')", tagtype->field, argv[i + 1]);
|
||||
else
|
||||
c1 = db_mprintf("(%s LIKE '%%%q%%')", tagtype->field, argv[i + 1]);
|
||||
}
|
||||
else if (tagtype->type == MPD_TYPE_INT)
|
||||
{
|
||||
ret = safe_atou32(argv[i + 1], &num);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_WARN, L_MPD, "%s parameter '%s' is not an integer and will be ignored\n", tagtype->tag, argv[i + 1]);
|
||||
else
|
||||
c1 = db_mprintf("(%s = %d)", tagtype->field, num);
|
||||
}
|
||||
else if (tagtype->type == MPD_TYPE_SPECIAL)
|
||||
{
|
||||
if (0 == strcasecmp(tagtype->tag, "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"))
|
||||
else if (0 == strcasecmp(tagtype->tag, "file"))
|
||||
{
|
||||
if (exact_match)
|
||||
c1 = db_mprintf("(f.virtual_path = '/%q')", argv[i + 1]);
|
||||
else
|
||||
c1 = db_mprintf("(f.virtual_path LIKE '%%%q%%')", argv[i + 1]);
|
||||
}
|
||||
else if (0 == strcasecmp(argv[i], "base"))
|
||||
else if (0 == strcasecmp(tagtype->tag, "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]);
|
||||
DPRINTF(E_WARN, L_MPD, "Unknown special parameter '%s' will be ignored\n", tagtype->tag);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
@ -683,61 +750,19 @@ mpd_get_query_params_find(int argc, char **argv, struct query_params *qp)
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF(E_WARN, L_MPD, "Parameter '%s' is not supported by forked-daapd and will be ignored\n", argv[i]);
|
||||
DPRINTF(E_WARN, L_MPD, "Missing value for parameter '%s', ignoring '%s'\n", argv[i], argv[i]);
|
||||
}
|
||||
|
||||
if (c1)
|
||||
{
|
||||
if (qp->filter)
|
||||
c2 = db_mprintf("%s AND %s", qp->filter, c1);
|
||||
else
|
||||
c2 = db_mprintf("%s", c1);
|
||||
append_string(&qp->filter, c1, " AND ");
|
||||
|
||||
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"))
|
||||
if ((i + 1) < argc && 0 == strcasecmp(argv[i], "window"))
|
||||
{
|
||||
ret = mpd_pars_range_arg(argv[i + 1], &start_pos, &end_pos);
|
||||
if (ret == 0)
|
||||
@ -750,69 +775,51 @@ mpd_get_query_params_search(int argc, char **argv, struct query_params *qp)
|
||||
{
|
||||
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]);
|
||||
i += 2;
|
||||
}
|
||||
|
||||
if (c1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_group_params(int argc, char **argv, bool group_in_listcommand, struct query_params *qp, struct mpd_tagtype ***group, int *groupsize)
|
||||
{
|
||||
int first_group;
|
||||
int i;
|
||||
int j;
|
||||
struct mpd_tagtype *tagtype;
|
||||
|
||||
*groupsize = 0;
|
||||
*group = NULL;
|
||||
|
||||
// Iterate through arguments to the first "group" argument
|
||||
for (first_group = 0; first_group < argc; first_group++)
|
||||
{
|
||||
if (qp->filter)
|
||||
c2 = db_mprintf("%s AND %s", qp->filter, c1);
|
||||
else
|
||||
c2 = db_mprintf("%s", c1);
|
||||
if (0 == strcasecmp(argv[first_group], "group"))
|
||||
break;
|
||||
}
|
||||
|
||||
free(qp->filter);
|
||||
// Early return if no group keyword in arguments (or group keyword not followed by field argument)
|
||||
if ((first_group + 1) >= argc || (argc - first_group) % 2 != 0)
|
||||
return 0;
|
||||
|
||||
qp->filter = c2;
|
||||
c2 = NULL;
|
||||
free(c1);
|
||||
c1 = NULL;
|
||||
*groupsize = (argc - first_group) / 2;
|
||||
*group = calloc(*groupsize, sizeof(struct mpd_tagtype *));
|
||||
|
||||
// Now process all group/field arguments
|
||||
for (j = 0; j < (*groupsize); j++)
|
||||
{
|
||||
i = first_group + (j * 2);
|
||||
|
||||
if ((i + 1) < argc && 0 == strcasecmp(argv[i], "group"))
|
||||
{
|
||||
tagtype = find_tagtype(argv[i + 1]);
|
||||
if (tagtype && tagtype->type != MPD_TYPE_SPECIAL)
|
||||
{
|
||||
if (group_in_listcommand)
|
||||
append_string(&qp->group, tagtype->group_field, ", ");
|
||||
(*group)[j] = tagtype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2054,7 +2061,7 @@ mpd_command_playlistfind(struct evbuffer *evbuf, int argc, char **argv, char **e
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
mpd_get_query_params_find(argc - 1, argv + 1, &query_params);
|
||||
parse_filter_window_params(argc - 1, argv + 1, true, &query_params);
|
||||
|
||||
ret = db_queue_enum_start(&query_params);
|
||||
if (ret < 0)
|
||||
@ -2098,7 +2105,7 @@ mpd_command_playlistsearch(struct evbuffer *evbuf, int argc, char **argv, char *
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
mpd_get_query_params_search(argc - 1, argv + 1, &query_params);
|
||||
parse_filter_window_params(argc - 1, argv + 1, false, &query_params);
|
||||
|
||||
ret = db_queue_enum_start(&query_params);
|
||||
if (ret < 0)
|
||||
@ -2598,7 +2605,7 @@ mpd_command_count(struct evbuffer *evbuf, int argc, char **argv, char **errmsg,
|
||||
|
||||
memset(&qp, 0, sizeof(struct query_params));
|
||||
qp.type = Q_COUNT_ITEMS;
|
||||
mpd_get_query_params_find(argc - 1, argv + 1, &qp);
|
||||
parse_filter_window_params(argc - 1, argv + 1, true, &qp);
|
||||
|
||||
ret = db_filecount_get(&fci, &qp);
|
||||
if (ret < 0)
|
||||
@ -2640,7 +2647,7 @@ mpd_command_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s
|
||||
qp.sort = S_NAME;
|
||||
qp.idx_type = I_NONE;
|
||||
|
||||
mpd_get_query_params_find(argc - 1, argv + 1, &qp);
|
||||
parse_filter_window_params(argc - 1, argv + 1, true, &qp);
|
||||
|
||||
ret = db_query_start(&qp);
|
||||
if (ret < 0)
|
||||
@ -2686,7 +2693,7 @@ mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
|
||||
qp.sort = S_ARTIST;
|
||||
qp.idx_type = I_NONE;
|
||||
|
||||
mpd_get_query_params_find(argc - 1, argv + 1, &qp);
|
||||
parse_filter_window_params(argc - 1, argv + 1, true, &qp);
|
||||
|
||||
player_get_status(&status);
|
||||
|
||||
@ -2704,11 +2711,13 @@ mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
|
||||
static int
|
||||
mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
|
||||
{
|
||||
struct mpd_tagtype *tagtype;
|
||||
struct query_params qp;
|
||||
struct db_group_info dbgri;
|
||||
char *type;
|
||||
char *browse_item;
|
||||
char *sort_item;
|
||||
struct mpd_tagtype **group;
|
||||
int groupsize;
|
||||
struct db_media_file_info dbmfi;
|
||||
char **strval;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (argc < 2 || ((argc % 2) != 0))
|
||||
@ -2720,111 +2729,77 @@ mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s
|
||||
}
|
||||
}
|
||||
|
||||
memset(&qp, 0, sizeof(struct query_params));
|
||||
tagtype = find_tagtype(argv[1]);
|
||||
|
||||
if (0 == strcasecmp(argv[1], "artist"))
|
||||
{
|
||||
qp.type = Q_GROUP_ARTISTS;
|
||||
qp.sort = S_ARTIST;
|
||||
type = "Artist: ";
|
||||
}
|
||||
else if (0 == strcasecmp(argv[1], "albumartist"))
|
||||
{
|
||||
qp.type = Q_GROUP_ARTISTS;
|
||||
qp.sort = S_ARTIST;
|
||||
type = "AlbumArtist: ";
|
||||
}
|
||||
else if (0 == strcasecmp(argv[1], "album"))
|
||||
{
|
||||
qp.type = Q_GROUP_ALBUMS;
|
||||
qp.sort = S_ALBUM;
|
||||
type = "Album: ";
|
||||
}
|
||||
else if (0 == strcasecmp(argv[1], "date"))
|
||||
{
|
||||
qp.type = Q_BROWSE_YEARS;
|
||||
type = "Date: ";
|
||||
}
|
||||
else if (0 == strcasecmp(argv[1], "genre"))
|
||||
{
|
||||
qp.type = Q_BROWSE_GENRES;
|
||||
type = "Genre: ";
|
||||
}
|
||||
else if (0 == strcasecmp(argv[1], "disc"))
|
||||
{
|
||||
qp.type = Q_BROWSE_DISCS;
|
||||
type = "Disc: ";
|
||||
}
|
||||
else if (0 == strcasecmp(argv[1], "track"))
|
||||
{
|
||||
qp.type = Q_BROWSE_TRACKS;
|
||||
type = "Track: ";
|
||||
}
|
||||
else if (0 == strcasecmp(argv[1], "file"))
|
||||
{
|
||||
qp.type = Q_BROWSE_VPATH;
|
||||
type = "file: ";
|
||||
}
|
||||
else
|
||||
if (!tagtype || tagtype->type == MPD_TYPE_SPECIAL) //FIXME allow "file" tagtype
|
||||
{
|
||||
DPRINTF(E_WARN, L_MPD, "Unsupported type argument for command 'list': %s\n", argv[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&qp, 0, sizeof(struct query_params));
|
||||
qp.type = Q_ITEMS;
|
||||
qp.idx_type = I_NONE;
|
||||
qp.order = tagtype->sort_field;
|
||||
qp.group = strdup(tagtype->group_field);
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
mpd_get_query_params_find(argc - 2, argv + 2, &qp);
|
||||
parse_filter_window_params(argc - 2, argv + 2, true, &qp);
|
||||
}
|
||||
|
||||
group = NULL;
|
||||
groupsize = 0;
|
||||
parse_group_params(argc - 2, argv + 2, tagtype->group_in_listcommand, &qp, &group, &groupsize);
|
||||
|
||||
ret = db_query_start(&qp);
|
||||
if (ret < 0)
|
||||
{
|
||||
db_query_end(&qp);
|
||||
free(qp.filter);
|
||||
free(qp.group);
|
||||
free(group);
|
||||
|
||||
*errmsg = safe_asprintf("Could not start query");
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (qp.type & Q_F_BROWSE)
|
||||
while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
|
||||
{
|
||||
if (qp.type == Q_BROWSE_VPATH)
|
||||
{
|
||||
while (((ret = db_query_fetch_string_sort(&qp, &browse_item, &sort_item)) == 0) && (browse_item))
|
||||
{
|
||||
// Remove the first "/" from the virtual_path
|
||||
strval = (char **) ((char *)&dbmfi + tagtype->mfi_offset);
|
||||
|
||||
if (!(*strval) || (**strval == '\0'))
|
||||
continue;
|
||||
|
||||
evbuffer_add_printf(evbuf,
|
||||
"%s%s\n",
|
||||
type,
|
||||
(browse_item + 1));
|
||||
}
|
||||
}
|
||||
else
|
||||
"%s: %s\n",
|
||||
tagtype->tag,
|
||||
*strval);
|
||||
|
||||
if (group && groupsize > 0)
|
||||
{
|
||||
while (((ret = db_query_fetch_string_sort(&qp, &browse_item, &sort_item)) == 0) && (browse_item))
|
||||
for (i = 0; i < groupsize; i++)
|
||||
{
|
||||
if (!group[i])
|
||||
continue;
|
||||
|
||||
strval = (char **) ((char *)&dbmfi + group[i]->mfi_offset);
|
||||
|
||||
if (!(*strval) || (**strval == '\0'))
|
||||
continue;
|
||||
|
||||
evbuffer_add_printf(evbuf,
|
||||
"%s%s\n",
|
||||
type,
|
||||
browse_item);
|
||||
"%s: %s\n",
|
||||
group[i]->tag,
|
||||
*strval);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((ret = db_query_fetch_group(&qp, &dbgri)) == 0)
|
||||
{
|
||||
evbuffer_add_printf(evbuf,
|
||||
"%s%s\n",
|
||||
type,
|
||||
dbgri.itemname);
|
||||
}
|
||||
}
|
||||
|
||||
db_query_end(&qp);
|
||||
free(qp.filter);
|
||||
free(qp.group);
|
||||
free(group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3140,7 +3115,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_search(argc - 1, argv + 1, &qp);
|
||||
parse_filter_window_params(argc - 1, argv + 1, false, &qp);
|
||||
|
||||
ret = db_query_start(&qp);
|
||||
if (ret < 0)
|
||||
@ -3186,7 +3161,7 @@ mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errm
|
||||
qp.sort = S_ARTIST;
|
||||
qp.idx_type = I_NONE;
|
||||
|
||||
mpd_get_query_params_search(argc - 1, argv + 1, &qp);
|
||||
parse_filter_window_params(argc - 1, argv + 1, false, &qp);
|
||||
|
||||
player_get_status(&status);
|
||||
|
||||
@ -3962,16 +3937,13 @@ mpd_command_commands(struct evbuffer *evbuf, int argc, char **argv, char **errms
|
||||
static int
|
||||
mpd_command_tagtypes(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
|
||||
{
|
||||
evbuffer_add_printf(evbuf,
|
||||
"tagtype: Artist\n"
|
||||
"tagtype: AlbumArtist\n"
|
||||
"tagtype: ArtistSort\n"
|
||||
"tagtype: AlbumArtistSort\n"
|
||||
"tagtype: Album\n"
|
||||
"tagtype: Title\n"
|
||||
"tagtype: Track\n"
|
||||
"tagtype: Genre\n"
|
||||
"tagtype: Disc\n");
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tagtypes); i++)
|
||||
{
|
||||
if (tagtypes[i].type != MPD_TYPE_SPECIAL)
|
||||
evbuffer_add_printf(evbuf, "tagtype: %s\n", tagtypes[i].tag);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user