mirror of
https://github.com/owntone/owntone-server.git
synced 2025-11-09 13:39:47 -05:00
Merge pull request #790 from chme/admin_settings
Introduce new settings for displaying the composer in the now playing page
This commit is contained in:
@@ -122,6 +122,7 @@ forked_daapd_SOURCES = main.c \
|
||||
smartpl_query.c smartpl_query.h \
|
||||
player.c player.h \
|
||||
worker.c worker.h \
|
||||
settings.c settings.h \
|
||||
input.h input.c \
|
||||
inputs/file_http.c inputs/pipe.c \
|
||||
outputs.h outputs.c \
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "misc_json.h"
|
||||
#include "player.h"
|
||||
#include "remote_pairing.h"
|
||||
#include "settings.h"
|
||||
#include "smartpl_query.h"
|
||||
#ifdef HAVE_SPOTIFY_H
|
||||
# include "spotify_webapi.h"
|
||||
@@ -729,6 +730,259 @@ jsonapi_reply_config(struct httpd_request *hreq)
|
||||
return HTTP_OK;
|
||||
}
|
||||
|
||||
static json_object *
|
||||
option_get_json(struct settings_option *option)
|
||||
{
|
||||
const char *optionname;
|
||||
json_object *json_option;
|
||||
int intval;
|
||||
bool boolval;
|
||||
char *strval;
|
||||
|
||||
|
||||
optionname = option->name;
|
||||
|
||||
CHECK_NULL(L_WEB, json_option = json_object_new_object());
|
||||
json_object_object_add(json_option, "name", json_object_new_string(option->name));
|
||||
json_object_object_add(json_option, "type", json_object_new_int(option->type));
|
||||
|
||||
if (option->type == SETTINGS_TYPE_INT)
|
||||
{
|
||||
intval = settings_option_getint(option);
|
||||
json_object_object_add(json_option, "value", json_object_new_int(intval));
|
||||
}
|
||||
else if (option->type == SETTINGS_TYPE_BOOL)
|
||||
{
|
||||
boolval = settings_option_getbool(option);
|
||||
json_object_object_add(json_option, "value", json_object_new_boolean(boolval));
|
||||
}
|
||||
else if (option->type == SETTINGS_TYPE_STR)
|
||||
{
|
||||
strval = settings_option_getstr(option);
|
||||
if (strval)
|
||||
{
|
||||
json_object_object_add(json_option, "value", json_object_new_string(strval));
|
||||
free(strval);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Option '%s' has unknown type %d\n", optionname, option->type);
|
||||
jparse_free(json_option);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return json_option;
|
||||
}
|
||||
|
||||
static json_object *
|
||||
category_get_json(struct settings_category *category)
|
||||
{
|
||||
json_object *json_category;
|
||||
json_object *json_options;
|
||||
json_object *json_option;
|
||||
struct settings_option *option;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
json_category = json_object_new_object();
|
||||
|
||||
json_object_object_add(json_category, "name", json_object_new_string(category->name));
|
||||
|
||||
json_options = json_object_new_array();
|
||||
|
||||
count = settings_option_count(category);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
option = settings_option_get_byindex(category, i);
|
||||
json_option = option_get_json(option);
|
||||
if (json_option)
|
||||
json_object_array_add(json_options, json_option);
|
||||
}
|
||||
|
||||
json_object_object_add(json_category, "options", json_options);
|
||||
|
||||
return json_category;
|
||||
}
|
||||
|
||||
static int
|
||||
jsonapi_reply_settings_get(struct httpd_request *hreq)
|
||||
{
|
||||
struct settings_category *category;
|
||||
json_object *jreply;
|
||||
json_object *json_categories;
|
||||
json_object *json_category;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
CHECK_NULL(L_WEB, jreply = json_object_new_object());
|
||||
|
||||
json_categories = json_object_new_array();
|
||||
|
||||
count = settings_categories_count();
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
category = settings_category_get_byindex(i);
|
||||
json_category = category_get_json(category);
|
||||
if (json_category)
|
||||
json_object_array_add(json_categories, json_category);
|
||||
}
|
||||
|
||||
json_object_object_add(jreply, "categories", json_categories);
|
||||
|
||||
CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply)));
|
||||
|
||||
jparse_free(jreply);
|
||||
|
||||
return HTTP_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
jsonapi_reply_settings_category_get(struct httpd_request *hreq)
|
||||
{
|
||||
const char *categoryname;
|
||||
struct settings_category *category;
|
||||
json_object *jreply;
|
||||
|
||||
|
||||
categoryname = hreq->uri_parsed->path_parts[2];
|
||||
|
||||
category = settings_category_get(categoryname);
|
||||
if (!category)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Invalid category name '%s' given\n", categoryname);
|
||||
return HTTP_NOTFOUND;
|
||||
}
|
||||
|
||||
jreply = category_get_json(category);
|
||||
|
||||
if (!jreply)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Error getting value for category '%s'\n", categoryname);
|
||||
return HTTP_INTERNAL;
|
||||
}
|
||||
|
||||
CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply)));
|
||||
|
||||
jparse_free(jreply);
|
||||
|
||||
return HTTP_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
jsonapi_reply_settings_option_get(struct httpd_request *hreq)
|
||||
{
|
||||
const char *categoryname;
|
||||
const char *optionname;
|
||||
struct settings_category *category;
|
||||
struct settings_option *option;
|
||||
json_object *jreply;
|
||||
|
||||
|
||||
categoryname = hreq->uri_parsed->path_parts[2];
|
||||
optionname = hreq->uri_parsed->path_parts[3];
|
||||
|
||||
category = settings_category_get(categoryname);
|
||||
if (!category)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Invalid category name '%s' given\n", categoryname);
|
||||
return HTTP_NOTFOUND;
|
||||
}
|
||||
|
||||
option = settings_option_get(category, optionname);
|
||||
if (!option)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Invalid option name '%s' given\n", optionname);
|
||||
return HTTP_NOTFOUND;
|
||||
}
|
||||
|
||||
jreply = option_get_json(option);
|
||||
|
||||
if (!jreply)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Error getting value for option '%s'\n", optionname);
|
||||
return HTTP_INTERNAL;
|
||||
}
|
||||
|
||||
CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply)));
|
||||
|
||||
jparse_free(jreply);
|
||||
|
||||
return HTTP_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
jsonapi_reply_settings_option_put(struct httpd_request *hreq)
|
||||
{
|
||||
const char *categoryname;
|
||||
const char *optionname;
|
||||
struct settings_category *category;
|
||||
struct settings_option *option;
|
||||
struct evbuffer *in_evbuf;
|
||||
json_object* request;
|
||||
int intval;
|
||||
bool boolval;
|
||||
const char *strval;
|
||||
int ret;
|
||||
|
||||
|
||||
categoryname = hreq->uri_parsed->path_parts[2];
|
||||
optionname = hreq->uri_parsed->path_parts[3];
|
||||
|
||||
category = settings_category_get(categoryname);
|
||||
if (!category)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Invalid category name '%s' given\n", categoryname);
|
||||
return HTTP_NOTFOUND;
|
||||
}
|
||||
|
||||
option = settings_option_get(category, optionname);
|
||||
|
||||
if (!option)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Invalid option name '%s' given\n", optionname);
|
||||
return HTTP_NOTFOUND;
|
||||
}
|
||||
|
||||
in_evbuf = evhttp_request_get_input_buffer(hreq->req);
|
||||
request = jparse_obj_from_evbuffer(in_evbuf);
|
||||
if (!request)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Missing request body for setting option '%s' (type %d)\n", optionname, option->type);
|
||||
return HTTP_BADREQUEST;
|
||||
}
|
||||
|
||||
if (option->type == SETTINGS_TYPE_INT && jparse_contains_key(request, "value", json_type_int))
|
||||
{
|
||||
intval = jparse_int_from_obj(request, "value");
|
||||
ret = settings_option_setint(option, intval);
|
||||
}
|
||||
else if (option->type == SETTINGS_TYPE_BOOL && jparse_contains_key(request, "value", json_type_boolean))
|
||||
{
|
||||
boolval = jparse_bool_from_obj(request, "value");
|
||||
ret = settings_option_setbool(option, boolval);
|
||||
}
|
||||
else if (option->type == SETTINGS_TYPE_STR && jparse_contains_key(request, "value", json_type_string))
|
||||
{
|
||||
strval = jparse_str_from_obj(request, "value");
|
||||
ret = settings_option_setstr(option, strval);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Invalid value given for option '%s' (type %d): '%s'\n", optionname, option->type, json_object_to_json_string(request));
|
||||
return HTTP_BADREQUEST;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Error changing setting '%s' (type %d) to '%s'\n", optionname, option->type, json_object_to_json_string(request));
|
||||
return HTTP_INTERNAL;
|
||||
}
|
||||
|
||||
DPRINTF(E_INFO, L_WEB, "Setting option '%s.%s' changed to '%s'\n", categoryname, optionname, json_object_to_json_string(request));
|
||||
return HTTP_NOCONTENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Endpoint to retrieve informations about the library
|
||||
*
|
||||
@@ -3541,6 +3795,10 @@ jsonapi_reply_search(struct httpd_request *hreq)
|
||||
static struct httpd_uri_map adm_handlers[] =
|
||||
{
|
||||
{ EVHTTP_REQ_GET, "^/api/config$", jsonapi_reply_config },
|
||||
{ EVHTTP_REQ_GET, "^/api/settings$", jsonapi_reply_settings_get },
|
||||
{ EVHTTP_REQ_GET, "^/api/settings/[A-Za-z0-9_]+$", jsonapi_reply_settings_category_get },
|
||||
{ EVHTTP_REQ_GET, "^/api/settings/[A-Za-z0-9_]+/[A-Za-z0-9_]+$", jsonapi_reply_settings_option_get },
|
||||
{ EVHTTP_REQ_PUT, "^/api/settings/[A-Za-z0-9_]+/[A-Za-z0-9_]+$", jsonapi_reply_settings_option_put },
|
||||
{ EVHTTP_REQ_GET, "^/api/library$", jsonapi_reply_library },
|
||||
{ EVHTTP_REQ_GET |
|
||||
EVHTTP_REQ_PUT, "^/api/update$", jsonapi_reply_update },
|
||||
|
||||
153
src/settings.c
Normal file
153
src/settings.c
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Christian Meffert <christian.meffert@googlemail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
|
||||
|
||||
static struct settings_option webinterface_options[] =
|
||||
{
|
||||
{ "show_composer_now_playing", SETTINGS_TYPE_BOOL },
|
||||
{ "show_composer_for_genre", SETTINGS_TYPE_STR },
|
||||
};
|
||||
|
||||
static struct settings_category categories[] =
|
||||
{
|
||||
{ "webinterface", webinterface_options, ARRAY_SIZE(webinterface_options) },
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
settings_categories_count()
|
||||
{
|
||||
return ARRAY_SIZE(categories);
|
||||
}
|
||||
|
||||
struct settings_category *
|
||||
settings_category_get_byindex(int index)
|
||||
{
|
||||
if (index < 0 || settings_categories_count() <= index)
|
||||
return NULL;
|
||||
return &categories[index];
|
||||
}
|
||||
|
||||
struct settings_category *
|
||||
settings_category_get(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < settings_categories_count(); i++)
|
||||
{
|
||||
if (strcasecmp(name, categories[i].name) == 0)
|
||||
return &categories[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
settings_option_count(struct settings_category *category)
|
||||
{
|
||||
return category->count_options;
|
||||
}
|
||||
|
||||
struct settings_option *
|
||||
settings_option_get_byindex(struct settings_category *category, int index)
|
||||
{
|
||||
if (index < 0 || !category || category->count_options <= index)
|
||||
return NULL;
|
||||
|
||||
return &category->options[index];
|
||||
}
|
||||
|
||||
struct settings_option *
|
||||
settings_option_get(struct settings_category *category, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!category || !name)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < category->count_options; i++)
|
||||
{
|
||||
if (strcasecmp(name, category->options[i].name) == 0)
|
||||
return &category->options[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
settings_option_getint(struct settings_option *option)
|
||||
{
|
||||
if (!option || option->type != SETTINGS_TYPE_INT)
|
||||
return 0;
|
||||
|
||||
return db_admin_getint(option->name);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
settings_option_getbool(struct settings_option *option)
|
||||
{
|
||||
if (!option || option->type != SETTINGS_TYPE_BOOL)
|
||||
return false;
|
||||
|
||||
return db_admin_getint(option->name) > 0;
|
||||
}
|
||||
|
||||
char *
|
||||
settings_option_getstr(struct settings_option *option)
|
||||
{
|
||||
if (!option || option->type != SETTINGS_TYPE_STR)
|
||||
return NULL;
|
||||
|
||||
return db_admin_get(option->name);
|
||||
}
|
||||
|
||||
int
|
||||
settings_option_setint(struct settings_option *option, int value)
|
||||
{
|
||||
if (!option || option->type != SETTINGS_TYPE_INT)
|
||||
return -1;
|
||||
|
||||
return db_admin_setint(option->name, value);
|
||||
}
|
||||
|
||||
int
|
||||
settings_option_setbool(struct settings_option *option, bool value)
|
||||
{
|
||||
if (!option || option->type != SETTINGS_TYPE_BOOL)
|
||||
return -1;
|
||||
|
||||
return db_admin_setint(option->name, value);
|
||||
}
|
||||
|
||||
int
|
||||
settings_option_setstr(struct settings_option *option, const char *value)
|
||||
{
|
||||
if (!option || option->type != SETTINGS_TYPE_STR)
|
||||
return -1;
|
||||
|
||||
return db_admin_set(option->name, value);
|
||||
}
|
||||
65
src/settings.h
Normal file
65
src/settings.h
Normal file
@@ -0,0 +1,65 @@
|
||||
|
||||
#ifndef __SETTINGS_H__
|
||||
#define __SETTINGS_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
enum settings_type {
|
||||
SETTINGS_TYPE_INT,
|
||||
SETTINGS_TYPE_BOOL,
|
||||
SETTINGS_TYPE_STR,
|
||||
SETTINGS_TYPE_CATEGORY,
|
||||
};
|
||||
|
||||
struct settings_option {
|
||||
const char *name;
|
||||
enum settings_type type;
|
||||
};
|
||||
|
||||
struct settings_category {
|
||||
const char *name;
|
||||
struct settings_option *options;
|
||||
int count_options;
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
settings_categories_count();
|
||||
|
||||
struct settings_category *
|
||||
settings_category_get_byindex(int index);
|
||||
|
||||
struct settings_category *
|
||||
settings_category_get(const char *name);
|
||||
|
||||
int
|
||||
settings_option_count(struct settings_category *category);
|
||||
|
||||
struct settings_option *
|
||||
settings_option_get_byindex(struct settings_category *category, int index);
|
||||
|
||||
struct settings_option *
|
||||
settings_option_get(struct settings_category *category, const char *name);
|
||||
|
||||
int
|
||||
settings_option_getint(struct settings_option *option);
|
||||
|
||||
|
||||
bool
|
||||
settings_option_getbool(struct settings_option *option);
|
||||
|
||||
char *
|
||||
settings_option_getstr(struct settings_option *option);
|
||||
|
||||
int
|
||||
settings_option_setint(struct settings_option *option, int value);
|
||||
|
||||
int
|
||||
settings_option_setbool(struct settings_option *option, bool value);
|
||||
|
||||
int
|
||||
settings_option_setstr(struct settings_option *option, const char *value);
|
||||
|
||||
|
||||
#endif /* __SETTINGS_H__ */
|
||||
Reference in New Issue
Block a user