cargo fmt
This commit is contained in:
parent
9ca4dda9d9
commit
c2ea9b87b0
17
src/api.rs
17
src/api.rs
|
@ -2,18 +2,23 @@ use crate::structs;
|
|||
|
||||
extern crate serde_json;
|
||||
|
||||
pub async fn get_sauce_info(client: reqwest::Client, sauce: i32) -> Result<structs::GalleryInfo, reqwest::Error> {
|
||||
pub async fn get_sauce_info(
|
||||
client: reqwest::Client,
|
||||
sauce: i32,
|
||||
) -> Result<structs::GalleryInfo, reqwest::Error> {
|
||||
let mut uri = String::from("https://nhentai.net/api/gallery/");
|
||||
uri.push_str(&sauce.to_string());
|
||||
let resp = client.get(&uri)
|
||||
.send()
|
||||
.await?;
|
||||
let resp = client.get(&uri).send().await?;
|
||||
Ok(serde_json::from_str(&resp.text().await?).unwrap())
|
||||
}
|
||||
|
||||
pub async fn get_search_info(client: reqwest::Client, search_query: &str) -> Result<structs::SearchInfo, reqwest::Error> {
|
||||
pub async fn get_search_info(
|
||||
client: reqwest::Client,
|
||||
search_query: &str,
|
||||
) -> Result<structs::SearchInfo, reqwest::Error> {
|
||||
let uri = "https://nhentai.net/api/galleries/search";
|
||||
let resp = client.get(uri)
|
||||
let resp = client
|
||||
.get(uri)
|
||||
.query(&[("query", search_query)])
|
||||
.send()
|
||||
.await?;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
mod view;
|
||||
mod search;
|
||||
mod download;
|
||||
mod search;
|
||||
mod view;
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
@ -21,9 +21,12 @@ pub async fn run() {
|
|||
"search" => search::run(args).await,
|
||||
"view" | "show" | "info" => view::run(args).await,
|
||||
"download" | "dl" => download::run(args).await,
|
||||
"help" => println!(r#"Usage: {} search QUERY
|
||||
"help" => println!(
|
||||
r#"Usage: {} search QUERY
|
||||
or {} info/view/show SAUCE [SAUCE]...
|
||||
or {} download/dl SAUCE [SAUCE]..."#, path, path, path),
|
||||
or {} download/dl SAUCE [SAUCE]..."#,
|
||||
path, path, path
|
||||
),
|
||||
_ => {
|
||||
eprintln!("Unknown operation, run `{} help`", path);
|
||||
exit(1)
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
use crate::api;
|
||||
use crate::utils;
|
||||
use crate::structs;
|
||||
use crate::utils;
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::fs::{create_dir, rename, write};
|
||||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::{sleep, Duration};
|
||||
use std::fs::{rename, create_dir, write};
|
||||
extern crate tokio;
|
||||
extern crate reqwest;
|
||||
extern crate tokio;
|
||||
|
||||
const DOWNLOAD_WORKERS: usize = 5;
|
||||
const FAIL_DOWNLOAD_WAIT_TIME: u64 = 5000;
|
||||
|
@ -27,14 +27,17 @@ pub async fn run(args: env::Args) {
|
|||
let client = reqwest::Client::new();
|
||||
let mut pages_vec: Vec<(String, String)> = Vec::new();
|
||||
{
|
||||
let mut handles: Vec<JoinHandle<structs::GalleryInfoSuccess>> = Vec::with_capacity(sauces.len());
|
||||
let mut handles: Vec<JoinHandle<structs::GalleryInfoSuccess>> =
|
||||
Vec::with_capacity(sauces.len());
|
||||
let mut sauce_info_vec: Vec<structs::GalleryInfoSuccess> = Vec::with_capacity(sauces.len());
|
||||
for sauce in sauces {
|
||||
let cloned_client = client.clone();
|
||||
handles.push(tokio::spawn(async move {
|
||||
match api::get_sauce_info(cloned_client, sauce).await.unwrap() {
|
||||
structs::GalleryInfo::Info(sauce_info) => sauce_info,
|
||||
structs::GalleryInfo::Error(sauce_error) => panic!("{} returned: {}", sauce, sauce_error.error)
|
||||
structs::GalleryInfo::Error(sauce_error) => {
|
||||
panic!("{} returned: {}", sauce, sauce_error.error)
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -48,8 +51,8 @@ pub async fn run(args: env::Args) {
|
|||
Ok(()) => write(base_path.join("info.txt"), format!("{}\n", &sauce_info)).unwrap(),
|
||||
Err(err) => match err.kind() {
|
||||
std::io::ErrorKind::AlreadyExists => (),
|
||||
_ => panic!("Got a weird error while creating dir: {}", err)
|
||||
}
|
||||
_ => panic!("Got a weird error while creating dir: {}", err),
|
||||
},
|
||||
};
|
||||
let mut page_num: i32 = 1;
|
||||
for page in sauce_info.images.pages {
|
||||
|
@ -57,7 +60,7 @@ pub async fn run(args: env::Args) {
|
|||
"j" => ".jpg",
|
||||
"p" => ".png",
|
||||
"g" => ".gif",
|
||||
_ => panic!("Unknown extension type: {}", page.t)
|
||||
_ => panic!("Unknown extension type: {}", page.t),
|
||||
};
|
||||
let mut file_name = page_num.to_string();
|
||||
file_name.push_str(file_ext);
|
||||
|
@ -65,9 +68,10 @@ pub async fn run(args: env::Args) {
|
|||
if !file_path.exists() {
|
||||
pages_vec.push((
|
||||
String::from(file_path.to_str().unwrap()),
|
||||
format!("https://i.nhentai.net/galleries/{}/{}",
|
||||
sauce_info.media_id,
|
||||
file_name)
|
||||
format!(
|
||||
"https://i.nhentai.net/galleries/{}/{}",
|
||||
sauce_info.media_id, file_name
|
||||
),
|
||||
));
|
||||
}
|
||||
page_num += 1;
|
||||
|
@ -101,8 +105,11 @@ pub async fn run(args: env::Args) {
|
|||
if success {
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(err) => eprintln!("[DW{}] Failed to download {} due to {}, sleeping for {}ms", worker_id, file_path, err, FAIL_DOWNLOAD_WAIT_TIME)
|
||||
}
|
||||
Err(err) => eprintln!(
|
||||
"[DW{}] Failed to download {} due to {}, sleeping for {}ms",
|
||||
worker_id, file_path, err, FAIL_DOWNLOAD_WAIT_TIME
|
||||
),
|
||||
};
|
||||
sleep(Duration::from_millis(FAIL_DOWNLOAD_WAIT_TIME)).await;
|
||||
}
|
||||
|
@ -116,18 +123,19 @@ pub async fn run(args: env::Args) {
|
|||
}
|
||||
}
|
||||
|
||||
async fn download_file(client: reqwest::Client, url: &str, file_name: &str) -> Result<bool, reqwest::Error> {
|
||||
let resp = client.get(url)
|
||||
.send()
|
||||
.await?;
|
||||
async fn download_file(
|
||||
client: reqwest::Client,
|
||||
url: &str,
|
||||
file_name: &str,
|
||||
) -> Result<bool, reqwest::Error> {
|
||||
let resp = client.get(url).send().await?;
|
||||
Ok(match resp.headers().get("Content-Type") {
|
||||
Some(header) if header.to_str().unwrap_or_default().starts_with("image/") => {
|
||||
let bytes = resp.bytes().await?;
|
||||
let mut file = File::create(&file_name).unwrap();
|
||||
file.write_all(&bytes).unwrap();
|
||||
true
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@ pub async fn run(args: env::Args) {
|
|||
eprintln!("Missing search query");
|
||||
exit(1);
|
||||
}
|
||||
let search_info = api::get_search_info(reqwest::Client::new(), &query).await.unwrap();
|
||||
let search_info = api::get_search_info(reqwest::Client::new(), &query)
|
||||
.await
|
||||
.unwrap();
|
||||
if search_info.num_pages < 1 {
|
||||
eprintln!("No results found");
|
||||
exit(1);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use crate::api;
|
||||
use crate::utils;
|
||||
use crate::structs;
|
||||
use crate::utils;
|
||||
|
||||
use std::env;
|
||||
use std::process::exit;
|
||||
use tokio::task::JoinHandle;
|
||||
extern crate tokio;
|
||||
extern crate reqwest;
|
||||
extern crate tokio;
|
||||
|
||||
pub async fn run(args: env::Args) {
|
||||
let sauces = utils::get_arg_sauces(args).unwrap();
|
||||
|
@ -15,11 +15,15 @@ pub async fn run(args: env::Args) {
|
|||
exit(1);
|
||||
}
|
||||
let client = reqwest::Client::new();
|
||||
let mut handles: Vec<JoinHandle<(structs::GalleryInfo, i32)>> = Vec::with_capacity(sauces.len());
|
||||
let mut handles: Vec<JoinHandle<(structs::GalleryInfo, i32)>> =
|
||||
Vec::with_capacity(sauces.len());
|
||||
for sauce in sauces {
|
||||
let cloned_client = client.clone();
|
||||
handles.push(tokio::spawn(async move {
|
||||
(api::get_sauce_info(cloned_client, sauce).await.unwrap(), sauce)
|
||||
(
|
||||
api::get_sauce_info(cloned_client, sauce).await.unwrap(),
|
||||
sauce,
|
||||
)
|
||||
}));
|
||||
}
|
||||
let mut fail = false;
|
||||
|
@ -32,7 +36,7 @@ pub async fn run(args: env::Args) {
|
|||
println!("");
|
||||
}
|
||||
println!("{}", &sauce_info);
|
||||
},
|
||||
}
|
||||
structs::GalleryInfo::Error(sauce_error) => {
|
||||
if one_done {
|
||||
eprintln!("");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
mod api;
|
||||
mod utils;
|
||||
mod structs;
|
||||
mod commands;
|
||||
mod structs;
|
||||
mod utils;
|
||||
|
||||
extern crate tokio;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::collections::BTreeMap;
|
||||
use serde::de::{self, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct GalleryTitleInfo {
|
||||
|
@ -15,14 +15,14 @@ pub struct GalleryTitleInfo {
|
|||
pub struct GalleryImageInfo {
|
||||
pub t: String,
|
||||
pub w: i32,
|
||||
pub h: i32
|
||||
pub h: i32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct GalleryImagesInfo {
|
||||
pub pages: Vec<GalleryImageInfo>,
|
||||
pub cover: GalleryImageInfo,
|
||||
pub thumbnail: GalleryImageInfo
|
||||
pub thumbnail: GalleryImageInfo,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
|
@ -31,7 +31,7 @@ pub struct GalleryTagInfo {
|
|||
pub r#type: String,
|
||||
pub name: String,
|
||||
pub url: String,
|
||||
pub count: i32
|
||||
pub count: i32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
|
@ -45,26 +45,26 @@ pub struct GalleryInfoSuccess {
|
|||
pub upload_date: i32,
|
||||
pub tags: Vec<GalleryTagInfo>,
|
||||
pub num_pages: i32,
|
||||
pub num_favorites: i32
|
||||
pub num_favorites: i32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct GalleryInfoError {
|
||||
pub error: String
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(untagged)]
|
||||
pub enum GalleryInfo {
|
||||
Info(GalleryInfoSuccess),
|
||||
Error(GalleryInfoError)
|
||||
Error(GalleryInfoError),
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct SearchInfo {
|
||||
pub result: Vec<GalleryInfoSuccess>,
|
||||
pub num_pages: i32,
|
||||
pub per_page: i32
|
||||
pub per_page: i32,
|
||||
}
|
||||
|
||||
impl fmt::Display for GalleryInfoSuccess {
|
||||
|
@ -96,23 +96,25 @@ impl fmt::Display for GalleryInfoSuccess {
|
|||
"group" => "Groups",
|
||||
"language" => "Languages",
|
||||
"category" => "Categories",
|
||||
_ => tag_key
|
||||
_ => tag_key,
|
||||
};
|
||||
text.push_str(&format!("\n{}: {}", tag_key, tag_value.join(", ")));
|
||||
}
|
||||
text.push_str(&format!("\nPages: {}\nFavorites: {}", self.num_pages, self.num_favorites));
|
||||
text.push_str(&format!(
|
||||
"\nPages: {}\nFavorites: {}",
|
||||
self.num_pages, self.num_favorites
|
||||
));
|
||||
formatter.write_str(&text)
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_to_i32<'de, D>(deserializer: D) -> Result<i32, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct ConvertToI32<T>(PhantomData<fn() -> T>);
|
||||
|
||||
impl<'de> Visitor<'de> for ConvertToI32<i32>
|
||||
{
|
||||
impl<'de> Visitor<'de> for ConvertToI32<i32> {
|
||||
type Value = i32;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
@ -121,28 +123,28 @@ where
|
|||
|
||||
fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error
|
||||
E: de::Error,
|
||||
{
|
||||
Ok(i32::from(value))
|
||||
}
|
||||
|
||||
fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error
|
||||
E: de::Error,
|
||||
{
|
||||
Ok(i32::from(value))
|
||||
}
|
||||
|
||||
fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error
|
||||
E: de::Error,
|
||||
{
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error
|
||||
E: de::Error,
|
||||
{
|
||||
use std::i32;
|
||||
if value >= i64::from(i32::MIN) && value <= i64::from(i32::MAX) {
|
||||
|
@ -154,21 +156,21 @@ where
|
|||
|
||||
fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error
|
||||
E: de::Error,
|
||||
{
|
||||
Ok(i32::from(value))
|
||||
}
|
||||
|
||||
fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error
|
||||
E: de::Error,
|
||||
{
|
||||
Ok(i32::from(value))
|
||||
}
|
||||
|
||||
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error
|
||||
E: de::Error,
|
||||
{
|
||||
use std::{i32, u32};
|
||||
if value <= i32::MAX as u32 {
|
||||
|
@ -180,7 +182,7 @@ where
|
|||
|
||||
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error
|
||||
E: de::Error,
|
||||
{
|
||||
use std::{i32, u64};
|
||||
if value <= i32::MAX as u64 {
|
||||
|
@ -192,9 +194,9 @@ where
|
|||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error
|
||||
E: de::Error,
|
||||
{
|
||||
// https://brokenco.de/2020/08/03/serde-deserialize-with-string.html
|
||||
// https://brokenco.de/2020/08/03/serde-deserialize-with-string.html
|
||||
value.parse::<i32>().map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue