Support download fanbox image post

This commit is contained in:
2022-07-15 09:16:31 +00:00
committed by GitHub
parent 26f2bb32bd
commit 8cdde2fd65
8 changed files with 217 additions and 24 deletions

View File

@@ -706,31 +706,81 @@ pub fn derive_check_unknown(item: TokenStream) -> TokenStream {
}
struct CreateFanboxDownloadHelper {
pub file_name: Option<Expr>,
pub fn_name: Ident,
pub headers: Option<Expr>,
}
impl Parse for CreateFanboxDownloadHelper {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let fn_name = input.parse()?;
Ok(Self { fn_name })
let mut file_name = None;
let mut headers = None;
loop {
if input.cursor().eof() {
break;
}
token::Comma::parse(input)?;
if input.cursor().eof() {
break;
}
let name: Ident = input.parse()?;
let nname = name.to_string();
match nname.as_str() {
"file_path" => {
token::Eq::parse(input)?;
file_name.replace(Expr::parse(input)?);
}
"headers" => {
token::Eq::parse(input)?;
headers.replace(Expr::parse(input)?);
}
_ => {
return Err(syn::Error::new(name.span(), "Unsupported name."));
}
}
}
Ok(Self {
file_name,
fn_name,
headers,
})
}
}
#[proc_macro]
pub fn create_fanbox_download_helper(item: TokenStream) -> TokenStream {
let CreateFanboxDownloadHelper { fn_name } =
parse_macro_input!(item as CreateFanboxDownloadHelper);
let CreateFanboxDownloadHelper {
file_name,
fn_name,
headers,
} = parse_macro_input!(item as CreateFanboxDownloadHelper);
let defn_name = Ident::new(
format!("download_{}", fn_name.to_string()).as_str(),
fn_name.span(),
);
let headers = match headers {
Some(headers) => {
quote!(.headers(#headers))
}
None => quote!(),
};
let file_name = match file_name {
Some(file_name) => {
quote!(.file_name(#file_name))
}
None => quote!(),
};
let stream = quote!(
#[inline]
pub fn #defn_name(&self) -> Result<Option<crate::downloader::DownloaderHelper>, crate::downloader::DownloaderError> {
match self.#fn_name() {
Some(url) => {
let client: &std::sync::Arc<crate::webclient::WebClient> = self.client.as_ref().as_ref();
Ok(Some(crate::downloader::DownloaderHelper::builder(url)?.client(client).build()))
Ok(Some(crate::downloader::DownloaderHelper::builder(url)?.client(client)
#file_name
#headers
.build()))
}
None => Ok(None),
}

View File

@@ -18,7 +18,10 @@ pub trait ExifDataSource {
}
impl<T: ExifDataSource> ExifDataSource for std::sync::Arc<T> {
call_parent_data_source_fun!("src/data/exif_data_source.json", *self,);
call_parent_data_source_fun!(
"src/data/exif_data_source.json",
std::ops::Deref::deref(self),
);
}
impl<T: ExifDataSource> ExifDataSource for Option<T> {

View File

@@ -29,6 +29,16 @@ impl FanboxData {
}
}
impl Clone for FanboxData {
fn clone(&self) -> Self {
Self {
id: self.id.clone(),
raw: self.raw.clone(),
exif_data: None,
}
}
}
#[cfg(feature = "exif")]
impl ExifDataSource for FanboxData {
call_parent_data_source_fun!(

View File

@@ -120,6 +120,17 @@ impl From<FanboxData> for JSONDataFile {
}
}
impl From<&FanboxData> for JSONDataFile {
fn from(d: &FanboxData) -> Self {
let mut f = Self {
id: d.id.clone(),
maps: HashMap::new(),
};
f.add("raw", d.raw.clone()).unwrap();
f
}
}
impl ToJson for JSONDataFile {
fn to_json(&self) -> Option<JsonValue> {
let mut value = json::object! {};

View File

@@ -9,6 +9,7 @@ use crate::data::json::JSONDataFile;
#[cfg(feature = "ugoira")]
use crate::data::video::get_video_metadata;
use crate::downloader::Downloader;
use crate::downloader::DownloaderHelper;
use crate::downloader::DownloaderResult;
use crate::downloader::LocalFile;
use crate::error::PixivDownloaderError;
@@ -28,7 +29,7 @@ use crate::Main;
use indicatif::MultiProgress;
use json::JsonValue;
use reqwest::IntoUrl;
use std::fs::create_dir;
use std::fs::create_dir_all;
use std::path::PathBuf;
use std::sync::Arc;
@@ -372,6 +373,65 @@ impl Main {
Ok(())
}
/// Download a fanbox image link
/// * `dh` - Link and other informations
/// * `np` - Number of page
/// * `progress_bars` - Multiple progress bars
/// * `datas` - The artwork's data
/// * `base` - The directory of the target
pub async fn download_fanbox_image(
&self,
dh: DownloaderHelper,
np: u16,
progress_bars: Option<Arc<MultiProgress>>,
datas: Arc<FanboxData>,
base: Arc<PathBuf>,
) -> Result<(), PixivDownloaderError> {
let helper = get_helper();
let file_name = dh
.get_local_file_path(&*base)
.try_err(gettext("Failed to get file name from url."))?;
match dh.download_local(helper.overwrite(), &*base)? {
DownloaderResult::Ok(d) => {
d.handle_options(&helper, progress_bars);
d.download();
d.join().await?;
if d.is_downloaded() {
#[cfg(feature = "exif")]
{
if add_exifdata_to_image(&file_name, &datas, np).is_err() {
println!(
"{} {}",
gettext("Failed to add exif data to image:"),
file_name.to_str().unwrap_or("(null)")
);
}
}
} else if d.is_panic() {
return Err(PixivDownloaderError::from(
d.get_panic()
.try_err(gettext("Failed to get error message."))?,
));
}
}
DownloaderResult::Canceled => {
#[cfg(feature = "exif")]
{
if helper.update_exif() && file_name.exists() {
if add_exifdata_to_image(&file_name, &datas, np).is_err() {
println!(
"{} {}",
gettext("Failed to add exif data to image:"),
file_name.to_str().unwrap_or("(null)")
);
}
}
}
}
}
Ok(())
}
pub async fn download_fanbox_post(
&self,
fc: Arc<FanboxClient>,
@@ -406,9 +466,9 @@ impl Main {
let base = Arc::new(PathBuf::from(format!("./{}/{}", id.creator_id, id.post_id)));
let json_file = base.join("data.json");
let data = FanboxData::new(id, &post).try_err("Failed to create data file.")?;
let data_file = JSONDataFile::from(data);
let data_file = JSONDataFile::from(&data);
if !base.exists() {
match create_dir(&*base) {
match create_dir_all(&*base) {
Ok(_) => {}
Err(e) => {
if !base.exists() {
@@ -423,15 +483,32 @@ impl Main {
match post {
FanboxPost::Article(article) => {}
FanboxPost::Image(img) => {
let img = Arc::new(img);
let body = img
.body()
.try_err(gettext("Failed to get the body of image post."))?;
let text = body
.text()
.try_err(gettext("Failed to get the text of the image post."))?;
let images = body
.images()
.try_err(gettext("Failed to get images from the image post."))?;
let mut np = 0;
let mut datas = data.clone();
datas.exif_data.replace(Box::new(Arc::clone(&img)));
let datas = Arc::new(datas);
for img in images.iter() {
let dh = img
.download_original_url()?
.try_err(gettext("Can not get original url for image"))?;
Self::download_fanbox_image(
&self,
dh,
np,
None,
Arc::clone(&datas),
Arc::clone(&base),
)
.await?;
np += 1;
}
}
FanboxPost::Unknown(_) => {
return Err(PixivDownloaderError::from(gettext(

View File

@@ -3,6 +3,7 @@ use super::enums::DownloaderResult;
use super::error::DownloaderError;
use super::local_file::LocalFile;
use crate::ext::replace::ReplaceWith;
use crate::ext::try_err::TryErr;
use crate::gettext;
use crate::webclient::ToHeaders;
use crate::webclient::WebClient;
@@ -48,18 +49,9 @@ impl DownloaderHelper {
overwrite: Option<bool>,
base: &P,
) -> Result<DownloaderResult<Downloader<LocalFile>>, DownloaderError> {
let base = base.as_ref();
let file = match &self.file_name {
Some(file_name) => base.join(file_name.as_ref()),
None => match crate::utils::get_file_name_from_url(self.url.clone()) {
Some(file_name) => base.join(file_name),
None => {
return Err(DownloaderError::from(gettext(
"Failed to get file name from url.",
)));
}
},
};
let file = self
.get_local_file_path(base)
.try_err(gettext("Failed to get file name from url."))?;
let headers = match &self.headers {
Some(headers) => headers.to_headers(),
None => None,
@@ -76,6 +68,20 @@ impl DownloaderHelper {
}
}
pub fn get_local_file_path<P: AsRef<Path> + ?Sized>(
&self,
base: &P,
) -> Option<std::path::PathBuf> {
let base = base.as_ref();
match &self.file_name {
Some(file_name) => Some(base.join(file_name.as_ref())),
None => match crate::utils::get_file_name_from_url(self.url.clone()) {
Some(file_name) => Some(base.join(file_name)),
None => None,
},
}
}
pub fn set_client(&mut self, client: &Arc<WebClient>) {
self.client.replace(Arc::clone(client));
}

View File

@@ -100,7 +100,7 @@ fanbox_api_test!(test_comment_list, {
);
match data {
FanboxPost::Article(a) => {
println!("{:?}", a);
println!("{:#?}", a);
match a.check_unknown() {
Ok(_) => {}
Err(e) => {

View File

@@ -3,6 +3,8 @@ use super::article::image::FanboxArticleImage;
use super::check::CheckUnknown;
use super::comment_list::FanboxCommentList;
use super::error::FanboxAPIError;
#[cfg(feature = "exif")]
use crate::data::exif::ExifDataSource;
use crate::fanbox_api::FanboxClientInternal;
use crate::parser::json::parse_u64;
use json::JsonValue;
@@ -313,6 +315,16 @@ impl Debug for FanboxImageBody {
}
}
#[cfg(feature = "exif")]
impl ExifDataSource for FanboxImageBody {
fn image_comment(&self) -> Option<String> {
match self.text() {
Some(text) => Some(text.to_owned()),
None => None,
}
}
}
/// Fanbox image post
pub struct FanboxPostImage {
/// Raw data
@@ -558,6 +570,30 @@ impl Debug for FanboxPostImage {
}
}
#[cfg(feature = "exif")]
impl ExifDataSource for FanboxPostImage {
fn image_author(&self) -> Option<String> {
match self.user_name() {
Some(u) => Some(u.to_owned()),
None => None,
}
}
fn image_comment(&self) -> Option<String> {
match self.body() {
Some(body) => body.image_comment(),
None => None,
}
}
fn image_title(&self) -> Option<String> {
match self.title() {
Some(t) => Some(t.to_owned()),
None => None,
}
}
}
/// A reference to another post
pub struct FanboxPostRef {
/// Raw data