From 085409049d4f7dfe1807b2e9e034a26647a60c00 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Fri, 14 Jul 2023 20:49:16 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=A4=9A=E5=AA=92=E4=BD=93=E5=BA=93?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +-- app/api/endpoints/dashboard.py | 4 +- app/api/servarr.py | 5 ++- app/modules/filetransfer/__init__.py | 58 +++++++++++++++++++--------- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 4dfc941a..c0e477f6 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ docker pull jxxghp/moviepilot:latest - **PROXY_HOST:** 网络代理(可选),访问themoviedb需要使用代理访问,格式为`ip:port` - **TMDB_API_DOMAIN:** TMDB API地址,默认`api.themoviedb.org`,也可配置为`api.tmdb.org`或其它中转代理服务地址,能连通即可 - **DOWNLOAD_PATH:** 下载保存目录,**注意:需要将`moviepilot`及`下载器`的映射路径与宿主机`真实路径`保持一致**,例如群晖中下载路程径为`/volume1/downloads`,则需要将`moviepilot`及`下载器`的映射路径均设置为`/volume1/downloads`,否则会导致下载文件无法转移 -- **LIBRARY_PATH:** 媒体库目录,**注意:需要将`moviepilot`的映射路径与宿主机`真实路径`保持一致** +- **LIBRARY_PATH:** 媒体库目录,**注意:需要将`moviepilot`的映射路径与宿主机`真实路径`保持一致**,多个目录使用`,`分隔 - **LIBRARY_CATEGORY:** 二级分类开关,`true`/`false`,开启后会根据配置自动在媒体库目录下建立二级目录分类 - **DOUBAN_USER_IDS:** 豆瓣用户ID,用于同步豆瓣标记的`想看`数据,自动添加订阅,多个用户使用,分隔 - **TRANSFER_TYPE:** 转移方式,支持`link`/`copy`/`move`/`softlink` @@ -196,7 +196,7 @@ docker pull jxxghp/moviepilot:latest - 通过CookieCloud同步快速同步站点,不需要使用的站点可在WEB管理界面中禁用。 - 通过下载器监控实现资源下载后自动整理入库刮削。 - 通过微信/Telegram/Slack远程搜索下载、订阅和管理设置,其中Telegram将会自动添加操作菜单。微信回调相对路径为`/api/v1/message/`。 -- 通过WEB进行管理,将WEB添加到手机桌面获得类App使用效果,管理界面地址:http://ip:3000。 +- 通过WEB进行管理,将WEB添加到手机桌面获得类App使用效果,管理界面端口:`3000`。 - 设置媒体服务器Webhook,通过MoviePilot发送播放通知,以及后续播放限速等插件功能。Webhook回调相对路径为`/api/v1/message?token=moviepilot`,其中`moviepilot`为设置的`API_TOKEN`。 - 将MoviePilot做为Radarr或Sonarr服务器添加到Overseerr或Jellyseerr,可使用Overseerr/Jellyseerr选片。 @@ -216,7 +216,7 @@ docker pull jxxghp/moviepilot:latest - [x] 搜索结果过滤 - [x] 多通知渠道支持 -- [ ] 多媒体库目录支持 +- [x] 多媒体库目录支持 - [ ] 插件管理,支持自定义插件功能界面 - [ ] 更易用的自定义识别词 - [ ] 手动整理功能增强 diff --git a/app/api/endpoints/dashboard.py b/app/api/endpoints/dashboard.py index 08b28a5c..96d7f1c7 100644 --- a/app/api/endpoints/dashboard.py +++ b/app/api/endpoints/dashboard.py @@ -38,7 +38,9 @@ def storage(_: schemas.TokenPayload = Depends(verify_token)) -> Any: 查询存储空间信息 """ if settings.LIBRARY_PATH: - total_storage, free_storage = SystemUtils.space_usage(Path(settings.LIBRARY_PATH)) + total_storage, free_storage = SystemUtils.space_usage( + [Path(path) for path in settings.LIBRARY_PATH.split(",")] + ) else: total_storage, free_storage = 0, 0 return schemas.Storage( diff --git a/app/api/servarr.py b/app/api/servarr.py index 89587b76..bbfa05c2 100644 --- a/app/api/servarr.py +++ b/app/api/servarr.py @@ -63,10 +63,13 @@ def arr_rootfolder(apikey: str) -> Any: status_code=403, detail="认证失败!", ) + library_path = "/" + if settings.LIBRARY_PATH: + library_path = settings.LIBRARY_PATH.split(",")[0] return [ { "id": 1, - "path": settings.LIBRARY_PATH, + "path": library_path, "accessible": True, "freeSpace": 0, "unmappedFolders": [] diff --git a/app/modules/filetransfer/__init__.py b/app/modules/filetransfer/__init__.py index 7e01c062..94c43903 100644 --- a/app/modules/filetransfer/__init__.py +++ b/app/modules/filetransfer/__init__.py @@ -36,13 +36,16 @@ class FileTransferModule(_ModuleBase): :param mediainfo: 识别的媒体信息 :return: {path, target_path, message} """ - if not settings.LIBRARY_PATH: - logger.error("未设置媒体库目录,无法转移文件") - return None + # 获取目标路径 + target_path = self.get_target_path(in_path=path) + if not target_path: + logger.error("未找到媒体库目录,无法转移文件") + return TransferInfo(message="未找到媒体库目录,无法转移文件") + # 转移 result = self.transfer_media(in_path=path, meidainfo=mediainfo, rmt_mode=settings.TRANSFER_TYPE, - target_dir=Path(settings.LIBRARY_PATH)) + target_dir=target_path) if not result: return TransferInfo() if isinstance(result, str): @@ -514,20 +517,6 @@ class FileTransferModule(_ModuleBase): "fileExt": file_ext } - def get_movie_dest_path(self, meta: MetaBase, mediainfo: MediaInfo) -> Tuple[str, str]: - """ - 计算电影文件路径 - :return: 电影目录、电影名称 - """ - pass - - def get_tv_dest_path(self, meta: MetaBase, mediainfo: MediaInfo) -> Tuple[str, str, str]: - """ - 计算电视剧文件路径 - :return: 电视剧目录、季目录、集名称 - """ - pass - @staticmethod def get_rename_path(template_string: str, rename_dict: dict, path: Path = None) -> Path: """ @@ -542,3 +531,36 @@ class FileTransferModule(_ModuleBase): return path / render_str else: return Path(render_str) + + @staticmethod + def get_target_path(in_path: Path = None) -> Optional[Path]: + """ + 计算一个最好的目的目录,有in_path时找与in_path同路径的,没有in_path时,顺序查找1个符合大小要求的,没有in_path和size时,返回第1个 + :param in_path: 源目录 + """ + if not settings.LIBRARY_PATH: + return None + # 目的路径,多路径以,分隔 + dest_paths = str(settings.LIBRARY_PATH).split(",") + # 只有一个路径,直接返回 + if len(dest_paths) == 1: + return Path(dest_paths[0]) + # 匹配有最长共同上级路径的目录 + max_length = 0 + target_path = None + if in_path: + for path in dest_paths: + relative = Path(path).relative_to(in_path).as_posix() + if relative.startswith("..") or len(relative) > max_length: + max_length = len(relative) + target_path = path + if target_path: + return Path(target_path) + # 顺序匹配第1个满足空间存储要求的目录 + if in_path.exists(): + file_size = in_path.stat().st_size + for path in dest_paths: + if SystemUtils.free_space(Path(path)) > file_size: + return Path(path) + # 默认返回第1个 + return Path(dest_paths[0])