selene-core 0.8.0

selene-core is the backend for Selene, a local-first music player
Documentation
use std::{fs, sync::Arc};

use barber::{ProgressBar, ProgressRenderer};
use lunar_lib::iterator_ext::IteratorExtensions;

use crate::library::{
    LinkingError,
    track::{Track, lyric_data::LyricData},
};

pub fn link_lrc_files<'a>(
    tracks: impl IntoIterator<Item = &'a mut (Track, bool)> + ExactSizeIterator,
    progress_renderer: Arc<dyn ProgressRenderer + 'static>,
) -> Result<(), LinkingError> {
    let has_lyric_file = tracks
        .into_iter()
        .filter_map(|(track, changed)| {
            let mut lrc_path = track.container().path().to_path_buf();
            lrc_path.set_extension("slrc");
            if lrc_path.exists() {
                return Some((track, changed, lrc_path));
            }

            lrc_path.set_extension("lrc");
            if lrc_path.exists() {
                return Some((track, changed, lrc_path));
            }

            None
        })
        .to_vec();

    let progress_bar = ProgressBar::new(0, has_lyric_file.len(), progress_renderer);
    for (track, changed, lrc_file) in has_lyric_file {
        let string = fs::read_to_string(lrc_file)?;

        let Ok(lyric_data) = LyricData::infer_from_string(string) else {
            progress_bar.set_label(&format!(
                "Invalid lyric data for: {}",
                track.metadata.safe_title()
            ));
            progress_bar.increment();
            continue;
        };

        track.metadata.lyric_data = Some(lyric_data);
        *changed = true;
        progress_bar.set_label(&format!(
            "Linked lyric files for {}",
            track.metadata.safe_title()
        ));
        progress_bar.increment();
    }

    Ok(())
}