initial
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
/target
|
/target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
/images
|
/images
|
||||||
|
/cba
|
||||||
*.jpg
|
*.jpg
|
||||||
*.png
|
*.png
|
||||||
|
|||||||
42
src/main.rs
42
src/main.rs
@@ -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,17 +69,27 @@ 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 {
|
||||||
match util::get_input("Read bonus chapters? [y/n] : ").as_str() {
|
bonus
|
||||||
"y" | "yes" => break true,
|
} else {
|
||||||
"n" | "no" => break false,
|
loop {
|
||||||
_ => continue,
|
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 {
|
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)
|
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()),
|
||||||
|
|||||||
@@ -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(()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
111
src/util.rs
111
src/util.rs
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user