use crate::client::params::SearchMode;
use crate::client::{params::SortMode, PixivAppClient};
use crate::models::{Illustration, Novel, PixivResult, PixivUserResult, Tag};
use crate::PixivAppError;
use chrono::{DateTime, Utc};
use reqwest_middleware::reqwest::Method;
use std::error::Error;
impl PixivAppClient {
pub async fn search_tag(&self, word: String) -> Result<Vec<Tag>, Box<dyn Error + Send + Sync>> {
let url = format!("{}/v2/search/autocomplete", self.host);
let req = self
.http_client
.request(Method::GET, url)
.query(&[("word", word), ("filter", format!("for_{}", self.platform))]);
let res = self.process_request::<PixivResult>(req).await?;
res.tags.ok_or(res.error.map_or_else(
|| Box::<dyn Error + Sync + Send>::from(PixivAppError::Unknown),
|v| Box::new(v),
))
}
pub async fn search_user(
&self,
word: String,
sort: SortMode,
duration: Option<&'static str>,
offset: Option<u32>,
) -> Result<Vec<PixivUserResult>, Box<dyn Error + Send + Sync>> {
let url = format!("{}/v1/search/user", self.host);
let mut params = vec![
("word", word),
("sort", sort.to_string()),
("filter", format!("for_{}", self.platform)),
("offset", offset.unwrap_or(0).to_string()),
];
if let Some(duration) = duration {
params.push(("duration", duration.to_string()));
}
let req = self.http_client.request(Method::GET, url).query(¶ms);
let res = self.process_request::<PixivResult>(req).await?;
res.user_previews.ok_or(res.error.map_or_else(
|| Box::<dyn Error + Sync + Send>::from(PixivAppError::Unknown),
|v| Box::new(v),
))
}
pub async fn search_novel(
&self,
word: String,
search_targets: SearchMode,
sort: SortMode,
merge_plain_keyword_results: Option<bool>,
include_translated_tag_results: Option<bool>,
start_date: Option<DateTime<Utc>>,
end_date: Option<DateTime<Utc>>,
offset: Option<u32>,
) -> Result<Vec<Novel>, Box<dyn Error + Send + Sync>> {
let url = format!("{}/v1/search/novel", self.host);
let mut params = vec![
("word", word),
("search_targets", search_targets.to_string()),
("sort", sort.to_string()),
(
"merge_plain_keyword_results",
merge_plain_keyword_results.unwrap_or(true).to_string(),
),
(
"include_translated_tag_results",
include_translated_tag_results.unwrap_or(true).to_string(),
),
("filter", format!("for_{}", self.platform)),
("offset", offset.unwrap_or(0).to_string()),
];
if let Some(start_date) = start_date {
params.push(("start_date", start_date.format("%Y-%M-%d").to_string()));
}
if let Some(end_date) = end_date {
params.push(("start_date", end_date.format("%Y-%M-%d").to_string()));
}
let req = self.http_client.request(Method::GET, url).query(¶ms);
let res = self.process_request::<PixivResult>(req).await?;
res.novels.ok_or(res.error.map_or_else(
|| Box::<dyn Error + Sync + Send>::from(PixivAppError::Unknown),
|v| Box::new(v),
))
}
pub async fn search_illust(
&self,
word: String,
search_targets: SearchMode,
sort: SortMode,
duration: Option<&'static str>,
start_date: Option<DateTime<Utc>>,
end_date: Option<DateTime<Utc>>,
offset: Option<u32>,
) -> Result<Vec<Illustration>, Box<dyn Error + Send + Sync>> {
let url = if offset.unwrap_or_default() == 0 && sort == SortMode::PopularDescending {
format!("{}/v1/search/popular-preview/illust", self.host)
} else {
format!("{}/v1/search/illust", self.host)
};
let mut params = vec![
("word", word),
("search_targets", search_targets.to_string()),
("sort", sort.to_string()),
("filter", format!("for_{}", self.platform)),
("offset", offset.unwrap_or(0).to_string()),
];
if let Some(duration) = duration {
params.push(("duration", duration.to_string()))
}
if let Some(start_date) = start_date {
params.push(("start_date", start_date.format("%Y-%M-%d").to_string()));
}
if let Some(end_date) = end_date {
params.push(("start_date", end_date.format("%Y-%M-%d").to_string()));
}
let req = self.http_client.request(Method::GET, url).query(¶ms);
let res = self.process_request::<PixivResult>(req).await?;
res.illusts.ok_or(res.error.map_or_else(
|| Box::<dyn Error + Sync + Send>::from(PixivAppError::Unknown),
|v| Box::new(v),
))
}
}
#[cfg(test)]
mod tests {
use crate::client::{
params::{SearchMode, SortMode},
tests::*,
};
use tokio::test;
#[test]
async fn test_tag_search() {
let result = get_client().search_tag(String::from("wallpaper")).await;
let Ok(_) = result else {
panic!("Failed to search tag: {}", result.err().unwrap());
};
}
#[test]
async fn test_illustration_search() {
let result = get_client()
.search_illust(
String::from("wallpaper"),
SearchMode::PartialMatchForTags,
SortMode::PopularDescending,
None,
None,
None,
None,
)
.await;
let Ok(_) = result else {
panic!("Failed to search tag: {}", result.err().unwrap());
};
}
#[test]
async fn test_user_search() {
let result = get_client()
.search_user(String::from(USER), SortMode::DateAscending, None, None)
.await;
let Ok(_) = result else {
panic!("Failed to search user: {}", result.err().unwrap());
};
}
#[test]
async fn test_novel_search() {
let result = get_client()
.search_novel(
String::from("foo"),
SearchMode::PartialMatchForTags,
SortMode::PopularDescending,
None,
None,
None,
None,
None,
)
.await;
let Ok(_) = result else {
panic!("Failed to search novel: {}", result.err().unwrap());
};
}
}