mirror of
https://github.com/lifegpc/pixiv_downloader.git
synced 2026-07-08 01:32:41 +08:00
Update
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1337,6 +1337,7 @@ name = "proc_macros"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"convert_case 0.5.0",
|
||||
"json",
|
||||
"parse_duration",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -12,6 +12,7 @@ proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
convert_case = "0.5"
|
||||
json = "0"
|
||||
parse_duration = "2"
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use convert_case::Case;
|
||||
use convert_case::Casing;
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Span;
|
||||
use quote::quote;
|
||||
use std::io::Read;
|
||||
use std::str::FromStr;
|
||||
use syn::bracketed;
|
||||
use syn::parse::Parse;
|
||||
use syn::parse_macro_input;
|
||||
@@ -735,3 +738,140 @@ pub fn create_fanbox_download_helper(item: TokenStream) -> TokenStream {
|
||||
);
|
||||
stream.into()
|
||||
}
|
||||
|
||||
fn read_json_file<P: AsRef<std::path::Path> + ?Sized>(p: &P) -> json::JsonValue {
|
||||
let mut f = std::fs::File::open(p).unwrap();
|
||||
let mut s = String::new();
|
||||
f.read_to_string(&mut s).unwrap();
|
||||
json::parse(s.as_str()).unwrap()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn define_exif_data_source(item: TokenStream) -> TokenStream {
|
||||
let file_path = parse_macro_input!(item as LitStr).value();
|
||||
let path =
|
||||
std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join(file_path);
|
||||
let data = read_json_file(&path);
|
||||
let mut streams = Vec::new();
|
||||
for (key, data) in data.entries() {
|
||||
let doc = match data["description"].as_str() {
|
||||
Some(doc) => {
|
||||
let doc = LitStr::new(doc, Span::call_site());
|
||||
quote!(#[doc = #doc])
|
||||
}
|
||||
None => {
|
||||
quote!()
|
||||
}
|
||||
};
|
||||
let fname = Ident::new(key, Span::call_site());
|
||||
let result = proc_macro2::TokenStream::from_str(match data["return"].as_str() {
|
||||
Some(r) => r,
|
||||
None => "String",
|
||||
})
|
||||
.unwrap();
|
||||
streams.push(quote!(
|
||||
#doc
|
||||
#[inline]
|
||||
fn #fname(&self) -> Option<#result> {
|
||||
None
|
||||
}
|
||||
));
|
||||
}
|
||||
let stream = quote!(
|
||||
#(#streams)*
|
||||
);
|
||||
stream.into()
|
||||
}
|
||||
|
||||
struct CallParentDataSourceFun {
|
||||
pub file: LitStr,
|
||||
pub expr: Expr,
|
||||
pub keys: Vec<Ident>,
|
||||
pub is_include: bool,
|
||||
}
|
||||
|
||||
impl Parse for CallParentDataSourceFun {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let filel = Lit::parse(input)?;
|
||||
let file = match filel {
|
||||
Lit::Str(s) => s,
|
||||
_ => {
|
||||
return Err(syn::Error::new(filel.span(), "Unsupported literal."));
|
||||
}
|
||||
};
|
||||
token::Comma::parse(input)?;
|
||||
let expr = input.parse()?;
|
||||
let mut keys = Vec::new();
|
||||
let mut is_include = false;
|
||||
let mut is_first = true;
|
||||
loop {
|
||||
if input.cursor().eof() {
|
||||
break;
|
||||
}
|
||||
token::Comma::parse(input)?;
|
||||
if input.cursor().eof() {
|
||||
break;
|
||||
}
|
||||
if is_first {
|
||||
is_first = false;
|
||||
match syn::Lit::parse(input) {
|
||||
Ok(lit) => {
|
||||
match lit {
|
||||
syn::Lit::Bool(lit) => {
|
||||
is_include = lit.value();
|
||||
}
|
||||
_ => {
|
||||
return Err(syn::Error::new(lit.span(), "Unsupported literal."));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
keys.push(Ident::parse(input)?);
|
||||
}
|
||||
Ok(Self {
|
||||
file,
|
||||
expr,
|
||||
keys,
|
||||
is_include,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn call_parent_data_source_fun(item: TokenStream) -> TokenStream {
|
||||
let CallParentDataSourceFun {
|
||||
file,
|
||||
expr,
|
||||
keys,
|
||||
is_include,
|
||||
} = parse_macro_input!(item as CallParentDataSourceFun);
|
||||
let path =
|
||||
std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join(file.value());
|
||||
let data = read_json_file(&path);
|
||||
let mut streams = Vec::new();
|
||||
for (key, data) in data.entries() {
|
||||
let is_in = keys.iter().find(|&r| r.to_string() == key).is_some();
|
||||
if is_in != is_include {
|
||||
continue;
|
||||
}
|
||||
let fname = Ident::new(key, Span::call_site());
|
||||
let result = proc_macro2::TokenStream::from_str(match data["return"].as_str() {
|
||||
Some(r) => r,
|
||||
None => "String",
|
||||
})
|
||||
.unwrap();
|
||||
streams.push(quote!(
|
||||
#[inline]
|
||||
fn #fname(&self) -> Option<#result> {
|
||||
(#expr).#fname()
|
||||
}
|
||||
));
|
||||
}
|
||||
let stream = quote!(
|
||||
#(#streams)*
|
||||
);
|
||||
stream.into()
|
||||
}
|
||||
|
||||
@@ -6,27 +6,31 @@ use crate::exif::ExifTypeID;
|
||||
use crate::exif::ExifValue;
|
||||
use crate::ext::try_err::TryErr;
|
||||
use crate::parser::description::parse_description;
|
||||
use proc_macros::call_parent_data_source_fun;
|
||||
use proc_macros::define_exif_data_source;
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi::OsStr;
|
||||
use utf16string::LittleEndian;
|
||||
use utf16string::WString;
|
||||
|
||||
pub trait ExifDataSource {
|
||||
fn image_author(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
define_exif_data_source!("src/data/exif_data_source.json");
|
||||
}
|
||||
|
||||
fn image_comment(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
impl<T: ExifDataSource> ExifDataSource for std::sync::Arc<T> {
|
||||
call_parent_data_source_fun!("src/data/exif_data_source.json", *self,);
|
||||
}
|
||||
|
||||
fn image_id(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
fn image_title(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
impl<T: ExifDataSource> ExifDataSource for Option<T> {
|
||||
call_parent_data_source_fun!(
|
||||
"src/data/exif_data_source.json",
|
||||
match self {
|
||||
Some(data) => data,
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn add_image_id<D: ExifDataSource>(data: &mut ExifData, d: &D) -> Result<(), ()> {
|
||||
|
||||
6
src/data/exif_data_source.json
Normal file
6
src/data/exif_data_source.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"image_author": { "return": "String", "description": "The author of the image." },
|
||||
"image_comment": { "return": "String", "description": "The comment of the image." },
|
||||
"image_id": { "return": "String", "description": "The image id." },
|
||||
"image_title": { "return": "String", "description": "The title of the image." }
|
||||
}
|
||||
@@ -1,12 +1,18 @@
|
||||
#[cfg(feature = "exif")]
|
||||
use super::exif::ExifDataSource;
|
||||
use crate::fanbox::post::FanboxPost;
|
||||
use crate::pixiv_link::PixivID;
|
||||
use crate::pixiv_link::ToPixivID;
|
||||
use json::JsonValue;
|
||||
#[cfg(feature = "exif")]
|
||||
use proc_macros::call_parent_data_source_fun;
|
||||
|
||||
pub struct FanboxData {
|
||||
pub id: PixivID,
|
||||
/// Raw data
|
||||
pub raw: JsonValue,
|
||||
#[cfg(feature = "exif")]
|
||||
pub exif_data: Option<Box<dyn ExifDataSource>>,
|
||||
}
|
||||
|
||||
impl FanboxData {
|
||||
@@ -15,8 +21,28 @@ impl FanboxData {
|
||||
Some(id) => Some(Self {
|
||||
id,
|
||||
raw: post.get_json().clone(),
|
||||
#[cfg(feature = "exif")]
|
||||
exif_data: None,
|
||||
}),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "exif")]
|
||||
impl ExifDataSource for FanboxData {
|
||||
call_parent_data_source_fun!(
|
||||
"src/data/exif_data_source.json",
|
||||
match &self.exif_data {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
},
|
||||
image_id,
|
||||
);
|
||||
|
||||
fn image_id(&self) -> Option<String> {
|
||||
Some(self.id.to_link())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ impl Main {
|
||||
if d.is_downloaded() {
|
||||
#[cfg(feature = "exif")]
|
||||
{
|
||||
if add_exifdata_to_image(&file_name, &*datas, np).is_err() {
|
||||
if add_exifdata_to_image(&file_name, &datas, np).is_err() {
|
||||
println!(
|
||||
"{} {}",
|
||||
gettext("Failed to add exif data to image:"),
|
||||
@@ -150,7 +150,7 @@ impl Main {
|
||||
#[cfg(feature = "exif")]
|
||||
{
|
||||
if helper.update_exif() && file_name.exists() {
|
||||
if add_exifdata_to_image(&file_name, &*datas, np).is_err() {
|
||||
if add_exifdata_to_image(&file_name, &datas, np).is_err() {
|
||||
println!(
|
||||
"{} {}",
|
||||
gettext("Failed to add exif data to image:"),
|
||||
|
||||
Reference in New Issue
Block a user