mirror of
https://github.com/lifegpc/pixiv_downloader.git
synced 2026-06-17 08:24:59 +08:00
Update
This commit is contained in:
28
Cargo.lock
generated
28
Cargo.lock
generated
@@ -935,6 +935,27 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modular-bitfield"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74"
|
||||
dependencies = [
|
||||
"modular-bitfield-impl",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modular-bitfield-impl"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.8"
|
||||
@@ -1142,6 +1163,7 @@ dependencies = [
|
||||
"json",
|
||||
"lazy_static",
|
||||
"link-cplusplus",
|
||||
"modular-bitfield",
|
||||
"proc_macros",
|
||||
"regex",
|
||||
"reqwest",
|
||||
@@ -1470,6 +1492,12 @@ dependencies = [
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
|
||||
@@ -20,6 +20,7 @@ indicatif = "0.17.0-rc.11"
|
||||
int-enum = "0.4"
|
||||
json = "0.12"
|
||||
lazy_static = "1.4"
|
||||
modular-bitfield = "0.11"
|
||||
proc_macros = { path = "proc_macros" }
|
||||
regex = "1"
|
||||
reqwest = { version = "0.11", features = ["brotli", "deflate", "gzip", "rustls-tls", "socks", "stream"] }
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::downloader::pd_file::file::PdFile;
|
||||
use int_enum::IntEnum;
|
||||
use modular_bitfield::BitfieldSpecifier;
|
||||
use std::fmt::Display;
|
||||
|
||||
/// The status of the downloaded file.
|
||||
#[repr(u8)]
|
||||
@@ -59,8 +61,52 @@ impl PdFileType {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(BitfieldSpecifier, Clone, Copy, Debug, Eq, PartialEq, IntEnum)]
|
||||
#[bits = 2]
|
||||
/// The status of the each part in pd file.
|
||||
pub enum PdFilePartStatus {
|
||||
/// The download of this part is waited.
|
||||
Waited = 0,
|
||||
/// The download of this part is started.
|
||||
Downloading = 1,
|
||||
/// The download of this part is completed.
|
||||
Downloaded = 2,
|
||||
}
|
||||
|
||||
impl PdFilePartStatus {
|
||||
#[inline]
|
||||
/// Returns true if the download is waited
|
||||
pub fn is_waited(&self) -> bool {
|
||||
*self == Self::Waited
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns true if the download is started
|
||||
pub fn is_downloading(&self) -> bool {
|
||||
*self == Self::Downloading
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns true if the download is completed.
|
||||
pub fn is_downloaded(&self) -> bool {
|
||||
*self == Self::Downloaded
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PdFilePartStatus {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Waited => { f.write_str("PdFilePartStatus::Waited") }
|
||||
Self::Downloading => { f.write_str("PdFilePartStatus::Downloading") }
|
||||
Self::Downloaded => { f.write_str("PdFilePartStatus::Downloaded") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enums() {
|
||||
assert_eq!(PdFileStatus::Downloading.int_value().to_le_bytes(), [1]);
|
||||
assert_eq!(PdFileType::MultiThread.int_value().to_le_bytes(), [1]);
|
||||
assert_eq!(PdFilePartStatus::Downloaded.int_value().to_le_bytes(), [2]);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use super::part_status::OutOfBoundsError;
|
||||
use crate::gettext;
|
||||
use int_enum::IntEnum;
|
||||
use int_enum::IntEnumError;
|
||||
@@ -5,6 +6,7 @@ use std::convert::From;
|
||||
use std::fmt::Display;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
/// Pd file's error
|
||||
#[derive(Debug, derive_more::From)]
|
||||
pub enum PdFileError {
|
||||
IoError(std::io::Error),
|
||||
@@ -50,3 +52,9 @@ impl<T: IntEnum> From<IntEnumError<T>> for PdFileError {
|
||||
Self::String(format!("{} {}", gettext("Invalid pd file: "), e))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Display> From<OutOfBoundsError<T>> for PdFileError {
|
||||
fn from(e: OutOfBoundsError<T>) -> Self {
|
||||
Self::String(format!("{}", e))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::downloader::pd_file::error::PdFileError;
|
||||
use crate::downloader::pd_file::enums::PdFileResult;
|
||||
use crate::downloader::pd_file::enums::PdFileStatus;
|
||||
use crate::downloader::pd_file::enums::PdFileType;
|
||||
use crate::downloader::pd_file::part_status::PdFilePartStatus;
|
||||
use crate::downloader::pd_file::version::PdFileVersion;
|
||||
use crate::ext::io::StructRead;
|
||||
use crate::ext::replace::ReplaceWith2;
|
||||
@@ -24,6 +25,7 @@ use std::io::Write;
|
||||
use std::ops::Drop;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
@@ -60,6 +62,8 @@ pub struct PdFile {
|
||||
part_size: AtomicU32,
|
||||
/// Only stored in memory.
|
||||
mem_only: AtomicBool,
|
||||
/// The status of the each part.
|
||||
part_datas: RwLock<Vec<Arc<PdFilePartStatus>>>,
|
||||
}
|
||||
|
||||
impl PdFile {
|
||||
@@ -77,6 +81,7 @@ impl PdFile {
|
||||
downloaded_file_size: AtomicU64::new(0),
|
||||
part_size: AtomicU32::new(0),
|
||||
mem_only: AtomicBool::new(true),
|
||||
part_datas: RwLock::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +111,17 @@ impl PdFile {
|
||||
self.downloaded_file_size.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Return status data of a part
|
||||
/// * `index` - The part index
|
||||
pub fn get_part_data(&self, index: usize) -> Option<Arc<PdFilePartStatus>> {
|
||||
let datas = self.part_datas.get_ref();
|
||||
if index < datas.len() {
|
||||
Some(Arc::clone(&datas[index]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns true if the download is completed.
|
||||
pub fn is_completed(&self) -> bool {
|
||||
@@ -198,6 +214,8 @@ impl PdFile {
|
||||
downloaded_file_size: AtomicU64::new(downloaded_file_size),
|
||||
part_size: AtomicU32::new(part_size),
|
||||
mem_only: AtomicBool::new(false),
|
||||
// #TODO
|
||||
part_datas: RwLock::new(Vec::new()),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/// The enums of the pd file.
|
||||
pub mod enums;
|
||||
/// The error type of the pd file.
|
||||
pub mod error;
|
||||
/// The pd file
|
||||
pub mod file;
|
||||
/// The enums of the pd file.
|
||||
pub mod enums;
|
||||
/// The status of the each part.
|
||||
#[allow(dead_code)]
|
||||
pub mod part_status;
|
||||
/// Version of the pd file
|
||||
pub mod version;
|
||||
|
||||
126
src/downloader/pd_file/part_status.rs
Normal file
126
src/downloader/pd_file/part_status.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
use crate::downloader::pd_file::enums::PdFilePartStatus as PdFilePartStatus2;
|
||||
use crate::downloader::pd_file::error::PdFileError;
|
||||
use crate::ext::rw_lock::GetRwLock;
|
||||
use crate::gettext;
|
||||
use int_enum::IntEnum;
|
||||
use modular_bitfield::bitfield;
|
||||
use modular_bitfield::prelude::B30;
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::Display;
|
||||
use std::sync::RwLock;
|
||||
|
||||
/// The data is out of bounds.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OutOfBoundsError<T> {
|
||||
/// Type name
|
||||
t: String,
|
||||
/// the value
|
||||
v: T,
|
||||
}
|
||||
|
||||
impl<T> OutOfBoundsError<T> {
|
||||
pub fn new<S: AsRef<str> + ?Sized>(t: &S, v: T) -> Self {
|
||||
Self { t: String::from(t.as_ref()), v: v }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Display> Display for OutOfBoundsError<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("Failed to set type {} with value {}", self.t.as_str(), self.v))
|
||||
}
|
||||
}
|
||||
|
||||
#[bitfield(bits = 32)]
|
||||
#[derive(Clone)]
|
||||
/// The status of the each part in pd file (For internal usage)
|
||||
struct PdFilePartStatusInternal {
|
||||
#[bits = 2]
|
||||
status: PdFilePartStatus2,
|
||||
downloaded_size: B30,
|
||||
}
|
||||
|
||||
impl Debug for PdFilePartStatusInternal {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("{{ status: {:?}, downloaded_size: {:?} }}", self.status(), self.downloaded_size()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// The status of the each part in pd file
|
||||
pub struct PdFilePartStatus {
|
||||
status: RwLock<PdFilePartStatusInternal>,
|
||||
}
|
||||
|
||||
impl PdFilePartStatus {
|
||||
/// Create a new [PdFilePartStatus]
|
||||
/// # paincs
|
||||
/// Will panic if internal errors happened.
|
||||
pub fn new() -> Self {
|
||||
let mut status = PdFilePartStatusInternal::new();
|
||||
status.set_status(PdFilePartStatus2::Waited);
|
||||
status.set_downloaded_size(0);
|
||||
Self { status: RwLock::new(status) }
|
||||
}
|
||||
|
||||
/// Returns the status of this part
|
||||
pub fn status(&self) -> PdFilePartStatus2 {
|
||||
self.status.get_ref().status()
|
||||
}
|
||||
|
||||
/// Set the status of this part
|
||||
pub fn set_status(&self, status: PdFilePartStatus2) -> Result<(), PdFileError> {
|
||||
match self.status.get_mut().set_status_checked(status) {
|
||||
Ok(_) => { Ok(()) }
|
||||
Err(_) => {
|
||||
Err(PdFileError::from(OutOfBoundsError::new("PdFilePartStatus", status)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns true if the download is waited
|
||||
pub fn is_waited(&self) -> bool {
|
||||
self.status().is_waited()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns true if the download is started
|
||||
pub fn is_downloading(&self) -> bool {
|
||||
self.status().is_downloading()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns true if the download is completed.
|
||||
pub fn is_downloaded(&self) -> bool {
|
||||
self.status().is_downloaded()
|
||||
}
|
||||
|
||||
/// Create a new instance of the [PdFilePartStatus] from bytes.
|
||||
/// * `bytes` - The data
|
||||
/// * `offset` - The offset of the needed data
|
||||
///
|
||||
/// Returns a new instance if succeed otherwise a Error because the data is less than 4 bytes.
|
||||
/// # Panics
|
||||
/// Will panic if unwanted error occured
|
||||
pub fn from_bytes<T: AsRef<[u8]> + ?Sized>(bytes: &T, offset: usize) -> Result<Self, PdFileError> {
|
||||
let value = bytes.as_ref();
|
||||
if (value.len() - offset) < 4 {
|
||||
Err(gettext("At least 4 bytes is needed."))?;
|
||||
}
|
||||
let st = (value[offset] & 0xC0) / 0x20;
|
||||
let mut status = PdFilePartStatusInternal::new();
|
||||
status.set_status(PdFilePartStatus2::from_int(st)?);
|
||||
// #TODO
|
||||
Ok(Self { status: RwLock::new(status) })
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part_status() {
|
||||
assert_eq!(std::mem::size_of::<PdFilePartStatusInternal>(), 4);
|
||||
let status = PdFilePartStatus::new();
|
||||
assert_eq!(status.status(), PdFilePartStatus2::Waited);
|
||||
assert_eq!(status.is_waited(), true);
|
||||
let status = PdFilePartStatus::from_bytes(&[80u8, 0, 0, 0], 0).unwrap();
|
||||
assert_eq!(status.is_downloaded(), true);
|
||||
}
|
||||
@@ -14,6 +14,7 @@ extern crate int_enum;
|
||||
extern crate lazy_static;
|
||||
#[cfg(all(feature = "link-cplusplus", target_env = "gnu"))]
|
||||
extern crate link_cplusplus;
|
||||
extern crate modular_bitfield;
|
||||
extern crate proc_macros;
|
||||
extern crate tokio;
|
||||
extern crate regex;
|
||||
|
||||
Reference in New Issue
Block a user