diff --git a/inc/lektor/common.h b/inc/lektor/common.h
index 12cea20343d4b5f0ff8524ec938046bd0be1788a..21f6076dc8bd109e7a32fe0a3987522d8452ed63 100644
--- a/inc/lektor/common.h
+++ b/inc/lektor/common.h
@@ -32,12 +32,12 @@
 #define NOTHING                         /* Usefull to return nothing in previous macros */
 
 #define STRTOL(ret, str, endptr, err_flag)                  \
-{                                                           \
+({                                                          \
     err_flag = 0;                                           \
     errno    = 0;                                           \
     ret      = str == NULL ? 0 : strtol(str, &(endptr), 0); \
     err_flag = errno != 0 || endptr == str;                 \
-}
+})
 
 /* Custom defined assert. */
 extern void (*__lkt_assert)(const char *file, int line, const char *func, const char *msg);
@@ -100,6 +100,11 @@ void __lkt_log_unlock(enum log_level);
 #define LKT_MESSAGE_MAX             2048
 #define LKT_DEFAULT_LIST_SIZE       10
 
+#define LKT_BACKLOG         32
+#define COMMAND_LIST_MAX    64
+#define BUFFER_OUT_MAX      16
+#define MPD_VERSION         "0.21.16"
+
 typedef volatile enum {
     MPD_IDLE_NONE               = 0,
 
@@ -123,11 +128,6 @@ typedef volatile enum {
         MPD_IDLE_STICKER  | MPD_IDLE_SUBSCRIPTION | MPD_IDLE_MESSAGE,
 } mpd_idle_flag;
 
-#define LKT_BACKLOG         32
-#define COMMAND_LIST_MAX    64
-#define BUFFER_OUT_MAX      16
-#define MPD_VERSION         "0.21.16"
-
 #define STR_MATCH(str1, str2)           (! strcasecmp(str1, str2))
 #define STR_NMATCH(str1, str2, n)       (! strncasecmp(str1, str2, n))
 
diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index e980b680ac3dd7b0026b09492f4f3609826663f6..d8174136119e9032d14b0fc32d83dbf01cd95771 100644
--- a/inc/lektor/database.h
+++ b/inc/lektor/database.h
@@ -171,6 +171,7 @@ struct lkt_playlist_metadata {
 };
 
 /* Control playlists */
+bool database_plt_touch     (volatile sqlite3 *db, const char *name);
 bool database_plt_create    (volatile sqlite3 *db, const char *name);
 bool database_plt_remove    (volatile sqlite3 *db, const char *name);
 bool database_plt_remove_pos(volatile sqlite3 *db, const char *name, int pos);
diff --git a/src/database/playlist.c b/src/database/playlist.c
index eef0491dad14187106e1c128f5b9620d4b0bfcf1..35c45950e690abbd4a0c75368911051d9067bc76 100644
--- a/src/database/playlist.c
+++ b/src/database/playlist.c
@@ -9,6 +9,34 @@
 
 #include "macro.h"
 
+bool
+database_plt_touch(volatile sqlite3 *db, const char *name)
+{
+    static const char *SQL_STMT = "SELECT name FROM playlist WHERE name = ?";
+    static const char *SQL_TOUCH = "UPDATE playlist SET last_update = strftime('%s', 'now') WHERE name = ?";
+    sqlite3_stmt *stmt = NULL;
+    bool sta = false;
+
+    SQLITE_PREPARE(db, stmt, SQL_STMT, error);
+    SQLITE_BIND_TEXT(db, stmt, 1, name, error);
+
+    if (sqlite3_step(stmt) != SQLITE_ROW) {
+        sta = database_plt_create(db, name);
+    } else {
+        sqlite3_finalize(stmt);
+        stmt = NULL;
+        SQLITE_PREPARE(db, stmt, SQL_TOUCH, error);
+        SQLITE_BIND_TEXT(db, stmt, 1, name, error);
+        SQLITE_STEP_DONE(db, stmt, error);
+        sta = true;
+    }
+
+error:
+    if (stmt)
+        sqlite3_finalize(stmt);
+    return sta;
+}
+
 bool
 database_plt_create(volatile sqlite3 *db, const char *name)
 {
@@ -159,22 +187,29 @@ error:
 bool
 database_plt_add_uri(volatile sqlite3 *db, const char *name, struct lkt_uri *uri)
 {
-    static const char *SQL =
-        "INSERT OR REPLACE INTO kara_playlist (kara_id, playlist_id) "
-        "SELECT"
-        " kara.id,"
-        " (SELECT playlist.id FROM playlist WHERE name = ? COLLATE NOCASE)"
-        "FROM kara WHERE kara.%s LIKE ?;";
-    char SQL_STMT[LKT_MAX_SQLITE_STATEMENT], sta = false;
-    sqlite3_stmt *stmt;
-
-    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL, uri->column_name);
-    SQLITE_PREPARE(db, stmt, SQL_STMT, error);
-    SQLITE_BIND_TEXT(db, stmt, 1, name, error);
-    SQLITE_BIND_TEXT(db, stmt, 2, (char *) uri->value, error);
-    SQLITE_STEP_DONE(db, stmt, error);
-    sta = true;
+    if (uri->is_int) {
+        LOG_ERROR("DB", "Add by ID (where the uri is an integer) is not implemented yet");
+        return false;
+    }
+
+    else {
+        static const char *SQL =
+            "INSERT OR REPLACE INTO kara_playlist (kara_id, playlist_id) "
+            "SELECT"
+            " kara.id,"
+            " (SELECT playlist.id FROM playlist WHERE name = ? COLLATE NOCASE)"
+            "FROM kara WHERE kara.%s LIKE ?;";
+        char SQL_STMT[LKT_MAX_SQLITE_STATEMENT], sta = false;
+        sqlite3_stmt *stmt;
+
+        safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL, uri->column_name);
+        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
+        SQLITE_BIND_TEXT(db, stmt, 1, name, error);
+        SQLITE_BIND_TEXT(db, stmt, 2, (char *) uri->value, error);
+        SQLITE_STEP_DONE(db, stmt, error);
+        sta = true;
 error:
-    sqlite3_finalize(stmt);
-    return sta;
+        sqlite3_finalize(stmt);
+        return sta;
+    }
 }
diff --git a/src/module/module_repo.c b/src/module/module_repo.c
index 5866a92f7b50ffe2f36a13e206313f82b228289b..c029e999a38607917f01b266c2d75fc721f9bca1 100644
--- a/src/module/module_repo.c
+++ b/src/module/module_repo.c
@@ -80,25 +80,30 @@ struct __file {
 
 /* Recursive mkdir, where the last word of the string is a file, not a folder. */
 static inline void
-__mkdir(const char *dir)
+__mkdir(const char *dir, unsigned int umask)
 {
     /* TODO pour le Kubat du futur: include le umask dans la conf. */
 
+    if (umask == 0)
+        umask = 00700;
+
     char tmp[PATH_MAX];
     char *p = NULL;
     safe_snprintf(tmp, sizeof(tmp) / sizeof(char), "%s", dir);
     size_t len = strlen(tmp);
     if (tmp[len - 1] == '/')
         tmp[len - 1] = 0;
+
     for (p = tmp + 1; *p; p++) {
         if (*p == '/') {
             *p = 0;
-            mkdir(tmp, 00700);
+            mkdir(tmp, umask);
             *p = '/';
         }
     }
+
     /* Do the final mkdir, because it's a folder. */
-    mkdir(tmp, 00700);
+    mkdir(tmp, umask);
 }
 
 static inline void
@@ -115,7 +120,7 @@ __craft_filename_non_obfuscate(char str[PATH_MAX], size_t len, struct kara *kara
      * possible.  The program will fail later, when write will be attempted. */
     len += safe_snprintf(str + len, PATH_MAX - len, "%s/%s/%s/", kara->mdt.category,
                          kara->mdt.language, kara->mdt.author_name);
-    __mkdir(str);
+    __mkdir(str, 0);
     if (access(str, R_OK | W_OK))
         LOG_ERROR("REPO", "No access in read / write for folder %s", str);
     safe_snprintf(str + len, PATH_MAX - len, "%s - %s%d - %s.mkv", kara->mdt.source_name,
@@ -190,7 +195,7 @@ __safe_json_get_long(struct json_object *json, const char *key, long *ret)
 }
 
 static int
-__json_sync(struct module_repo_internal *repo, struct json_object **json)
+__json_dl(const char *url, struct json_object **json)
 {
     RETURN_UNLESS(json, "Invalid argument", 1);
     CURL *curl_handle;
@@ -208,15 +213,14 @@ __json_sync(struct module_repo_internal *repo, struct json_object **json)
 
     curl_handle = curl_easy_init();
     curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER,    headers);
-    curl_easy_setopt(curl_handle, CURLOPT_URL,           repo->get_all_json);
+    curl_easy_setopt(curl_handle, CURLOPT_URL,           url);
     curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, __write_mem);
     curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA,     (void *) &file);
     curl_easy_setopt(curl_handle, CURLOPT_USERAGENT,     "libcurl-agent/1.0");
     res = curl_easy_perform(curl_handle);
 
     if (res != CURLE_OK) {
-        LOG_ERROR("CURL", "curl_easy_perform failed on url %s: %s", repo->get_all_json,
-                  curl_easy_strerror(res));
+        LOG_ERROR("CURL", "curl_easy_perform failed on url %s: %s", url, curl_easy_strerror(res));
         goto err;
     }
 
@@ -439,7 +443,7 @@ __worker_update(void *__repo)
     struct json_object *json;
     LOG_INFO("REPO", "Download kara list from %s (%s), directory is %s",
              repo->name, repo->get_all_json, repo->kara_dir);
-    if (__json_sync(repo, &json)) {
+    if (__json_dl(repo->get_all_json, &json)) {
         LOG_ERROR("REPO", "Failed to get json, possibly no internet connexion or repo is down");
         pthread_exit(NULL);
     }
@@ -475,8 +479,8 @@ __worker_rescan(void *__repo)
     repo->updating &= REPO_UPDATE_KARA;
     GOTO_IF(pthread_mutex_unlock(&(repo->mtx)), "Failed to unlock", end_no_lock);
 
-    database_update(repo->db, kara_prefix, 0); /* Don't check timestamp.
-                                                * TODO: Sometimes we want to check them */
+    database_update(repo->db, kara_prefix, 0);
+    /* Don't check timestamp. TODO: Sometimes we want to check them */
 
     GOTO_IF(pthread_mutex_lock(&(repo->mtx)), "Failed to lock", end_no_lock);
     repo->updating &= (~ REPO_UPDATE_KARA);
@@ -487,6 +491,61 @@ end_no_lock:
     pthread_exit(NULL);
 }
 
+static inline void
+__handle_fav_list(struct module_repo_internal *repo, char *fav, size_t fav_size)
+{
+    struct json_object *json, *item_json = NULL;
+    char fav_url[LKT_LINE_MAX];
+    char *fav_origin = NULL;
+
+    memset(fav_url, 0, LKT_LINE_MAX * sizeof(char));
+    strncat(fav_url, repo->get_fav_json, LKT_LINE_MAX - 1);
+    strncat(fav_url, fav, LKT_LINE_MAX - 1);
+
+    RETURN_IF(__json_dl(fav_url, &json), "Failed to download fav list", NOTHING);
+
+    /* Prepend by `@`, to diferentiate with playlists */
+    size_t fav_len = strlen(fav);
+    if (fav_size - 1 == fav_len) {
+        fav_origin = fav;
+        LOG_WARN("REPO", "Fav list has a name to big to prepend it by '@'. Possible collision with other playlists");
+    } else {
+        memmove(fav + sizeof(char), fav, fav_len * sizeof(char));
+        fav_origin = fav;
+        fav[0] = (char) ("@");
+        fav += sizeof(char);
+        LOG_INFO("REPO", "Importing fav list '%s' as '%s'", fav_origin, fav);
+    }
+
+    database_plt_touch(repo->db, fav);
+    struct lkt_uri uri = {
+        .type   = uri_id,
+        .is_int = true,
+    };
+
+    size_t len = json_object_array_length(json), i;
+    long id;
+    for (i = 0; i < len; ++i) {
+        item_json = json_object_array_get_idx(json, i);
+        if (item_json == NULL) {
+            LOG_ERROR("REPO", "There is no kara at index %ld in fav list %s", i, fav);
+            continue;
+        }
+        if (__safe_json_get_long(item_json, "id", &id)) {
+            LOG_ERROR("REPO", "Failed to get the id of the kara in fav list %s", fav_origin);
+            continue;
+        }
+        uri.id = id;
+        if (!database_plt_add_uri(repo->db, fav, &uri)) {
+            LOG_ERROR("REPO", "Failed to add kara %ld to playlist %s", fav);
+            continue;
+        }
+    }
+
+    LOG_INFO("REPO", "Finished importing fav list '%s' as '%s'", fav_origin, fav);
+    json_object_put(json);
+}
+
 static void *
 __worker_import_favorites(void *__repo)
 {
@@ -496,19 +555,33 @@ __worker_import_favorites(void *__repo)
     repo->updating &= REPO_UPDATE_FAV;
     GOTO_IF(pthread_mutex_unlock(&(repo->mtx)), "Failed to unlock", end_no_lock);
 
-    // struct json_object *json;
+    struct json_object *json, *item_json = NULL;
     LOG_INFO("REPO", "Download favorite lists from %s (%s), directory is %s",
-             repo->name, repo->get_all_json, repo->kara_dir);
-    // if (__json_sync(repo, &json)) {
-    //     LOG_ERROR("REPO", "Failed to get json, possibly no internet connexion or repo is down");
-    //     pthread_exit(NULL);
-    // }
-    // __handle_got_json(repo->db, repo, json);
-    // LOG_INFO("REPO", "Finished to download and insert kara list");
-    // json_object_put(json);
-    // __handle_deleted_kara(repo->db);
-    // LOG_INFO("REPO", "Finished to deal with deleted kara");
-    // database_updated(repo->db);
+             repo->name, repo->get_fav_json, repo->kara_dir);
+    if (__json_dl(repo->get_fav_json, &json)) {
+        LOG_ERROR("REPO", "Failed to get json, possibly no internet connexion or repo is down");
+        pthread_exit(NULL);
+    }
+    LOG_INFO("REPO", "Finished to dl favorite lists");
+
+    size_t len = json_object_array_length(json), i;
+    char fav_name[LKT_LINE_MAX];
+    for (i = 0; i < len; ++i) {
+        item_json = json_object_array_get_idx(json, i);
+        if (item_json == NULL) {
+            LOG_ERROR("REPO", "There is no item with index %ld in fav list", i);
+            continue;
+        }
+        GOTO_IF(__safe_json_get_string(item_json, "pseudo", fav_name, LKT_LINE_MAX),
+                "Field 'pseudo' not found in json item", error);
+
+        /* TODO: Add a way to use the workers to do this for each fav list */
+        __handle_fav_list(repo, fav_name, LKT_LINE_MAX);
+    }
+
+error:
+    json_object_put(json);
+    LOG_INFO("REPO", "Finished to deal with %ld favorite lists", len);
 
     GOTO_IF(pthread_mutex_lock(&(repo->mtx)), "Failed to lock", end_no_lock);
     repo->updating &= (~ REPO_UPDATE_FAV);