From c00fbfde9c5f0267f9bad7340d51c66c2214adca Mon Sep 17 00:00:00 2001 From: lifegpc Date: Mon, 30 May 2022 10:44:33 +0000 Subject: [PATCH] Update OptHelper, current only an instance in whole programs --- src/data/data.rs | 8 ++- src/download.rs | 21 ++++---- src/main.rs | 12 +++-- src/opthelper.rs | 131 +++++++++++++++++++++++++++-------------------- src/opts.rs | 6 +++ src/pixiv_web.rs | 30 +++++------ src/webclient.rs | 16 ++++-- 7 files changed, 130 insertions(+), 94 deletions(-) diff --git a/src/data/data.rs b/src/data/data.rs index bb9bc04..6cc55d8 100644 --- a/src/data/data.rs +++ b/src/data/data.rs @@ -1,6 +1,6 @@ use crate::author_name_filter::AuthorFiler; use crate::gettext; -use crate::opthelper::OptHelper; +use crate::opthelper::get_helper; use crate::pixiv_link::ToPixivID; use crate::pixiv_link::PixivID; use json::JsonValue; @@ -16,11 +16,10 @@ pub struct PixivData { /// The author pub author: Option, pub description: Option, - helper: OptHelper, } impl PixivData { - pub fn new(id: T, helper: OptHelper) -> Option { + pub fn new(id: T) -> Option { let i = id.to_pixiv_id(); if i.is_none() { return None; @@ -30,7 +29,6 @@ impl PixivData { title: None, author: None, description: None, - helper: helper, }) } @@ -59,7 +57,7 @@ impl PixivData { let author = value["userName"].as_str(); if author.is_some() { let au = author.unwrap(); - match self.helper.author_name_filters() { + match get_helper().author_name_filters() { Some(l) => { self.author = Some(l.filter(au)) } None => { self.author = Some(String::from(author.unwrap())); } } diff --git a/src/download.rs b/src/download.rs index a6580e8..8a3b805 100644 --- a/src/download.rs +++ b/src/download.rs @@ -9,7 +9,7 @@ use crate::data::video::get_video_metadata; use crate::downloader::pd_file::enums::PdFileResult; use crate::downloader::pd_file::PdFile; use crate::gettext; -use crate::opthelper::OptHelper; +use crate::opthelper::get_helper; use crate::pixiv_link::PixivID; use crate::pixiv_web::PixivWebClient; #[cfg(feature = "ugoira")] @@ -26,7 +26,7 @@ use std::sync::Arc; impl Main { pub fn download(&mut self) -> i32 { - let pw = Arc::new(PixivWebClient::new(&self)); + let pw = Arc::new(PixivWebClient::new()); if !pw.init() { println!("{}", gettext("Failed to initialize pixiv web api client.")); return 1; @@ -53,7 +53,7 @@ impl Main { 0 } - pub async fn download_artwork_page(pw: Arc, page: JsonValue, np: u16, progress_bars: Arc, datas: Arc, base: Arc, helper: Arc) -> i32 { + pub async fn download_artwork_page(pw: Arc, page: JsonValue, np: u16, progress_bars: Arc, datas: Arc, base: Arc) -> i32 { let link = &page["urls"]["original"]; if !link.is_string() { println!("{}", gettext("Failed to get original picture's link.")); @@ -67,6 +67,7 @@ impl Main { } let file_name = file_name.unwrap(); let file_name = base.join(file_name); + let helper = get_helper(); let pdf = match PdFile::open(&file_name) { Ok(f) => { match f { @@ -152,7 +153,7 @@ impl Main { } } let r = r.unwrap(); - let re = WebClient::adownload_stream(&file_name, r, &helper, Some(progress_bars)).await; + let re = WebClient::adownload_stream(&file_name, r, Some(progress_bars)).await; if re.is_err() { println!("{} {}", gettext("Failed to download image:"), link); return 1; @@ -174,7 +175,7 @@ impl Main { let mut re = None; let pages; let mut ajax_ver = true; - let helper = Arc::new(pw.helper.clone()); + let helper = get_helper(); if helper.use_webpage() { re = pw.get_artwork(id); if re.is_some() { @@ -208,7 +209,7 @@ impl Main { } let base = Arc::new(PathBuf::from(".")); let json_file = base.join(format!("{}.json", id)); - let mut datas = PixivData::new(id, (*helper).clone()).unwrap(); + let mut datas = PixivData::new(id).unwrap(); if ajax_ver { datas.from_web_page_ajax_data(&re, true); } else { @@ -264,7 +265,7 @@ impl Main { return 1; } let r = r.unwrap(); - let re = WebClient::download_stream(&file_name, r, &helper); + let re = WebClient::download_stream(&file_name, r); if re.is_err() { println!("{} {}", gettext("Failed to download ugoira:"), src); return 1; @@ -315,7 +316,7 @@ impl Main { let progress_bars = Arc::new(MultiProgress::new()); let mut tasks = Vec::new(); for page in pages_data.members() { - let f = tokio::spawn(Self::download_artwork_page(Arc::clone(&pw), page.clone(), np, Arc::clone(&progress_bars), Arc::clone(&datas), Arc::clone(&base), Arc::clone(&helper))); + let f = tokio::spawn(Self::download_artwork_page(Arc::clone(&pw), page.clone(), np, Arc::clone(&progress_bars), Arc::clone(&datas), Arc::clone(&base))); tasks.push(f); np += 1; } @@ -377,7 +378,7 @@ impl Main { return 1; } let r = r.unwrap(); - let re = WebClient::download_stream(&file_name, r, &helper); + let re = WebClient::download_stream(&file_name, r); if re.is_err() { println!("{} {}", gettext("Failed to download image:"), link); return 1; @@ -447,7 +448,7 @@ impl Main { return 1; } let r = r.unwrap(); - let re = WebClient::download_stream(&file_name, r, &helper); + let re = WebClient::download_stream(&file_name, r); if re.is_err() { println!("{} {}", gettext("Failed to download image:"), link); return 1; diff --git a/src/main.rs b/src/main.rs index 91ecee7..f417cb4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -61,11 +61,12 @@ mod ugoira; mod utils; mod webclient; -use i18n::gettext; -use opts::Command; -use opts::CommandOpts; -use opts::ConfigCommand; -use settings::SettingStore; +use crate::i18n::gettext; +use crate::opthelper::get_helper; +use crate::opts::Command; +use crate::opts::CommandOpts; +use crate::opts::ConfigCommand; +use crate::settings::SettingStore; pub struct Main { pub cmd: Option, @@ -135,6 +136,7 @@ impl Main { } None => {} } + get_helper().update(cmd.clone(), self.settings.as_ref().unwrap().clone()); match cmd.cmd { Command::Config => { self.deal_config_cmd(); diff --git a/src/opthelper.rs b/src/opthelper.rs index 3ced2ee..d3e0439 100644 --- a/src/opthelper.rs +++ b/src/opthelper.rs @@ -1,5 +1,7 @@ use crate::author_name_filter::AuthorNameFilter; use crate::ext::json::FromJson; +use crate::ext::replace::ReplaceWith2; +use crate::ext::rw_lock::GetRwLock; use crate::ext::use_or_not::ToBool; use crate::ext::use_or_not::UseOrNot; use crate::opt::use_progress_bar::UseProgressBar; @@ -7,34 +9,37 @@ use crate::opts::CommandOpts; use crate::list::NonTailList; use crate::retry_interval::parse_retry_interval_from_json; use crate::settings::SettingStore; +use std::sync::Arc; +use std::sync::RwLock; +use std::sync::RwLockReadGuard; use std::time::Duration; /// An sturct to access all available settings/command line switches -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct OptHelper { /// Command Line Options - opt: CommandOpts, + opt: RwLock, /// Settings - settings: SettingStore, - default_retry_interval: NonTailList, - _author_name_filters: Option>, - _use_progress_bar: Option, + settings: RwLock, + default_retry_interval: RwLock>, + _author_name_filters: RwLock>, + _use_progress_bar: RwLock>, } impl OptHelper { - pub fn author_name_filters(&self) -> Option<&Vec> { - if self.settings.have("author-name-filters") { - return self._author_name_filters.as_ref(); + pub fn author_name_filters<'a>(&'a self) -> Option>> { + if self.settings.get_ref().have("author-name-filters") { + return Some(self._author_name_filters.get_ref()); } None } /// return cookies location, no any check pub fn cookies(&self) -> Option { - if self.opt.cookies.is_some() { - self.opt.cookies.clone() - } else if self.settings.have_str("cookies") { - self.settings.get_str("cookies") + if self.opt.get_ref().cookies.is_some() { + self.opt.get_ref().cookies.clone() + } else if self.settings.get_ref().have_str("cookies") { + self.settings.get_ref().get_str("cookies") } else { None } @@ -42,53 +47,47 @@ impl OptHelper { /// return language pub fn language(&self) -> Option { - if self.opt.language.is_some() { - self.opt.language.clone() - } else if self.settings.have_str("language") { - self.settings.get_str("language") + if self.opt.get_ref().language.is_some() { + self.opt.get_ref().language.clone() + } else if self.settings.get_ref().have_str("language") { + self.settings.get_ref().get_str("language") } else { None } } - pub fn new(opt: CommandOpts, settings: SettingStore) -> Self { + pub fn update(&self, opt: CommandOpts, settings: SettingStore) { let mut l = NonTailList::default(); l += Duration::new(3, 0); - let _author_name_filters = if settings.have("author-name-filters") { - Some(AuthorNameFilter::from_json(settings.get("author-name-filters").unwrap()).unwrap()) - } else { - None - }; - let _use_progress_bar = if opt.use_progress_bar.is_some() { + self.default_retry_interval.replace_with2(l); + if settings.have("author-name-filters") { + self._author_name_filters.replace_with2(AuthorNameFilter::from_json(settings.get("author-name-filters").unwrap()).unwrap()); + } + self._use_progress_bar.replace_with2(if opt.use_progress_bar.is_some() { Some(UseProgressBar::from(opt.use_progress_bar.unwrap())) } else if settings.have("use-progress-bar") { Some(UseProgressBar::from(UseOrNot::from_json(settings.get("use-progress-bar").unwrap()).unwrap())) } else { None - }; - Self { - opt, - settings, - default_retry_interval: l, - _author_name_filters: _author_name_filters, - _use_progress_bar: _use_progress_bar, - } + }); + self.opt.replace_with2(opt); + self.settings.replace_with2(settings); } pub fn overwrite(&self) -> Option { - self.opt.overwrite + self.opt.get_ref().overwrite } pub fn verbose(&self) -> bool { - self.opt.verbose + self.opt.get_ref().verbose } /// Return retry count pub fn retry(&self) -> Option { - if self.opt.retry.is_some() { - return Some(self.opt.retry.unwrap()); + if self.opt.get_ref().retry.is_some() { + return Some(self.opt.get_ref().retry.unwrap()); } - let re = self.settings.get("retry"); + let re = self.settings.get_ref().get("retry"); if re.is_some() { return Some(re.unwrap().as_u64().unwrap()); } @@ -97,23 +96,23 @@ impl OptHelper { /// Return retry interval pub fn retry_interval(&self) -> NonTailList { - if self.opt.retry_interval.is_some() { - return self.opt.retry_interval.as_ref().unwrap().clone(); + if self.opt.get_ref().retry_interval.is_some() { + return self.opt.get_ref().retry_interval.as_ref().unwrap().clone(); } - if self.settings.have("retry-interval") { - let v = self.settings.get("retry-interval").unwrap(); + if self.settings.get_ref().have("retry-interval") { + let v = self.settings.get_ref().get("retry-interval").unwrap(); return parse_retry_interval_from_json(v).unwrap(); } - self.default_retry_interval.clone() + self.default_retry_interval.get_ref().clone() } /// Return whether to use data from webpage first. pub fn use_webpage(&self) -> bool { - if self.opt.use_webpage { + if self.opt.get_ref().use_webpage { return true; } - if self.settings.have_bool("use-webpage") { - return self.settings.get_bool("use-webpage").unwrap(); + if self.settings.get_ref().have_bool("use-webpage") { + return self.settings.get_ref().get_bool("use-webpage").unwrap(); } false } @@ -122,40 +121,62 @@ impl OptHelper { /// Return whether to add/update exif information to image files even /// when overwrite are disabled. pub fn update_exif(&self) -> bool { - if self.opt.update_exif { + if self.opt.get_ref().update_exif { return true; } - if self.settings.have_bool("update-exif") { - return self.settings.get_bool("update-exif").unwrap(); + if self.settings.get_ref().have_bool("update-exif") { + return self.settings.get_ref().get_bool("update-exif").unwrap(); } false } /// Return whether to use progress bar. pub fn use_progress_bar(&self) -> bool { - if self._use_progress_bar.is_some() { - return self._use_progress_bar.as_ref().unwrap().to_bool(); + if self._use_progress_bar.get_ref().is_some() { + return self._use_progress_bar.get_ref().as_ref().unwrap().to_bool(); } atty::is(atty::Stream::Stdout) } /// Return progress bar's template pub fn progress_bar_template(&self) -> String { - if self.settings.have("progress-bar-template") { - return self.settings.get_str("progress-bar-template").unwrap() + if self.settings.get_ref().have("progress-bar-template") { + return self.settings.get_ref().get_str("progress-bar-template").unwrap() } String::from("[{elapsed_precise}] [{wide_bar:.green/yellow}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta}) {msg:40}") } /// Return whether to download multiple images at the same time. pub fn download_multiple_images(&self) -> bool { - match self.opt.download_multiple_images { + match self.opt.get_ref().download_multiple_images { Some(r) => { return r; } None => {} } - if self.settings.have_bool("download-multiple-images") { - return self.settings.get_bool("download-multiple-images").unwrap(); + if self.settings.get_ref().have_bool("download-multiple-images") { + return self.settings.get_ref().get_bool("download-multiple-images").unwrap(); } false } } + +impl Default for OptHelper { + fn default() -> Self { + Self { + opt: RwLock::new(CommandOpts::default()), + settings: RwLock::new(SettingStore::default()), + default_retry_interval: RwLock::new(NonTailList::default()), + _author_name_filters: RwLock::new(Vec::new()), + _use_progress_bar: RwLock::new(None), + } + } +} + +lazy_static!{ + #[doc(hidden)] + pub static ref HELPER: Arc = Arc::new(OptHelper::default()); +} + +/// Get a [OptHelper] interface. +pub fn get_helper() -> Arc { + Arc::clone(&HELPER) +} diff --git a/src/opts.rs b/src/opts.rs index db4d8bc..00d8880 100644 --- a/src/opts.rs +++ b/src/opts.rs @@ -366,3 +366,9 @@ pub fn parse_cmd() -> Option { } re } + +impl Default for CommandOpts { + fn default() -> Self { + Self::new(Command::None) + } +} diff --git a/src/pixiv_web.rs b/src/pixiv_web.rs index fb6b6ee..2e876d4 100644 --- a/src/pixiv_web.rs +++ b/src/pixiv_web.rs @@ -1,10 +1,9 @@ use crate::downloader::pd_file::PdFile; use crate::ext::rw_lock::GetRwLock; use crate::gettext; -use crate::opthelper::OptHelper; +use crate::opthelper::get_helper; use crate::parser::metadata::MetaDataParser; use crate::webclient::WebClient; -use crate::Main; use json::JsonValue; use reqwest::IntoUrl; use reqwest::Response; @@ -20,7 +19,6 @@ use std::time::Duration; /// A client which use Pixiv's web API pub struct PixivWebClient { client: WebClient, - pub helper: OptHelper, /// true if in is initialized inited: Arc, /// pixiv global data @@ -30,10 +28,9 @@ pub struct PixivWebClient { } impl PixivWebClient { - pub fn new(m: &Main) -> Self { + pub fn new() -> Self { Self { client: WebClient::new(), - helper: OptHelper::new(m.cmd.as_ref().unwrap().clone(), m.settings.as_ref().unwrap().clone()), inited: Arc::new(AtomicBool::new(false)), data: RwLock::new(None), params: RwLock::new(None), @@ -75,14 +72,15 @@ impl PixivWebClient { } pub fn init(&self) -> bool { - let c = self.helper.cookies(); + let helper = get_helper(); + let c = helper.cookies(); if c.is_some() { if !self.client.read_cookies(c.as_ref().unwrap()) { return false; } } self.client.set_header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"); - let l = self.helper.language(); + let l = helper.language(); if l.is_some() { self.client.set_header("Accept-Language", l.as_ref().unwrap()); self.params.get_mut().replace(json::object! { "lang": l.as_ref().unwrap().replace("-", "_").as_str() }); @@ -90,12 +88,12 @@ impl PixivWebClient { self.client.set_header("Accept-Language", "ja"); self.params.get_mut().replace(json::object! { "lang": "ja" }); } - self.client.set_verbose(self.helper.verbose()); - let retry = self.helper.retry(); + self.client.set_verbose(helper.verbose()); + let retry = helper.retry(); if retry.is_some() { self.client.set_retry(retry.unwrap()); } - self.client.get_retry_interval_as_mut().replace(self.helper.retry_interval()); + self.client.get_retry_interval_as_mut().replace(helper.retry_interval()); self.inited.store(true, Ordering::Relaxed); true } @@ -133,7 +131,7 @@ impl PixivWebClient { println!("{}", gettext("Failed to parse main page.")); return false; } - if self.helper.verbose() { + if get_helper().verbose() { println!("{}\n{}", gettext("Main page's data:"), p.value.as_ref().unwrap().pretty(2).as_str()); } self.get_data_as_mut().replace(p.value.unwrap()); @@ -229,7 +227,7 @@ impl PixivWebClient { } let r = r.unwrap(); let v = self.deal_json(r); - if self.helper.verbose() && v.is_some() { + if get_helper().verbose() && v.is_some() { println!("{} {}", gettext("Artwork's data:"), v.as_ref().unwrap().pretty(2)); } v @@ -259,7 +257,7 @@ impl PixivWebClient { println!("{}", gettext("Failed to parse artwork page.")); return None; } - if self.helper.verbose() { + if get_helper().verbose() { println!("{} {}", gettext("Artwork's data:"), p.value.as_ref().unwrap().pretty(2)); } Some(p.value.unwrap()) @@ -273,7 +271,7 @@ impl PixivWebClient { } let r = r.unwrap(); let v = self.deal_json(r); - if self.helper.verbose() && v.is_some() { + if get_helper().verbose() && v.is_some() { println!("{} {}", gettext("Artwork's page data:"), v.as_ref().unwrap().pretty(2)); } v @@ -287,7 +285,7 @@ impl PixivWebClient { } let r = r.unwrap(); let v = self.deal_json(r); - if self.helper.verbose() && v.is_some() { + if get_helper().verbose() && v.is_some() { println!("{} {}", gettext("Ugoira's data:"), v.as_ref().unwrap().pretty(2)); } v @@ -310,7 +308,7 @@ impl PixivWebClient { impl Drop for PixivWebClient { fn drop(&mut self) { if self.is_inited() { - let c = self.helper.cookies(); + let c = get_helper().cookies(); if c.is_some() { if !self.client.save_cookies(c.as_ref().unwrap()) { println!("{} {}", gettext("Warning: Failed to save cookies file:"), c.as_ref().unwrap()); diff --git a/src/webclient.rs b/src/webclient.rs index 14a6af1..9f23044 100644 --- a/src/webclient.rs +++ b/src/webclient.rs @@ -5,7 +5,7 @@ use crate::cookies::CookieJar; use crate::ext::json::ToJson; use crate::gettext; use crate::list::NonTailList; -use crate::opthelper::OptHelper; +use crate::opthelper::get_helper; use futures_util::StreamExt; use indicatif::MultiProgress; use indicatif::ProgressBar; @@ -15,6 +15,7 @@ use reqwest::{Client, IntoUrl, RequestBuilder, Response}; use spin_on::spin_on; use std::collections::HashMap; use std::convert::TryInto; +use std::default::Default; use std::ffi::OsStr; use std::fs::File; use std::fs::remove_file; @@ -474,8 +475,9 @@ impl WebClient { /// * `progess_bars` - Multiple progress bars /// /// Note: If file already exists, will remove existing file first. - pub async fn adownload_stream + ?Sized>(file_name: &S, r: Response, opt: &OptHelper, progress_bars: Option>) -> Result<(), ()> { + pub async fn adownload_stream + ?Sized>(file_name: &S, r: Response, progress_bars: Option>) -> Result<(), ()> { let content_length = r.content_length(); + let opt = get_helper(); let use_progress_bar = match &content_length { Some(_) => { opt.use_progress_bar() } None => { false } @@ -558,8 +560,9 @@ impl WebClient { /// * `opt` - Options /// /// Note: If file already exists, will remove existing file first. - pub fn download_stream + ?Sized>(file_name: &S, r: Response, opt: &OptHelper) -> Result<(), ()> { + pub fn download_stream + ?Sized>(file_name: &S, r: Response) -> Result<(), ()> { let content_length = r.content_length(); + let opt = get_helper(); let use_progress_bar = match &content_length { Some(_) => { opt.use_progress_bar() } None => { false } @@ -613,3 +616,10 @@ impl WebClient { Ok(()) } } + +impl Default for WebClient { + fn default() -> Self { + let c = Self::new(); + c + } +}