diff --git a/music_mgr/Cargo.lock b/music_mgr/Cargo.lock index 27ea056..aed264f 100644 --- a/music_mgr/Cargo.lock +++ b/music_mgr/Cargo.lock @@ -266,15 +266,18 @@ dependencies = [ name = "music_mgr" version = "0.1.0" dependencies = [ + "anstyle", "anyhow", "camino", "clap", "env_logger", "lazy_static", + "libc", "log", "serde", "serde_json", "tokio", + "windows", ] [[package]] @@ -464,6 +467,59 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "windows" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" +dependencies = [ + "windows-core", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-core" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-implement" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -479,7 +535,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -499,17 +555,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -520,9 +577,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -532,9 +589,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -544,9 +601,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -556,9 +619,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -568,9 +631,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -580,9 +643,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -592,6 +655,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/music_mgr/Cargo.toml b/music_mgr/Cargo.toml index b473d1f..9c34ecf 100644 --- a/music_mgr/Cargo.toml +++ b/music_mgr/Cargo.toml @@ -6,12 +6,15 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anstyle = "1.0.6" anyhow = "1.0.81" camino = "1.1.6" clap = { version = "4.5.4", features = ["derive"] } env_logger = "0.11.3" lazy_static = "1.4.0" +libc = "0.2.153" log = "0.4.21" serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" tokio = { version = "1.37.0", features = ["macros", "rt-multi-thread", "process", "sync"] } +windows = { version = "0.56.0", features = ["Win32_Foundation", "Win32_Storage_FileSystem", "Win32_System_Console"] } diff --git a/music_mgr/src/cli.rs b/music_mgr/src/cli.rs index c979ad9..198db3e 100644 --- a/music_mgr/src/cli.rs +++ b/music_mgr/src/cli.rs @@ -1,6 +1,8 @@ use camino::Utf8PathBuf; use clap::{Parser, Subcommand}; +use crate::util::isatty; + #[derive(Debug, Parser)] pub struct CliArgs { /// Show more info @@ -17,6 +19,9 @@ pub struct CliArgs { #[command(subcommand)] pub command: Option, + + #[clap(skip)] + pub is_tty: bool } #[derive(Debug, Subcommand, Default)] @@ -28,4 +33,11 @@ pub enum CliCommand { name: String, genre: String } +} + +impl CliArgs { + pub fn populate_extra(&mut self) -> &mut Self{ + self.is_tty = isatty(); + self + } } \ No newline at end of file diff --git a/music_mgr/src/commands/mod.rs b/music_mgr/src/commands/mod.rs new file mode 100644 index 0000000..88e673d --- /dev/null +++ b/music_mgr/src/commands/mod.rs @@ -0,0 +1,22 @@ +use crate::{cli::{CliArgs, CliCommand}, downloader::Downloader, manifest::Manifest, util}; + + +pub async fn command_run(cli: &CliArgs, manifest: &Manifest) { + let mut downloader = Downloader::new(util::get_ytdlp_path()); + match &cli.command { + None | Some(CliCommand::Download) => { + if let Ok(count) = downloader.download_all(manifest, &cli).await { + log::info!("Downloaded {count} songs"); + } else { + log::error!("Failed to download songs"); + return; + } + }, + Some(c) => { + match c { + CliCommand::Download => unreachable!(), + CliCommand::Add { .. } => todo!(), + } + } + } +} \ No newline at end of file diff --git a/music_mgr/src/downloader.rs b/music_mgr/src/downloader.rs index 9920407..ff34d48 100644 --- a/music_mgr/src/downloader.rs +++ b/music_mgr/src/downloader.rs @@ -33,7 +33,7 @@ impl Downloader { } } - pub async fn download_all(&mut self, manifest: Manifest, cli: &CliArgs) -> anyhow::Result { + pub async fn download_all(&mut self, manifest: &Manifest, cli: &CliArgs) -> anyhow::Result { let format = manifest.format()?; for (genre, songs) in &manifest.genres { diff --git a/music_mgr/src/main.rs b/music_mgr/src/main.rs index 2a8f87f..18b9e4f 100644 --- a/music_mgr/src/main.rs +++ b/music_mgr/src/main.rs @@ -7,11 +7,15 @@ mod manifest; mod logger; mod downloader; mod util; +mod commands; +mod prompt; #[tokio::main] async fn main() { - let cli_args = CliArgs::parse(); + let mut cli_args = CliArgs::parse(); + cli_args.populate_extra(); logger::init_logger(cli_args.debug); + let manifest = match manifest::Manifest::from_path(&cli_args.manifest.as_std_path()) { Ok(m) => m, Err(e) => { @@ -20,22 +24,6 @@ async fn main() { } }; - let mut downloader = Downloader::new(util::get_ytdlp_path()); - - match cli_args.command { - None | Some(CliCommand::Download) => { - if let Ok(count) = downloader.download_all(manifest, &cli_args).await { - log::info!("Downloaded {count} songs"); - } else { - log::error!("Failed to download songs"); - return; - } - }, - Some(c) => { - match c { - CliCommand::Download => unreachable!(), - CliCommand::Add { .. } => todo!(), - } - } - } + + commands::command_run(&cli_args, &manifest); } diff --git a/music_mgr/src/prompt.rs b/music_mgr/src/prompt.rs new file mode 100644 index 0000000..a7b1362 --- /dev/null +++ b/music_mgr/src/prompt.rs @@ -0,0 +1,75 @@ +use std::{collections::HashMap, io::Write}; + + + +pub fn simple_prompt(p: &str) -> String { + + print!("{c}prompt{r}: {p}", + c=anstyle::AnsiColor::Magenta.render_fg(), + r=anstyle::Style::new().render_reset() + ); + + // I dont care if it fails + let _ = std::io::stdout().flush(); + + let mut buf = String::new(); + let _ = std::io::stdin().read_line(&mut buf); + + buf +} + +pub fn prompt_with_options(p: &str, options: &[&str]) -> usize { + println!("{c}prompt{r}: {p}", + c=anstyle::AnsiColor::Magenta.render_fg(), + r=anstyle::Style::new().render_reset() + ); + + for (i, op) in options.iter().enumerate() { + println!(" - {}: {}", i, op); + } + + print!("> "); + // I dont care if it fails + let _ = std::io::stdout().flush(); + + let mut buf = String::new(); + let _ = std::io::stdin().read_line(&mut buf); + + if let Ok(num) = buf.parse::() { + if num <= options.len() { + return num; + } else { + log::error!("Number not in range"); + return prompt_with_options(p, options); + } + } else { + log::error!("Not a number"); + return prompt_with_options(p, options); + } +} + +pub fn prompt_with_named_options(p: &str, options: HashMap<&str, &str>) -> String { + println!("{c}prompt{r}: {p}", + c=anstyle::AnsiColor::Magenta.render_fg(), + r=anstyle::Style::new().render_reset() + ); + + let mut keys = Vec::new(); + + for (k, v) in &options { + println!(" - {}: {}", k, v); + keys.push(k.trim().to_lowercase()) + } + + print!("> "); + + // I dont care if it fails + let _ = std::io::stdout().flush(); + + let mut buf = String::new(); + let _ = std::io::stdin().read_line(&mut buf); + if !keys.contains(&buf.trim().to_lowercase()) { + return prompt_with_named_options(p, options); + } + buf +} diff --git a/music_mgr/src/util.rs b/music_mgr/src/util.rs index 4522c82..2b9ed5c 100644 --- a/music_mgr/src/util.rs +++ b/music_mgr/src/util.rs @@ -19,4 +19,30 @@ pub fn get_ytdlp_path() -> String { } // TODO: Download yt-dlp to ./.bin/yt-dlp if doesnt exist todo!() +} + +#[cfg(target_family="unix")] +pub fn isatty() -> bool { + use std::{ffi::c_int, os::fd::AsRawFd}; + unsafe { + let fd = std::io::stdin().as_raw_fd(); + libc::isatty(fd as c_int) == 1 + } +} + +#[cfg(target_family="windows")] +pub fn isatty() -> bool { + unsafe { + use windows::Win32::System::Console; + use Console::{CONSOLE_MODE, STD_OUTPUT_HANDLE}; + let Ok(handle) = Console::GetStdHandle(STD_OUTPUT_HANDLE) else { + return false; + }; + + let mut out = CONSOLE_MODE(0); + + let ret = Console::GetConsoleMode(handle, &mut out); + + ret.is_ok() + } } \ No newline at end of file