This commit is contained in:
2024-08-12 02:16:58 +02:00
parent 692cb43e9f
commit 5905bd6b15
5 changed files with 161 additions and 24 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
/target /target
Cargo.lock Cargo.lock
/images /images
/cba
*.jpg *.jpg
*.png *.png

View File

@@ -14,7 +14,7 @@ type Client = ClientWithMiddleware;
#[tokio::main] #[tokio::main]
async fn 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 retry_policy = ExponentialBackoff::builder().build_with_max_retries(3);
let client = ClientBuilder::new( let client = ClientBuilder::new(
reqwest::Client::builder() reqwest::Client::builder()
@@ -29,7 +29,13 @@ async fn main() {
//("status[]", "completed"), //("status[]", "completed"),
// ("contentRating[]", "suggestive"), // ("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![]; let mut entries = vec![];
for result in results.data.iter() { for result in results.data.iter() {
let mut entry = Entry::new(result.attributes.title.en.clone()); let mut entry = Entry::new(result.attributes.title.en.clone());
@@ -63,18 +69,28 @@ async fn main() {
.unwrap(); .unwrap();
let result = util::convert_to_sixel(&data); let result = util::convert_to_sixel(&data);
entry.add_image(result) entry.set_image(result)
} }
entries.push(entry); 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 choice_id = &results.data[choice as usize].id;
let bonus = loop { let bonus = if let Some(bonus) = config.bonus {
bonus
} else {
loop {
match util::get_input("Read bonus chapters? [y/n] : ").as_str() { match util::get_input("Read bonus chapters? [y/n] : ").as_str() {
"y" | "yes" => break true, "y" | "yes" => break true,
"n" | "no" => break false, "n" | "no" => break false,
_ => continue, _ => continue,
} }
}
}; };
let mut chapters = match get_chapters(&client, choice_id).await { let mut chapters = match get_chapters(&client, choice_id).await {
Ok(v) => v, Ok(v) => v,
@@ -217,8 +233,12 @@ async fn get_chapters(client: &Client, id: &Id) -> Result<Vec<Chapter>, reqwest_
Ok(result.data) Ok(result.data)
} }
async fn search(client: &Client, query: &str, filters: &[(&str, &str)]) -> SearchResult { async fn search(
let limit = 10; client: &Client,
query: &str,
filters: &[(&str, &str)],
limit: u32,
) -> SearchResult {
let params = [ let params = [
("title", query), ("title", query),
("limit", &limit.to_string()), ("limit", &limit.to_string()),

View File

@@ -14,6 +14,17 @@ pub enum ResponseResult {
#[derive(Debug)] #[derive(Debug)]
pub enum Language { pub enum Language {
Tagalog,
SimplifiedChinese,
Greek,
Persian,
TraditionalChinese,
Ukranian,
Romanian,
Arabic,
German,
Vietnamese,
French,
Turkish, Turkish,
Korean, Korean,
SpanishLatinAmerican, SpanishLatinAmerican,
@@ -412,6 +423,17 @@ impl TryInto<Language> for &str {
"eo" => Language::Esperanto, "eo" => Language::Esperanto,
"pl" => Language::Polish, "pl" => Language::Polish,
"ko" => Language::Korean, "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(()), _ => return Err(()),
}) })
} }

View File

@@ -45,7 +45,7 @@ impl Entry {
self.info.push((key.to_owned(), value.to_string())); 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); self.image = Some(sixel_data);
} }
} }
@@ -64,7 +64,7 @@ fn get_input() -> Option<Action> {
}), }),
Err(e) => { Err(e) => {
eprintln!("ERROR: {:#?}", e); eprintln!("ERROR: {:#?}", e);
std::process::exit(1); exit();
} }
_ => None, _ => None,
} }
@@ -72,7 +72,7 @@ fn get_input() -> Option<Action> {
Ok(false) => None, Ok(false) => None,
Err(e) => { Err(e) => {
eprintln!("ERROR: {:#?}", e); eprintln!("ERROR: {:#?}", e);
std::process::exit(1); exit();
} }
} }
} }
@@ -138,6 +138,9 @@ fn render(
selected: u16, selected: u16,
offset: u16, offset: u16,
) -> Result<(), io::Error> { ) -> Result<(), io::Error> {
if entries.is_empty() {
return Ok(());
}
stdout.queue(MoveTo(0, 0))?.queue(Clear(ClearType::All))?; stdout.queue(MoveTo(0, 0))?.queue(Clear(ClearType::All))?;
for (i, entry) in entries.iter().enumerate() { for (i, entry) in entries.iter().enumerate() {
stdout stdout

View File

@@ -1,5 +1,6 @@
use crate::Chapter; use crate::Chapter;
use icy_sixel::{DiffusionMethod, MethodForLargest, MethodForRep, PixelFormat, Quality}; use icy_sixel::{DiffusionMethod, MethodForLargest, MethodForRep, PixelFormat, Quality};
use image::DynamicImage;
use std::{io, io::Write}; use std::{io, io::Write};
pub struct Selection { pub struct Selection {
@@ -35,6 +36,12 @@ pub enum ChapterSelection {
Single(f32), Single(f32),
} }
pub struct Config {
pub bonus: Option<bool>,
pub search: Option<String>,
pub result_limit: u32,
}
fn filter_bonus(bonus: bool, volume: Option<u32>, chapter: Option<f32>) -> bool { fn filter_bonus(bonus: bool, volume: Option<u32>, chapter: Option<f32>) -> bool {
if bonus { if bonus {
return true; return true;
@@ -231,18 +238,40 @@ pub fn get_input(msg: &str) -> String {
} }
pub fn convert_to_sixel(data: &[u8]) -> String { pub fn convert_to_sixel(data: &[u8]) -> String {
let a = image::load_from_memory(data).unwrap(); let image = image::load_from_memory(data).unwrap();
let a = a.as_rgb8().unwrap(); let mut pixels = Vec::new();
let mut pixels = vec![]; match &image {
a.pixels().for_each(|m| { DynamicImage::ImageRgb8(image) => image.pixels().for_each(|m| {
pixels.push(m.0[0]); pixels.push(m.0[0]);
pixels.push(m.0[1]); pixels.push(m.0[1]);
pixels.push(m.0[2]); 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( icy_sixel::sixel_string(
&pixels, &pixels,
a.width() as i32, image.width() as i32,
a.height() as i32, image.height() as i32,
PixelFormat::RGB888, PixelFormat::RGB888,
DiffusionMethod::Auto, DiffusionMethod::Auto,
MethodForLargest::Auto, MethodForLargest::Auto,
@@ -253,3 +282,65 @@ pub fn convert_to_sixel(data: &[u8]) -> String {
} }
// pub fn convert_to_/ // 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
}