diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index ea396b229b66930e474fd911e2159528e9892c11..b6fe3bf2aa4333f7223d80d612ef99b1849be357 100644
--- a/inc/lektor/database.h
+++ b/inc/lektor/database.h
@@ -92,21 +92,24 @@ struct lkt_search {
         lkt_search_sticker,
     } type;
 
-    void (*call)(void);     /* Called during the iter phase, casted         */
+    void (*call)(void);     /* Called during the iter phase, casted     */
 
     struct lkt_state *srv;
     size_t c;
 
-    long continuation;      /* The continuation state of the client         */
-    int msg_count;          /* How much messages we can send                */
+    long continuation;      /* The continuation state of the client     */
+    int msg_count;          /* How much messages we can send            */
 
-    const char *st_name;    /* Stickers and playlists                       */
-    int st_value;           /* The value of a sticker                       */
-    int st_uri;             /* URI of a sticker                             */
-    char st_op;             /* Comparaison operator for stickers            */
-    char *st_type;          /* Type of sticker                              */
+    union {
+        const char *st_name;    /* Sticker name                         */
+        const char *plt_name;   /* Playlist name                        */
+    };
+    int st_value;               /* The value of a sticker               */
+    int st_uri;                 /* URI of a sticker                     */
+    char st_op;                 /* Comparaison operator for stickers    */
+    char *st_type;              /* Type of sticker                      */
 
-    struct lkt_uri ka_uri;  /* Search by uri, depract the use of ka_rgx     */
+    struct lkt_uri ka_uri;      /* Search by uri                        */
 };
 
 typedef bool (*lkt_search_init_add_func)(volatile sqlite3 *, struct lkt_uri *, int);
@@ -117,6 +120,7 @@ typedef bool (*lkt_search_sticker_func) (struct lkt_state *srv, size_t c, const
 bool database_search_database_init(volatile sqlite3 *db, struct lkt_search *ret);
 bool database_search_queue_init   (volatile sqlite3 *db, struct lkt_search *ret);
 bool database_search_sticker_init (volatile sqlite3 *db, struct lkt_search *ret);
+bool database_search_playlist_init(volatile sqlite3 *db, struct lkt_search *ret);
 bool database_search_iter(struct lkt_search *item);
 
 /* Next and prev operation on the queue. */
diff --git a/src/commands.c b/src/commands.c
index 92f63810f3b300e1f3d8bcba16a3b6742c1e0daf..497786cee00542d7dac11879057c1949d7179be9 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -282,9 +282,8 @@ command_addid(volatile sqlite3 *db, struct lkt_win *win,
     errno = 0;
     int i;
     struct lkt_uri uri = { .type = uri_id };
-    for (i = 0; (uri.id = strtol(args[i], NULL, 0)) && ! errno; ++i) {
+    for (i = 0; (uri.id = strtol(args[i], NULL, 0)) && ! errno; ++i)
         errno |= database_queue_add_id(db, uri.id, 1);
-    }
     *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
     return ! errno;
 }
@@ -443,15 +442,22 @@ command_find(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_MAX],
         .srv = srv,
         .c = c,
         .continuation = continuation,
-        .msg_count = lkt_remaining_msg(srv, c) - 3, /* Reserve slots for OK/ACK and continue: */
+        /* Reserve slots for OK/ACK and continue: */
+        .msg_count = lkt_remaining_msg(srv, c) - 3,
         .call = (void(*)(void)) lkt_callback_send_row_v2,
         .ka_uri = {0},
+        .plt_name = args[0], /* In case of playlist searchs */
     };
 
     /* Check args */
     RETURN_UNLESS(args[0], "Invalid argument", false);
-    RETURN_UNLESS(lkt_uri_from_list(&search.ka_uri, args),
-                  "Failed to create the uri from the cmd", false);
+    if (!lkt_uri_from_list(&search.ka_uri, args)) {
+        /* Try from idx 1, in case of playlust searches */
+        LOG_DEBUG("COMMAND", "URI may not starts at idx 0, may be because "
+                  "of playlist search. At idx 0, value was '%s'", args[0]);
+        RETURN_UNLESS(lkt_uri_from_list(&search.ka_uri, &args[1]),
+                      "Failed to create the uri", false);
+    }
 
     /* Make the search langand do the right action */
     RETURN_UNLESS(init(srv->db, &search), "Failed to init search", false);
diff --git a/src/database/find.c b/src/database/find.c
index 6d1024feff341213ab59f3884b39d8b70faad964..30707bf11c7b653f257bc6ed5fb71989936c836f 100644
--- a/src/database/find.c
+++ b/src/database/find.c
@@ -8,6 +8,12 @@
 #include <stdio.h>
 #include <string.h>
 
+static inline int
+__check_sticker_type(const char *type)
+{
+    return ! ( STR_MATCH(type, "kara") || STR_MATCH(type, "plt") );
+}
+
 bool
 database_search_database_init(volatile sqlite3 *db, struct lkt_search *ret)
 {
@@ -33,11 +39,43 @@ error:
     return false;
 }
 
+bool
+database_search_playlist_init(volatile sqlite3 *db, struct lkt_search *ret)
+{
+    RETURN_UNLESS(ret, "Exit because return pointer is NULL", false);
+    static const char *SQL_TEMPLATE =
+        "WITH content AS ("
+        " SELECT kara.id AS id, string, LENGTH(CAST(kara.id AS TEXT)) AS len"
+        " FROM kara_playlist"
+        " JOIN playlist ON playlist.id = playlist_id"
+        "               AND playlist.name COLLATE nocase = ?"
+        " JOIN kara ON kara.id = kara_id"
+        "           AND %s LIKE ?)"
+        "SELECT id, string, (SELECT MAX(len) FROM content)"
+        "FROM content LIMIT %d OFFSET %d;";
+    char SQL_STMT[LKT_MAX_SQLITE_STATEMENT];
+    ret->type = lkt_search_playlist;
+
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_TEMPLATE,
+                  ret->ka_uri.column_name, ret->msg_count, ret->continuation);
+    SQLITE_PREPARE(db, ret->stmt, SQL_STMT, error);
+    SQLITE_BIND_TEXT(db, ret->stmt, 1, ret->plt_name, error);
+    SQLITE_BIND_TEXT(db, ret->stmt, 2, ret->ka_uri.value, error);
+    ret->db = db;
+    return true;
+error:
+    sqlite3_finalize(ret->stmt);
+    return false;
+}
+
 bool
 database_search_sticker_init(volatile sqlite3 *db, struct lkt_search *ret)
 {
-    /* No bound checks in strcats, should be fine. Possible SQL injection,
-       depend on the `type`. */
+    if (__check_sticker_type(ret->st_type)) {
+        LOG_ERROR("DB", "Type '%s' is invalid", ret->st_type);
+        return false;
+    }
+
     static const char *SQL_all_types =
         "SELECT name, sts.id, value FROM 'stickers' JOIN "
         "( SELECT id, sticker, value, 'kara' FROM 'stickers.kara'"
@@ -125,19 +163,19 @@ database_search_iter(struct lkt_search *item)
     switch (item->type) {
     case lkt_search_database:
     case lkt_search_queue:
-        id      = sqlite3_column_int(item->stmt, 0);
-        sql_row = (const char *) sqlite3_column_text(item->stmt, 1);
-        id_len  = sqlite3_column_int(item->stmt, 2);
+    case lkt_search_playlist:
+        id      = sqlite3_column_int  (item->stmt, 0);
+        sql_row = sqlite3_column_chars(item->stmt, 1);
+        id_len  = sqlite3_column_int  (item->stmt, 2);
         return ((lkt_search_database_func) item->call)
                (item->srv, item->c, id, id_len, sql_row);
     case lkt_search_sticker:
-        sql_row = (const char *) sqlite3_column_text(item->stmt, 0); /* Name */
-        id      = sqlite3_column_int(item->stmt, 1);                 /* Id   */
-        code    = sqlite3_column_int(item->stmt, 2);                 /* Val  */
-        type    = (const char *) sqlite3_column_text(item->stmt, 3); /* Type */
+        sql_row = sqlite3_column_chars(item->stmt, 0);  /* Name */
+        id      = sqlite3_column_int  (item->stmt, 1);  /* Id   */
+        code    = sqlite3_column_int  (item->stmt, 2);  /* Val  */
+        type    = sqlite3_column_chars(item->stmt, 3);  /* Type */
         return ((lkt_search_sticker_func) item->call)
                (item->srv, item->c, sql_row, type, id, code);
-    case lkt_search_playlist:
     default:
         LOG_WARN("DB", "Search type %d is not implemented", item->type);
         goto end;
diff --git a/src/database/queue.c b/src/database/queue.c
index 3cd69290dd0d70b7ad1dc8eb2a12e6c885bc946b..03ec706a050ed23e25b61e36f2642c0feeb6c97d 100644
--- a/src/database/queue.c
+++ b/src/database/queue.c
@@ -669,7 +669,7 @@ database_queue_dump(volatile sqlite3 *db, const char *plt_name)
     static const char *SQL =
         "WITH plt_id AS (SELECT playlist.id AS id FROM playlist"
         " WHERE name COLLATE nocase = ?) "
-        "INSERT INTO kara_playlist (kara_id, playlist_id)"
+        "INSERT OR IGNORE INTO kara_playlist (kara_id, playlist_id)"
         " SELECT DISTINCT kara_id, plt_id.id"
         " FROM queue, plt_id"
         " ORDER BY RANDOM();";
diff --git a/src/main/lkt.c b/src/main/lkt.c
index 20895dc829b8d4e24d9f5af6a2e628a0c849ce16..6057953f84154b01486ddeb97d9d04ad75354885 100644
--- a/src/main/lkt.c
+++ b/src/main/lkt.c
@@ -855,7 +855,7 @@ redo:
 
     write_socket(sock, "%d listplaylist %s %s://", continuation,
                  args->argv[0], args->argv[1]);
-    for (i = 1; i < args->argc - 1; ++i)
+    for (i = 2; i < args->argc - 1; ++i)
         write_socket(sock, "%s ", args->argv[i]);
     write_socket(sock, "%s\n", args->argv[i]);
 
diff --git a/src/net/listen.c b/src/net/listen.c
index a960160afe9fb2d154181ddbf16026788769b490..59ffd99c68c90ee7726d4c9a059d7b7be1301da8 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -254,6 +254,8 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
             err = ! command_plt_import(srv->db, cmd.args, &srv->mpd_idle_events);
         else if (STR_MATCH(cmd.name, "__dump"))
             err = ! command_dump(srv->db, cmd.args, &srv->mpd_idle_events);
+        else if (STR_MATCH(cmd.name, "listplaylist"))
+            err = ! command_find(srv, c, cmd.args, cmd.cont, database_search_playlist_init);
 
         else if (STR_MATCH(cmd.name, "random"))
             err = !command_set_playback_option(srv, c, lkt_playback_option_random, cmd.args);