mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-27 06:33:21 -05:00
[db/mpd/jsonapi] Include artist and album count in filecount query; add
count endpoint and additional metadata to JSON API; remove unused artist-/album-count queries
This commit is contained in:
parent
ae3e0b6bf5
commit
41e99ca3cd
16
src/db.c
16
src/db.c
@ -1834,7 +1834,7 @@ db_build_query_count_items(struct query_params *qp)
|
||||
|
||||
qp->results = 1;
|
||||
|
||||
query = sqlite3_mprintf("SELECT COUNT(*), SUM(song_length) FROM files f %s;", qc->where);
|
||||
query = sqlite3_mprintf("SELECT COUNT(*), SUM(song_length), COUNT(distinct songartistid), COUNT(distinct songalbumid) FROM files f %s;", qc->where);
|
||||
if (!query)
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
|
||||
|
||||
@ -2218,6 +2218,8 @@ db_query_fetch_count(struct query_params *qp, struct filecount_info *fci)
|
||||
|
||||
fci->count = sqlite3_column_int(qp->stmt, 0);
|
||||
fci->length = sqlite3_column_int64(qp->stmt, 1);
|
||||
fci->artist_count = sqlite3_column_int(qp->stmt, 2);
|
||||
fci->album_count = sqlite3_column_int(qp->stmt, 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2324,18 +2326,6 @@ db_files_get_count(void)
|
||||
return db_get_one_int("SELECT COUNT(*) FROM files f WHERE f.disabled = 0;");
|
||||
}
|
||||
|
||||
int
|
||||
db_files_get_artist_count(void)
|
||||
{
|
||||
return db_get_one_int("SELECT COUNT(DISTINCT songartistid) FROM files f WHERE f.disabled = 0;");
|
||||
}
|
||||
|
||||
int
|
||||
db_files_get_album_count(void)
|
||||
{
|
||||
return db_get_one_int("SELECT COUNT(DISTINCT songalbumid) FROM files f WHERE f.disabled = 0;");
|
||||
}
|
||||
|
||||
void
|
||||
db_file_inc_playcount(int id)
|
||||
{
|
||||
|
8
src/db.h
8
src/db.h
@ -391,6 +391,8 @@ struct watch_enum {
|
||||
struct filecount_info {
|
||||
uint32_t count;
|
||||
uint64_t length;
|
||||
uint32_t artist_count;
|
||||
uint32_t album_count;
|
||||
};
|
||||
|
||||
/* Directory ids must be in sync with the ids in Q_DIR* in db_init.c */
|
||||
@ -552,12 +554,6 @@ db_query_fetch_string_sort(struct query_params *qp, char **string, char **sortst
|
||||
int
|
||||
db_files_get_count(void);
|
||||
|
||||
int
|
||||
db_files_get_artist_count(void);
|
||||
|
||||
int
|
||||
db_files_get_album_count(void);
|
||||
|
||||
void
|
||||
db_file_inc_playcount(int id);
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#endif
|
||||
|
||||
#include <regex.h>
|
||||
#include <sqlite3.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@ -77,7 +78,7 @@ safe_json_add_int_from_string(json_object *obj, const char *key, const char *val
|
||||
}
|
||||
|
||||
static inline void
|
||||
safe_json_add_time_from_string(json_object *obj, const char *key, const char *value)
|
||||
safe_json_add_time_from_string(json_object *obj, const char *key, const char *value, bool with_time)
|
||||
{
|
||||
uint32_t tmp;
|
||||
time_t timestamp;
|
||||
@ -103,7 +104,10 @@ safe_json_add_time_from_string(json_object *obj, const char *key, const char *va
|
||||
return;
|
||||
}
|
||||
|
||||
strftime(result, sizeof(result), "%FT%TZ", &tm);
|
||||
if (with_time)
|
||||
strftime(result, sizeof(result), "%FT%TZ", &tm);
|
||||
else
|
||||
strftime(result, sizeof(result), "%F", &tm);
|
||||
|
||||
json_object_object_add(obj, key, json_object_new_string(result));
|
||||
}
|
||||
@ -182,7 +186,10 @@ track_to_json(struct db_media_file_info *dbmfi)
|
||||
safe_json_add_int_from_string(item, "length_ms", dbmfi->song_length);
|
||||
|
||||
safe_json_add_int_from_string(item, "play_count", dbmfi->play_count);
|
||||
safe_json_add_time_from_string(item, "time_played", dbmfi->time_played);
|
||||
safe_json_add_time_from_string(item, "time_played", dbmfi->time_played, true);
|
||||
safe_json_add_time_from_string(item, "time_added", dbmfi->time_added, true);
|
||||
safe_json_add_time_from_string(item, "date_released", dbmfi->date_released, false);
|
||||
safe_json_add_int_from_string(item, "seek_ms", dbmfi->seek);
|
||||
|
||||
ret = safe_atoi32(dbmfi->media_kind, &intval);
|
||||
if (ret == 0)
|
||||
@ -556,39 +563,33 @@ jsonapi_reply_library(struct httpd_request *hreq)
|
||||
{
|
||||
struct query_params qp;
|
||||
struct filecount_info fci;
|
||||
int artists;
|
||||
int albums;
|
||||
bool is_scanning;
|
||||
json_object *jreply;
|
||||
int ret;
|
||||
|
||||
// Fetch values for response
|
||||
|
||||
CHECK_NULL(L_WEB, jreply = json_object_new_object());
|
||||
|
||||
memset(&qp, 0, sizeof(struct query_params));
|
||||
qp.type = Q_COUNT_ITEMS;
|
||||
ret = db_filecount_get(&fci, &qp);
|
||||
if (ret < 0)
|
||||
if (ret == 0)
|
||||
{
|
||||
json_object_object_add(jreply, "songs", json_object_new_int(fci.count));
|
||||
json_object_object_add(jreply, "db_playtime", json_object_new_int64((fci.length / 1000)));
|
||||
json_object_object_add(jreply, "artists", json_object_new_int(fci.artist_count));
|
||||
json_object_object_add(jreply, "albums", json_object_new_int(fci.album_count));
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "library: failed to get file count info\n");
|
||||
return HTTP_INTERNAL;
|
||||
}
|
||||
|
||||
artists = db_files_get_artist_count();
|
||||
albums = db_files_get_album_count();
|
||||
safe_json_add_time_from_string(jreply, "started_at", db_admin_get(DB_ADMIN_START_TIME), true);
|
||||
safe_json_add_time_from_string(jreply, "updated_at", db_admin_get(DB_ADMIN_DB_UPDATE), true);
|
||||
|
||||
is_scanning = library_is_scanning();
|
||||
|
||||
// Build json response
|
||||
CHECK_NULL(L_WEB, jreply = json_object_new_object());
|
||||
|
||||
json_object_object_add(jreply, "artists", json_object_new_int(artists));
|
||||
json_object_object_add(jreply, "albums", json_object_new_int(albums));
|
||||
json_object_object_add(jreply, "songs", json_object_new_int(fci.count));
|
||||
json_object_object_add(jreply, "db_playtime", json_object_new_int64((fci.length / 1000)));
|
||||
json_object_object_add(jreply, "updating", json_object_new_boolean(is_scanning));
|
||||
json_object_object_add(jreply, "updating", json_object_new_boolean(library_is_scanning()));
|
||||
|
||||
CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply)));
|
||||
|
||||
jparse_free(jreply);
|
||||
|
||||
return HTTP_OK;
|
||||
@ -2340,7 +2341,60 @@ jsonapi_reply_library_playlist_tracks(struct httpd_request *hreq)
|
||||
}
|
||||
|
||||
static int
|
||||
search_tracks(json_object *reply, struct httpd_request *hreq, const char *param_query, struct smartpl *smartpl_expression)
|
||||
jsonapi_reply_library_count(struct httpd_request *hreq)
|
||||
{
|
||||
const char *param_expression;
|
||||
char *expression;
|
||||
struct smartpl smartpl_expression;
|
||||
struct query_params qp;
|
||||
struct filecount_info fci;
|
||||
json_object *jreply;
|
||||
int ret;
|
||||
|
||||
|
||||
memset(&qp, 0, sizeof(struct query_params));
|
||||
qp.type = Q_COUNT_ITEMS;
|
||||
|
||||
param_expression = evhttp_find_header(hreq->query, "expression");
|
||||
if (param_expression)
|
||||
{
|
||||
memset(&smartpl_expression, 0, sizeof(struct smartpl));
|
||||
expression = safe_asprintf("\"query\" { %s }", param_expression);
|
||||
ret = smartpl_query_parse_string(&smartpl_expression, expression);
|
||||
free(expression);
|
||||
|
||||
if (ret < 0)
|
||||
return HTTP_BADREQUEST;
|
||||
|
||||
qp.filter = strdup(smartpl_expression.query_where);
|
||||
free_smartpl(&smartpl_expression, 1);
|
||||
}
|
||||
|
||||
CHECK_NULL(L_WEB, jreply = json_object_new_object());
|
||||
|
||||
ret = db_filecount_get(&fci, &qp);
|
||||
if (ret == 0)
|
||||
{
|
||||
json_object_object_add(jreply, "tracks", json_object_new_int(fci.count));
|
||||
json_object_object_add(jreply, "artists", json_object_new_int(fci.artist_count));
|
||||
json_object_object_add(jreply, "albums", json_object_new_int(fci.album_count));
|
||||
json_object_object_add(jreply, "db_playtime", json_object_new_int64((fci.length / 1000)));
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "library: failed to get count info\n");
|
||||
}
|
||||
|
||||
free(qp.filter);
|
||||
|
||||
CHECK_ERRNO(L_WEB, evbuffer_add_printf(hreq->reply, "%s", json_object_to_json_string(jreply)));
|
||||
jparse_free(jreply);
|
||||
|
||||
return HTTP_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
search_tracks(json_object *reply, struct httpd_request *hreq, const char *param_query, struct smartpl *smartpl_expression, enum media_kind media_kind)
|
||||
{
|
||||
json_object *type;
|
||||
json_object *items;
|
||||
@ -2364,7 +2418,10 @@ search_tracks(json_object *reply, struct httpd_request *hreq, const char *param_
|
||||
|
||||
if (param_query)
|
||||
{
|
||||
query_params.filter = db_mprintf("(f.title LIKE '%%%q%%')", param_query);
|
||||
if (media_kind)
|
||||
query_params.filter = db_mprintf("(f.title LIKE '%%%q%%' AND f.media_kind = %d)", param_query, media_kind);
|
||||
else
|
||||
query_params.filter = db_mprintf("(f.title LIKE '%%%q%%')", param_query);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2394,7 +2451,7 @@ search_tracks(json_object *reply, struct httpd_request *hreq, const char *param_
|
||||
}
|
||||
|
||||
static int
|
||||
search_artists(json_object *reply, struct httpd_request *hreq, const char *param_query, struct smartpl *smartpl_expression)
|
||||
search_artists(json_object *reply, struct httpd_request *hreq, const char *param_query, struct smartpl *smartpl_expression, enum media_kind media_kind)
|
||||
{
|
||||
json_object *type;
|
||||
json_object *items;
|
||||
@ -2422,7 +2479,10 @@ search_artists(json_object *reply, struct httpd_request *hreq, const char *param
|
||||
|
||||
if (param_query)
|
||||
{
|
||||
query_params.filter = db_mprintf("(f.album_artist LIKE '%%%q%%')", param_query);
|
||||
if (media_kind)
|
||||
query_params.filter = db_mprintf("(f.album_artist LIKE '%%%q%%' AND f.media_kind = %d)", param_query, media_kind);
|
||||
else
|
||||
query_params.filter = db_mprintf("(f.album_artist LIKE '%%%q%%')", param_query);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2453,7 +2513,7 @@ search_artists(json_object *reply, struct httpd_request *hreq, const char *param
|
||||
}
|
||||
|
||||
static int
|
||||
search_albums(json_object *reply, struct httpd_request *hreq, const char *param_query, struct smartpl *smartpl_expression)
|
||||
search_albums(json_object *reply, struct httpd_request *hreq, const char *param_query, struct smartpl *smartpl_expression, enum media_kind media_kind)
|
||||
{
|
||||
json_object *type;
|
||||
json_object *items;
|
||||
@ -2481,7 +2541,10 @@ search_albums(json_object *reply, struct httpd_request *hreq, const char *param_
|
||||
|
||||
if (param_query)
|
||||
{
|
||||
query_params.filter = db_mprintf("(f.album LIKE '%%%q%%')", param_query);
|
||||
if (media_kind)
|
||||
query_params.filter = db_mprintf("(f.album LIKE '%%%q%%' AND f.media_kind = %d)", param_query, media_kind);
|
||||
else
|
||||
query_params.filter = db_mprintf("(f.album LIKE '%%%q%%')", param_query);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2558,6 +2621,8 @@ jsonapi_reply_search(struct httpd_request *hreq)
|
||||
const char *param_type;
|
||||
const char *param_query;
|
||||
const char *param_expression;
|
||||
const char *param_media_kind;
|
||||
enum media_kind media_kind;
|
||||
char *expression;
|
||||
struct smartpl smartpl_expression;
|
||||
json_object *reply;
|
||||
@ -2576,6 +2641,18 @@ jsonapi_reply_search(struct httpd_request *hreq)
|
||||
return HTTP_BADREQUEST;
|
||||
}
|
||||
|
||||
media_kind = 0;
|
||||
param_media_kind = evhttp_find_header(hreq->query, "media_kind");
|
||||
if (param_media_kind)
|
||||
{
|
||||
media_kind = db_media_kind_enum(param_media_kind);
|
||||
if (!media_kind)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Invalid media kind '%s'\n", param_media_kind);
|
||||
return HTTP_BADREQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&smartpl_expression, 0, sizeof(struct smartpl));
|
||||
|
||||
if (param_expression)
|
||||
@ -2592,21 +2669,21 @@ jsonapi_reply_search(struct httpd_request *hreq)
|
||||
|
||||
if (strstr(param_type, "track"))
|
||||
{
|
||||
ret = search_tracks(reply, hreq, param_query, &smartpl_expression);
|
||||
ret = search_tracks(reply, hreq, param_query, &smartpl_expression, media_kind);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (strstr(param_type, "artist"))
|
||||
{
|
||||
ret = search_artists(reply, hreq, param_query, &smartpl_expression);
|
||||
ret = search_artists(reply, hreq, param_query, &smartpl_expression, media_kind);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (strstr(param_type, "album"))
|
||||
{
|
||||
ret = search_albums(reply, hreq, param_query, &smartpl_expression);
|
||||
ret = search_albums(reply, hreq, param_query, &smartpl_expression, media_kind);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
@ -2681,6 +2758,7 @@ static struct httpd_uri_map adm_handlers[] =
|
||||
{ EVHTTP_REQ_GET, "^/api/library/albums$", jsonapi_reply_library_albums },
|
||||
{ EVHTTP_REQ_GET, "^/api/library/albums/[[:digit:]]+$", jsonapi_reply_library_album },
|
||||
{ EVHTTP_REQ_GET, "^/api/library/albums/[[:digit:]]+/tracks$", jsonapi_reply_library_album_tracks },
|
||||
{ EVHTTP_REQ_GET, "^/api/library/count$", jsonapi_reply_library_count },
|
||||
|
||||
{ EVHTTP_REQ_GET, "^/api/search$", jsonapi_reply_search },
|
||||
|
||||
|
@ -1053,8 +1053,6 @@ mpd_command_stats(struct evbuffer *evbuf, int argc, char **argv, char **errmsg,
|
||||
{
|
||||
struct query_params qp;
|
||||
struct filecount_info fci;
|
||||
int artists;
|
||||
int albums;
|
||||
time_t start_time;
|
||||
double uptime;
|
||||
int64_t db_update;
|
||||
@ -1070,9 +1068,6 @@ mpd_command_stats(struct evbuffer *evbuf, int argc, char **argv, char **errmsg,
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
artists = db_files_get_artist_count();
|
||||
albums = db_files_get_album_count();
|
||||
|
||||
start_time = (time_t) db_admin_getint64(DB_ADMIN_START_TIME);
|
||||
uptime = difftime(time(NULL), start_time);
|
||||
db_update = db_admin_getint64(DB_ADMIN_DB_UPDATE);
|
||||
@ -1086,8 +1081,8 @@ mpd_command_stats(struct evbuffer *evbuf, int argc, char **argv, char **errmsg,
|
||||
"db_playtime: %" PRIi64 "\n"
|
||||
"db_update: %" PRIi64 "\n"
|
||||
"playtime: %d\n",
|
||||
artists,
|
||||
albums,
|
||||
fci.artist_count,
|
||||
fci.album_count,
|
||||
fci.count,
|
||||
uptime,
|
||||
(fci.length / 1000),
|
||||
|
Loading…
x
Reference in New Issue
Block a user