From 09a4f91fc932ae9fea7d4aa1c066e8896e097056 Mon Sep 17 00:00:00 2001 From: Craig Drummond Date: Sun, 20 Feb 2022 11:50:52 +0000 Subject: [PATCH] Add upload option to send DB to LMS --- Cargo.lock | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 3 +- src/main.rs | 56 +++++++----- src/upload.rs | 89 ++++++++++++++++++ 4 files changed, 371 insertions(+), 23 deletions(-) create mode 100644 src/upload.rs diff --git a/Cargo.lock b/Cargo.lock index 278510a..1ac3b63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,6 +128,7 @@ dependencies = [ "regex", "rusqlite", "substring", + "ureq", ] [[package]] @@ -203,6 +204,12 @@ dependencies = [ "byte-tools", ] +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + [[package]] name = "byte-tools" version = "0.3.1" @@ -258,6 +265,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "chunked_transfer" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" + [[package]] name = "clang-sys" version = "0.29.3" @@ -474,6 +487,16 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + [[package]] name = "generic-array" version = "0.12.4" @@ -563,6 +586,17 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "1.8.0" @@ -603,6 +637,15 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -670,6 +713,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + [[package]] name = "matrixmultiply" version = "0.3.2" @@ -869,6 +918,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + [[package]] name = "pest" version = "2.1.3" @@ -1059,6 +1114,21 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + [[package]] name = "ripemd160" version = "0.9.1" @@ -1117,12 +1187,34 @@ dependencies = [ "transpose", ] +[[package]] +name = "rustls" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "sha-1" version = "0.8.2" @@ -1147,6 +1239,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "strength_reduce" version = "0.2.3" @@ -1241,6 +1339,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "transpose" version = "0.2.1" @@ -1263,6 +1376,21 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-segmentation" version = "1.9.0" @@ -1275,6 +1403,41 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "ureq" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5" +dependencies = [ + "base64", + "chunked_transfer", + "flate2", + "log", + "once_cell", + "rustls", + "url", + "webpki", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -1299,6 +1462,89 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "wasm-bindgen" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + +[[package]] +name = "web-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +dependencies = [ + "webpki", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index ade3e5d..d8bc0a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,4 +21,5 @@ lofty = { git = "https://github.com/Serial-ATA/lofty-rs", rev = "4c0b7c2" } dirs = "1" chrono = "0.4.19" regex = "1" -substring = "1.4.5" \ No newline at end of file +substring = "1.4.5" +ureq = "2.4.0" diff --git a/src/main.rs b/src/main.rs index a891303..10c1670 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ use std::process; mod analyse; mod db; mod tags; +mod upload; const VERSION: &'static str = env!("CARGO_PKG_VERSION"); @@ -26,6 +27,7 @@ fn main() { let mut keep_old:bool = false; let mut dry_run:bool = false; let mut tags_only:bool = false; + let mut upload = "".to_string(); match dirs::home_dir() { Some(path) => { music_path = String::from(path.join("Music").to_string_lossy()); } @@ -48,6 +50,7 @@ fn main() { arg_parse.refer(&mut dry_run).add_option(&["-r", "--dry-run"], StoreTrue, "Dry run, only show what needs to be done"); arg_parse.refer(&mut tags_only).add_option(&["-t", "--tags-only"], StoreTrue, "Re-read tags"); arg_parse.refer(&mut ignore_file).add_option(&["-i", "--ignore"], Store, "Update ignore status in DB"); + arg_parse.refer(&mut upload).add_option(&["-u", "--upload"], Store, "Upload database to LMS (specify hostname or IP address)"); arg_parse.parse_args_or_exit(); } @@ -70,30 +73,39 @@ fn main() { process::exit(-1); } - 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); - } - - if tags_only { - analyse::read_tags(&db_path, &mpath); - } else if !ignore_file.is_empty() { - let ignore_path = PathBuf::from(&ignore_file); - if !ignore_path.exists() { - log::error!("Ignore file ({}) does not exist", ignore_file); + if !upload.is_empty() { + if path.exists() { + upload::upload_db(&db_path, &upload); + } else { + log::error!("DB ({}) does not exist", db_path); process::exit(-1); } - if !ignore_path.is_file() { - log::error!("Ignore file ({}) is not a file", ignore_file); - process::exit(-1); - } - analyse::update_ignore(&db_path, &ignore_path); } else { - analyse::analyse_files(&db_path, &mpath, dry_run, keep_old); + 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); + } + + if tags_only { + analyse::read_tags(&db_path, &mpath); + } else if !ignore_file.is_empty() { + let ignore_path = PathBuf::from(&ignore_file); + if !ignore_path.exists() { + log::error!("Ignore file ({}) does not exist", ignore_file); + process::exit(-1); + } + if !ignore_path.is_file() { + log::error!("Ignore file ({}) is not a file", ignore_file); + process::exit(-1); + } + analyse::update_ignore(&db_path, &ignore_path); + } else { + analyse::analyse_files(&db_path, &mpath, dry_run, keep_old); + } } } diff --git a/src/upload.rs b/src/upload.rs new file mode 100644 index 0000000..8c8c092 --- /dev/null +++ b/src/upload.rs @@ -0,0 +1,89 @@ +/** + * Analyse music with Bliss + * + * Copyright (c) 2022 Craig Drummond + * GPLv3 license. + * + **/ + +use std::fs::File; +use std::io::BufReader; +use std::process; +use substring::Substring; +use ureq; + + +fn fail(msg:&str) { + log::error!("{}", msg); + process::exit(-1); +} + +pub fn upload_db(db_path:&String, lms:&String) { + // First tell LMS to restart the mixer in upload mode + let start_req = "{\"id\":1, \"method\":\"slim.request\",\"params\":[\"\",[\"blissmixer\",\"start-upload\"]]}"; + let mut port:u16 = 0; + + log::info!("Requesting LMS plugin to allow uploads"); + + match ureq::post(&format!("http://{}:9000/jsonrpc.js", lms)).send_string(&start_req) { + Ok(resp) => { + match resp.into_string() { + Ok(text) => { + match text.find("\"port\":") { + Some(s) => { + let txt = text.to_string().substring(s+7, text.len()).to_string(); + match txt.find("}") { + Some(e) => { + let p = txt.substring(0, e); + let test = p.parse::(); + match test { + Ok(val) => { + port = val; + }, + Err(_) => { fail("Could not parse resp (cast)"); } + } + }, + None => { fail("Could not parse resp (closing)"); } + } + }, + None => { fail("Could not parse resp (no port)"); } + } + }, + Err(_) => { fail("No text?")} + } + }, + Err(e) => { + fail(&format!("Failed to ask LMS plugin to allow upload. {}", e)); + } + } + + if port<=0 { + fail("Invalid port"); + } + + // Now we have port number, do the actual upload... + log::info!("Uploading {}", db_path); + match File::open(db_path) { + Ok(file) => { + match file.metadata() { + Ok(meta) => { + let buffered_reader = BufReader::new(file); + match ureq::put(&format!("http://{}:{}/upload", lms, port)).set("Content-Length", &meta.len().to_string()).send(buffered_reader) { + Ok(_) => { + log::info!("Database uploaded") + }, + Err(e) => { + fail(&format!("Failed to upload database. {}", e)); + } + } + }, + Err(e) => { + fail(&format!("Failed to open database. {}", e)); + } + } + }, + Err(e) => { + fail(&format!("Failed to open database. {}", e)); + } + } + } \ No newline at end of file