use std::sync::Arc;
use barber::{ProgressBar, ProgressRenderer};
use lunar_lib::database::{Database, DatabaseEntry, DatabaseError, TransactionError};
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("Database Error: {0}")]
Database(#[from] DatabaseError),
#[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...");
for mut track in check_tracks {
if let Some(source) = sources.get(&track.id()) {
track.set_source_file(source.to_owned());
track.db_upsert()?;
progress_bar.set_label(&format!(
"Relinked {} to {}",
track.metadata.safe_title(),
source.display()
));
} else {
let db = LibraryDb::open()?;
db.remove(*track.id()).map_err(DatabaseError::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(())
}