use crate::structs; use std::env; use std::fs::File; use std::io::Write; use tokio::stream::StreamExt; use std::collections::BTreeMap; extern crate serde_json; extern crate reqwest; fn fix_gallery(body: &mut serde_json::Value) -> Result<(), serde_json::Error> { if body["id"].is_string() { body["id"] = serde_json::json!( body["id"].as_str().unwrap().parse::().unwrap() ); } Ok(()) } 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 body = resp.text().await?; let mut body: serde_json::Value = serde_json::from_str(&body).unwrap(); fix_gallery(&mut body).unwrap(); Ok(serde_json::from_str(&serde_json::to_string(&body).unwrap()).unwrap()) } pub async fn get_search_info(client: reqwest::Client, search_query: &str) -> Result { let uri = "https://nhentai.net/api/galleries/search"; let resp = client.get(uri) .query(&[("query", search_query)]) .send() .await?; assert!(resp.status().is_success()); let body = resp.text().await?; let mut body: serde_json::Value = serde_json::from_str(&body).unwrap(); for i in 0..body["result"].as_array().unwrap().len() { fix_gallery(&mut body["result"][i]).unwrap(); } Ok(serde_json::from_str(&serde_json::to_string(&body).unwrap()).unwrap()) } pub async fn download_file(client: reqwest::Client, url: &str, file_name: &str) -> Result<(), reqwest::Error> { let resp = client.get(url) .send() .await?; let mut file = File::create(&file_name).unwrap(); let mut stream = resp.bytes_stream(); while let Some(item) = stream.next().await { file.write(&item?).unwrap(); } Ok(()) } pub fn get_arg_sauces(args: env::Args) -> Result, String> { let mut sauces: Vec = Vec::new(); for sauce in args { let sauce: i32 = match sauce.parse() { Ok(sauce) => sauce, Err(_) => { return Err(format!("{} is not a number/sauce", sauce)); } }; if !sauces.contains(&sauce) { sauces.push(sauce); } } Ok(sauces) } pub fn human_sauce_info(sauce_info: &structs::GalleryInfoSuccess) -> String { let mut text = format!("Sauce: {}\nTitle: ", sauce_info.id); let japanese_title = sauce_info.title.japanese.as_ref(); let english_title = sauce_info.title.english.as_ref(); if english_title.is_some() { text.push_str(english_title.unwrap()); if japanese_title.is_some() { text.push_str(&format!("\nJapanese Title: {}", japanese_title.unwrap())); } } else { text.push_str(japanese_title.unwrap()); } let mut tag_hashmap = BTreeMap::new(); for tag_info in &sauce_info.tags { let tag_key = tag_info.r#type.as_str(); let tag_value = tag_info.name.as_str(); let tag_vec = tag_hashmap.entry(tag_key).or_insert(Vec::new()); tag_vec.push(tag_value); } for (tag_key, tag_value) in tag_hashmap { let tag_key = match tag_key { "tag" => "Tags", "artist" => "Artists", "parody" => "Parodies", "character" => "Characters", "group" => "Groups", "language" => "Languages", "category" => "Categories", _ => tag_key }; text.push_str(&format!("\n{}: {}", tag_key, tag_value.join(", "))); } text.push_str(&format!("\nPages: {}\nFavorites: {}", sauce_info.num_pages, sauce_info.num_favorites)); text }