diff --git a/app/chain/download.py b/app/chain/download.py index 23229452..fe9cddd2 100644 --- a/app/chain/download.py +++ b/app/chain/download.py @@ -233,7 +233,7 @@ class DownloadChain(ChainBase): if not save_path: # 获取下载目录 dir_info = self.directoryhelper.get_download_dir(_media) - if not dir_info or not dir_info.path: + if not dir_info: logger.error(f"未找到下载目录:{_media.type.value} {_media.title_year}") self.messagehelper.put(f"{_media.type.value} {_media.title_year} 未找到下载目录!", title="下载失败", role="system") diff --git a/app/core/config.py b/app/core/config.py index 81ff48d9..48691e24 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -185,6 +185,8 @@ class Settings(BaseSettings): PLEX_TOKEN: Optional[str] = None # 转移方式 link/copy/move/softlink TRANSFER_TYPE: str = "copy" + # 是否同盘优先 + TRANSFER_SAME_DISK: bool = True # CookieCloud是否启动本地服务 COOKIECLOUD_ENABLE_LOCAL: Optional[bool] = False # CookieCloud服务器地址 diff --git a/app/helper/directory.py b/app/helper/directory.py index 96c25483..46f678bb 100644 --- a/app/helper/directory.py +++ b/app/helper/directory.py @@ -1,3 +1,4 @@ +from pathlib import Path from typing import List, Optional from app import schemas @@ -5,6 +6,7 @@ from app.core.config import settings from app.core.context import MediaInfo from app.db.systemconfig_oper import SystemConfigOper from app.schemas.types import SystemConfigKey, MediaType +from app.utils.system import SystemUtils class DirectoryHelper: @@ -41,6 +43,8 @@ class DirectoryHelper: media_dirs = self.get_download_dirs() # 按照配置顺序查找(保存后的数据已经排序) for media_dir in media_dirs: + if not media_dir.path: + continue # 没有媒体信息时,返回第一个类型为全部的目录 if (not media or media.type == MediaType.UNKNOWN) and not media_dir.media_type: return media_dir @@ -62,20 +66,24 @@ class DirectoryHelper: return None - def get_library_dir(self, media: MediaInfo = None) -> Optional[schemas.MediaDirectory]: + def get_library_dir(self, media: MediaInfo = None, in_path: Path = None) -> Optional[schemas.MediaDirectory]: """ - 根据媒体信息获取媒体库目录 + 根据媒体信息获取媒体库目录,需判断是否同盘优先 :param media: 媒体信息 + :param in_path: 源目录 """ + matched_dirs = [] library_dirs = self.get_library_dirs() # 按照配置顺序查找(保存后的数据已经排序) for library_dir in library_dirs: + if not library_dir.path: + continue # 没有媒体信息时,返回第一个类型为全部的目录 if (not media or media.type == MediaType.UNKNOWN) and not library_dir.media_type: - return library_dir + matched_dirs.append(library_dir) # 目录类型为全部的,符合条件 if not library_dir.media_type: - return library_dir + matched_dirs.append(library_dir) # 处理类型 if media.genre_ids \ and set(media.genre_ids).intersection(set(settings.ANIME_GENREIDS)): @@ -84,9 +92,22 @@ class DirectoryHelper: media_type = media.type.value # 目录类型相等,目录类别为全部,符合条件 if library_dir.media_type == media_type and not library_dir.category: - return library_dir + matched_dirs.append(library_dir) # 目录类型相等,目录类别相等,符合条件 if library_dir.media_type == media_type and library_dir.category == media.category: - return library_dir + matched_dirs.append(library_dir) - return None + # 未匹配到 + if not matched_dirs: + return None + + # 优先同盘 + if in_path and settings.TRANSFER_SAME_DISK: + for matched_dir in matched_dirs: + matched_path = Path(matched_dir.path) + if not matched_path.exists(): + matched_path.mkdir(parents=True, exist_ok=True) + if SystemUtils.is_same_disk(matched_path, in_path): + return matched_dir + + return matched_dirs[0] diff --git a/app/modules/filetransfer/__init__.py b/app/modules/filetransfer/__init__.py index 12c436ca..8e0befcf 100644 --- a/app/modules/filetransfer/__init__.py +++ b/app/modules/filetransfer/__init__.py @@ -72,9 +72,9 @@ class FileTransferModule(_ModuleBase): for d_path in download_paths: download_path = Path(d_path.path) if l_path.media_type == d_path.media_type and l_path.category == d_path.category: - if library_path.stat().st_dev != download_path.stat().st_dev: + if not SystemUtils.is_same_disk(library_path, download_path): return False, f"媒体库目录 {library_path} " \ - f"与下载目录 {download_path} 不在同一设备,将无法硬链接" + f"与下载目录 {download_path} 不在同一磁盘/存储空间/映射路径,将无法硬链接" return True, "" def init_setting(self) -> Tuple[str, Union[str, bool]]: @@ -98,8 +98,8 @@ class FileTransferModule(_ModuleBase): # 获取目标路径 if not target: # 未指定目的目录,选择一个媒体库 - dir_info = DirectoryHelper().get_library_dir(mediainfo) - if not dir_info or not dir_info.path: + dir_info = DirectoryHelper().get_library_dir(mediainfo, in_path=path) + if not dir_info: logger.error(f"{mediainfo.type.value} {mediainfo.title_year} 未找到有效的媒体库目录,无法转移文件,源路径:{path}") return TransferInfo(success=False, path=path, diff --git a/app/utils/system.py b/app/utils/system.py index c9ec487b..d4ab0d46 100644 --- a/app/utils/system.py +++ b/app/utils/system.py @@ -465,3 +465,14 @@ class SystemUtils: except Exception as err: print(str(err)) return False, f"重启时发生错误:{str(err)}" + + @staticmethod + def is_same_disk(src: Path, dest: Path) -> bool: + """ + 判断两个路径是否在同一磁盘 + """ + if not src.exists() or not dest.exists(): + return False + if os.name == "nt": + return src.drive == dest.drive + return os.stat(src).st_dev == os.stat(dest).st_dev