use std::io::Read;
use json::{JsonValue, object, parse};
use rand::seq::SliceRandom;
use regex::Regex;
use crate::error::WikiFeetError;
#[doc(hidden)]
const PATTERN_MODEL_INFO: &str = r#"Feet of the day(.*?)<a href='/(.*?)'><div>"#;
#[doc(hidden)]
const PATTERN_RATING_INFO: &str = r#"width:100%'>(.*?)<br><span style='color:#abc'>(.*?)</span>"#;
#[doc(hidden)]
const PATTERN_ID: &str = r#"messanger\['gdata'\] = (\[.*?\]);"#;
#[doc(hidden)]
const PATTERN_SHOE_SIZE: &str = r#"id=ssize_label>(.*?)<a"#;
#[doc(hidden)]
const PATTERN_BIRTH_PLACE: &str = r#"id=nation_label>(.*?)<a"#;
#[doc(hidden)]
const PATTERN_BIRTH_DATE: &str = r#"id=bdate_label>(.*?)<a"#;
#[doc(hidden)]
const PATTERN_RATING: &str = r#"white-space:nowrap' > \((.*?) feet\)</div>"#;
#[doc(hidden)]
const PATTERN_RATING_STATS: &str = r#"Feet rating stats \((.*?) (.*?)<br>"#;
#[doc(hidden)]
const PATTERN_RATING_GORGEOUS: &str = r#"Rating(.*?) \((.*?) feet\)</div>"#;
#[doc(hidden)]
const PATTERN_IMDB: &str = r#"www.imdb.com/(.*?)'(.*?)Go to IMDb page"#;
pub struct FeetOfTheDay {
#[doc(hidden)]
model_info: Option<String>
}
#[doc(hidden)]
struct FeetOfTheDayInternal;
#[doc(hidden)]
fn http(url: &str) -> Option<String> {
match reqwest::blocking::get(url.to_string()) {
Ok(mut data) => {
let mut body = String::new();
match data.read_to_string(&mut body) {
Ok(_) => Some(body),
Err(_) => None
}
},
Err(_) => None
}
}
#[doc(hidden)]
fn json(info: Option<String>, key: &str) -> Option<String> {
match info {
Some(info) => {
match parse(&info) {
Ok(json) => {
if json[key].is_null() {
None
} else {
Some(json[key].to_string())
}
},
Err(_) => None
}
},
None => None
}
}
impl FeetOfTheDay {
pub fn new() -> Self {
let model_info = FeetOfTheDayInternal::model_info();
Self {
model_info
}
}
#[doc(hidden)]
fn rating_info(&self) -> Option<String> {
match json(self.model_info.clone(),"url") {
Some(data_url) => {
match http(&data_url) {
Some(url) => {
match Regex::new(PATTERN_RATING_INFO) {
Ok(regex) => {
let mut json = JsonValue::new_object();
for cap in regex.captures_iter(&url) {
json[&cap[2]] = cap[1].into();
}
Some(json.to_string())
},
Err(_) => None
}
},
None => None
}
},
None => None
}
}
#[doc(hidden)]
fn id(&self) -> Option<String> {
match json(self.model_info.clone(),"url") {
Some(data_url) => {
match http(&data_url) {
Some(url) => {
match Regex::new(PATTERN_ID) {
Ok(regex) => {
match regex.captures(&url) {
Some(cap) => {
let capture = match cap.get(1) {
Some(data) => data.as_str(),
None => return None
};
match parse(&capture) {
Ok(json) => {
let mut list = vec![];
let mut i = 0;
while i < json.len(){
list.push(json[i]["pid"].to_string());
i +=1;
}
let mut random = rand::thread_rng();
match list.choose(&mut random) {
Some(id) => Some(id.to_string()),
None => None
}
},
Err(_) => None
}
},
None => None
}
},
Err(_) => None
}
},
None => None
}
},
None => None
}
}
pub fn model_name(&self) -> Result<String, WikiFeetError> {
match json(self.model_info.clone(),"name") {
Some(name) => Ok(name),
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn model_page(&self) -> Result<String, WikiFeetError> {
match json(self.model_info.clone(),"url") {
Some(data) => Ok(data),
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn thumbnail(&self) -> Result<String, WikiFeetError> {
match self.id() {
Some(id) => Ok(format!("https://thumbs.wikifeet.com/{}.jpg",id)),
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn image(&self) -> Result<String, WikiFeetError> {
match json(self.model_info.clone(),"username") {
Some(username) => {
match self.id() {
Some(id) => Ok(format!("https://pics.wikifeet.com/{}-feet-{}.jpg",username,id)),
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn shoe_size(&self) -> Result<String, WikiFeetError> {
match json(self.model_info.clone(),"url") {
Some(data_url) => {
match http(&data_url) {
Some(url) => {
match Regex::new(PATTERN_SHOE_SIZE) {
Ok(regex) => {
match regex.captures(&url) {
Some(cap) => {
match cap.get(1) {
Some(data) => Ok(data.as_str().to_string()),
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
Err(_) => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn birth_place(&self) -> Result<String, WikiFeetError> {
match json(self.model_info.clone(),"url") {
Some(data_url) => {
match http(&data_url) {
Some(url) => {
match Regex::new(PATTERN_BIRTH_PLACE) {
Ok(regex) => {
match regex.captures(&url) {
Some(cap) => {
match cap.get(1) {
Some(data) => Ok(data.as_str().to_string()),
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
Err(_) => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn birth_date(&self) -> Result<String, WikiFeetError> {
match json(self.model_info.clone(),"url") {
Some(data_url) => {
match http(&data_url) {
Some(url) => {
match Regex::new(PATTERN_BIRTH_DATE) {
Ok(regex) => {
match regex.captures(&url) {
Some(cap) => {
match cap.get(1) {
Some(data) => Ok(data.as_str().to_string()),
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
Err(_) => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn rating(&self) -> Result<String, WikiFeetError> {
match json(self.model_info.clone(),"url") {
Some(data_url) => {
match http(&data_url) {
Some(url) => {
match Regex::new(PATTERN_RATING) {
Ok(regex) => {
match regex.captures(&url) {
Some(cap) => {
match cap.get(1) {
Some(data) => Ok(data.as_str().to_string()),
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => {
match Regex::new(PATTERN_RATING_GORGEOUS) {
Ok(regex) => {
match regex.captures(&url) {
Some(cap) => {
match cap.get(2) {
Some(data) => Ok(data.as_str().to_string()),
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
Err(_) => Err(WikiFeetError::Null(String::from("null")))
}
}
}
},
Err(_) => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn beautiful_rating(&self) -> Result<String, WikiFeetError> {
match json(self.rating_info(),"beautiful") {
Some(data) => Ok(data),
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn nice_rating(&self) -> Result<String, WikiFeetError> {
match json(self.rating_info(),"nice") {
Some(data) => Ok(data),
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn ok_rating(&self) -> Result<String, WikiFeetError> {
match json(self.rating_info(),"ok") {
Some(data) => Ok(data),
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn bad_rating(&self) -> Result<String, WikiFeetError> {
match json(self.rating_info(),"bad") {
Some(data) => Ok(data),
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn ugly_rating(&self) -> Result<String, WikiFeetError> {
match json(self.rating_info(),"ugly") {
Some(data) => Ok(data),
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn rating_stats(&self) -> Result<String, WikiFeetError> {
match json(self.model_info.clone(),"url") {
Some(data_url) => {
match http(&data_url) {
Some(url) => {
match Regex::new(PATTERN_RATING_STATS) {
Ok(regex) => {
match regex.captures(&url) {
Some(cap) => {
match cap.get(1) {
Some(data) => Ok(data.as_str().to_string()),
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
Err(_) => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
}
pub fn imdb_page(&self) -> Result<String, WikiFeetError> {
match json(self.model_info.clone(),"url") {
Some(data_url) => {
match http(&data_url) {
Some(url) => {
match Regex::new(PATTERN_IMDB) {
Ok(regex) => {
match regex.captures(&url) {
Some(cap) => {
match cap.get(1) {
Some(data) => Ok(format!("https://www.imdb.com/{}",data.as_str())),
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
Err(_) => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
},
None => Err(WikiFeetError::Null(String::from("null")))
}
}
}
impl FeetOfTheDayInternal {
fn model_info() -> Option<String> {
match http("https://www.wikifeet.com") {
Some(url) => {
match Regex::new(PATTERN_MODEL_INFO) {
Ok(regex) => {
match regex.captures(&url) {
Some(cap) => {
let model_name = match cap.get(2) {
Some(data) => data.as_str().replace(r#"_"#, " "),
None => return None
};
let model_username = match cap.get(2) {
Some(data) => data.as_str().replace(r#"_"#, "-"),
None => return None
};
let model_url = match cap.get(2) {
Some(data) => format!("https://www.wikifeet.com/{}", data.as_str()),
None => return None
};
Some(object! {
name: model_name,
username: model_username,
url: model_url
}.to_string())
},
None => None
}
},
Err(_) => None
}
},
None => None
}
}
}