diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index 4da2d086ac7ee9ca666078a5a341594198ef4f21..c6a399b88a301266cef52c3587bb381ee590dc1b 100644
--- a/inc/lektor/database.h
+++ b/inc/lektor/database.h
@@ -103,9 +103,9 @@ typedef bool (*lkt_search_database_func)(struct lkt_state *srv, size_t c, int id
 typedef bool (*lkt_search_queue_func)   (struct lkt_state *srv, size_t c, int id, int id_len, const char *row);
 typedef bool (*lkt_search_sticker_func) (struct lkt_state *srv, size_t c, const char *sticker, const char *type, int uri, int value);
 
-bool database_search_database_init(volatile sqlite3 *db, char *col_name, char *rgx,  struct lkt_search *ret);
-bool database_search_queue_init   (volatile sqlite3 *db, char *col_name, char *rgx,  struct lkt_search *ret);
-bool database_search_sticker_init (volatile sqlite3 *db, char *type,     char *name, struct lkt_search *ret);
+bool database_search_database_init(volatile sqlite3 *db, char *col_name, char *rgx,                               struct lkt_search *ret);
+bool database_search_queue_init   (volatile sqlite3 *db, char *col_name, char *rgx,                               struct lkt_search *ret);
+bool database_search_sticker_init (volatile sqlite3 *db, char *type,     char *name, int uri, char op, int value, struct lkt_search *ret);
 bool database_search_iter(struct lkt_search *item);
 
 /* Next and prev operation on the queue. */
@@ -147,17 +147,7 @@ bool database_user_authentificate(volatile sqlite3 *db, const char *password);
 bool database_user_add(volatile sqlite3 *db, const char *username, const char *password);
 
 /* Stickers manipulations. */
-struct sticker_callback {
-    struct lkt_state *srv;
-    size_t c;
-    int uri, value, is_ok;
-    const char *name;
-    bool (*call)(void *args, const char *sticker, const char *type, int uri, int value);
-};
-
 bool database_sticker_create        (volatile sqlite3 *db, const char *name);
 bool database_sticker_delete        (volatile sqlite3 *db, const char *name);
 bool database_sticker_delete_specify(volatile sqlite3 *sb, const char *type, int uri, const char *name);
-bool database_sticker_list          (volatile sqlite3 *db, const char *type, struct sticker_callback *call);
 bool database_sticker_set           (volatile sqlite3 *db, const char *type, const char *name, int uri, int value);
-bool database_sticker_get           (volatile sqlite3 *db, const char *type, const char *name, int uri, struct sticker_callback *call);
diff --git a/scripts/init.sql b/scripts/init.sql
index 040b0ff1005adb785082cc1a462f9e2436df7318..98d88281bebf0cb13ffa638df8ec077dedb615a5 100644
--- a/scripts/init.sql
+++ b/scripts/init.sql
@@ -98,6 +98,7 @@ INSERT OR REPLACE INTO users (username, password) VALUES ('sakura', 'hashire');
 -- Used to implement the stickers MPD functionnality, documentation can be found
 -- here: https://www.musicpd.org/doc/html/protocol.html#stickers. Need to be
 -- authentified to use stickers commands. Support tags for `song` and `plt`.
+-- URIs in stickers are kara/playlist IDs.
 
 CREATE TABLE IF NOT EXISTS 'stickers'
   ( id      INTEGER PRIMARY KEY
diff --git a/src/commands.c b/src/commands.c
index 4e2b1a5b585ca60cc51a95184d2eca6f70f1671a..b92c2a106bd1a464bf46ed14e96fd2b91893ee0a 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -713,82 +713,11 @@ command_user_add(struct lkt_state *srv, size_t c, volatile sqlite3 *db, char *ar
 /* Stickers */
 
 static bool
-sticker_send_one_value(void *_args, const char *sticker, const char *type, int uri, int value)
+sticker_send(struct lkt_state *srv, size_t c, char *name, int id, int value)
 {
-    UNUSED(sticker, type, uri);
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    struct lkt_message *out = lkt_message_new();
-    out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "value: %d\n", value);
-    lkt_state_send(args->srv, args->c, out);
-    return false;
-}
-
-static bool
-sticker_send_all(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    struct lkt_message *out = lkt_message_new();
-    out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "%s: %d\nsticker: %s\nvalue: %d\n",
-                             type, uri, sticker, value);
-    lkt_state_send(args->srv, args->c, out);
-    return true;
-}
-
-static bool
-sticker_send_check_uri(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    UNUSED(type);
-
-    if (uri == args->uri) {
-        struct lkt_message *out = lkt_message_new();
-        out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "%s: %d\n", sticker, value);
-        lkt_state_send(args->srv, args->c, out);
-    }
-
-    return true;
-}
-
-static bool
-sticker_send_value_check_uri_name(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    struct lkt_message *out;
-    UNUSED(type);
-
-    if (uri == args->uri || !strcasecmp(sticker, args->name)) {
-        out = lkt_message_new();
-        out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "value: %d\n", value);
-        lkt_state_send(args->srv, args->c, out);
-    }
-
-    return true;
-}
-
-static bool
-sticker_check_is_present_eq(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    UNUSED(type);
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    args->is_ok |= (uri == args->uri) && !strcasecmp(sticker, args->name) && (value == args->value);
-    return true;
-}
-
-static bool
-sticker_check_is_present_lt(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    UNUSED(type);
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    args->is_ok |= (uri == args->uri) && !strcasecmp(sticker, args->name) && (value < args->value);
-    return true;
-}
-
-static bool
-sticker_check_is_present_gt(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    UNUSED(type);
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    args->is_ok |= (uri == args->uri) && !strcasecmp(sticker, args->name) && (value > args->value);
+    struct lkt_message *msg = lkt_message_new();
+    msg->data_len = snprintf(msg->data, LKT_MESSAGE_ARGS_MAX, "%d: %s . %d", id, name, value);
+    lkt_state_send(srv, c, msg);
     return true;
 }
 
@@ -800,12 +729,14 @@ command_sticker_get(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS
     char *endptr;
     STRTOL(uri, argv[1], endptr, err);
     RETURN_IF(err, "STRTOL failed", false);
-    struct sticker_callback cb = {
+    struct lkt_search cb = {
         .srv = srv,
         .c = c,
-        .call = sticker_send_one_value,
     };
-    RETURN_UNLESS(database_sticker_get(srv->db, argv[0], argv[2], uri, &cb), "Failed to get sticker", false);
+    if (!database_search_sticker_init(srv->db, argv[0], argv[2], uri, 0, 0, &cb))
+        return false;
+    while(database_search_iter(&cb))
+        continue;
     return true;
 }
 
@@ -827,9 +758,10 @@ command_sticker_set(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS
 bool
 command_sticker_list(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX])
 {
-    struct sticker_callback callback = {
+    struct lkt_search callback = {
         .srv = srv,
         .c = c,
+        .call = (void(*)(void)) sticker_send,
     };
 
     /* Simple list {type} {uri} command */
@@ -855,38 +787,29 @@ command_sticker_list(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARG
         goto unknown;
 
 just_list_all:
-    callback.call = sticker_send_all;
-    return database_sticker_list(srv->db, argv[0], &callback);
+    if (!database_search_sticker_init(srv->db, argv[0], NULL, 0, 0, 0, &callback))
+        return false;
+    goto iter;
 
 simple_list_command:
-    callback.uri  = atoi(argv[1]);   /* FIXME: Use strtol. */
-    callback.call = sticker_send_check_uri;
-    return database_sticker_list(srv->db, argv[0], &callback);
+    if (!database_search_sticker_init(srv->db, argv[0], NULL, atoi(argv[1]), 0, 0, &callback))
+        return false;
+    goto iter;
 
 list_stickers_in_uri:
-    callback.uri  = atoi(argv[1]);  /* FIXME: Use strtol. */
-    callback.name = argv[2];
-    callback.call = sticker_send_value_check_uri_name;
-    return database_sticker_list(srv->db, argv[0], &callback);
-    return false;
+    if (!database_search_sticker_init(srv->db, argv[0], argv[2], atoi(argv[1]), 0, 0, &callback))
+        return false;
+    goto iter;
 
 list_stickers_check_value:
-    callback.uri   = atoi(argv[1]); /* FIXME: Use strtol. */
-    callback.value = atoi(argv[4]); /* FIXME: Use strtol. */
-    callback.name  = argv[2];
-    switch (argv[3][0]) {
-    case '=':
-        callback.call = sticker_check_is_present_eq;
-        return database_sticker_list(srv->db, argv[0], &callback);
-    case '<':
-        callback.call = sticker_check_is_present_lt;
-        return database_sticker_list(srv->db, argv[0], &callback);
-    case '>':
-        callback.call = sticker_check_is_present_gt;
-        return database_sticker_list(srv->db, argv[0], &callback);
-    default:
-        return 0;
-    }
+    if (!database_search_sticker_init(srv->db, argv[0], argv[2], atoi(argv[1]), argv[3][0], atoi(argv[4]), &callback))
+        return false;
+    goto iter;
+
+iter:
+    while (database_search_iter(&callback))
+        continue;
+    return true;
 
 unknown:
     LOG_ERROR_SCT("COMMAND", "%s", "Specified command is invalid or unknown");
diff --git a/src/database/find.c b/src/database/find.c
index c95a2374aa30b9ff2ad2c5716b0f00da61c56889..2d378348c93fddb45143ad77d8ac88d63a7a6cef 100644
--- a/src/database/find.c
+++ b/src/database/find.c
@@ -35,7 +35,7 @@ error:
 }
 
 bool
-database_search_sticker_init(volatile sqlite3 *db, char *type, char *name, struct lkt_search *ret)
+database_search_sticker_init(volatile sqlite3 *db, char *type, char *name, int uri, char op, int value, struct lkt_search *ret)
 {
     /* No bound checks in strcats, should be fine. Possible SQL injection, depend on the `type`. */
     static const char *SQL_all_types =
@@ -47,17 +47,20 @@ database_search_sticker_init(volatile sqlite3 *db, char *type, char *name, struc
         "ON sts.sticker = 'stickers'.id";
     static const char *SQL_one_type =
         "SELECT name, 'stickers.%s'.id, value "
-        "FROM 'stickers' "
+        "FROM 'stickers.%s' AS sts"
         "LEFT OUTER JOIN 'stickers' "
-        "ON 'stickers'.id = 'stickers.%s'.sticker";
-    static const char *SQL_check_name = " AND name = ?;";
+        "ON 'stickers'.id = sts.sticker";
     char SQL[LKT_MAX_SQLITE_STATEMENT];
 
     if (type == NULL)
         memcpy(SQL, SQL_all_types, strlen(SQL_all_types) + 1);
     else
         sprintf(SQL, SQL_one_type, type, type);
-    strcat(SQL, name ? SQL_check_name : ";");
+    if (uri != 0)
+        sprintf(SQL, " AND sts.id = %d", uri);
+    if (op != 0)
+        sprintf(SQL, " AND sts.value %s %d", op == '>' ? ">=" : op == '<' ? "<=" : "=", value);
+    strcat(SQL, name ? " AND name = ?;": ";");
 
     SQLITE_PREPARE(db, ret->stmt, SQL, error);
     if (name)
diff --git a/src/database/stickers.c b/src/database/stickers.c
index 376621987d250e6819dd9feb44637f7a6e44d2ad..bc49c60339d52926e49cf96e6dd7197fdf2b8f20 100644
--- a/src/database/stickers.c
+++ b/src/database/stickers.c
@@ -45,66 +45,6 @@ error:
     return ret;
 }
 
-bool
-database_sticker_list(volatile sqlite3 *db, const char *type, struct sticker_callback *call)
-{
-    const char *SQL = NULL;
-    int ret = false, uri, value;
-    sqlite3_stmt *stmt;
-    const char *sticker;
-
-    if (type == NULL)
-        SQL =
-            "SELECT name, sts.id, value FROM 'stickers' LEFT OUTER JOIN "
-            "( SELECT id, sticker, value FROM 'stickers.song'"
-            "  UNION"
-            "  SELECT id, sticker, value FROM 'stickers.plt'"
-            ") AS sts"
-            "ON sts.sticker = 'stickers'.id;";
-    else if (!strcasecmp(type, "plt"))
-        SQL =
-            "SELECT name, 'stickers.plt'.id, value "
-            "FROM 'stickers' "
-            "LEFT OUTER JOIN 'stickers' "
-            "ON 'stickers'.id = 'stickers.plt'.sticker;";
-    else if (!strcasecmp(type, "song"))
-        SQL =
-            "SELECT name, 'stickers.song'.id, value "
-            "FROM 'stickers' "
-            "LEFT OUTER JOIN 'stickers' "
-            "ON 'stickers'.id = 'stickers.song'.sticker;";
-    else {
-        LOG_ERROR_SCT("DB", "Type '%s' is invalid", type);
-        return false;
-    }
-
-    SQLITE_PREPARE(db, stmt, SQL, error);
-
-    for (;;) {
-        switch (sqlite3_step(stmt)) {
-        case SQLITE_ROW:
-            sticker = (const char *) sqlite3_column_text(stmt, 0);
-            uri     = sqlite3_column_int(stmt, 1);
-            value   = sqlite3_column_int(stmt, 2);
-            if (!call->call(call, sticker, type, uri, value))
-                goto end_loop;
-            continue;
-
-        case SQLITE_DONE:
-            goto end_loop;
-
-        default:
-            goto error;
-        }
-    }
-
-end_loop:
-    ret = true;
-error:
-    sqlite3_finalize(stmt);
-    return ret;
-}
-
 bool
 database_sticker_set(volatile sqlite3 *db, const char *type, const char *name, int uri, int value)
 {
@@ -146,58 +86,6 @@ error:
     return ret;
 }
 
-bool
-database_sticker_get(volatile sqlite3 *db, const char *type, const char *name, int uri, struct sticker_callback *call)
-{
-    const char *SQL = NULL;
-    sqlite3_stmt *stmt;
-    int ret = false, value;
-
-    if (!strcasecmp(type, "song"))
-        SQL =
-            "SELECT value "
-            "FROM 'stickers' "
-            "JOIN 'stickers.song'"
-            " ON 'stickers'.id = 'stickers.song'.sticker"
-            " AND 'stickers'.name = ?;\n";
-    else if (!strcasecmp(type, "plt"))
-        SQL =
-            "SELECT value "
-            "FROM 'stickers' "
-            "JOIN 'stickers.plt'"
-            " ON 'stickers'.id = 'stickers.plt'.sticker"
-            " AND 'stickers'.name = ?;\n";
-    else {
-        LOG_ERROR_SCT("DB", "Type '%s' is invalid", type);
-        return false;
-    }
-
-    SQLITE_PREPARE(db, stmt, SQL, error);
-    SQLITE_BIND_TEXT(db, stmt, 1, name, error);
-
-    for (;;) {
-        switch (sqlite3_step(stmt)) {
-        case SQLITE_ROW:
-            value = sqlite3_column_int(stmt, 1);
-            if (!call->call(call, name, type, uri, value))
-                goto end_loop;
-            continue;
-
-        case SQLITE_DONE:
-            goto end_loop;
-
-        default:
-            goto error;
-        }
-    }
-
-end_loop:
-    ret = true;
-error:
-    sqlite3_finalize(stmt);
-    return ret;
-}
-
 bool
 database_sticker_delete_specify(volatile sqlite3 *db, const char *type, int uri, const char *name)
 {
diff --git a/src/main/lkt.c b/src/main/lkt.c
index ea03894d8bd2574d6c0eb9acca7b65c1d0bafae6..4c69449bb3a2d4db76ed837810870b69412437ea 100644
--- a/src/main/lkt.c
+++ b/src/main/lkt.c
@@ -378,7 +378,7 @@ ok:
 noreturn void
 queue_pop__(struct lkt_cmd_args *args)
 {
-    fail_if(!args->argc, "Invalid argument");
+    fail_if(args->argc, "Invalid argument");
     int songid = 0;
     char buff[LKT_MESSAGE_MAX];
     FILE *sock = lkt_connect();