diff --git a/README.md b/README.md index 149d1e3d..11117996 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ docker pull jxxghp/moviepilot:latest - **DOWNLOAD_SUBTITLE:** 下载站点字幕,`true`/`false`,默认`true` - **REFRESH_MEDIASERVER:** 入库刷新媒体库,`true`/`false`,默认`true` - **SCRAP_METADATA:** 刮削入库的媒体文件,`true`/`false`,默认`true` +- **SCRAP_FOLLOW_TMDB:** 新增已入库媒体是否跟随TMDB信息变化,`true`/`false`,默认`true` - **TORRENT_TAG:** 种子标签,默认为`MOVIEPILOT`,设置后只有MoviePilot添加的下载才会处理,留空所有下载器中的任务均会处理 - **LIBRARY_PATH:** 媒体库目录,多个目录使用`,`分隔 - **LIBRARY_MOVIE_NAME:** 电影媒体库目录名,默认`电影` diff --git a/app/chain/transfer.py b/app/chain/transfer.py index d841b666..9328532a 100644 --- a/app/chain/transfer.py +++ b/app/chain/transfer.py @@ -242,7 +242,12 @@ class TransferChain(ChainBase): f"回复:```\n/redo {his.id} [tmdbid]|[类型]\n``` 手动识别转移。" )) continue - + # 如果未开启新增已入库媒体是否跟随TMDB信息变化则根据tmdbid查询之前的title + if not settings.SCRAP_FOLLOW_TMDB: + transfer_historys = self.transferhis.get_by(tmdbid=file_mediainfo.tmdb_id, + type=file_mediainfo.type.value) + if transfer_historys: + file_mediainfo.title = transfer_historys[0].title logger.info(f"{file_path.name} 识别为:{file_mediainfo.type.value} {file_mediainfo.title_year}") # 电视剧没有集无法转移 diff --git a/app/core/config.py b/app/core/config.py index debf69c0..5833aebb 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -39,6 +39,8 @@ class Settings(BaseSettings): SEARCH_SOURCE: str = "themoviedb" # 刮削入库的媒体文件 SCRAP_METADATA: bool = True + # 新增已入库媒体是否跟随TMDB信息变化 + SCRAP_FOLLOW_TMDB: bool = True # 刮削来源 SCRAP_SOURCE: str = "themoviedb" # TMDB图片地址 diff --git a/app/db/models/transferhistory.py b/app/db/models/transferhistory.py index 9f1686ef..e8158aa2 100644 --- a/app/db/models/transferhistory.py +++ b/app/db/models/transferhistory.py @@ -85,11 +85,14 @@ class TransferHistory(Base): return db.query(func.count(TransferHistory.id)).filter(TransferHistory.title.like(f'%{title}%')).first()[0] @staticmethod - def list_by(db: Session, title: str = None, year: int = None, season: str = None, + def list_by(db: Session, type: str = None, title: str = None, year: int = None, season: str = None, episode: str = None, tmdbid: int = None): """ 据tmdbid、season、season_episode查询转移记录 """ + if tmdbid and type: + return db.query(TransferHistory).filter(TransferHistory.tmdbid == tmdbid, + TransferHistory.type == type).all() if tmdbid and not season and not episode: return db.query(TransferHistory).filter(TransferHistory.tmdbid == tmdbid).all() if tmdbid and season and not episode: diff --git a/app/db/transferhistory_oper.py b/app/db/transferhistory_oper.py index c9f9c395..e04bf4c7 100644 --- a/app/db/transferhistory_oper.py +++ b/app/db/transferhistory_oper.py @@ -51,12 +51,13 @@ class TransferHistoryOper(DbOper): """ return TransferHistory.statistic(self._db, days) - def get_by(self, title: str = None, year: str = None, + def get_by(self, title: str = None, year: str = None, type: str = None, season: str = None, episode: str = None, tmdbid: int = None) -> List[TransferHistory]: """ 按类型、标题、年份、季集查询转移记录 """ return TransferHistory.list_by(db=self._db, + type=type, title=title, year=year, season=season, diff --git a/app/plugins/dirmonitor/__init__.py b/app/plugins/dirmonitor/__init__.py index 48ab6ecd..73887bd5 100644 --- a/app/plugins/dirmonitor/__init__.py +++ b/app/plugins/dirmonitor/__init__.py @@ -69,9 +69,6 @@ class DirMonitor(_PluginBase): # 可使用的用户级别 auth_level = 1 - # 已处理的文件清单 - _synced_files = [] - # 私有属性 _scheduler = None transferhis = None @@ -193,9 +190,8 @@ class DirMonitor(_PluginBase): # 全程加锁 with lock: - if event_path not in self._synced_files: - self._synced_files.append(event_path) - else: + transfer_history = self.transferhis.get_by_src(event_path) + if transfer_history: logger.debug("文件已处理过:%s" % event_path) return @@ -264,6 +260,13 @@ class DirMonitor(_PluginBase): meta=file_meta ) return + + # 如果未开启新增已入库媒体是否跟随TMDB信息变化则根据tmdbid查询之前的title + if not settings.SCRAP_FOLLOW_TMDB: + transfer_historys = self.transferhis.get_by(tmdbid=mediainfo.tmdb_id, + type=mediainfo.type.value) + if transfer_historys: + mediainfo.title = transfer_historys[0].title logger.info(f"{file_path.name} 识别为:{mediainfo.type.value} {mediainfo.title_year}") # 更新媒体图片 @@ -482,149 +485,149 @@ class DirMonitor(_PluginBase): def get_form(self) -> Tuple[List[dict], Dict[str, Any]]: return [ - { - 'component': 'VForm', - 'content': [ - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'enabled', - 'label': '启用插件', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'notify', - 'label': '发送通知', - } - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6 - }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'mode', - 'label': '监控模式', - 'items': [ - {'title': '兼容模式', 'value': 'compatibility'}, - {'title': '性能模式', 'value': 'fast'} - ] - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6 - }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'transfer_type', - 'label': '转移方式', - 'items': [ - {'title': '移动', 'value': 'move'}, - {'title': '复制', 'value': 'copy'}, - {'title': '硬链接', 'value': 'link'}, - {'title': '软链接', 'value': 'softlink'} - ] - } - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12 - }, - 'content': [ - { - 'component': 'VTextarea', - 'props': { - 'model': 'monitor_dirs', - 'label': '监控目录', - 'rows': 5, - 'placeholder': '每一行一个目录,支持两种配置方式:\n' - '监控目录\n' - '监控目录:转移目的目录' - } - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12 - }, - 'content': [ - { - 'component': 'VTextarea', - 'props': { - 'model': 'exclude_keywords', - 'label': '排除关键词', - 'rows': 2, - 'placeholder': '每一行一个关键词' - } - } - ] - } - ] - } - ] - } - ], { - "enabled": False, - "notify": False, - "mode": "fast", - "transfer_type": settings.TRANSFER_TYPE, - "monitor_dirs": "", - "exclude_keywords": "" - } + { + 'component': 'VForm', + 'content': [ + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'enabled', + 'label': '启用插件', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'notify', + 'label': '发送通知', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'mode', + 'label': '监控模式', + 'items': [ + {'title': '兼容模式', 'value': 'compatibility'}, + {'title': '性能模式', 'value': 'fast'} + ] + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'transfer_type', + 'label': '转移方式', + 'items': [ + {'title': '移动', 'value': 'move'}, + {'title': '复制', 'value': 'copy'}, + {'title': '硬链接', 'value': 'link'}, + {'title': '软链接', 'value': 'softlink'} + ] + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VTextarea', + 'props': { + 'model': 'monitor_dirs', + 'label': '监控目录', + 'rows': 5, + 'placeholder': '每一行一个目录,支持两种配置方式:\n' + '监控目录\n' + '监控目录:转移目的目录' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12 + }, + 'content': [ + { + 'component': 'VTextarea', + 'props': { + 'model': 'exclude_keywords', + 'label': '排除关键词', + 'rows': 2, + 'placeholder': '每一行一个关键词' + } + } + ] + } + ] + } + ] + } + ], { + "enabled": False, + "notify": False, + "mode": "fast", + "transfer_type": settings.TRANSFER_TYPE, + "monitor_dirs": "", + "exclude_keywords": "" + } def get_page(self) -> List[dict]: pass diff --git a/app/plugins/libraryscraper/__init__.py b/app/plugins/libraryscraper/__init__.py index 096d2619..8ef79579 100644 --- a/app/plugins/libraryscraper/__init__.py +++ b/app/plugins/libraryscraper/__init__.py @@ -9,6 +9,7 @@ from apscheduler.triggers.cron import CronTrigger from app.core.config import settings from app.core.metainfo import MetaInfo +from app.db.transferhistory_oper import TransferHistoryOper from app.helper.nfo import NfoReader from app.log import logger from app.plugins import _PluginBase @@ -40,6 +41,7 @@ class LibraryScraper(_PluginBase): user_level = 1 # 私有属性 + transferhis = None _scheduler = None _scraper = None # 限速开关 @@ -67,6 +69,7 @@ class LibraryScraper(_PluginBase): # 启动定时任务 & 立即运行一次 if self._enabled or self._onlyonce: + self.transferhis = TransferHistoryOper(self.db) self._scheduler = BackgroundScheduler(timezone=settings.TZ) if self._cron: logger.info(f"媒体库刮削服务启动,周期:{self._cron}") @@ -346,6 +349,13 @@ class LibraryScraper(_PluginBase): if not mediainfo: logger.warn(f"未识别到媒体信息:{file}") continue + + # 如果未开启新增已入库媒体是否跟随TMDB信息变化则根据tmdbid查询之前的title + if not settings.SCRAP_FOLLOW_TMDB: + transfer_historys = self.transferhis.get_by(tmdbid=mediainfo.tmdb_id, + type=mediainfo.type.value) + if transfer_historys: + mediainfo.title = transfer_historys[0].title # 覆盖模式时,提前删除nfo if self._mode in ["force_all", "force_nfo"]: diff --git a/app/plugins/messageforward/__init__.py b/app/plugins/messageforward/__init__.py index 52855564..4927ab2d 100644 --- a/app/plugins/messageforward/__init__.py +++ b/app/plugins/messageforward/__init__.py @@ -303,7 +303,7 @@ class MessageForward(_PluginBase): "enable_id_trans": 0, "enable_duplicate_check": 0 } - return self.__post_request(message_url, req_json, i, title) + return self.__post_request(message_url=message_url, req_json=req_json, i=i, title=title) def __send_image_message(self, title: str, text: str, image_url: str, userid: str = None, access_token: str = None, appid: str = None, i: int = None) -> Optional[bool]: @@ -335,9 +335,9 @@ class MessageForward(_PluginBase): ] } } - return self.__post_request(message_url, req_json, i, title) + return self.__post_request(message_url=message_url, req_json=req_json, i=i, title=title) - def __post_request(self, message_url: str, req_json: dict, i: int, title: str) -> bool: + def __post_request(self, message_url: str, req_json: dict, i: int, title: str, retry: int = 0) -> bool: """ 向微信发送请求 """ @@ -355,6 +355,11 @@ class MessageForward(_PluginBase): if ret_json.get('errcode') == 42001: # 重新获取token self.__flush_access_token(i) + retry += 1 + # 重发请求 + if retry <= 3: + self.__post_request(message_url=message_url, req_json=req_json, i=i, title=title, + retry=retry) logger.error(f"转发消息 {title} 失败,错误信息:{ret_json}") return False elif res is not None: @@ -364,7 +369,7 @@ class MessageForward(_PluginBase): logger.error(f"转发消息 {title} 失败,未获取到返回信息") return False except Exception as err: - logger.error(f"转发消息 {title} 失败,错误信息:{err}") + logger.error(f"转发消息 {title} 异常,错误信息:{err}") return False def __get_access_token(self, corpid, appsecret):