From 052cf487dbd37114ea2ebe354c60ab17da8253a9 Mon Sep 17 00:00:00 2001
From: Kubat <mael.martin31@gmail.com>
Date: Thu, 7 May 2020 14:31:39 +0200
Subject: [PATCH] Deal with deleted karas from kurisu

---
 inc/lektor/database.h | 10 +++++++---
 src/database/queue.c  | 20 +++++++++++++++++++-
 src/database/update.c | 41 +++++++++++++++++++++++++++++++++++++++++
 src/net/downloader.c  | 19 ++++++++++++++++++-
 4 files changed, 85 insertions(+), 5 deletions(-)

diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index 1fe0610a..7d1fc780 100644
--- a/inc/lektor/database.h
+++ b/inc/lektor/database.h
@@ -23,9 +23,10 @@ struct lkt_queue_state {
 };
 
 /* Update stuff */
-void database_get_update(volatile sqlite3 *db, long *timestamp, long *job, int *current);
-void database_stamp     (volatile sqlite3 *db);
-void database_updated   (volatile sqlite3 *db);
+void database_get_update  (volatile sqlite3 *db, long *timestamp, long *job, int *current);
+void database_stamp       (volatile sqlite3 *db);
+void database_updated     (volatile sqlite3 *db);
+void database_deleted_kara(volatile sqlite3 *db, int **kara_id, size_t *len);
 
 /* Open correctly a database for lektor. */
 bool database_new   (volatile sqlite3 **db);
@@ -42,6 +43,8 @@ bool database_queue_set_paused       (volatile sqlite3 *db, bool paused);
 bool database_queue_set_current_index(volatile sqlite3 *db, int idx);
 bool database_queue_get_current_file (volatile sqlite3 *db, char filepath[PATH_MAX]);
 
+bool database_get_kara_path(volatile sqlite3 *db, int id, char filepath[PATH_MAX]);
+
 /* Mpv and database synchronisation. */
 bool database_sync_mpv_state(volatile sqlite3 *db, mpv_handle **mpv);
 
@@ -49,6 +52,7 @@ bool database_sync_mpv_state(volatile sqlite3 *db, mpv_handle **mpv);
 bool database_update              (volatile sqlite3 *db, const char *kara_dir, int check_timestamp);
 bool database_update_add          (volatile sqlite3 *db, const char *kara_path, struct kara_metadata *mdt, uint64_t id, bool avail);
 bool database_update_set_available(volatile sqlite3 *db, uint64_t id);
+void database_update_del          (volatile sqlite3 *db, int id);
 
 /* Control the content of the queue. */
 bool database_queue_add_uri(volatile sqlite3 *db, struct lkt_uri *uri, int priority);
diff --git a/src/database/queue.c b/src/database/queue.c
index 2981a045..abce4426 100644
--- a/src/database/queue.c
+++ b/src/database/queue.c
@@ -508,8 +508,10 @@ database_queue_get_current_file(volatile sqlite3 *db, char filepath[PATH_MAX])
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
     code = sqlite3_step(stmt);
 
-    if (code == SQLITE_ROW)
+    if (code == SQLITE_ROW) {
         strncpy(filepath, (const char *) sqlite3_column_text(stmt, 0), PATH_MAX);
+        filepath[PATH_MAX - 1] = '\0';
+    }
 
     else {
         LOG_ERROR_SCT("DB", "Failed to fetch prev kara: %s", sqlite3_errmsg((sqlite3 *) db));
@@ -522,6 +524,22 @@ error:
     return status;
 }
 
+bool
+database_get_kara_path(volatile sqlite3 *db, int id, char filepath[PATH_MAX])
+{
+    sqlite3_stmt *stmt = NULL;
+    static const char *SQL = "SELECT file_path FROM kara WHERE id = ?;";
+    RETURN_UNLESS(id && db && filepath, "Invalid argument", false);
+    SQLITE_PREPARE(db, stmt, SQL, error);
+    SQLITE_BIND_INT(db, stmt, 1, id, error);
+    SQLITE_STEP_ROW(db, stmt, error);
+    strncpy(filepath, (const char *) sqlite3_column_text(stmt, 0), PATH_MAX);
+    filepath[PATH_MAX - 1] = '\0';
+    return true;
+error:
+    return false;
+}
+
 bool
 database_queue_shuffle(volatile sqlite3 *db)
 {
diff --git a/src/database/update.c b/src/database/update.c
index 5a56f927..1ffe8c1d 100644
--- a/src/database/update.c
+++ b/src/database/update.c
@@ -208,6 +208,34 @@ database_update(volatile sqlite3 *db, const char *kara_dir, int check_timestamp)
     return true;
 }
 
+void
+database_deleted_kara(volatile sqlite3 *db, int **kara_id, size_t *len)
+{
+    static const char *SQL =
+        "SELECT kara.id, file_path FROM kara WHERE kara.id NOT IN"
+        "(SELECT kara_id FROM updates JOIN misc ON job = update_job);";
+    sqlite3_stmt *stmt = NULL;
+    *kara_id = (int *) calloc(LKT_DEFAULT_LIST_SIZE, sizeof(int));
+    *len = 0;
+    RETURN_UNLESS(*kara_id, "Out of memory", NOTHING);
+    SQLITE_PREPARE(db, stmt, SQL, out);
+    size_t size = LKT_DEFAULT_LIST_SIZE;
+    void *new;
+
+    while (sqlite3_step(stmt) == SQLITE_ROW) {
+        if (size == *len) {
+            new = realloc((void *) kara_id, (*len) * 2 * sizeof(void *));
+            GOTO_UNLESS(new, "Out of memory", out);
+            size *= 2;
+            *kara_id = new;
+        }
+        (*kara_id)[(*len)++] = sqlite3_column_int(stmt, 0);
+    }
+
+out:
+    return;
+}
+
 void
 database_get_update(volatile sqlite3 *db, long *timestamp, long *job, int *current)
 {
@@ -226,6 +254,19 @@ error:
     LOG_WARN_SCT("DB", "Failed to get informations about the last update: %s", sqlite3_errmsg((sqlite3 *) db));
 }
 
+void
+database_update_del(volatile sqlite3 *db, int id)
+{
+    static const char *SQL = "DELETE FROM kara WHERE id = ?;";
+    sqlite3_stmt *stmt = NULL;
+    SQLITE_PREPARE(db, stmt, SQL, error);
+    SQLITE_BIND_INT(db, stmt, 1, id, error);
+    SQLITE_STEP_OK(db, stmt, error);
+    LOG_WARN_SCT("DB", "Deleted kara with id '%d' from database", id);
+error:
+    return;
+}
+
 #define sqlite_just_exec(func, query)   \
     void func (volatile sqlite3 *db) {  \
         SQLITE_EXEC(db, #query, error); \
diff --git a/src/net/downloader.c b/src/net/downloader.c
index 2bda911e..9606701e 100644
--- a/src/net/downloader.c
+++ b/src/net/downloader.c
@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
+#include <strings.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -371,7 +372,6 @@ __handle_got_json(volatile sqlite3 *db, struct lkt_repo *repo, struct json_objec
             LOG_INFO_SCT("REPO", "Ignore kara '%ld' with path '%s'", kara.id, kara.filename);
             continue;
         }
-        LOG_WARN_SCT("REPO", "Download kara '%ld' with path '%s'", kara.id, kara.filename);
 
         if (!database_update_add((sqlite3 *) db, kara.filename, &kara.mdt, kara.id, false)) {
             LOG_ERROR_SCT("REPO", "Could not add unavailable kara %ld to db", kara.id);
@@ -400,6 +400,21 @@ __handle_got_json(volatile sqlite3 *db, struct lkt_repo *repo, struct json_objec
     }
 }
 
+static inline void
+__handle_deleted_kara(volatile sqlite3 *db)
+{
+    size_t len, i;
+    int *kara_ids;
+    char filepath[PATH_MAX];
+    database_deleted_kara(db, &kara_ids, &len);
+
+    for (i = 0; i < len; ++i) {
+        if (!database_get_kara_path(db, kara_ids[i], filepath))
+            continue;
+        database_update_del(db, kara_ids[i]);
+    }
+}
+
 void *
 __repo_get_all_id_async(void *arg)
 {
@@ -411,6 +426,8 @@ __repo_get_all_id_async(void *arg)
     __handle_got_json(repo->db, repo, json);
     LOG_INFO_SCT("REPO", "%s", "Finished to download and insert kara list");
     json_object_put(json);
+    __handle_deleted_kara(repo->db);
+    LOG_INFO_SCT("REPO", "%s", "Finished to deal with deleted kara");
     database_updated(repo->db);
     return NULL;
 }
-- 
GitLab