mirror of
https://github.com/lifegpc/pixiv_downloader.git
synced 2026-07-08 01:32:41 +08:00
fanbox api: deserialize fanbox item
This commit is contained in:
10
src/fanbox/error.rs
Normal file
10
src/fanbox/error.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
#[derive(Debug, derive_more::From, derive_more::Display)]
|
||||
pub enum FanboxAPIError {
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl From<&'static str> for FanboxAPIError {
|
||||
fn from(v: &'static str) -> Self {
|
||||
Self::String(v.to_owned())
|
||||
}
|
||||
}
|
||||
58
src/fanbox/item.rs
Normal file
58
src/fanbox/item.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use json::JsonValue;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// To represent a fanbox item
|
||||
pub struct FanboxItem {
|
||||
/// JSON object
|
||||
pub data: JsonValue,
|
||||
}
|
||||
|
||||
impl FanboxItem {
|
||||
/// Returns the id of the item
|
||||
pub fn id(&self) -> Option<u64> {
|
||||
let id = &self.data["id"];
|
||||
match id.as_u64() {
|
||||
Some(id) => Some(id),
|
||||
None => match id.as_str() {
|
||||
Some(id) => match id.trim().parse::<u64>() {
|
||||
Ok(id) => Some(id),
|
||||
Err(_) => None,
|
||||
},
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_liked(&self) -> Option<bool> {
|
||||
self.data["isLiked"].as_bool()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns item's title
|
||||
pub fn title(&self) -> Option<&str> {
|
||||
self.data["title"].as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for FanboxItem {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("FanboxItem")
|
||||
.field("id", &self.id())
|
||||
.field("title", &self.title())
|
||||
.field("is_liked", &self.is_liked())
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JsonValue> for FanboxItem {
|
||||
fn from(data: JsonValue) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for FanboxItem {
|
||||
fn from(data: &JsonValue) -> Self {
|
||||
Self::from(data.clone())
|
||||
}
|
||||
}
|
||||
51
src/fanbox/item_list.rs
Normal file
51
src/fanbox/item_list.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use super::error::FanboxAPIError;
|
||||
use super::item::FanboxItem;
|
||||
use crate::fanbox_api::FanboxClientInternal;
|
||||
use crate::gettext;
|
||||
use json::JsonValue;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// A list of fanbox item.
|
||||
pub struct FanboxItemList {
|
||||
/// Item list
|
||||
pub items: Vec<FanboxItem>,
|
||||
/// The url of the next page
|
||||
next_url: Option<String>,
|
||||
/// Fanbox api client
|
||||
client: Arc<FanboxClientInternal>,
|
||||
}
|
||||
|
||||
impl FanboxItemList {
|
||||
pub fn new(
|
||||
value: &JsonValue,
|
||||
client: Arc<FanboxClientInternal>,
|
||||
) -> Result<Self, FanboxAPIError> {
|
||||
let oitems = &value["items"];
|
||||
if !oitems.is_array() {
|
||||
return Err(FanboxAPIError::from(gettext("Failed to parse item list.")));
|
||||
}
|
||||
let mut items = Vec::new();
|
||||
for item in oitems.members() {
|
||||
items.push(FanboxItem::from(item));
|
||||
}
|
||||
let next_url = match value["nextUrl"].as_str() {
|
||||
Some(next_url) => Some(next_url.to_owned()),
|
||||
None => None,
|
||||
};
|
||||
Ok(Self {
|
||||
items,
|
||||
next_url,
|
||||
client,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for FanboxItemList {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("FanboxItemList")
|
||||
.field("items", &self.items)
|
||||
.field("next_url", &self.next_url)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
@@ -1 +1,4 @@
|
||||
pub mod error;
|
||||
pub mod item;
|
||||
pub mod item_list;
|
||||
pub mod paginated_creator_posts;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use super::error::FanboxAPIError;
|
||||
use super::item_list::FanboxItemList;
|
||||
#[cfg(test)]
|
||||
use crate::fanbox_api::FanboxClient;
|
||||
use crate::fanbox_api::FanboxClientInternal;
|
||||
@@ -7,17 +9,6 @@ use proc_macros::fanbox_api_test;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, derive_more::From, derive_more::Display)]
|
||||
pub enum PaginatedCreatorPostsError {
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl From<&'static str> for PaginatedCreatorPostsError {
|
||||
fn from(v: &'static str) -> Self {
|
||||
Self::String(v.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
/// List creator posts
|
||||
pub struct PaginatedCreatorPosts {
|
||||
/// Fanbox API Client
|
||||
@@ -33,10 +24,10 @@ impl PaginatedCreatorPosts {
|
||||
pub fn new(
|
||||
value: &JsonValue,
|
||||
client: Arc<FanboxClientInternal>,
|
||||
) -> Result<Self, PaginatedCreatorPostsError> {
|
||||
) -> Result<Self, FanboxAPIError> {
|
||||
let body = &value["body"];
|
||||
if !body.is_array() {
|
||||
return Err(PaginatedCreatorPostsError::from(gettext(
|
||||
return Err(FanboxAPIError::from(gettext(
|
||||
"Failed to parse paginated data.",
|
||||
)));
|
||||
}
|
||||
@@ -47,7 +38,7 @@ impl PaginatedCreatorPosts {
|
||||
pages.push(s.to_owned());
|
||||
}
|
||||
None => {
|
||||
return Err(PaginatedCreatorPostsError::from(gettext(
|
||||
return Err(FanboxAPIError::from(gettext(
|
||||
"Failed to parse paginated data.",
|
||||
)));
|
||||
}
|
||||
@@ -55,6 +46,39 @@ impl PaginatedCreatorPosts {
|
||||
}
|
||||
Ok(Self { client, pages })
|
||||
}
|
||||
|
||||
/// Get posts' data in specified page.
|
||||
/// * `index` - The index of the page
|
||||
pub async fn get_page(&self, index: usize) -> Option<FanboxItemList> {
|
||||
if index >= self.pages.len() {
|
||||
None
|
||||
} else {
|
||||
match self
|
||||
.client
|
||||
.get_url(
|
||||
self.pages[index].as_str(),
|
||||
gettext("Failed to get posts' data:"),
|
||||
gettext("Posts' data:"),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Some(d) => match FanboxItemList::new(&d["body"], Arc::clone(&self.client)) {
|
||||
Ok(d) => Some(d),
|
||||
Err(e) => {
|
||||
println!("{} {}", gettext("Failed to parse posts's data:"), e);
|
||||
None
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns the total pages
|
||||
pub fn len(&self) -> usize {
|
||||
self.pages.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for PaginatedCreatorPosts {
|
||||
@@ -69,7 +93,7 @@ impl Debug for PaginatedCreatorPosts {
|
||||
f.write_fmt(format_args!("{} {}\n", index, page))?;
|
||||
index += 1;
|
||||
}
|
||||
f.write_str("}\n")
|
||||
f.write_str("}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +102,14 @@ fanbox_api_test!(test_paginate_creator_posts, {
|
||||
match client.paginate_creator_post("mozukun43").await {
|
||||
Some(pages) => {
|
||||
println!("{:?}", pages);
|
||||
if pages.len() > 0 {
|
||||
match pages.get_page(0).await {
|
||||
Some(data) => {
|
||||
println!("{:?}", data)
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
panic!("Failed to paginate creator's posts.")
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::parser::metadata::MetaDataParser;
|
||||
use crate::webclient::WebClient;
|
||||
use json::JsonValue;
|
||||
use proc_macros::fanbox_api_quick_test;
|
||||
use reqwest::IntoUrl;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
@@ -157,6 +158,24 @@ impl FanboxClientInternal {
|
||||
)
|
||||
}
|
||||
|
||||
/// Send requests to speicfied url.
|
||||
/// * `url` - The url
|
||||
/// * `errmsg` - The error message when error occured.
|
||||
/// * `infomsg` - Verbose output info message.
|
||||
pub async fn get_url<U: IntoUrl + Clone, S: AsRef<str> + ?Sized, I: AsRef<str> + ?Sized>(
|
||||
&self,
|
||||
url: U,
|
||||
errmsg: &S,
|
||||
infomsg: &I,
|
||||
) -> Option<JsonValue> {
|
||||
self.auto_init();
|
||||
handle_data!(
|
||||
self.client.get(url, None),
|
||||
errmsg.as_ref(),
|
||||
infomsg.as_ref()
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
/// List home page's post list. All supported and followed creators' posts are included.
|
||||
/// * `limit` - The max count. 10 is used on Fanbox website.
|
||||
|
||||
Reference in New Issue
Block a user