mirror of
https://github.com/CDrummond/bliss-analyser.git
synced 2025-04-13 15:37:14 +03:00
Add support for multiple music folders
This commit is contained in:
parent
cf729aaef3
commit
a6284c3761
@ -1,6 +1,8 @@
|
|||||||
0.1.0
|
0.1.0
|
||||||
-----
|
-----
|
||||||
1. Add support for analysing CUE files.
|
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
|
0.0.2
|
||||||
-----
|
-----
|
||||||
|
@ -102,7 +102,8 @@ ignore=ignore.txt
|
|||||||
|
|
||||||
The following items are supported:
|
The following items are supported:
|
||||||
* `music` specifies the location of your music collection - e.g. `c:\Users\user\Music`
|
* `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
|
* `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.
|
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
|
* `lms` specifies the hostname, or IP address, of your LMS server. This is used
|
||||||
|
@ -287,54 +287,61 @@ pub fn analyse_new_cue_tracks(db:&db::Db, mpath: &PathBuf, cue_tracks:Vec<cue::C
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyse_files(db_path: &str, mpath: &PathBuf, dry_run:bool, keep_old:bool, max_num_tracks:usize) {
|
pub fn analyse_files(db_path: &str, mpaths: &Vec<PathBuf>, dry_run:bool, keep_old:bool, max_num_tracks:usize) {
|
||||||
let mut track_paths:Vec<String> = Vec::new();
|
|
||||||
let mut cue_tracks:Vec<cue::CueTrack> = Vec::new();
|
|
||||||
let mut db = db::Db::new(&String::from(db_path));
|
let mut db = db::Db::new(&String::from(db_path));
|
||||||
let cur = PathBuf::from(mpath);
|
|
||||||
|
|
||||||
db.init();
|
db.init();
|
||||||
log::info!("Looking for new tracks");
|
|
||||||
get_file_list(&mut db, mpath, &cur, &mut track_paths, &mut cue_tracks);
|
for path in mpaths {
|
||||||
log::info!("Num new tracks: {}", track_paths.len());
|
let mpath = path.clone();
|
||||||
if !cue_tracks.is_empty() {
|
let cur = path.clone();
|
||||||
log::info!("Num new cue tracks: {}", cue_tracks.len());
|
let mut track_paths:Vec<String> = Vec::new();
|
||||||
}
|
let mut cue_tracks:Vec<cue::CueTrack> = Vec::new();
|
||||||
if !dry_run && max_num_tracks>0 && track_paths.len()>max_num_tracks {
|
|
||||||
log::info!("Only analysing {} tracks", max_num_tracks);
|
log::info!("Looking for new tracks in {}", mpath.to_string_lossy());
|
||||||
track_paths.truncate(max_num_tracks);
|
get_file_list(&mut db, &mpath, &cur, &mut track_paths, &mut cue_tracks);
|
||||||
}
|
log::info!("Num new tracks: {}", track_paths.len());
|
||||||
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");
|
|
||||||
}
|
|
||||||
if !cue_tracks.is_empty() {
|
if !cue_tracks.is_empty() {
|
||||||
match analyse_new_cue_tracks(&db, mpath, cue_tracks) {
|
log::info!("Num new cue tracks: {}", cue_tracks.len());
|
||||||
Ok(_) => { },
|
}
|
||||||
Err(e) => { log::error!("Cue analysis returned error: {}", e); }
|
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();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_tags(db_path: &str, mpath: &PathBuf) {
|
pub fn read_tags(db_path: &str, mpaths: &Vec<PathBuf>) {
|
||||||
let db = db::Db::new(&String::from(db_path));
|
let db = db::Db::new(&String::from(db_path));
|
||||||
db.init();
|
db.init();
|
||||||
db.update_tags(&mpath);
|
db.update_tags(&mpaths);
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
src/db.rs
47
src/db.rs
@ -10,7 +10,7 @@ use bliss_audio::{Analysis, AnalysisIndex};
|
|||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use rusqlite::{Connection, params};
|
use rusqlite::{Connection, params};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
use std::process;
|
use std::process;
|
||||||
use crate::cue;
|
use crate::cue;
|
||||||
use crate::tags;
|
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<PathBuf>, dry_run:bool) {
|
||||||
log::info!("Looking for non-existant tracks");
|
log::info!("Looking for non-existant tracks");
|
||||||
let mut stmt = self.conn.prepare("SELECT File FROM Tracks;").unwrap();
|
let mut stmt = self.conn.prepare("SELECT File FROM Tracks;").unwrap();
|
||||||
let track_iter = stmt.query_map([], |row| {
|
let track_iter = stmt.query_map([], |row| {
|
||||||
@ -169,13 +169,23 @@ impl Db {
|
|||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
db_path = db_path.replace("/", "\\");
|
db_path = db_path.replace("/", "\\");
|
||||||
}
|
}
|
||||||
let path = mpath.join(PathBuf::from(db_path.clone()));
|
let mut exists = false;
|
||||||
//log::debug!("Check if '{}' exists.", path.to_string_lossy());
|
|
||||||
|
|
||||||
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);
|
to_remove.push(orig_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_to_remove = to_remove.len();
|
let num_to_remove = to_remove.len();
|
||||||
log::info!("Num non-existant tracks: {}", num_to_remove);
|
log::info!("Num non-existant tracks: {}", num_to_remove);
|
||||||
if !dry_run && num_to_remove>0 {
|
if !dry_run && num_to_remove>0 {
|
||||||
@ -207,7 +217,7 @@ impl Db {
|
|||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_tags(&self, mpath:&PathBuf) {
|
pub fn update_tags(&self, mpaths: &Vec<PathBuf>) {
|
||||||
let total = self.get_track_count();
|
let total = self.get_track_count();
|
||||||
if total>0 {
|
if total>0 {
|
||||||
let pb = ProgressBar::new(total.try_into().unwrap());
|
let pb = ProgressBar::new(total.try_into().unwrap());
|
||||||
@ -242,15 +252,22 @@ impl Db {
|
|||||||
duration:dbtags.duration
|
duration:dbtags.duration
|
||||||
};
|
};
|
||||||
pb.set_message(format!("{}", dbtags.file));
|
pb.set_message(format!("{}", dbtags.file));
|
||||||
let path = String::from(mpath.join(&dbtags.file).to_string_lossy());
|
|
||||||
let ftags = tags::read(&path);
|
for mpath in mpaths {
|
||||||
if ftags.title.is_empty() && ftags.artist.is_empty() && ftags.album_artist.is_empty() && ftags.album.is_empty() && ftags.genre.is_empty() {
|
let track_path = mpath.join(&dbtags.file);
|
||||||
log::error!("Failed to read tags of '{}'", dbtags.file);
|
if track_path.exists() {
|
||||||
} 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 {
|
let path = String::from(track_path.to_string_lossy());
|
||||||
match self.conn.execute("UPDATE Tracks SET Title=?, Artist=?, AlbumArtist=?, Album=?, Genre=?, Duration=? WHERE rowid=?;",
|
let ftags = tags::read(&path);
|
||||||
params![ftags.title, ftags.artist, ftags.album_artist, ftags.album, ftags.genre, ftags.duration, dbtags.rowid]) {
|
if ftags.title.is_empty() && ftags.artist.is_empty() && ftags.album_artist.is_empty() && ftags.album.is_empty() && ftags.genre.is_empty() {
|
||||||
Ok(_) => { updated += 1; },
|
log::error!("Failed to read tags of '{}'", dbtags.file);
|
||||||
Err(e) => { log::error!("Failed to update tags of '{}'. {}", dbtags.file, e); }
|
} 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
src/main.rs
41
src/main.rs
@ -34,6 +34,7 @@ fn main() {
|
|||||||
let mut task = "".to_string();
|
let mut task = "".to_string();
|
||||||
let mut lms_host = "127.0.0.1".to_string();
|
let mut lms_host = "127.0.0.1".to_string();
|
||||||
let mut max_num_tracks:usize = 0;
|
let mut max_num_tracks:usize = 0;
|
||||||
|
let mut music_paths:Vec<PathBuf> = Vec::new();
|
||||||
|
|
||||||
match dirs::home_dir() {
|
match dirs::home_dir() {
|
||||||
Some(path) => { music_path = String::from(path.join("Music").to_string_lossy()); }
|
Some(path) => { music_path = String::from(path.join("Music").to_string_lossy()); }
|
||||||
@ -90,20 +91,23 @@ fn main() {
|
|||||||
let mut config = Ini::new();
|
let mut config = Ini::new();
|
||||||
match config.load(&config_file) {
|
match config.load(&config_file) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
match config.get(TOP_LEVEL_INI_TAG, "music") {
|
let path_keys: [&str; 5] = ["music", "music_1", "music_2", "music_3", "music_4"];
|
||||||
Some(val) => { music_path = val; },
|
for key in &path_keys {
|
||||||
None => { }
|
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") {
|
match config.get(TOP_LEVEL_INI_TAG, "db") {
|
||||||
Some(val) => { db_path = val; },
|
Some(val) => { db_path = val; },
|
||||||
None => { }
|
None => { }
|
||||||
}
|
}
|
||||||
match config.get(TOP_LEVEL_INI_TAG, "lms") {
|
match config.get(TOP_LEVEL_INI_TAG, "lms") {
|
||||||
Some(val) => { lms_host = val; },
|
Some(val) => { lms_host = val; },
|
||||||
None => { }
|
None => { }
|
||||||
}
|
}
|
||||||
match config.get(TOP_LEVEL_INI_TAG, "ignore") {
|
match config.get(TOP_LEVEL_INI_TAG, "ignore") {
|
||||||
Some(val) => { ignore_file = val; },
|
Some(val) => { ignore_file = val; },
|
||||||
None => { }
|
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") {
|
if task.eq_ignore_ascii_case("stopmixer") {
|
||||||
upload::stop_mixer(&lms_host);
|
upload::stop_mixer(&lms_host);
|
||||||
} else {
|
} else {
|
||||||
@ -137,18 +145,19 @@ fn main() {
|
|||||||
process::exit(-1);
|
process::exit(-1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mpath = PathBuf::from(&music_path);
|
for mpath in &music_paths {
|
||||||
if !mpath.exists() {
|
if !mpath.exists() {
|
||||||
log::error!("Music path ({}) does not exist", music_path);
|
log::error!("Music path ({}) does not exist", mpath.to_string_lossy());
|
||||||
process::exit(-1);
|
process::exit(-1);
|
||||||
}
|
}
|
||||||
if !mpath.is_dir() {
|
if !mpath.is_dir() {
|
||||||
log::error!("Music path ({}) is not a directory", music_path);
|
log::error!("Music path ({}) is not a directory", mpath.to_string_lossy());
|
||||||
process::exit(-1);
|
process::exit(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if task.eq_ignore_ascii_case("tags") {
|
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") {
|
} else if task.eq_ignore_ascii_case("ignore") {
|
||||||
let ignore_path = PathBuf::from(&ignore_file);
|
let ignore_path = PathBuf::from(&ignore_file);
|
||||||
if !ignore_path.exists() {
|
if !ignore_path.exists() {
|
||||||
@ -161,7 +170,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
analyse::update_ignore(&db_path, &ignore_path);
|
analyse::update_ignore(&db_path, &ignore_path);
|
||||||
} else {
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user