From 288883a13baa41c702ad4192f93b3e21fbc23d46 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 12 Nov 2023 08:03:15 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E6=96=87=E4=BB=B6=E6=95=B4=E7=90=86?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=BB=85=E4=BF=9D=E7=95=99=E6=9C=80=E6=96=B0?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++--- app/modules/filetransfer/__init__.py | 48 +++++++++++++++++++++++++- config/app.env | 50 ++++++++++++++-------------- 3 files changed, 77 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index bafe443a..03c580fe 100644 --- a/README.md +++ b/README.md @@ -78,14 +78,14 @@ MoviePilot需要配套下载器和媒体服务器配合使用。 - **TMDB_API_DOMAIN:** TMDB API地址,默认`api.themoviedb.org`,也可配置为`api.tmdb.org`或其它中转代理服务地址,能连通即可 - **TMDB_IMAGE_DOMAIN:** TMDB图片地址,默认`image.tmdb.org`,可配置为其它中转代理以加速TMDB图片显示,如:`static-mdb.v.geilijiasu.com` - **WALLPAPER:** 登录首页电影海报,`tmdb`/`bing`,默认`tmdb` -- **RECOGNIZE_SOURCE:** 媒体信息识别来源,`themoviedb`/`douban`,默认`themoviedb` +- **RECOGNIZE_SOURCE:** 媒体信息识别来源,`themoviedb`/`douban`,默认`themoviedb`,使用`douban`时不支持二级分类 - **SCRAP_SOURCE:** 刮削元数据及图片使用的数据源,`themoviedb`/`douban`,默认`themoviedb` --- - **SCRAP_METADATA:** 刮削入库的媒体文件,`true`/`false`,默认`true` -- **SCRAP_FOLLOW_TMDB:** 新增已入库媒体是否跟随TMDB信息变化,`true`/`false`,默认`true` +- **SCRAP_FOLLOW_TMDB:** 新增已入库媒体是否跟随TMDB信息变化,`true`/`false`,默认`true`,为`false`时即使TMDB信息变化了也会仍然按历史记录中已入库的信息进行刮削 --- - **❗TRANSFER_TYPE:** 整理转移方式,支持`link`/`copy`/`move`/`softlink`/`rclone_copy`/`rclone_move` **注意:在`link`和`softlink`转移方式下,转移后的文件会继承源文件的权限掩码,不受`UMASK`影响;rclone需要自行映射rclone配置目录到容器中或在容器内完成rclone配置,节点名称必须为:`MP`** -- **❗OVERWRITE_MODE:** 转移覆盖模式,默认为`size`,支持`nerver`/`size`/`always`,分别表示`不覆盖`/`根据文件大小覆盖(大覆盖小)`/`总是覆盖` +- **❗OVERWRITE_MODE:** 转移覆盖模式,默认为`size`,支持`nerver`/`size`/`always`/`latest`,分别表示`不覆盖同名文件`/`同名文件根据文件大小覆盖(大覆盖小)`/`总是覆盖同名文件`/`仅保留最新版本,删除旧版本文件(包括非同名文件)` - **❗LIBRARY_PATH:** 媒体库目录,多个目录使用`,`分隔 - **LIBRARY_MOVIE_NAME:** 电影媒体库目录名称(不是完整路径),默认`电影` - **LIBRARY_TV_NAME:** 电视剧媒体库目录称(不是完整路径),默认`电视剧` @@ -101,7 +101,7 @@ MoviePilot需要配套下载器和媒体服务器配合使用。 - **SUBSCRIBE_MODE:** 订阅模式,`rss`/`spider`,默认`spider`,`rss`模式通过定时刷新RSS来匹配订阅(RSS地址会自动获取,也可手动维护),对站点压力小,同时可设置订阅刷新周期,24小时运行,但订阅和下载通知不能过滤和显示免费,推荐使用rss模式。 - **SUBSCRIBE_RSS_INTERVAL:** RSS订阅模式刷新时间间隔(分钟),默认`30`分钟,不能小于5分钟。 - **SUBSCRIBE_SEARCH:** 订阅搜索,`true`/`false`,默认`false`,开启后会每隔24小时对所有订阅进行全量搜索,以补齐缺失剧集(一般情况下正常订阅即可,订阅搜索只做为兜底,会增加站点压力,不建议开启)。 -- **AUTO_DOWNLOAD_USER:** 远程交互搜索时自动择优下载的用户ID,多个用户使用,分割,未设置需要选择资源或者回复`0` +- **AUTO_DOWNLOAD_USER:** 远程交互搜索时自动择优下载的用户ID(消息通知渠道的用户ID),多个用户使用,分割,未设置需要选择资源或者回复`0` --- - **OCR_HOST:** OCR识别服务器地址,格式:`http(s)://ip:port`,用于识别站点验证码实现自动登录获取Cookie等,不配置默认使用内建服务器`https://movie-pilot.org`,可使用 [这个镜像](https://hub.docker.com/r/jxxghp/moviepilot-ocr) 自行搭建。 - **PLUGIN_MARKET:** 插件市场仓库地址,多个地址使用`,`分隔,保留最后的/,默认为官方插件仓库:`https://raw.githubusercontent.com/jxxghp/MoviePilot-Plugins/main/`。 @@ -212,7 +212,7 @@ MoviePilot需要配套下载器和媒体服务器配合使用。 ### 2. **进阶配置** -- **BIG_MEMORY_MODE:** 大内存模式,默认为`false`,开启后会占用更多的内存,但响应速度会更快 +- **BIG_MEMORY_MODE:** 大内存模式,默认为`false`,开启后会增加缓存数量,占用更多的内存,但响应速度会更快 - **MOVIE_RENAME_FORMAT:** 电影重命名格式 diff --git a/app/modules/filetransfer/__init__.py b/app/modules/filetransfer/__init__.py index c935f261..df377ffd 100644 --- a/app/modules/filetransfer/__init__.py +++ b/app/modules/filetransfer/__init__.py @@ -8,7 +8,7 @@ from jinja2 import Template from app.core.config import settings from app.core.context import MediaInfo from app.core.meta import MetaBase -from app.core.metainfo import MetaInfo +from app.core.metainfo import MetaInfo, MetaInfoPath from app.log import logger from app.modules import _ModuleBase from app.schemas import TransferInfo, ExistMediaInfo, TmdbEpisode @@ -416,6 +416,14 @@ class FileTransferModule(_ModuleBase): rename_dict=self.__get_naming_dict(meta=in_meta, mediainfo=mediainfo) ).parent + # 目录已存在时不处理 + if new_path.exists(): + logger.warn(f"目标目录已存在:{new_path}") + return TransferInfo(success=False, + message=f"目标目录已存在:{new_path}", + path=in_path, + target_path=new_path, + is_bluray=bluray_flag) # 转移蓝光原盘 retcode = self.__transfer_dir(file_path=in_path, new_path=new_path, @@ -475,8 +483,10 @@ class FileTransferModule(_ModuleBase): logger.info(f"目标文件已存在,转移覆盖模式:{settings.OVERWRITE_MODE}") match settings.OVERWRITE_MODE: case 'always': + # 总是覆盖同名文件 overflag = True case 'size': + # 存在时大覆盖小 if new_file.stat().st_size < in_path.stat().st_size: logger.info(f"目标文件文件大小更小,将被覆盖:{new_file}") overflag = True @@ -487,11 +497,16 @@ class FileTransferModule(_ModuleBase): target_path=new_file, fail_list=[str(in_path)]) case 'never': + # 存在不覆盖 return TransferInfo(success=False, message=f"媒体库中已存在,当前设置为不覆盖", path=in_path, target_path=new_file, fail_list=[str(in_path)]) + case 'latest': + # 仅保留最新版本 + self.delete_all_version_files(new_file) + overflag = True case _: pass # 原文件大小 @@ -720,3 +735,34 @@ class FileTransferModule(_ModuleBase): return ExistMediaInfo(type=MediaType.TV, seasons=seasons) # 不存在 return None + + @staticmethod + def delete_all_version_files(path: Path) -> bool: + """ + 删除目录下的所有版本文件 + :param path: 目录路径 + """ + if not path.exists(): + return False + # 识别文件中的季集信息 + meta = MetaInfoPath(path) + season = meta.season + episode = meta.episode + # 检索媒体文件 + logger.warn(f"正在删除目标目录中其它版本的文件:{path.parent}") + media_files = SystemUtils.list_files(directory=path.parent, extensions=settings.RMT_MEDIAEXT) + if not media_files: + logger.info(f"目录中没有媒体文件:{path.parent}") + return False + # 删除文件 + for media_file in media_files: + if media_file == path: + continue + # 识别文件中的季集信息 + filemeta = MetaInfoPath(media_file) + # 相同季集的文件才删除 + if filemeta.season != season or filemeta.episode != episode: + continue + logger.info(f"正在删除文件:{media_file}") + media_file.unlink() + return True diff --git a/config/app.env b/config/app.env index 4218b603..8bff6387 100644 --- a/config/app.env +++ b/config/app.env @@ -7,25 +7,25 @@ #################################### # 【*】API监听地址 HOST=0.0.0.0 -# 是否调试模式 +# 是否调试模式,打开后将输出更多日志 DEBUG=false -# 是否开发模式 +# 是否开发模式,打开后后台服务将不会启动 DEV=false -# 【*】超级管理员 +# 【*】超级管理员,设置后一但重启将固化到数据库中,修改将无效 SUPERUSER=admin -# 【*】超级管理员初始密码 +# 【*】超级管理员初始密码,设置后一但重启将固化到数据库中,修改将无效 SUPERUSER_PASSWORD=password -# 【*】API密钥,建议更换复杂字符串 +# 【*】API密钥,建议更换复杂字符串,有Jellyseerr/Overseerr、媒体服务器Webhook等配置以及部分支持API_TOKEN的API中使用 API_TOKEN=moviepilot -# 登录页面电影海报,tmdb/bing +# 登录页面电影海报,tmdb/bing,tmdb要求能正常连接api.themoviedb.org WALLPAPER=tmdb -# TMDB图片地址,无需修改需保留默认值 +# TMDB图片地址,无需修改需保留默认值,如果默认地址连通性不好可以尝试修改为:`static-mdb.v.geilijiasu.com` TMDB_IMAGE_DOMAIN=image.tmdb.org -# TMDB API地址,无需修改需保留默认值 +# TMDB API地址,无需修改需保留默认值,也可配置为`api.tmdb.org`或其它中转代理服务地址,能连通即可 TMDB_API_DOMAIN=api.themoviedb.org -# 媒体识别来源 themoviedb/douban +# 媒体识别来源 themoviedb/douban,使用themoviedb时需要确保能正常连接api.themoviedb.org,使用douban时不支持二级分类 RECOGNIZE_SOURCE=themoviedb -# 大内存模式 +# 大内存模式,开启后会增加缓存数量,但会占用更多内存 BIG_MEMORY_MODE=false #################################### @@ -33,9 +33,9 @@ BIG_MEMORY_MODE=false #################################### # 刮削入库的媒体文件 true/false SCRAP_METADATA=true -# 新增已入库媒体是否跟随TMDB信息变化 +# 新增已入库媒体是否跟随TMDB信息变化,true/false,为false时即使TMDB信息变化时也会仍然按历史记录中已入库的信息进行刮削 SCRAP_FOLLOW_TMDB=true -# 刮削来源 themoviedb/douban +# 刮削来源 themoviedb/douban,使用themoviedb时需要确保能正常连接api.themoviedb.org,使用douban时会缺失部分信息 SCRAP_SOURCE=themoviedb #################################### @@ -43,7 +43,7 @@ SCRAP_SOURCE=themoviedb #################################### # 【*】转移方式 link/copy/move/softlink/rclone_copy/rclone_move TRANSFER_TYPE=copy -# 转移时覆盖模式 +# 转移覆盖模式,`nerver`/`size`/`always`/`latest`,分别表示`不覆盖同名文件`/`同名文件根据文件大小覆盖(大覆盖小)`/`总是覆盖同名文件`/`仅保留最新版本,删除旧版本文件(包括非同名文件)` OVERWRITE_MODE=size # 【*】媒体库目录,多个目录使用,分隔 LIBRARY_PATH= @@ -53,11 +53,11 @@ LIBRARY_MOVIE_NAME= LIBRARY_TV_NAME= # 动漫媒体库目录名,默认电视剧/动漫 LIBRARY_ANIME_NAME= -# 二级分类 +# 二级分类,开启后会根据配置 [category.yaml](https://github.com/jxxghp/MoviePilot/raw/main/config/category.yaml) 自动在媒体库目录下建立二级目录分类 LIBRARY_CATEGORY=true -# 电影重命名格式 +# 电影重命名格式,Jinja2语法,参考:https://jinja.palletsprojects.com/en/3.0.x/templates/ MOVIE_RENAME_FORMAT={{title}}{% if year %} ({{year}}){% endif %}/{{title}}{% if year %} ({{year}}){% endif %}{% if part %}-{{part}}{% endif %}{% if videoFormat %} - {{videoFormat}}{% endif %}{{fileExt}} -# 电视剧重命名格式 +# 电视剧重命名格式,Jinja2语法,参考:https://jinja.palletsprojects.com/en/3.0.x/templates/ TV_RENAME_FORMAT={{title}}{% if year %} ({{year}}){% endif %}/Season {{season}}/{{title}} - {{season_episode}}{% if part %}-{{part}}{% endif %}{% if episode %} - 第 {{episode}} 集{% endif %}{{fileExt}} #################################### @@ -77,13 +77,13 @@ USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, #################################### # 订阅 & 搜索 # #################################### -# 订阅模式 spider/rss +# 订阅模式 spider/rss,`rss`模式通过定时刷新RSS来匹配订阅(RSS地址会自动获取,也可手动维护),`spider`为爬虫模式,随机时间(间隔20-40分钟)爬取站点首页种子 SUBSCRIBE_MODE=spider # RSS订阅模式刷新时间间隔(分钟) SUBSCRIBE_RSS_INTERVAL=30 -# 订阅搜索开关 +# 订阅搜索开关,开启后会每隔24小时对所有订阅进行全量搜索,以补齐缺失剧集 SUBSCRIBE_SEARCH=false -# 交互搜索自动下载用户ID,使用,分割 +# 交互搜索自动下载用户ID(消息通知渠道的用户ID),使用,分割,未设置需要用户手动选择资源或者回复`0` AUTO_DOWNLOAD_USER= #################################### @@ -127,7 +127,7 @@ SYNOLOGYCHAT_TOKEN= #################################### # 下载 # #################################### -# 【*】下载器 qbittorrent/transmission +# 【*】下载器 qbittorrent/transmission,仅支持单个下载器,做为主下载器使用,非主下载器只要配置了参数仍可在插件等使用 DOWNLOADER=qbittorrent # 下载器监控开关 DOWNLOADER_MONITOR=true @@ -151,15 +151,15 @@ TR_USER= TR_PASSWORD= # 种子标签 TORRENT_TAG=MOVIEPILOT -# 【*】下载保存目录,容器内映射路径需要一致 +# 【*】下载保存目录,容器内映射路径需要一致,支持不同类型设置不同的下载目录(跨盘) DOWNLOAD_PATH=/downloads -# 电影下载保存目录,容器内映射路径需要一致 +# 电影下载保存目录(路径),容器内映射路径需要一致 DOWNLOAD_MOVIE_PATH= -# 电视剧下载保存目录,容器内映射路径需要一致 +# 电视剧下载保存目录(路径),容器内映射路径需要一致 DOWNLOAD_TV_PATH= -# 动漫下载保存目录,容器内映射路径需要一致 +# 动漫下载保存目录(路径),容器内映射路径需要一致 DOWNLOAD_ANIME_PATH= -# 下载目录二级分类 +# 下载目录二级分类,开启后会根据配置 [category.yaml](https://github.com/jxxghp/MoviePilot/raw/main/config/category.yaml) 自动在下载目录下建立二级目录分类 DOWNLOAD_CATEGORY=false # 下载站点字幕 DOWNLOAD_SUBTITLE=true