mirror of
https://github.com/owntone/owntone-server.git
synced 2025-02-25 04:19:15 -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:
commit
7925639f5b
@ -8,6 +8,7 @@ Available API endpoints:
|
|||||||
* [Library](#library): list playlists, artists, albums and tracks from your library or trigger library rescan
|
* [Library](#library): list playlists, artists, albums and tracks from your library or trigger library rescan
|
||||||
* [Search](#search): search for playlists, artists, albums and tracks
|
* [Search](#search): search for playlists, artists, albums and tracks
|
||||||
* [Server info](#server-info): get server information
|
* [Server info](#server-info): get server information
|
||||||
|
* [Settings](#settings): list and change settings for the player web interface
|
||||||
* [Push notifications](#push-notifications): receive push notifications
|
* [Push notifications](#push-notifications): receive push notifications
|
||||||
|
|
||||||
JSON-Object model:
|
JSON-Object model:
|
||||||
@ -1916,6 +1917,163 @@ curl -X GET "http://localhost:3689/api/config"
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
|
||||||
|
| Method | Endpoint | Description |
|
||||||
|
| --------- | ------------------------------------------------ | ------------------------------------ |
|
||||||
|
| GET | [/api/settings](#list-categories) | Get all available categories |
|
||||||
|
| GET | [/api/settings/{category-name}](#get-a-category) | Get all available options for a category |
|
||||||
|
| GET | [/api/settings/{category-name}/{option-name}](#get-a-option) | Get a single setting option |
|
||||||
|
| PUT | [/api/settings/{category-name}/{option-name}](#change-a-option-value) | Change the value of a setting option |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### List categories
|
||||||
|
|
||||||
|
List all settings categories with their options
|
||||||
|
|
||||||
|
**Endpoint**
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/settings
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
| Key | Type | Value |
|
||||||
|
| --------------- | -------- | ----------------------------------------- |
|
||||||
|
| categories | array | Array of settings [category](#category-object) objects |
|
||||||
|
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -X GET "http://localhost:3689/api/settings"
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"name": "webinterface",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "show_composer_now_playing",
|
||||||
|
"type": 1,
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "show_composer_for_genre",
|
||||||
|
"type": 2,
|
||||||
|
"value": "classical"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Get a category
|
||||||
|
|
||||||
|
Get a settings category with their options
|
||||||
|
|
||||||
|
**Endpoint**
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/settings/{category-name}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
Returns a settings [category](#category-object) object
|
||||||
|
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -X GET "http://localhost:3689/api/settings/webinterface"
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "webinterface",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "show_composer_now_playing",
|
||||||
|
"type": 1,
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "show_composer_for_genre",
|
||||||
|
"type": 2,
|
||||||
|
"value": "classical"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Get a option
|
||||||
|
|
||||||
|
Get a single settings option
|
||||||
|
|
||||||
|
**Endpoint**
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/settings/{category-name}/{option-name}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
Returns a settings [option](#option-object) object
|
||||||
|
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -X GET "http://localhost:3689/api/settings/webinterface/show_composer_now_playing"
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "show_composer_now_playing",
|
||||||
|
"type": 1,
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Change a option value
|
||||||
|
|
||||||
|
Get a single settings option
|
||||||
|
|
||||||
|
**Endpoint**
|
||||||
|
|
||||||
|
```http
|
||||||
|
PUT /api/settings/{category-name}/{option-name}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request**
|
||||||
|
|
||||||
|
| Key | Type | Value |
|
||||||
|
| --------------- | -------- | ----------------------------------------- |
|
||||||
|
| name | string | Option name |
|
||||||
|
| value | (integer / boolean / string) | New option value |
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
On success returns the HTTP `204 No Content` success status response code.
|
||||||
|
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -X PUT "http://localhost:3689/api/settings/webinterface/show_composer_now_playing" --data "{\"name\":\"show_composer_now_playing\",\"value\":true}"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Push notifications
|
## Push notifications
|
||||||
|
|
||||||
If forked-daapd was built with websocket support, forked-daapd exposes a websocket at `localhost:3688` to inform clients of changes (e. g. player state or library updates).
|
If forked-daapd was built with websocket support, forked-daapd exposes a websocket at `localhost:3688` to inform clients of changes (e. g. player state or library updates).
|
||||||
@ -2103,6 +2261,23 @@ curl --include \
|
|||||||
| path | string | Directory path |
|
| path | string | Directory path |
|
||||||
|
|
||||||
|
|
||||||
|
### `category` object
|
||||||
|
|
||||||
|
| Key | Type | Value |
|
||||||
|
| --------------- | -------- | ----------------------------------------- |
|
||||||
|
| name | string | Category name |
|
||||||
|
| options | array | Array of option in this category |
|
||||||
|
|
||||||
|
|
||||||
|
### `option` object
|
||||||
|
|
||||||
|
| Key | Type | Value |
|
||||||
|
| --------------- | -------- | ----------------------------------------- |
|
||||||
|
| name | string | Option name |
|
||||||
|
| type | integer | The type of the value for this option (`0`: integer, `1`: boolean, `2`: string) |
|
||||||
|
| value | (integer / boolean / string) | Current value for this option |
|
||||||
|
|
||||||
|
|
||||||
### Artwork urls
|
### Artwork urls
|
||||||
|
|
||||||
Artwork urls in `queue item`, `artist`, `album` and `track` objects can be either relative urls or absolute urls to the artwork image.
|
Artwork urls in `queue item`, `artist`, `album` and `track` objects can be either relative urls or absolute urls to the artwork image.
|
||||||
|
@ -122,6 +122,7 @@ forked_daapd_SOURCES = main.c \
|
|||||||
smartpl_query.c smartpl_query.h \
|
smartpl_query.c smartpl_query.h \
|
||||||
player.c player.h \
|
player.c player.h \
|
||||||
worker.c worker.h \
|
worker.c worker.h \
|
||||||
|
settings.c settings.h \
|
||||||
input.h input.c \
|
input.h input.c \
|
||||||
inputs/file_http.c inputs/pipe.c \
|
inputs/file_http.c inputs/pipe.c \
|
||||||
outputs.h outputs.c \
|
outputs.h outputs.c \
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "misc_json.h"
|
#include "misc_json.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "remote_pairing.h"
|
#include "remote_pairing.h"
|
||||||
|
#include "settings.h"
|
||||||
#include "smartpl_query.h"
|
#include "smartpl_query.h"
|
||||||
#ifdef HAVE_SPOTIFY_H
|
#ifdef HAVE_SPOTIFY_H
|
||||||
# include "spotify_webapi.h"
|
# include "spotify_webapi.h"
|
||||||
@ -729,6 +730,259 @@ jsonapi_reply_config(struct httpd_request *hreq)
|
|||||||
return HTTP_OK;
|
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
|
* 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[] =
|
static struct httpd_uri_map adm_handlers[] =
|
||||||
{
|
{
|
||||||
{ EVHTTP_REQ_GET, "^/api/config$", jsonapi_reply_config },
|
{ 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, "^/api/library$", jsonapi_reply_library },
|
||||||
{ EVHTTP_REQ_GET |
|
{ EVHTTP_REQ_GET |
|
||||||
EVHTTP_REQ_PUT, "^/api/update$", jsonapi_reply_update },
|
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__ */
|
@ -106,6 +106,7 @@ export default {
|
|||||||
vm.update_outputs()
|
vm.update_outputs()
|
||||||
vm.update_player_status()
|
vm.update_player_status()
|
||||||
vm.update_library_stats()
|
vm.update_library_stats()
|
||||||
|
vm.update_settings()
|
||||||
vm.update_queue()
|
vm.update_queue()
|
||||||
vm.update_spotify()
|
vm.update_spotify()
|
||||||
}
|
}
|
||||||
@ -166,6 +167,12 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
update_settings: function () {
|
||||||
|
webapi.settings().then(({ data }) => {
|
||||||
|
this.$store.commit(types.UPDATE_SETTINGS, data)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
update_spotify: function () {
|
update_spotify: function () {
|
||||||
webapi.spotify().then(({ data }) => {
|
webapi.spotify().then(({ data }) => {
|
||||||
this.$store.commit(types.UPDATE_SPOTIFY, data)
|
this.$store.commit(types.UPDATE_SPOTIFY, data)
|
||||||
|
@ -121,17 +121,13 @@
|
|||||||
|
|
||||||
<!-- Settings drop down -->
|
<!-- Settings drop down -->
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link is-arrowless"><span class="icon is-hidden-mobile is-hidden-tablet-only"><i class="mdi mdi-settings"></i></span> <span class="is-hidden-desktop has-text-weight-bold">Settings</span></a>
|
<a class="navbar-link is-arrowless"><span class="icon is-hidden-mobile is-hidden-tablet-only"><i class="mdi mdi-settings"></i></span> <span class="is-hidden-desktop has-text-weight-bold">forked-daapd</span></a>
|
||||||
|
|
||||||
<div class="navbar-dropdown is-right">
|
<div class="navbar-dropdown is-right">
|
||||||
<a class="navbar-item" href="/admin.html">Admin</a>
|
<a class="navbar-item" href="/admin.html">Admin</a>
|
||||||
<hr class="navbar-divider">
|
<hr class="navbar-divider">
|
||||||
<navbar-item-link to="/about">
|
<navbar-item-link to="/settings/webinterface">Settings</navbar-item-link>
|
||||||
<div>
|
<navbar-item-link to="/about">About</navbar-item-link>
|
||||||
<p class="title is-7">forked-daapd</p>
|
|
||||||
<p class="subtitle is-7">{{ config.version }}</p>
|
|
||||||
</div>
|
|
||||||
</navbar-item-link>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -144,8 +144,6 @@ section.fd-tabs-section + section.fd-content {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now playing progress bar */
|
/* Now playing progress bar */
|
||||||
.fd-progress-now-playing {
|
|
||||||
}
|
|
||||||
.seek-slider {
|
.seek-slider {
|
||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
<h2 class="title is-6">
|
<h2 class="title is-6">
|
||||||
{{ now_playing.artist }}
|
{{ now_playing.artist }}
|
||||||
</h2>
|
</h2>
|
||||||
|
<h2 class="subtitle is-6 has-text-grey has-text-weight-bold" v-if="composer">
|
||||||
|
{{ composer }}
|
||||||
|
</h2>
|
||||||
<h3 class="subtitle is-6">
|
<h3 class="subtitle is-6">
|
||||||
{{ now_playing.album }}
|
{{ now_playing.album }}
|
||||||
</h3>
|
</h3>
|
||||||
@ -102,12 +105,34 @@ export default {
|
|||||||
state () {
|
state () {
|
||||||
return this.$store.state.player
|
return this.$store.state.player
|
||||||
},
|
},
|
||||||
|
|
||||||
now_playing () {
|
now_playing () {
|
||||||
return this.$store.getters.now_playing
|
return this.$store.getters.now_playing
|
||||||
},
|
},
|
||||||
|
|
||||||
artwork_url: function () {
|
artwork_url: function () {
|
||||||
return webapi.artwork_url_append_size_params(this.now_playing.artwork_url)
|
return webapi.artwork_url_append_size_params(this.now_playing.artwork_url)
|
||||||
|
},
|
||||||
|
|
||||||
|
settings_option_show_composer_now_playing () {
|
||||||
|
return this.$store.getters.settings_option_show_composer_now_playing
|
||||||
|
},
|
||||||
|
|
||||||
|
settings_option_show_composer_for_genre () {
|
||||||
|
return this.$store.getters.settings_option_show_composer_for_genre
|
||||||
|
},
|
||||||
|
|
||||||
|
composer () {
|
||||||
|
if (this.settings_option_show_composer_now_playing) {
|
||||||
|
if (!this.settings_option_show_composer_for_genre ||
|
||||||
|
(this.now_playing.genre &&
|
||||||
|
this.settings_option_show_composer_for_genre.toLowerCase()
|
||||||
|
.split(',')
|
||||||
|
.findIndex(elem => this.now_playing.genre.toLowerCase().indexOf(elem.trim()) >= 0) >= 0)) {
|
||||||
|
return this.now_playing.composer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
202
web-src/src/pages/SettingsPageWebinterface.vue
Normal file
202
web-src/src/pages/SettingsPageWebinterface.vue
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
<template>
|
||||||
|
<content-with-heading>
|
||||||
|
<template slot="heading-left">
|
||||||
|
<div class="title is-4">Settings</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template slot="heading-right">
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template slot="content">
|
||||||
|
<div class="heading fd-has-margin-bottom">Now playing page</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" :checked="settings_option_show_composer_now_playing" @change="set_timer_show_composer_now_playing" ref="checkbox_show_composer">
|
||||||
|
Show composer
|
||||||
|
<i class="is-size-7"
|
||||||
|
:class="{
|
||||||
|
'has-text-info': statusUpdateShowComposerNowPlaying === 'success',
|
||||||
|
'has-text-danger': statusUpdateShowComposerNowPlaying === 'error'
|
||||||
|
}">{{ info_option_show_composer_now_playing }}</i>
|
||||||
|
</label>
|
||||||
|
<p class="help has-text-justified">
|
||||||
|
If enabled the composer of the current playing track is shown on the "now playing page"
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<fieldset :disabled="!settings_option_show_composer_now_playing">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label has-text-weight-normal">
|
||||||
|
Show composer only for listed genres
|
||||||
|
<i class="is-size-7"
|
||||||
|
:class="{
|
||||||
|
'has-text-info': statusUpdateShowComposerForGenre === 'success',
|
||||||
|
'has-text-danger': statusUpdateShowComposerForGenre === 'error'
|
||||||
|
}">{{ info_option_show_composer_for_genre }}</i>
|
||||||
|
</label>
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" type="text" placeholder="Genres"
|
||||||
|
:value="settings_option_show_composer_for_genre"
|
||||||
|
@input="set_timer_show_composer_for_genre"
|
||||||
|
ref="field_composer_for_genre">
|
||||||
|
</div>
|
||||||
|
<p class="help">
|
||||||
|
Comma separated list of genres the composer should be displayed on the "now playing page".
|
||||||
|
</p>
|
||||||
|
<p class="help">
|
||||||
|
Leave empty to always show the composer.
|
||||||
|
</p>
|
||||||
|
<p class="help">
|
||||||
|
The genre tag of the current track is matched by checking, if one of the defined genres are included.
|
||||||
|
For example setting to <code>classical, soundtrack</code> will show the composer for tracks with
|
||||||
|
a genre tag of "Contemporary Classical".<br>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</content-with-heading>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ContentWithHeading from '@/templates/ContentWithHeading'
|
||||||
|
import webapi from '@/webapi'
|
||||||
|
import * as types from '@/store/mutation_types'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SettingsPageWebinterface',
|
||||||
|
components: { ContentWithHeading },
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
timerDelay: 2000,
|
||||||
|
timerIdShowComposerNowPlaying: -1,
|
||||||
|
timerIdShowComposerForGenre: -1,
|
||||||
|
|
||||||
|
// <empty>: default/no changes, 'success': update succesful, 'error': update failed
|
||||||
|
statusUpdateShowComposerNowPlaying: '',
|
||||||
|
statusUpdateShowComposerForGenre: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
settings_category_webinterface () {
|
||||||
|
return this.$store.getters.settings_webinterface
|
||||||
|
},
|
||||||
|
settings_option_show_composer_now_playing () {
|
||||||
|
return this.$store.getters.settings_option_show_composer_now_playing
|
||||||
|
},
|
||||||
|
settings_option_show_composer_for_genre () {
|
||||||
|
return this.$store.getters.settings_option_show_composer_for_genre
|
||||||
|
},
|
||||||
|
info_option_show_composer_for_genre () {
|
||||||
|
if (this.statusUpdateShowComposerForGenre === 'success') {
|
||||||
|
return '(setting saved)'
|
||||||
|
} else if (this.statusUpdateShowComposerForGenre === 'error') {
|
||||||
|
return '(error saving setting)'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
info_option_show_composer_now_playing () {
|
||||||
|
if (this.statusUpdateShowComposerNowPlaying === 'success') {
|
||||||
|
return '(setting saved)'
|
||||||
|
} else if (this.statusUpdateShowComposerNowPlaying === 'error') {
|
||||||
|
return '(error saving setting)'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
set_timer_show_composer_now_playing () {
|
||||||
|
if (this.timerIdShowComposerNowPlaying > 0) {
|
||||||
|
window.clearTimeout(this.timerIdShowComposerNowPlaying)
|
||||||
|
this.timerIdShowComposerNowPlaying = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
this.statusUpdateShowComposerNowPlaying = ''
|
||||||
|
const newValue = this.$refs.checkbox_show_composer.checked
|
||||||
|
if (newValue !== this.settings_option_show_composer_now_playing) {
|
||||||
|
this.timerIdShowComposerNowPlaying = window.setTimeout(this.update_show_composer_now_playing, this.timerDelay)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
update_show_composer_now_playing () {
|
||||||
|
this.timerIdShowComposerNowPlaying = -1
|
||||||
|
|
||||||
|
const newValue = this.$refs.checkbox_show_composer.checked
|
||||||
|
if (newValue === this.settings_option_show_composer_now_playing) {
|
||||||
|
this.statusUpdateShowComposerNowPlaying = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
category: this.settings_category_webinterface.name,
|
||||||
|
name: 'show_composer_now_playing',
|
||||||
|
value: newValue
|
||||||
|
}
|
||||||
|
webapi.settings_update(this.settings_category_webinterface.name, option).then(() => {
|
||||||
|
this.$store.commit(types.UPDATE_SETTINGS_OPTION, option)
|
||||||
|
this.statusUpdateShowComposerNowPlaying = 'success'
|
||||||
|
}).catch(() => {
|
||||||
|
this.statusUpdateShowComposerNowPlaying = 'error'
|
||||||
|
this.$refs.checkbox_show_composer.checked = this.settings_option_show_composer_now_playing
|
||||||
|
}).finally(() => {
|
||||||
|
this.timerIdShowComposerNowPlaying = window.setTimeout(this.clear_status_show_composer_now_playing, this.timerDelay)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
set_timer_show_composer_for_genre () {
|
||||||
|
if (this.timerIdShowComposerForGenre > 0) {
|
||||||
|
window.clearTimeout(this.timerIdShowComposerForGenre)
|
||||||
|
this.timerIdShowComposerForGenre = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
this.statusUpdateShowComposerForGenre = ''
|
||||||
|
const newValue = this.$refs.field_composer_for_genre.value
|
||||||
|
if (newValue !== this.settings_option_show_composer_for_genre) {
|
||||||
|
this.timerIdShowComposerForGenre = window.setTimeout(this.update_show_composer_for_genre, this.timerDelay)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
update_show_composer_for_genre () {
|
||||||
|
this.timerIdShowComposerForGenre = -1
|
||||||
|
|
||||||
|
const newValue = this.$refs.field_composer_for_genre.value
|
||||||
|
if (newValue === this.settings_option_show_composer_for_genre) {
|
||||||
|
this.statusUpdateShowComposerForGenre = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
category: this.settings_category_webinterface.name,
|
||||||
|
name: 'show_composer_for_genre',
|
||||||
|
value: newValue
|
||||||
|
}
|
||||||
|
webapi.settings_update(this.settings_category_webinterface.name, option).then(() => {
|
||||||
|
this.$store.commit(types.UPDATE_SETTINGS_OPTION, option)
|
||||||
|
this.statusUpdateShowComposerForGenre = 'success'
|
||||||
|
}).catch(() => {
|
||||||
|
this.statusUpdateShowComposerForGenre = 'error'
|
||||||
|
this.$refs.field_composer_for_genre.value = this.settings_option_show_composer_for_genre
|
||||||
|
}).finally(() => {
|
||||||
|
this.timerIdShowComposerForGenre = window.setTimeout(this.clear_status_show_composer_for_genre, this.timerDelay)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
clear_status_show_composer_for_genre () {
|
||||||
|
this.statusUpdateShowComposerForGenre = ''
|
||||||
|
},
|
||||||
|
|
||||||
|
clear_status_show_composer_now_playing () {
|
||||||
|
this.statusUpdateShowComposerNowPlaying = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
filters: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -31,6 +31,7 @@ import SpotifyPageArtist from '@/pages/SpotifyPageArtist'
|
|||||||
import SpotifyPageAlbum from '@/pages/SpotifyPageAlbum'
|
import SpotifyPageAlbum from '@/pages/SpotifyPageAlbum'
|
||||||
import SpotifyPagePlaylist from '@/pages/SpotifyPagePlaylist'
|
import SpotifyPagePlaylist from '@/pages/SpotifyPagePlaylist'
|
||||||
import SpotifyPageSearch from '@/pages/SpotifyPageSearch'
|
import SpotifyPageSearch from '@/pages/SpotifyPageSearch'
|
||||||
|
import SettingsPageWebinterface from '@/pages/SettingsPageWebinterface'
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
@ -212,6 +213,11 @@ export const router = new VueRouter({
|
|||||||
path: '/search/spotify',
|
path: '/search/spotify',
|
||||||
name: 'Spotify Search',
|
name: 'Spotify Search',
|
||||||
component: SpotifyPageSearch
|
component: SpotifyPageSearch
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings/webinterface',
|
||||||
|
name: 'Settings Webinterface',
|
||||||
|
component: SettingsPageWebinterface
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
scrollBehavior (to, from, savedPosition) {
|
scrollBehavior (to, from, savedPosition) {
|
||||||
|
@ -11,6 +11,9 @@ export default new Vuex.Store({
|
|||||||
'version': '',
|
'version': '',
|
||||||
'buildoptions': [ ]
|
'buildoptions': [ ]
|
||||||
},
|
},
|
||||||
|
settings: {
|
||||||
|
'categories': []
|
||||||
|
},
|
||||||
library: {
|
library: {
|
||||||
'artists': 0,
|
'artists': 0,
|
||||||
'albums': 0,
|
'albums': 0,
|
||||||
@ -58,6 +61,33 @@ export default new Vuex.Store({
|
|||||||
return item.id === state.player.item_id
|
return item.id === state.player.item_id
|
||||||
})
|
})
|
||||||
return (item === undefined) ? {} : item
|
return (item === undefined) ? {} : item
|
||||||
|
},
|
||||||
|
|
||||||
|
settings_webinterface: state => {
|
||||||
|
if (state.settings) {
|
||||||
|
return state.settings.categories.find(elem => elem.name === 'webinterface')
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
|
||||||
|
settings_option_show_composer_now_playing: (state, getters) => {
|
||||||
|
if (getters.settings_webinterface) {
|
||||||
|
const option = getters.settings_webinterface.options.find(elem => elem.name === 'show_composer_now_playing')
|
||||||
|
if (option) {
|
||||||
|
return option.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
settings_option_show_composer_for_genre: (state, getters) => {
|
||||||
|
if (getters.settings_webinterface) {
|
||||||
|
const option = getters.settings_webinterface.options.find(elem => elem.name === 'show_composer_for_genre')
|
||||||
|
if (option) {
|
||||||
|
return option.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -65,6 +95,14 @@ export default new Vuex.Store({
|
|||||||
[types.UPDATE_CONFIG] (state, config) {
|
[types.UPDATE_CONFIG] (state, config) {
|
||||||
state.config = config
|
state.config = config
|
||||||
},
|
},
|
||||||
|
[types.UPDATE_SETTINGS] (state, settings) {
|
||||||
|
state.settings = settings
|
||||||
|
},
|
||||||
|
[types.UPDATE_SETTINGS_OPTION] (state, option) {
|
||||||
|
const settingCategory = state.settings.categories.find(elem => elem.name === option.category)
|
||||||
|
const settingOption = settingCategory.options.find(elem => elem.name === option.name)
|
||||||
|
settingOption.value = option.value
|
||||||
|
},
|
||||||
[types.UPDATE_LIBRARY_STATS] (state, libraryStats) {
|
[types.UPDATE_LIBRARY_STATS] (state, libraryStats) {
|
||||||
state.library = libraryStats
|
state.library = libraryStats
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
export const UPDATE_CONFIG = 'UPDATE_CONFIG'
|
export const UPDATE_CONFIG = 'UPDATE_CONFIG'
|
||||||
|
export const UPDATE_SETTINGS = 'UPDATE_SETTINGS'
|
||||||
|
export const UPDATE_SETTINGS_OPTION = 'UPDATE_SETTINGS_OPTION'
|
||||||
export const UPDATE_LIBRARY_STATS = 'UPDATE_LIBRARY_STATS'
|
export const UPDATE_LIBRARY_STATS = 'UPDATE_LIBRARY_STATS'
|
||||||
export const UPDATE_LIBRARY_AUDIOBOOKS_COUNT = 'UPDATE_LIBRARY_AUDIOBOOKS_COUNT'
|
export const UPDATE_LIBRARY_AUDIOBOOKS_COUNT = 'UPDATE_LIBRARY_AUDIOBOOKS_COUNT'
|
||||||
export const UPDATE_LIBRARY_PODCASTS_COUNT = 'UPDATE_LIBRARY_PODCASTS_COUNT'
|
export const UPDATE_LIBRARY_PODCASTS_COUNT = 'UPDATE_LIBRARY_PODCASTS_COUNT'
|
||||||
|
@ -13,6 +13,14 @@ export default {
|
|||||||
return axios.get('/api/config')
|
return axios.get('/api/config')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
settings () {
|
||||||
|
return axios.get('/api/settings')
|
||||||
|
},
|
||||||
|
|
||||||
|
settings_update (categoryName, option) {
|
||||||
|
return axios.put('/api/settings/' + categoryName + '/' + option.name, option)
|
||||||
|
},
|
||||||
|
|
||||||
library_stats () {
|
library_stats () {
|
||||||
return axios.get('/api/library')
|
return axios.get('/api/library')
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user