[db,jsonapi] Additional meta data for browse queries

This commit is contained in:
chme 2021-12-24 14:02:37 +01:00
parent 17ba3c6e03
commit d7086cab00
3 changed files with 130 additions and 8 deletions

View File

@ -420,6 +420,27 @@ static const ssize_t dbgri_cols_map[] =
dbgri_offsetof(seek),
};
/* This list must be kept in sync with
* - the order of fields in the Q_BROWSE_INFO query
* - the name of the fields in struct db_browse_info
*/
static const ssize_t dbbi_cols_map[] =
{
dbbi_offsetof(itemname),
dbbi_offsetof(itemname_sort),
dbbi_offsetof(track_count),
dbbi_offsetof(album_count),
dbbi_offsetof(artist_count),
dbbi_offsetof(song_length),
dbbi_offsetof(data_kind),
dbbi_offsetof(media_kind),
dbbi_offsetof(year),
dbbi_offsetof(date_released),
dbbi_offsetof(time_added),
dbbi_offsetof(time_played),
dbbi_offsetof(seek),
};
/* This list must be kept in sync with
* - qi_cols_map
*/
@ -2188,7 +2209,10 @@ db_build_query_browse(struct query_params *qp, struct query_clause *qc)
where = browse_clause[qp->type & ~Q_F_BROWSE].where;
count = sqlite3_mprintf("SELECT COUNT(*) FROM (SELECT %s FROM files f %s AND %s != '' %s);", select, qc->where, where, qc->group);
query = sqlite3_mprintf("SELECT %s FROM files f %s AND %s != '' %s %s %s;", select, qc->where, where, qc->group, qc->order, qc->index);
query = sqlite3_mprintf("SELECT %s, COUNT(f.id) as track_count, COUNT(DISTINCT f.songalbumid) as album_count, COUNT(DISTINCT f.songartistid) as artist_count, "
" SUM(f.song_length), MIN(f.data_kind), MIN(f.media_kind), MAX(f.year), MAX(f.date_released), "
" MAX(f.time_added), MAX(f.time_played), MAX(f.seek) FROM files f %s AND %s != '' %s %s %s;",
select, qc->where, where, qc->group, qc->order, qc->index);
return db_build_query_check(qp, count, query);
}
@ -2522,6 +2546,59 @@ db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri)
return 0;
}
int
db_query_fetch_browse(struct query_params *qp, struct db_browse_info *dbbi)
{
int ncols;
char **strcol;
int i;
int ret;
memset(dbbi, 0, sizeof(struct db_browse_info));
if (!qp->stmt)
{
DPRINTF(E_LOG, L_DB, "Query not started!\n");
return -1;
}
if (!(qp->type & Q_F_BROWSE))
{
DPRINTF(E_LOG, L_DB, "Not a browse query!\n");
return -1;
}
ret = db_blocking_step(qp->stmt);
if (ret == SQLITE_DONE)
{
DPRINTF(E_DBG, L_DB, "End of query results\n");
return 1;
}
else if (ret != SQLITE_ROW)
{
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
return -1;
}
ncols = sqlite3_column_count(qp->stmt);
// We allow more cols in db than in map because the db may be a future schema
if (ncols < ARRAY_SIZE(dbbi_cols_map))
{
DPRINTF(E_LOG, L_DB, "BUG: database has fewer columns (%d) than dbbi column map (%u)\n", ncols, ARRAY_SIZE(dbbi_cols_map));
return -1;
}
for (i = 0; i < ARRAY_SIZE(dbbi_cols_map); i++)
{
strcol = (char **) ((char *)dbbi + dbbi_cols_map[i]);
*strcol = (char *)sqlite3_column_text(qp->stmt, i);
}
return 0;
}
int
db_query_fetch_count(struct query_params *qp, struct filecount_info *fci)
{

View File

@ -409,6 +409,24 @@ struct db_media_file_info {
#define dbmfi_offsetof(field) offsetof(struct db_media_file_info, field)
struct db_browse_info {
char *itemname;
char *itemname_sort;
char *track_count;
char *album_count;
char *artist_count;
char *song_length;
char *data_kind;
char *media_kind;
char *year;
char *date_released;
char *time_added;
char *time_played;
char *seek;
};
#define dbbi_offsetof(field) offsetof(struct db_browse_info, field)
enum strip_type {
STRIP_NONE,
STRIP_PATH,
@ -593,6 +611,9 @@ db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli);
int
db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri);
int
db_query_fetch_browse(struct query_params *qp, struct db_browse_info *dbbi);
int
db_query_fetch_count(struct query_params *qp, struct filecount_info *fci);

View File

@ -388,17 +388,42 @@ playlist_to_json(struct db_playlist_info *dbpli)
}
static json_object *
genre_to_json(const char *genre)
browse_info_to_json(struct db_browse_info *dbbi)
{
json_object *item;
int intval;
int ret;
if (genre == NULL)
if (dbbi == NULL)
{
return NULL;
}
item = json_object_new_object();
safe_json_add_string(item, "name", genre);
safe_json_add_string(item, "name", dbbi->itemname);
safe_json_add_string(item, "name_sort", dbbi->itemname_sort);
safe_json_add_int_from_string(item, "track_count", dbbi->track_count);
safe_json_add_int_from_string(item, "album_count", dbbi->album_count);
safe_json_add_int_from_string(item, "artist_count", dbbi->artist_count);
safe_json_add_int_from_string(item, "length_ms", dbbi->song_length);
safe_json_add_time_from_string(item, "time_played", dbbi->time_played);
safe_json_add_time_from_string(item, "time_added", dbbi->time_added);
ret = safe_atoi32(dbbi->seek, &intval);
if (ret == 0)
json_object_object_add(item, "in_progress", json_object_new_boolean(intval > 0));
ret = safe_atoi32(dbbi->media_kind, &intval);
if (ret == 0)
safe_json_add_string(item, "media_kind", db_media_kind_label(intval));
ret = safe_atoi32(dbbi->data_kind, &intval);
if (ret == 0)
safe_json_add_string(item, "data_kind", db_data_kind_label(intval));
safe_json_add_date_from_string(item, "date_released", dbbi->date_released);
safe_json_add_int_from_string(item, "year", dbbi->year);
return item;
}
@ -662,18 +687,17 @@ fetch_playlist(bool *notfound, uint32_t playlist_id)
static int
fetch_genres(struct query_params *query_params, json_object *items, int *total)
{
struct db_browse_info dbbi;
json_object *item;
int ret;
char *genre;
char *sort_item;
ret = db_query_start(query_params);
if (ret < 0)
goto error;
while (((ret = db_query_fetch_string_sort(query_params, &genre, &sort_item)) == 0) && (genre))
while (((ret = db_query_fetch_browse(query_params, &dbbi)) == 0) && (dbbi.track_count))
{
item = genre_to_json(genre);
item = browse_info_to_json(&dbbi);
if (!item)
{
ret = -1;