diff --git a/.gitignore b/.gitignore index ba28109..d61fb69 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ test/ .workspace/ expand.rs +*.log diff --git a/src/download.rs b/src/download.rs index 5b5ccc0..078f8e6 100644 --- a/src/download.rs +++ b/src/download.rs @@ -35,7 +35,8 @@ use crate::Main; use indicatif::MultiProgress; use json::JsonValue; use reqwest::IntoUrl; -use std::fs::create_dir_all; +use std::fs::{create_dir_all, File}; +use std::io::Write; use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; @@ -786,6 +787,14 @@ pub async fn download_fanbox_post( np += 1; } } + FanboxPost::Text(t) => { + let text = t + .text() + .ok_or(gettext("Failed to get text from text post."))?; + let text_file = base.join("data.txt"); + let mut f = File::create(&text_file)?; + f.write_all(text.as_bytes())?; + } FanboxPost::Unknown(_) => { return Err(PixivDownloaderError::from(gettext( "Unrecognized post type.", diff --git a/src/fanbox/post.rs b/src/fanbox/post.rs index 55f120c..30f8ab8 100644 --- a/src/fanbox/post.rs +++ b/src/fanbox/post.rs @@ -1009,6 +1009,242 @@ impl ExifDataSource for FanboxPostImage { } } +/// Fanbox text post +pub struct FanboxPostText { + /// Raw data + pub data: JsonValue, + /// The api client + client: Arc, +} + +impl FanboxPostText { + #[inline] + pub fn text(&self) -> Option<&str> { + self.data["body"]["text"].as_str() + } + + #[inline] + pub fn comment_count(&self) -> Option { + self.data["commentCount"].as_u64() + } + + #[inline] + pub fn comment_list(&self) -> Option { + FanboxCommentList::new(&self.data["commentList"], Arc::clone(&self.client)) + } + + #[inline] + pub fn cover_image_url(&self) -> Option<&str> { + self.data["coverImageUrl"].as_str() + } + + #[inline] + pub fn creator_id(&self) -> Option<&str> { + self.data["creatorId"].as_str() + } + + #[inline] + pub fn excerpt(&self) -> Option<&str> { + self.data["excerpt"].as_str() + } + + #[inline] + pub fn fee_required(&self) -> Option { + self.data["feeRequired"].as_u64() + } + + #[inline] + pub fn has_adult_content(&self) -> Option { + self.data["hasAdultContent"].as_bool() + } + + #[inline] + pub fn id(&self) -> Option { + parse_u64(&self.data["id"]) + } + + #[inline] + pub fn image_for_share(&self) -> Option<&str> { + self.data["imageForShare"].as_str() + } + + #[inline] + pub fn is_liked(&self) -> Option { + self.data["isLiked"].as_bool() + } + + #[inline] + pub fn is_restricted(&self) -> Option { + self.data["isRestricted"].as_bool() + } + + #[inline] + pub fn like_count(&self) -> Option { + self.data["likeCount"].as_u64() + } + + #[inline] + /// Create a new instance + pub fn new(data: &JsonValue, client: Arc) -> Self { + Self { + data: data.clone(), + client, + } + } + + #[inline] + pub fn next_post(&self) -> Option { + let obj = &self.data["nextPost"]; + if obj.is_object() { + Some(FanboxPostRef::new(obj, Arc::clone(&self.client))) + } else { + None + } + } + + #[inline] + pub fn prev_post(&self) -> Option { + let obj = &self.data["prevPost"]; + if obj.is_object() { + Some(FanboxPostRef::new(obj, Arc::clone(&self.client))) + } else { + None + } + } + + #[inline] + pub fn published_datetime(&self) -> Option<&str> { + self.data["publishedDatetime"].as_str() + } + + #[inline] + pub fn tags(&self) -> Option> { + let mut list = Vec::new(); + let tags = &self.data["tags"]; + if tags.is_array() { + for i in tags.members() { + match i.as_str() { + Some(tag) => { + list.push(tag); + } + None => { + return None; + } + } + } + Some(list) + } else { + None + } + } + + #[inline] + pub fn title(&self) -> Option<&str> { + self.data["title"].as_str() + } + + #[inline] + pub fn updated_datetime(&self) -> Option<&str> { + self.data["updatedDatetime"].as_str() + } + + #[inline] + pub fn user_icon_url(&self) -> Option<&str> { + self.data["user"]["iconUrl"].as_str() + } + + #[inline] + pub fn user_id(&self) -> Option { + parse_u64(&self.data["user"]["userId"]) + } + + #[inline] + pub fn user_name(&self) -> Option<&str> { + self.data["user"]["name"].as_str() + } +} + +impl CheckUnknown for FanboxPostText { + fn check_unknown(&self) -> Result<(), FanboxAPIError> { + check_json_keys!( + "id"+, + "body": [ + "text"+text, + ], + "commentCount"+, + "commentList", + "coverImageUrl", + "creatorId"+, + "excerpt"+, + "feeRequired"+, + "hasAdultContent"+, + "imageForShare", + "isLiked"+, + "isRestricted"+, + "likeCount"+, + "nextPost", + "prevPost", + "publishedDatetime"+, + "restrictedFor", + "tags"+, + "title"+, + "type", + "updatedDatetime"+, + "user": [ + "userId"+user_id, + "iconUrl", + "name"+, + ], + ); + match self.comment_list() { + Some(list) => { + for i in list.items { + i.check_unknown()?; + } + } + None => {} + } + match self.next_post() { + Some(post) => post.check_unknown()?, + None => {} + } + match self.prev_post() { + Some(post) => post.check_unknown()?, + None => {} + } + Ok(()) + } +} + +impl Debug for FanboxPostText { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("FanboxPostText") + .field("id", &self.id()) + .field("text", &self.text()) + .field("comment_count", &self.comment_count()) + .field("comment_list", &self.comment_list()) + .field("cover_image_url", &self.cover_image_url()) + .field("creator_id", &self.creator_id()) + .field("excerpt", &self.excerpt()) + .field("fee_required", &self.fee_required()) + .field("has_adult_content", &self.has_adult_content()) + .field("image_for_share", &self.image_for_share()) + .field("is_liked", &self.is_liked()) + .field("is_restricted", &self.is_restricted()) + .field("like_count", &self.like_count()) + .field("next_post", &self.next_post()) + .field("prev_post", &self.prev_post()) + .field("published_datetime", &self.published_datetime()) + .field("tags", &self.tags()) + .field("title", &self.title()) + .field("updated_datetime", &self.updated_datetime()) + .field("user_icon_url", &self.user_icon_url()) + .field("user_id", &self.user_id()) + .field("user_name", &self.user_name()) + .finish_non_exhaustive() + } +} + /// A reference to another post pub struct FanboxPostRef { /// Raw data @@ -1143,6 +1379,8 @@ pub enum FanboxPost { File(FanboxPostFile), /// Image Image(FanboxPostImage), + /// Text + Text(FanboxPostText), /// Unknown Unknown(FanboxPostUnknown), } @@ -1156,6 +1394,7 @@ impl FanboxPost { "article" => Self::Article(FanboxPostArticle::new(data, client)), "file" => Self::File(FanboxPostFile::new(data, client)), "image" => Self::Image(FanboxPostImage::new(data, client)), + "text" => Self::Text(FanboxPostText::new(data, client)), _ => Self::Unknown(FanboxPostUnknown::new(data, client)), }, _ => Self::Unknown(FanboxPostUnknown::new(data, client)), @@ -1176,6 +1415,7 @@ impl FanboxPost { Self::Article(a) => a.comment_list(), Self::File(f) => f.comment_list(), Self::Image(i) => i.comment_list(), + Self::Text(t) => t.comment_list(), Self::Unknown(u) => u.comment_list(), } } @@ -1206,6 +1446,7 @@ impl FanboxPost { Self::Article(a) => &a.data, Self::File(f) => &f.data, Self::Image(a) => &a.data, + Self::Text(a) => &a.data, Self::Unknown(a) => &a.data, } } @@ -1246,6 +1487,7 @@ impl FanboxPost { Self::Article(a) => a.next_post(), Self::File(f) => f.next_post(), Self::Image(i) => i.next_post(), + Self::Text(t) => t.next_post(), Self::Unknown(u) => u.next_post(), } } @@ -1256,6 +1498,7 @@ impl FanboxPost { Self::Article(a) => a.prev_post(), Self::File(f) => f.prev_post(), Self::Image(i) => i.prev_post(), + Self::Text(t) => t.prev_post(), Self::Unknown(u) => u.prev_post(), } } @@ -1392,6 +1635,9 @@ fanbox_api_test!(test_get_post_info2, { println!("{:#?}", data); } } + if data.is_restricted().unwrap() { + return; + } match data.check_unknown() { Ok(_) => {} Err(e) => { @@ -1420,6 +1666,9 @@ fanbox_api_test!(test_get_post_info3, { println!("{:#?}", data); } } + if data.is_restricted().unwrap() { + return; + } match data.check_unknown() { Ok(_) => {} Err(e) => {