initial
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
/images
|
||||
/cba
|
||||
*.jpg
|
||||
*.png
|
||||
|
||||
42
src/main.rs
42
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<Vec<Chapter>, 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()),
|
||||
|
||||
@@ -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<Language> 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(()),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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<Action> {
|
||||
}),
|
||||
Err(e) => {
|
||||
eprintln!("ERROR: {:#?}", e);
|
||||
std::process::exit(1);
|
||||
exit();
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
@@ -72,7 +72,7 @@ fn get_input() -> Option<Action> {
|
||||
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
|
||||
|
||||
111
src/util.rs
111
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<bool>,
|
||||
pub search: Option<String>,
|
||||
pub result_limit: u32,
|
||||
}
|
||||
|
||||
fn filter_bonus(bonus: bool, volume: Option<u32>, chapter: Option<f32>) -> 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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user