diff --git a/src/api.rs b/src/api.rs index ec1d831..2841ea4 100644 --- a/src/api.rs +++ b/src/api.rs @@ -31,9 +31,20 @@ pub async fn get_sauce_info( client: reqwest::Client, sauce: i32, ) -> Result { - let mut uri = String::from("https://nhentai.net/api/gallery/"); - uri.push_str(&sauce.to_string()); - let resp = client.get(&uri).send().await?; + let mut url = String::from("https://nhentai.net/api/gallery/"); + url.push_str(&sauce.to_string()); + let resp = client.get(&url).send().await?; + Ok(serde_json::from_str(&resp.text().await?)?) +} + +pub async fn get_related_galleries( + client: &reqwest::Client, + sauce: i32, +) -> Result { + let mut url = String::from("https://nhentai.net/api/gallery/"); + url.push_str(&sauce.to_string()); + url.push_str("/related"); + let resp = client.get(&url).send().await?; Ok(serde_json::from_str(&resp.text().await?)?) } diff --git a/src/commands.rs b/src/commands.rs index ff8e443..d7822c8 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,4 +1,5 @@ mod download; +mod related; mod search; mod view; @@ -20,12 +21,14 @@ pub async fn run() { match operation.as_str() { "search" => search::run(args).await, "view" | "show" | "info" => view::run(args).await, + "related" => related::run(args).await, "download" | "dl" => download::run(args).await, "help" => println!( - r#"Usage: {} search QUERY - or {} info/view/show SAUCE [SAUCE]... - or {} download/dl SAUCE [SAUCE]..."#, - path, path, path + r#"Usage: {} search + or {} info/view/show ... + or {} related ... + or {} download/dl ..."#, + path, path, path, path ), _ => { eprintln!("Unknown operation, run `{} help`", path); diff --git a/src/commands/related.rs b/src/commands/related.rs new file mode 100644 index 0000000..d723a2c --- /dev/null +++ b/src/commands/related.rs @@ -0,0 +1,74 @@ +use crate::api; +use crate::structs; +use crate::utils; + +use std::env; +use std::process::exit; +extern crate reqwest; +extern crate tokio; + +pub async fn run(args: env::Args) { + let sauces = utils::get_arg_sauces(args); + let is_multi = sauces.len() > 1; + + let client = api::get_client(); + let mut failures = 0; + let mut one_done = false; + + for sauce in sauces { + let sauce_info = api::get_related_galleries(&client, sauce).await; + match sauce_info { + Ok(structs::RelatedGalleries::Galleries(related_galleries)) => { + show_related_galleries(sauce, &related_galleries, one_done, is_multi) + } + Ok(structs::RelatedGalleries::Error(err)) => { + show_error(sauce, &err.error, one_done, true); + failures += 1; + } + Err(err) => { + show_error(sauce, &err, one_done, is_multi); + failures += 1; + } + } + one_done = true; + } + exit(failures); +} + +fn show_related_galleries( + sauce: i32, + related_galleries: &structs::RelatedGalleriesSuccess, + prepend_newline: bool, + is_multi: bool, +) { + if prepend_newline { + println!(""); + } + + let mut prefix = ""; + if is_multi { + println!("{}:", sauce); + prefix = "- "; + } + for i in &related_galleries.result { + let title = i.title.english.as_deref().or(i.title.japanese.as_deref()); + println!("{}{}: {}", prefix, i.id, title.unwrap_or("")); + } +} + +fn show_error( + sauce: i32, + error: &T, + prepend_newline: bool, + prepend_sauce: bool, +) { + if prepend_newline { + eprintln!(""); + } + + if !prepend_sauce { + eprintln!("{}", error); + } else { + eprintln!("{}: {}", sauce, error); + } +} diff --git a/src/structs.rs b/src/structs.rs index 1031674..9da4989 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -5,6 +5,11 @@ use std::fmt; use std::marker::PhantomData; use std::num::ParseIntError; +#[derive(Deserialize, Debug)] +pub struct APIError { + pub error: String, +} + #[derive(Deserialize, Debug)] pub struct GalleryTitleInfo { pub english: Option, @@ -50,15 +55,22 @@ pub struct GalleryInfoSuccess { } #[derive(Deserialize, Debug)] -pub struct GalleryInfoError { - pub error: String, +#[serde(untagged)] +pub enum GalleryInfo { + Info(GalleryInfoSuccess), + Error(APIError), +} + +#[derive(Deserialize, Debug)] +pub struct RelatedGalleriesSuccess { + pub result: Vec, } #[derive(Deserialize, Debug)] #[serde(untagged)] -pub enum GalleryInfo { - Info(GalleryInfoSuccess), - Error(GalleryInfoError), +pub enum RelatedGalleries { + Galleries(RelatedGalleriesSuccess), + Error(APIError), } #[derive(Debug)]