diff --git a/Cargo.lock b/Cargo.lock
index 53cd97a6a076b49c42f90ac06121ca10aeab9d0b..8d1356eca2abf569994bc6055c3b8c060ab42215 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3258,6 +3258,7 @@ dependencies = [
  "anyhow",
  "axum",
  "clap",
+ "derive_more",
  "futures",
  "hashbrown 0.15.1",
  "hyper",
diff --git a/lektor_mpris/src/server.rs b/lektor_mpris/src/server.rs
index 42e35123d30f72ed5e8a54c2b16a72cf3a654d3b..b98e5599c4caa072dcfc2600053713c0753711b6 100644
--- a/lektor_mpris/src/server.rs
+++ b/lektor_mpris/src/server.rs
@@ -2,18 +2,24 @@
 //! `org.mpris.MediaPlayer2.TrackList`
 
 use crate::{types::*, AsMpris};
-use zbus::{connection, object_server::SignalEmitter, Connection};
+use zbus::{
+    connection,
+    object_server::{InterfaceRef, SignalEmitter},
+    Connection,
+};
 
 /// The adapter for MPRIS.
 #[derive(Debug)]
-pub struct MPRISAdapter<T: AsMpris + Send + Sync + Clone + 'static>(Connection, T);
+pub struct MPRISAdapter<T: AsMpris + Send + Sync + Clone + 'static> {
+    connection: Connection,
+    application: T,
+}
 
 /// Builder used to configure and create the adapter.
 pub struct MPRISBuilder<T: AsMpris + Send + Sync + Clone + 'static> {
     application: T,
     identity: String,
-    desktop_entry: Option<String>,
-    is_unique: bool,
+    desk_entry: Option<String>,
 }
 
 impl<T: AsMpris + Send + Sync + Clone + 'static> MPRISAdapter<T> {
@@ -22,54 +28,105 @@ impl<T: AsMpris + Send + Sync + Clone + 'static> MPRISAdapter<T> {
         MPRISBuilder {
             application,
             identity: identity.as_ref().into(),
-            desktop_entry: None,
-            is_unique: false,
+            desk_entry: None,
         }
     }
+
+    /// Get the application that is wrapped inside the [MPRISAdapter].
+    pub fn application(&self) -> &T {
+        &self.application
+    }
+
+    /// Get the [TrackList] server object, to emit some signals with it.
+    async fn object_track_list(&self) -> zbus::Result<InterfaceRef<TrackList<T>>> {
+        self.connection
+            .object_server()
+            .interface::<&str, TrackList<T>>("org.mpris.MediaPlayer2.TrackList")
+            .await
+    }
+
+    /// TrackAdded signal
+    pub async fn signal_track_added(
+        &self,
+        metadata: impl Into<TrackMetadata>,
+        after: ObjectPath,
+    ) -> zbus::Result<()> {
+        self.object_track_list()
+            .await?
+            .track_added(metadata.into(), after)
+            .await
+    }
+
+    /// TrackListReplaced signal
+    pub async fn signal_track_list_replaced(
+        &self,
+        tracks: impl IntoIterator<Item = ObjectPath>,
+        current: ObjectPath,
+    ) -> zbus::Result<()> {
+        self.object_track_list()
+            .await?
+            .track_list_replaced(tracks.into_iter().collect(), current)
+            .await
+    }
+
+    /// TrackMetadataChanged signal
+    pub async fn signal_track_metadata_changed(
+        &self,
+        track_id: ObjectPath,
+        metadata: impl Into<TrackMetadata>,
+    ) -> zbus::Result<()> {
+        self.object_track_list()
+            .await?
+            .track_metadata_changed(track_id, metadata.into())
+            .await
+    }
+
+    /// TrackRemoved signal
+    pub async fn signal_track_removed(&self, track_id: ObjectPath) -> zbus::Result<()> {
+        self.object_track_list()
+            .await?
+            .track_removed(track_id)
+            .await
+    }
 }
 
 impl<T: AsMpris + Send + Sync + Clone + 'static> MPRISBuilder<T> {
     /// Name of the application (Lektord, Amadeus, etc)
-    pub fn desktop_entry(mut self, desktop_entry: impl AsRef<str>) -> Self {
-        self.desktop_entry = Some(desktop_entry.as_ref().into());
-        self
+    pub fn desktop_entry(self, desktop_entry: impl AsRef<str>) -> Self {
+        Self {
+            desk_entry: Some(desktop_entry.as_ref().into()),
+            ..self
+        }
     }
 
-    /// Should we be unique?
-    /// - Lektord should be a unique instance.
-    /// - It makes sens for Amadeus to not be unique, so we must call this function to make each
-    ///   mpris server unique.
-    pub fn unique(mut self) -> Self {
-        self.is_unique = true;
-        self
+    /// Get the DBus name. We can't have multiple Lektord or Amadeus instances.
+    fn get_name(&self) -> String {
+        format!("org.mpris.MediaPlayer2.{}", self.identity)
     }
 
     /// Try to build the DBus server.
     pub async fn try_build(self) -> zbus::Result<MPRISAdapter<T>> {
-        let name = format!(
-            "org.mpris.MediaPlayer2.{}{}",
-            self.identity,
-            self.is_unique
-                .then_some(format!("-{}", std::process::id()))
-                .unwrap_or_default()
-        );
-        let obj_main = Main {
-            desktop_entry: self.desktop_entry.unwrap_or_else(|| self.identity.clone()),
-            identity: self.identity,
-        };
-        let obj_player = Player(self.application.clone());
-        let obj_tracks = TrackList(self.application.clone());
+        let name = self.get_name();
+        let Self {
+            application,
+            identity,
+            desk_entry,
+        } = self;
 
         log::info!("try to create new dbus connection for: {name}");
+
         let connection = connection::Builder::session()?
             .name(name)?
-            .serve_at("/org/mpris/MediaPlayer2", obj_main)?
-            .serve_at("/org/mpris/MediaPlayer2", obj_player)?
-            .serve_at("/org/mpris/MediaPlayer2", obj_tracks)?
+            .serve_at("/org/mpris/MediaPlayer2", Main::new(identity, desk_entry))?
+            .serve_at("/org/mpris/MediaPlayer2", Player(application.clone()))?
+            .serve_at("/org/mpris/MediaPlayer2", TrackList(application.clone()))?
             .build()
             .await?;
 
-        Ok(MPRISAdapter(connection, self.application))
+        Ok(MPRISAdapter {
+            connection,
+            application,
+        })
     }
 }
 
@@ -80,6 +137,15 @@ struct Main {
     desktop_entry: String,
 }
 
+impl Main {
+    fn new(identity: String, desktop_entry: Option<String>) -> Self {
+        Self {
+            desktop_entry: desktop_entry.unwrap_or_else(|| identity.clone()),
+            identity,
+        }
+    }
+}
+
 #[zbus::interface(name = "org.mpris.MediaPlayer2")]
 impl Main {
     /// Quit method
@@ -153,57 +219,64 @@ impl Main {
 impl<T: AsMpris + Send + Sync + Clone + 'static> Player<T> {
     /// Next method
     #[zbus(name = "Next")]
-    fn next(&self) {
-        self.0.play_next()
+    async fn next(&self) {
+        self.0.play_next().await
     }
 
     /// Pause method
     #[zbus(name = "Pause")]
-    fn pause(&self) {
-        self.0.set_playback_status(PlaybackStatus::Paused.into())
+    async fn pause(&self) {
+        self.0
+            .set_playback_status(PlaybackStatus::Paused.into())
+            .await
     }
 
     /// Play method
     #[zbus(name = "Play")]
-    fn play(&self) {
-        self.0.set_playback_status(PlaybackStatus::Playing.into())
+    async fn play(&self) {
+        self.0
+            .set_playback_status(PlaybackStatus::Playing.into())
+            .await
     }
 
     /// OpenUri method
     #[zbus(name = "OpenUri")]
-    fn open_uri(&self, uri: &str) {
-        self.0.play_file(uri)
+    async fn open_uri(&self, uri: &str) {
+        self.0.play_file(uri).await
     }
 
     /// Toggle play pause status.
     #[zbus(name = "PlayPause")]
-    fn play_pause(&self) {
-        self.0.toggle_playback_status()
+    async fn play_pause(&self) {
+        self.0.toggle_playback_status().await
     }
 
     /// Previous method
     #[zbus(name = "Previous")]
-    fn previous(&self) {
-        self.0.play_previous()
+    async fn previous(&self) {
+        self.0.play_previous().await
     }
 
     /// Seek method
     #[zbus(name = "Seek")]
-    fn seek(&self, offset: TimeMicroSec) {
-        let position = self.0.position().into() + offset;
-        self.0.seek(None, position.into());
+    async fn seek(&self, offset: TimeMicroSec) {
+        self.0
+            .seek(None, (self.0.position().await.into() + offset).into())
+            .await;
     }
 
     /// SetPosition method
     #[zbus(name = "SetPosition")]
-    fn set_position(&self, track_id: ObjectPath, position: TimeMicroSec) {
-        self.0.seek(Some(track_id.into()), position.into());
+    async fn set_position(&self, track_id: ObjectPath, position: TimeMicroSec) {
+        self.0.seek(Some(track_id.into()), position.into()).await;
     }
 
     /// Stop method
     #[zbus(name = "Stop")]
-    fn stop(&self) {
-        log::warn!("ignore stop command")
+    async fn stop(&self) {
+        self.0
+            .set_playback_status(PlaybackStatus::Stopped.into())
+            .await
     }
 
     /// CanControl property
@@ -240,51 +313,74 @@ impl<T: AsMpris + Send + Sync + Clone + 'static> Player<T> {
         log::warn!("ignore loop status {loop_status:?}")
     }
 
-    #[rustfmt::skip] #[zbus(property, name = "MaximumRate")]    fn maximum_rate(&self) -> f64 { 1.0 }
-    #[rustfmt::skip] #[zbus(property, name = "MinimumRate")]    fn minimum_rate(&self) -> f64 { 1.0 }
-    #[rustfmt::skip] #[zbus(property, name = "MaximumRate")]    fn set_maximum_rate(&self, rate: f64) { log::warn!("ignore rate {rate}") }
-    #[rustfmt::skip] #[zbus(property, name = "MinimumRate")]    fn set_minimum_rate(&self, rate: f64) { log::warn!("ignore rate {rate}") }
-    #[rustfmt::skip] #[zbus(property, name = "Rate"       )]    fn rate(&self) -> f64 { 1.0 }
-    #[rustfmt::skip] #[zbus(property, name = "Rate"       )]    fn set_rate(&self, rate: f64) { log::warn!("ignore rate {rate}") }
+    #[zbus(property, name = "MaximumRate")]
+    fn maximum_rate(&self) -> f64 {
+        1.0
+    }
+
+    #[zbus(property, name = "MinimumRate")]
+    fn minimum_rate(&self) -> f64 {
+        1.0
+    }
+
+    #[zbus(property, name = "MaximumRate")]
+    fn set_maximum_rate(&self, rate: f64) {
+        log::warn!("ignore rate {rate}")
+    }
+
+    #[zbus(property, name = "MinimumRate")]
+    fn set_minimum_rate(&self, rate: f64) {
+        log::warn!("ignore rate {rate}")
+    }
+
+    #[zbus(property, name = "Rate")]
+    fn rate(&self) -> f64 {
+        1.0
+    }
+
+    #[zbus(property, name = "Rate")]
+    fn set_rate(&self, rate: f64) {
+        log::warn!("ignore rate {rate}")
+    }
 
     /// Shuffle property
     #[zbus(property, name = "Shuffle")]
     fn shuffle(&self) -> bool {
-        self.0.shuffle()
+        false
     }
     #[zbus(property, name = "Shuffle")]
     fn set_shuffle(&self, shuffle: bool) {
-        self.0.set_shuffle(shuffle);
+        log::error!("ignore shuffle request to: {shuffle}")
     }
 
     /// Volume property
     #[zbus(property, name = "Volume")]
-    fn volume(&self) -> f64 {
-        self.0.volume()
+    async fn volume(&self) -> f64 {
+        self.0.volume().await
     }
     #[zbus(property, name = "Volume")]
-    fn set_volume(&self, volume: f64) {
-        self.0.set_volume(volume)
+    async fn set_volume(&self, volume: f64) {
+        self.0.set_volume(volume).await
     }
 
     /// PlaybackStatus property
     #[zbus(property, name = "PlaybackStatus")]
-    fn playback_status(&self) -> PlaybackStatus {
-        self.0.get_playback_status().into()
+    async fn playback_status(&self) -> PlaybackStatus {
+        self.0.get_playback_status().await.into()
     }
 
     /// Position property
     #[zbus(property, name = "Position")]
-    fn position(&self) -> TimeMicroSec {
-        self.0.position().into()
+    async fn position(&self) -> TimeMicroSec {
+        self.0.position().await.into()
     }
 
     /// Metadata property. If there is a current kara playing, there must be at
     /// least a `mpris:trackid` value of type `o` which is the object path of
     /// the current kara id.
     #[zbus(property, name = "Metadata")]
-    fn metadata(&self) -> TrackMetadata {
-        self.0.get_current_metadata().into()
+    async fn metadata(&self) -> TrackMetadata {
+        self.0.get_current_metadata().await.into()
     }
 }
 
@@ -292,16 +388,16 @@ impl<T: AsMpris + Send + Sync + Clone + 'static> Player<T> {
 impl<T: AsMpris + Send + Sync + Clone + 'static> TrackList<T> {
     /// AddTrack method
     #[zbus(name = "AddTrack")]
-    fn add_track(&self, uri: &str, after: ObjectPath, set_as_current: bool) {
-        self.0.add_track(uri, after.into(), set_as_current)
+    async fn add_track(&self, uri: &str, after: ObjectPath, set_as_current: bool) {
+        self.0.add_track(uri, after.into(), set_as_current).await
     }
 
     /// GetTracksMetadata method
     #[zbus(name = "GetTracksMetadata")]
-    fn get_tracks_metadata(&self, tracks_ids: Vec<ObjectPath>) -> Vec<TrackMetadata> {
-        let tracks = tracks_ids.into_iter().map(From::from).collect();
+    async fn get_tracks_metadata(&self, tracks_ids: Vec<ObjectPath>) -> Vec<TrackMetadata> {
         self.0
-            .get_tracks_metadata(tracks)
+            .get_tracks_metadata(tracks_ids.into_iter().map(From::from).collect())
+            .await
             .into_iter()
             .map(Into::into)
             .collect()
@@ -309,14 +405,14 @@ impl<T: AsMpris + Send + Sync + Clone + 'static> TrackList<T> {
 
     /// GoTo method
     #[zbus(name = "GoTo")]
-    fn go_to(&self, track_id: ObjectPath) {
-        self.0.go_to(track_id.into())
+    async fn go_to(&self, track_id: ObjectPath) {
+        self.0.go_to(track_id.into()).await
     }
 
     /// RemoveTrack method
     #[zbus(name = "RemoveTrack")]
-    fn remove_track(&self, track_id: ObjectPath) {
-        self.0.remove_track(track_id.into())
+    async fn remove_track(&self, track_id: ObjectPath) {
+        self.0.remove_track(track_id.into()).await
     }
 
     /// CanEditTracks property
@@ -327,9 +423,10 @@ impl<T: AsMpris + Send + Sync + Clone + 'static> TrackList<T> {
 
     /// Tracks property
     #[zbus(property, name = "Tracks")]
-    fn tracks(&self) -> Vec<ObjectPath> {
+    async fn tracks(&self) -> Vec<ObjectPath> {
         self.0
             .get_queue_content()
+            .await
             .into_iter()
             .map(Into::into)
             .collect()
diff --git a/lektor_mpris/src/traits.rs b/lektor_mpris/src/traits.rs
index fadd07ceea90208fabd1f79f682988f085d9aea0..5103ac0a96b82fba3a044f22a00296ee5603a73a 100644
--- a/lektor_mpris/src/traits.rs
+++ b/lektor_mpris/src/traits.rs
@@ -1,41 +1,49 @@
-//! TODO: See how we can do for the signals... We may need to fire them at some point.
-
 use crate::types::*;
+use std::future::Future;
 
 /// An application must implement the [AsMpris] trait to be able to be wrapped by the
 /// [crate::server::MPRISAdapter].
-pub trait AsMpris {
-    type Status: From<PlaybackStatus> + Into<PlaybackStatus>;
-    type Time: From<TimeMicroSec> + Into<TimeMicroSec>;
-    type TrackMdt: Into<TrackMetadata>;
-    type Path: From<ObjectPath> + Into<ObjectPath>;
-
-    fn set_playback_status(&self, status: Self::Status);
-    fn get_playback_status(&self) -> Self::Status;
-    fn toggle_playback_status(&self);
-
-    fn play_next(&self);
-    fn play_previous(&self);
-
-    fn seek(&self, file: Option<Self::Path>, position: Self::Time);
-    fn go_to(&self, track_id: Self::Path);
-    fn position(&self) -> Self::Time;
-
-    fn shuffle(&self) -> bool;
-    fn set_shuffle(&self, shuffle: bool);
-
-    fn volume(&self) -> f64 {
-        100.0
+pub trait AsMpris: Send {
+    type Status: From<PlaybackStatus> + Into<PlaybackStatus> + Send + Copy;
+    type Time: From<TimeMicroSec> + Into<TimeMicroSec> + Send + Copy;
+    type TrackMdt: Into<TrackMetadata> + Send;
+    type Path: From<ObjectPath> + Into<ObjectPath> + Send;
+
+    fn get_playback_status(&self) -> impl Future<Output = Self::Status> + Send;
+    fn set_playback_status(&self, status: Self::Status) -> impl Future<Output = ()> + Send;
+    fn toggle_playback_status(&self) -> impl Future<Output = ()> + Send;
+
+    fn play_next(&self) -> impl Future<Output = ()> + Send;
+    fn play_previous(&self) -> impl Future<Output = ()> + Send;
+
+    fn seek(
+        &self,
+        file: Option<Self::Path>,
+        position: Self::Time,
+    ) -> impl Future<Output = ()> + Send;
+    fn go_to(&self, track_id: Self::Path) -> impl Future<Output = ()> + Send;
+    fn position(&self) -> impl Future<Output = Self::Time> + Send;
+
+    fn volume(&self) -> impl Future<Output = f64> + Send {
+        async { 100.0 }
     }
-    fn set_volume(&self, volume: f64) {
-        log::warn!("ignore volume {volume}");
+    fn set_volume(&self, volume: f64) -> impl Future<Output = ()> + Send {
+        async move { log::warn!("ignore volume {volume}") }
     }
 
-    fn get_current_metadata(&self) -> Self::TrackMdt;
-    fn get_tracks_metadata(&self, tracks_ids: Vec<Self::Path>) -> Vec<Self::TrackMdt>;
-    fn get_queue_content(&self) -> Vec<Self::Path>;
-
-    fn add_track(&self, uri: &str, after: Self::Path, set_as_current: bool);
-    fn remove_track(&self, track_id: Self::Path);
-    fn play_file(&self, uri: &str);
+    fn get_current_metadata(&self) -> impl Future<Output = Self::TrackMdt> + Send;
+    fn get_tracks_metadata(
+        &self,
+        tracks_ids: Vec<Self::Path>,
+    ) -> impl Future<Output = Vec<Self::TrackMdt>> + Send;
+    fn get_queue_content(&self) -> impl Future<Output = Vec<Self::Path>> + Send;
+
+    fn add_track(
+        &self,
+        uri: &str,
+        after: Self::Path,
+        set_as_current: bool,
+    ) -> impl Future<Output = ()> + Send;
+    fn remove_track(&self, track_id: Self::Path) -> impl Future<Output = ()> + Send;
+    fn play_file(&self, uri: &str) -> impl Future<Output = ()> + Send;
 }
diff --git a/lektor_mpris/src/types.rs b/lektor_mpris/src/types.rs
index cf268909bdb7120fbcf52e9e0b3277d273a427ff..5c60bb5b3821df96ad6f2bcdf407951d1a96e084 100644
--- a/lektor_mpris/src/types.rs
+++ b/lektor_mpris/src/types.rs
@@ -38,7 +38,7 @@ impl std::ops::Add for TimeMicroSec {
 }
 
 /// The metadata of a track. We will need to convert a kara from nkdb into this type.
-#[derive(Debug, Serialize, Deserialize, ZType, Clone, PartialEq, Eq)]
+#[derive(Debug, Serialize, Deserialize, ZType, Clone, PartialEq, Eq, Default)]
 #[zvariant(signature = "a{sv}")]
 pub struct TrackMetadata(HashMap<String, String>);
 
@@ -119,6 +119,7 @@ impl From<ZValue<'_>> for PlaybackStatus {
 
 impl From<ZValue<'_>> for ObjectPath {
     fn from(value: ZValue<'_>) -> Self {
+        log::error!("we may want to replace the lektor by amadeus here...");
         let value: ZObjectPath = value.try_into().unwrap_or_default();
         let value = value.trim_start_matches('/');
         match value.split('/').collect::<Vec<_>>()[..] {
@@ -138,6 +139,7 @@ impl From<ZValue<'_>> for ObjectPath {
 
 impl From<ObjectPath> for ZValue<'_> {
     fn from(value: ObjectPath) -> Self {
+        log::error!("we may want to replace the lektor by amadeus here...");
         use ObjectPath::*;
         let path = match value {
             None => "/org/lektor/MPRIS/None".try_into(),
diff --git a/lektor_nkdb/src/database/epoch.rs b/lektor_nkdb/src/database/epoch.rs
index 27ddba1952df02035043c7e470d4e786fd61e6a2..30787020fa0cec62437febe9c962d74c668a3ebf 100644
--- a/lektor_nkdb/src/database/epoch.rs
+++ b/lektor_nkdb/src/database/epoch.rs
@@ -1,9 +1,9 @@
 //! An epoch is a complete representation of the database at a point in time. It should be valid
 //! and sufficient to load the database and update it (well, appart from the files...)
 
-use hashbrown::hash_map;
-
 use crate::*;
+use hashbrown::hash_map;
+use std::{ffi::OsStr, path::Path};
 
 /// The epoch contains all available karas at a certain point in time. It can be submitted and
 /// available to all readers of the database or unsubmited and only one writter can edit it.
@@ -35,10 +35,11 @@ impl Epoch {
 
     /// Get the list of [Kara] corresponding to the [KId]. If we failed to find one kara we log the
     /// error and continue (silent fail).
-    pub fn get_karas_by_kid(&self, ids: impl IntoIterator<Item = KId>) -> Vec<&Kara> {
-        ids.into_iter()
-            .flat_map(|id| self.get_kara_by_kid(id))
-            .collect()
+    pub fn get_karas_by_kid(
+        &self,
+        ids: impl IntoIterator<Item = KId>,
+    ) -> impl Iterator<Item = &Kara> {
+        ids.into_iter().flat_map(|id| self.get_kara_by_kid(id))
     }
 
     /// Get a [Kara] by its local id [KId]. Should be more efficient that the [get_kara_by_u64]
@@ -48,6 +49,29 @@ impl Epoch {
         self.0.get(&id)
     }
 
+    /// Like [Self::get_kara_by_kid], but we try to find it by its [uri](url::Url). This is usefull
+    /// only when handling things from MPRIS because it's the only way to request a kara by its
+    /// file path in lektord.
+    pub fn get_kara_by_uri(&self, uri: &url::Url) -> Option<&Kara> {
+        self.get_kara_by_kid(match uri.scheme() {
+            "file" => {
+                let path = Path::new(uri.path());
+                (path.extension()? == OsStr::new("mkv"))
+                    .then(|| path.file_name()?.to_str()?.parse::<KId>().ok())
+                    .flatten()?
+            }
+
+            "id" => (uri.path().parse::<KId>())
+                .map_err(|err| log::error!("invalid kara id in uri: {err}"))
+                .ok()?,
+
+            scheme => {
+                log::error!("unsuported uri scheme: {scheme}");
+                return None;
+            }
+        })
+    }
+
     /// Get access to the karas in the epoch.
     pub fn data(&self) -> &EpochData {
         &self.0
diff --git a/lektor_nkdb/src/lib.rs b/lektor_nkdb/src/lib.rs
index 73d585f9bcbb38ec835b1805d629d1c8085779c7..a4d0df06ef9e16f97986bd634c5aeae385136214 100644
--- a/lektor_nkdb/src/lib.rs
+++ b/lektor_nkdb/src/lib.rs
@@ -21,10 +21,11 @@ pub use crate::{
 pub use kurisu_api::v2::{SongOrigin, SongType, SONGORIGIN_LENGTH, SONGTYPE_LENGTH};
 
 use crate::database::{epoch::EpochData, pool::Pool};
-use anyhow::Context as _;
+use anyhow::{anyhow, Context as _};
 use hashbrown::HashMap;
 use lektor_utils::pushvec::*;
 use playlists::Playlists;
+use std::fmt;
 
 mod database;
 mod id;
@@ -91,6 +92,11 @@ impl<Storage: DatabaseStorage> Database<Storage> {
         )
     }
 
+    /// Get the last epoch from the database.
+    pub async fn last_epoch(&self) -> Option<&Epoch> {
+        self.epochs.last().await
+    }
+
     /// Get a [Kara] by its [KId] representation in the last epoch. Should be more efficient than
     /// the [Self::get_kara_by_id] because we dirrectly use the hash thing and we don't iterate
     /// over all the items in the [HashMap].
@@ -102,9 +108,20 @@ impl<Storage: DatabaseStorage> Database<Storage> {
             .with_context(|| format!("no kara {id}"))
     }
 
-    /// Get the last epoch from the database.
-    pub async fn last_epoch(&self) -> Option<&Epoch> {
-        self.epochs.last().await
+    /// Like [Self::get_kara_by_kid], but we try to find it by its [uri](url::Url). This is usefull
+    /// only when handling things from MPRIS because it's the only way to request a kara by its
+    /// file path in lektord.
+    pub async fn get_kara_by_uri<U>(&self, uri: U) -> anyhow::Result<&Kara>
+    where
+        U: TryInto<url::Url>,
+        <U as TryInto<url::Url>>::Error: fmt::Display,
+    {
+        let uri = uri.try_into().map_err(|err| anyhow!("{err}"))?;
+        self.last_epoch()
+            .await
+            .context("empty epoch")?
+            .get_kara_by_uri(&uri)
+            .with_context(|| format!("no kara matched uri `{uri}`"))
     }
 
     /// Get the path to a kara, try to get the absolute path, so here we append the relative path
diff --git a/lektord/Cargo.toml b/lektord/Cargo.toml
index a4e54f9cb1445f790f6d8d835a58f790405c8b3e..56ab4d1eac69e3e866603abffd526e425039056d 100644
--- a/lektord/Cargo.toml
+++ b/lektord/Cargo.toml
@@ -12,10 +12,11 @@ license.workspace      = true
 serde.workspace      = true
 serde_json.workspace = true
 
-log.workspace       = true
-rand.workspace      = true
-anyhow.workspace    = true
-hashbrown.workspace = true
+log.workspace         = true
+rand.workspace        = true
+anyhow.workspace      = true
+hashbrown.workspace   = true
+derive_more.workspace = true
 
 futures.workspace      = true
 tokio.workspace        = true
diff --git a/lektord/src/app/mod.rs b/lektord/src/app/mod.rs
index d020f169bc1aa131ecd7e5cfb243c53848137add..47897747779d524df7c308cb053f0f2327ea64ca 100644
--- a/lektord/src/app/mod.rs
+++ b/lektord/src/app/mod.rs
@@ -9,7 +9,7 @@ mod routes;
 mod search_adaptors;
 
 use crate::LektorConfig;
-use anyhow::{Context, Result};
+use anyhow::Context as _;
 use axum::{
     extract::Request,
     http::{response, StatusCode},
@@ -18,8 +18,8 @@ use axum::{
     routing::{delete, get, post, put},
 };
 use lektor_mpris::MPRISAdapter;
-use lektor_nkdb::{Database, DatabaseDiskStorage, Epoch};
-use lektor_payloads::{Epochs, LektorUser};
+use lektor_nkdb::{Database, DatabaseDiskStorage, Epoch, KId};
+use lektor_payloads::{Epochs, LektorUser, PlayState};
 use lektor_repo::Repo;
 use lektor_utils::config::LektorDatabaseConfig;
 use play_state::StoredPlayState;
@@ -31,7 +31,7 @@ use tokio::sync::{oneshot::Sender, RwLock};
 /// the tokio test framework.
 pub async fn app(
     config: LektorConfig,
-) -> Result<(axum::Router, tokio::sync::oneshot::Receiver<()>)> {
+) -> anyhow::Result<(axum::Router, tokio::sync::oneshot::Receiver<()>)> {
     /// Try to declare the routes in a more legible way without having an ugly formating.
     macro_rules! router {
         (
@@ -186,7 +186,7 @@ pub(crate) type LektorStatePtr = Arc<LektorState>;
 
 impl LektorState {
     /// Create a new server state from the configuration file.
-    pub async fn new(config: LektorConfig, shutdown: Sender<()>) -> Result<LektorStatePtr> {
+    pub async fn new(config: LektorConfig, shutdown: Sender<()>) -> anyhow::Result<LektorStatePtr> {
         let LektorConfig {
             database: LektorDatabaseConfig { folder, .. },
             player,
@@ -215,8 +215,7 @@ impl LektorState {
                     .desktop_entry("Lektord")
                     .try_build()
                     .await
-                    .with_context(|| "failed to build mpris server, run with no mpris")
-                    .map_err(|err| log::error!("{err}"))
+                    .map_err(|err| log::error!("can't build mpris server, run with one: {err}"))
                     .ok();
         }
         crate::c_wrapper::init_player_module(ptr.clone(), player)?;
@@ -245,13 +244,59 @@ impl LektorState {
         }
     }
 
+    /// Toggle the playstate.
+    fn toggle_play_state(&self) -> anyhow::Result<()> {
+        crate::c_wrapper::player_toggle_pause()
+    }
+
+    /// Set the playstate.
+    async fn set_play_state(&self, to: PlayState) -> anyhow::Result<()> {
+        if to == PlayState::Stop {
+            return crate::c_wrapper::player_stop();
+        }
+
+        match self.queue().read(|_, state| state).await {
+            PlayState::Stop if to == PlayState::Play => self.play_next().await?,
+            PlayState::Stop => log::error!("can't change state from Stop to {to:?}"),
+            _ => crate::c_wrapper::player_set_paused(to)?,
+        };
+
+        Ok(())
+    }
+
+    /// Play from a certain kara if it is present in the queue. If the kara is present multiple
+    /// times, we play from the first found position.
+    async fn play_from_queue_kid(&self, id: KId) -> anyhow::Result<()> {
+        (self.queue())
+            .write(|content, _| {
+                let idx = (content.get(..).into_iter().enumerate())
+                    .find_map(|(idx, (_, kid))| (kid == id).then_some(idx))?;
+                content.play_from_position(idx)?;
+                Some(())
+            })
+            .await
+            .with_context(|| format!("can't find kara with id {id} in the queue"))?;
+        crate::c_wrapper::player_load_file(self.database.get_kara_uri(id)?.to_string(), id)?;
+        Ok(())
+    }
+
+    /// Play from a certain position in the queue.
+    async fn play_from_queue_pos(&self, position: usize) -> anyhow::Result<()> {
+        let id = (self.queue())
+            .write(|content, _| content.play_from_position(position))
+            .await
+            .with_context(|| format!("position {position} doesn't exists in queue"))?;
+        crate::c_wrapper::player_load_file(self.database.get_kara_uri(id)?.to_string(), id)?;
+        Ok(())
+    }
+
     /// Get a handle to read or write the queue, alongside the playstate.
     pub(crate) fn queue(&self) -> QueueHandle {
         QueueHandle::new(&self.queue, &self.playstate)
     }
 
     /// Play the next kara in the queue.
-    pub(crate) async fn play_next(&self) -> Result<()> {
+    pub(crate) async fn play_next(&self) -> anyhow::Result<()> {
         let id = self
             .queue()
             .write(|queue, _| queue.next().context("no next kara to play"))
@@ -260,7 +305,7 @@ impl LektorState {
     }
 
     /// Play the previous kara in the queue.
-    pub(crate) async fn play_previous(&self) -> Result<()> {
+    pub(crate) async fn play_previous(&self) -> anyhow::Result<()> {
         let id = self
             .queue()
             .write(|queue, _| queue.previous().context("no next kara to play"))
@@ -272,6 +317,12 @@ impl LektorState {
 #[derive(Debug, Clone)]
 pub struct LektorStateWeakPtr(Weak<LektorState>);
 
+impl LektorStateWeakPtr {
+    fn upgrade(&self) -> Option<LektorStatePtr> {
+        Weak::upgrade(&self.0)
+    }
+}
+
 impl From<&Arc<LektorState>> for LektorStateWeakPtr {
     fn from(value: &Arc<LektorState>) -> Self {
         Self(Arc::downgrade(value))
diff --git a/lektord/src/app/mpris.rs b/lektord/src/app/mpris.rs
index b34e9deae6ef71d0da091525b2418fc7198430bc..046b684d8e2f60d542d8934c770e527515743960 100644
--- a/lektord/src/app/mpris.rs
+++ b/lektord/src/app/mpris.rs
@@ -1,97 +1,221 @@
 use crate::LektorStateWeakPtr;
+use derive_more::Display;
 use lektor_mpris::AsMpris;
-use lektor_nkdb::Kara;
-use std::sync::Arc;
+use lektor_nkdb::{KId, Kara};
+use std::{
+    ops::{self, Bound},
+    sync::Arc,
+};
 
 /// The play state, convertible to the thing liked by MPRIS.
+#[derive(Debug, Default, Clone, Copy)]
 pub struct PlayState(lektor_payloads::PlayState);
 
 /// A thing used to convert a [Kara] into track metadatas for MPRIS.
-pub struct TrackMdt(Arc<Kara>);
+pub struct TrackMdt<'a>(&'a Kara);
 
 /// An object used to designate karas in the database/queue by their path. It can also be used to
 /// specify other things as MPRIS like them.
-pub enum ObjPath {}
+#[derive(Debug, Default, Clone, Copy)]
+pub enum ObjPath {
+    #[default]
+    None,
+    Id(KId),
+    Position(usize),
+}
 
 /// Wrapper around the time for MPRIS.
+#[derive(Debug, Default, Clone, Copy, Display)]
+#[display("{_0}")]
 pub struct Time(u64);
 
 impl AsMpris for LektorStateWeakPtr {
     type Status = PlayState;
     type Time = Time;
-    type TrackMdt = TrackMdt;
+    type TrackMdt = lektor_mpris::types::TrackMetadata;
     type Path = ObjPath;
 
-    fn set_playback_status(&self, _status: Self::Status) {
-        todo!()
-    }
-
-    fn get_playback_status(&self) -> Self::Status {
-        todo!()
-    }
-
-    fn toggle_playback_status(&self) {
-        todo!()
+    async fn set_playback_status(&self, PlayState(status): Self::Status) {
+        if let Some(state) = self.upgrade() {
+            _ = (state.set_play_state(status))
+                .await
+                .map_err(|err| log::error!("{err}"));
+        }
     }
 
-    fn play_next(&self) {
-        todo!()
+    async fn get_playback_status(&self) -> Self::Status {
+        if let Some(state) = self.upgrade() {
+            state.queue().read(|_, status| status).await.into()
+        } else {
+            Default::default()
+        }
     }
 
-    fn play_previous(&self) {
-        todo!()
+    async fn toggle_playback_status(&self) {
+        if let Some(state) = self.upgrade() {
+            _ = state
+                .toggle_play_state()
+                .map_err(|err| log::error!("{err}"));
+        }
     }
 
-    fn seek(&self, _file: Option<Self::Path>, _position: Self::Time) {
-        todo!()
+    async fn play_next(&self) {
+        if let Some(state) = self.upgrade() {
+            _ = state.play_next().await.map_err(|err| log::error!("{err}"));
+        }
     }
 
-    fn go_to(&self, _track_id: Self::Path) {
-        todo!()
+    async fn play_previous(&self) {
+        if let Some(state) = self.upgrade() {
+            _ = (state.play_previous())
+                .await
+                .map_err(|err| log::error!("{err}"));
+        }
     }
 
-    fn position(&self) -> Self::Time {
-        todo!()
+    async fn seek(&self, file: Option<Self::Path>, position: Self::Time) {
+        log::error!("ignore the seeking thing for now, don't go to time: {position}");
+        if let Some(track_id) = file {
+            self.go_to(track_id).await;
+        }
     }
 
-    fn shuffle(&self) -> bool {
-        todo!()
+    async fn go_to(&self, track_id: Self::Path) {
+        let Some(state) = self.upgrade() else { return };
+        _ = match track_id {
+            ObjPath::None => Ok(()),
+            ObjPath::Id(kid) => state.play_from_queue_kid(kid).await,
+            ObjPath::Position(pos) => state.play_from_queue_pos(pos).await,
+        }
+        .map_err(|err| log::error!("{err}"));
     }
 
-    fn set_shuffle(&self, _shuffle: bool) {
-        todo!()
+    async fn position(&self) -> Self::Time {
+        let seconds = crate::c_wrapper::player_get_elapsed()
+            .map_err(|err| log::error!("failed to get state: {err}"))
+            .unwrap_or_default()
+            .max(0) as u64;
+        Time(seconds)
     }
 
-    fn get_current_metadata(&self) -> Self::TrackMdt {
-        todo!()
+    async fn get_current_metadata(&self) -> Self::TrackMdt {
+        let Some(state) = self.upgrade() else {
+            return Default::default();
+        };
+        let Some(id) = state.queue().read(|content, _| content.current()).await else {
+            return Default::default();
+        };
+        let Some(epoch) = state.database.last_epoch().await else {
+            return Default::default();
+        };
+        epoch
+            .get_kara_by_kid(id)
+            .map(|kara| TrackMdt(kara).into())
+            .unwrap_or_default()
     }
 
-    fn get_tracks_metadata(&self, _tracks_ids: Vec<Self::Path>) -> Vec<Self::TrackMdt> {
-        todo!()
+    async fn get_tracks_metadata(&self, tracks_ids: Vec<Self::Path>) -> Vec<Self::TrackMdt> {
+        let Some(state) = self.upgrade() else {
+            return vec![];
+        };
+        let Some(epoch) = state.database.last_epoch().await else {
+            return vec![];
+        };
+
+        let mut ret = Vec::with_capacity(tracks_ids.len());
+        for path in tracks_ids {
+            let kid = match path {
+                ObjPath::None => continue,
+                ObjPath::Id(kid) => kid,
+                ObjPath::Position(pos) => match state
+                    .queue()
+                    .read(move |content, _| {
+                        content.get((ops::Bound::Included(pos), ops::Bound::Included(pos)))
+                    })
+                    .await
+                    .pop()
+                {
+                    Some((_, id)) => id,
+                    None => continue,
+                },
+            };
+            if let Some(kara) = epoch.get_kara_by_kid(kid) {
+                ret.push(TrackMdt(kara).into());
+            }
+        }
+        ret
     }
 
-    fn get_queue_content(&self) -> Vec<Self::Path> {
-        todo!()
+    async fn get_queue_content(&self) -> Vec<Self::Path> {
+        let Some(state) = self.upgrade() else {
+            return vec![];
+        };
+        (state.queue())
+            .read(|content, _| content.get(..))
+            .await
+            .into_iter()
+            .map(|(_, kid)| ObjPath::Id(kid))
+            .collect()
     }
 
-    fn add_track(&self, _uri: &str, _after: Self::Path, _set_as_current: bool) {
-        todo!()
+    async fn add_track(&self, uri: &str, after: Self::Path, set_as_current: bool) {
+        let Some(state) = self.upgrade() else { return };
+
+        let id = match state.database.get_kara_by_uri(uri).await {
+            Ok(kara) => kara.id,
+            Err(err) => return log::error!("{err}"),
+        };
+
+        let after = match after {
+            ObjPath::None => None,
+            ObjPath::Position(pos) => Some(pos),
+            ObjPath::Id(kid) => state.queue().read(|content, _| content.index_of(kid)).await,
+        };
+
+        state
+            .queue()
+            .write(|content, _| content.insert_after(after, id))
+            .await;
+
+        _ = match (after, set_as_current) {
+            (None, true) => state.play_next().await,
+            (Some(after), true) => state.play_from_queue_pos(after).await,
+            _ => anyhow::Ok(()),
+        }
+        .map_err(|err| log::error!("{err}"));
     }
 
-    fn remove_track(&self, _track_id: Self::Path) {
-        todo!()
+    async fn remove_track(&self, track_id: Self::Path) {
+        let Some(state) = self.upgrade() else { return };
+        match track_id {
+            ObjPath::None => {}
+            ObjPath::Id(kid) => {
+                state
+                    .queue()
+                    .write(|content, _| content.delete_all(kid))
+                    .await
+            }
+            ObjPath::Position(pos) => {
+                let range = (Bound::Included(pos), Bound::Included(pos));
+                state
+                    .queue()
+                    .write(|content, _| content.delete(range))
+                    .await
+            }
+        }
     }
 
-    fn play_file(&self, _uri: &str) {
-        todo!()
-    }
+    async fn play_file(&self, uri: &str) {
+        let Some(state) = self.upgrade() else { return };
 
-    fn volume(&self) -> f64 {
-        100.0
-    }
+        let id = match state.database.get_kara_by_uri(uri).await {
+            Ok(kara) => kara.id,
+            Err(err) => return log::error!("{err}"),
+        };
 
-    fn set_volume(&self, volume: f64) {
-        log::warn!("ignore volume {volume}");
+        if let Err(err) = state.play_from_queue_kid(id).await {
+            log::error!("{err}")
+        }
     }
 }
 
@@ -140,34 +264,43 @@ impl From<Time> for lektor_mpris::types::TimeMicroSec {
     }
 }
 
-impl From<TrackMdt> for lektor_mpris::types::TrackMetadata {
-    fn from(TrackMdt(kara): TrackMdt) -> Self {
-        let mut kara_makers: Vec<_> = kara.kara_makers.iter().cloned().collect();
+impl From<TrackMdt<'_>> for lektor_mpris::types::TrackMetadata {
+    fn from(TrackMdt(kara): TrackMdt<'_>) -> Self {
+        let mut kara_makers: Vec<_> = kara.kara_makers.iter().map(Arc::as_ref).collect();
         kara_makers.sort();
-        let kara_makers = kara_makers.join(", ");
 
-        let mut language: Vec<_> = kara.language.iter().cloned().collect();
+        let mut language: Vec<_> = kara.language.iter().map(Arc::as_ref).collect();
         language.sort();
-        let language = language.join(", ");
 
         lektor_mpris::types::TrackMetadata::from_iter([
             ("Song Title".to_string(), kara.song_title.clone()),
             ("Song Source".to_string(), kara.song_source.clone()),
             ("Sont Type".to_string(), kara.song_type.to_string()),
-            ("Kara Makers".to_string(), kara_makers),
-            ("Languages".to_string(), language),
+            ("Song Origin".to_string(), kara.song_origin.to_string()),
+            ("Kara Makers".to_string(), kara_makers.join(", ")),
+            ("Languages".to_string(), language.join(", ")),
         ])
     }
 }
 
 impl From<lektor_mpris::types::ObjectPath> for ObjPath {
-    fn from(_value: lektor_mpris::types::ObjectPath) -> Self {
-        todo!()
+    fn from(value: lektor_mpris::types::ObjectPath) -> Self {
+        match value {
+            lektor_mpris::types::ObjectPath::Id(id) => Self::Id(KId::from_u64(id)),
+            lektor_mpris::types::ObjectPath::Position(pos) => Self::Position(pos),
+            lektor_mpris::types::ObjectPath::None | lektor_mpris::types::ObjectPath::NoTrack => {
+                Default::default()
+            }
+        }
     }
 }
 
 impl From<ObjPath> for lektor_mpris::types::ObjectPath {
-    fn from(_value: ObjPath) -> Self {
-        todo!()
+    fn from(value: ObjPath) -> Self {
+        match value {
+            ObjPath::None => lektor_mpris::types::ObjectPath::NoTrack,
+            ObjPath::Id(kid) => lektor_mpris::types::ObjectPath::Id(kid.into()),
+            ObjPath::Position(pos) => lektor_mpris::types::ObjectPath::Position(pos),
+        }
     }
 }
diff --git a/lektord/src/app/queue.rs b/lektord/src/app/queue.rs
index a368cba3d0b7e150be5113402f59e92bd788c58b..4edf12f609108c49d685bf6fddf6921b40630907 100644
--- a/lektord/src/app/queue.rs
+++ b/lektord/src/app/queue.rs
@@ -78,10 +78,7 @@ impl QueueContent {
                 std::ops::Bound::Unbounded => self.count(),
             },
         );
-        self.queue
-            .iter()
-            .enumerate()
-            .rev()
+        (self.queue.iter().enumerate().rev())
             .flat_map(|(idx, lvl)| {
                 let ret = (start <= lvl.len())
                     .then(|| (Priority::from(idx + 1), start..=(lvl.len() - 1).min(end)));
@@ -237,6 +234,43 @@ impl QueueContent {
         self.insert_slice(prio, &kara)
     }
 
+    /// Insert a kara after a certain position.
+    pub fn insert_after(&mut self, maybe_after: Option<usize>, kid: KId) {
+        match maybe_after {
+            Some(mut pos) => {
+                let insert_in = (self.queue.iter().enumerate().rev()).find_map(
+                    |(level_index, level)| match pos < level.len() {
+                        true => Some((level_index, pos + 1)),
+                        false => {
+                            pos -= level.len();
+                            None
+                        }
+                    },
+                );
+
+                match insert_in {
+                    Some((level, position)) => self.queue[level].insert(position, kid),
+                    None => self.queue[Priority::Add.index()].push(kid),
+                }
+            }
+
+            None => {
+                let level = (self.queue.iter().enumerate().rev())
+                    .find_map(|(idx, level)| (!level.is_empty()).then_some(idx))
+                    .unwrap_or_default();
+                self.queue[level].insert(0, kid);
+            }
+        }
+    }
+
+    /// Get the index of the first occurance of a kara by its [KId].
+    pub fn index_of(&self, kid: KId) -> Option<usize> {
+        self.get(..)
+            .into_iter()
+            .enumerate()
+            .find_map(|(idx, (_, id))| (id == kid).then_some(idx))
+    }
+
     /// Get the next kara to play from the queue and insert the old-playing one into the history.
     /// The returned kara is the new current one.
     pub fn next(&mut self) -> Option<KId> {
diff --git a/lektord/src/app/routes.rs b/lektord/src/app/routes.rs
index d71f918f0ff79c2afd357a8ff80c684471403b2c..17e538b87e538b2fac0a308cfcf67a10fd29ca14 100644
--- a/lektord/src/app/routes.rs
+++ b/lektord/src/app/routes.rs
@@ -75,12 +75,7 @@ pub(crate) async fn play_from_queue_pos(
     State(state): State<LektorStatePtr>,
     Path(position): Path<usize>,
 ) -> Result<(), LektordError> {
-    let id = state
-        .queue()
-        .write(|content, _| content.play_from_position(position))
-        .await
-        .with_context(|| format!("position {position} doesn't exists in queue"))?;
-    crate::c_wrapper::player_load_file(state.database.get_kara_uri(id)?.to_string(), id)?;
+    state.play_from_queue_pos(position).await?;
     Ok(())
 }
 
@@ -90,29 +85,17 @@ pub(crate) async fn set_play_state(
     State(state): State<LektorStatePtr>,
     Json(to): Json<PlayState>,
 ) -> Result<(), LektordError> {
-    if to == PlayState::Stop {
-        c_wrapper::player_stop()?
-    } else if state
-        .queue()
-        .write(|_, state| match state.get() {
-            PlayState::Stop if to == PlayState::Play => Ok(true),
-            stop @ PlayState::Stop => {
-                log::trace!("can't change playback from {stop:?} to {to:?}");
-                Ok(false)
-            }
-            _ => c_wrapper::player_set_paused(to).map(|_| false),
-        })
-        .await?
-    {
-        state.play_next().await?
-    }
+    state.set_play_state(to).await?;
     Ok(())
 }
 
 /// Toggle the play state of the server, Be aware of race conditions...
 #[axum::debug_handler(state = LektorStatePtr)]
-pub(crate) async fn toggle_play_state() -> Result<(), LektordError> {
-    Ok(crate::c_wrapper::player_toggle_pause()?)
+pub(crate) async fn toggle_play_state(
+    State(state): State<LektorStatePtr>,
+) -> Result<(), LektordError> {
+    state.toggle_play_state()?;
+    Ok(())
 }
 
 /// Get all the informations about a kara by its id. Returns the kara as a json object to avoid