diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 5314aaf704d5fbe48d8b6b86764dcc54391a8dfe..79624569c87ab6a1231400e6ae134b88e2a1ba09 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -1765,6 +1765,7 @@ dependencies = [
  "lektor_db",
  "reqwest",
  "serde",
+ "serde_json",
  "smallstring",
  "tokio",
 ]
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
index 5c914887aef9e6b5fd033ed2cd2795066a412fd1..a2765b896091871a57d7ff67ecc2c3a55cad7187 100644
--- a/src/rust/Cargo.toml
+++ b/src/rust/Cargo.toml
@@ -63,7 +63,6 @@ serde = { version = "^1", default-features = false, features = [
 reqwest = { version = "0.11", default-features = false, features = [
     "rustls-tls",
     "rustls-tls-native-roots",
-    "json",
 ] }
 
 # Async stuff
diff --git a/src/rust/kurisu_api/src/route.rs b/src/rust/kurisu_api/src/route.rs
index c497855d685896c49691c75553bb5da5140f5ea8..a666601260a1c2644401e29ef2342415505f5b7a 100644
--- a/src/rust/kurisu_api/src/route.rs
+++ b/src/rust/kurisu_api/src/route.rs
@@ -39,6 +39,12 @@ macro_rules! route {
         const COUNT: usize = $crate::route!(count_args $($expr),*);
         $crate::route::build_request::<$route, COUNT>([$($expr),*])
     }};
+
+    ($route: ident -> $base: expr ; $($expr: expr),*) => {{
+        let mut route = $crate::route!($route -> $($expr),*);
+        route.insert_str(0, &$base);
+        route
+    }};
 }
 
 /// Create a new route.
diff --git a/src/rust/kurisu_api/src/v1.rs b/src/rust/kurisu_api/src/v1.rs
index 31af93179b6c66abaacd506c37fec28ddc6bee1e..f28ca2d07116d8752ba9089d39a80ae7988bf9a3 100644
--- a/src/rust/kurisu_api/src/v1.rs
+++ b/src/rust/kurisu_api/src/v1.rs
@@ -18,6 +18,9 @@ pub struct Kara<'a> {
     pub popularity: i64,
     pub unix_timestamp: i64,
     pub size: i64,
+
+    /// Still need to be present on kurisu...
+    pub file_hash: &'a str,
 }
 
 #[derive(Debug, Deserialize)]
@@ -41,6 +44,19 @@ pub enum MaybeKaraList<'a> {
     Multi(Vec<Kara<'a>>),
 }
 
+impl<'a> IntoIterator for MaybeKaraList<'a> {
+    type Item = Kara<'a>;
+    type IntoIter = std::vec::IntoIter<Kara<'a>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        match self {
+            MaybeKaraList::Empty => vec![].into_iter(),
+            MaybeKaraList::Single(kara) => vec![kara].into_iter(),
+            MaybeKaraList::Multi(karas) => karas.into_iter(),
+        }
+    }
+}
+
 impl<'a, 'de> Deserialize<'de> for MaybeKaraList<'a>
 where
     'de: 'a,
diff --git a/src/rust/kurisu_api/src/v2.rs b/src/rust/kurisu_api/src/v2.rs
index 0ba6f985eb5d5d43b1dea48dfaf5f9dd79e13ea5..d6d5bb44991da3992d9954c7bc09c5eabf2bf8be 100644
--- a/src/rust/kurisu_api/src/v2.rs
+++ b/src/rust/kurisu_api/src/v2.rs
@@ -42,8 +42,34 @@ pub enum SongOrigin {
     Autre,
 }
 
+impl SongType {
+    pub fn as_str(&self) -> &str {
+        match self {
+            SongType::OP => "OP",
+            SongType::ED => "ED",
+            SongType::IS => "IS",
+            SongType::MV => "MV",
+            SongType::OT => "OT",
+        }
+    }
+}
+
+impl SongOrigin {
+    pub fn as_str(&self) -> &str {
+        match self {
+            SongOrigin::Anime => "anime",
+            SongOrigin::VN => "vn",
+            SongOrigin::Game => "game",
+            SongOrigin::Music => "music",
+            SongOrigin::Autre => "autre",
+        }
+    }
+}
+
 #[derive(Debug, Deserialize, PartialEq, Eq)]
 pub struct Kara<'a> {
+    pub id: i64,
+
     #[serde(rename = "title")]
     pub song_title: &'a str,
 
@@ -66,6 +92,8 @@ pub struct Kara<'a> {
     pub last_modified_epoch: i64,
     pub creation_epoch: i64,
 
+    pub file_hash: &'a str,
+
     #[serde(flatten)]
     pub tags: HashMap<&'a str, Vec<&'a str>>,
 }
@@ -99,7 +127,8 @@ pub struct PlaylistList<'a> {
 
 new_route! { GetRepo         :: "/"           #0 -> Repo          }
 
-new_route! { GetKaras        :: "/kara"       #0 -> KaraList      }
+new_route! { GetAllKaras     :: "/kara"       #0 -> KaraList      }
+new_route! { GetKaras        :: "/kara/@"     #1 -> KaraList      }
 new_route! { GetKara         :: "/kara/@"     #1 -> Kara          }
 new_route! { GetKaraDl       :: "/kara/dl/@"  #1 -> KaraDl        }
 
@@ -199,6 +228,7 @@ mod test {
                , "karamakers": [ "Viieux", "Totoro" ]
                , "is_virtual": false
                , "type": "op"
+               , "id": 42
                , "origin": "anime"
                , "languages": [ "jp" ]
                , "last_modified_epoch": 1
@@ -216,6 +246,7 @@ mod test {
                , "is_virtual": false
                , "tag_1": [ "1", "2" ]
                , "type": "op"
+               , "id": 42
                , "origin": "anime"
                , "languages": [ "jp" ]
                , "tag_2": []
diff --git a/src/rust/lektor_db/src/connexion.rs b/src/rust/lektor_db/src/connexion.rs
index 65551092ed8709ea280a3da9e1b60cfd200dc3c7..11af90b9395eb8dbe6d66ddce33663cf24288ec3 100644
--- a/src/rust/lektor_db/src/connexion.rs
+++ b/src/rust/lektor_db/src/connexion.rs
@@ -107,6 +107,15 @@ impl LktDatabaseConnection {
         Ok(Self { sqlite })
     }
 
+    pub fn get_repo_id(&mut self, repo_name: impl AsRef<str>) -> LktDatabaseResult<i64> {
+        with_dsl!(repo => repo
+            .select(id)
+            .filter(name.is(repo_name.as_ref()))
+            .first::<i64>(&mut self.sqlite)
+            .map_err(LktDatabaseError::DieselResult)
+        )
+    }
+
     /// Get a tag id by its name. If the tag doesn't exists, create it.
     fn get_tag_id_by_name(&mut self, tag_name: impl AsRef<str>) -> LktDatabaseResult<i64> {
         with_dsl!(tag => self.sqlite.exclusive_transaction(|conn| {
@@ -203,6 +212,10 @@ impl LktDatabaseConnection {
         })
     }
 
+    pub fn make_kara_available<'a>(&mut self, remote_id: RemoteKaraId) -> LktDatabaseResult<()> {
+        todo!()
+    }
+
     /// Create a series of models from a kara signature from Kurisu's V1 API.
     pub fn new_kara_v1<'a>(
         &mut self,
@@ -237,7 +250,7 @@ impl LktDatabaseConnection {
             song_type: kara.song_type,
             song_origin: kara.category,
             source_name: kara.source_name,
-            file_hash: format!("{}", kara.unix_timestamp),
+            file_hash: kara.file_hash,
         };
         Ok((id, kara, kara_maker, vec![lang], tags))
     }
diff --git a/src/rust/lektor_db/src/error.rs b/src/rust/lektor_db/src/error.rs
index 05e562c974237ba747fdc9ee7ae6592dde399194..bbbff5e8325e7bcf8e4c9b3dc858fca30cc0ae74 100644
--- a/src/rust/lektor_db/src/error.rs
+++ b/src/rust/lektor_db/src/error.rs
@@ -14,6 +14,9 @@ pub enum LktDatabaseError {
 
     #[error("database error: {0}")]
     Str(&'static str),
+
+    #[error("database error: not found!")]
+    NotFound,
 }
 
 #[derive(Debug, thiserror::Error)]
diff --git a/src/rust/lektor_db/src/lib.rs b/src/rust/lektor_db/src/lib.rs
index add72f281086040fe052ad7b4ec92f3242be49d6..be1412471b52f9d3291d05928b38566e3f75ed99 100644
--- a/src/rust/lektor_db/src/lib.rs
+++ b/src/rust/lektor_db/src/lib.rs
@@ -11,8 +11,9 @@ pub mod uri;
 
 pub(self) mod schema;
 
+pub use error::*;
+
 pub(self) use diesel::prelude::*;
-pub(self) use error::*;
 pub(self) use std::{collections::VecDeque, ops::Range, path::Path};
 
 /// All the information needed to add a kara recieved from a repo!
diff --git a/src/rust/lektor_db/src/models.rs b/src/rust/lektor_db/src/models.rs
index b42f25edebc82387fb70732815dc6d20747e5065..f07ed82013bc797f2a57b076c84c6a5ce4d4ffb6 100644
--- a/src/rust/lektor_db/src/models.rs
+++ b/src/rust/lektor_db/src/models.rs
@@ -18,6 +18,13 @@ pub struct KaraId {
     pub local_kara_id: i64,
 }
 
+#[derive(Debug, Queryable, Selectable)]
+#[diesel(table_name = repo_kara)]
+pub struct RemoteKaraId {
+    pub repo_id: i64,
+    pub repo_kara_id: i64,
+}
+
 #[derive(Debug, Insertable, Queryable, Selectable)]
 #[diesel(table_name = history)]
 pub struct HistoryRecord {
@@ -43,7 +50,7 @@ pub struct NewKara<'a> {
     pub song_type: &'a str,
     pub song_origin: &'a str,
     pub source_name: &'a str,
-    pub file_hash: String,
+    pub file_hash: &'a str,
 }
 
 #[derive(Debug, Insertable)]
diff --git a/src/rust/lektor_repo/Cargo.toml b/src/rust/lektor_repo/Cargo.toml
index 1d11b3ab08c9e2fbb8437ff8885f1c801124f5f3..fd0872121ae94209d8e5bb5dad2eb9284aece13b 100644
--- a/src/rust/lektor_repo/Cargo.toml
+++ b/src/rust/lektor_repo/Cargo.toml
@@ -14,6 +14,7 @@ tokio.workspace = true
 futures.workspace = true
 reqwest.workspace = true
 hashbrown.workspace = true
+serde_json.workspace = true
 
 lektor_c_compat = { path = "../lektor_c_compat" }
 lektor_config = { path = "../lektor_config" }
diff --git a/src/rust/lektor_repo/src/download.rs b/src/rust/lektor_repo/src/download.rs
index 20a01f616b4b141d58a04db054020215b73d8291..7008c955c2ace05e64d4afbf1525a5ffc65903bb 100644
--- a/src/rust/lektor_repo/src/download.rs
+++ b/src/rust/lektor_repo/src/download.rs
@@ -1,7 +1,6 @@
-use std::path::PathBuf;
-
 use crate::*;
 use futures::stream::{self, StreamExt};
+use std::path::{Path, PathBuf};
 
 pub struct DownloadBuilder {
     hosts: Vec<RepoConfig>,
@@ -49,20 +48,6 @@ fn formatter_for_api_version(version: RepoApiVersion) -> fn(&LktUri) -> Result<S
     }
 }
 
-/// Download the metadata of the kara, should be a json thing. Deserialize it latter depending on
-/// the API version.
-fn download_metadata<'a>(
-    _api: RepoApiVersion,
-    _base: &'a str,
-    _url: &str,
-) -> Result<(&'a str, String), String> {
-    todo!()
-}
-
-fn download_kara(search_urls: &[String], destination: PathBuf) -> Result<(), String> {
-    todo!()
-}
-
 impl Download {
     pub fn builder(queue: LktCQueue, hosts: Vec<RepoConfig>, db: LktLockDbPtr) -> DownloadBuilder {
         DownloadBuilder {
@@ -74,30 +59,134 @@ impl Download {
         }
     }
 
+    /// Download the metadata of the kara. We update the database with the downloaded metadata. The
+    /// function only returns the karas' id viewed from the repo.
+    async fn download_metadata<'a>(
+        db: LktLockDbPtr,
+        api: RepoApiVersion,
+        base: &'a str,
+        repo_id: i64,
+        uri: &str,
+    ) -> Result<(&'a str, Vec<i64>), String> {
+        use kurisu_api::route;
+        match api {
+            RepoApiVersion::V1 => {
+                use kurisu_api::v1::*;
+                let content = reqwest::get(route!(GetKara -> base; uri))
+                    .await
+                    .map_err(|err| format!("{err}"))?
+                    .text()
+                    .await
+                    .map_err(|err| format!("{err}"))?;
+                let (new_karas, errors): (Vec<_>, Vec<_>) =
+                    serde_json::from_str::<MaybeKaraList>(&content)
+                        .map_err(|err| format!("{err}"))?
+                        .into_iter()
+                        .map(|kara_v1| {
+                            let mut db = db.lock().expect("failed to lock the database...");
+                            let new_kara = db.new_kara_v1(repo_id, kara_v1)?;
+                            let repo_kara_id = new_kara.0.repo_kara_id;
+                            db.add_kara_from_request(new_kara)?;
+                            Ok::<i64, lektor_db::LktDatabaseError>(repo_kara_id)
+                        })
+                        .partition(Result::is_ok);
+                for error in errors.into_iter().map(Result::unwrap_err) {
+                    log::error!(target: "REPO", "failed to download metadata for kara from {base}: {error}");
+                }
+                either!(new_karas.is_empty()
+                    => Err(format!("no kara found in {base} for uri: {uri}"))
+                    ; Ok((base, new_karas.into_iter().map(Result::unwrap).collect())))
+            }
+
+            RepoApiVersion::V2 => {
+                todo!()
+            }
+        }
+    }
+
+    /// Build the destination file path for the kara.
+    fn build_destination_file_path(
+        _db: LktLockDbPtr,
+        _repo_id: i64,
+        _repo_kara_id: i64,
+    ) -> Result<(i64, PathBuf), String> {
+        todo!()
+    }
+
+    /// Download the kara file.
+    async fn download_kara(
+        _db: LktLockDbPtr,
+        _api: RepoApiVersion,
+        _search_urls: &[&str],
+        _repo_id: i64,
+        _repo_kara_id: i64,
+        _destination: impl AsRef<Path>,
+    ) -> Result<(), String> {
+        todo!()
+    }
+
     pub async fn download(self) {
+        let db = &self.db;
         let uri = &self.uri;
+        let repo_id = {
+            let mut db = self.db.lock().expect("failed to lock the database...");
+            let repo_id =
+                self.hosts
+                    .iter()
+                    .find_map(|RepoConfig { name, .. }| match db.get_repo_id(name) {
+                        Ok(repo_id) => Some(repo_id),
+                        Err(err) => {
+                            log::error!(target: "REPO", "no id found for repo: {err}");
+                            None
+                        }
+                    });
+            match repo_id {
+                Some(repo_id) => repo_id,
+                None => return,
+            }
+        };
+
         stream::iter(&self.hosts)
             .for_each_concurrent(2, |RepoConfig { name, api, urls }| async move {
-                let uri = match formatter_for_api_version(*api)(uri) {
+                let uri = match formatter_for_api_version(*api)(&uri) {
                     Ok(uri) => uri,
                     Err(err) => {
                         log::error!(target: "REPO", "{err}");
                         return;
                     }
                 };
-                let ok_urls = stream::iter(urls.iter().map(|base| (base, format!("{base}/{uri}"))))
-                    .filter_map(|(base, url)| async move {
-                        download_metadata(*api, base, &url).map_err(|err| log::error!(target: "REPO", "failed to download metadata with url `{url}`: {err}")).ok()
+                let uri = &uri;
+                let ok_urls = stream::iter(urls.iter())
+                    .filter_map(|base | async move {
+                        Download::download_metadata(db.clone(), *api, base, repo_id, &uri)
+                            .await
+                            .map_err(|err| log::error!(target: "REPO", "failed to download metadata with uri `{uri}`: {err}"))
+                            .ok()
                     });
-                let Some((base, content)) = Box::pin(ok_urls).next().await else {
+                let Some((base, karas_id)) = Box::pin(ok_urls).next().await else {
                     log::error!("can't find uri {uri} in repo {name}");
                     return;
                 };
-
-                let search_urls: Vec<_> = Some(base).into_iter().chain(urls.iter().filter_map(|url| (url != base).then_some(url.as_str()))).collect();
-
-                // Find the first url with an Ok status, then get the id and dl the kara if not dry.
-                // If the dl was not successfull, try the next url
+                let other_urls = urls.iter().filter_map(|url| (url != base).then_some(url.as_str()));
+                let search_urls: Vec<_> = Some(base).into_iter().chain(other_urls).collect();
+                let (karas_id, errors): (Vec<_>, Vec<_>) = karas_id
+                    .into_iter()
+                    .map(|repo_kara_id| Download::build_destination_file_path(db.clone(), repo_id, repo_kara_id))
+                    .partition(Result::is_ok);
+                for error in errors.into_iter().map(Result::unwrap_err) {
+                    log::error!(target: "REPO", "failed to build a file path for kara from repo {name}: {error}");
+                }
+                for (repo_kara_id, destination) in karas_id.into_iter().map(Result::unwrap) {
+                    if let Err(err) = Download::download_kara(db.clone(), *api, &search_urls[..], repo_id, repo_kara_id, &destination).await {
+                        log::error!(target: "REPO", "failed to download file `{}` for kara {repo_kara_id}: {err}", destination.to_string_lossy());
+                        return;
+                    }
+                    if let Err(err) = db.lock().expect("failed to lock the database...")
+                        .make_kara_available(lektor_db::models::RemoteKaraId { repo_id, repo_kara_id }) {
+                        log::error!(target: "REPO", "failed to make kara `{repo_kara_id}` from {name} available: {err}");
+                        return;
+                    }
+                }
             })
             .await;
     }