[mpd] Refactor sticker commands

This commit is contained in:
chme 2017-12-10 09:24:29 +01:00 committed by ejurgensen
parent ef52f4ddc0
commit 7a916c84a2

235
src/mpd.c
View File

@ -59,6 +59,9 @@
#include "remote_pairing.h" #include "remote_pairing.h"
#define MPD_ALL_IDLE_LISTENER_EVENTS (LISTENER_PLAYER | LISTENER_QUEUE | LISTENER_VOLUME | LISTENER_SPEAKER | LISTENER_OPTIONS | LISTENER_DATABASE | LISTENER_UPDATE | LISTENER_STORED_PLAYLIST | LISTENER_STICKER)
#define MPD_RATING_FACTOR 10.0
static pthread_t tid_mpd; static pthread_t tid_mpd;
static struct event_base *evbase_mpd; static struct event_base *evbase_mpd;
@ -67,8 +70,6 @@ static struct commands_base *cmdbase;
static struct evhttp *evhttpd; static struct evhttp *evhttpd;
#define ALL_IDLE_LISTENER_EVENTS (LISTENER_PLAYER | LISTENER_QUEUE | LISTENER_VOLUME | LISTENER_SPEAKER | LISTENER_OPTIONS | LISTENER_DATABASE | LISTENER_UPDATE | LISTENER_STORED_PLAYLIST | LISTENER_STICKER)
struct evconnlistener *mpd_listener6; struct evconnlistener *mpd_listener6;
struct evconnlistener *mpd_listener; struct evconnlistener *mpd_listener;
@ -674,7 +675,7 @@ mpd_command_idle(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s
} }
} }
else else
ctx->idle_events = ALL_IDLE_LISTENER_EVENTS; ctx->idle_events = MPD_ALL_IDLE_LISTENER_EVENTS;
// If events the client listens to occurred since the last idle call (or since the client connected, // If events the client listens to occurred since the last idle call (or since the client connected,
// if it is the first idle call), notify immediately. // if it is the first idle call), notify immediately.
@ -3248,108 +3249,128 @@ mpd_command_update(struct evbuffer *evbuf, int argc, char **argv, char **errmsg,
return 0; return 0;
} }
struct mpd_sticker_command {
const char *cmd;
int (*handler)(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *name, const char *virtual_path, bool name_is_rating, struct media_file_info *mfi, int *rating, bool *set_rating);
int need_args;
int want_dir;
int get_mfi;
};
#define MPD_RATING_FACTOR 10.0
static int static int
mpd_sticker_get(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *name, const char *virtual_path, bool name_is_rating, struct media_file_info *mfi, int *rating, bool *set_rating) mpd_sticker_get(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *virtual_path)
{ {
struct media_file_info *mfi = NULL;
uint32_t rating;
int ret = 0; int ret = 0;
if (name_is_rating) if (strcmp(argv[4], "rating") != 0)
{
if (!mfi || !mfi->rating)
{ {
*errmsg = safe_asprintf("no such sticker"); *errmsg = safe_asprintf("no such sticker");
ret = ACK_ERROR_NO_EXIST; return ACK_ERROR_NO_EXIST;
return ret;
}
*rating = mfi->rating / MPD_RATING_FACTOR;
evbuffer_add_printf(evbuf, "sticker: rating=%d\n", *rating);
return ret;
} }
/* |:todo:| real sticker implementation */ mfi = db_file_fetch_byvirtualpath(virtual_path);
*errmsg = safe_asprintf("no such sticker"); if (!mfi)
ret = ACK_ERROR_NO_EXIST; {
return ret; DPRINTF(E_LOG, L_MPD, "Virtual path not found: %s\n", virtual_path);
*errmsg = safe_asprintf("unknown sticker domain");
return ACK_ERROR_ARG;
}
if (mfi && mfi->rating > 0)
{
rating = mfi->rating / MPD_RATING_FACTOR;
evbuffer_add_printf(evbuf, "sticker: rating=%d\n", rating);
}
free_mfi(mfi, 0);
return 0;
} }
static int static int
mpd_sticker_set(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *name, const char *virtual_path, bool name_is_rating, struct media_file_info *mfi, int *rating, bool *set_rating) mpd_sticker_set(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *virtual_path)
{ {
uint32_t rating;
int ret = 0; int ret = 0;
if (name_is_rating) if (strcmp(argv[4], "rating") != 0)
{ {
ret = safe_atou32(argv[5], (unsigned int *) rating); *errmsg = safe_asprintf("no such sticker");
return ACK_ERROR_NO_EXIST;
}
ret = safe_atou32(argv[5], &rating);
if (ret < 0) if (ret < 0)
{ {
*errmsg = safe_asprintf("rating '%s' doesn't convert to integer", argv[5]); *errmsg = safe_asprintf("rating '%s' doesn't convert to integer", argv[5]);
ret = ACK_ERROR_ARG; return ACK_ERROR_ARG;
return ret;
}
*rating *= MPD_RATING_FACTOR;
*set_rating = 1;
return ret;
} }
/* |:todo:| real sticker implementation */ rating *= MPD_RATING_FACTOR;
ret = db_file_rating_update_byvirtualpath(virtual_path, rating);
if (ret <= 0)
{
*errmsg = safe_asprintf("Invalid path '%s'", virtual_path);
return ACK_ERROR_ARG;
}
return 0;
}
static int
mpd_sticker_delete(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *virtual_path)
{
int ret = 0;
if (strcmp(argv[4], "rating") != 0)
{
*errmsg = safe_asprintf("no such sticker"); *errmsg = safe_asprintf("no such sticker");
ret = ACK_ERROR_NO_EXIST; return ACK_ERROR_NO_EXIST;
return ret;
}
static int
mpd_sticker_delete(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *name, const char *virtual_path, bool name_is_rating, struct media_file_info *mfi, int *rating, bool *set_rating)
{
int ret = 0;
if (name_is_rating)
{
*rating = 0;
*set_rating = 1;
return ret;
} }
/* |:todo:| real sticker implementation */ ret = db_file_rating_update_byvirtualpath(virtual_path, 0);
*errmsg = safe_asprintf("no such sticker"); if (ret <= 0)
ret = ACK_ERROR_NO_EXIST; {
return ret; *errmsg = safe_asprintf("Invalid path '%s'", virtual_path);
return ACK_ERROR_ARG;
}
return 0;
} }
static int static int
mpd_sticker_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *name, const char *virtual_path, bool name_is_rating, struct media_file_info *mfi, int *rating, bool *set_rating) mpd_sticker_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *virtual_path)
{ {
struct media_file_info *mfi = NULL;
uint32_t rating;
int ret = 0; int ret = 0;
if (mfi && mfi->rating) mfi = db_file_fetch_byvirtualpath(virtual_path);
if (!mfi)
{ {
*rating = mfi->rating / MPD_RATING_FACTOR; DPRINTF(E_LOG, L_MPD, "Virtual path not found: %s\n", virtual_path);
evbuffer_add_printf(evbuf, "sticker: rating=%d\n", *rating); *errmsg = safe_asprintf("unknown sticker domain");
return ACK_ERROR_ARG;
} }
if (mfi && mfi->rating > 0)
{
rating = mfi->rating / MPD_RATING_FACTOR;
evbuffer_add_printf(evbuf, "sticker: rating=%d\n", rating);
}
free_mfi(mfi, 0);
/* |:todo:| real sticker implementation */ /* |:todo:| real sticker implementation */
return ret; return 0;
} }
static int static int
mpd_sticker_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *name, const char *virtual_path, bool name_is_rating, struct media_file_info *mfi, int *rating, bool *set_rating) mpd_sticker_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *virtual_path)
{ {
int ret = 0;
if (name_is_rating && argc == 5)
{
struct query_params qp; struct query_params qp;
struct db_media_file_info dbmfi; struct db_media_file_info dbmfi;
char *c1; uint32_t rating;
int ret = 0;
if (strcmp(argv[4], "rating") != 0)
{
*errmsg = safe_asprintf("no such sticker");
return ACK_ERROR_NO_EXIST;
}
memset(&qp, 0, sizeof(struct query_params)); memset(&qp, 0, sizeof(struct query_params));
@ -3357,14 +3378,13 @@ mpd_sticker_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, c
qp.sort = S_VPATH; qp.sort = S_VPATH;
qp.idx_type = I_NONE; qp.idx_type = I_NONE;
c1 = db_mprintf("(f.virtual_path LIKE '%s%%' AND f.rating != 0)", virtual_path); qp.filter = db_mprintf("(f.virtual_path LIKE '%s%%' AND f.rating > 0)", virtual_path);
if (!c1) if (!qp.filter)
{ {
*errmsg = safe_asprintf("Out of memory"); *errmsg = safe_asprintf("Out of memory");
ret = ACK_ERROR_UNKNOWN; ret = ACK_ERROR_UNKNOWN;
return ret; return ret;
} }
qp.filter = c1;
ret = db_query_start(&qp); ret = db_query_start(&qp);
if (ret < 0) if (ret < 0)
@ -3379,48 +3399,42 @@ mpd_sticker_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, c
while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
{ {
ret = safe_atou32(dbmfi.rating, (unsigned int *) rating); ret = safe_atou32(dbmfi.rating, &rating);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_MPD, "Error rating=%s doesn't convert to integer, song id: %s\n", DPRINTF(E_LOG, L_MPD, "Error rating=%s doesn't convert to integer, song id: %s\n",
dbmfi.rating, dbmfi.id); dbmfi.rating, dbmfi.id);
continue; continue;
} }
*rating /= MPD_RATING_FACTOR;
if (!*rating)
/* inconsistent database */
continue;
rating /= MPD_RATING_FACTOR;
ret = evbuffer_add_printf(evbuf, ret = evbuffer_add_printf(evbuf,
"file: file:%s\n" "file: file:%s\n"
"sticker: rating=%d\n", "sticker: rating=%d\n",
dbmfi.path, dbmfi.path,
*rating); rating);
if (ret < 0) if (ret < 0)
DPRINTF(E_LOG, L_MPD, "Error adding song to the evbuffer, song id: %s\n", dbmfi.id); DPRINTF(E_LOG, L_MPD, "Error adding song to the evbuffer, song id: %s\n", dbmfi.id);
} }
ret = 0;
db_query_end(&qp); db_query_end(&qp);
free(qp.filter); free(qp.filter);
return ret; return 0;
}
/* |:todo:| MPD_STICKER_FIND with expressions */
/* |:todo:| real sticker implementation */
*errmsg = safe_asprintf("bad request");
ret = ACK_ERROR_ARG;
return ret;
} }
struct mpd_sticker_command {
const char *cmd;
int (*handler)(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *virtual_path);
int need_args;
};
static struct mpd_sticker_command mpd_sticker_handlers[] = { static struct mpd_sticker_command mpd_sticker_handlers[] = {
{ "get", mpd_sticker_get, 5, 0, 0 }, { "get", mpd_sticker_get, 5 },
{ "set", mpd_sticker_set, 6, 0, 0 }, { "set", mpd_sticker_set, 6 },
{ "delete", mpd_sticker_delete, 5, 0, 0 }, { "delete", mpd_sticker_delete, 5 },
{ "list", mpd_sticker_list, 4, 0, 1 }, { "list", mpd_sticker_list, 4 },
{ "find", mpd_sticker_find, 5, 1, 0 }, { "find", mpd_sticker_find, 5 },
{ NULL, NULL, 0, 0, 0 }, { NULL, NULL, 0 },
}; };
/* /*
@ -3444,13 +3458,7 @@ static int
mpd_command_sticker(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx) mpd_command_sticker(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct mpd_sticker_command *cmd_param; struct mpd_sticker_command *cmd_param;
const char *cmd;
char *virtual_path = NULL; char *virtual_path = NULL;
const char *name = NULL;
bool name_is_rating = false;
struct media_file_info *mfi = NULL;
int rating = -1;
bool set_rating = false;
int i; int i;
int ret; int ret;
@ -3466,11 +3474,10 @@ mpd_command_sticker(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
return ACK_ERROR_ARG; return ACK_ERROR_ARG;
} }
cmd = argv[1];
for (i=0; i<(sizeof(mpd_sticker_handlers) / sizeof(struct mpd_sticker_command)); ++i) for (i=0; i<(sizeof(mpd_sticker_handlers) / sizeof(struct mpd_sticker_command)); ++i)
{ {
cmd_param = &mpd_sticker_handlers[i]; cmd_param = &mpd_sticker_handlers[i];
if (cmd_param->cmd && strcmp(cmd, cmd_param->cmd) == 0) if (cmd_param->cmd && strcmp(argv[1], cmd_param->cmd) == 0)
break; break;
} }
if (!cmd_param->cmd) if (!cmd_param->cmd)
@ -3484,38 +3491,12 @@ mpd_command_sticker(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
return ACK_ERROR_ARG; return ACK_ERROR_ARG;
} }
if (argc > 4)
{
name = argv[4];
name_is_rating = strcmp(name, "rating") == 0;
}
virtual_path = prepend_slash(argv[3]); virtual_path = prepend_slash(argv[3]);
if (cmd_param->get_mfi || (!cmd_param->want_dir && name_is_rating)) ret = cmd_param->handler(evbuf, argc, argv, errmsg, virtual_path);
{
mfi = db_file_fetch_byvirtualpath(virtual_path);
if (!mfi)
{
DPRINTF(E_LOG, L_MPD, "Virtual path not found: %s\n", virtual_path);
*errmsg = safe_asprintf("unknown sticker domain");
free(virtual_path);
return ACK_ERROR_ARG;
}
}
ret = cmd_param->handler(evbuf, argc, argv, errmsg, name, virtual_path, name_is_rating, mfi, &rating, &set_rating);
if (ret == 0 && mfi && set_rating && mfi->rating != rating)
{
db_file_rating_update_byvirtualpath(virtual_path, rating);
}
free(virtual_path); free(virtual_path);
if (mfi)
free_mfi(mfi, 0);
return ret; return ret;
} }
@ -5396,7 +5377,7 @@ int mpd_init(void)
#endif #endif
mpd_clients = NULL; mpd_clients = NULL;
listener_add(mpd_listener_cb, ALL_IDLE_LISTENER_EVENTS); listener_add(mpd_listener_cb, MPD_ALL_IDLE_LISTENER_EVENTS);
return 0; return 0;