Skip to content

Commit

Permalink
Add app api
Browse files Browse the repository at this point in the history
  • Loading branch information
lifegpc authored Oct 5, 2023
1 parent db101b5 commit 25006a6
Show file tree
Hide file tree
Showing 17 changed files with 543 additions and 55 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ int-enum = "0.5"
itertools = "0.10"
json = "0.12"
lazy_static = "1.4"
md5 = "0.7"
modular-bitfield = "0.11"
multipart = { features = ["server"], git = 'https://github.com/lifegpc/multipart', optional = true, default-features = false }
openssl = { version = "0.10", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion Language/pixiv_downloader.pot
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ msgid "Failed to flush file:"
msgstr ""

#: src/settings_list.rs:24
msgid "Pixiv's refresh tokens. Used to login."
msgid "Pixiv's refresh token. Used to login."
msgstr ""

#: src/settings_list.rs:30
Expand Down
4 changes: 2 additions & 2 deletions Language/pixiv_downloader.zh_CN.po
Original file line number Diff line number Diff line change
Expand Up @@ -915,8 +915,8 @@ msgid "Failed to flush file:"
msgstr "无法刷新文件缓冲区:"

#: src/settings_list.rs:24
msgid "Pixiv's refresh tokens. Used to login."
msgstr "Pixiv 的 refresh tokens。用于登录。"
msgid "Pixiv's refresh token. Used to login."
msgstr "Pixiv 的 refresh token。用于登录。"

#: src/settings_list.rs:30
msgid "Remove the part which after these parttens."
Expand Down
41 changes: 41 additions & 0 deletions proc_macros/proc_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -944,3 +944,44 @@ pub fn http_error(item: TokenStream) -> TokenStream {
);
stream.into()
}

struct PrintError {
pub msg: Expr,
pub expr: Expr,
pub re: Option<Expr>,
}

impl Parse for PrintError {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let msg = input.parse()?;
input.parse::<token::Comma>()?;
let expr = input.parse()?;
let mut re = None;
match input.parse::<token::Comma>() {
Ok(_) => {
re.replace(input.parse()?);
}
Err(_) => {}
}
Ok(Self { msg, expr, re })
}
}

#[proc_macro]
pub fn print_error(item: TokenStream) -> TokenStream {
let PrintError { msg, expr, re } = parse_macro_input!(item as PrintError);
let re = match re {
Some(re) => quote!(#re),
None => quote!(None),
};
let stream = quote!(
match (#expr) {
Ok(re) => re,
Err(e) => {
println!("{}{}", #msg, e);
return #re;
}
}
);
stream.into()
}
71 changes: 58 additions & 13 deletions src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::data::fanbox::FanboxData;
use crate::data::json::JSONDataFile;
#[cfg(feature = "ugoira")]
use crate::data::video::get_video_metadata;
#[cfg(feature = "db")]
use crate::db::open_and_init_database;
use crate::downloader::Downloader;
use crate::downloader::DownloaderHelper;
use crate::downloader::DownloaderResult;
Expand All @@ -23,6 +25,7 @@ use crate::fanbox::post::FanboxPost;
use crate::fanbox_api::FanboxClient;
use crate::gettext;
use crate::opthelper::get_helper;
use crate::pixiv_app::PixivAppClient;
use crate::pixiv_link::FanboxPostID;
use crate::pixiv_link::PixivID;
use crate::pixiv_web::PixivWebClient;
Expand All @@ -34,6 +37,7 @@ use crate::utils::get_file_name_from_url;
use crate::Main;
use indicatif::MultiProgress;
use json::JsonValue;
use proc_macros::print_error;
use reqwest::IntoUrl;
use std::fs::{create_dir_all, File};
use std::io::Write;
Expand All @@ -45,25 +49,23 @@ impl Main {
pub async fn download(&mut self) -> i32 {
let pw = Arc::new(PixivWebClient::new());
let fc = Arc::new(FanboxClient::new());
#[cfg(feature = "db")]
let db = Arc::new(print_error!(
gettext("Failed to open database:"),
open_and_init_database(get_helper().db()).await,
0
));
#[cfg(not(feature = "db"))]
let ac = Arc::new(PixivAppClient::new());
#[cfg(feature = "db")]
let ac = PixivAppClient::with_db(Some(db));
let tasks = TaskManager::new_post();
let download_multiple_posts = get_helper().download_multiple_posts();
for id in self.cmd.as_ref().unwrap().ids.iter() {
match id {
PixivID::Artwork(id) => {
if !pw.is_inited() {
if !pw.init() {
println!("{}", gettext("Failed to initialize pixiv web api client."));
return 1;
}
if !pw.check_login().await {
return 1;
}
if !pw.logined() {
println!("{}", gettext("Warning: Web api client not logged in, some future may not work."));
}
}
tasks
.add_task(download_artwork(Arc::clone(&pw), id.clone()))
.add_task(download_artwork(ac.clone(), Arc::clone(&pw), id.clone()))
.await;
if !download_multiple_posts {
tasks.join().await;
Expand Down Expand Up @@ -249,9 +251,52 @@ pub async fn download_artwork_link<L: IntoUrl + Clone>(
}

pub async fn download_artwork(
ac: PixivAppClient,
pw: Arc<PixivWebClient>,
id: u64,
) -> Result<(), PixivDownloaderError> {
let helper = get_helper();
let app_ok = helper.refresh_token().is_some();
if app_ok && helper.use_app_api() {
if let Err(e) = download_artwork_app(ac, pw.clone(), id).await {
println!("{}{}", gettext("Warning: Failed to download artwork with app api, trying to download with web api: "), e);
download_artwork_web(pw.clone(), id).await?;
}
} else if app_ok {
if let Err(_) = download_artwork_web(pw.clone(), id).await {
download_artwork_app(ac, pw.clone(), id).await?;
}
} else {
download_artwork_web(pw, id).await?;
}
Ok(())
}

pub async fn download_artwork_app(
ac: PixivAppClient,
pw: Arc<PixivWebClient>,
id: u64,
) -> Result<(), PixivDownloaderError> {
let data = ac.get_illust_details(id).await?;
Ok(())
}

pub async fn download_artwork_web(
pw: Arc<PixivWebClient>,
id: u64,
) -> Result<(), PixivDownloaderError> {
if !pw.is_login_checked() {
if !pw.check_login().await {
println!("{}", gettext("Failed to check login status."));
} else {
if !pw.logined() {
println!(
"{}",
gettext("Warning: Web api client not logged in, some future may not work.")
);
}
}
}
let mut re = None;
let pages;
let mut ajax_ver = true;
Expand Down
1 change: 0 additions & 1 deletion src/downloader/downloader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ pub trait SetLen {
fn set_len(&mut self, size: u64) -> Result<(), DownloaderError>;
}

#[derive(Debug)]
/// A file downloader
pub struct DownloaderInternal<
T: Write + Seek + Send + Sync + ClearFile + GetTargetFileName + SetLen,
Expand Down
1 change: 0 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ pub enum PixivDownloaderError {
FromUtf8Error(std::string::FromUtf8Error),
#[cfg(feature = "server")]
ToStrError(http::header::ToStrError),
#[cfg(all(feature = "server", feature = "db_sqlite", test))]
JSONError(json::Error),
#[cfg(feature = "openssl")]
OpenSSLError(openssl::error::ErrorStack),
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ mod opt;
mod opthelper;
mod opts;
mod parser;
mod pixiv_app;
mod pixiv_link;
mod pixiv_web;
mod push;
Expand Down
21 changes: 21 additions & 0 deletions src/opthelper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,16 @@ impl OptHelper {
65536
}

pub fn refresh_token(&self) -> Option<String> {
if self.opt.get_ref().refresh_token.is_some() {
self.opt.get_ref().refresh_token.clone()
} else if self.settings.get_ref().have_str("refresh-token") {
self.settings.get_ref().get_str("refresh-token")
} else {
None
}
}

pub fn update(&self, opt: CommandOpts, settings: SettingStore) {
if settings.have("author-name-filters") {
self._author_name_filters.replace_with2(
Expand Down Expand Up @@ -323,6 +333,17 @@ impl OptHelper {
self.settings.replace_with2(settings);
}

/// Whether to use Pixiv APP API first.
pub fn use_app_api(&self) -> bool {
if self.opt.get_ref().use_app_api.is_some() {
return self.opt.get_ref().use_app_api.unwrap();
}
if self.settings.get_ref().have("use-app-api") {
return self.settings.get_ref().get_bool("use-app-api").unwrap();
}
false
}

pub fn overwrite(&self) -> Option<bool> {
self.opt.get_ref().overwrite
}
Expand Down
40 changes: 40 additions & 0 deletions src/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ pub struct CommandOpts {
#[cfg(feature = "ugoira")]
pub ugoira_max_fps: Option<f32>,
pub fanbox_page_number: Option<bool>,
/// Pixiv's refresh token. Used to login.
pub refresh_token: Option<String>,
/// Whether to use Pixiv APP API first.
pub use_app_api: Option<bool>,
}

impl CommandOpts {
Expand Down Expand Up @@ -163,6 +167,8 @@ impl CommandOpts {
#[cfg(feature = "ugoira")]
ugoira_max_fps: None,
fanbox_page_number: None,
refresh_token: None,
use_app_api: None,
}
}

Expand Down Expand Up @@ -591,6 +597,26 @@ pub fn parse_cmd() -> Option<CommandOpts> {
HasArg::Maybe,
getopts::Occur::Optional,
);
opts.optopt(
"",
"refresh-token",
gettext("Pixiv's refresh token. Used to login."),
"TOKEN",
);
opts.opt(
"",
"use-app-api",
format!(
"{} ({} {})",
gettext("Whether to use Pixiv APP API first."),
gettext("Default:"),
"yes"
)
.as_str(),
"yes/no",
HasArg::Maybe,
getopts::Occur::Optional,
);
let result = match opts.parse(&argv[1..]) {
Ok(m) => m,
Err(err) => {
Expand Down Expand Up @@ -952,6 +978,20 @@ pub fn parse_cmd() -> Option<CommandOpts> {
return None;
}
}
re.as_mut().unwrap().refresh_token = result.opt_str("refresh-token");
match parse_optional_opt(&result, "use-app-api", true, parse_bool) {
Ok(b) => re.as_mut().unwrap().use_app_api = b,
Err(e) => {
println!(
"{} {}",
gettext("Failed to parse <opt>:")
.replace("<opt>", "use-app-api")
.as_str(),
e
);
return None;
}
}
re
}

Expand Down
Loading

0 comments on commit 25006a6

Please sign in to comment.