diff --git a/src/db.c b/src/db.c index a840054e..6e1d3429 100644 --- a/src/db.c +++ b/src/db.c @@ -287,6 +287,7 @@ static const char *sort_clause[] = "ORDER BY f.composer_sort ASC", "ORDER BY f.disc ASC", "ORDER BY f.track ASC", + "ORDER BY f.virtual_path ASC", }; static char *db_path; @@ -1529,6 +1530,10 @@ db_query_start(struct query_params *qp) ret = db_build_query_browse(qp, "track", "track", &query); break; + case Q_BROWSE_VPATH: + ret = db_build_query_browse(qp, "virtual_path", "virtual_path", &query); + break; + case Q_COUNT_ITEMS: ret = db_build_query_count_items(qp, &query); break; diff --git a/src/db.h b/src/db.h index 4b8faefe..6d3e7092 100644 --- a/src/db.h +++ b/src/db.h @@ -27,26 +27,28 @@ enum sort_type { S_COMPOSER, S_DISC, S_TRACK, + S_VPATH, }; #define Q_F_BROWSE (1 << 15) enum query_type { - Q_ITEMS = (1 << 0), - Q_PL = (1 << 1), - Q_PLITEMS = (1 << 2), - Q_BROWSE_ARTISTS = Q_F_BROWSE | (1 << 3), - Q_BROWSE_ALBUMS = Q_F_BROWSE | (1 << 4), - Q_BROWSE_GENRES = Q_F_BROWSE | (1 << 5), - Q_BROWSE_COMPOSERS = Q_F_BROWSE | (1 << 6), - Q_GROUP_ALBUMS = (1 << 7), - Q_GROUP_ARTISTS = (1 << 8), - Q_GROUP_ITEMS = (1 << 9), - Q_GROUP_DIRS = Q_F_BROWSE | (1 << 10), - Q_BROWSE_YEARS = Q_F_BROWSE | (1 << 11), - Q_COUNT_ITEMS = (1 << 12), - Q_BROWSE_DISCS = Q_F_BROWSE | (1 << 13), - Q_BROWSE_TRACKS = Q_F_BROWSE | (1 << 14), + Q_ITEMS = 1, + Q_PL = 2, + Q_PLITEMS = 3, + Q_BROWSE_ARTISTS = Q_F_BROWSE | 4, + Q_BROWSE_ALBUMS = Q_F_BROWSE | 5, + Q_BROWSE_GENRES = Q_F_BROWSE | 6, + Q_BROWSE_COMPOSERS = Q_F_BROWSE | 7, + Q_GROUP_ALBUMS = 8, + Q_GROUP_ARTISTS = 9, + Q_GROUP_ITEMS = 10, + Q_GROUP_DIRS = Q_F_BROWSE | 11, + Q_BROWSE_YEARS = Q_F_BROWSE | 12, + Q_COUNT_ITEMS = 13, + Q_BROWSE_DISCS = Q_F_BROWSE | 14, + Q_BROWSE_TRACKS = Q_F_BROWSE | 15, + Q_BROWSE_VPATH = Q_F_BROWSE | 16, }; #define ARTWORK_UNKNOWN 0 diff --git a/src/mpd.c b/src/mpd.c index a51577d9..9c0b28ed 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -1797,10 +1797,49 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e return 0; } +/* + * Command handler function for 'plchanges' + * Lists all changed songs in the queue since the given playlist version in argv[1]. + */ static int mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) { - DPRINTF(E_WARN, L_MPD, "Ignore command %s\n", argv[0]); + struct player_queue *queue; + int pos_pl; + int i; + int ret; + + /* + * forked-daapd does not keep track of changes in the queue based on the playlist version, + * therefor plchanges returns all songs in the queue as changed ignoring the given version. + */ + queue = player_queue_get(0, -1, 0); + + if (!queue) + { + // Queue is emtpy + return 0; + } + + pos_pl = queue->start_pos; + for (i = 0; i < queue->count; i++) + { + ret = mpd_add_mediainfo_byid(evbuf, queue->queue[i], pos_pl); + if (ret < 0) + { + ret = asprintf(errmsg, "Error adding media info for file with id: %d", queue->queue[i]); + + queue_free(queue); + + if (ret < 0) + DPRINTF(E_LOG, L_MPD, "Out of memory\n"); + return ACK_ERROR_UNKNOWN; + } + + pos_pl++; + } + + queue_free(queue); return 0; } @@ -2151,6 +2190,14 @@ mpd_get_query_params_find(int argc, char **argv, struct query_params *qp) else c1 = sqlite3_mprintf("(f.track = %d)", num); } + else if (0 == strcasecmp(argv[i], "date")) + { + ret = safe_atou32(argv[i + 1], &num); + if (ret < 0) + c1 = sqlite3_mprintf("(f.year = 0 OR f.year IS NULL)"); + else + c1 = sqlite3_mprintf("(f.year = %d)", num); + } else if (i == 0 && argc == 1) { // Special case: a single token is allowed if listing albums for an artist @@ -2392,6 +2439,12 @@ mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) qp.sort = S_TRACK; type = "Track: "; } + else if (0 == strcasecmp(argv[1], "file")) + { + qp.type = Q_BROWSE_VPATH; + qp.sort = S_VPATH; + type = "file: "; + } else { DPRINTF(E_WARN, L_MPD, "Unsupported type argument for command 'list': %s\n", argv[1]); @@ -2418,12 +2471,26 @@ mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) if (qp.type & Q_F_BROWSE) { - while (((ret = db_query_fetch_string_sort(&qp, &browse_item, &sort_item)) == 0) && (browse_item)) + if (qp.type == Q_BROWSE_VPATH) { - evbuffer_add_printf(evbuf, - "%s%s\n", - type, - browse_item); + while (((ret = db_query_fetch_string_sort(&qp, &browse_item, &sort_item)) == 0) && (browse_item)) + { + // Remove the first "/" from the virtual_path + evbuffer_add_printf(evbuf, + "%s%s\n", + type, + (browse_item + 1)); + } + } + else + { + while (((ret = db_query_fetch_string_sort(&qp, &browse_item, &sort_item)) == 0) && (browse_item)) + { + evbuffer_add_printf(evbuf, + "%s%s\n", + type, + browse_item); + } } } else @@ -2624,6 +2691,14 @@ mpd_get_query_params_search(int argc, char **argv, struct query_params *qp) else c1 = sqlite3_mprintf("(f.track = %d)", num); } + else if (0 == strcasecmp(argv[i], "date")) + { + ret = safe_atou32(argv[i + 1], &num); + if (ret < 0) + c1 = sqlite3_mprintf("(f.year = 0 OR f.year IS NULL)"); + else + c1 = sqlite3_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]);