refactor: switch to own quirks_path

This commit is contained in:
master 2024-03-05 09:59:00 +08:00
parent b996be0702
commit 8c460dfdc0
12 changed files with 66 additions and 177 deletions

8
Cargo.lock generated
View File

@ -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"

View File

@ -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<P: AsRef<Path>>(&mut self, path: P) {
pub fn push<P: AsRef<Path>>(&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 {

View File

@ -95,3 +95,13 @@ pub(crate) fn path_to_file_url_segments(
Ok((host_end, host_internal))
}
pub fn path_equals_as_file_url<A: AsRef<Path>, B: AsRef<Path>>(
a: A,
b: B,
) -> Result<bool, PathToUrlError> {
let u1 = a.as_ref().to_file_url()?;
let u2 = b.as_ref().to_file_url()?;
Ok(u1.as_str() == u2.as_str())
}

View File

@ -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" }
testcontainers-modules = { version = "0.3.5" }

View File

@ -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},

View File

@ -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::<VFSSubPathBuf>();
.map(Path::new)
.collect::<PathBuf>();
let mut fs_builder = services::Fs::default();
fs_builder.root(self.config.fs_root.as_str());

View File

@ -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<Qbit>,
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(),

View File

@ -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,

View File

@ -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<i32>,
file_type: Option<&str>,

View File

@ -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,
};

View File

@ -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<VFSSubPathBuf>, Vec<VFSSubPathBuf>) {
pub fn check_files(info: &Torrent) -> (Vec<PathBuf>, Vec<PathBuf>) {
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<VFSSubPathBuf>, Vec<VFSSubPathBuf>) {
}
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 {

View File

@ -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> {
Url::parse(&format!("file:///{path}")).map_err(|e| e.into())
}
pub fn path_str_equals(p1: &str, p2: &str) -> eyre::Result<bool> {
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<VFSPath> {
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<P: AsRef<VFSSubPath>>(&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<R: Into<String>, S: Into<VFSSubPathBuf>>(root: R, sub: S) -> Self {
Self {
root: root.into(),
sub: sub.into(),
}
}
pub fn from_root(root: &str) -> Result<Self, ParseError> {
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<P: AsRef<VFSSubPath>>(&mut self, path: P) {
self.sub.push(path);
}
pub fn pop(&mut self) -> bool {
self.sub.pop()
}
pub fn set_extension<S: AsRef<str>>(&mut self, ext: S) {
self.sub.set_extension(ext);
}
pub fn set_file_name<S: AsRef<str>>(&mut self, file_name: S) {
self.sub.set_file_name(file_name);
}
}
impl Into<PathBuf> for VFSPathBuf {
fn into(self) -> PathBuf {
let root = self.root;
PathBuf::from(root).join(self.sub.as_str())
}
}