[mpd] Refactor sticker commands
This commit is contained in:
parent
ef52f4ddc0
commit
7a916c84a2
365
src/mpd.c
365
src/mpd.c
|
@ -59,6 +59,9 @@
|
|||
#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 struct event_base *evbase_mpd;
|
||||
|
@ -67,8 +70,6 @@ static struct commands_base *cmdbase;
|
|||
|
||||
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_listener;
|
||||
|
||||
|
@ -674,7 +675,7 @@ mpd_command_idle(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, s
|
|||
}
|
||||
}
|
||||
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 it is the first idle call), notify immediately.
|
||||
|
@ -3248,179 +3249,192 @@ mpd_command_update(struct evbuffer *evbuf, int argc, char **argv, char **errmsg,
|
|||
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;
|
||||
};
|
||||
static int
|
||||
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;
|
||||
|
||||
#define MPD_RATING_FACTOR 10.0
|
||||
if (strcmp(argv[4], "rating") != 0)
|
||||
{
|
||||
*errmsg = safe_asprintf("no such sticker");
|
||||
return ACK_ERROR_NO_EXIST;
|
||||
}
|
||||
|
||||
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");
|
||||
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
|
||||
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_set(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *virtual_path)
|
||||
{
|
||||
uint32_t rating;
|
||||
int ret = 0;
|
||||
|
||||
if (strcmp(argv[4], "rating") != 0)
|
||||
{
|
||||
*errmsg = safe_asprintf("no such sticker");
|
||||
return ACK_ERROR_NO_EXIST;
|
||||
}
|
||||
|
||||
ret = safe_atou32(argv[5], &rating);
|
||||
if (ret < 0)
|
||||
{
|
||||
*errmsg = safe_asprintf("rating '%s' doesn't convert to integer", argv[5]);
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
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 (name_is_rating)
|
||||
if (strcmp(argv[4], "rating") != 0)
|
||||
{
|
||||
if (!mfi || !mfi->rating)
|
||||
{
|
||||
*errmsg = safe_asprintf("no such sticker");
|
||||
ret = ACK_ERROR_NO_EXIST;
|
||||
return ret;
|
||||
}
|
||||
*rating = mfi->rating / MPD_RATING_FACTOR;
|
||||
evbuffer_add_printf(evbuf, "sticker: rating=%d\n", *rating);
|
||||
*errmsg = safe_asprintf("no such sticker");
|
||||
return ACK_ERROR_NO_EXIST;
|
||||
}
|
||||
|
||||
ret = db_file_rating_update_byvirtualpath(virtual_path, 0);
|
||||
if (ret <= 0)
|
||||
{
|
||||
*errmsg = safe_asprintf("Invalid path '%s'", virtual_path);
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
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;
|
||||
|
||||
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");
|
||||
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 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mpd_sticker_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, const char *virtual_path)
|
||||
{
|
||||
struct query_params qp;
|
||||
struct db_media_file_info dbmfi;
|
||||
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));
|
||||
|
||||
qp.type = Q_ITEMS;
|
||||
qp.sort = S_VPATH;
|
||||
qp.idx_type = I_NONE;
|
||||
|
||||
qp.filter = db_mprintf("(f.virtual_path LIKE '%s%%' AND f.rating > 0)", virtual_path);
|
||||
if (!qp.filter)
|
||||
{
|
||||
*errmsg = safe_asprintf("Out of memory");
|
||||
ret = ACK_ERROR_UNKNOWN;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* |:todo:| real sticker implementation */
|
||||
*errmsg = safe_asprintf("no such sticker");
|
||||
ret = ACK_ERROR_NO_EXIST;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (name_is_rating)
|
||||
ret = db_query_start(&qp);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = safe_atou32(argv[5], (unsigned int *) rating);
|
||||
if (ret < 0)
|
||||
{
|
||||
*errmsg = safe_asprintf("rating '%s' doesn't convert to integer", argv[5]);
|
||||
ret = ACK_ERROR_ARG;
|
||||
return ret;
|
||||
}
|
||||
*rating *= MPD_RATING_FACTOR;
|
||||
*set_rating = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* |:todo:| real sticker implementation */
|
||||
*errmsg = safe_asprintf("no such sticker");
|
||||
ret = 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 */
|
||||
*errmsg = safe_asprintf("no such sticker");
|
||||
ret = ACK_ERROR_NO_EXIST;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (mfi && mfi->rating)
|
||||
{
|
||||
*rating = mfi->rating / MPD_RATING_FACTOR;
|
||||
evbuffer_add_printf(evbuf, "sticker: rating=%d\n", *rating);
|
||||
}
|
||||
|
||||
/* |:todo:| real sticker implementation */
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (name_is_rating && argc == 5)
|
||||
{
|
||||
struct query_params qp;
|
||||
struct db_media_file_info dbmfi;
|
||||
char *c1;
|
||||
|
||||
memset(&qp, 0, sizeof(struct query_params));
|
||||
|
||||
qp.type = Q_ITEMS;
|
||||
qp.sort = S_VPATH;
|
||||
qp.idx_type = I_NONE;
|
||||
|
||||
c1 = db_mprintf("(f.virtual_path LIKE '%s%%' AND f.rating != 0)", virtual_path);
|
||||
if (!c1)
|
||||
{
|
||||
*errmsg = safe_asprintf("Out of memory");
|
||||
ret = ACK_ERROR_UNKNOWN;
|
||||
return ret;
|
||||
}
|
||||
qp.filter = c1;
|
||||
|
||||
ret = db_query_start(&qp);
|
||||
if (ret < 0)
|
||||
{
|
||||
db_query_end(&qp);
|
||||
free(qp.filter);
|
||||
|
||||
*errmsg = safe_asprintf("Could not start query");
|
||||
ret = ACK_ERROR_UNKNOWN;
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
|
||||
{
|
||||
ret = safe_atou32(dbmfi.rating, (unsigned int *) rating);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MPD, "Error rating=%s doesn't convert to integer, song id: %s\n",
|
||||
dbmfi.rating, dbmfi.id);
|
||||
continue;
|
||||
}
|
||||
*rating /= MPD_RATING_FACTOR;
|
||||
if (!*rating)
|
||||
/* inconsistent database */
|
||||
continue;
|
||||
|
||||
ret = evbuffer_add_printf(evbuf,
|
||||
"file: file:%s\n"
|
||||
"sticker: rating=%d\n",
|
||||
dbmfi.path,
|
||||
*rating);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Error adding song to the evbuffer, song id: %s\n", dbmfi.id);
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
db_query_end(&qp);
|
||||
free(qp.filter);
|
||||
|
||||
*errmsg = safe_asprintf("Could not start query");
|
||||
ret = ACK_ERROR_UNKNOWN;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* |:todo:| MPD_STICKER_FIND with expressions */
|
||||
while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
|
||||
{
|
||||
ret = safe_atou32(dbmfi.rating, &rating);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MPD, "Error rating=%s doesn't convert to integer, song id: %s\n",
|
||||
dbmfi.rating, dbmfi.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* |:todo:| real sticker implementation */
|
||||
*errmsg = safe_asprintf("bad request");
|
||||
ret = ACK_ERROR_ARG;
|
||||
return ret;
|
||||
rating /= MPD_RATING_FACTOR;
|
||||
ret = evbuffer_add_printf(evbuf,
|
||||
"file: file:%s\n"
|
||||
"sticker: rating=%d\n",
|
||||
dbmfi.path,
|
||||
rating);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Error adding song to the evbuffer, song id: %s\n", dbmfi.id);
|
||||
}
|
||||
|
||||
db_query_end(&qp);
|
||||
free(qp.filter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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[] = {
|
||||
{ "get", mpd_sticker_get, 5, 0, 0 },
|
||||
{ "set", mpd_sticker_set, 6, 0, 0 },
|
||||
{ "delete", mpd_sticker_delete, 5, 0, 0 },
|
||||
{ "list", mpd_sticker_list, 4, 0, 1 },
|
||||
{ "find", mpd_sticker_find, 5, 1, 0 },
|
||||
{ NULL, NULL, 0, 0, 0 },
|
||||
{ "get", mpd_sticker_get, 5 },
|
||||
{ "set", mpd_sticker_set, 6 },
|
||||
{ "delete", mpd_sticker_delete, 5 },
|
||||
{ "list", mpd_sticker_list, 4 },
|
||||
{ "find", mpd_sticker_find, 5 },
|
||||
{ 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)
|
||||
{
|
||||
struct mpd_sticker_command *cmd_param;
|
||||
const char *cmd;
|
||||
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 ret;
|
||||
|
||||
|
@ -3466,11 +3474,10 @@ mpd_command_sticker(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
|
|||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
cmd = argv[1];
|
||||
for (i=0; i<(sizeof(mpd_sticker_handlers) / sizeof(struct mpd_sticker_command)); ++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;
|
||||
}
|
||||
if (!cmd_param->cmd)
|
||||
|
@ -3484,38 +3491,12 @@ mpd_command_sticker(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
|
|||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
if (argc > 4)
|
||||
{
|
||||
name = argv[4];
|
||||
name_is_rating = strcmp(name, "rating") == 0;
|
||||
}
|
||||
|
||||
virtual_path = prepend_slash(argv[3]);
|
||||
|
||||
if (cmd_param->get_mfi || (!cmd_param->want_dir && name_is_rating))
|
||||
{
|
||||
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);
|
||||
}
|
||||
ret = cmd_param->handler(evbuf, argc, argv, errmsg, virtual_path);
|
||||
|
||||
free(virtual_path);
|
||||
|
||||
if (mfi)
|
||||
free_mfi(mfi, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -5396,7 +5377,7 @@ int mpd_init(void)
|
|||
#endif
|
||||
|
||||
mpd_clients = NULL;
|
||||
listener_add(mpd_listener_cb, ALL_IDLE_LISTENER_EVENTS);
|
||||
listener_add(mpd_listener_cb, MPD_ALL_IDLE_LISTENER_EVENTS);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue