diff --git a/.gitignore b/.gitignore index 6b61b43..bca458a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /target Cargo.lock /images +/cba *.jpg *.png diff --git a/src/main.rs b/src/main.rs index 547735e..ba9f7bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ type Client = ClientWithMiddleware; #[tokio::main] async fn main() { - let input = util::get_input("Enter search query: "); + let config = util::args(); let retry_policy = ExponentialBackoff::builder().build_with_max_retries(3); let client = ClientBuilder::new( reqwest::Client::builder() @@ -29,7 +29,13 @@ async fn main() { //("status[]", "completed"), // ("contentRating[]", "suggestive"), ]; - let results = search(&client, &input, &filters).await; + let limit = config.result_limit; + let results = if let Some(query) = config.search { + search(&client, &query, &filters, limit).await + } else { + let input = util::get_input("Enter search query: "); + search(&client, &input, &filters, limit).await + }; let mut entries = vec![]; for result in results.data.iter() { let mut entry = Entry::new(result.attributes.title.en.clone()); @@ -63,17 +69,27 @@ async fn main() { .unwrap(); let result = util::convert_to_sixel(&data); - entry.add_image(result) + entry.set_image(result) } entries.push(entry); } - let choice = select::select(&entries).unwrap(); + let choice = match select::select(&entries) { + Ok(v) => v, + Err(e) => { + eprintln!("ERROR: Failed to select: {:?}", e); + std::process::exit(1); + } + }; let choice_id = &results.data[choice as usize].id; - let bonus = loop { - match util::get_input("Read bonus chapters? [y/n] : ").as_str() { - "y" | "yes" => break true, - "n" | "no" => break false, - _ => continue, + let bonus = if let Some(bonus) = config.bonus { + bonus + } else { + loop { + match util::get_input("Read bonus chapters? [y/n] : ").as_str() { + "y" | "yes" => break true, + "n" | "no" => break false, + _ => continue, + } } }; let mut chapters = match get_chapters(&client, choice_id).await { @@ -217,8 +233,12 @@ async fn get_chapters(client: &Client, id: &Id) -> Result, reqwest_ Ok(result.data) } -async fn search(client: &Client, query: &str, filters: &[(&str, &str)]) -> SearchResult { - let limit = 10; +async fn search( + client: &Client, + query: &str, + filters: &[(&str, &str)], + limit: u32, +) -> SearchResult { let params = [ ("title", query), ("limit", &limit.to_string()), diff --git a/src/response_deserializer.rs b/src/response_deserializer.rs index 2ae38df..a6ad7d2 100644 --- a/src/response_deserializer.rs +++ b/src/response_deserializer.rs @@ -14,6 +14,17 @@ pub enum ResponseResult { #[derive(Debug)] pub enum Language { + Tagalog, + SimplifiedChinese, + Greek, + Persian, + TraditionalChinese, + Ukranian, + Romanian, + Arabic, + German, + Vietnamese, + French, Turkish, Korean, SpanishLatinAmerican, @@ -412,6 +423,17 @@ impl TryInto for &str { "eo" => Language::Esperanto, "pl" => Language::Polish, "ko" => Language::Korean, + "fr" => Language::French, + "vi" => Language::Vietnamese, + "de" => Language::German, + "ar" => Language::Arabic, + "ro" => Language::Romanian, + "uk" => Language::Ukranian, + "zh-hk" => Language::TraditionalChinese, + "fa" => Language::Persian, + "el" => Language::Greek, + "zh" => Language::SimplifiedChinese, + "tl" => Language::Tagalog, _ => return Err(()), }) } diff --git a/src/select.rs b/src/select.rs index 6414aa6..786663f 100644 --- a/src/select.rs +++ b/src/select.rs @@ -45,7 +45,7 @@ impl Entry { self.info.push((key.to_owned(), value.to_string())); } - pub fn add_image(&mut self, sixel_data: String) { + pub fn set_image(&mut self, sixel_data: String) { self.image = Some(sixel_data); } } @@ -64,7 +64,7 @@ fn get_input() -> Option { }), Err(e) => { eprintln!("ERROR: {:#?}", e); - std::process::exit(1); + exit(); } _ => None, } @@ -72,7 +72,7 @@ fn get_input() -> Option { Ok(false) => None, Err(e) => { eprintln!("ERROR: {:#?}", e); - std::process::exit(1); + exit(); } } } @@ -138,6 +138,9 @@ fn render( selected: u16, offset: u16, ) -> Result<(), io::Error> { + if entries.is_empty() { + return Ok(()); + } stdout.queue(MoveTo(0, 0))?.queue(Clear(ClearType::All))?; for (i, entry) in entries.iter().enumerate() { stdout diff --git a/src/util.rs b/src/util.rs index a237401..dc88e82 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,6 @@ use crate::Chapter; use icy_sixel::{DiffusionMethod, MethodForLargest, MethodForRep, PixelFormat, Quality}; +use image::DynamicImage; use std::{io, io::Write}; pub struct Selection { @@ -35,6 +36,12 @@ pub enum ChapterSelection { Single(f32), } +pub struct Config { + pub bonus: Option, + pub search: Option, + pub result_limit: u32, +} + fn filter_bonus(bonus: bool, volume: Option, chapter: Option) -> bool { if bonus { return true; @@ -231,18 +238,40 @@ pub fn get_input(msg: &str) -> String { } pub fn convert_to_sixel(data: &[u8]) -> String { - let a = image::load_from_memory(data).unwrap(); - let a = a.as_rgb8().unwrap(); - let mut pixels = vec![]; - a.pixels().for_each(|m| { - pixels.push(m.0[0]); - pixels.push(m.0[1]); - pixels.push(m.0[2]); - }); + let image = image::load_from_memory(data).unwrap(); + let mut pixels = Vec::new(); + match &image { + DynamicImage::ImageRgb8(image) => image.pixels().for_each(|m| { + pixels.push(m.0[0]); + pixels.push(m.0[1]); + pixels.push(m.0[2]); + }), + DynamicImage::ImageRgba8(image) => image.pixels().for_each(|m| { + pixels.push(m.0[0]); + pixels.push(m.0[1]); + pixels.push(m.0[2]); + }), + DynamicImage::ImageLuma8(image) => image.pixels().for_each(|m| { + pixels.push(m.0[0]); + pixels.push(m.0[0]); + pixels.push(m.0[0]); + }), + DynamicImage::ImageLumaA8(_) => println!("Found lumaa8 image"), + DynamicImage::ImageRgb16(_) => println!("Found rgb16 image"), + DynamicImage::ImageLuma16(_) => println!("Found luma16 image"), + DynamicImage::ImageRgba16(_) => println!("Found rgba16 image"), + _ => panic!(), + } + // let mut pixels = vec![]; + // a.pixels().for_each(|m| { + // pixels.push(m.0[0]); + // pixels.push(m.0[1]); + // pixels.push(m.0[2]); + // }); icy_sixel::sixel_string( &pixels, - a.width() as i32, - a.height() as i32, + image.width() as i32, + image.height() as i32, PixelFormat::RGB888, DiffusionMethod::Auto, MethodForLargest::Auto, @@ -253,3 +282,65 @@ pub fn convert_to_sixel(data: &[u8]) -> String { } // pub fn convert_to_/ +// + +impl Config { + fn new() -> Self { + Self { + bonus: None, + search: None, + result_limit: 5, + } + } +} + +pub fn args() -> Config { + let mut args = std::env::args().skip(1); + + let mut config = Config::new(); + while args.len() != 0 { + match args.next().unwrap().as_ref() { + "-s" | "--search" => { + if let Some(query) = args.next() { + config.search = Some(query); + } else { + eprintln!("Missing query for search"); + std::process::exit(1); + } + } + "-b" | "--bonus" => { + config.bonus = match args.next() { + Some(a) => Some(match a.as_str() { + "true" => true, + "false" => false, + _ => { + eprintln!("Invalid value for bonus, type: bool"); + std::process::exit(1); + } + }), + None => { + eprintln!("Missing value for bonus, type: bool"); + std::process::exit(1); + } + }; + } + "-r" | "--result-limit" => { + config.result_limit = match args.next() { + Some(a) => match a.parse() { + Ok(v) => v, + Err(e) => { + eprintln!("Failed to parse value for result-limit: {:?}, type: u32", e); + std::process::exit(1); + } + }, + None => { + eprintln!("Missing value for bonus, type: u32"); + std::process::exit(1); + } + }; + } + _ => (), + } + } + config +}