diff --git a/src/db.c b/src/db.c index c9ce861b..c3c739d5 100644 --- a/src/db.c +++ b/src/db.c @@ -42,6 +42,10 @@ /* Inotify cookies are uint32_t */ #define INOTIFY_FAKE_COOKIE ((int64_t)1 << 32) +enum group_type { + G_ALBUMS = 1, +}; + #define DB_TYPE_CHAR 1 #define DB_TYPE_INT 2 #define DB_TYPE_INT64 3 @@ -211,6 +215,7 @@ static ssize_t dbpli_cols_map[] = static ssize_t dbgri_cols_map[] = { dbgri_offsetof(itemcount), + dbgri_offsetof(id), dbgri_offsetof(persistentid), dbgri_offsetof(songalbumartist), dbgri_offsetof(itemname), @@ -731,13 +736,13 @@ db_build_query_groups(struct query_params *qp, char **q) return -1; if (idx && qp->filter) - query = sqlite3_mprintf("SELECT COUNT(*) AS items, songalbumid AS persistentid, album_artist, album FROM files GROUP BY album_artist, album HAVING disabled = 0 AND %s %s;", qp->filter, idx); + query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f JOIN groups g ON f.songalbumid = g.persistentid GROUP BY f.album_artist, g.name HAVING g.type = %d AND disabled = 0 AND %s %s;", G_ALBUMS, qp->filter, idx); else if (idx) - query = sqlite3_mprintf("SELECT COUNT(*) AS items, songalbumid AS persistentid, album_artist, album FROM files GROUP BY album_artist, album HAVING disabled = 0 %s;", idx); + query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f JOIN groups g ON f.songalbumid = g.persistentid GROUP BY f.album_artist, g.name HAVING g.type = %d AND disabled = 0 %s;", G_ALBUMS, idx); else if (qp->filter) - query = sqlite3_mprintf("SELECT COUNT(*) AS items, songalbumid AS persistentid, album_artist, album FROM files GROUP BY album_artist, album HAVING disabled = 0 AND %s;", qp->filter); + query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f JOIN groups g ON f.songalbumid = g.persistentid GROUP BY f.album_artist, g.name HAVING g.type = %d AND disabled = 0 AND %s;", G_ALBUMS, qp->filter); else - query = sqlite3_mprintf("SELECT COUNT(*) AS items, songalbumid AS persistentid, album_artist, album FROM files GROUP BY album_artist, album HAVING disabled = 0;"); + query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f JOIN groups g ON f.songalbumid = g.persistentid GROUP BY f.album_artist, g.name HAVING g.type = %d AND disabled = 0;", G_ALBUMS); if (!query) { @@ -2443,6 +2448,30 @@ db_pl_enable_bycookie(uint32_t cookie, char *path) } +/* Groups */ +int +db_groups_clear(void) +{ + char *query = "DELETE FROM groups;"; + char *errmsg; + int ret; + + DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query); + + errmsg = NULL; + ret = sqlite3_exec(hdl, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) + { + DPRINTF(E_LOG, L_DB, "Query error: %s\n", errmsg); + + sqlite3_free(errmsg); + return -1; + } + + return 0; +} + + /* Remotes */ static int db_pairing_delete_byremote(char *remote_id) @@ -3212,6 +3241,15 @@ db_perthread_deinit(void) " filepath VARCHAR(4096) NOT NULL" \ ");" +#define T_GROUPS \ + "CREATE TABLE IF NOT EXISTS groups (" \ + " id INTEGER PRIMARY KEY NOT NULL," \ + " type INTEGER NOT NULL," \ + " name VARCHAR(1024) NOT NULL," \ + " persistentid INTEGER NOT NULL," \ + "CONSTRAINT groups_type_unique_persistentid UNIQUE (type, persistentid)" \ + ");" + #define T_PAIRINGS \ "CREATE TABLE IF NOT EXISTS pairings(" \ " remote VARCHAR(64) PRIMARY KEY NOT NULL," \ @@ -3239,6 +3277,18 @@ db_perthread_deinit(void) #define I_PAIRING \ "CREATE INDEX IF NOT EXISTS idx_pairingguid ON pairings(guid);" +#define TRG_GROUPS_INSERT_FILES \ + "CREATE TRIGGER update_groups_new_file AFTER INSERT ON files FOR EACH ROW" \ + " BEGIN" \ + " INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid);" \ + " END;" + +#define TRG_GROUPS_UPDATE_FILES \ + "CREATE TRIGGER update_groups_update_file AFTER UPDATE OF songalbumid ON files FOR EACH ROW" \ + " BEGIN" \ + " INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid);" \ + " END;" + #define Q_PL1 \ "INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \ " VALUES(1, 'Library', 1, '1 = 1', 0, '', 0, 0);" @@ -3264,9 +3314,9 @@ db_perthread_deinit(void) */ -#define SCHEMA_VERSION 7 +#define SCHEMA_VERSION 8 #define Q_SCVER \ - "INSERT INTO admin (key, value) VALUES ('schema_version', '7');" + "INSERT INTO admin (key, value) VALUES ('schema_version', '8');" struct db_init_query { char *query; @@ -3279,6 +3329,7 @@ static struct db_init_query db_init_queries[] = { T_FILES, "create table files" }, { T_PL, "create table playlists" }, { T_PLITEMS, "create table playlistitems" }, + { T_GROUPS, "create table groups" }, { T_PAIRINGS, "create table pairings" }, { T_INOTIFY, "create table inotify" }, @@ -3287,6 +3338,9 @@ static struct db_init_query db_init_queries[] = { I_PLITEMID, "create playlist id index" }, { I_PAIRING, "create pairing guid index" }, + { TRG_GROUPS_INSERT_FILES, "create trigger update_groups_new_file" }, + { TRG_GROUPS_UPDATE_FILES, "create trigger update_groups_update_file" }, + { Q_PL1, "create default playlist" }, { Q_PL2, "create default smart playlist 'Music'" }, { Q_PL3, "create default smart playlist 'Movies'" }, diff --git a/src/db.h b/src/db.h index 19328a98..72e4d5b4 100644 --- a/src/db.h +++ b/src/db.h @@ -160,7 +160,7 @@ struct db_playlist_info { #define dbpli_offsetof(field) offsetof(struct db_playlist_info, field) struct group_info { - uint32_t itemid; /* integer id (miid) */ + uint32_t id; /* integer id (miid) */ uint64_t persistentid; /* ulonglong id (mper) */ char *itemname; /* playlist name as displayed in iTunes (minm) */ uint32_t itemcount; /* number of items (mimc) */ @@ -170,7 +170,7 @@ struct group_info { #define gri_offsetof(field) offsetof(struct group_info, field) struct db_group_info { - char *itemid; + char *id; char *persistentid; char *itemname; char *itemcount; @@ -374,6 +374,10 @@ db_pl_disable_bymatch(char *path, char *strip, uint32_t cookie); int db_pl_enable_bycookie(uint32_t cookie, char *path); +/* Groups */ +int +db_groups_clear(void); + /* Remotes */ int db_pairing_add(struct pairing_info *pi); diff --git a/src/filescanner.c b/src/filescanner.c index da2f4478..b733b90b 100644 --- a/src/filescanner.c +++ b/src/filescanner.c @@ -697,8 +697,17 @@ filescanner(void *arg) pthread_exit(NULL); } + ret = db_groups_clear(); + if (ret < 0) + { + DPRINTF(E_LOG, L_SCAN, "Error: could not clear old groups from DB\n"); + + pthread_exit(NULL); + } + /* Recompute all songalbumids, in case the SQLite DB got transferred * to a different host; the hash is not portable. + * It will also rebuild the groups we just cleared. */ db_files_update_songalbumid(); diff --git a/src/httpd_daap.c b/src/httpd_daap.c index b4224b13..7c9302e4 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -2044,7 +2044,10 @@ daap_reply_groups(struct evhttp_request *req, struct evbuffer *evbuf, char **uri dmap_add_string(group, "asaa", dbgri.songalbumartist); /* Item id (miid) */ - dmap_add_int(group, "miid", ngrp); + val = 0; + ret = safe_atoi32(dbgri.id, &val); + if ((ret == 0) && (val > 0)) + dmap_add_int(group, "miid", val); DPRINTF(E_DBG, L_DAAP, "Done with group\n");