diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c3d2469bb04228eab654e5f65ca98df2513f69dd..88280fb7c0fbb6f0a9bf50e64dad91b1839bdd22 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,8 +9,12 @@ stages:
     tags:
         - kurisu
     only:
-        - main
+        - master
         - merge_requests
+    except:
+        variables:
+            - $CI_MERGE_REQUEST_TITLE =~ /^WIP:/
+            - $CI_MERGE_REQUEST_TITLE =~ /^Draft:/
     variables:
         SRC_DIR: $CI_PROJECT_DIR                            # Where the sources are
         WORK_DIR: "/home/gitlab-runner/CI_$CI_PIPELINE_ID"  # Where we will work, so that it's not erased
diff --git a/configure b/configure
index 440c4c2844dad8c136d117db7a1a0e533f16b3ba..ca7d3351e34d7450c5fd52df31e9866bd8a453f9 100755
--- a/configure
+++ b/configure
@@ -1422,7 +1422,7 @@ Optional Features:
                           optimize for fast installation [default=yes]
   --disable-libtool-lock  avoid locking (might break parallel builds)
   --enable-debug          Enable debug so you can use gdb
-  --enable-static-module  Build modules statically in liblektor
+  --disable-static-module Build modules statically not in liblektor
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -13541,9 +13541,9 @@ fi
 
 # Check whether --enable-static-module was given.
 if test "${enable_static_module+set}" = set; then :
-  enableval=$enable_static_module; LKT_STATIC_MODULE=yes
+  enableval=$enable_static_module; LKT_STATIC_MODULE=no
 else
-  LKT_STATIC_MODULE=no
+  LKT_STATIC_MODULE=yes
 fi
 
  if test "x${LKT_STATIC_MODULE}" = "xyes"; then
diff --git a/configure.ac b/configure.ac
index 8f32808d1692d4c87b189b394bdb6276d3d82f64..cfa8891779f1e5f89dc1cc73b3dbcb567d90fdbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -88,10 +88,10 @@ if test "x${LKT_DEBUG_ENABLED}" = "xyes" ; then
 fi
 
 AC_ARG_ENABLE([static-module],
-              [AS_HELP_STRING([--enable-static-module],
-                              [Build modules statically in liblektor])],
-              [LKT_STATIC_MODULE=yes],
-              [LKT_STATIC_MODULE=no])
+              [AS_HELP_STRING([--disable-static-module],
+                              [Build modules statically not in liblektor])],
+              [LKT_STATIC_MODULE=no],
+              [LKT_STATIC_MODULE=yes])
 AM_CONDITIONAL([LKT_STATIC_MODULE], [test "x${LKT_STATIC_MODULE}" = "xyes"])
 if test "x${LKT_STATIC_MODULE}" = "xyes" ; then
     AC_DEFINE([LKT_STATIC_MODULE], [], [Build with modules inside liblektor])
diff --git a/inc/lektor/common.h b/inc/lektor/common.h
index 6699edeffb2658f0948d96c562b063981efaec15..c65f732a5fc441a5d90858350852c337ef4af2ad 100644
--- a/inc/lektor/common.h
+++ b/inc/lektor/common.h
@@ -180,5 +180,10 @@ long long_length(long integer);
 void *safe_malloc(size_t size);
 void *safe_zero_malloc(size_t size);
 int safe_snprintf(char *dest, const size_t max_len, const char *format, ...);
+char *safe_strncpy(char *dest, const char *src, size_t n);
+
+/* Iterate throught a string, copy each element in the dest string.
+   The save ptr must contains a null integer. */
+int iter_string(const char *str, const char *sep, char *dest, const size_t dest_len, size_t *save);
 
 #endif /* __LKT_COMMON_H__ */
diff --git a/inc/lektor/config.def b/inc/lektor/config.def
index 8c442b0174fc5749145561b10e4186218a738fca..e32c0f78000a0ce91c3712dfad0448c69758b937 100644
--- a/inc/lektor/config.def
+++ b/inc/lektor/config.def
@@ -13,6 +13,8 @@ value("kara_dir",       "/home/kara") /* All the folder and sub folder
                                          must be on the same partition */
 value("db_path",        "/home/kara/kara.db")
 
+/* The repo module, here to be able to sync the bakabase with kurisu or
+   any other server, if configured correctly */
 section("repo")
 value("obfuscate",      "1")
 value("module",         "repo")
@@ -23,6 +25,9 @@ value("json",           "https://kurisu.iiens.net/api")
 value("id_json",        "https://kurisu.iiens.net/api?id=%ld")
 value("id_kara",        "https://kurisu.iiens.net/download.php?id=%ld")
 
+/* The player module, so that people can 'sing' when using lektor. By
+   default it's sdl, but one can create any module, for audio support
+   only for example. */
 section("player")
 value("module",         "sdl2")
 value("autoclear",      "true")
@@ -33,3 +38,16 @@ value("def_repeat",     "false")
 value("font_size",      "20")
 value("font_name",      "Hack Nerd Font")
 value("msg_duration",   "4")
+
+/* To place hooks, when some things are done in lektor. The default value 'none' is here so that
+   nothing happens. Like any module, the value can point to a module or a function in the internal
+   register. To specify multiple modules, use a comma separated list, line this:
+   `kara_load = print_stdout, print_stderr`
+   For the moment, only functions in the server register are supported.
+   NOTE: All the functions will recieve a va_list as a unique argument. */
+section("hook")
+value("kara_load",   "none") /* Before a kara is loaded to be played,
+                                the 'player' module needs to support it */
+value("queue_begin", "none") /* On play, when the player is not already playing or paused */
+
+// vi:syntax=c
diff --git a/inc/lektor/config.h b/inc/lektor/config.h
index 4515f0e352df48e9bc35978cedd42993206534ce..051e1e617104f85c86da00f2e5dd222bc2b6ae3b 100644
--- a/inc/lektor/config.h
+++ b/inc/lektor/config.h
@@ -9,6 +9,7 @@
 /* Forward definition of the lkt_state structure */
 struct lkt_state;
 
+/* The default configuration, stored as a string */
 #define section(sct)        "\n[" sct "]\n"
 #define value(key, val)     key " = " val "\n"
 #define value_opt(key, val) value(key, val)
@@ -44,4 +45,7 @@ void config_default_file(char *dest, size_t len);
 #define env_set(var, val)   setenv(var, val, 1)
 #define env_get             getenv
 
+/* Handle everything for a hook */
+void config_handle_hook(volatile sqlite3 *db, const char *hook_name);
+
 #endif /* __LKT_CONFIG_H__ */
diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index 1c709d90f14bad6ccd2c65add613ebd80a1b0a06..dc7f91c396eab8d9d23d7342999731c26f162540 100644
--- a/inc/lektor/database.h
+++ b/inc/lektor/database.h
@@ -144,8 +144,9 @@ bool database_validate_conf  (volatile sqlite3 *db);
 bool database_config_set     (volatile sqlite3 *db, const char *section, const char *key,
                               const char *value);
 bool database_config_get_text(volatile sqlite3 *db, const char *section, const char *key,
-                              char *value,
-                              size_t len);
+                              char *value, size_t len);
+bool database_config_get_text_nospace(volatile sqlite3 *db, const char *section,
+                                      const char *key, char *value, size_t len);
 bool database_config_get_int (volatile sqlite3 *db, const char *section, const char *key,
                               int *value);
 bool database_config_exists  (volatile sqlite3 *db, const char *section, const char *key);
diff --git a/inc/lektor/reg.h b/inc/lektor/reg.h
index 9439439d1f63e3ad939160a70a5e6f60c8a0ee16..f1b4ec8ea92842ba4f3673a6235720c6974a59a1 100644
--- a/inc/lektor/reg.h
+++ b/inc/lektor/reg.h
@@ -46,6 +46,9 @@ struct lkt_module {
     REG_DECLARE(reg)                    \
     static struct module_reg *as = reg;
 
+/* The server register */
+#define REG_SERVER __reg__
+
 /* Call a function from a reg.
  * NOTE:
  * - Use the MOD_CALL macro to call a function that takes arguments
@@ -66,5 +69,6 @@ int reg_import(const char *mod, struct module_reg **ret, void **handle);
 
 /* Set the __reg__ pointer. */
 void reg_export(struct module_reg *reg);
+void reg_global(struct module_reg **reg_ptr);
 
 #endif /* __LKT_REG_H__ */
diff --git a/src/base/commands.c b/src/base/commands.c
index 5fc5b0ac8eedd10e6ee2078d0400252c00fc4d60..cb0808dd0b67d09af388c956ef0ac8244835875b 100644
--- a/src/base/commands.c
+++ b/src/base/commands.c
@@ -161,7 +161,12 @@ command_next(struct lkt_state *srv, char __attribute__((unused)) *args[LKT_MESSA
     char filepath[PATH_MAX];
     if (!database_queue_next(srv->db, filepath))
         return false;
-    return ! MOD_CALL(srv->window_mod, "load", filepath);
+    if (MOD_CALL(srv->window_mod, "load", filepath))
+        return false;
+    else {
+        config_handle_hook(srv->db, "kara_load");
+        return true;
+    }
 }
 
 bool
@@ -180,7 +185,12 @@ command_previous(struct lkt_state *srv, char __attribute__((unused)) *args[LKT_M
     char filepath[PATH_MAX];
     if (!database_queue_prev(srv->db, filepath))
         return false;
-    return ! MOD_CALL(srv->window_mod, "load", filepath);
+    if (MOD_CALL(srv->window_mod, "load", filepath))
+        return false;
+    else {
+        config_handle_hook(srv->db, "kara_load");
+        return true;
+    }
 }
 
 static inline bool
@@ -210,7 +220,14 @@ command_play(struct lkt_state *srv, char __attribute__((unused)) *args[LKT_MESSA
     database_queue_stop(srv->db);
     RETURN_IF(MOD_CALL(srv->window_mod, "new", &srv->queue, srv->db), "Can't create window", false);
     srv->mpd_idle_events |= MPD_IDLE_PLAYER;
-    return __play_that_file(srv, pos);
+
+    /* Hooks */
+    if (__play_that_file(srv, pos)) {
+        config_handle_hook(srv->db, "queue_begin");
+        config_handle_hook(srv->db, "kara_load");
+        return true;
+    } else
+        return false;
 }
 
 bool
@@ -238,14 +255,21 @@ command_playid(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
     srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     RETURN_IF(MOD_CALL(srv->window_mod, "new", &srv->queue, srv->db), "Can't create window", false);
     database_queue_seekid(srv->db, (int) id, &pos);
-    return __play_that_file(srv, pos);
+
+    /* Hooks */
+    if (__play_that_file(srv, pos)) {
+        config_handle_hook(srv->db, "queue_begin");
+        config_handle_hook(srv->db, "kara_load");
+        return true;
+    } else
+        return false;
 }
 
 
 bool
 command_stop(struct lkt_state *srv, char __attribute__((unused))  *args[LKT_MESSAGE_ARGS_MAX])
 {
-    RETURN_UNLESS(database_queue_stop(srv->db), "DB error", false);
+    RETURN_UNLESS(database_queue_stop(srv->db), "DB error on stop", false);
     MOD_PROC(srv->window_mod, "close");
     srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     return true;
@@ -283,7 +307,8 @@ inline bool
 command_clear(struct lkt_state *srv, char __attribute__((unused)) *args[LKT_MESSAGE_ARGS_MAX])
 {
     srv->mpd_idle_events |= MPD_IDLE_PLAYER;
-    return database_queue_clear(srv->db);
+    return command_stop(srv, args) &&
+           database_queue_clear(srv->db);
 }
 
 inline bool
diff --git a/src/base/common.c b/src/base/common.c
index 7d76ad345b8bcaff011d6388eb564475c1bf98ef..093e5ff3fe816a7b1bba9e9a04a02031d2fec86a 100644
--- a/src/base/common.c
+++ b/src/base/common.c
@@ -274,3 +274,27 @@ long_length(long integer)
     }
     return count;
 }
+
+char *
+safe_strncpy(char *dest, const char *src, size_t n)
+{
+    char *ret = strncpy(dest, src, n);
+    dest[n - 1] = '\0';
+    return ret;
+}
+
+int
+iter_string(const char *str_list, const char *sep, char *dest, const size_t dest_len, size_t *save)
+{
+    size_t len = strcspn(&str_list[*save], sep);
+
+    if (len == 0)
+        return 1;
+    if (len >= dest_len)
+        return -1;
+
+    strncpy(dest, &str_list[*save], len);
+    dest[len] = '\0';
+    *save += len + 1;
+    return 0;
+}
diff --git a/src/base/config.c b/src/base/config.c
index 4d5d7d50564dfdbe22a04befaa19cef117c30d8f..6ec549ae16bb368977914111c8c8d268922a5179 100644
--- a/src/base/config.c
+++ b/src/base/config.c
@@ -296,3 +296,28 @@ config_open(volatile sqlite3 *db)
 error:
     return ret;
 }
+
+void
+config_handle_hook(volatile sqlite3 *db, const char *hook_name)
+{
+    char hook_handlers[LKT_LINE_MAX];
+    if (!database_config_get_text_nospace(db, "hook", hook_name, hook_handlers, LKT_LINE_MAX)) {
+        LOG_ERROR("HOOK", "Failed to get the hook handlers list for hook '%s'", hook_name);
+        return;
+    }
+
+    size_t save = 0;
+    char name[LKT_LINE_MAX];
+    int code;
+    struct module_reg *server_reg;
+    reg_global(&server_reg);
+
+    while (0 == (code = iter_string(hook_handlers, ",", name, LKT_LINE_MAX, &save))) {
+        if (STR_MATCH("none", name))
+            continue;
+        reg_call(server_reg, name, 1, db);
+    }
+
+    if (code == -1)
+        LOG_ERROR("HOOK", "Failed to parse the handle list for hook '%s'", hook_name);
+}
diff --git a/src/base/reg.c b/src/base/reg.c
index 5a92130142a629d67b315b9cb96468e633cc9ea7..ec42e88851878a5971851aabf93d4c279c353742 100644
--- a/src/base/reg.c
+++ b/src/base/reg.c
@@ -20,6 +20,12 @@ reg_export(struct module_reg *reg)
     __reg__ = reg;
 }
 
+void
+reg_global(struct module_reg **reg_ptr)
+{
+    *reg_ptr = __reg__;
+}
+
 void *
 __reg_get(struct module_reg *reg, const char *name)
 {
diff --git a/src/database/config.c b/src/database/config.c
index ec8c5b139abcb0279ef7a3a4c3022f6b8e2d8af1..86fd2d605dc58eaec6adfd56db04057c101b9c0c 100644
--- a/src/database/config.c
+++ b/src/database/config.c
@@ -67,6 +67,32 @@ error:
     return ret;
 }
 
+bool
+database_config_get_text_nospace(volatile sqlite3 *db, const char *section, const char *key,
+                                 char *value, size_t len)
+{
+    static const char *SQL_STMT =
+        "SELECT REPLACE(value, ' ', '')"
+        " FROM config"
+        " WHERE section = ? AND key = ?;\n";
+    sqlite3_stmt *stmt = 0;
+    bool ret = false;
+    char *row;
+
+    SQLITE_PREPARE(db, stmt, SQL_STMT, error);
+    SQLITE_BIND_TEXT(db, stmt, 1, section, error);
+    SQLITE_BIND_TEXT(db, stmt, 2, key, error);
+    SQLITE_STEP_ROW(db, stmt, error);
+
+    row = (char *) sqlite3_column_text(stmt, 0);
+    strncpy(value, row, len);
+    value[len - 1] = 0;
+    ret = true;
+error:
+    sqlite3_finalize(stmt);
+    return ret;
+}
+
 bool
 database_config_exists(volatile sqlite3 *db, const char *section,
                        const char *key)
diff --git a/src/database/queue.c b/src/database/queue.c
index 1573e56557e7023618ed3cfdbfc0129cfef5966b..ac5d1181731da4fc42923e8e85aceec6648b0c7d 100644
--- a/src/database/queue.c
+++ b/src/database/queue.c
@@ -19,11 +19,18 @@
         SQLITE_DO_ROLLBACK(db);                                         \
         return false;                                                   \
     }
-sqlite_just_exec(database_queue_toggle_pause, "UPDATE queue_state SET paused = 1 - paused;")
-sqlite_just_exec(database_queue_crop, "DELETE FROM queue WHERE queue.kara_id <> (SELECT current FROM queue_state LIMIT 1);")
-sqlite_just_exec(database_queue_stop, "UPDATE queue_state SET current = NULL;")
-sqlite_just_exec(database_queue_clear, "DELETE FROM queue;DELETE FROM sqlite_sequence WHERE name = 'queue';UPDATE queue_state SET current = NULL;")
-sqlite_just_exec(database_config_queue_default, "UPDATE queue_state SET volume = 100, paused = 1, random = 0, repeat = 0, single = 0, consume = 0, current = NULL, duration = 0;")
+sqlite_just_exec(database_queue_toggle_pause,   "UPDATE queue_state SET paused = 1 - paused;")
+sqlite_just_exec(database_queue_crop,           "DELETE FROM queue WHERE queue.kara_id <>"
+                                                " (SELECT current FROM queue_state LIMIT 1);")
+sqlite_just_exec(database_queue_stop,           "UPDATE queue_state SET current = NULL;")
+sqlite_just_exec(database_queue_clear,          "DELETE FROM queue;"
+                                                "DELETE FROM queue_tmp;"
+                                                "DELETE FROM sqlite_sequence WHERE name = 'queue_tmp';"
+                                                "DELETE FROM sqlite_sequence WHERE name = 'queue';"
+                                                "UPDATE queue_state SET current = NULL;")
+sqlite_just_exec(database_config_queue_default, "UPDATE queue_state SET volume = 100, paused = 1,"
+                                                " random = 0, repeat = 0, single = 0, consume = 0,"
+                                                " current = NULL, duration = 0;")
 #undef sqlite_just_exec
 // *INDENT-ON*
 
diff --git a/src/module/module_repo.c b/src/module/module_repo.c
index fc93c722f26819397560f8a2d409a2690e36d4d3..e11cc7101f547009fa5244e8ebb4a2bf982e7b5c 100644
--- a/src/module/module_repo.c
+++ b/src/module/module_repo.c
@@ -387,9 +387,16 @@ static void *
 __worker_rescan(void *__repo)
 {
     struct module_repo_internal *repo = __repo;
+    char kara_prefix[LKT_LINE_MAX];
     lkt_queue_send(repo->queue, lkt_event_db_updating, LKT_DB_UPDATING_PROGRESS);
+    if (!database_config_get_text(repo->db, "database", "kara_dir", kara_prefix, LKT_LINE_MAX)) {
+        LOG_ERROR("REPO", "Failed to get kara prefix from config");
+        pthread_exit(NULL);
+    }
     repo->updating = 1;
-    /* Use the database_update(db, prefix, forced) function here ! */
+    database_update(repo->db, kara_prefix, 0); /* Don't check timestamp.
+                                                  TODO: Sometimes we want to check them */
+    repo->updating = 0;
     lkt_queue_send(repo->queue, lkt_event_db_updating, LKT_DB_UPDATING_FINISHED);
     pthread_exit(NULL);
 }