diff --git a/README.md b/README.md
index 71c5cb9ab60671ed0a3d3fc9b3c2d9e2ccc77d2d..0e19ed3af58660f4b2668fe6a9025d5ead2c3eea 100644
--- a/README.md
+++ b/README.md
@@ -204,9 +204,9 @@ For the compatibility column, the possible values are the following:
 | `play [songpos]`                  | `play [songpos]`                  | +     | if no `songpos` passed, defaults to `0`         |
 | `playid [songid]`                 | `playid {songid}`                 | +     | get the first found `songid` in the queue       |
 | `previous`                        | `previous`                        | +     |                                                 |
-| `seek {songpos} {time}`           |                                   |       | not implemented                                 |
-| `seekid {songid} {time}`          |                                   |       | not implemented                                 |
-| `seekcur {time}`                  | `seekcur {time}`                  |       | not implemented                                 |
+| `seek {songpos} {time}`           | `seek {songpos} {time}`           | +     |                                                 |
+| `seekid {songid} {time}`          | `seekid {songid} {time}`          | +     | seek to the first found id, sqlite dependent    |
+| `seekcur {time}`                  | `seekcur {time}`                  | +     |                                                 |
 | `stop`                            | `stop`                            | +     |                                                 |
 | `add {uri}`                       | `add {uri}`                       | +     |                                                 |
 | `addid {id} [pos]`                | `addid {id...}`                   | ~     | can add multiple songs, but no position support |
diff --git a/inc/lektor/commands.h b/inc/lektor/commands.h
index bae6beeb64f2f5dec74a45dedd77c348ae32e634..0eb603cbb73672f7f0df08699762f79ea6b82ff1 100644
--- a/inc/lektor/commands.h
+++ b/inc/lektor/commands.h
@@ -27,6 +27,10 @@ bool command_play    (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
 bool command_playid  (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
 bool command_stop    (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
 
+bool command_seek    (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_seekid  (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_seekcur (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+
 bool command_set_pos(struct lkt_state *srv, int index); /* FIXME: Not used in net/listen.c */
 
 /* The queue */
diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index e57b4aba87cea06737e1a34178067597020368c0..61bea9e27167ce20dbfa65f886daf334144a8978 100644
--- a/inc/lektor/database.h
+++ b/inc/lektor/database.h
@@ -46,7 +46,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]);
+bool database_get_kara_path    (volatile sqlite3 *db, int id, char filepath[PATH_MAX]);
+bool database_get_kara_position(volatile sqlite3 *db, int id, int *pos);
 
 /* Update the database. */
 bool database_update              (volatile sqlite3 *db, const char *kara_dir, int check_timestamp);
diff --git a/src/base/commands.c b/src/base/commands.c
index ca8b9208bacf2ffed79649aa7ad522972d20fa54..049afeb3785b8f371ce0352e13215c45c2a333c3 100644
--- a/src/base/commands.c
+++ b/src/base/commands.c
@@ -694,6 +694,59 @@ command_set_pos(struct lkt_state *srv, int index)
     return ! MOD_CALL(srv->window_mod, "load", filepath);
 }
 
+bool
+command_seek(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
+{
+    int pos, seconds, err_flag;
+    char *endptr;
+    RETURN_UNLESS(args && args[0] && args[1], "Invalid arguments", false);
+
+    STRTOL(pos, args[0], endptr, err_flag);
+    RETURN_IF(err_flag, "Failed to get a number!", false);
+
+    STRTOL(seconds, args[1], endptr, err_flag);
+    RETURN_IF(err_flag, "Failed to get a number!", false);
+
+    RETURN_UNLESS(command_set_pos(srv, pos), "Failed to get to the right file", false);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    return ! MOD_CALL(srv->window_mod, "set_position", seconds);
+}
+
+bool
+command_seekid(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
+{
+    int id, seconds, err_flag, position;
+    char *endptr;
+    RETURN_UNLESS(args && args[0] && args[1], "Invalid arguments", false);
+
+    STRTOL(id, args[0], endptr, err_flag);
+    RETURN_IF(err_flag, "Failed to get a number!", false);
+
+    STRTOL(seconds, args[1], endptr, err_flag);
+    RETURN_IF(err_flag, "Failed to get a number!", false);
+
+    RETURN_UNLESS(database_get_kara_position(srv->db, id, &position),
+                  "Can't find kara in queue", false);
+
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    RETURN_UNLESS(command_set_pos(srv, position), "Failed to set position to right kara", false);
+    return ! MOD_CALL(srv->window_mod, "set_position", seconds);
+}
+
+bool
+command_seekcur(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
+{
+    int seconds, err_flag;
+    char *endptr;
+    RETURN_UNLESS(args && args[0], "Invalid arguments", false);
+
+    STRTOL(seconds, args[0], endptr, err_flag);
+    RETURN_IF(err_flag, "Failed to get a number!", false);
+
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    return ! MOD_CALL(srv->window_mod, "set_position", seconds);
+}
+
 bool
 command_plt_add(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
diff --git a/src/database/queue.c b/src/database/queue.c
index 6ef69d50de2cbb7d9064b88b00ee9d3e5ce38070..635c36445f4b5ea91c270d454509eba306ed75ff 100644
--- a/src/database/queue.c
+++ b/src/database/queue.c
@@ -85,8 +85,7 @@ error:
 }
 
 bool
-database_queue_current_kara(volatile sqlite3 *db, struct kara_metadata *res,
-                            int *id)
+database_queue_current_kara(volatile sqlite3 *db, struct kara_metadata *res, int *id)
 {
     static const char *SQL_STMT =
         "SELECT song_name, source_name, category, language, author_name, "
@@ -668,6 +667,27 @@ error:
     return false;
 }
 
+bool
+database_get_kara_position(volatile sqlite3 *db, int id, int *pos)
+{
+    sqlite3_stmt *stmt = NULL;
+    static const char *SQL =
+        "WITH content AS ("
+        " SELECT kara.id AS id, position"
+        "  FROM queue"
+        "  JOIN kara ON kara_id = kara.id"
+        "  GROUP BY position ORDER BY position ASC, priority DESC)"
+        "SELECT id, position FROM content WHERE id = ?;";
+    RETURN_UNLESS(db && pos, "Invalid argument", false);
+    SQLITE_PREPARE(db, stmt, SQL, error);
+    SQLITE_BIND_INT(db, stmt, 1, id, error);
+    SQLITE_STEP_ROW(db, stmt, error);
+    *pos = sqlite3_column_int(stmt, 0);
+    return true;
+error:
+    return false;
+}
+
 bool
 database_queue_shuffle(volatile sqlite3 *db)
 {
diff --git a/src/module/module_sdl2.c b/src/module/module_sdl2.c
index f1169076ca379176c745aa74de3c41c8abc5a52f..67418b9aa5b7397673f1ec022eb73b2bc58d7622 100644
--- a/src/module/module_sdl2.c
+++ b/src/module/module_sdl2.c
@@ -235,6 +235,7 @@ REG_ADD_NAMED("load",         mod_load_file)
 REG_ADD_NAMED("set_volume",   mod_set_volume)
 REG_ADD_NAMED("get_duration", mod_get_duration)
 REG_ADD_NAMED("get_elapsed",  mod_get_elapsed)
+/* Add "set_position" */
 REG_END()
 #if ! defined (LKT_STATIC_MODULE)
     REG_EXPORT(sdl2_reg)
diff --git a/src/net/listen.c b/src/net/listen.c
index cffd0fe0d0fa793b11d832349a8b0c1e0e128b2d..bd2b98112bac6aec052d8045bcb68a55448a76ea 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -204,6 +204,13 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
         else if (STR_MATCH(cmd.name, "shuffle"))
             err = ! command_shuffle(srv, NULL);
 
+        else if (STR_MATCH(cmd.name, "seek"))
+            err = ! command_seek(srv, cmd.args);
+        else if (STR_MATCH(cmd.name, "seekid"))
+            err = ! command_seekid(srv, cmd.args);
+        else if (STR_MATCH(cmd.name, "seekcur"))
+            err = ! command_seekcur(srv, cmd.args);
+
         else if (STR_MATCH(cmd.name, "playlist") || STR_MATCH(cmd.name, "playlistinfo"))
             err = ! command_queue_list(srv, c, cmd.args);
         else if (STR_MATCH(cmd.name, "playlistfind") || STR_MATCH(cmd.name, "playlistsearch"))