diff --git a/src/cache.c b/src/cache.c index e1276a59..3039e3d1 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1596,7 +1596,7 @@ cache_init(void) cmdbase = commands_base_new(evbase_cache, NULL); - ret = listener_add(cache_daap_listener_cb, LISTENER_DATABASE); + ret = listener_add(cache_daap_listener_cb, LISTENER_DATABASE | LISTENER_STICKER); if (ret < 0) { DPRINTF(E_LOG, L_CACHE, "Could not create listener event\n"); diff --git a/src/db.c b/src/db.c index e7c9181f..f0ca3e40 100644 --- a/src/db.c +++ b/src/db.c @@ -329,7 +329,7 @@ static enum group_type db_group_type_bypersistentid(int64_t persistentid); static int -db_query_run(char *query, int free, int cache_update); +db_query_run(char *query, int free, short update_events); char * @@ -804,7 +804,7 @@ db_purge_cruft(time_t ref) DPRINTF(E_DBG, L_DB, "Running purge query '%s'\n", query); - ret = db_query_run(query, 1, 1); + ret = db_query_run(query, 1, LISTENER_DATABASE); if (ret == 0) DPRINTF(E_DBG, L_DB, "Purged %d rows\n", sqlite3_changes(hdl)); @@ -1496,7 +1496,7 @@ db_query_end(struct query_params *qp) * to update their cache of the library (and of course also of our own cache). */ static int -db_query_run(char *query, int free, int library_update) +db_query_run(char *query, int free, short update_events) { char *errmsg; int changes = 0; @@ -1527,8 +1527,8 @@ db_query_run(char *query, int free, int library_update) cache_daap_resume(); - if (library_update && changes > 0) - library_update_trigger(); + if (update_events && changes > 0) + library_update_trigger(update_events); return ((ret != SQLITE_OK) ? -1 : 0); } @@ -2392,7 +2392,7 @@ db_file_add(struct media_file_info *mfi) sqlite3_free(query); - library_update_trigger(); + library_update_trigger(LISTENER_DATABASE); return 0; @@ -2471,7 +2471,7 @@ db_file_update(struct media_file_info *mfi) sqlite3_free(query); - library_update_trigger(); + library_update_trigger(LISTENER_DATABASE); return 0; @@ -2499,6 +2499,36 @@ db_file_seek_update(int id, uint32_t seek) #undef Q_TMPL } +int +db_file_rating_update_byid(uint32_t id, uint32_t rating) +{ +#define Q_TMPL "UPDATE files SET rating = %d WHERE id = %d;" + char *query; + int ret; + + query = sqlite3_mprintf(Q_TMPL, rating, id); + + ret = db_query_run(query, 1, LISTENER_STICKER); + + return ((ret < 0) ? -1 : sqlite3_changes(hdl)); +#undef Q_TMPL +} + +int +db_file_rating_update_byvirtualpath(const char *virtual_path, uint32_t rating) +{ +#define Q_TMPL "UPDATE files SET rating = %d WHERE virtual_path = %Q;" + char *query; + int ret; + + query = sqlite3_mprintf(Q_TMPL, rating, virtual_path); + + ret = db_query_run(query, 1, LISTENER_STICKER); + + return ((ret < 0) ? -1 : sqlite3_changes(hdl)); +#undef Q_TMPL +} + void db_file_delete_bypath(const char *path) { @@ -2507,7 +2537,7 @@ db_file_delete_bypath(const char *path) query = sqlite3_mprintf(Q_TMPL, path); - db_query_run(query, 1, 1); + db_query_run(query, 1, LISTENER_DATABASE); #undef Q_TMPL } @@ -2529,7 +2559,7 @@ db_file_disable_bypath(const char *path, char *strip, uint32_t cookie) query = sqlite3_mprintf(Q_TMPL, striplen, striplenvpath, disabled, path); - db_query_run(query, 1, 1); + db_query_run(query, 1, LISTENER_DATABASE); #undef Q_TMPL } @@ -2551,7 +2581,7 @@ db_file_disable_bymatch(const char *path, char *strip, uint32_t cookie) query = sqlite3_mprintf(Q_TMPL, striplen, striplenvpath, disabled, path); - db_query_run(query, 1, 1); + db_query_run(query, 1, LISTENER_DATABASE); #undef Q_TMPL } @@ -3161,7 +3191,7 @@ db_groups_cleanup() db_transaction_begin(); - ret = db_query_run(Q_TMPL_ALBUM, 0, 1); + ret = db_query_run(Q_TMPL_ALBUM, 0, LISTENER_DATABASE); if (ret < 0) { db_transaction_rollback(); @@ -3170,7 +3200,7 @@ db_groups_cleanup() DPRINTF(E_DBG, L_DB, "Removed album group-entries: %d\n", sqlite3_changes(hdl)); - ret = db_query_run(Q_TMPL_ARTIST, 0, 1); + ret = db_query_run(Q_TMPL_ARTIST, 0, LISTENER_DATABASE); if (ret < 0) { db_transaction_rollback(); @@ -3558,7 +3588,7 @@ db_directory_disable_bymatch(char *path, char *strip, uint32_t cookie) query = sqlite3_mprintf(Q_TMPL, striplen, disabled, path, path, path); - db_query_run(query, 1, 1); + db_query_run(query, 1, LISTENER_DATABASE); #undef Q_TMPL } @@ -3571,7 +3601,7 @@ db_directory_enable_bycookie(uint32_t cookie, char *path) query = sqlite3_mprintf(Q_TMPL, path, (int64_t)cookie); - ret = db_query_run(query, 1, 1); + ret = db_query_run(query, 1, LISTENER_DATABASE); return ((ret < 0) ? -1 : sqlite3_changes(hdl)); #undef Q_TMPL @@ -3586,7 +3616,7 @@ db_directory_enable_bypath(char *path) query = sqlite3_mprintf(Q_TMPL, path); - ret = db_query_run(query, 1, 1); + ret = db_query_run(query, 1, LISTENER_DATABASE); return ((ret < 0) ? -1 : sqlite3_changes(hdl)); #undef Q_TMPL @@ -3695,7 +3725,7 @@ db_spotify_purge(void) for (i = 0; i < (sizeof(queries) / sizeof(queries[0])); i++) { - ret = db_query_run(queries[i], 0, 1); + ret = db_query_run(queries[i], 0, LISTENER_DATABASE); if (ret == 0) DPRINTF(E_DBG, L_DB, "Processed %d rows\n", sqlite3_changes(hdl)); @@ -3708,7 +3738,7 @@ db_spotify_purge(void) DPRINTF(E_LOG, L_DB, "Out of memory for query string\n"); return; } - ret = db_query_run(query, 1, 1); + ret = db_query_run(query, 1, LISTENER_DATABASE); if (ret == 0) DPRINTF(E_DBG, L_DB, "Disabled spotify directory\n"); @@ -3733,7 +3763,7 @@ db_spotify_pl_delete(int id) { query = sqlite3_mprintf(queries_tmpl[i], id); - ret = db_query_run(query, 1, 1); + ret = db_query_run(query, 1, LISTENER_DATABASE); if (ret == 0) DPRINTF(E_DBG, L_DB, "Deleted %d rows\n", sqlite3_changes(hdl)); @@ -3750,7 +3780,7 @@ db_spotify_files_delete(void) query = sqlite3_mprintf(Q_TMPL); - ret = db_query_run(query, 1, 1); + ret = db_query_run(query, 1, LISTENER_DATABASE); if (ret == 0) DPRINTF(E_DBG, L_DB, "Deleted %d rows\n", sqlite3_changes(hdl)); diff --git a/src/db.h b/src/db.h index d38c40fd..f6ff7343 100644 --- a/src/db.h +++ b/src/db.h @@ -559,6 +559,12 @@ db_file_update(struct media_file_info *mfi); void db_file_seek_update(int id, uint32_t seek); +int +db_file_rating_update_byid(uint32_t id, uint32_t rating); + +int +db_file_rating_update_byvirtualpath(const char *virtual_path, uint32_t rating); + void db_file_delete_bypath(const char *path); diff --git a/src/httpd_dacp.c b/src/httpd_dacp.c index 4d73974f..9cec68b8 100644 --- a/src/httpd_dacp.c +++ b/src/httpd_dacp.c @@ -1005,7 +1005,6 @@ dacp_propset_repeatstate(const char *value, struct evkeyvalq *query) static void dacp_propset_userrating(const char *value, struct evkeyvalq *query) { - struct media_file_info *mfi; const char *param; uint32_t itemid; uint32_t rating; @@ -1052,35 +1051,31 @@ dacp_propset_userrating(const char *value, struct evkeyvalq *query) return; } - mfi = db_file_fetch_byid(itemid); + ret = db_file_rating_update_byid(itemid, rating); /* If no mfi, it may be because we sent an invalid nowplaying itemid. In this * case request the real one from the player and default to that. */ - if (!mfi) + if (ret == 0) { DPRINTF(E_WARN, L_DACP, "Invalid id %d for rating, defaulting to player id\n", itemid); ret = player_now_playing(&itemid); - if ((ret < 0) || !(mfi = db_file_fetch_byid(itemid))) + if (ret < 0) { DPRINTF(E_WARN, L_DACP, "Could not find an id for rating\n"); return; } + + ret = db_file_rating_update_byid(itemid, rating); + if (ret <= 0) + { + DPRINTF(E_WARN, L_DACP, "Could not find an id for rating\n"); + + return; + } } - - mfi->rating = rating; - - /* rating is shared as MPD sticker `rating` */ - listener_notify(LISTENER_STICKER); - - /* We're not touching any string field in mfi, so it's safe to - * skip unicode_fixup_mfi() before the update - */ - db_file_update(mfi); - - free_mfi(mfi, 0); } diff --git a/src/library.c b/src/library.c index b5e357f0..cafbc654 100644 --- a/src/library.c +++ b/src/library.c @@ -93,6 +93,7 @@ static struct event *updateev; // Counts the number of changes made to the database between to DATABASE // event notifications static unsigned int deferred_update_notifications = 0; +static short deferred_update_events = 0; static bool handle_deferred_update_notifications(void) @@ -654,14 +655,18 @@ update_trigger_cb(int fd, short what, void *arg) { if (handle_deferred_update_notifications()) { - listener_notify(LISTENER_DATABASE); + listener_notify(deferred_update_events); + deferred_update_events = 0; } } static enum command_state update_trigger(void *arg, int *retval) { + short *events = arg; + ++deferred_update_notifications; + deferred_update_events |= *events; // Only add the timer event if the update occurred outside a (init-/re-/fullre-) scan. // The scanning functions take care of notifying clients of database changes directly @@ -780,19 +785,22 @@ library_is_exiting() * is emitted with the delay 'library_update_wait'. It is safe to call this function from any thread. */ void -library_update_trigger(void) +library_update_trigger(short update_events) { + short *events; int ret; pthread_t current_thread = pthread_self(); if (pthread_equal(current_thread, tid_library)) { // We are already running in the library thread, it is safe to directly call update_trigger - update_trigger(NULL, &ret); + update_trigger(&update_events, &ret); } else { - commands_exec_async(cmdbase, update_trigger, NULL); + events = malloc(sizeof(short)); + *events = update_events; + commands_exec_async(cmdbase, update_trigger, events); } } diff --git a/src/library.h b/src/library.h index c4586e07..63f4d986 100644 --- a/src/library.h +++ b/src/library.h @@ -116,7 +116,7 @@ bool library_is_exiting(); void -library_update_trigger(void); +library_update_trigger(short update_events); int library_playlist_add(const char *vp_playlist, const char *vp_item); diff --git a/src/mpd.c b/src/mpd.c index bfa95ab0..f11c619d 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -3423,9 +3423,6 @@ static struct mpd_sticker_command mpd_sticker_handlers[] = { { NULL, NULL, 0, 0, 0 }, }; -static void -mpd_add_idle_events(short event_mask); - /* * Command handler function for 'sticker' * @@ -3511,12 +3508,7 @@ mpd_command_sticker(struct evbuffer *evbuf, int argc, char **argv, char **errmsg if (ret == 0 && mfi && set_rating && mfi->rating != rating) { - DPRINTF(E_DBG, L_MPD, "STICKER notification for changed rating: %d -> %d\n", mfi->rating, rating); - mfi->rating = rating; - /* Note, that a DATABASE event is triggered, but the - * client actually expects a sticker event, so add it here. */ - mpd_add_idle_events(LISTENER_STICKER); - db_file_update(mfi); + db_file_rating_update_byvirtualpath(virtual_path, rating); } free(virtual_path); @@ -5057,28 +5049,6 @@ mpd_accept_error_cb(struct evconnlistener *listener, void *ctx) DPRINTF(E_LOG, L_MPD, "Error occured %d (%s) on the listener.\n", err, evutil_socket_error_to_string(err)); } -static void -mpd_add_idle_events(short event_mask) -{ - struct mpd_client_ctx *client; - int i; - - DPRINTF(E_DBG, L_MPD, "Add idle events (untriggered): %d\n", event_mask); - - i = 0; - client = mpd_clients; - while (client) - { - client->events |= event_mask; - if (client->is_idle) - { - client->events &= client->idle_events; - } - client = client->next; - i++; - } -} - static int mpd_notify_idle_client(struct mpd_client_ctx *client_ctx, short events) { @@ -5154,21 +5124,11 @@ static void mpd_listener_cb(short event_mask) { short *ptr; - pthread_t current_thread = pthread_self(); - if (pthread_equal(current_thread, tid_mpd)) - { - int ret; - DPRINTF(E_DBG, L_MPD, "Immediate listener callback called with event type %d.\n", event_mask); - mpd_notify_idle(&event_mask, &ret); - } - else - { - ptr = (short *)malloc(sizeof(short)); - *ptr = event_mask; - DPRINTF(E_DBG, L_MPD, "Asynchronous listener callback called with event type %d.\n", event_mask); - commands_exec_async(cmdbase, mpd_notify_idle, ptr); - } + ptr = (short *)malloc(sizeof(short)); + *ptr = event_mask; + DPRINTF(E_DBG, L_MPD, "Asynchronous listener callback called with event type %d.\n", event_mask); + commands_exec_async(cmdbase, mpd_notify_idle, ptr); } /*