use std::sync::Arc;
use barber::{ProgressBar, ProgressRenderer};
use lunar_lib::database::{Database, DbHandle, TransactionError, db_transaction};
use thiserror::Error;
use crate::{
database::LibraryDb,
library::{hash_source_files, track::Track},
};
#[derive(Debug, Error)]
pub enum OrphanRelinkError {
#[error("IoError: {0}")]
Io(#[from] std::io::Error),
#[error("Transaction Error: {0}")]
Transaction(#[from] TransactionError),
}
pub fn relink_orphans(
mut check_tracks: Vec<Track>,
progress_renderer: Arc<dyn ProgressRenderer>,
) -> Result<(), OrphanRelinkError> {
if check_tracks.is_empty() {
return Ok(());
}
let sources = hash_source_files(progress_renderer.clone())?;
check_tracks.retain(|t| {
let expected_source = t.container().path();
!expected_source.exists() || sources.get(&t.id()).is_some_and(|t| t != expected_source)
});
let progress_bar = ProgressBar::new(0, check_tracks.len(), progress_renderer);
progress_bar.set_label("Relinking orphaned sources...");
let db = DbHandle::<LibraryDb>::open().unwrap();
for mut track in check_tracks {
if let Some(source) = sources.get(&track.id()) {
track.set_source_file(source.to_owned());
db_transaction(
|cas_tx| cas_tx.tx_upsert(track.clone()).map_err(Into::into),
db.clone(),
false,
)
.map_err(TransactionError::from)?;
progress_bar.set_label(&format!(
"Relinked {} to {}",
track.metadata.safe_title(),
source.display()
));
} else {
db.db()
.remove(*track.id())
.map_err(TransactionError::Sled)?;
progress_bar.set_label(&format!(
"Failed to relink {}: No source found. Removing from library",
track.metadata.safe_title()
));
}
progress_bar.increment();
}
progress_bar.flush();
Ok(())
}