fanbox api: deserialize fanbox item

This commit is contained in:
2022-06-26 08:06:19 +00:00
committed by GitHub
parent 742877489b
commit ad97e261cb
6 changed files with 188 additions and 15 deletions

10
src/fanbox/error.rs Normal file
View 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
View 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
View 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()
}
}

View File

@@ -1 +1,4 @@
pub mod error;
pub mod item;
pub mod item_list;
pub mod paginated_creator_posts;

View File

@@ -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.")

View File

@@ -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.