From bb4c268f822e1661015f047ec61ea71b3de20870 Mon Sep 17 00:00:00 2001 From: CDrummond Date: Wed, 17 Sep 2025 13:16:42 +0100 Subject: [PATCH] Add sending of notifications --- src/analyse.rs | 45 ++++++++++++++++++++++++++++++++++++++------- src/main.rs | 6 +++++- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/analyse.rs b/src/analyse.rs index a94fb9c..af7e099 100644 --- a/src/analyse.rs +++ b/src/analyse.rs @@ -39,6 +39,7 @@ use bliss_audio::decoder::symphonia::SymphoniaDecoder as SongDecoder; use bliss_audio::{BlissResult, Song, AnalysisOptions, decoder::Decoder}; #[cfg(not(feature = "ffmpeg"))] use bliss_audio::{AnalysisOptions, decoder::Decoder}; +use ureq; const DONT_ANALYSE: &str = ".notmusic"; const MAX_ERRORS_TO_SHOW: usize = 100; @@ -59,6 +60,13 @@ fn handle_ctrl_c() { } } +pub fn send_notif(lms_host: &String, json_port: u16, text: &str) { + let json = &format!("{{\"id\":1, \"method\":\"slim.request\",\"params\":[\"\",[\"blissmixer\",\"analyser\",\"update:{}\"]]}}", text); + + log::info!("Sending notif to LMS: {}", text); + let _ = ureq::post(&format!("http://{}:{}/jsonrpc.js", lms_host, json_port)).send_string(&json); +} + fn get_file_list(db: &mut db::Db, mpath: &Path, path: &Path, track_paths: &mut Vec, cue_tracks:&mut Vec, file_count:&mut usize, max_num_files: usize, tagged_file_count:&mut usize, dry_run: bool) { if !path.is_dir() { return; @@ -173,7 +181,8 @@ fn show_errors(failed: &mut Vec, tag_error: &mut Vec) { } #[cfg(not(feature = "ffmpeg"))] -fn analyse_new_files(db: &db::Db, mpath: &PathBuf, track_paths: Vec, max_threads: usize, write_tags: bool, preserve_mod_times: bool) -> Result<()> { +fn analyse_new_files(db: &db::Db, mpath: &PathBuf, track_paths: Vec, max_threads: usize, write_tags: bool, + preserve_mod_times: bool, lms_host: &String, json_port: u16, send_notifs: bool) -> Result<()> { let total = track_paths.len(); let progress = ProgressBar::new(total.try_into().unwrap()).with_style( ProgressStyle::default_bar() @@ -186,6 +195,7 @@ fn analyse_new_files(db: &db::Db, mpath: &PathBuf, track_paths: Vec, max _ => NonZeroUsize::new(max_threads).unwrap(), }; + let mut last_update = 0; let mut analysed = 0; let mut failed: Vec = Vec::new(); let mut tag_error: Vec = Vec::new(); @@ -197,7 +207,11 @@ fn analyse_new_files(db: &db::Db, mpath: &PathBuf, track_paths: Vec, max options.number_cores = cpu_threads; } - log::info!("Analysing new files"); + if send_notifs { + send_notif(lms_host, json_port, " 0%"); + } else { + log::info!("Analysing new files"); + } for (path, result) in SongDecoder::analyze_paths_with_options(track_paths, options) { let stripped = path.strip_prefix(mpath).unwrap(); let spbuff = stripped.to_path_buf(); @@ -268,6 +282,14 @@ fn analyse_new_files(db: &db::Db, mpath: &PathBuf, track_paths: Vec, max if inc_progress { progress.inc(1); + if send_notifs { + let val = (progress.position()/((total as u64)*100)) as u64 ; + if val!=last_update { + last_update = val; + let secs = progress.eta().as_secs(); + send_notif(lms_host, json_port, &format!("{:3}% ({:02}:{:02}:{:02})", last_update, (secs/60)/60, (secs/60)%60, secs%60)); + } + } } if terminate_analysis() { break @@ -285,7 +307,8 @@ fn analyse_new_files(db: &db::Db, mpath: &PathBuf, track_paths: Vec, max } #[cfg(feature = "ffmpeg")] -fn analyse_new_files(db: &db::Db, mpath: &PathBuf, track_paths: Vec, max_threads: usize, write_tags: bool, preserve_mod_times: bool) -> Result<()> { +fn analyse_new_files(db: &db::Db, mpath: &PathBuf, track_paths: Vec, max_threads: usize, write_tags: bool, + preserve_mod_times: bool, lms_host: &String, json_port: u16, send_notifs: bool) -> Result<()> { let total = track_paths.len(); let progress = ProgressBar::new(total.try_into().unwrap()).with_style( ProgressStyle::default_bar() @@ -454,7 +477,9 @@ fn analyse_new_cue_tracks(db:&db::Db, mpath: &PathBuf, cue_tracks:Vec, dry_run: bool, keep_old: bool, max_num_files: usize, max_threads: usize, ignore_path: &PathBuf, write_tags: bool, preserve_mod_times: bool) -> bool { +pub fn analyse_files(db_path: &str, mpaths: &Vec, dry_run: bool, keep_old: bool, max_num_files: usize, + max_threads: usize, ignore_path: &PathBuf, write_tags: bool, preserve_mod_times: bool, + lms_host: &String, json_port: u16, send_notifs: bool) -> bool { let mut db = db::Db::new(&String::from(db_path)); ctrlc::set_handler(move || { @@ -476,8 +501,14 @@ pub fn analyse_files(db_path: &str, mpaths: &Vec, dry_run: bool, keep_o let mut file_count:usize = 0; let mut tagged_file_count:usize = 0; - if mpaths.len() > 1 { - log::info!("Looking for new files in {}", mpath.to_string_lossy()); + if send_notifs { + send_notif(lms_host, json_port, "Looking for new files"); + } else if mpaths.len() > 1 { + if send_notifs { + send_notif(lms_host, json_port, "Looking for new files"); + } else { + log::info!("Looking for new files in {}", mpath.to_string_lossy()); + } } else { log::info!("Looking for new files"); } @@ -502,7 +533,7 @@ pub fn analyse_files(db_path: &str, mpaths: &Vec, dry_run: bool, keep_o } } else { if !track_paths.is_empty() { - match analyse_new_files(&db, &mpath, track_paths, max_threads, write_tags, preserve_mod_times) { + match analyse_new_files(&db, &mpath, track_paths, max_threads, write_tags, preserve_mod_times, lms_host, json_port, send_notifs) { Ok(_) => { changes_made = true; } Err(e) => { log::error!("Analysis returned error: {}", e); } } diff --git a/src/main.rs b/src/main.rs index c0acb5e..a74717d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,6 +47,7 @@ fn main() { let mut max_threads: usize = 0; let mut write_tags = false; let mut preserve_mod_times = false; + let mut send_notifs = false; match dirs::home_dir() { Some(path) => { @@ -87,6 +88,7 @@ fn main() { arg_parse.refer(&mut max_threads).add_option(&["-t", "--threads"], Store, "Maximum number of threads to use for analysis"); arg_parse.refer(&mut write_tags).add_option(&["-T", "--tags"], StoreTrue, "When analysing files, also store results within files themselves"); arg_parse.refer(&mut preserve_mod_times).add_option(&["-p", "--preserve"], StoreTrue, "Preserve modification time when writing results to files"); + arg_parse.refer(&mut send_notifs).add_option(&["-N", "--notifs"], StoreTrue, "Periodically send notification messages to LMS"); arg_parse.refer(&mut task).add_argument("task", Store, "Task to perform; analyse, tags, ignore, upload, export, stopmixer."); arg_parse.parse_args_or_exit(); } @@ -238,7 +240,9 @@ fn main() { db::export(&db_path, &music_paths, max_threads, preserve_mod_times); } else { let ignore_path = PathBuf::from(&ignore_file); - let modified = analyse::analyse_files(&db_path, &music_paths, dry_run, keep_old, max_num_files, max_threads, &ignore_path, write_tags, preserve_mod_times); + let modified = analyse::analyse_files(&db_path, &music_paths, dry_run, keep_old, max_num_files, max_threads, + &ignore_path, write_tags, preserve_mod_times, &lms_host, lms_json_port, + send_notifs); if modified && task.eq_ignore_ascii_case("analyse-lms") && path.exists() { upload::stop_mixer(&lms_host, lms_json_port); }