From 8c460dfdc062db70388ed5bec448f2ecd0afec54 Mon Sep 17 00:00:00 2001 From: lonelyhentxi Date: Tue, 5 Mar 2024 09:59:00 +0800 Subject: [PATCH] refactor: switch to own quirks_path --- Cargo.lock | 8 +- crates/quirks_path/src/lib.rs | 17 ++- crates/quirks_path/src/url.rs | 10 ++ crates/recorder/Cargo.toml | 4 +- crates/recorder/src/app.rs | 1 - crates/recorder/src/dal/mod.rs | 10 +- crates/recorder/src/downloaders/qbitorrent.rs | 27 ++-- .../src/downloaders/torrent_downloader.rs | 5 +- crates/recorder/src/parsers/torrent_parser.rs | 11 +- crates/recorder/src/path/mod.rs | 6 - crates/recorder/src/path/torrent_path.rs | 19 +-- crates/recorder/src/path/vfs_path.rs | 125 ------------------ 12 files changed, 66 insertions(+), 177 deletions(-) delete mode 100644 crates/recorder/src/path/vfs_path.rs diff --git a/Cargo.lock b/Cargo.lock index 834b811..3b374cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3584,6 +3584,7 @@ dependencies = [ "maplit", "opendal", "qbit-rs", + "quirks_path", "regex", "reqwest", "rss", @@ -3600,7 +3601,6 @@ dependencies = [ "tokio", "tracing", "tracing-subscriber", - "uni-path", "url", "uuid", "validator", @@ -5592,12 +5592,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" -[[package]] -name = "uni-path" -version = "1.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e328d505b1f855c20e7358711b7ec6398524181664f016dd15cfb36c3a6275" - [[package]] name = "unic-char-property" version = "0.9.0" diff --git a/crates/quirks_path/src/lib.rs b/crates/quirks_path/src/lib.rs index f682157..879b269 100644 --- a/crates/quirks_path/src/lib.rs +++ b/crates/quirks_path/src/lib.rs @@ -10,6 +10,7 @@ use std::{ collections::TryReserveError, error::Error, fmt, + fmt::Formatter, hash::{Hash, Hasher}, io, iter::FusedIterator, @@ -20,7 +21,7 @@ use std::{ }; use ::url::Url; -pub use url::PathToUrlError; +pub use url::{path_equals_as_file_url, PathToUrlError}; use windows::is_windows_sep; use crate::{ @@ -707,7 +708,7 @@ impl PathBuf { self } - fn push>(&mut self, path: P) { + pub fn push>(&mut self, path: P) { self._push(path.as_ref()) } @@ -991,6 +992,12 @@ impl fmt::Debug for PathBuf { } } +impl fmt::Display for PathBuf { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, formatter) + } +} + impl Deref for PathBuf { type Target = Path; #[inline] @@ -1364,6 +1371,12 @@ impl fmt::Debug for Path { } } +impl fmt::Display for Path { + fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.inner, formatter) + } +} + impl PartialEq for Path { #[inline] fn eq(&self, other: &Path) -> bool { diff --git a/crates/quirks_path/src/url.rs b/crates/quirks_path/src/url.rs index 74fa94b..f3b3db9 100644 --- a/crates/quirks_path/src/url.rs +++ b/crates/quirks_path/src/url.rs @@ -95,3 +95,13 @@ pub(crate) fn path_to_file_url_segments( Ok((host_end, host_internal)) } + +pub fn path_equals_as_file_url, B: AsRef>( + a: A, + b: B, +) -> Result { + let u1 = a.as_ref().to_file_url()?; + let u2 = b.as_ref().to_file_url()?; + + Ok(u1.as_str() == u2.as_str()) +} diff --git a/crates/recorder/Cargo.toml b/crates/recorder/Cargo.toml index cf46f3f..18c9d45 100644 --- a/crates/recorder/Cargo.toml +++ b/crates/recorder/Cargo.toml @@ -53,12 +53,12 @@ fancy-regex = "0.13.0" regex = "1.10.3" lazy_static = "1.4.0" maplit = "1.0.2" -uni-path = "1.51.1" tl = { version = "0.7.8", features = ["simd"] } lightningcss = "1.0.0-alpha.54" html-escape = "0.2.13" opendal = "0.45.0" librqbit-core = "3.5.0" +quirks_path = { path = "../quirks_path" } [dev-dependencies] serial_test = "2.0.0" @@ -66,4 +66,4 @@ rstest = "0.18.2" loco-rs = { version = "0.3.1", features = ["testing"] } insta = { version = "1.34.0", features = ["redactions", "yaml", "filters"] } testcontainers = { version = "0.15.0" } -testcontainers-modules = { version = "0.3.5" } \ No newline at end of file +testcontainers-modules = { version = "0.3.5" } diff --git a/crates/recorder/src/app.rs b/crates/recorder/src/app.rs index 4c919d5..970a823 100644 --- a/crates/recorder/src/app.rs +++ b/crates/recorder/src/app.rs @@ -1,7 +1,6 @@ use std::path::Path; use async_trait::async_trait; -use axum::Router; use loco_rs::{ app::{AppContext, Hooks}, boot::{create_app, BootResult, StartMode}, diff --git a/crates/recorder/src/dal/mod.rs b/crates/recorder/src/dal/mod.rs index a57a863..7e45f96 100644 --- a/crates/recorder/src/dal/mod.rs +++ b/crates/recorder/src/dal/mod.rs @@ -1,13 +1,11 @@ use bytes::Bytes; use opendal::{layers::LoggingLayer, services, Operator}; +use quirks_path::{Path, PathBuf}; use serde::{Deserialize, Serialize}; use url::Url; use uuid::Uuid; -use crate::{ - config::AppDalConf, - path::{VFSSubPath, VFSSubPathBuf}, -}; +use crate::config::AppDalConf; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] @@ -50,8 +48,8 @@ impl AppDalContext { let basename = format!("{}{}", Uuid::new_v4(), extname); let mut dirname = [subscriber_pid, content_category.as_ref()] .into_iter() - .map(VFSSubPath::new) - .collect::(); + .map(Path::new) + .collect::(); let mut fs_builder = services::Fs::default(); fs_builder.root(self.config.fs_root.as_str()); diff --git a/crates/recorder/src/downloaders/qbitorrent.rs b/crates/recorder/src/downloaders/qbitorrent.rs index 92632df..af84c61 100644 --- a/crates/recorder/src/downloaders/qbitorrent.rs +++ b/crates/recorder/src/downloaders/qbitorrent.rs @@ -13,6 +13,7 @@ use qbit_rs::{ model::{AddTorrentArg, Credential, GetTorrentListArg, NonEmptyStr, SyncData}, Qbit, }; +use quirks_path::{path_equals_as_file_url, Path, PathBuf}; use tokio::time::sleep; use url::Url; @@ -24,7 +25,6 @@ use super::{ use crate::{ downloaders::defs::{QbitTorrent, QbitTorrentContent, TorrentContent}, models::{entities::downloaders, prelude::DownloaderCategory}, - path::{path_str_equals, VFSPathBuf, VFSSubPath}, }; pub struct SyncDataCache { @@ -35,7 +35,7 @@ pub struct QBittorrentDownloader { pub subscriber_id: i32, pub endpoint_url: Url, pub client: Arc, - pub save_path: String, + pub save_path: PathBuf, pub wait_sync_timeout: Duration, } @@ -65,7 +65,7 @@ impl QBittorrentDownloader { client: Arc::new(client), endpoint_url, subscriber_id: model.subscriber_id, - save_path: model.save_path, + save_path: model.save_path.into(), wait_sync_timeout: Duration::from_millis(10000), }) } @@ -268,12 +268,15 @@ impl TorrentDownloader for QBittorrentDownloader { new_path: &str, ) -> eyre::Result<()> { self.client.rename_file(hash, old_path, new_path).await?; + let new_path = self.save_path.join(new_path); + let save_path = self.save_path.as_path(); self.wait_torrent_contents_until( hash, |contents| -> bool { - contents - .iter() - .any(|c| path_str_equals(c.get_name(), new_path).unwrap_or(false)) + contents.iter().any(|c| { + path_equals_as_file_url(save_path.join(c.get_name()), &new_path) + .unwrap_or(false) + }) }, None, ) @@ -291,9 +294,9 @@ impl TorrentDownloader for QBittorrentDownloader { .build(), |torrents| -> bool { torrents.iter().all(|t| { - t.save_path - .as_ref() - .map_or(false, |p| path_str_equals(p, new_path).unwrap_or(false)) + t.save_path.as_ref().map_or(false, |p| { + path_equals_as_file_url(p, new_path).unwrap_or(false) + }) }) }, None, @@ -396,8 +399,8 @@ impl TorrentDownloader for QBittorrentDownloader { Ok(()) } - fn get_save_path(&self, sub_path: &VFSSubPath) -> VFSPathBuf { - VFSPathBuf::new(self.save_path.clone(), sub_path.to_path_buf()) + fn get_save_path(&self, sub_path: &Path) -> PathBuf { + self.save_path.join(sub_path) } } @@ -463,7 +466,7 @@ pub mod tests { } async fn test_qbittorrent_downloader_impl() { - let base_save_path = VFSSubPath::new(get_tmp_qbit_test_folder()); + let base_save_path = Path::new(get_tmp_qbit_test_folder()); let downloader = QBittorrentDownloader::from_downloader_model(downloaders::Model { created_at: Default::default(), diff --git a/crates/recorder/src/downloaders/torrent_downloader.rs b/crates/recorder/src/downloaders/torrent_downloader.rs index 8e4a7a1..55a1a3b 100644 --- a/crates/recorder/src/downloaders/torrent_downloader.rs +++ b/crates/recorder/src/downloaders/torrent_downloader.rs @@ -1,4 +1,5 @@ use downloaders::DownloaderCategory; +use quirks_path::{Path, PathBuf}; use sea_orm::{ActiveModelTrait, ActiveValue, DatabaseConnection, IntoActiveModel}; use url::Url; @@ -8,7 +9,7 @@ use super::{ }; use crate::{ models::{bangumi, downloaders, downloads}, - path::{torrent_path::gen_bangumi_sub_path, VFSPathBuf, VFSSubPath}, + path::torrent_path::gen_bangumi_sub_path, }; #[async_trait::async_trait] @@ -48,7 +49,7 @@ pub trait TorrentDownloader { async fn add_category(&self, category: &str) -> eyre::Result<()>; - fn get_save_path(&self, sub_path: &VFSSubPath) -> VFSPathBuf; + fn get_save_path(&self, sub_path: &Path) -> PathBuf; async fn add_downloads_for_bangumi<'a, 'b>( &self, diff --git a/crates/recorder/src/parsers/torrent_parser.rs b/crates/recorder/src/parsers/torrent_parser.rs index 103196c..323e65d 100644 --- a/crates/recorder/src/parsers/torrent_parser.rs +++ b/crates/recorder/src/parsers/torrent_parser.rs @@ -1,10 +1,11 @@ +use quirks_path::Path; + use super::defs::{ BRACKETS_REG, DIGIT_1PLUS_REG, SEASON_REGEX, SUBTITLE_LANG, TORRENT_PRASE_RULE_REGS, }; -use crate::path::VFSPath; -pub fn get_path_basename<'a>(path: &'a VFSPath) -> &'a str { - path.basename() +pub fn get_path_basename(path: &Path) -> &str { + path.parent().map_or("", |s| s.as_str()) } pub fn get_fansub(group_and_title: &str) -> (Option<&str>, &str) { @@ -53,8 +54,8 @@ pub fn get_subtitle_lang(subtitle_name: &str) -> Option<&'static str> { None } -pub fn parse_torrent<'a>( - torrent_path: &'a VFSPath<'a>, +pub fn parse_torrent( + torrent_path: &Path, torrent_name: Option<&str>, season: Option, file_type: Option<&str>, diff --git a/crates/recorder/src/path/mod.rs b/crates/recorder/src/path/mod.rs index e4858ca..f8de902 100644 --- a/crates/recorder/src/path/mod.rs +++ b/crates/recorder/src/path/mod.rs @@ -1,7 +1 @@ pub mod torrent_path; -pub mod vfs_path; - -pub use vfs_path::{ - path_str_equals, path_str_to_file_url, VFSComponent, VFSComponents, VFSPath, VFSPathBuf, - VFSSubPath, VFSSubPathBuf, -}; diff --git a/crates/recorder/src/path/torrent_path.rs b/crates/recorder/src/path/torrent_path.rs index 127b15d..c4bf58c 100644 --- a/crates/recorder/src/path/torrent_path.rs +++ b/crates/recorder/src/path/torrent_path.rs @@ -1,17 +1,18 @@ use std::collections::HashSet; +use quirks_path::{Path, PathBuf}; + use crate::{ downloaders::defs::Torrent, models::{bangumi, subscribers}, parsers::defs::SEASON_REGEX, - path::{VFSPath, VFSSubPathBuf}, }; -pub fn check_files(info: &Torrent) -> (Vec, Vec) { +pub fn check_files(info: &Torrent) -> (Vec, Vec) { let mut media_list = vec![]; let mut subtitle_list = vec![]; for f in info.iter_files() { - let file_name = VFSSubPathBuf::from(f.get_name()); + let file_name = PathBuf::from(f.get_name()); let extension = file_name.extension().unwrap_or_default().to_lowercase(); match extension.as_str() { @@ -27,8 +28,8 @@ pub fn check_files(info: &Torrent) -> (Vec, Vec) { } pub fn path_to_bangumi<'a>( - save_path: VFSPath<'a>, - downloader_path: VFSPath<'a>, + save_path: &'a Path, + downloader_path: &'a Path, ) -> Option<(&'a str, i32)> { let downloader_parts = downloader_path .components() @@ -57,16 +58,16 @@ pub fn path_to_bangumi<'a>( } } -pub fn file_depth(path: &VFSPath<'_>) -> usize { +pub fn file_depth(path: &Path) -> usize { path.components().count() } -pub fn is_ep(path: &VFSPath<'_>) -> bool { +pub fn is_ep(path: &Path) -> bool { file_depth(path) <= 2 } -pub fn gen_bangumi_sub_path(data: &bangumi::Model) -> VFSSubPathBuf { - VFSSubPathBuf::from(data.official_title.to_string()).join(format!("Season {}", data.season)) +pub fn gen_bangumi_sub_path(data: &bangumi::Model) -> PathBuf { + PathBuf::from(data.official_title.to_string()).join(format!("Season {}", data.season)) } pub fn rule_name(bgm: &bangumi::Model, conf: &subscribers::SubscriberBangumiConfig) -> String { diff --git a/crates/recorder/src/path/vfs_path.rs b/crates/recorder/src/path/vfs_path.rs deleted file mode 100644 index 0b991b8..0000000 --- a/crates/recorder/src/path/vfs_path.rs +++ /dev/null @@ -1,125 +0,0 @@ -use std::{borrow::Cow, collections::VecDeque, path::PathBuf}; - -use lazy_static::lazy_static; -pub use uni_path::{Path as VFSSubPath, PathBuf as VFSSubPathBuf}; -use url::Url; - -use crate::parsers::errors::ParseError; - -pub fn path_str_to_file_url(path: &str) -> eyre::Result { - Url::parse(&format!("file:///{path}")).map_err(|e| e.into()) -} - -pub fn path_str_equals(p1: &str, p2: &str) -> eyre::Result { - let p1 = path_str_to_file_url(p1)?; - let p2 = path_str_to_file_url(p2)?; - Ok(p1.as_str() == p2.as_str()) -} - -const VFS_EMPTY_STR: &str = ""; - -lazy_static! { - pub static ref VFS_SUB_ROOT_BUF: VFSSubPathBuf = VFSSubPathBuf::from("/"); - pub static ref VFS_SUB_ROOT: &'static VFSSubPath = &VFS_SUB_ROOT_BUF.as_path(); -} - -pub type VFSComponents<'a> = uni_path::Components<'a>; -pub type VFSComponent<'a> = uni_path::Component<'a>; - -#[derive(Debug, Clone)] -pub struct VFSPath<'a> { - pub root: &'a str, - pub sub: &'a VFSSubPath, -} - -impl<'a> VFSPath<'a> { - pub fn new(root: &'a str, sub: &'a VFSSubPath) -> VFSPath<'a> { - Self { root, sub } - } - - pub fn file_name(&self) -> Option<&str> { - self.sub.file_name() - } - - pub fn parent(&self) -> Option { - self.sub.parent().map(|p| Self::new(self.root, p)) - } - - pub fn dirname(&'a self) -> VFSPath<'a> { - self.parent() - .unwrap_or_else(|| Self::new(self.root, &VFS_SUB_ROOT)) - } - - pub fn basename(&self) -> &str { - self.file_name().unwrap_or(VFS_EMPTY_STR) - } - - pub fn components(&self) -> VFSComponents<'a> { - self.sub.components() - } - - pub fn join>(&self, path: P) -> VFSPathBuf { - VFSPathBuf::new(self.root, self.sub.join(path)) - } - - pub fn extension(&self) -> Option<&str> { - self.sub.extension() - } - - pub fn extname(&self) -> &str { - self.extension().unwrap_or_default() - } - - pub fn to_std_path_buf(&self) -> PathBuf { - PathBuf::from(self.root).join(self.sub.as_str()) - } -} - -#[derive(Clone, Debug)] -pub struct VFSPathBuf { - root: String, - sub: VFSSubPathBuf, -} - -impl VFSPathBuf { - pub fn new, S: Into>(root: R, sub: S) -> Self { - Self { - root: root.into(), - sub: sub.into(), - } - } - - pub fn from_root(root: &str) -> Result { - Ok(Self { - root: root.to_string(), - sub: VFS_SUB_ROOT_BUF.clone(), - }) - } - - pub fn as_path(&self) -> VFSPath { - VFSPath::new(&self.root as &str, self.sub.as_path()) - } - - pub fn push>(&mut self, path: P) { - self.sub.push(path); - } - - pub fn pop(&mut self) -> bool { - self.sub.pop() - } - - pub fn set_extension>(&mut self, ext: S) { - self.sub.set_extension(ext); - } - - pub fn set_file_name>(&mut self, file_name: S) { - self.sub.set_file_name(file_name); - } -} - -impl Into for VFSPathBuf { - fn into(self) -> PathBuf { - let root = self.root; - PathBuf::from(root).join(self.sub.as_str()) - } -}