diff --git a/inc/lektor/commands.h b/inc/lektor/commands.h
index aa6681bc32d12049d1f5bfc554ff7fa911c442a2..ab48132758365411a28c778ee3cff022510c7f3b 100644
--- a/inc/lektor/commands.h
+++ b/inc/lektor/commands.h
@@ -101,6 +101,12 @@ typedef enum {
     LKT_PLAYBACK_OPTION_VOLUME,
 } LKT_PLAYBACK_OPTION;
 
+/* Other search commands */
+bool command_kara_info(struct lkt_state *srv, size_t, char *[LKT_MESSAGE_ARGS_MAX], int cont);
+bool command_kara_tags(struct lkt_state *srv, size_t, char *[LKT_MESSAGE_ARGS_MAX], int cont);
+bool command_kara_infotags(struct lkt_state *srv, size_t, char *[LKT_MESSAGE_ARGS_MAX], int cont);
+
+/* Playback commands */
 bool command_set_playback_option(struct lkt_state *, size_t, LKT_PLAYBACK_OPTION, char *[LKT_MESSAGE_ARGS_MAX]);
 
 PRIVATE_FUNCTION bool
diff --git a/inc/lektor/internal/commands.def b/inc/lektor/internal/commands.def
index 6828306de22e5e51cac8e59cfb41bf3e40284685..0594fa986e1025993edd8a94e97f06999723a2e1 100644
--- a/inc/lektor/internal/commands.def
+++ b/inc/lektor/internal/commands.def
@@ -28,6 +28,10 @@ mpd_command("swap",              command_swap)
 mpd_command("swapid",            command_swapid)
 mpd_command("__flat",            command_flat)
 
+mpd_command("__getinfo",         command_kara_info)
+mpd_command("__gettags",         command_kara_tags)
+mpd_command("readcomments",      command_kara_infotags)
+
 mpd_command("playlistid",        command_queue_listid)
 mpd_command("playlist",          command_queue_list)
 mpd_command("playlistinfo",      command_queue_list)
diff --git a/inc/liblektor-rs/database.h b/inc/liblektor-rs/database.h
index 23bab61ffc3d11dd96644f61aaa175106e6d540b..34b6ffd59d34f5016b4b520268ea0d7d79e4ae42 100644
--- a/inc/liblektor-rs/database.h
+++ b/inc/liblektor-rs/database.h
@@ -10,11 +10,22 @@ extern "C" {
 struct lkt_sqlite_connection;
 typedef struct lkt_sqlite_connection lkt_sqlite_connection;
 
+/* The callback called on every information when calling the
+ * `lkt_database_get_kara_{info,tag}` functions. The first argument is the name
+ * of the info/tag, the second is the text representation of such tag/info. The
+ * last parameter of the function is a `void*` passed by the user to the parent
+ * function. The function can't fail.
+ */
+typedef void (*lkt_info_cb)(const char *, const char *, void *restrict);
+
 lkt_sqlite_connection *lkt_database_establish_connection(const char *);
-void lkt_database_close_connection(lkt_sqlite_connection *const);
+void lkt_database_close_connection(lkt_sqlite_connection *);
+
+bool lkt_database_delete_kara_by_repo(lkt_sqlite_connection *, int64_t, int64_t);
+bool lkt_database_delete_kara_by_local_id(lkt_sqlite_connection *, int64_t);
 
-bool lkt_database_delete_kara_by_repo(lkt_sqlite_connection *const, int64_t, int64_t);
-bool lkt_database_delete_kara_by_local_id(lkt_sqlite_connection *const, int64_t);
+bool lkt_database_get_kara_info(lkt_sqlite_connection *, int64_t, lkt_info_cb, void *restrict);
+bool lkt_database_get_kara_tags(lkt_sqlite_connection *, int64_t, lkt_info_cb, void *restrict);
 
 #if defined(__cplusplus)
 }
diff --git a/src/.vscode/settings.json b/src/.vscode/settings.json
index 1106b5acd293c929a3aa0f1016f3a2754bc106bf..96d2140d5d00fb4f8a21c32a47e8be69c798088a 100644
--- a/src/.vscode/settings.json
+++ b/src/.vscode/settings.json
@@ -1,5 +1,6 @@
 {
     "files.exclude": {
         "**/rust": true,
+        "rust": true,
     },
-}
\ No newline at end of file
+}
diff --git a/src/base/commands.c b/src/base/commands.c
index 54ac40dd9935427e1155d81a08b133303e4f2bf4..7cad7dbcfc98a83f79d1ec6075d67ebb6482e41f 100644
--- a/src/base/commands.c
+++ b/src/base/commands.c
@@ -779,6 +779,36 @@ command_find(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_MAX],
     return ret;
 }
 
+/* Constate for base continuations regarding tags in the `command_kara_infotags`
+ * function. Below that limit, continuation will be for info, above (ge) the
+ * continuation will be for tags. This limits informations to `UINT64_MAX / 2`
+ * the number of informations for a kara, this limit should be fine.
+ */
+static const int64_t BASE_TAGS_CONTINUATION = UINT64_MAX / 2;
+
+bool
+command_kara_info(struct lkt_state UNUSED *srv, size_t UNUSED c,
+                  char UNUSED *args[LKT_MESSAGE_ARGS_MAX], int UNUSED cont)
+{
+    LOG_ERROR("COMMAND", "The command kara info is not implemented for now");
+    return false;
+}
+
+bool
+command_kara_tags(struct lkt_state UNUSED *srv, size_t UNUSED c,
+                  char UNUSED *args[LKT_MESSAGE_ARGS_MAX], int UNUSED cont)
+{
+    LOG_ERROR("COMMAND", "The command kara tags is not implemented for now");
+    return false;
+}
+
+bool
+command_kara_infotags(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_MAX], int cont)
+{
+    LOG_ERROR("COMMAND", "The command kara infotags is not implemented for now");
+    return false;
+}
+
 bool
 command_plt_list(struct lkt_state *srv, size_t c, char UNUSED *args[LKT_MESSAGE_ARGS_MAX], int cont)
 {
diff --git a/src/rust/liblektor-rs/lektor_c_compat/src/c_types.rs b/src/rust/liblektor-rs/lektor_c_compat/src/c_types.rs
index 8e49a097b9d0d5d0c79aaa8397424d9744e5cba3..1aac3ddf18f4bc8f8aad07397ec2a09085ed2bd8 100644
--- a/src/rust/liblektor-rs/lektor_c_compat/src/c_types.rs
+++ b/src/rust/liblektor-rs/lektor_c_compat/src/c_types.rs
@@ -156,7 +156,6 @@ extern "C" {
     pub(crate) fn lkt_uri_get_value_as_str(_: LktUriPtr) -> *const c_char;
     pub(crate) fn lkt_uri_get_value_as_int(_: LktUriPtr) -> c_int;
     pub(crate) fn lkt_uri_get_value_type(_: LktUriPtr) -> LktUriValueType;
-    pub(crate) fn lkt_uri_get_column_name(_: LktUriPtr) -> *const c_char;
 }
 
 extern "C" {
diff --git a/src/rust/liblektor-rs/lektor_c_compat/src/rs_types/uri.rs b/src/rust/liblektor-rs/lektor_c_compat/src/rs_types/uri.rs
index e8184010730e6be879d828afb98d345d81939786..d58c370c2bf216e895d52e615f6d9ef2a9ed0592 100644
--- a/src/rust/liblektor-rs/lektor_c_compat/src/rs_types/uri.rs
+++ b/src/rust/liblektor-rs/lektor_c_compat/src/rs_types/uri.rs
@@ -16,12 +16,6 @@ pub enum LktUriField {
     /// The origin of the kara must match the URI.
     Origin,
 
-    /// The title of the kara must match the query.
-    Title,
-
-    /// The source of the kara must match the query.
-    Source,
-
     /// The type of the kara must match the query.
     Type,
 
@@ -31,6 +25,16 @@ pub enum LktUriField {
     /// Do a fuzzy search with the value if the URI. This is the default action
     /// for an URI.
     FuzzySearch,
+
+    /// Do a search by the name of the playlist.
+    Playlist,
+}
+
+/// The value of an URI, can be a string or an integer.
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum LktUriValue<'a> {
+    String(&'a str),
+    Integer(i32),
 }
 
 impl Default for LktUriField {
@@ -46,8 +50,18 @@ impl From<LktUriPtr> for LktCUri {
 }
 
 impl LktCUri {
-    pub fn get_type(&self) -> LktUriType {
-        unsafe { lkt_uri_get_type(self.ptr) }
+    pub fn get_type(&self) -> Option<LktUriField> {
+        use LktUriField::*;
+        match unsafe { lkt_uri_get_type(self.ptr) } {
+            LktUriType::Null => None,
+            LktUriType::Id => Some(Id),
+            LktUriType::Playlist => Some(Playlist),
+            LktUriType::Type => Some(Type),
+            LktUriType::Author => Some(KaraMaker),
+            LktUriType::Category => Some(Origin),
+            LktUriType::Lanquage => Some(Language),
+            LktUriType::Query => Some(FuzzySearch),
+        }
     }
 
     pub fn get_value_type(&self) -> LktUriValueType {
@@ -76,21 +90,11 @@ impl LktCUri {
         }
     }
 
-    /// Get the field that query the uri. See the `inc/lektor/common.h`,
-    /// `LKT_DB_*` defines. If those defines change, the implementation of this
-    /// function must also change.
-    pub fn get_query_field(&self) -> Option<LktUriField> {
-        use LktUriField::*;
-        match unsafe { ptr_to_str(lkt_uri_get_column_name(self.ptr)) } {
-            "id" => Some(Id),
-            "source_name" => Some(Source),
-            "song_title" => Some(Title),
-            "category" => Some(Origin),
-            "song_type" => Some(Type),
-            "author_name" => Some(KaraMaker),
-            "language" => Some(Language),
-            "string" => Some(FuzzySearch),
-            _ => None,
+    pub fn get_value(&self) -> Option<LktUriValue> {
+        match self.get_value_type() {
+            LktUriValueType::Null => None,
+            LktUriValueType::String => self.get_value_as_str().map(LktUriValue::String),
+            LktUriValueType::Integer => self.get_value_as_int().map(LktUriValue::Integer),
         }
     }
 }
diff --git a/src/rust/liblektor-rs/lektor_db/Cargo.toml b/src/rust/liblektor-rs/lektor_db/Cargo.toml
index 5410dc3a4246390205c36a68108da7601e74cadf..6016644038606c3d8415dd7536ab61b8c8d736ee 100644
--- a/src/rust/liblektor-rs/lektor_db/Cargo.toml
+++ b/src/rust/liblektor-rs/lektor_db/Cargo.toml
@@ -13,3 +13,4 @@ diesel_migrations = "2"
 diesel = { version = "2", default-features = false, features = ["sqlite"] }
 
 kurisu_api = { path = "../kurisu_api" }
+lektor_c_compat = { path = "../lektor_c_compat" }
diff --git a/src/rust/liblektor-rs/lektor_db/src/connexion.rs b/src/rust/liblektor-rs/lektor_db/src/connexion.rs
index 75907ae3ebe8f507b593886cd389cf2b4de05ed9..493584ebb0d8d8d9c4f20c12007c65dcb047f501 100644
--- a/src/rust/liblektor-rs/lektor_db/src/connexion.rs
+++ b/src/rust/liblektor-rs/lektor_db/src/connexion.rs
@@ -4,6 +4,7 @@ use crate::{
     *,
 };
 use kurisu_api::v1 as api_v1;
+use lektor_c_compat::rs::LktCUri;
 
 /// Create a connexion to a database and run automatically the migrations.
 fn establish_connection(path: impl AsRef<str>) -> Result<SqliteConnection, String> {
@@ -21,6 +22,50 @@ pub struct LktDatabaseConnection {
     queue: queue::LktDatabaseQueue,
 }
 
+/// Get the value of a [LktCUri] and returns Err(String) in case of invalid
+/// value.
+macro_rules! uri_val {
+    ($uri: literal :/ $expr: expr) => {
+        $expr
+            .get_value()
+            .ok_or_else(|| format!("the value of the {}:// uri is invalid", $uri))?
+    };
+
+    ($expr: expr) => {
+        $expr
+            .get_value()
+            .ok_or_else(|| format!("the value of the uri is invalid"))?
+    };
+}
+
+/// Do the same thing as [uri_val], but we ensure that the value is a string and
+/// then return such string.
+macro_rules! uri_str {
+    ($what: literal :/ $uri: expr) => {{
+        let LktUriValue::String(str) = uri_val!($what :/ $uri) else {
+            return Err(format!("try to pass integer `{}` as {} in uri", String::from($uri), $what))
+        };
+        str
+    }};
+}
+
+/// Do the same thing as [uri_val], but we ensure that the value is an integer
+/// and then return integer. If the value is a string, we try to convert it into
+/// an integer.
+macro_rules! uri_as_int {
+    ($what: literal :/ $uri: expr) => {
+        match uri_val!($what :/ $uri) {
+            LktUriValue::Integer(int) => int,
+            LktUriValue::String(str) => {
+                let str = str.parse::<u64>().map_err(|err| {
+                    format!("the {} `{str}` is not a correct integer: {err}", $what)
+                })?;
+                i32::try_from(str).map_err(|err| format!("the {} `{str}` {err}", $what))?
+            }
+        }
+    };
+}
+
 /// Load the diesel DSL for a given table. With the loaded dsl execute the
 /// expression...
 macro_rules! with_dsl {
@@ -48,7 +93,7 @@ impl LktDatabaseConnection {
     }
 
     /// Get a tag id by its name.
-    pub fn get_tag_id_by_name(&mut self, tag_name: impl AsRef<str>) -> LktDatabaseResult<i32> {
+    fn get_tag_id_by_name(&mut self, tag_name: impl AsRef<str>) -> LktDatabaseResult<i32> {
         Ok(with_dsl!(tag => tag.filter(name.is(tag_name.as_ref()))
             .first::<Tag>(&mut self.sqlite)?.id
         ))
@@ -201,4 +246,81 @@ impl LktDatabaseConnection {
     pub fn insert_kara_with_priority(&mut self, local_id: u64, priority: LktDatabasePriority) {
         self.queue.insert_kara_with_priority(local_id, priority)
     }
+
+    /// Search karas by URIs. We returns the local ids.
+    pub fn search(&mut self, uri: LktCUri) -> Result<Vec<i32>, String> {
+        use lektor_c_compat::rs::{LktUriField, LktUriValue};
+        let uri_type = uri
+            .get_type()
+            .ok_or_else(|| "passed an URI which has no valid type...".to_string())?;
+
+        match uri_type {
+            LktUriField::Id => Ok(vec![with_dsl!(kara => kara
+                .filter(id.is(uri_as_int!("id" :/ uri)))
+                .select(id)
+                .first::<i32>(&mut self.sqlite)
+                .map_err(|err| format!("{err}"))?
+            )]),
+
+            LktUriField::KaraMaker => Ok(with_dsl!(kara_makers => kara_makers
+                .filter(name.like(uri_str!("author" :/ uri)))
+                .inner_join(with_dsl!(kara => kara))
+                .select(id)
+                .load::<i32>(&mut self.sqlite)
+                .map_err(|err| format!("{err}"))?
+            )),
+
+            LktUriField::Origin => Ok(with_dsl!(kara => kara
+                .filter(song_origin.like(uri_str!("origin" :/ uri)))
+                .select(id).load::<i32>(&mut self.sqlite)
+                .map_err(|err| format!("{err}"))?
+            )),
+
+            LktUriField::Type => Ok(with_dsl!(kara => kara
+                .filter(song_type.is(uri_str!("type" :/ uri)))
+                .select(id).load::<i32>(&mut self.sqlite)
+                .map_err(|err| format!("{err}"))?
+            )),
+
+            LktUriField::Language => Ok(with_dsl!(kara_langs => kara_langs
+                .filter(code.like(uri_str!("language" :/ uri)))
+                .inner_join(with_dsl!(kara => kara))
+                .select(id)
+                .load::<i32>(&mut self.sqlite)
+                .map_err(|err| format!("{err}"))?
+            )),
+
+            LktUriField::FuzzySearch => {
+                let _ = uri_str!("query" :/ uri);
+                todo!()
+            }
+
+            LktUriField::Playlist => {
+                let _ = uri_str!("playlist" :/ uri);
+                todo!()
+            }
+        }
+    }
+
+    /// Get all infos about a kara, its metadata, its tags, repo, repo id,
+    /// languages, karamakers...
+    pub fn get_info(&mut self, local_id: u64) -> Result<(), String> {
+        let local_id = i32::try_from(local_id)
+            .map_err(|err| format!("the id {local_id} is too big to be an i32: {err}"))?;
+        let _repo: String = with_dsl!(repo_kara => repo_kara
+            .filter(local_kara_id.is(local_id))
+            .inner_join(with_dsl!(repo => repo.on(id.is(repo_id))))
+            .select(schema::repo::name)
+            .first::<String>(&mut self.sqlite)
+            .map_err(|err| format!("failed to get parent repo of kara {local_id}: {err}"))?
+        );
+        let _kara_makers: Vec<String> = with_dsl!(kara => kara
+            .filter(id.is(local_id))
+            .inner_join(schema::kara_makers::table)
+            .select(schema::kara_makers::name)
+            .load::<String>(&mut self.sqlite)
+            .map_err(|err| format!("failed to get makers for kara {local_id}: {err}"))?
+        );
+        todo!()
+    }
 }
diff --git a/src/rust/liblektor-rs/lektor_db/src/models.rs b/src/rust/liblektor-rs/lektor_db/src/models.rs
index 60940e027310bf9858fd64f62fabfefe7c7e57fd..9cbf5321b415bbf74946b222bb83e470278981fd 100644
--- a/src/rust/liblektor-rs/lektor_db/src/models.rs
+++ b/src/rust/liblektor-rs/lektor_db/src/models.rs
@@ -81,3 +81,15 @@ pub struct Tag {
     pub id: i32,
     pub name: String,
 }
+
+#[derive(Queryable, Selectable)]
+#[diesel(table_name = kara)]
+pub struct Kara {
+    pub id: i32,
+    pub is_dl: bool,
+    pub song_title: String,
+    pub song_type: String,
+    pub song_origin: String,
+    pub source_name: String,
+    pub file_hash: String,
+}
diff --git a/src/rust/liblektor-rs/lektor_unsafe/src/db.rs b/src/rust/liblektor-rs/lektor_unsafe/src/db.rs
index bc2e8f7ac685da4abf9ed3f922d9b7dc73352430..2468c6b55b5aa3a38dea03a2bff10032c4139a8f 100644
--- a/src/rust/liblektor-rs/lektor_unsafe/src/db.rs
+++ b/src/rust/liblektor-rs/lektor_unsafe/src/db.rs
@@ -82,3 +82,31 @@ pub unsafe extern "C" fn lkt_database_delete_kara_by_local_id(
         .map_err(|err| error!(target: "DB", "delete_kara_by_local_id failed: {err}"))
         .is_ok()
 }
+
+/// Get the related informations to a kara and call the `cb` for each one.
+/// ### Safety
+/// The passed db pointer must be created by
+/// [`lkt_database_establish_connection`].
+#[no_mangle]
+pub unsafe extern "C" fn lkt_database_get_kara_info(
+    db: *mut LktDatabaseConnection,
+    local_id: u64,
+    cb: extern "C" fn(*const c_char, *const c_char, *mut c_void),
+    user: *mut c_void,
+) -> bool {
+    unimplemented!()
+}
+
+/// Get the related tags to a kara and call the `cb` for each one.
+/// ### Safety
+/// The passed db pointer must be created by
+/// [`lkt_database_establish_connection`].
+#[no_mangle]
+pub unsafe extern "C" fn lkt_database_get_kara_tags(
+    db: *mut LktDatabaseConnection,
+    local_id: u64,
+    cb: extern "C" fn(*const c_char, *const c_char, *mut c_void),
+    user: *mut c_void,
+) -> bool {
+    unimplemented!()
+}