From a6284c37617043a039b008df80cc0540331fd6df Mon Sep 17 00:00:00 2001 From: CDrummond Date: Mon, 14 Mar 2022 11:24:16 +0000 Subject: [PATCH] Add support for multiple music folders --- ChangeLog | 2 ++ UserGuide.md | 3 +- src/analyse.rs | 77 +++++++++++++++++++++++++++----------------------- src/db.rs | 47 ++++++++++++++++++++---------- src/main.rs | 41 ++++++++++++++++----------- 5 files changed, 103 insertions(+), 67 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5aebf50..cc19df5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,8 @@ 0.1.0 ----- 1. Add support for analysing CUE files. +2. Support up to 5 music folders (music, music_1, music_2, music_3, and + music_4). 0.0.2 ----- diff --git a/UserGuide.md b/UserGuide.md index 84412b6..6dff867 100644 --- a/UserGuide.md +++ b/UserGuide.md @@ -102,7 +102,8 @@ ignore=ignore.txt The following items are supported: * `music` specifies the location of your music collection - e.g. `c:\Users\user\Music` -for windows. This default to `Music` within the user's home folder. +for windows. This default to `Music` within the user's home folder. Up to 4 other +music folders may be specified via `music_1`, `music_2`, `music_3`, and `music_4` * `db` specifies the name and location of the database file used to store the analysis results. This will default to `bliss.db` in the current folder. * `lms` specifies the hostname, or IP address, of your LMS server. This is used diff --git a/src/analyse.rs b/src/analyse.rs index 5b531a9..b06043b 100644 --- a/src/analyse.rs +++ b/src/analyse.rs @@ -287,54 +287,61 @@ pub fn analyse_new_cue_tracks(db:&db::Db, mpath: &PathBuf, cue_tracks:Vec = Vec::new(); - let mut cue_tracks:Vec = Vec::new(); +pub fn analyse_files(db_path: &str, mpaths: &Vec, dry_run:bool, keep_old:bool, max_num_tracks:usize) { let mut db = db::Db::new(&String::from(db_path)); - let cur = PathBuf::from(mpath); db.init(); - log::info!("Looking for new tracks"); - get_file_list(&mut db, mpath, &cur, &mut track_paths, &mut cue_tracks); - log::info!("Num new tracks: {}", track_paths.len()); - if !cue_tracks.is_empty() { - log::info!("Num new cue tracks: {}", cue_tracks.len()); - } - if !dry_run && max_num_tracks>0 && track_paths.len()>max_num_tracks { - log::info!("Only analysing {} tracks", max_num_tracks); - track_paths.truncate(max_num_tracks); - } - if !dry_run && max_num_tracks>0 && cue_tracks.len()>max_num_tracks { - log::info!("Only analysing {} cue tracks", max_num_tracks); - cue_tracks.truncate(max_num_tracks); - } - if !keep_old { - db.remove_old(mpath, dry_run); - } - if !dry_run { - if track_paths.len()>0 { - match analyse_new_files(&db, mpath, track_paths) { - Ok(_) => { }, - Err(e) => { log::error!("Analysis returned error: {}", e); } - } - } else { - log::info!("No new tracks to analyse"); - } + + for path in mpaths { + let mpath = path.clone(); + let cur = path.clone(); + let mut track_paths:Vec = Vec::new(); + let mut cue_tracks:Vec = Vec::new(); + + log::info!("Looking for new tracks in {}", mpath.to_string_lossy()); + get_file_list(&mut db, &mpath, &cur, &mut track_paths, &mut cue_tracks); + log::info!("Num new tracks: {}", track_paths.len()); if !cue_tracks.is_empty() { - match analyse_new_cue_tracks(&db, mpath, cue_tracks) { - Ok(_) => { }, - Err(e) => { log::error!("Cue analysis returned error: {}", e); } + log::info!("Num new cue tracks: {}", cue_tracks.len()); + } + if !dry_run && max_num_tracks>0 && track_paths.len()>max_num_tracks { + log::info!("Only analysing {} tracks", max_num_tracks); + track_paths.truncate(max_num_tracks); + } + if !dry_run && max_num_tracks>0 && cue_tracks.len()>max_num_tracks { + log::info!("Only analysing {} cue tracks", max_num_tracks); + cue_tracks.truncate(max_num_tracks); + } + + if !dry_run { + if track_paths.len()>0 { + match analyse_new_files(&db, &mpath, track_paths) { + Ok(_) => { }, + Err(e) => { log::error!("Analysis returned error: {}", e); } + } + } else { + log::info!("No new tracks to analyse"); + } + if !cue_tracks.is_empty() { + match analyse_new_cue_tracks(&db, &mpath, cue_tracks) { + Ok(_) => { }, + Err(e) => { log::error!("Cue analysis returned error: {}", e); } + } } } } + if !keep_old { + db.remove_old(mpaths, dry_run); + } + db.close(); } -pub fn read_tags(db_path: &str, mpath: &PathBuf) { +pub fn read_tags(db_path: &str, mpaths: &Vec) { let db = db::Db::new(&String::from(db_path)); db.init(); - db.update_tags(&mpath); + db.update_tags(&mpaths); db.close(); } diff --git a/src/db.rs b/src/db.rs index 101d5e7..ac641d8 100644 --- a/src/db.rs +++ b/src/db.rs @@ -10,7 +10,7 @@ use bliss_audio::{Analysis, AnalysisIndex}; use indicatif::{ProgressBar, ProgressStyle}; use rusqlite::{Connection, params}; use std::convert::TryInto; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::process; use crate::cue; use crate::tags; @@ -150,7 +150,7 @@ impl Db { } } - pub fn remove_old(&self, mpath:&Path, dry_run:bool) { + pub fn remove_old(&self, mpaths: &Vec, dry_run:bool) { log::info!("Looking for non-existant tracks"); let mut stmt = self.conn.prepare("SELECT File FROM Tracks;").unwrap(); let track_iter = stmt.query_map([], |row| { @@ -169,13 +169,23 @@ impl Db { if cfg!(windows) { db_path = db_path.replace("/", "\\"); } - let path = mpath.join(PathBuf::from(db_path.clone())); - //log::debug!("Check if '{}' exists.", path.to_string_lossy()); + let mut exists = false; - if !path.exists() { + for mpath in mpaths { + let path = mpath.join(PathBuf::from(db_path.clone())); + //log::debug!("Check if '{}' exists.", path.to_string_lossy()); + + if path.exists() { + exists = true; + break; + } + } + + if !exists { to_remove.push(orig_path); } } + let num_to_remove = to_remove.len(); log::info!("Num non-existant tracks: {}", num_to_remove); if !dry_run && num_to_remove>0 { @@ -207,7 +217,7 @@ impl Db { count } - pub fn update_tags(&self, mpath:&PathBuf) { + pub fn update_tags(&self, mpaths: &Vec) { let total = self.get_track_count(); if total>0 { let pb = ProgressBar::new(total.try_into().unwrap()); @@ -242,15 +252,22 @@ impl Db { duration:dbtags.duration }; pb.set_message(format!("{}", dbtags.file)); - let path = String::from(mpath.join(&dbtags.file).to_string_lossy()); - let ftags = tags::read(&path); - if ftags.title.is_empty() && ftags.artist.is_empty() && ftags.album_artist.is_empty() && ftags.album.is_empty() && ftags.genre.is_empty() { - log::error!("Failed to read tags of '{}'", dbtags.file); - } else if ftags.duration!=dtags.duration || ftags.title!=dtags.title || ftags.artist!=dtags.artist || ftags.album_artist!=dtags.album_artist || ftags.album!=dtags.album || ftags.genre!=dtags.genre { - match self.conn.execute("UPDATE Tracks SET Title=?, Artist=?, AlbumArtist=?, Album=?, Genre=?, Duration=? WHERE rowid=?;", - params![ftags.title, ftags.artist, ftags.album_artist, ftags.album, ftags.genre, ftags.duration, dbtags.rowid]) { - Ok(_) => { updated += 1; }, - Err(e) => { log::error!("Failed to update tags of '{}'. {}", dbtags.file, e); } + + for mpath in mpaths { + let track_path = mpath.join(&dbtags.file); + if track_path.exists() { + let path = String::from(track_path.to_string_lossy()); + let ftags = tags::read(&path); + if ftags.title.is_empty() && ftags.artist.is_empty() && ftags.album_artist.is_empty() && ftags.album.is_empty() && ftags.genre.is_empty() { + log::error!("Failed to read tags of '{}'", dbtags.file); + } else if ftags.duration!=dtags.duration || ftags.title!=dtags.title || ftags.artist!=dtags.artist || ftags.album_artist!=dtags.album_artist || ftags.album!=dtags.album || ftags.genre!=dtags.genre { + match self.conn.execute("UPDATE Tracks SET Title=?, Artist=?, AlbumArtist=?, Album=?, Genre=?, Duration=? WHERE rowid=?;", + params![ftags.title, ftags.artist, ftags.album_artist, ftags.album, ftags.genre, ftags.duration, dbtags.rowid]) { + Ok(_) => { updated += 1; }, + Err(e) => { log::error!("Failed to update tags of '{}'. {}", dbtags.file, e); } + } + } + break; } } } diff --git a/src/main.rs b/src/main.rs index 497d4b8..4c15e61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,7 @@ fn main() { let mut task = "".to_string(); let mut lms_host = "127.0.0.1".to_string(); let mut max_num_tracks:usize = 0; + let mut music_paths:Vec = Vec::new(); match dirs::home_dir() { Some(path) => { music_path = String::from(path.join("Music").to_string_lossy()); } @@ -90,20 +91,23 @@ fn main() { let mut config = Ini::new(); match config.load(&config_file) { Ok(_) => { - match config.get(TOP_LEVEL_INI_TAG, "music") { - Some(val) => { music_path = val; }, - None => { } + let path_keys: [&str; 5] = ["music", "music_1", "music_2", "music_3", "music_4"]; + for key in &path_keys { + match config.get(TOP_LEVEL_INI_TAG, key) { + Some(val) => { music_paths.push(PathBuf::from(&val)); }, + None => { } + } } match config.get(TOP_LEVEL_INI_TAG, "db") { - Some(val) => { db_path = val; }, + Some(val) => { db_path = val; }, None => { } } match config.get(TOP_LEVEL_INI_TAG, "lms") { - Some(val) => { lms_host = val; }, + Some(val) => { lms_host = val; }, None => { } } match config.get(TOP_LEVEL_INI_TAG, "ignore") { - Some(val) => { ignore_file = val; }, + Some(val) => { ignore_file = val; }, None => { } } }, @@ -115,6 +119,10 @@ fn main() { } } + if music_paths.is_empty() { + music_paths.push(PathBuf::from(&music_path)); + } + if task.eq_ignore_ascii_case("stopmixer") { upload::stop_mixer(&lms_host); } else { @@ -137,18 +145,19 @@ fn main() { process::exit(-1); } } else { - let mpath = PathBuf::from(&music_path); - if !mpath.exists() { - log::error!("Music path ({}) does not exist", music_path); - process::exit(-1); - } - if !mpath.is_dir() { - log::error!("Music path ({}) is not a directory", music_path); - process::exit(-1); + for mpath in &music_paths { + if !mpath.exists() { + log::error!("Music path ({}) does not exist", mpath.to_string_lossy()); + process::exit(-1); + } + if !mpath.is_dir() { + log::error!("Music path ({}) is not a directory", mpath.to_string_lossy()); + process::exit(-1); + } } if task.eq_ignore_ascii_case("tags") { - analyse::read_tags(&db_path, &mpath); + analyse::read_tags(&db_path, &music_paths); } else if task.eq_ignore_ascii_case("ignore") { let ignore_path = PathBuf::from(&ignore_file); if !ignore_path.exists() { @@ -161,7 +170,7 @@ fn main() { } analyse::update_ignore(&db_path, &ignore_path); } else { - analyse::analyse_files(&db_path, &mpath, dry_run, keep_old, max_num_tracks); + analyse::analyse_files(&db_path, &music_paths, dry_run, keep_old, max_num_tracks); } } }