use forecast::{ ApiClient as DSClient, ApiResponse, ForecastRequestBuilder, Lang, Units }; use geocoding::Opencage; use kitsu::model::{ Response, Anime,Manga }; use kitsu::{ KitsuReqwestRequester, Error as KitsuErr }; use reqwest::header::{ Headers, UserAgent, ContentType, Accept, Authorization, qitem }; use reqwest::mime; use reqwest::{ Client, Result as ReqwestResult, Response as ReqwestResponse }; use std::collections::HashMap; use std::env; use urbandictionary::{ ReqwestUrbanDictionaryRequester, Result as UrbanResult, model::Response as UrbanResponse }; const UA: &str = "wisp-bot"; // Endpoints const DOG: &str = "https://dog.ceo/api/breeds/image/random"; const CAT: &str = "http://aws.random.cat/meow"; const DAD_JOKE: &str = "https://icanhazdadjoke.com"; const FURRY: &str = "https://e621.net/post/index.json"; const DBOTS: &str = "http://discordbots.org/api/bots"; // const BUNNY: &str = "https://api.bunnies.io/v2/loop/random/?media=gif,png"; const DUCK: &str = "https://random-d.uk/api/v1/random?type=gif"; const FOX: &str = "https://randomfox.ca/floof/"; const OWL: &str = "https://pics.floofybot.moe/owl"; const YO_MOMMA: &str = "https://api.yomomma.info/"; // const WAIFU_BACKSTORY: &str = "https://www.thiswaifudoesnotexist.net/snippet-"; // .txt // const WAIFU_IMAGE: &str = "https://www.thiswaifudoesnotexist.net/example-"; // .jpg // Deserialization Structs // #[derive(Deserialize, Debug)] // pub struct Bunny { // pub id: String, // pub media: Vec, // pub source: String, // pub thisServed: u32, // pub totalServed: u32 // } #[derive(Deserialize, Debug)] pub struct Dog { pub message: String, pub status: String } #[derive(Deserialize, Debug)] pub struct Duck { pub message: String, pub url: String } #[derive(Deserialize, Debug)] pub struct Cat { pub file: String } #[derive(Deserialize, Debug)] pub struct CreatedAt { pub json_class: String, pub s: usize, pub n: usize } #[derive(Deserialize, Debug)] pub struct Fox { pub image: String, pub link: String } #[derive(Deserialize, Debug)] pub struct FurPost { pub id: usize, pub tags: String, pub locked_tags: Option, pub description: String, pub created_at: CreatedAt, pub creator_id: usize, pub author: String, pub change: usize, pub source: Option, pub score: isize, pub fav_count: usize, pub md5: Option, pub file_size: Option, pub file_url: String, pub file_ext: Option, pub preview_url: String, pub preview_width: Option, pub preview_height: Option, pub sample_url: Option, pub sample_width: Option, pub sample_height: Option, pub rating: String, pub status: String, pub width: usize, pub height: usize, pub has_comments: bool, pub has_notes: bool, pub has_children: Option, pub children: Option, pub parent_id: Option, pub artist: Vec, pub sources: Option> } #[derive(Deserialize, Debug)] pub struct Owl { pub image: String } #[derive(Deserialize, Debug)] pub struct YoMomma { pub joke: String } // The Client pub struct ApiClient { pub client: Client, pub oc_client: Opencage, } impl ApiClient { pub fn new() -> Self { let client = Client::new(); let oc_key = env::var("OPENCAGE_KEY").expect("Expected key for OpenCage in environment."); let oc_client = Opencage::new(oc_key); ApiClient { client, oc_client } } pub fn stats_update(&self, bot_id: u64, server_count: usize) -> ReqwestResult { let mut headers = Headers::new(); headers.set(ContentType::json()); headers.set(Authorization(env::var("DBOTS_ORG_TOKEN").expect("Expected DiscordBots.org token in environment."))); let mut data = HashMap::new(); data.insert("server_count", server_count); self.client.post(format!("{}/{}/stats", DBOTS, bot_id).as_str()) .json(&data) .send() } // pub fn bunny(&self) -> ReqwestResult { // match self.client.get(BUNNY).send() { // Ok(mut res) => { // res.json::() // }, // Err(why) => { // error!("{:?}", why); // Err(why) // }, // } // } pub fn dog(&self) -> ReqwestResult { match self.client.get(DOG).send() { Ok(mut res) => { res.json::() }, Err(why) => { error!("{:?}", why); Err(why) }, } } pub fn duck(&self) -> ReqwestResult { match self.client.get(DUCK).send() { Ok(mut res) => { res.json::() }, Err(why) => { error!("{:?}", why); Err(why) }, } } pub fn cat(&self) -> ReqwestResult { match self.client.get(CAT).send() { Ok(mut res) => { res.json::() }, Err(why) => { error!("{:?}", why); Err(why) }, } } pub fn joke(&self) -> ReqwestResult { let mut headers = Headers::new(); headers.set(UserAgent::new(UA)); headers.set(Accept(vec![qitem(mime::TEXT_PLAIN)])); match self.client.get(DAD_JOKE) .headers(headers) .send() { Ok(mut res) => { res.text() }, Err(why) => { error!("{:?}", why); Err(why) }, } } pub fn urban(&self, input: &str) -> UrbanResult { self.client.definitions(input) } pub fn furry>(&self, input: S, count: u32) -> ReqwestResult> { let mut headers = Headers::new(); headers.set(UserAgent::new(UA)); match self.client.get(FURRY) .headers(headers) .query(&[("tags", input.into()+" order:random"), ("limit", count.to_string())]) .send() { Ok(mut res) => { res.json::>() }, Err(why) => { error!("{:?}", why); Err(why) }, } } pub fn fox(&self) -> ReqwestResult { match self.client.get(FOX).send() { Ok(mut res) => { res.json::() }, Err(why) => { error!("{:?}", why); Err(why) }, } } pub fn owl(&self) -> ReqwestResult { match self.client.get(OWL).send() { Ok(mut res) => { res.json::() }, Err(why) => { error!("{:?}", why); Err(why) }, } } pub fn yo_momma(&self) -> ReqwestResult { match self.client.get(YO_MOMMA).send() { Ok(mut res) => { res.json::() }, Err(why) => { error!("{:?}", why); Err(why) }, } } pub fn anime>(&self, input: S) -> Result>, KitsuErr> { self.client.search_anime(|f| f.filter("text", input.into().trim())) } pub fn manga>(&self, input: S) -> Result>, KitsuErr> { self.client.search_manga(|f| f.filter("text", input.into().trim())) } pub fn weather(&self, input: &str, units: Units) -> Option<(String, ReqwestResult)> { match self.oc_client.forward_full(input, &None) { Ok(data) => { if !data.results.is_empty() { let first = data.results.first().unwrap(); let city_info = format!("{}, {}, {}", first.components.get("city").unwrap(), first.components.get("state").unwrap(), first.components.get("country").unwrap() ); let ds_key = env::var("DARKSKY_KEY").expect("Expected DarkSky API Key in environment."); let fc_req = Some(ForecastRequestBuilder::new(ds_key.as_str(), *first.geometry.get("lat").unwrap(), *first.geometry.get("lng").unwrap()) .lang(Lang::English) .units(units) .build()); if let Some(req) = fc_req { let ds_client = DSClient::new(&self.client); match ds_client.get_forecast(req) { Ok(mut res) => { return Some((city_info, res.json::())); }, Err(why) => { return Some((city_info, Err(why))); }, } } } }, Err(why) => { debug!("Failed to resolve location: {:?}", why); } } None } }