use std::collections::HashMap;
use serde::{Deserialize, Deserializer, Serialize};
use time::OffsetDateTime;
use super::tag::Tag;
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum AbstractSize {
SquareMedium,
Medium,
Large,
Original,
Master,
BigThumbnail,
SquareMediumWebp, }
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
pub struct Size {
pub width: u32,
pub height: u32,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Urls {
pub square_medium: String,
pub medium: String,
pub large: String,
}
#[allow(non_snake_case)]
#[derive(Deserialize, Debug, Clone)]
pub struct Illust {
pub id: u32,
pub title: String,
#[serde(rename(deserialize = "type"))]
pub work_type: String,
pub image_urls: Urls,
pub caption: String,
pub restrict: u32,
#[serde(with = "crate::models::tag")]
pub tags: Vec<Tag>,
#[serde(with = "time::serde::rfc3339")]
pub create_date: OffsetDateTime,
#[serde(flatten)]
pub size: Size,
pub page_count: u32,
pub sanity_level: u32,
pub x_restrict: u32,
#[serde(with = "Urls")]
pub meta_pages: Vec<Urls>,
pub total_view: u32,
pub total_bookmarks: u32,
pub is_bookmarked: bool,
pub visible: bool,
pub is_muted: bool,
pub illust_ai_type: u32,
}
impl Illust {
pub fn get_meta_pages(&self) -> Vec<Illust> {
let mut v = vec![];
for i in &self.meta_pages {
let mut a = self.clone();
a.image_urls = i.clone();
a.meta_pages.clear();
v.push(a);
}
v
}
}
impl Size {
pub fn unknown() -> Size {
Size {
width: 0,
height: 0,
}
}
pub fn master(&self) -> Size {
if self.width == 0 || self.height == 0 {
return Size {
width: 1200,
height: 600,
};
}
if self.width <= 1200 && self.height <= 1200 {
return self.clone();
}
if self.width > self.height {
Size {
width: 1200,
height: (1200.0 * self.height as f32 / self.width as f32) as u32,
}
} else {
Size {
height: 1200,
width: (1200.0 * self.width as f32 / self.height as f32) as u32,
}
}
}
pub fn large(&self) -> Size {
if self.width == 0 || self.height == 0 {
return Size {
width: 600,
height: 600,
};
}
if self.height > 2 * self.width {
Size {
height: 1200,
width: (1200.0 * self.width as f32 / self.height as f32) as u32,
}
} else {
Size {
width: 600,
height: (600.0 * self.height as f32 / self.width as f32) as u32,
}
}
}
pub fn medium(&self) -> Size {
if self.width == 0 || self.height == 0 {
return Size {
width: 540,
height: 540,
};
}
if self.width > self.height {
Size {
width: 540,
height: (540.0 * self.height as f32 / self.width as f32) as u32,
}
} else {
Size {
height: 540,
width: (540.0 * self.width as f32 / self.height as f32) as u32,
}
}
}
}
impl Into<[usize; 2]> for Size {
fn into(self) -> [usize; 2] {
[self.width as usize, self.height as usize]
}
}
impl Urls {
pub fn original(&self) -> String {
self.square_medium
.replace("c/360x360_70/", "")
.replace("img-master", "img-original")
.replace("_square1200", "")
}
pub fn master(&self) -> String {
self.square_medium
.replace("c/360x360_70/", "")
.replace("_square1200", "_master1200")
}
pub fn square_medium_webp(&self) -> String {
self.square_medium
.replacen("c/360x360_70/", "c/360x360_10_webp/", 1)
}
pub fn by_abstract_size(&self, abstract_size: AbstractSize) -> String {
match abstract_size {
AbstractSize::SquareMedium => self.square_medium.to_string(),
AbstractSize::Medium => self.medium.to_string(),
AbstractSize::Large => self.large.to_string(),
AbstractSize::Original => self.original(),
AbstractSize::Master => self.master(),
AbstractSize::BigThumbnail => self.square_medium.to_string(),
AbstractSize::SquareMediumWebp => self.square_medium_webp(),
}
}
pub fn deserialize<'de, D>(d: D) -> Result<Vec<Urls>, D::Error>
where
D: Deserializer<'de>,
{
let a = <Vec<HashMap<String, Urls>>>::deserialize(d);
match a {
Ok(a) => Ok(a
.into_iter()
.map(|x| x.into_values().next().unwrap())
.collect()),
Err(err) => Err(err),
}
}
}