From 5722b04c85b4cba894ea83b1bc4918e20e2075ad Mon Sep 17 00:00:00 2001 From: CDrummond Date: Tue, 13 May 2025 12:25:50 +0100 Subject: [PATCH] - Store analysis in BLISS_ANALYSIS tag, not in a COMMENT tag. - Fix read of tags during analysis phase. Closes #23 --- Cargo.lock | 2 +- Cargo.toml | 2 +- ChangeLog | 5 ++ src/analyse.rs | 12 +++-- src/tags.rs | 123 +++++++++++++++++++++++++++---------------------- 5 files changed, 84 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46ed1da..3458346 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,7 +180,7 @@ dependencies = [ [[package]] name = "bliss-analyser" -version = "0.4.0" +version = "0.5.0" dependencies = [ "anyhow", "argparse", diff --git a/Cargo.toml b/Cargo.toml index a01131b..3d9a67e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bliss-analyser" -version = "0.4.0" +version = "0.5.0" authors = ["Craig Drummond "] edition = "2021" license = "GPL-3.0-only" diff --git a/ChangeLog b/ChangeLog index 2456ab5..0ae55e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +0.5.0 +----- +1. Store analysis in BLISS_ANALYSIS tag, not in a COMMENT tag. +2. Fix read of tags during analysis phase. + 0.4.0 ----- 1. Add action to export results from database to files. diff --git a/src/analyse.rs b/src/analyse.rs index 969a535..edc2681 100644 --- a/src/analyse.rs +++ b/src/analyse.rs @@ -111,7 +111,7 @@ fn check_dir_entry(db: &mut db::Db, mpath: &Path, entry: DirEntry, track_paths: if id<=0 { let mut tags_used = false; if use_tags { - let meta = tags::read(&sname, true); + let meta = tags::read(&String::from(pb.to_string_lossy()), true); if !meta.is_empty() && !meta.analysis.is_none() { if !dry_run { db.add_track(&sname, &meta, &meta.analysis.unwrap()); @@ -430,12 +430,16 @@ pub fn analyse_files(db_path: &str, mpaths: &Vec, dry_run: bool, keep_o } get_file_list(&mut db, &mpath, &cur, &mut track_paths, &mut cue_tracks, &mut file_count, max_num_files, use_tags, &mut tagged_file_count, dry_run); track_paths.sort(); - log::info!("Num new files: {}", track_paths.len()); + if use_tags { + log::info!("New untagged files: {}", track_paths.len()); + } else { + log::info!("New files: {}", track_paths.len()); + } if !cue_tracks.is_empty() { - log::info!("Num new cue tracks: {}", cue_tracks.len()); + log::info!("New cue tracks: {}", cue_tracks.len()); } if use_tags { - log::info!("Num tagged files: {}", tagged_file_count); + log::info!("New tagged files: {}", tagged_file_count); } if dry_run { diff --git a/src/tags.rs b/src/tags.rs index 0a2f907..af41d24 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -21,12 +21,11 @@ use bliss_audio::{Analysis, AnalysisIndex}; const MAX_GENRE_VAL: usize = 192; const NUM_ANALYSIS_VALS: usize = 20; -const ANALYSIS_TAG:ItemKey = ItemKey::Comment; -const ANALYSIS_TAG_START: &str = "BLISS_ANALYSIS"; +const ANALYSIS_TAG: &str = "BLISS_ANALYSIS"; const ANALYSIS_TAG_VER: u16 = 1; pub fn write_analysis(track: &String, analysis: &Analysis, preserve_mod_times: bool) { - let value = format!("{},{},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24}", ANALYSIS_TAG_START, ANALYSIS_TAG_VER, + let value = format!("{},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24},{:.24}", ANALYSIS_TAG_VER, analysis[AnalysisIndex::Tempo], analysis[AnalysisIndex::Zcr], analysis[AnalysisIndex::MeanSpectralCentroid], analysis[AnalysisIndex::StdDeviationSpectralCentroid], analysis[AnalysisIndex::MeanSpectralRolloff], analysis[AnalysisIndex::StdDeviationSpectralRolloff], analysis[AnalysisIndex::MeanSpectralFlatness], analysis[AnalysisIndex::StdDeviationSpectralFlatness], analysis[AnalysisIndex::MeanLoudness], analysis[AnalysisIndex::StdDeviationLoudness], analysis[AnalysisIndex::Chroma1], analysis[AnalysisIndex::Chroma2], analysis[AnalysisIndex::Chroma3], analysis[AnalysisIndex::Chroma4], analysis[AnalysisIndex::Chroma5], @@ -46,23 +45,13 @@ pub fn write_analysis(track: &String, analysis: &Analysis, preserve_mod_times: b }, }; - // Remove any existing analysis result tag - let entries = tag.get_strings(&ANALYSIS_TAG); - let mut keep: Vec = Vec::new(); - for entry in entries { - if !entry.starts_with(ANALYSIS_TAG_START) { - keep.push(ItemValue::Text(entry.to_string())); - } - } - tag.remove_key(&ANALYSIS_TAG); - for k in keep { - tag.push(TagItem::new(ANALYSIS_TAG, k)); - } - // Store analysis results - tag.push(TagItem::new(ANALYSIS_TAG, ItemValue::Text(value))); + let tag_key = ItemKey::Unknown(ANALYSIS_TAG.to_string()); + tag.remove_key(&tag_key); + tag.insert_unchecked(TagItem::new(tag_key, ItemValue::Text(value))); let now = SystemTime::now(); let mut mod_time = now; + if preserve_mod_times { if let Ok(fmeta) = fs::metadata(track) { if let Ok(time) = fmeta.modified() { @@ -81,6 +70,49 @@ pub fn write_analysis(track: &String, analysis: &Analysis, preserve_mod_times: b } } +fn read_analysis_string(tag_str: &str, start_tag_pos:usize, version_pos:usize) -> Option { + let parts = tag_str.split(","); + let mut index = 0; + let mut num_read_vals = 0; + let mut vals = [0.; NUM_ANALYSIS_VALS]; + let val_start_pos = version_pos+1; + for part in parts { + if index==start_tag_pos && start_tag_pos() { + Ok(ver) => { + if ver!=ANALYSIS_TAG_VER { + break; + } + }, + Err(_) => { + break; + } + } + } else if (index - val_start_pos) < NUM_ANALYSIS_VALS { + match part.parse::() { + Ok(val) => { + num_read_vals += 1; + vals[index - val_start_pos] = val; + }, + Err(_) => { + break; + } + } + } else { + break; + } + index += 1; + } + if num_read_vals == NUM_ANALYSIS_VALS { + return Some(Analysis::new(vals)); + } + None +} + pub fn read(track: &String, read_analysis: bool) -> db::Metadata { let mut meta = db::Metadata { duration: 180, @@ -140,45 +172,28 @@ pub fn read(track: &String, read_analysis: bool) -> db::Metadata { meta.duration = file.properties().duration().as_secs() as u32; if read_analysis { - let entries = tag.get_strings(&ANALYSIS_TAG); - for entry in entries { - if entry.len()>(ANALYSIS_TAG_START.len()+(NUM_ANALYSIS_VALS*8)) && entry.starts_with(ANALYSIS_TAG_START) { - let parts = entry.split(","); - let mut index = 0; - let mut vals = [0.; NUM_ANALYSIS_VALS]; - for part in parts { - if 0==index { - if part!=ANALYSIS_TAG_START { - break; - } - } else if 1==index { - match part.parse::() { - Ok(ver) => { - if ver!=ANALYSIS_TAG_VER { - break; - } - }, - Err(_) => { - break; - } - } - } else if (index - 2) < NUM_ANALYSIS_VALS { - match part.parse::() { - Ok(val) => { - vals[index - 2] = val; - }, - Err(_) => { - break; - } - } - } else { - break; + match tag.get_string(&ItemKey::Unknown(ANALYSIS_TAG.to_string())) { + Some(tag_str) => { + match read_analysis_string(tag_str, 100, 0) { + Some(analysis) => { + meta.analysis = Some(analysis); } - index += 1; + None => { } } - if index == (NUM_ANALYSIS_VALS+2) { - meta.analysis = Some(Analysis::new(vals)); - break; + } + None => { + // Old, stored in comment + let entries = tag.get_strings(&ItemKey::Comment); + for entry in entries { + if entry.len()>(ANALYSIS_TAG.len()+(NUM_ANALYSIS_VALS*8)) && entry.starts_with(ANALYSIS_TAG) { + match read_analysis_string(entry, 0, 1) { + Some(analysis) => { + meta.analysis = Some(analysis); + break; + } + None => { } + } + } } } }