Skip to content

Commit 8c97ad5

Browse files
authored
Merge pull request owntone#1373 from chme/feat/browse-info-query
Fetch additional meta data in "browse" queries
2 parents f8f2b6e + 8dfbb46 commit 8c97ad5

File tree

15 files changed

+191
-113
lines changed

15 files changed

+191
-113
lines changed

README_JSON_API.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,7 @@ GET /api/library/genres
16771677

16781678
| Key | Type | Value |
16791679
| --------------- | -------- | ----------------------------------------- |
1680-
| items | array | Array of [`genre`](#genre-object) objects |
1680+
| items | array | Array of [`browse-info`](#browse-info-object) objects |
16811681
| total | integer | Total number of genres in the library |
16821682
| offset | integer | Requested offset of the first genre |
16831683
| limit | integer | Requested maximum number of genres |
@@ -2604,11 +2604,17 @@ curl --include \
26042604
| limit | integer | Requested maximum number of items |
26052605

26062606

2607-
### `genre` object
2607+
### `browse-info` object
26082608

26092609
| Key | Type | Value |
26102610
| --------------- | -------- | ----------------------------------------- |
2611-
| name | string | Name of genre |
2611+
| name | string | Name (depends on the type of the query) |
2612+
| name_sort | string | Sort name |
2613+
| artist_count | integer | Number of artists |
2614+
| album_count | integer | Number of albums |
2615+
| track_count | integer | Number of tracks |
2616+
| time_played | string | Timestamp in `ISO 8601` format |
2617+
| time_added | string | Timestamp in `ISO 8601` format |
26122618

26132619

26142620
### `directory` object

src/artwork.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,7 +1377,7 @@ source_group_dir_get(struct artwork_ctx *ctx)
13771377
return ART_E_ERROR;
13781378
}
13791379

1380-
while (((ret = db_query_fetch_string(&qp, &dir)) == 0) && (dir))
1380+
while (((ret = db_query_fetch_string(&dir, &qp)) == 0) && (dir))
13811381
{
13821382
/* The db query may return non-directories (eg if item is an internet stream or Spotify) */
13831383
if (access(dir, F_OK) < 0)
@@ -1718,7 +1718,7 @@ source_item_ownpl_get(struct artwork_ctx *ctx)
17181718
mfi_path = ctx->dbmfi->path;
17191719

17201720
format = ART_E_NONE;
1721-
while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.id) && (format == ART_E_NONE))
1721+
while (((ret = db_query_fetch_pl(&dbpli, &qp)) == 0) && (dbpli.id) && (format == ART_E_NONE))
17221722
{
17231723
if (!dbpli.path)
17241724
continue;
@@ -1766,7 +1766,7 @@ process_items(struct artwork_ctx *ctx, int item_mode)
17661766
return -1;
17671767
}
17681768

1769-
while (((ret = db_query_fetch_file(&ctx->qp, &dbmfi)) == 0) && (dbmfi.id))
1769+
while ((ret = db_query_fetch_file(&dbmfi, &ctx->qp)) == 0)
17701770
{
17711771
// Save the first songalbumid, might need it for process_group() if this search doesn't give anything
17721772
if (!ctx->persistentid)
@@ -1859,7 +1859,7 @@ process_group(struct artwork_ctx *ctx)
18591859
goto invalid_group;
18601860
}
18611861

1862-
is_valid = (db_query_fetch_file(&ctx->qp, &dbmfi) == 0 && dbmfi.id && strcmp(dbmfi.album, CFG_NAME_UNKNOWN_ALBUM) != 0 && strcmp(dbmfi.album_artist, CFG_NAME_UNKNOWN_ARTIST) != 0);
1862+
is_valid = (db_query_fetch_file(&dbmfi, &ctx->qp) == 0 && strcmp(dbmfi.album, CFG_NAME_UNKNOWN_ALBUM) != 0 && strcmp(dbmfi.album_artist, CFG_NAME_UNKNOWN_ARTIST) != 0);
18631863
db_query_end(&ctx->qp);
18641864
if (!is_valid)
18651865
{

src/db.c

Lines changed: 83 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,27 @@ static const ssize_t dbgri_cols_map[] =
420420
dbgri_offsetof(seek),
421421
};
422422

423+
/* This list must be kept in sync with
424+
* - the order of fields in the Q_BROWSE_INFO query
425+
* - the name of the fields in struct db_browse_info
426+
*/
427+
static const ssize_t dbbi_cols_map[] =
428+
{
429+
dbbi_offsetof(itemname),
430+
dbbi_offsetof(itemname_sort),
431+
dbbi_offsetof(track_count),
432+
dbbi_offsetof(album_count),
433+
dbbi_offsetof(artist_count),
434+
dbbi_offsetof(song_length),
435+
dbbi_offsetof(data_kind),
436+
dbbi_offsetof(media_kind),
437+
dbbi_offsetof(year),
438+
dbbi_offsetof(date_released),
439+
dbbi_offsetof(time_added),
440+
dbbi_offsetof(time_played),
441+
dbbi_offsetof(seek),
442+
};
443+
423444
/* This list must be kept in sync with
424445
* - qi_cols_map
425446
*/
@@ -2188,7 +2209,10 @@ db_build_query_browse(struct query_params *qp, struct query_clause *qc)
21882209
where = browse_clause[qp->type & ~Q_F_BROWSE].where;
21892210

21902211
count = sqlite3_mprintf("SELECT COUNT(*) FROM (SELECT %s FROM files f %s AND %s != '' %s);", select, qc->where, where, qc->group);
2191-
query = sqlite3_mprintf("SELECT %s FROM files f %s AND %s != '' %s %s %s;", select, qc->where, where, qc->group, qc->order, qc->index);
2212+
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, "
2213+
" SUM(f.song_length), MIN(f.data_kind), MIN(f.media_kind), MAX(f.year), MAX(f.date_released), "
2214+
" MAX(f.time_added), MAX(f.time_played), MAX(f.seek) FROM files f %s AND %s != '' %s %s %s;",
2215+
select, qc->where, where, qc->group, qc->order, qc->index);
21922216

21932217
return db_build_query_check(qp, count, query);
21942218
}
@@ -2348,53 +2372,44 @@ db_query_run(char *query, int free, short update_events)
23482372
return ((ret != SQLITE_OK) ? -1 : 0);
23492373
}
23502374

2351-
int
2352-
db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi)
2375+
static int
2376+
db_query_fetch(void *item, struct query_params *qp, const ssize_t cols_map[], int size)
23532377
{
23542378
int ncols;
23552379
char **strcol;
23562380
int i;
23572381
int ret;
23582382

2359-
memset(dbmfi, 0, sizeof(struct db_media_file_info));
2360-
23612383
if (!qp->stmt)
23622384
{
23632385
DPRINTF(E_LOG, L_DB, "Query not started!\n");
23642386
return -1;
23652387
}
23662388

2367-
if ((qp->type != Q_ITEMS) && (qp->type != Q_PLITEMS) && (qp->type != Q_GROUP_ITEMS))
2368-
{
2369-
DPRINTF(E_LOG, L_DB, "Not an items, playlist or group items query!\n");
2370-
return -1;
2371-
}
2372-
23732389
ret = db_blocking_step(qp->stmt);
23742390
if (ret == SQLITE_DONE)
23752391
{
23762392
DPRINTF(E_DBG, L_DB, "End of query results\n");
2377-
dbmfi->id = NULL;
2378-
return 0;
2393+
return 1;
23792394
}
23802395
else if (ret != SQLITE_ROW)
23812396
{
2382-
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
2397+
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
23832398
return -1;
23842399
}
23852400

23862401
ncols = sqlite3_column_count(qp->stmt);
23872402

23882403
// We allow more cols in db than in map because the db may be a future schema
2389-
if (ncols < ARRAY_SIZE(dbmfi_cols_map))
2404+
if (ncols < size)
23902405
{
2391-
DPRINTF(E_LOG, L_DB, "BUG: database has fewer columns (%d) than dbmfi column map (%u)\n", ncols, ARRAY_SIZE(dbmfi_cols_map));
2406+
DPRINTF(E_LOG, L_DB, "BUG: database has fewer columns (%d) than column map (%u)\n", ncols, size);
23922407
return -1;
23932408
}
23942409

2395-
for (i = 0; i < ARRAY_SIZE(dbmfi_cols_map); i++)
2410+
for (i = 0; i < size; i++)
23962411
{
2397-
strcol = (char **) ((char *)dbmfi + dbmfi_cols_map[i]);
2412+
strcol = (char **) ((char *)item + cols_map[i]);
23982413

23992414
*strcol = (char *)sqlite3_column_text(qp->stmt, i);
24002415
}
@@ -2403,7 +2418,27 @@ db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi)
24032418
}
24042419

24052420
int
2406-
db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli)
2421+
db_query_fetch_file(struct db_media_file_info *dbmfi, struct query_params *qp)
2422+
{
2423+
int ret;
2424+
2425+
memset(dbmfi, 0, sizeof(struct db_media_file_info));
2426+
2427+
if ((qp->type != Q_ITEMS) && (qp->type != Q_PLITEMS) && (qp->type != Q_GROUP_ITEMS))
2428+
{
2429+
DPRINTF(E_LOG, L_DB, "Not an items, playlist or group items query!\n");
2430+
return -1;
2431+
}
2432+
2433+
ret = db_query_fetch(dbmfi, qp, dbmfi_cols_map, ARRAY_SIZE(dbmfi_cols_map));
2434+
if (ret < 0) {
2435+
DPRINTF(E_LOG, L_DB, "Failed to fetch db_media_file_info\n");
2436+
}
2437+
return ret;
2438+
}
2439+
2440+
int
2441+
db_query_fetch_pl(struct db_playlist_info *dbpli, struct query_params *qp)
24072442
{
24082443
int ncols;
24092444
char **strcol;
@@ -2470,60 +2505,47 @@ db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli)
24702505
}
24712506

24722507
int
2473-
db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri)
2508+
db_query_fetch_group(struct db_group_info *dbgri, struct query_params *qp)
24742509
{
2475-
int ncols;
2476-
char **strcol;
2477-
int i;
24782510
int ret;
24792511

24802512
memset(dbgri, 0, sizeof(struct db_group_info));
24812513

2482-
if (!qp->stmt)
2483-
{
2484-
DPRINTF(E_LOG, L_DB, "Query not started!\n");
2485-
return -1;
2486-
}
2487-
24882514
if ((qp->type != Q_GROUP_ALBUMS) && (qp->type != Q_GROUP_ARTISTS))
24892515
{
24902516
DPRINTF(E_LOG, L_DB, "Not a groups query!\n");
24912517
return -1;
24922518
}
24932519

2494-
ret = db_blocking_step(qp->stmt);
2495-
if (ret == SQLITE_DONE)
2496-
{
2497-
DPRINTF(E_DBG, L_DB, "End of query results\n");
2498-
return 1;
2499-
}
2500-
else if (ret != SQLITE_ROW)
2501-
{
2502-
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
2503-
return -1;
2504-
}
2520+
ret = db_query_fetch(dbgri, qp, dbgri_cols_map, ARRAY_SIZE(dbgri_cols_map));
2521+
if (ret < 0) {
2522+
DPRINTF(E_LOG, L_DB, "Failed to fetch db_group_info\n");
2523+
}
2524+
return ret;
2525+
}
25052526

2506-
ncols = sqlite3_column_count(qp->stmt);
2527+
int
2528+
db_query_fetch_browse(struct db_browse_info *dbbi, struct query_params *qp)
2529+
{
2530+
int ret;
25072531

2508-
// We allow more cols in db than in map because the db may be a future schema
2509-
if (ncols < ARRAY_SIZE(dbgri_cols_map))
2510-
{
2511-
DPRINTF(E_LOG, L_DB, "BUG: database has fewer columns (%d) than dbgri column map (%u)\n", ncols, ARRAY_SIZE(dbgri_cols_map));
2512-
return -1;
2513-
}
2532+
memset(dbbi, 0, sizeof(struct db_browse_info));
25142533

2515-
for (i = 0; i < ARRAY_SIZE(dbgri_cols_map); i++)
2534+
if (!(qp->type & Q_F_BROWSE))
25162535
{
2517-
strcol = (char **) ((char *)dbgri + dbgri_cols_map[i]);
2518-
2519-
*strcol = (char *)sqlite3_column_text(qp->stmt, i);
2536+
DPRINTF(E_LOG, L_DB, "Not a browse query!\n");
2537+
return -1;
25202538
}
25212539

2522-
return 0;
2540+
ret = db_query_fetch(dbbi, qp, dbbi_cols_map, ARRAY_SIZE(dbbi_cols_map));
2541+
if (ret < 0) {
2542+
DPRINTF(E_LOG, L_DB, "Failed to fetch db_browse_info\n");
2543+
}
2544+
return ret;
25232545
}
25242546

25252547
int
2526-
db_query_fetch_count(struct query_params *qp, struct filecount_info *fci)
2548+
db_query_fetch_count(struct filecount_info *fci, struct query_params *qp)
25272549
{
25282550
int ret;
25292551

@@ -2574,7 +2596,7 @@ db_filecount_get(struct filecount_info *fci, struct query_params *qp)
25742596
return -1;
25752597
}
25762598

2577-
ret = db_query_fetch_count(qp, fci);
2599+
ret = db_query_fetch_count(fci, qp);
25782600
if (ret < 0)
25792601
{
25802602
db_query_end(qp);
@@ -2587,7 +2609,7 @@ db_filecount_get(struct filecount_info *fci, struct query_params *qp)
25872609
}
25882610

25892611
int
2590-
db_query_fetch_string(struct query_params *qp, char **string)
2612+
db_query_fetch_string(char **string, struct query_params *qp)
25912613
{
25922614
int ret;
25932615

@@ -2618,7 +2640,7 @@ db_query_fetch_string(struct query_params *qp, char **string)
26182640
}
26192641

26202642
int
2621-
db_query_fetch_string_sort(struct query_params *qp, char **string, char **sortstring)
2643+
db_query_fetch_string_sort(char **string, char **sortstring, struct query_params *qp)
26222644
{
26232645
int ret;
26242646

@@ -3841,7 +3863,7 @@ db_pl_delete_bypath(const char *path)
38413863
return;
38423864
}
38433865

3844-
while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.id))
3866+
while (((ret = db_query_fetch_pl(&dbpli, &qp)) == 0) && (dbpli.id))
38453867
{
38463868
if (safe_atoi32(dbpli.id, &id) != 0)
38473869
continue;
@@ -5097,7 +5119,7 @@ db_queue_add_by_query(struct query_params *qp, char reshuffle, uint32_t item_id,
50975119
goto end_transaction;
50985120
}
50995121

5100-
while (((ret = db_query_fetch_file(qp, &dbmfi)) == 0) && (dbmfi.id))
5122+
while ((ret = db_query_fetch_file(&dbmfi, qp)) == 0)
51015123
{
51025124
ret = queue_item_add_from_file(&dbmfi, pos, queue_count, queue_version);
51035125

@@ -5118,6 +5140,9 @@ db_queue_add_by_query(struct query_params *qp, char reshuffle, uint32_t item_id,
51185140
queue_count++;
51195141
}
51205142

5143+
if (ret > 0)
5144+
ret = 0;
5145+
51215146
db_query_end(qp);
51225147

51235148
if (ret < 0)

src/db.h

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,28 @@ struct db_media_file_info {
409409

410410
#define dbmfi_offsetof(field) offsetof(struct db_media_file_info, field)
411411

412+
/* Info object for generic browse queries that want more info than just
413+
* the item string and sort string (e. g. for genre or compose queries
414+
* that want to display the total track / album count).
415+
*/
416+
struct db_browse_info {
417+
char *itemname;
418+
char *itemname_sort;
419+
char *track_count;
420+
char *album_count;
421+
char *artist_count;
422+
char *song_length;
423+
char *data_kind;
424+
char *media_kind;
425+
char *year;
426+
char *date_released;
427+
char *time_added;
428+
char *time_played;
429+
char *seek;
430+
};
431+
432+
#define dbbi_offsetof(field) offsetof(struct db_browse_info, field)
433+
412434
enum strip_type {
413435
STRIP_NONE,
414436
STRIP_PATH,
@@ -585,22 +607,25 @@ void
585607
db_query_end(struct query_params *qp);
586608

587609
int
588-
db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi);
610+
db_query_fetch_file(struct db_media_file_info *dbmfi, struct query_params *qp);
611+
612+
int
613+
db_query_fetch_pl(struct db_playlist_info *dbpli, struct query_params *qp);
589614

590615
int
591-
db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli);
616+
db_query_fetch_group(struct db_group_info *dbgri, struct query_params *qp);
592617

593618
int
594-
db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri);
619+
db_query_fetch_browse(struct db_browse_info *dbbi, struct query_params *qp);
595620

596621
int
597-
db_query_fetch_count(struct query_params *qp, struct filecount_info *fci);
622+
db_query_fetch_count(struct filecount_info *fci, struct query_params *qp);
598623

599624
int
600-
db_query_fetch_string(struct query_params *qp, char **string);
625+
db_query_fetch_string(char **string, struct query_params *qp);
601626

602627
int
603-
db_query_fetch_string_sort(struct query_params *qp, char **string, char **sortstring);
628+
db_query_fetch_string_sort(char **string, char **sortstring, struct query_params *qp);
604629

605630
/* Files */
606631
int

0 commit comments

Comments
 (0)