mirror of
https://github.com/lifegpc/pixiv_downloader.git
synced 2026-07-08 01:32:41 +08:00
Update
This commit is contained in:
@@ -3,18 +3,21 @@ use super::pd_file::PdFileResult;
|
||||
use super::enums::DownloaderResult;
|
||||
use super::enums::DownloaderStatus;
|
||||
use super::error::DownloaderError;
|
||||
use super::local_file::LocalFile;
|
||||
use super::tasks::create_download_tasks_simple;
|
||||
use crate::ext::atomic::AtomicQuick;
|
||||
use crate::ext::io::ClearFile;
|
||||
use crate::ext::rw_lock::GetRwLock;
|
||||
use crate::ext::try_err::TryErr;
|
||||
use crate::utils::ask_need_overwrite;
|
||||
use crate::webclient::WebClient;
|
||||
use crate::webclient::ToHeaders;
|
||||
use reqwest::IntoUrl;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::fs::remove_file;
|
||||
use std::io::Seek;
|
||||
use std::io::Write;
|
||||
use std::ops::DerefMut;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
@@ -24,7 +27,7 @@ use url::Url;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// A file downloader
|
||||
pub struct DownloaderInternal<T: Write + Seek + Send + Sync> {
|
||||
pub struct DownloaderInternal<T: Write + Seek + Send + Sync + ClearFile> {
|
||||
/// The webclient
|
||||
pub client: Arc<WebClient>,
|
||||
/// The download status
|
||||
@@ -43,7 +46,7 @@ pub struct DownloaderInternal<T: Write + Seek + Send + Sync> {
|
||||
multi: AtomicBool,
|
||||
}
|
||||
|
||||
impl DownloaderInternal<File> {
|
||||
impl DownloaderInternal<LocalFile> {
|
||||
/// Create a new [DownloaderInternal] instance
|
||||
/// * `url` - The url of the file
|
||||
/// * `header` - HTTP headers
|
||||
@@ -91,9 +94,9 @@ impl DownloaderInternal<File> {
|
||||
let file = match path {
|
||||
Some(p) => {
|
||||
if already_exists {
|
||||
Some(File::open(p)?)
|
||||
Some(LocalFile::open(p)?)
|
||||
} else {
|
||||
Some(File::create(p)?)
|
||||
Some(LocalFile::create(p)?)
|
||||
}
|
||||
}
|
||||
None => { None }
|
||||
@@ -111,13 +114,22 @@ impl DownloaderInternal<File> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: Write + Seek + Send + Sync> DownloaderInternal<T> {
|
||||
impl <T: Write + Seek + Send + Sync + ClearFile> DownloaderInternal<T> {
|
||||
/// Add a new task to tasks
|
||||
/// * `task` - Task
|
||||
pub fn add_task(&self, task: JoinHandle<Result<(), DownloaderError>>) {
|
||||
self.tasks.get_mut().push(task)
|
||||
}
|
||||
|
||||
/// Clear all datas in file
|
||||
pub fn clear_file(&self) -> std::io::Result<()> {
|
||||
match self.file.get_mut().deref_mut() {
|
||||
Some(f) => { f.clear_file()? }
|
||||
None => {}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the status of the downloader.
|
||||
pub fn get_status(&self) -> DownloaderStatus {
|
||||
self.status.get_ref().clone()
|
||||
@@ -138,22 +150,32 @@ impl <T: Write + Seek + Send + Sync> DownloaderInternal<T> {
|
||||
self.multi.qload()
|
||||
}
|
||||
}
|
||||
|
||||
/// Write datas to the file.
|
||||
/// * `data` - Data
|
||||
pub fn write(&self, data: &[u8]) -> Result<(), DownloaderError> {
|
||||
match self.file.get_mut().deref_mut() {
|
||||
Some(f) => { f.write_all(data)? }
|
||||
None => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A file downloader
|
||||
pub struct Downloader<T: Write + Seek + Send + Sync> {
|
||||
pub struct Downloader<T: Write + Seek + Send + Sync + ClearFile> {
|
||||
/// internal type
|
||||
downloader: Arc<DownloaderInternal<T>>,
|
||||
}
|
||||
|
||||
impl Downloader<File> {
|
||||
impl Downloader<LocalFile> {
|
||||
/// Create a new [Downloader] instance
|
||||
/// * `url` - The url of the file
|
||||
/// * `header` - HTTP headers
|
||||
/// * `path` - The path to store downloaded file.
|
||||
/// * `overwrite` - Whether to overwrite file
|
||||
pub fn new<U: IntoUrl, H: ToHeaders, P: AsRef<Path> + ?Sized>(url: U, headers: H, path: Option<&P>, overwrite: Option<bool>) -> Result<DownloaderResult<Self>, DownloaderError> {
|
||||
Ok(match DownloaderInternal::<File>::new(url, headers, path, overwrite)? {
|
||||
Ok(match DownloaderInternal::<LocalFile>::new(url, headers, path, overwrite)? {
|
||||
DownloaderResult::Ok(d) => {
|
||||
DownloaderResult::Ok(Self { downloader: Arc::new(d) })
|
||||
}
|
||||
@@ -173,7 +195,7 @@ macro_rules! define_downloader_fn {
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: Write + Seek + Send + Sync + 'static> Downloader<T> {
|
||||
impl <T: Write + Seek + Send + Sync + ClearFile + 'static> Downloader<T> {
|
||||
/// Start download if download not started.
|
||||
///
|
||||
/// Returns the status of the Downloader
|
||||
|
||||
73
src/downloader/local_file.rs
Normal file
73
src/downloader/local_file.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use crate::ext::io::ClearFile;
|
||||
use std::fs::File;
|
||||
use std::fs::remove_file;
|
||||
use std::io::Seek;
|
||||
use std::io::Write;
|
||||
use std::ops::Deref;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct LocalFile {
|
||||
file: Option<File>,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl LocalFile {
|
||||
/// Opens a file in write-only mode.
|
||||
///
|
||||
/// This function will create a file if it does not exist, and will truncate it if it does.
|
||||
pub fn create<P: AsRef<Path>>(path: P) -> std::io::Result<Self> {
|
||||
let p = path.as_ref().to_owned();
|
||||
let f = File::create(&p)?;
|
||||
Ok(Self {
|
||||
file: Some(f),
|
||||
path: p,
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempts to open a file in read-only mode.
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> std::io::Result<Self> {
|
||||
let p = path.as_ref().to_owned();
|
||||
let f = File::open(&p)?;
|
||||
Ok(Self {
|
||||
file: Some(f),
|
||||
path: p,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ClearFile for LocalFile {
|
||||
fn clear_file(&mut self) -> std::io::Result<()> {
|
||||
self.file.take();
|
||||
remove_file(&self.path)?;
|
||||
self.file.replace(File::create(&self.path)?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for LocalFile {
|
||||
type Target = File;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.file.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for LocalFile {
|
||||
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
|
||||
self.file.as_ref().unwrap().seek(pos)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for LocalFile {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.file.as_ref().unwrap().write(buf)
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
|
||||
self.file.as_ref().unwrap().write_vectored(bufs)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.file.as_ref().unwrap().flush()
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,11 @@ pub mod downloader;
|
||||
pub mod enums;
|
||||
/// File downloader's error
|
||||
pub mod error;
|
||||
/// Local file type
|
||||
pub mod local_file;
|
||||
/// The pd file
|
||||
pub mod pd_file;
|
||||
/// Deal download tasks
|
||||
pub mod tasks;
|
||||
pub use downloader::Downloader;
|
||||
pub use error::DownloaderError;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::ext::io::ClearFile;
|
||||
use crate::ext::try_err::TryErr;
|
||||
use crate::gettext;
|
||||
use super::error::DownloaderError;
|
||||
@@ -9,7 +10,7 @@ use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Create a download tasks in simple thread mode.
|
||||
pub async fn create_download_tasks_simple<T: Seek + Write + Send + Sync>(d: Arc<DownloaderInternal<T>>) -> Result<(), DownloaderError> {
|
||||
pub async fn create_download_tasks_simple<T: Seek + Write + Send + Sync + ClearFile>(d: Arc<DownloaderInternal<T>>) -> Result<(), DownloaderError> {
|
||||
let start = if d.pd.is_downloading() {
|
||||
d.pd.get_downloaded_file_size()
|
||||
} else {
|
||||
@@ -55,6 +56,7 @@ pub async fn create_download_tasks_simple<T: Seek + Write + Send + Sync>(d: Arc<
|
||||
};
|
||||
if need_reget {
|
||||
d.pd.clear()?;
|
||||
d.clear_file()?;
|
||||
result = d.client.get(d.url.deref().clone(), d.headers.deref().clone()).try_err(gettext("Failed to get url."))?;
|
||||
status = result.status();
|
||||
}
|
||||
|
||||
@@ -51,3 +51,9 @@ impl<T: Read> StructRead for T {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear all datas in file
|
||||
pub trait ClearFile {
|
||||
/// Clear all datas in file
|
||||
fn clear_file(&mut self) -> std::io::Result<()>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user