diff --git a/crates/pinakes-core/src/import.rs b/crates/pinakes-core/src/import.rs index 4a8efe1..9d12a49 100644 --- a/crates/pinakes-core/src/import.rs +++ b/crates/pinakes-core/src/import.rs @@ -403,32 +403,42 @@ pub async fn import_directory_with_options( // Limit concurrency by draining when we hit the cap if join_set.len() >= concurrency - && let Some(Ok((path, result))) = join_set.join_next().await + && let Some(result) = join_set.join_next().await { - match result { - Ok(r) => results.push(Ok(r)), - Err(e) => { - tracing::warn!(path = %path.display(), error = %e, "failed to import file"); - results.push(Err(e)); - }, - } + collect_import_result(result, &mut results); } } // Drain remaining tasks - while let Some(Ok((path, result))) = join_set.join_next().await { - match result { - Ok(r) => results.push(Ok(r)), - Err(e) => { - tracing::warn!(path = %path.display(), error = %e, "failed to import file"); - results.push(Err(e)); - }, - } + while let Some(result) = join_set.join_next().await { + collect_import_result(result, &mut results); } Ok(results) } +fn collect_import_result( + join_result: std::result::Result< + (PathBuf, Result), + tokio::task::JoinError, + >, + results: &mut Vec>, +) { + match join_result { + Ok((_path, Ok(r))) => results.push(Ok(r)), + Ok((path, Err(e))) => { + tracing::warn!(path = %path.display(), error = %e, "failed to import file"); + results.push(Err(e)); + }, + Err(e) => { + tracing::error!(error = %e, "import task panicked"); + results.push(Err(PinakesError::InvalidOperation(format!( + "import task panicked: {e}" + )))); + }, + } +} + /// Extract markdown links from a file and store them in the database. async fn extract_and_store_links( storage: &DynStorageBackend, diff --git a/crates/pinakes-core/src/storage/mod.rs b/crates/pinakes-core/src/storage/mod.rs index ef8b9b6..d965b0d 100644 --- a/crates/pinakes-core/src/storage/mod.rs +++ b/crates/pinakes-core/src/storage/mod.rs @@ -155,7 +155,7 @@ pub trait StorageBackend: Send + Sync + 'static { &self, ) -> Result>; - // Batch metadata update + // Batch metadata update (must be implemented per backend for bulk SQL) #[allow(clippy::too_many_arguments)] async fn batch_update_media( &self, @@ -166,34 +166,7 @@ pub trait StorageBackend: Send + Sync + 'static { genre: Option<&str>, year: Option, description: Option<&str>, - ) -> Result { - let mut count = 0u64; - for id in ids { - let mut item = self.get_media(*id).await?; - if let Some(v) = title { - item.title = Some(v.to_string()); - } - if let Some(v) = artist { - item.artist = Some(v.to_string()); - } - if let Some(v) = album { - item.album = Some(v.to_string()); - } - if let Some(v) = genre { - item.genre = Some(v.to_string()); - } - if let Some(v) = &year { - item.year = Some(*v); - } - if let Some(v) = description { - item.description = Some(v.to_string()); - } - item.updated_at = chrono::Utc::now(); - self.update_media(&item).await?; - count += 1; - } - Ok(count) - } + ) -> Result; // Saved searches async fn save_search(